Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


(no commit message)
[palacios.git] / palacios / src / geekos / keyboard.c
1 /*
2  * Keyboard driver
3  * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
4  * $Revision: 1.1.1.1 $
5  * 
6  * This is free software.  You are permitted to use,
7  * redistribute, and modify it as specified in the file "COPYING".
8  */
9
10 /*
11  * Information sources:
12  * - Chapter 8 of _The Undocumented PC_, 2nd ed, by Frank van Gilluwe,
13  *   ISBN 0-201-47950-8.
14  * - Pages 400-409 of _The Programmers PC Sourcebook_, by Thom Hogan,
15  *   ISBN 1-55615-118-7.
16  */
17
18 /*
19  * Credits:
20  * - Peter Gnodde <peter@pcswebdesign.nl> added support for
21  *   the CTRL and ALT modifiers
22  */
23
24 /*
25  * TODO list:
26  * - Right now we're assuming an 83-key keyboard.
27  *   Should add support for 101+ keyboards.
28  * - Should toggle keyboard LEDs.
29  */
30
31 #include <geekos/kthread.h>
32 #include <geekos/kassert.h>
33 #include <geekos/screen.h>
34 #include <geekos/irq.h>
35 #include <geekos/io.h>
36 #include <geekos/keyboard.h>
37
38 /* ----------------------------------------------------------------------
39  * Private data and functions
40  * ---------------------------------------------------------------------- */
41
42 /*
43  * Current shift state.
44  */
45 #define LEFT_SHIFT  0x01
46 #define RIGHT_SHIFT 0x02
47 #define LEFT_CTRL   0x04
48 #define RIGHT_CTRL  0x08
49 #define LEFT_ALT    0x10
50 #define RIGHT_ALT   0x20
51 #define SHIFT_MASK  (LEFT_SHIFT | RIGHT_SHIFT)
52 #define CTRL_MASK   (LEFT_CTRL | RIGHT_CTRL)
53 #define ALT_MASK    (LEFT_ALT | RIGHT_ALT)
54 static unsigned s_shiftState = 0;
55
56 /*
57  * Queue for keycodes, in case they arrive faster than consumer
58  * can deal with them.
59  */
60 #define QUEUE_SIZE 256
61 #define QUEUE_MASK 0xff
62 #define NEXT(index) (((index) + 1) & QUEUE_MASK)
63 static Keycode s_queue[QUEUE_SIZE];
64 static int s_queueHead, s_queueTail;
65
66 /*
67  * Wait queue for thread(s) waiting for keyboard events.
68  */
69 static struct Thread_Queue s_waitQueue;
70
71 /*
72  * Translate from scan code to key code, when shift is not pressed.
73  */
74 static const Keycode s_scanTableNoShift[] = {
75     KEY_UNKNOWN, ASCII_ESC, '1', '2',   /* 0x00 - 0x03 */
76     '3', '4', '5', '6',                 /* 0x04 - 0x07 */
77     '7', '8', '9', '0',                 /* 0x08 - 0x0B */
78     '-', '=', ASCII_BS, '\t',           /* 0x0C - 0x0F */
79     'q', 'w', 'e', 'r',                 /* 0x10 - 0x13 */
80     't', 'y', 'u', 'i',                 /* 0x14 - 0x17 */
81     'o', 'p', '[', ']',                 /* 0x18 - 0x1B */
82     '\r', KEY_LCTRL, 'a', 's',          /* 0x1C - 0x1F */
83     'd', 'f', 'g', 'h',                 /* 0x20 - 0x23 */
84     'j', 'k', 'l', ';',                 /* 0x24 - 0x27 */
85     '\'', '`', KEY_LSHIFT, '\\',        /* 0x28 - 0x2B */
86     'z', 'x', 'c', 'v',                 /* 0x2C - 0x2F */
87     'b', 'n', 'm', ',',                 /* 0x30 - 0x33 */
88     '.', '/', KEY_RSHIFT, KEY_PRINTSCRN, /* 0x34 - 0x37 */
89     KEY_LALT, ' ', KEY_CAPSLOCK, KEY_F1, /* 0x38 - 0x3B */
90     KEY_F2, KEY_F3, KEY_F4, KEY_F5,     /* 0x3C - 0x3F */
91     KEY_F6, KEY_F7, KEY_F8, KEY_F9,     /* 0x40 - 0x43 */
92     KEY_F10, KEY_NUMLOCK, KEY_SCRLOCK, KEY_KPHOME,  /* 0x44 - 0x47 */
93     KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS, KEY_KPLEFT,  /* 0x48 - 0x4B */
94     KEY_KPCENTER, KEY_KPRIGHT, KEY_KPPLUS, KEY_KPEND,  /* 0x4C - 0x4F */
95     KEY_KPDOWN, KEY_KPPGDN, KEY_KPINSERT, KEY_KPDEL,  /* 0x50 - 0x53 */
96     KEY_SYSREQ, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,  /* 0x54 - 0x57 */
97 };
98 #define SCAN_TABLE_SIZE (sizeof(s_scanTableNoShift) / sizeof(Keycode))
99
100 /*
101  * Translate from scan code to key code, when shift *is* pressed.
102  * Keep this in sync with the unshifted table above!
103  * They must be the same size.
104  */
105 static const Keycode s_scanTableWithShift[] = {
106     KEY_UNKNOWN, ASCII_ESC, '!', '@',   /* 0x00 - 0x03 */
107     '#', '$', '%', '^',                 /* 0x04 - 0x07 */
108     '&', '*', '(', ')',                 /* 0x08 - 0x0B */
109     '_', '+', ASCII_BS, '\t',           /* 0x0C - 0x0F */
110     'Q', 'W', 'E', 'R',                 /* 0x10 - 0x13 */
111     'T', 'Y', 'U', 'I',                 /* 0x14 - 0x17 */
112     'O', 'P', '{', '}',                 /* 0x18 - 0x1B */
113     '\r', KEY_LCTRL, 'A', 'S',          /* 0x1C - 0x1F */
114     'D', 'F', 'G', 'H',                 /* 0x20 - 0x23 */
115     'J', 'K', 'L', ':',                 /* 0x24 - 0x27 */
116     '"', '~', KEY_LSHIFT, '|',          /* 0x28 - 0x2B */
117     'Z', 'X', 'C', 'V',                 /* 0x2C - 0x2F */
118     'B', 'N', 'M', '<',                 /* 0x30 - 0x33 */
119     '>', '?', KEY_RSHIFT, KEY_PRINTSCRN, /* 0x34 - 0x37 */
120     KEY_LALT, ' ', KEY_CAPSLOCK, KEY_F1, /* 0x38 - 0x3B */
121     KEY_F2, KEY_F3, KEY_F4, KEY_F5,     /* 0x3C - 0x3F */
122     KEY_F6, KEY_F7, KEY_F8, KEY_F9,     /* 0x40 - 0x43 */
123     KEY_F10, KEY_NUMLOCK, KEY_SCRLOCK, KEY_KPHOME,  /* 0x44 - 0x47 */
124     KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS, KEY_KPLEFT,  /* 0x48 - 0x4B */
125     KEY_KPCENTER, KEY_KPRIGHT, KEY_KPPLUS, KEY_KPEND,  /* 0x4C - 0x4F */
126     KEY_KPDOWN, KEY_KPPGDN, KEY_KPINSERT, KEY_KPDEL,  /* 0x50 - 0x53 */
127     KEY_SYSREQ, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,  /* 0x54 - 0x57 */
128 };
129
130 static __inline__ bool Is_Queue_Empty(void)
131 {
132     return s_queueHead == s_queueTail;
133 }
134
135 static __inline__ bool Is_Queue_Full(void)
136 {
137     return NEXT(s_queueTail) == s_queueHead;
138 }
139
140 static __inline__ void Enqueue_Keycode(Keycode keycode)
141 {
142     if (!Is_Queue_Full()) {
143         s_queue[ s_queueTail ] = keycode;
144         s_queueTail = NEXT(s_queueTail);
145     }
146 }
147
148 static __inline__ Keycode Dequeue_Keycode(void)
149 {
150     Keycode result;
151     KASSERT(!Is_Queue_Empty());
152     result = s_queue[ s_queueHead ];
153     s_queueHead = NEXT(s_queueHead);
154     return result;
155 }
156
157 /*
158  * Handler for keyboard interrupts.
159  */
160 static void Keyboard_Interrupt_Handler(struct Interrupt_State* state)
161 {
162     uchar_t status, scanCode;
163     unsigned flag = 0;
164     bool release = false, shift;
165     Keycode keycode;
166
167     Begin_IRQ(state);
168
169     status = In_Byte(KB_CMD);
170     IO_Delay();
171
172     if ((status & KB_OUTPUT_FULL) != 0) {
173         /* There is a byte available */
174         scanCode = In_Byte(KB_DATA);
175         IO_Delay();
176 /*
177  *      Print("code=%x%s\n", scanCode, (scanCode&0x80) ? " [release]" : "");
178  */
179
180         if (scanCode & KB_KEY_RELEASE) {
181             release = true;
182             scanCode &= ~(KB_KEY_RELEASE);
183         }
184
185         if (scanCode >= SCAN_TABLE_SIZE) {
186             Print("Unknown scan code: %x\n", scanCode);
187             goto done;
188         }
189
190         /* Process the key */
191         shift = ((s_shiftState & SHIFT_MASK) != 0);
192         keycode = shift ? s_scanTableWithShift[scanCode] : s_scanTableNoShift[scanCode];
193
194         /* Update shift, control and alt state */
195         switch (keycode) {
196         case KEY_LSHIFT:
197             flag = LEFT_SHIFT;
198             break;
199         case KEY_RSHIFT:
200             flag = RIGHT_SHIFT;
201             break;
202         case KEY_LCTRL:
203             flag = LEFT_CTRL;
204             break;
205         case KEY_RCTRL:
206             flag = RIGHT_CTRL;
207             break;
208         case KEY_LALT:
209             flag = LEFT_ALT;
210             break;
211         case KEY_RALT:
212             flag = RIGHT_ALT;
213             break;
214         default:
215             goto noflagchange;
216         }
217
218         if (release)
219             s_shiftState &= ~(flag);
220         else
221             s_shiftState |= flag;
222                         
223         /*
224          * Shift, control and alt keys don't have to be
225          * queued, flags will be set!
226          */
227         goto done;
228
229 noflagchange:
230         /* Format the new keycode */
231         if (shift)
232             keycode |= KEY_SHIFT_FLAG;
233         if ((s_shiftState & CTRL_MASK) != 0)
234             keycode |= KEY_CTRL_FLAG;
235         if ((s_shiftState & ALT_MASK) != 0)
236             keycode |= KEY_ALT_FLAG;
237         if (release)
238             keycode |= KEY_RELEASE_FLAG;
239                 
240         /* Put the keycode in the buffer */
241         Enqueue_Keycode(keycode);
242
243         /* Wake up event consumers */
244         Wake_Up(&s_waitQueue);
245
246         /*
247          * Pick a new thread upon return from interrupt
248          * (hopefully the one waiting for the keyboard event)
249          */
250         g_needReschedule = true;
251     }
252
253 done:
254     End_IRQ(state);
255 }
256
257 /* ----------------------------------------------------------------------
258  * Public functions
259  * ---------------------------------------------------------------------- */
260
261 void Init_Keyboard(void)
262 {
263     ushort_t irqMask;
264
265     Print("Initializing keyboard...\n");
266
267     /* Start out with no shift keys enabled. */
268     s_shiftState = 0;
269
270     /* Buffer is initially empty. */
271     s_queueHead = s_queueTail = 0;
272
273     /* Install interrupt handler */
274     Install_IRQ(KB_IRQ, Keyboard_Interrupt_Handler);
275
276     /* Enable IRQ1 (keyboard) */
277     irqMask = Get_IRQ_Mask();
278     irqMask &= ~(1 << KB_IRQ);
279     Set_IRQ_Mask(irqMask);
280 }
281
282 /*
283  * Poll for a key event.
284  * Returns true if a key is available,
285  * false if not.  If a key event is available,
286  * it will be stored in the location pointed to
287  * by keycode.
288  */
289 bool Read_Key(Keycode* keycode)
290 {
291     bool result, iflag;
292
293     iflag = Begin_Int_Atomic();
294
295     result = !Is_Queue_Empty();
296     if (result) {
297         *keycode = Dequeue_Keycode();
298     }
299
300     End_Int_Atomic(iflag);
301
302     return result;
303 }
304
305 /*
306  * Wait for a keycode to arrive.
307  * Uses the keyboard wait queue to sleep until
308  * a keycode arrives.
309  */
310 Keycode Wait_For_Key(void)
311 {
312     bool gotKey, iflag;
313     Keycode keycode = KEY_UNKNOWN;
314
315     iflag = Begin_Int_Atomic();
316
317     do {
318         gotKey = !Is_Queue_Empty();
319         if (gotKey)
320             keycode = Dequeue_Keycode();
321         else
322             Wait(&s_waitQueue);
323     }
324     while (!gotKey);
325
326     End_Int_Atomic(iflag);
327
328     return keycode;
329 }