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"
19 #include <debug_hooks.h>
21 #define USE_KERNEL_MAGIC 1
23 extern void Validate_VirtualMemoryUsage(void);
26 int Keyboard_Install(char **Arguments);
27 int Keyboard_Cleanup(void);
29 tKeymap *Keyboard_LoadMap(const char *Name);
30 void Keyboard_FreeMap(tKeymap *Keymap);
31 // - "User" side (Actually VT)
32 int Keyboard_IOCtl(tVFS_Node *Node, int ID, void *Data);
34 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name);
35 void Keyboard_RemoveInstance(tKeyboard *Instance);
36 void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym);
39 MODULE_DEFINE(0, VERSION, Keyboard, Keyboard_Install, Keyboard_Cleanup, NULL);
40 tVFS_NodeType gKB_NodeType = {
41 .IOCtl = Keyboard_IOCtl
43 tDevFS_Driver gKB_DevInfo = {
45 { .Type = &gKB_NodeType }
48 tDebugHook gKB_DebugHookInfo;
53 * \brief Initialise the keyboard driver
55 int Keyboard_Install(char **Arguments)
57 /// - Register with DevFS
58 DevFS_AddDevice( &gKB_DevInfo );
63 * \brief Pre-unload cleanup function
65 int Keyboard_Cleanup(void)
67 // TODO: Do I need this?
71 // --- Map Management ---
73 * \brief Load an arbitary keyboard map
74 * \param Name Keymap name (e.g. "en-us")
75 * \return Keymap pointer
77 tKeymap *Keyboard_int_LoadMap(const char *Name)
79 Log_Warning("Keyboard", "TOD: Impliment Keyboard_int_LoadMap");
84 * \brief Unload a keyboard map
85 * \param Keymap Keymap to unload/free
87 void Keyboard_int_FreeMap(tKeymap *Keymap)
91 // --- VFS Interface ---
92 static const char *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
94 * \brief Keyboard IOCtl
96 int Keyboard_IOCtl(tVFS_Node *Node, int Id, void *Data)
100 BASE_IOCTLS(DRV_TYPE_KEYBOARD, "Keyboard", 0x100, csaIOCTL_NAMES);
102 case KB_IOCTL_SETCALLBACK:
103 if( Threads_GetUID() != 0 ) return -1;
104 if( MM_IsUser( (tVAddr)Data ) ) return -1;
105 if( Node->ImplInt ) return 0; // Can only be set once
106 Node->ImplInt = (Uint)Data;
112 // --- Device Interface ---
114 * Create a new keyboard device instance
115 * TODO: Allow linking to other VFS nodes
116 * See Input/Keyboard/include/keyboard.h
118 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name)
121 int sym_bitmap_size = (MaxSym + 7)/8;
122 int string_size = strlen(Name) + 1;
124 ret = malloc( sizeof(tKeyboard) + sym_bitmap_size + string_size );
129 memset(ret, 0, sizeof(tKeyboard) + sym_bitmap_size );
131 ret->Name = (char*)ret + sizeof(tKeyboard) + sym_bitmap_size;
132 memcpy(ret->Name, Name, string_size);
133 // Set node and default keymap
134 ret->Node = &gKB_DevInfo.RootNode;
135 ret->Keymap = &gKeymap_KBDUS;
141 * Destroy a keyboard instance
142 * - See Input/Keyboard/include/keyboard.h
144 void Keyboard_RemoveInstance(tKeyboard *Instance)
147 Log_Error("Keyboard", "TODO: Implement Keyboard_RemoveInstance");
150 inline bool IsPressed(tKeyboard *Kb, Uint8 KeySym)
152 return !!(Kb->KeyStates[KeySym/8] & (1 << (KeySym&7)));
156 * Handle a key press/release event
157 * - See Input/Keyboard/include/keyboard.h
159 void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym)
167 Log_Error("Keyboard", "Passed NULL handle");
170 if( !Source->Node ) {
171 Log_Error("Keyboard", "Passed handle with NULL node");
175 bPressed = !(HIDKeySym & (1 << 31));
176 HIDKeySym &= 0x7FFFFFFF;
178 // - Determine the action (Press, Release or Refire)
180 Uint8 mask = 1 << (HIDKeySym&7);
181 int ofs = HIDKeySym / 8;
182 int oldstate = !!(Source->KeyStates[ofs] & mask);
184 // Get the state of all other devices attached
186 for( tKeyboard *kb = Source->Node->ImplPtr; kb; kb = kb->Next )
188 if( kb == Source ) continue ;
189 if( kb->MaxKeysym <= HIDKeySym ) continue ;
190 otherstate = otherstate || (kb->KeyStates[ofs] & mask);
195 Source->KeyStates[ ofs ] |= mask;
197 Source->KeyStates[ ofs ] &= ~mask;
199 // Get the final flag
202 if( !oldstate && !otherstate )
203 flag = KEY_ACTION_PRESS; // Down
205 flag = KEY_ACTION_REFIRE; // Refire
210 flag = KEY_ACTION_RELEASE; // Up
212 flag = -1; // Do nothing
216 // Translate \a State into layer
217 // TODO: Support non-trivial layouts
218 layer = !!(Source->State & 3);
221 if( flag == KEY_ACTION_RELEASE )
225 // Translate the keysym into a character
226 if( layer >= Source->Keymap->nLayers )
228 else if( HIDKeySym >= Source->Keymap->Layers[layer]->nSyms )
231 trans = Source->Keymap->Layers[layer]->Sym[HIDKeySym];
232 // - No translation in \a layer, fall back to layer=0
233 if(!trans && HIDKeySym < Source->Keymap->Layers[0]->nSyms)
234 trans = Source->Keymap->Layers[0]->Sym[HIDKeySym];
237 // Call callback (only if the action is valid)
240 tKeybardCallback Callback = (void*)Source->Node->ImplInt;
241 Callback( HIDKeySym | KEY_ACTION_RAWSYM );
242 Callback( flag | trans );
245 // TODO: Translate this into agnostic code
248 case KEYSYM_LEFTSHIFT:
249 if(bPressed) Source->State |= 1;
250 else Source->State &= ~1;
252 case KEYSYM_RIGHTSHIFT:
253 if(bPressed) Source->State |= 2;
254 else Source->State &= ~2;
260 if(bPressed && IsPressed(Source, KEYSYM_LEFTCTRL) && IsPressed(Source, KEYSYM_LEFTALT))
266 char str[5]; // utf8 only supports 8 bytes
267 size_t len = WriteUTF8((Uint8*)str, trans);
269 DebugHook_HandleInput(&gKB_DebugHookInfo, len, str);
275 // Ctrl-Alt-Del == Reboot
276 #if defined(ARCHDIR_is_x86) || defined(ARCHDIR_is_x86_64)
278 && (IsPressed(Source, KEYSYM_LEFTCTRL) || IsPressed(Source, KEYSYM_RIGHTCTRL))
279 && (IsPressed(Source, KEYSYM_LEFTALT) || IsPressed(Source, KEYSYM_LEFTALT))
282 if( HIDKeySym == KEYSYM_DELETE )
284 // Trigger triple fault
285 __asm__ __volatile__ ("lgdt (%esp) ; int $0x0");