8 #include <tpl_drv_common.h>
9 #include <tpl_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 MODULE_DEFINE(0, 0x0100, PS2Keyboard, KB_Install, NULL, NULL);
31 tDevFS_Driver gKB_DevInfo = {
40 tKeybardCallback gKB_Callback = NULL;
41 Uint32 **gpKB_Map = gpKBDUS;
42 Uint8 gbaKB_States[3][256];
43 int gbKB_ShiftState = 0;
44 int gbKB_CapsState = 0;
46 int giKB_KeyLayer = 0;
48 int gbKB_MagicState = 0;
49 int giKB_MagicAddress = 0;
50 int giKB_MagicAddressPos = 0;
52 //Uint64 giKB_ReadBase = 0;
53 //Uint32 gaKB_Buffer[KB_BUFFER_SIZE]; //!< Keyboard Ring Buffer
54 //volatile int giKB_InsertPoint = 0; //!< Writing location marker
55 //volatile int giKB_ReadPoint = 0; //!< Reading location marker
56 //volatile int giKB_InUse = 0; //!< Lock marker
60 * \brief Install the keyboard driver
62 int KB_Install(char **Arguments)
66 // Attempt to get around a strange bug in Bochs/Qemu by toggling
67 // the controller on and off
69 outb(0x61, temp | 0x80);
70 outb(0x61, temp & 0x7F);
71 inb(0x60); // Clear keyboard buffer
73 IRQ_AddHandler(1, KB_IRQHandler);
74 DevFS_AddDevice( &gKB_DevInfo );
75 //Log("KB_Install: Installed");
80 * \brief Called on a keyboard IRQ
81 * \param IRQNum IRQ number (unused)
83 void KB_IRQHandler(int IRQNum)
89 // Check port 0x64 to tell if this is from the aux port
90 //if( inb(0x64) & 0x20 ) return;
92 scancode = inb(0x60); // Read from the keyboard's data buffer
93 //Log_Debug("Keyboard", "scancode = %02x", scancode);
96 if(scancode == 0xFA) {
97 // Oh man! This is anarchic (I'm leaving it here to represent
98 // the mess that Acess once was)
99 //kb_lastChar = KB_ACK;
104 if(scancode == 0xE0) {
109 if(scancode == 0xE1) {
129 ch = gpKB_Map[giKB_KeyLayer][scancode];
130 //keyNum = giKB_KeyLayer * 256 + scancode;
131 // Check for unknown key
132 if(!ch && !gbKB_KeyUp)
133 Log_Warning("Keyboard", "UNK %i %x", giKB_KeyLayer, scancode);
139 gbaKB_States[giKB_KeyLayer][scancode] = 0; // Unset key state flag
142 if(ch == KEY_LCTRL) gbKB_MagicState &= ~1;
143 if(ch == KEY_LALT) gbKB_MagicState &= ~2;
146 if(ch == KEY_LSHIFT) gbKB_ShiftState &= ~1;
147 if(ch == KEY_RSHIFT) gbKB_ShiftState &= ~2;
150 if(ch != 0 && gKB_Callback)
151 gKB_Callback( ch & 0x80000000 );
158 // Set the bit relating to the key
159 gbaKB_States[giKB_KeyLayer][scancode] = 1;
160 // Set shift key bits
161 if(ch == KEY_LSHIFT) gbKB_ShiftState |= 1;
162 if(ch == KEY_RSHIFT) gbKB_ShiftState |= 2;
164 // Check for Caps Lock
165 if(ch == KEY_CAPSLOCK) {
166 gbKB_CapsState = !gbKB_CapsState;
173 // Ignore Non-Printable Characters
176 // --- Check for Kernel Magic Combos
178 if(ch == KEY_LCTRL) {
179 gbKB_MagicState |= 1;
180 //Log_Log("Keyboard", "Kernel Magic LCTRL Down\n");
183 gbKB_MagicState |= 2;
184 //Log_Log("Keyboard", "Kernel Magic LALT Down\n");
186 if(gbKB_MagicState == 3)
190 case '0': case '1': case '2': case '3':
191 case '4': case '5': case '6': case '7':
192 case '8': case '9': case 'a': case 'b':
193 case 'c': case 'd': case 'e': case 'f':
195 char str[4] = {'0', 'x', ch, 0};
196 if(giKB_MagicAddressPos == BITS/4) return;
197 giKB_MagicAddress |= atoi(str) << giKB_MagicAddressPos;
198 giKB_MagicAddressPos ++;
202 // Instruction Tracing
204 Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
205 Threads_ToggleTrace( giKB_MagicAddress );
206 giKB_MagicAddress = 0; giKB_MagicAddressPos = 0;
210 case 'p': Threads_Dump(); return;
212 case 'h': Heap_Stats(); return;
219 // Capitals required?
220 if( (gbKB_ShiftState != 0) != (gbKB_CapsState != 0))
222 // TODO: Move this to the keyboard map header
226 case '`': ch = '~'; break;
227 case '1': ch = '!'; break;
228 case '2': ch = '@'; break;
229 case '3': ch = '#'; break;
230 case '4': ch = '$'; break;
231 case '5': ch = '%'; break;
232 case '6': ch = '^'; break;
233 case '7': ch = '&'; break;
234 case '8': ch = '*'; break;
235 case '9': ch = '('; break;
236 case '0': 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;
243 case '\'': ch = '"'; break;
244 case ',': ch = '<'; break;
245 case '.': ch = '>'; break;
246 case '/': ch = '?'; break;
248 if('a' <= ch && ch <= 'z')
254 if(gKB_Callback && ch != 0) gKB_Callback(ch);
258 * \fn void KB_UpdateLEDs(void)
259 * \brief Updates the status of the keyboard LEDs
261 void KB_UpdateLEDs(void)
265 leds = (gbKB_CapsState ? 4 : 0);
267 while( inb(0x64) & 2 ); // Wait for bit 2 to unset
268 outb(0x60, 0xED); // Send update command
270 while( inb(0x64) & 2 ); // Wait for bit 2 to unset
275 * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
276 * \brief Calls an IOCtl Command
278 int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
282 case DRV_IOCTL_TYPE: return DRV_TYPE_KEYBOARD;
283 case DRV_IOCTL_IDENT: memcpy(Data, "KB\0\0", 4); return 1;
284 case DRV_IOCTL_VERSION: return 0x100;
285 case DRV_IOCTL_LOOKUP: return 0;
287 // Sets the Keyboard Callback
288 case KB_IOCTL_SETCALLBACK:
290 if((Uint)Data < KERNEL_BASE) return 0;
291 // Can only be set once
292 if(gKB_Callback != NULL) return 0;