Implement keyboard device.
[pintos-anon] / src / devices / kbd.c
1 #include "devices/kbd.h"
2 #include <ctype.h>
3 #include <debug.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include "devices/intq.h"
7 #include "threads/interrupt.h"
8 #include "threads/io.h"
9
10 /* Keyboard data register port. */
11 #define DATA_REG 0x60
12
13 /* Shift state bits. */
14 #define LSHIFT  0x01            /* Left Shift. */
15 #define RSHIFT  0x02            /* Right Shift. */
16 #define LALT    0x04            /* Left Alt. */
17 #define RALT    0x08            /* Right Alt. */
18 #define LCTRL   0x10            /* Left Ctrl. */
19 #define RCTRL   0x20            /* Right Ctrl. */
20 #define CAPS    0x40            /* Caps Lock. */
21
22 /* Current shift state. */
23 static unsigned shift_state;
24
25 /* Keyboard buffer. */
26 static struct intq buffer;
27
28 static intr_handler_func keyboard_interrupt;
29
30 /* Initializes the keyboard. */
31 void
32 kbd_init (void) 
33 {
34   intq_init (&buffer, "keyboard");
35   intr_register (0x21, 0, INTR_OFF, keyboard_interrupt, "8042 Keyboard");
36 }
37
38 /* Retrieves a key from the keyboard buffer.
39    If the buffer is empty, waits for a key to be pressed. */
40 uint8_t
41 kbd_getc (void) 
42 {
43   uint8_t key;
44   
45   intq_lock (&buffer);
46   key = intq_getc (&buffer);
47   intq_unlock (&buffer);
48   
49   return key;
50 }
51 \f
52 /* Maps a set of contiguous scancodes into characters. */
53 struct keymap
54   {
55     uint8_t first_scancode;     /* First scancode. */
56     const char *chars;          /* chars[0] has scancode first_scancode,
57                                    chars[1] has scancode first_scancode + 1,
58                                    and so on to the end of the string. */
59   };
60   
61 /* Keys that produce the same characters regardless of whether
62    the Shift keys are down.  Case of letters is an exception
63    that we handle elsewhere.  */
64 static const struct keymap invariant_keymap[] = 
65   {
66     {0x01, "\033"},
67     {0x0e, "\b"},
68     {0x0f, "\tQWERTYUIOP"},
69     {0x1c, "\n"},
70     {0x1e, "ASDFGHJKL"},
71     {0x2c, "ZXCVBNM"},
72     {0x37, "*"},
73     {0x39, " "},
74     {0, NULL},
75   };
76
77 /* Characters for keys pressed without Shift, for those keys
78    where it matters. */
79 static const struct keymap unshifted_keymap[] = 
80   {
81     {0x02, "1234567890-="},
82     {0x1a, "[]"},
83     {0x27, ";'`"},
84     {0x2b, "\\"},
85     {0x33, ",./"},
86     {0, NULL},
87   };
88   
89 /* Characters for keys pressed with Shift, for those keys where
90    it matters. */
91 static const struct keymap shifted_keymap[] = 
92   {
93     {0x02, "!@#$%^&*()_+"},
94     {0x1a, "{}"},
95     {0x27, ":\"~"},
96     {0x2b, "|"},
97     {0x33, "<>?"},
98     {0, NULL},
99   };
100
101 static bool map_key (const struct keymap[], unsigned scancode, uint8_t *);
102
103 static void
104 keyboard_interrupt (struct intr_frame *args UNUSED) 
105 {
106   /* Status of shift keys. */
107   bool shift = (shift_state & (LSHIFT | RSHIFT)) != 0;
108   bool alt = (shift_state & (LALT | RALT)) != 0;
109   bool ctrl = (shift_state & (LCTRL | RCTRL)) != 0;
110   bool caps = (shift_state & CAPS) != 0;
111
112   /* Keyboard scancode. */
113   unsigned code;
114
115   /* False if key pressed, true if key released. */
116   bool release;
117
118   /* Character that corresponds to `code'. */
119   uint8_t c;
120
121   /* Read scancode, including second byte if prefix code. */
122   code = inb (DATA_REG);
123   if (code == 0xe0)
124     code = (code << 8) | inb (DATA_REG);
125
126   /* Bit 0x80 distinguishes key press from key release
127      (even if there's a prefix). */
128   release = (code & 0x80) != 0;
129   code &= ~0x80u;
130
131   /* Interpret key. */
132   if (code == 0x3a) 
133     {
134       /* Caps Lock. */
135       if (!release)
136         shift_state ^= CAPS; 
137     }
138   else if (map_key (invariant_keymap, code, &c)
139            || (!shift && map_key (unshifted_keymap, code, &c))
140            || (shift && map_key (shifted_keymap, code, &c)))
141     {
142       /* Ordinary character. */
143       if (!release) 
144         {
145           /* Handle Ctrl, Shift.
146              Note that Ctrl overrides Shift. */
147           if (ctrl && c >= 0x40 && c < 0x60) 
148             {
149               /* A is 0x41, Ctrl+A is 0x01, etc. */
150               c -= 0x40; 
151             }
152           else if (shift == caps)
153             c = tolower (c);
154
155           /* Handle Alt by setting the high bit.
156              This 0x80 is unrelated to the one used to
157              distinguish key press from key release. */
158           if (alt)
159             c += 0x80;
160
161           /* Append to keyboard buffer. */
162           if (!intq_full (&buffer))
163             intq_putc (&buffer, c);
164         }
165     }
166   else
167     {
168       /* Table of shift keys.
169          Maps a keycode into a shift_state bit. */
170       static const unsigned shift_keys[][2] = 
171         {
172           {  0x2a, LSHIFT},
173           {  0x36, RSHIFT},
174           {  0x38, LALT},
175           {0xe038, RALT},
176           {  0x1d, LCTRL},
177           {0xe01d, RCTRL},
178           {0, 0},
179         };
180   
181       const unsigned (*key)[2];
182
183       /* Scan the table. */
184       for (key = shift_keys; (*key)[0] != 0; key++) 
185         if ((*key)[0] == code)
186           {
187             if (release)
188               shift_state &= ~(*key)[1];
189             else
190               shift_state |= (*key)[1];
191             break;
192           }
193     }
194 }
195
196 /* Scans the array of keymaps K for SCANCODE.
197    If found, sets *C to the corresponding character and returns
198    true.
199    If not found, returns false and C is ignored. */
200 static bool
201 map_key (const struct keymap k[], unsigned scancode, uint8_t *c) 
202 {
203   for (; k->first_scancode != 0; k++)
204     if (scancode >= k->first_scancode
205         && scancode < k->first_scancode + strlen (k->chars)) 
206       {
207         *c = k->chars[scancode - k->first_scancode];
208         return true; 
209       }
210
211   return false;
212 }