Add support for "keyboard" input over the serial port.
[pintos.git] / src / devices / kbd.c
blob4d7dfdf1a315df6cd3b92564c2719bc815d694de
1 #include "devices/kbd.h"
2 #include <ctype.h>
3 #include <debug.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include "devices/input.h"
7 #include "threads/interrupt.h"
8 #include "threads/io.h"
10 /* Keyboard data register port. */
11 #define DATA_REG 0x60
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 /* Number of keys pressed. */
24 static int64_t key_cnt;
26 static intr_handler_func keyboard_interrupt;
28 /* Initializes the keyboard. */
29 void
30 kbd_init (void)
32 intr_register_ext (0x21, keyboard_interrupt, "8042 Keyboard");
35 /* Prints keyboard statistics. */
36 void
37 kbd_print_stats (void)
39 printf ("Keyboard: %lld keys pressed\n", key_cnt);
42 /* Maps a set of contiguous scancodes into characters. */
43 struct keymap
45 uint8_t first_scancode; /* First scancode. */
46 const char *chars; /* chars[0] has scancode first_scancode,
47 chars[1] has scancode first_scancode + 1,
48 and so on to the end of the string. */
51 /* Keys that produce the same characters regardless of whether
52 the Shift keys are down. Case of letters is an exception
53 that we handle elsewhere. */
54 static const struct keymap invariant_keymap[] =
56 {0x01, "\033"},
57 {0x0e, "\b"},
58 {0x0f, "\tQWERTYUIOP"},
59 {0x1c, "\r"},
60 {0x1e, "ASDFGHJKL"},
61 {0x2c, "ZXCVBNM"},
62 {0x37, "*"},
63 {0x39, " "},
64 {0, NULL},
67 /* Characters for keys pressed without Shift, for those keys
68 where it matters. */
69 static const struct keymap unshifted_keymap[] =
71 {0x02, "1234567890-="},
72 {0x1a, "[]"},
73 {0x27, ";'`"},
74 {0x2b, "\\"},
75 {0x33, ",./"},
76 {0, NULL},
79 /* Characters for keys pressed with Shift, for those keys where
80 it matters. */
81 static const struct keymap shifted_keymap[] =
83 {0x02, "!@#$%^&*()_+"},
84 {0x1a, "{}"},
85 {0x27, ":\"~"},
86 {0x2b, "|"},
87 {0x33, "<>?"},
88 {0, NULL},
91 static bool map_key (const struct keymap[], unsigned scancode, uint8_t *);
93 static void
94 keyboard_interrupt (struct intr_frame *args UNUSED)
96 /* Status of shift keys. */
97 bool shift = left_shift || right_shift;
98 bool alt = left_alt || right_alt;
99 bool ctrl = left_ctrl || right_ctrl;
101 /* Keyboard scancode. */
102 unsigned code;
104 /* False if key pressed, true if key released. */
105 bool release;
107 /* Character that corresponds to `code'. */
108 uint8_t c;
110 /* Read scancode, including second byte if prefix code. */
111 code = inb (DATA_REG);
112 if (code == 0xe0)
113 code = (code << 8) | inb (DATA_REG);
115 /* Bit 0x80 distinguishes key press from key release
116 (even if there's a prefix). */
117 release = (code & 0x80) != 0;
118 code &= ~0x80u;
120 /* Interpret key. */
121 if (code == 0x3a)
123 /* Caps Lock. */
124 if (!release)
125 caps_lock = !caps_lock;
127 else if (map_key (invariant_keymap, code, &c)
128 || (!shift && map_key (unshifted_keymap, code, &c))
129 || (shift && map_key (shifted_keymap, code, &c)))
131 /* Ordinary character. */
132 if (!release)
134 /* Handle Ctrl, Shift.
135 Note that Ctrl overrides Shift. */
136 if (ctrl && c >= 0x40 && c < 0x60)
138 /* A is 0x41, Ctrl+A is 0x01, etc. */
139 c -= 0x40;
141 else if (shift == caps_lock)
142 c = tolower (c);
144 /* Handle Alt by setting the high bit.
145 This 0x80 is unrelated to the one used to
146 distinguish key press from key release. */
147 if (alt)
148 c += 0x80;
150 /* Append to keyboard buffer. */
151 if (!input_full ())
153 key_cnt++;
154 input_putc (c);
158 else
160 /* Maps a keycode into a shift state variable. */
161 struct shift_key
163 unsigned scancode;
164 bool *state_var;
167 /* Table of shift keys. */
168 static const struct shift_key shift_keys[] =
170 { 0x2a, &left_shift},
171 { 0x36, &right_shift},
172 { 0x38, &left_alt},
173 {0xe038, &right_alt},
174 { 0x1d, &left_ctrl},
175 {0xe01d, &right_ctrl},
176 {0, NULL},
179 const struct shift_key *key;
181 /* Scan the table. */
182 for (key = shift_keys; key->scancode != 0; key++)
183 if (key->scancode == code)
185 *key->state_var = !release;
186 break;
191 /* Scans the array of keymaps K for SCANCODE.
192 If found, sets *C to the corresponding character and returns
193 true.
194 If not found, returns false and C is ignored. */
195 static bool
196 map_key (const struct keymap k[], unsigned scancode, uint8_t *c)
198 for (; k->first_scancode != 0; k++)
199 if (scancode >= k->first_scancode
200 && scancode < k->first_scancode + strlen (k->chars))
202 *c = k->chars[scancode - k->first_scancode];
203 return true;
206 return false;