3 * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
6 * This is free software. You are permitted to use,
7 * redistribute, and modify it as specified in the file "COPYING".
11 * Information sources:
12 * - Chapter 8 of _The Undocumented PC_, 2nd ed, by Frank van Gilluwe,
14 * - Pages 400-409 of _The Programmers PC Sourcebook_, by Thom Hogan,
20 * - Peter Gnodde <peter@pcswebdesign.nl> added support for
21 * the CTRL and ALT modifiers
26 * - Right now we're assuming an 83-key keyboard.
27 * Should add support for 101+ keyboards.
28 * - Should toggle keyboard LEDs.
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>
42 static enum {TARGET_GEEKOS,TARGET_VMM} target = TARGET_VMM;
45 extern void deliver_key_to_vmm(uchar_t status, uchar_t scancode);
47 /* ----------------------------------------------------------------------
48 * Private data and functions
49 * ---------------------------------------------------------------------- */
52 * Current shift state.
54 #define LEFT_SHIFT 0x01
55 #define RIGHT_SHIFT 0x02
56 #define LEFT_CTRL 0x04
57 #define RIGHT_CTRL 0x08
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;
66 * Queue for keycodes, in case they arrive faster than consumer
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;
76 * Wait queue for thread(s) waiting for keyboard events.
78 static struct Thread_Queue s_waitQueue;
81 * Translate from scan code to key code, when shift is not pressed.
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 */
107 #define SCAN_TABLE_SIZE (sizeof(s_scanTableNoShift) / sizeof(Keycode))
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.
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 */
139 static __inline__ bool Is_Queue_Empty(void)
141 return s_queueHead == s_queueTail;
144 static __inline__ bool Is_Queue_Full(void)
146 return NEXT(s_queueTail) == s_queueHead;
149 static __inline__ void Enqueue_Keycode(Keycode keycode)
151 if (!Is_Queue_Full()) {
152 s_queue[ s_queueTail ] = keycode;
153 s_queueTail = NEXT(s_queueTail);
157 static __inline__ Keycode Dequeue_Keycode(void)
160 KASSERT(!Is_Queue_Empty());
161 result = s_queue[ s_queueHead ];
162 s_queueHead = NEXT(s_queueHead);
167 * Handler for keyboard interrupts.
169 static void Keyboard_Interrupt_Handler(struct Interrupt_State* state)
171 uchar_t raw_status, raw_scancode;
173 uchar_t status, scanCode;
175 bool release = false, shift;
181 //Print("Keyboard\n");
184 status = In_Byte(KB_CMD);
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);
197 * Print("code=%x%s\n", scanCode, (scanCode&0x80) ? " [release]" : "");
200 if (scanCode & KB_KEY_RELEASE) {
202 scanCode &= ~(KB_KEY_RELEASE);
205 if (scanCode >= SCAN_TABLE_SIZE) {
206 Print("Unknown scan code: %x\n", scanCode);
210 /* Process the key */
211 shift = ((s_shiftState & SHIFT_MASK) != 0);
212 keycode = shift ? s_scanTableWithShift[scanCode] : s_scanTableNoShift[scanCode];
216 /* Update shift, control and alt state */
241 s_shiftState &= ~(flag);
243 s_shiftState |= flag;
246 * Shift, control and alt keys don't have to be
247 * queued, flags will be set!
251 goto skip_flagchange;
254 /* Format the new keycode */
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;
262 keycode |= KEY_RELEASE_FLAG;
267 if (target==TARGET_GEEKOS) {
268 if (raw_scancode==0xc4) { // F10 release
269 Print("Switching keyboard to VMM\n");
275 /* Put the keycode in the buffer */
276 Enqueue_Keycode(keycode);
278 /* Wake up event consumers */
279 Wake_Up(&s_waitQueue);
282 * Pick a new thread upon return from interrupt
283 * (hopefully the one waiting for the keyboard event)
285 g_needReschedule = true;
287 } else if (target==TARGET_VMM) {
288 if (raw_scancode==0xc4) { // F10 release
289 Print("Switching keyboard to GeekOS\n");
290 target=TARGET_GEEKOS;
292 deliver_key_to_vmm(raw_status,raw_scancode);
302 /* ----------------------------------------------------------------------
304 * ---------------------------------------------------------------------- */
306 void Init_Keyboard(void)
310 Print("Initializing keyboard...\n");
312 /* Start out with no shift keys enabled. */
315 /* Buffer is initially empty. */
316 s_queueHead = s_queueTail = 0;
318 /* Install interrupt handler */
319 Install_IRQ(KB_IRQ, Keyboard_Interrupt_Handler);
321 /* Enable IRQ1 (keyboard) */
322 irqMask = Get_IRQ_Mask();
323 irqMask &= ~(1 << KB_IRQ);
324 Set_IRQ_Mask(irqMask);
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
334 bool Read_Key(Keycode* keycode)
338 iflag = Begin_Int_Atomic();
340 result = !Is_Queue_Empty();
342 *keycode = Dequeue_Keycode();
345 End_Int_Atomic(iflag);
351 * Wait for a keycode to arrive.
352 * Uses the keyboard wait queue to sleep until
355 Keycode Wait_For_Key(void)
358 Keycode keycode = KEY_UNKNOWN;
360 iflag = Begin_Int_Atomic();
363 gotKey = !Is_Queue_Empty();
365 keycode = Dequeue_Keycode();
371 End_Int_Atomic(iflag);