8 #include <api_drv_common.h>
9 #include <api_drv_keyboard.h>
13 #define KB_BUFFER_SIZE 1024
14 #define USE_KERNEL_MAGIC 1
17 extern void Threads_ToggleTrace(int TID);
18 extern void Threads_Dump(void);
19 extern void Heap_Stats(void);
22 int KB_Install(char **Arguments);
23 void KB_IRQHandler(int IRQNum);
24 void KB_AddBuffer(char ch);
25 Uint64 KB_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Dest);
26 void KB_UpdateLEDs(void);
27 int KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
30 tDevFS_Driver gKB_DevInfo = {
39 tKeybardCallback gKB_Callback = NULL;
40 Uint32 **gpKB_Map = gpKBDUS;
41 Uint8 gbaKB_States[3][256];
42 int gbKB_ShiftState = 0;
43 int gbKB_CapsState = 0;
45 int giKB_KeyLayer = 0;
47 int gbKB_MagicState = 0;
48 int giKB_MagicAddress = 0;
49 int giKB_MagicAddressPos = 0;
54 * \brief Install the keyboard driver
56 int KB_Install(char **Arguments)
59 IRQ_AddHandler(1, KB_IRQHandler);
63 // Attempt to get around a strange bug in Bochs/Qemu by toggling
64 // the controller on and off
66 outb(0x61, temp | 0x80);
67 outb(0x61, temp & 0x7F);
68 inb(0x60); // Clear keyboard buffer
71 DevFS_AddDevice( &gKB_DevInfo );
72 //Log("KB_Install: Installed");
77 * \brief Called on a keyboard IRQ
78 * \param IRQNum IRQ number (unused)
80 void KB_IRQHandler(int IRQNum)
86 // Check port 0x64 to tell if this is from the aux port
87 //if( inb(0x64) & 0x20 ) return;
89 scancode = inb(0x60); // Read from the keyboard's data buffer
90 //Log_Debug("Keyboard", "scancode = %02x", scancode);
93 if(scancode == 0xFA) {
94 // Oh man! This is anarchic (I'm leaving it here to represent
95 // the mess that Acess once was)
96 //kb_lastChar = KB_ACK;
101 if(scancode == 0xE0) {
106 if(scancode == 0xE1) {
126 ch = gpKB_Map[giKB_KeyLayer][scancode];
127 // Check for unknown key
128 if(!ch && !gbKB_KeyUp)
129 Log_Warning("Keyboard", "UNK %i %x", giKB_KeyLayer, scancode);
135 gbaKB_States[giKB_KeyLayer][scancode] = 0; // Unset key state flag
138 if(ch == KEY_LCTRL) gbKB_MagicState &= ~1;
139 if(ch == KEY_LALT) gbKB_MagicState &= ~2;
142 if(ch == KEY_LSHIFT) gbKB_ShiftState &= ~1;
143 if(ch == KEY_RSHIFT) gbKB_ShiftState &= ~2;
146 if(ch != 0 && gKB_Callback)
147 gKB_Callback( ch & 0x80000000 );
154 // Set the bit relating to the key
155 gbaKB_States[giKB_KeyLayer][scancode] = 1;
156 // Set shift key bits
157 if(ch == KEY_LSHIFT) gbKB_ShiftState |= 1;
158 if(ch == KEY_RSHIFT) gbKB_ShiftState |= 2;
160 // Check for Caps Lock
161 if(ch == KEY_CAPSLOCK) {
162 gbKB_CapsState = !gbKB_CapsState;
169 // Ignore Non-Printable Characters
172 // --- Check for Kernel Magic Combos
174 if(ch == KEY_LCTRL) {
175 gbKB_MagicState |= 1;
176 //Log_Log("Keyboard", "Kernel Magic LCTRL Down\n");
179 gbKB_MagicState |= 2;
180 //Log_Log("Keyboard", "Kernel Magic LALT Down\n");
182 if(gbKB_MagicState == 3)
186 case '0': case '1': case '2': case '3':
187 case '4': case '5': case '6': case '7':
188 case '8': case '9': case 'a': case 'b':
189 case 'c': case 'd': case 'e': case 'f':
191 char str[4] = {'0', 'x', ch, 0};
192 if(giKB_MagicAddressPos == BITS/4) return;
193 giKB_MagicAddress |= atoi(str) << giKB_MagicAddressPos;
194 giKB_MagicAddressPos ++;
198 // Instruction Tracing
200 Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
201 Threads_ToggleTrace( giKB_MagicAddress );
202 giKB_MagicAddress = 0; giKB_MagicAddressPos = 0;
206 case 'p': Threads_Dump(); return;
208 case 'h': Heap_Stats(); return;
215 // Capitals required?
216 if( (gbKB_ShiftState != 0) != (gbKB_CapsState != 0))
218 // TODO: Move this to the keyboard map header
222 case '`': ch = '~'; break;
223 case '1': ch = '!'; break;
224 case '2': ch = '@'; break;
225 case '3': ch = '#'; break;
226 case '4': ch = '$'; break;
227 case '5': ch = '%'; break;
228 case '6': ch = '^'; break;
229 case '7': ch = '&'; break;
230 case '8': ch = '*'; break;
231 case '9': ch = '('; break;
232 case '0': ch = ')'; break;
233 case '-': ch = '_'; break;
234 case '=': ch = '+'; break;
235 case '[': ch = '{'; break;
236 case ']': ch = '}'; break;
237 case '\\': ch = '|'; break;
238 case ';': ch = ':'; break;
239 case '\'': ch = '"'; break;
240 case ',': ch = '<'; break;
241 case '.': ch = '>'; break;
242 case '/': ch = '?'; break;
244 if('a' <= ch && ch <= 'z')
250 if(gKB_Callback && ch != 0) gKB_Callback(ch);
254 * \fn void KB_UpdateLEDs(void)
255 * \brief Updates the status of the keyboard LEDs
257 void KB_UpdateLEDs(void)
261 leds = (gbKB_CapsState ? 4 : 0);
263 while( inb(0x64) & 2 ); // Wait for bit 2 to unset
264 outb(0x60, 0xED); // Send update command
266 while( inb(0x64) & 2 ); // Wait for bit 2 to unset
270 static const char *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
273 * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
274 * \brief Calls an IOCtl Command
276 int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
280 BASE_IOCTLS(DRV_TYPE_KEYBOARD, "KB", 0x100, csaIOCTL_NAMES);
282 // Sets the Keyboard Callback
283 case KB_IOCTL_SETCALLBACK:
285 if((Uint)Data < KERNEL_BASE) return 0;
286 // Can only be set once
287 if(gKB_Callback != NULL) return 0;