1 #include "devices/kbd.h"
6 #include "devices/intq.h"
7 #include "threads/interrupt.h"
8 #include "threads/io.h"
10 /* Keyboard data register port. */
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. */
22 /* Current shift state. */
23 static unsigned shift_state;
25 /* Keyboard buffer. */
26 static struct intq buffer;
28 /* Number of keys pressed. */
29 static int64_t key_cnt;
31 static intr_handler_func keyboard_interrupt;
33 /* Initializes the keyboard. */
38 intr_register_ext (0x21, keyboard_interrupt, "8042 Keyboard");
41 /* Retrieves a key from the keyboard buffer.
42 If the buffer is empty, waits for a key to be pressed. */
46 enum intr_level old_level;
49 old_level = intr_disable ();
50 key = intq_getc (&buffer);
51 intr_set_level (old_level);
56 /* Prints keyboard statistics. */
58 kbd_print_stats (void)
60 printf ("Keyboard: %lld keys pressed\n", key_cnt);
63 /* Maps a set of contiguous scancodes into characters. */
66 uint8_t first_scancode; /* First scancode. */
67 const char *chars; /* chars[0] has scancode first_scancode,
68 chars[1] has scancode first_scancode + 1,
69 and so on to the end of the string. */
72 /* Keys that produce the same characters regardless of whether
73 the Shift keys are down. Case of letters is an exception
74 that we handle elsewhere. */
75 static const struct keymap invariant_keymap[] =
79 {0x0f, "\tQWERTYUIOP"},
88 /* Characters for keys pressed without Shift, for those keys
90 static const struct keymap unshifted_keymap[] =
92 {0x02, "1234567890-="},
100 /* Characters for keys pressed with Shift, for those keys where
102 static const struct keymap shifted_keymap[] =
104 {0x02, "!@#$%^&*()_+"},
112 static bool map_key (const struct keymap[], unsigned scancode, uint8_t *);
115 keyboard_interrupt (struct intr_frame *args UNUSED)
117 /* Status of shift keys. */
118 bool shift = (shift_state & (LSHIFT | RSHIFT)) != 0;
119 bool alt = (shift_state & (LALT | RALT)) != 0;
120 bool ctrl = (shift_state & (LCTRL | RCTRL)) != 0;
121 bool caps = (shift_state & CAPS) != 0;
123 /* Keyboard scancode. */
126 /* False if key pressed, true if key released. */
129 /* Character that corresponds to `code'. */
132 /* Read scancode, including second byte if prefix code. */
133 code = inb (DATA_REG);
135 code = (code << 8) | inb (DATA_REG);
137 /* Bit 0x80 distinguishes key press from key release
138 (even if there's a prefix). */
139 release = (code & 0x80) != 0;
149 else if (map_key (invariant_keymap, code, &c)
150 || (!shift && map_key (unshifted_keymap, code, &c))
151 || (shift && map_key (shifted_keymap, code, &c)))
153 /* Ordinary character. */
156 /* Handle Ctrl, Shift.
157 Note that Ctrl overrides Shift. */
158 if (ctrl && c >= 0x40 && c < 0x60)
160 /* A is 0x41, Ctrl+A is 0x01, etc. */
163 else if (shift == caps)
166 /* Handle Alt by setting the high bit.
167 This 0x80 is unrelated to the one used to
168 distinguish key press from key release. */
172 /* Append to keyboard buffer. */
173 if (!intq_full (&buffer))
176 intq_putc (&buffer, c);
182 /* Table of shift keys.
183 Maps a keycode into a shift_state bit. */
184 static const unsigned shift_keys[][2] =
195 const unsigned (*key)[2];
197 /* Scan the table. */
198 for (key = shift_keys; (*key)[0] != 0; key++)
199 if ((*key)[0] == code)
202 shift_state &= ~(*key)[1];
204 shift_state |= (*key)[1];
210 /* Scans the array of keymaps K for SCANCODE.
211 If found, sets *C to the corresponding character and returns
213 If not found, returns false and C is ignored. */
215 map_key (const struct keymap k[], unsigned scancode, uint8_t *c)
217 for (; k->first_scancode != 0; k++)
218 if (scancode >= k->first_scancode
219 && scancode < k->first_scancode + strlen (k->chars))
221 *c = k->chars[scancode - k->first_scancode];