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 /* Current state of shift keys.
14 True if depressed, false otherwise. */
15 static bool left_shift, right_shift; /* Left and right Shift keys. */
16 static bool left_alt, right_alt; /* Left and right Alt keys. */
17 static bool left_ctrl, right_ctrl; /* Left and right Ctl keys. */
19 /* Status of Caps Lock.
20 True when on, false when off. */
21 static bool caps_lock;
23 /* Keyboard buffer. */
24 static struct intq buffer;
26 /* Number of keys pressed. */
27 static int64_t key_cnt;
29 static intr_handler_func keyboard_interrupt;
31 /* Initializes the keyboard. */
36 intr_register_ext (0x21, keyboard_interrupt, "8042 Keyboard");
39 /* Retrieves a key from the keyboard buffer.
40 If the buffer is empty, waits for a key to be pressed. */
44 enum intr_level old_level;
47 old_level = intr_disable ();
48 key = intq_getc (&buffer);
49 intr_set_level (old_level);
54 /* Prints keyboard statistics. */
56 kbd_print_stats (void)
58 printf ("Keyboard: %lld keys pressed\n", key_cnt);
61 /* Maps a set of contiguous scancodes into characters. */
64 uint8_t first_scancode; /* First scancode. */
65 const char *chars; /* chars[0] has scancode first_scancode,
66 chars[1] has scancode first_scancode + 1,
67 and so on to the end of the string. */
70 /* Keys that produce the same characters regardless of whether
71 the Shift keys are down. Case of letters is an exception
72 that we handle elsewhere. */
73 static const struct keymap invariant_keymap[] =
77 {0x0f, "\tQWERTYUIOP"},
86 /* Characters for keys pressed without Shift, for those keys
88 static const struct keymap unshifted_keymap[] =
90 {0x02, "1234567890-="},
98 /* Characters for keys pressed with Shift, for those keys where
100 static const struct keymap shifted_keymap[] =
102 {0x02, "!@#$%^&*()_+"},
110 static bool map_key (const struct keymap[], unsigned scancode, uint8_t *);
113 keyboard_interrupt (struct intr_frame *args UNUSED)
115 /* Status of shift keys. */
116 bool shift = left_shift || right_shift;
117 bool alt = left_alt || right_alt;
118 bool ctrl = left_ctrl || right_ctrl;
120 /* Keyboard scancode. */
123 /* False if key pressed, true if key released. */
126 /* Character that corresponds to `code'. */
129 /* Read scancode, including second byte if prefix code. */
130 code = inb (DATA_REG);
132 code = (code << 8) | inb (DATA_REG);
134 /* Bit 0x80 distinguishes key press from key release
135 (even if there's a prefix). */
136 release = (code & 0x80) != 0;
144 caps_lock = !caps_lock;
146 else if (map_key (invariant_keymap, code, &c)
147 || (!shift && map_key (unshifted_keymap, code, &c))
148 || (shift && map_key (shifted_keymap, code, &c)))
150 /* Ordinary character. */
153 /* Handle Ctrl, Shift.
154 Note that Ctrl overrides Shift. */
155 if (ctrl && c >= 0x40 && c < 0x60)
157 /* A is 0x41, Ctrl+A is 0x01, etc. */
160 else if (shift == caps_lock)
163 /* Handle Alt by setting the high bit.
164 This 0x80 is unrelated to the one used to
165 distinguish key press from key release. */
169 /* Append to keyboard buffer. */
170 if (!intq_full (&buffer))
173 intq_putc (&buffer, c);
179 /* Maps a keycode into a shift state variable. */
186 /* Table of shift keys. */
187 static const struct shift_key shift_keys[] =
189 { 0x2a, &left_shift},
190 { 0x36, &right_shift},
192 {0xe038, &right_alt},
194 {0xe01d, &right_ctrl},
198 const struct shift_key *key;
200 /* Scan the table. */
201 for (key = shift_keys; key->scancode != 0; key++)
202 if (key->scancode == code)
204 *key->state_var = !release;
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];