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.


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