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.


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