4d7dfdf1a315df6cd3b92564c2719bc815d694de
[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/input.h"
7 #include "threads/interrupt.h"
8 #include "threads/io.h"
9
10 /* Keyboard data register port. */
11 #define DATA_REG 0x60
12
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. */
18
19 /* Status of Caps Lock.
20    True when on, false when off. */
21 static bool caps_lock;
22
23 /* Number of keys pressed. */
24 static int64_t key_cnt;
25
26 static intr_handler_func keyboard_interrupt;
27
28 /* Initializes the keyboard. */
29 void
30 kbd_init (void) 
31 {
32   intr_register_ext (0x21, keyboard_interrupt, "8042 Keyboard");
33 }
34
35 /* Prints keyboard statistics. */
36 void
37 kbd_print_stats (void) 
38 {
39   printf ("Keyboard: %lld keys pressed\n", key_cnt);
40 }
41 \f
42 /* Maps a set of contiguous scancodes into characters. */
43 struct keymap
44   {
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. */
49   };
50   
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[] = 
55   {
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},
65   };
66
67 /* Characters for keys pressed without Shift, for those keys
68    where it matters. */
69 static const struct keymap unshifted_keymap[] = 
70   {
71     {0x02, "1234567890-="},
72     {0x1a, "[]"},
73     {0x27, ";'`"},
74     {0x2b, "\\"},
75     {0x33, ",./"},
76     {0, NULL},
77   };
78   
79 /* Characters for keys pressed with Shift, for those keys where
80    it matters. */
81 static const struct keymap shifted_keymap[] = 
82   {
83     {0x02, "!@#$%^&*()_+"},
84     {0x1a, "{}"},
85     {0x27, ":\"~"},
86     {0x2b, "|"},
87     {0x33, "<>?"},
88     {0, NULL},
89   };
90
91 static bool map_key (const struct keymap[], unsigned scancode, uint8_t *);
92
93 static void
94 keyboard_interrupt (struct intr_frame *args UNUSED) 
95 {
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;
100
101   /* Keyboard scancode. */
102   unsigned code;
103
104   /* False if key pressed, true if key released. */
105   bool release;
106
107   /* Character that corresponds to `code'. */
108   uint8_t c;
109
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);
114
115   /* Bit 0x80 distinguishes key press from key release
116      (even if there's a prefix). */
117   release = (code & 0x80) != 0;
118   code &= ~0x80u;
119
120   /* Interpret key. */
121   if (code == 0x3a) 
122     {
123       /* Caps Lock. */
124       if (!release)
125         caps_lock = !caps_lock;
126     }
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)))
130     {
131       /* Ordinary character. */
132       if (!release) 
133         {
134           /* Handle Ctrl, Shift.
135              Note that Ctrl overrides Shift. */
136           if (ctrl && c >= 0x40 && c < 0x60) 
137             {
138               /* A is 0x41, Ctrl+A is 0x01, etc. */
139               c -= 0x40; 
140             }
141           else if (shift == caps_lock)
142             c = tolower (c);
143
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;
149
150           /* Append to keyboard buffer. */
151           if (!input_full ())
152             {
153               key_cnt++;
154               input_putc (c);
155             }
156         }
157     }
158   else
159     {
160       /* Maps a keycode into a shift state variable. */
161       struct shift_key 
162         {
163           unsigned scancode;
164           bool *state_var;
165         };
166
167       /* Table of shift keys. */
168       static const struct shift_key shift_keys[] = 
169         {
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},
177         };
178   
179       const struct shift_key *key;
180
181       /* Scan the table. */
182       for (key = shift_keys; key->scancode != 0; key++) 
183         if (key->scancode == code)
184           {
185             *key->state_var = !release;
186             break;
187           }
188     }
189 }
190
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) 
197 {
198   for (; k->first_scancode != 0; k++)
199     if (scancode >= k->first_scancode
200         && scancode < k->first_scancode + strlen (k->chars)) 
201       {
202         *c = k->chars[scancode - k->first_scancode];
203         return true; 
204       }
205
206   return false;
207 }