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.


21987b990c10cf3df5f8c1514d14607a7c153185
[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.5 $
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 static enum {TARGET_GEEKOS,TARGET_VMM} target=TARGET_VMM;
40
41 extern void deliver_key_to_vmm(uchar_t status, uchar_t scancode);
42
43 /* ----------------------------------------------------------------------
44  * Private data and functions
45  * ---------------------------------------------------------------------- */
46
47 /*
48  * Current shift state.
49  */
50 #define LEFT_SHIFT  0x01
51 #define RIGHT_SHIFT 0x02
52 #define LEFT_CTRL   0x04
53 #define RIGHT_CTRL  0x08
54 #define LEFT_ALT    0x10
55 #define RIGHT_ALT   0x20
56 #define SHIFT_MASK  (LEFT_SHIFT | RIGHT_SHIFT)
57 #define CTRL_MASK   (LEFT_CTRL | RIGHT_CTRL)
58 #define ALT_MASK    (LEFT_ALT | RIGHT_ALT)
59 static unsigned s_shiftState = 0;
60
61 /*
62  * Queue for keycodes, in case they arrive faster than consumer
63  * can deal with them.
64  */
65 #define QUEUE_SIZE 256
66 #define QUEUE_MASK 0xff
67 #define NEXT(index) (((index) + 1) & QUEUE_MASK)
68 static Keycode s_queue[QUEUE_SIZE];
69 static int s_queueHead, s_queueTail;
70
71 /*
72  * Wait queue for thread(s) waiting for keyboard events.
73  */
74 static struct Thread_Queue s_waitQueue;
75
76 /*
77  * Translate from scan code to key code, when shift is not pressed.
78  */
79 static const Keycode s_scanTableNoShift[] = {
80     KEY_UNKNOWN, ASCII_ESC, '1', '2',   /* 0x00 - 0x03 */
81     '3', '4', '5', '6',                 /* 0x04 - 0x07 */
82     '7', '8', '9', '0',                 /* 0x08 - 0x0B */
83     '-', '=', ASCII_BS, '\t',           /* 0x0C - 0x0F */
84     'q', 'w', 'e', 'r',                 /* 0x10 - 0x13 */
85     't', 'y', 'u', 'i',                 /* 0x14 - 0x17 */
86     'o', 'p', '[', ']',                 /* 0x18 - 0x1B */
87     '\r', KEY_LCTRL, 'a', 's',          /* 0x1C - 0x1F */
88     'd', 'f', 'g', 'h',                 /* 0x20 - 0x23 */
89     'j', 'k', 'l', ';',                 /* 0x24 - 0x27 */
90     '\'', '`', KEY_LSHIFT, '\\',        /* 0x28 - 0x2B */
91     'z', 'x', 'c', 'v',                 /* 0x2C - 0x2F */
92     'b', 'n', 'm', ',',                 /* 0x30 - 0x33 */
93     '.', '/', KEY_RSHIFT, KEY_PRINTSCRN, /* 0x34 - 0x37 */
94     KEY_LALT, ' ', KEY_CAPSLOCK, KEY_F1, /* 0x38 - 0x3B */
95     KEY_F2, KEY_F3, KEY_F4, KEY_F5,     /* 0x3C - 0x3F */
96     KEY_F6, KEY_F7, KEY_F8, KEY_F9,     /* 0x40 - 0x43 */
97     KEY_F10, KEY_NUMLOCK, KEY_SCRLOCK, KEY_KPHOME,  /* 0x44 - 0x47 */
98     KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS, KEY_KPLEFT,  /* 0x48 - 0x4B */
99     KEY_KPCENTER, KEY_KPRIGHT, KEY_KPPLUS, KEY_KPEND,  /* 0x4C - 0x4F */
100     KEY_KPDOWN, KEY_KPPGDN, KEY_KPINSERT, KEY_KPDEL,  /* 0x50 - 0x53 */
101     KEY_SYSREQ, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,  /* 0x54 - 0x57 */
102 };
103 #define SCAN_TABLE_SIZE (sizeof(s_scanTableNoShift) / sizeof(Keycode))
104
105 /*
106  * Translate from scan code to key code, when shift *is* pressed.
107  * Keep this in sync with the unshifted table above!
108  * They must be the same size.
109  */
110 static const Keycode s_scanTableWithShift[] = {
111     KEY_UNKNOWN, ASCII_ESC, '!', '@',   /* 0x00 - 0x03 */
112     '#', '$', '%', '^',                 /* 0x04 - 0x07 */
113     '&', '*', '(', ')',                 /* 0x08 - 0x0B */
114     '_', '+', ASCII_BS, '\t',           /* 0x0C - 0x0F */
115     'Q', 'W', 'E', 'R',                 /* 0x10 - 0x13 */
116     'T', 'Y', 'U', 'I',                 /* 0x14 - 0x17 */
117     'O', 'P', '{', '}',                 /* 0x18 - 0x1B */
118     '\r', KEY_LCTRL, 'A', 'S',          /* 0x1C - 0x1F */
119     'D', 'F', 'G', 'H',                 /* 0x20 - 0x23 */
120     'J', 'K', 'L', ':',                 /* 0x24 - 0x27 */
121     '"', '~', KEY_LSHIFT, '|',          /* 0x28 - 0x2B */
122     'Z', 'X', 'C', 'V',                 /* 0x2C - 0x2F */
123     'B', 'N', 'M', '<',                 /* 0x30 - 0x33 */
124     '>', '?', KEY_RSHIFT, KEY_PRINTSCRN, /* 0x34 - 0x37 */
125     KEY_LALT, ' ', KEY_CAPSLOCK, KEY_F1, /* 0x38 - 0x3B */
126     KEY_F2, KEY_F3, KEY_F4, KEY_F5,     /* 0x3C - 0x3F */
127     KEY_F6, KEY_F7, KEY_F8, KEY_F9,     /* 0x40 - 0x43 */
128     KEY_F10, KEY_NUMLOCK, KEY_SCRLOCK, KEY_KPHOME,  /* 0x44 - 0x47 */
129     KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS, KEY_KPLEFT,  /* 0x48 - 0x4B */
130     KEY_KPCENTER, KEY_KPRIGHT, KEY_KPPLUS, KEY_KPEND,  /* 0x4C - 0x4F */
131     KEY_KPDOWN, KEY_KPPGDN, KEY_KPINSERT, KEY_KPDEL,  /* 0x50 - 0x53 */
132     KEY_SYSREQ, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,  /* 0x54 - 0x57 */
133 };
134
135 static __inline__ bool Is_Queue_Empty(void)
136 {
137     return s_queueHead == s_queueTail;
138 }
139
140 static __inline__ bool Is_Queue_Full(void)
141 {
142     return NEXT(s_queueTail) == s_queueHead;
143 }
144
145 static __inline__ void Enqueue_Keycode(Keycode keycode)
146 {
147     if (!Is_Queue_Full()) {
148         s_queue[ s_queueTail ] = keycode;
149         s_queueTail = NEXT(s_queueTail);
150     }
151 }
152
153 static __inline__ Keycode Dequeue_Keycode(void)
154 {
155     Keycode result;
156     KASSERT(!Is_Queue_Empty());
157     result = s_queue[ s_queueHead ];
158     s_queueHead = NEXT(s_queueHead);
159     return result;
160 }
161
162 /*
163  * Handler for keyboard interrupts.
164  */
165 static void Keyboard_Interrupt_Handler(struct Interrupt_State* state)
166 {
167   uchar_t raw_status, raw_scancode;
168
169     uchar_t status, scanCode;
170     unsigned flag = 0;
171     bool release = false, shift;
172     Keycode keycode;
173     bool flagchange;
174
175     Begin_IRQ(state);
176
177     //Print("Keyboard\n");
178
179     status = In_Byte(KB_CMD);
180     
181     raw_status=status;
182
183     IO_Delay();
184
185     if ((status & KB_OUTPUT_FULL) != 0) {
186       /* There is a byte available */
187       scanCode = In_Byte(KB_DATA);
188       raw_scancode=scanCode;
189       //Print("Keyboard: status=0x%x, scancode=0x%x\n", raw_status, raw_scancode);
190       IO_Delay();
191       /*
192        *        Print("code=%x%s\n", scanCode, (scanCode&0x80) ? " [release]" : "");
193        */
194         
195       if (scanCode & KB_KEY_RELEASE) {
196         release = true;
197         scanCode &= ~(KB_KEY_RELEASE);
198       }
199       
200       if (scanCode >= SCAN_TABLE_SIZE) {
201         Print("Unknown scan code: %x\n", scanCode);
202         goto done;
203       }
204       
205       /* Process the key */
206       shift = ((s_shiftState & SHIFT_MASK) != 0);
207       keycode = shift ? s_scanTableWithShift[scanCode] : s_scanTableNoShift[scanCode];
208
209       flagchange=false;
210       
211       /* Update shift, control and alt state */
212       switch (keycode) {
213       case KEY_LSHIFT:
214         flag = LEFT_SHIFT;
215         break;
216       case KEY_RSHIFT:
217         flag = RIGHT_SHIFT;
218         break;
219       case KEY_LCTRL:
220         flag = LEFT_CTRL;
221         break;
222       case KEY_RCTRL:
223         flag = RIGHT_CTRL;
224         break;
225       case KEY_LALT:
226         flag = LEFT_ALT;
227         break;
228       case KEY_RALT:
229         flag = RIGHT_ALT;
230         break;
231       default:
232         goto noflagchange;
233       }
234       
235       if (release)
236         s_shiftState &= ~(flag);
237       else
238         s_shiftState |= flag;
239       
240       /*
241        * Shift, control and alt keys don't have to be
242        * queued, flags will be set!
243        */
244       // huh?
245       flagchange=true;
246       goto skip_flagchange;
247       
248 noflagchange:
249       /* Format the new keycode */
250       if (shift)
251         keycode |= KEY_SHIFT_FLAG;
252       if ((s_shiftState & CTRL_MASK) != 0)
253         keycode |= KEY_CTRL_FLAG;
254       if ((s_shiftState & ALT_MASK) != 0)
255         keycode |= KEY_ALT_FLAG;
256       if (release)
257         keycode |= KEY_RELEASE_FLAG;
258       
259       
260 skip_flagchange:
261
262       if (target==TARGET_GEEKOS) { 
263         if (raw_scancode==0xc4) {  // F10 release
264           Print("Switching keyboard to VMM\n");
265           target=TARGET_VMM;
266         } else {
267           if (flagchange) {
268             goto done;
269           }
270           /* Put the keycode in the buffer */
271           Enqueue_Keycode(keycode);
272           
273           /* Wake up event consumers */
274           Wake_Up(&s_waitQueue);
275           
276           /*
277            * Pick a new thread upon return from interrupt
278            * (hopefully the one waiting for the keyboard event)
279            */
280           g_needReschedule = true;
281         }
282       } else if (target==TARGET_VMM) { 
283         if (raw_scancode==0xc4) {   // F10 release
284           Print("Switching keyboard to GeekOS\n");
285           target=TARGET_GEEKOS;
286         } else {
287           deliver_key_to_vmm(raw_status,raw_scancode);
288         }
289       }
290     }
291
292  done:
293     End_IRQ(state);
294       
295 }
296
297 /* ----------------------------------------------------------------------
298  * Public functions
299  * ---------------------------------------------------------------------- */
300
301 void Init_Keyboard(void)
302 {
303     ushort_t irqMask;
304
305         Print("Initializing keyboard...\n");
306
307     /* Start out with no shift keys enabled. */
308     s_shiftState = 0;
309
310     /* Buffer is initially empty. */
311     s_queueHead = s_queueTail = 0;
312
313     /* Install interrupt handler */
314     Install_IRQ(KB_IRQ, Keyboard_Interrupt_Handler);
315
316     /* Enable IRQ1 (keyboard) */
317     irqMask = Get_IRQ_Mask();
318     irqMask &= ~(1 << KB_IRQ);
319     Set_IRQ_Mask(irqMask);
320 }
321
322 /*
323  * Poll for a key event.
324  * Returns true if a key is available,
325  * false if not.  If a key event is available,
326  * it will be stored in the location pointed to
327  * by keycode.
328  */
329 bool Read_Key(Keycode* keycode)
330 {
331     bool result, iflag;
332
333     iflag = Begin_Int_Atomic();
334
335     result = !Is_Queue_Empty();
336     if (result) {
337         *keycode = Dequeue_Keycode();
338     }
339
340     End_Int_Atomic(iflag);
341
342     return result;
343 }
344
345 /*
346  * Wait for a keycode to arrive.
347  * Uses the keyboard wait queue to sleep until
348  * a keycode arrives.
349  */
350 Keycode Wait_For_Key(void)
351 {
352     bool gotKey, iflag;
353     Keycode keycode = KEY_UNKNOWN;
354
355     iflag = Begin_Int_Atomic();
356
357     do {
358         gotKey = !Is_Queue_Empty();
359         if (gotKey)
360             keycode = Dequeue_Keycode();
361         else
362             Wait(&s_waitQueue);
363     }
364     while (!gotKey);
365
366     End_Int_Atomic(iflag);
367
368     return keycode;
369 }