2 * Acess2 Kernel - Keyboard Driver
3 * - By John Hodge (thePowersGang)
6 * - Keyboard driver core
8 * TODO: Make the key transation code more general (for non-US layouts)
9 * TODO: Support multiple virtual keyboards
12 #define VERSION VER2(1,0)
16 #include <Input/Keyboard/include/keyboard.h>
17 #include "keymap_int.h"
18 #include "layout_kbdus.h"
21 #define USE_KERNEL_MAGIC 1
25 extern void Threads_ToggleTrace(int TID);
26 extern void Threads_Dump(void);
27 extern void Heap_Stats(void);
31 int Keyboard_Install(char **Arguments);
32 int Keyboard_Cleanup(void);
34 tKeymap *Keyboard_LoadMap(const char *Name);
35 void Keyboard_FreeMap(tKeymap *Keymap);
36 // - "User" side (Actually VT)
37 int Keyboard_IOCtl(tVFS_Node *Node, int ID, void *Data);
39 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name);
40 void Keyboard_RemoveInstance(tKeyboard *Instance);
41 void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym);
44 MODULE_DEFINE(0, VERSION, Keyboard, Keyboard_Install, Keyboard_Cleanup, NULL);
45 tVFS_NodeType gKB_NodeType = {
46 .IOCtl = Keyboard_IOCtl
48 tDevFS_Driver gKB_DevInfo = {
50 { .Type = &gKB_NodeType }
53 int giKB_MagicAddress = 0;
54 int giKB_MagicAddressPos = 0;
59 * \brief Initialise the keyboard driver
61 int Keyboard_Install(char **Arguments)
63 /// - Register with DevFS
64 DevFS_AddDevice( &gKB_DevInfo );
69 * \brief Pre-unload cleanup function
71 int Keyboard_Cleanup(void)
73 // TODO: Do I need this?
77 // --- Map Management ---
79 * \brief Load an arbitary keyboard map
80 * \param Name Keymap name (e.g. "en-us")
81 * \return Keymap pointer
83 tKeymap *Keyboard_int_LoadMap(const char *Name)
85 Log_Warning("Keyboard", "TOD: Impliment Keyboard_int_LoadMap");
90 * \brief Unload a keyboard map
91 * \param Keymap Keymap to unload/free
93 void Keyboard_int_FreeMap(tKeymap *Keymap)
97 // --- VFS Interface ---
98 static const char *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
100 * \brief Keyboard IOCtl
102 int Keyboard_IOCtl(tVFS_Node *Node, int Id, void *Data)
106 BASE_IOCTLS(DRV_TYPE_KEYBOARD, "Keyboard", 0x100, csaIOCTL_NAMES);
108 case KB_IOCTL_SETCALLBACK:
109 if( Threads_GetUID() != 0 ) return -1;
110 if( MM_IsUser( (tVAddr)Data ) ) return -1;
111 if( Node->ImplInt ) return 0; // Can only be set once
112 Node->ImplInt = (Uint)Data;
118 // --- Device Interface ---
120 * Create a new keyboard device instance
121 * TODO: Allow linking to other VFS nodes
122 * See Input/Keyboard/include/keyboard.h
124 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name)
127 int sym_bitmap_size = (MaxSym + 7)/8;
128 int string_size = strlen(Name) + 1;
130 ret = malloc( sizeof(tKeyboard) + sym_bitmap_size + string_size );
135 memset(ret, 0, sizeof(tKeyboard) + sym_bitmap_size );
137 ret->Name = (char*)ret + sizeof(tKeyboard) + sym_bitmap_size;
138 memcpy(ret->Name, Name, string_size);
139 // Set node and default keymap
140 ret->Node = &gKB_DevInfo.RootNode;
141 ret->Keymap = &gKeymap_KBDUS;
147 * Destroy a keyboard instance
148 * - See Input/Keyboard/include/keyboard.h
150 void Keyboard_RemoveInstance(tKeyboard *Instance)
153 Log_Error("Keyboard", "TODO: Implement Keyboard_RemoveInstance");
157 * Handle a key press/release event
158 * - See Input/Keyboard/include/keyboard.h
160 void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym)
168 Log_Error("Keyboard", "Passed NULL handle");
171 if( !Source->Node ) {
172 Log_Error("Keyboard", "Passed handle with NULL node");
176 bPressed = !(HIDKeySym & (1 << 31));
177 HIDKeySym &= 0x7FFFFFFF;
179 // - Determine the action (Press, Release or Refire)
181 Uint8 mask = 1 << (HIDKeySym&7);
182 int ofs = HIDKeySym / 8;
183 int oldstate = !!(Source->KeyStates[ofs] & mask);
185 // Get the state of all other devices attached
187 for( tKeyboard *kb = Source->Node->ImplPtr; kb; kb = kb->Next )
189 if( kb == Source ) continue ;
190 if( kb->MaxKeysym <= HIDKeySym ) continue ;
191 otherstate = otherstate || (kb->KeyStates[ofs] & mask);
196 Source->KeyStates[ ofs ] |= mask;
198 Source->KeyStates[ ofs ] &= ~mask;
200 // Get the final flag
203 if( !oldstate && !otherstate )
204 flag = KEY_ACTION_PRESS; // Down
206 flag = KEY_ACTION_REFIRE; // Refire
211 flag = KEY_ACTION_RELEASE; // Up
213 flag = -1; // Do nothing
217 // Translate \a State into layer
218 // TODO: Support non-trivial layouts
219 layer = !!(Source->State & 3);
222 if( flag == KEY_ACTION_RELEASE )
226 // Translate the keysym into a character
227 if( layer >= Source->Keymap->nLayers )
229 else if( HIDKeySym >= Source->Keymap->Layers[layer]->nSyms )
232 trans = Source->Keymap->Layers[layer]->Sym[HIDKeySym];
233 // - No translation in \a layer, fall back to layer=0
234 if(!trans && HIDKeySym < Source->Keymap->Layers[0]->nSyms)
235 trans = Source->Keymap->Layers[0]->Sym[HIDKeySym];
238 // Call callback (only if the action is valid)
241 tKeybardCallback Callback = (void*)Source->Node->ImplInt;
242 Callback( HIDKeySym | KEY_ACTION_RAWSYM );
243 Callback( flag | trans );
246 // TODO: Translate this into agnostic code
249 case KEYSYM_LEFTSHIFT:
250 if(bPressed) Source->State |= 1;
251 else Source->State &= ~1;
253 case KEYSYM_RIGHTSHIFT:
254 if(bPressed) Source->State |= 2;
255 else Source->State &= ~2;
259 // --- Check for Kernel Magic Combos
262 && Source->KeyStates[KEYSYM_LEFTCTRL/8] & (1 << (KEYSYM_LEFTCTRL&7))
263 && Source->KeyStates[KEYSYM_LEFTALT/8] & (1 << (KEYSYM_LEFTALT &7)) )
268 case '0': val = 0; goto _av; case '1': val = 1; goto _av;
269 case '2': val = 2; goto _av; case '3': val = 3; goto _av;
270 case '4': val = 4; goto _av; case '5': val = 5; goto _av;
271 case '6': val = 6; goto _av; case '7': val = 7; goto _av;
272 case '8': val = 8; goto _av; case '9': val = 9; goto _av;
273 case 'a': val = 10; goto _av; case 'b': val = 11; goto _av;
274 case 'c': val = 12; goto _av; case 'd': val = 13; goto _av;
275 case 'e': val = 14; goto _av; case 'f': val = 15; goto _av;
277 if(giKB_MagicAddressPos == BITS/4) break;
278 giKB_MagicAddress |= (Uint)val << giKB_MagicAddressPos;
279 giKB_MagicAddressPos ++;
282 // Instruction Tracing
284 Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
285 Threads_ToggleTrace( giKB_MagicAddress );
286 giKB_MagicAddress = 0; giKB_MagicAddressPos = 0;
290 case 'p': Threads_Dump(); return;
292 case 'h': Heap_Stats(); return;
294 case 'm': MM_DumpStatistics(); return;
301 #if defined(ARCHDIR_is_x86) || defined(ARCHDIR_is_x86_64)
303 && Source->KeyStates[KEYSYM_LEFTCTRL/8] & (1 << (KEYSYM_LEFTCTRL&7))
304 && Source->KeyStates[KEYSYM_LEFTALT/8] & (1 << (KEYSYM_LEFTALT &7)) )
306 if( HIDKeySym == KEYSYM_DELETE )
308 // Trigger triple fault
309 __asm__ __volatile__ ("lgdt (%esp) ; int $0x0");