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.


First cut at a keyboard device (partially done)
[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.2 $
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     Print("Keybaord\n");
170
171     status = In_Byte(KB_CMD);
172     IO_Delay();
173
174     if ((status & KB_OUTPUT_FULL) != 0) {
175         /* There is a byte available */
176         scanCode = In_Byte(KB_DATA);
177         IO_Delay();
178 /*
179  *      Print("code=%x%s\n", scanCode, (scanCode&0x80) ? " [release]" : "");
180  */
181
182         if (scanCode & KB_KEY_RELEASE) {
183             release = true;
184             scanCode &= ~(KB_KEY_RELEASE);
185         }
186
187         if (scanCode >= SCAN_TABLE_SIZE) {
188             Print("Unknown scan code: %x\n", scanCode);
189             goto done;
190         }
191
192         /* Process the key */
193         shift = ((s_shiftState & SHIFT_MASK) != 0);
194         keycode = shift ? s_scanTableWithShift[scanCode] : s_scanTableNoShift[scanCode];
195
196         /* Update shift, control and alt state */
197         switch (keycode) {
198         case KEY_LSHIFT:
199             flag = LEFT_SHIFT;
200             break;
201         case KEY_RSHIFT:
202             flag = RIGHT_SHIFT;
203             break;
204         case KEY_LCTRL:
205             flag = LEFT_CTRL;
206             break;
207         case KEY_RCTRL:
208             flag = RIGHT_CTRL;
209             break;
210         case KEY_LALT:
211             flag = LEFT_ALT;
212             break;
213         case KEY_RALT:
214             flag = RIGHT_ALT;
215             break;
216         default:
217             goto noflagchange;
218         }
219
220         if (release)
221             s_shiftState &= ~(flag);
222         else
223             s_shiftState |= flag;
224                         
225         /*
226          * Shift, control and alt keys don't have to be
227          * queued, flags will be set!
228          */
229         goto done;
230
231 noflagchange:
232         /* Format the new keycode */
233         if (shift)
234             keycode |= KEY_SHIFT_FLAG;
235         if ((s_shiftState & CTRL_MASK) != 0)
236             keycode |= KEY_CTRL_FLAG;
237         if ((s_shiftState & ALT_MASK) != 0)
238             keycode |= KEY_ALT_FLAG;
239         if (release)
240             keycode |= KEY_RELEASE_FLAG;
241                 
242         /* Put the keycode in the buffer */
243         Enqueue_Keycode(keycode);
244
245         /* Wake up event consumers */
246         Wake_Up(&s_waitQueue);
247
248         /*
249          * Pick a new thread upon return from interrupt
250          * (hopefully the one waiting for the keyboard event)
251          */
252         g_needReschedule = true;
253     }
254
255 done:
256     End_IRQ(state);
257 }
258
259 /* ----------------------------------------------------------------------
260  * Public functions
261  * ---------------------------------------------------------------------- */
262
263 void Init_Keyboard(void)
264 {
265     ushort_t irqMask;
266
267     Print("Initializing keyboard...\n");
268
269     /* Start out with no shift keys enabled. */
270     s_shiftState = 0;
271
272     /* Buffer is initially empty. */
273     s_queueHead = s_queueTail = 0;
274
275     /* Install interrupt handler */
276     Install_IRQ(KB_IRQ, Keyboard_Interrupt_Handler);
277
278     /* Enable IRQ1 (keyboard) */
279     irqMask = Get_IRQ_Mask();
280     irqMask &= ~(1 << KB_IRQ);
281     Set_IRQ_Mask(irqMask);
282 }
283
284 /*
285  * Poll for a key event.
286  * Returns true if a key is available,
287  * false if not.  If a key event is available,
288  * it will be stored in the location pointed to
289  * by keycode.
290  */
291 bool Read_Key(Keycode* keycode)
292 {
293     bool result, iflag;
294
295     iflag = Begin_Int_Atomic();
296
297     result = !Is_Queue_Empty();
298     if (result) {
299         *keycode = Dequeue_Keycode();
300     }
301
302     End_Int_Atomic(iflag);
303
304     return result;
305 }
306
307 /*
308  * Wait for a keycode to arrive.
309  * Uses the keyboard wait queue to sleep until
310  * a keycode arrives.
311  */
312 Keycode Wait_For_Key(void)
313 {
314     bool gotKey, iflag;
315     Keycode keycode = KEY_UNKNOWN;
316
317     iflag = Begin_Int_Atomic();
318
319     do {
320         gotKey = !Is_Queue_Empty();
321         if (gotKey)
322             keycode = Dequeue_Keycode();
323         else
324             Wait(&s_waitQueue);
325     }
326     while (!gotKey);
327
328     End_Int_Atomic(iflag);
329
330     return keycode;
331 }