Kernel - Move debug hooks to common handler
[tpg/acess2.git] / KernelLand / Modules / Input / Keyboard / main.c
1 /*
2  * Acess2 Kernel - Keyboard Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * main.c
6  * - Keyboard driver core
7  *
8  * TODO: Make the key transation code more general (for non-US layouts)
9  * TODO: Support multiple virtual keyboards
10  */
11 #define DEBUG   0
12 #define VERSION VER2(1,0)
13 #include <acess.h>
14 #include <modules.h>
15 #include <fs_devfs.h>
16 #include <Input/Keyboard/include/keyboard.h>
17 #include "keymap_int.h"
18 #include "layout_kbdus.h"
19 #include <debug_hooks.h>
20
21 #define USE_KERNEL_MAGIC        1
22
23 extern void     Validate_VirtualMemoryUsage(void);
24
25 // === PROTOTYPES ===
26  int    Keyboard_Install(char **Arguments);
27  int    Keyboard_Cleanup(void);
28 // - Internal
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);
33 // - Device Side
34 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name);
35 void    Keyboard_RemoveInstance(tKeyboard *Instance);
36 void    Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym);
37
38 // === GLOBALS ===
39 MODULE_DEFINE(0, VERSION, Keyboard, Keyboard_Install, Keyboard_Cleanup, NULL);
40 tVFS_NodeType   gKB_NodeType = {
41         .IOCtl = Keyboard_IOCtl
42 };
43 tDevFS_Driver   gKB_DevInfo = {
44         NULL, "Keyboard",
45         { .Type = &gKB_NodeType }
46 };
47 #if USE_KERNEL_MAGIC
48 tDebugHook      gKB_DebugHookInfo;
49 #endif
50
51 // === CODE ===
52 /**
53  * \brief Initialise the keyboard driver
54  */
55 int Keyboard_Install(char **Arguments)
56 {
57         /// - Register with DevFS
58         DevFS_AddDevice( &gKB_DevInfo );
59         return 0;
60 }
61
62 /**
63  * \brief Pre-unload cleanup function
64  */
65 int Keyboard_Cleanup(void)
66 {
67         // TODO: Do I need this?
68         return 0;
69 }
70
71 // --- Map Management ---
72 /**
73  * \brief Load an arbitary keyboard map
74  * \param Name  Keymap name (e.g. "en-us")
75  * \return Keymap pointer
76  */
77 tKeymap *Keyboard_int_LoadMap(const char *Name)
78 {
79         Log_Warning("Keyboard", "TOD: Impliment Keyboard_int_LoadMap");
80         return NULL;
81 }
82
83 /**
84  * \brief Unload a keyboard map
85  * \param Keymap        Keymap to unload/free
86  */
87 void Keyboard_int_FreeMap(tKeymap *Keymap)
88 {
89 }
90
91 // --- VFS Interface ---
92 static const char *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
93 /**
94  * \brief Keyboard IOCtl
95  */
96 int Keyboard_IOCtl(tVFS_Node *Node, int Id, void *Data)
97 {
98         switch(Id)
99         {
100         BASE_IOCTLS(DRV_TYPE_KEYBOARD, "Keyboard", 0x100, csaIOCTL_NAMES);
101         
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;
107                 return 1;
108         }
109         return -1;
110 }
111
112 // --- Device Interface ---
113 /*
114  * Create a new keyboard device instance
115  * TODO: Allow linking to other VFS nodes
116  * See Input/Keyboard/include/keyboard.h
117  */
118 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name)
119 {
120         tKeyboard       *ret;
121          int    sym_bitmap_size = (MaxSym + 7)/8;
122          int    string_size = strlen(Name) + 1;
123
124         ret = malloc( sizeof(tKeyboard) + sym_bitmap_size + string_size );
125         if( !ret ) {
126                 return NULL;
127         }
128         // Clear
129         memset(ret, 0, sizeof(tKeyboard) + sym_bitmap_size );
130         // Set name
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;
136
137         return ret;
138 }
139
140 /*
141  * Destroy a keyboard instance
142  * - See Input/Keyboard/include/keyboard.h
143  */
144 void Keyboard_RemoveInstance(tKeyboard *Instance)
145 {
146         // TODO: Implement
147         Log_Error("Keyboard", "TODO: Implement Keyboard_RemoveInstance");
148 }
149
150 inline bool IsPressed(tKeyboard *Kb, Uint8 KeySym)
151 {
152         return !!(Kb->KeyStates[KeySym/8] & (1 << (KeySym&7)));
153 }
154
155 /*
156  * Handle a key press/release event
157  * - See Input/Keyboard/include/keyboard.h
158  */
159 void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym)
160 {
161          int    bPressed;
162         Uint32  trans;
163         Uint32  flag;
164         Uint8   layer;
165         
166         if( !Source ) {
167                 Log_Error("Keyboard", "Passed NULL handle");
168                 return ;
169         }
170         if( !Source->Node ) {
171                 Log_Error("Keyboard", "Passed handle with NULL node");
172                 return ;
173         }
174         
175         bPressed = !(HIDKeySym & (1 << 31));
176         HIDKeySym &= 0x7FFFFFFF;
177
178         // - Determine the action (Press, Release or Refire)
179         {
180                 Uint8   mask = 1 << (HIDKeySym&7);
181                  int    ofs = HIDKeySym / 8;
182                  int    oldstate = !!(Source->KeyStates[ofs] & mask);
183                 
184                 // Get the state of all other devices attached
185                  int    otherstate = 0;
186                 for( tKeyboard *kb = Source->Node->ImplPtr; kb; kb = kb->Next )
187                 {
188                         if( kb == Source )      continue ;
189                         if( kb->MaxKeysym <= HIDKeySym )        continue ;
190                         otherstate = otherstate || (kb->KeyStates[ofs] & mask);
191                 }
192                 
193                 // Update key state
194                 if( bPressed )
195                         Source->KeyStates[ ofs ] |= mask;
196                 else
197                         Source->KeyStates[ ofs ] &= ~mask;
198                 
199                 // Get the final flag
200                 if( bPressed )
201                 {
202                         if( !oldstate && !otherstate )
203                                 flag = KEY_ACTION_PRESS; // Down
204                         else
205                                 flag = KEY_ACTION_REFIRE; // Refire
206                 }
207                 else
208                 {
209                         if( !otherstate )
210                                 flag = KEY_ACTION_RELEASE; // Up
211                         else
212                                 flag = -1; // Do nothing
213                 }
214         }
215
216         // Translate \a State into layer
217         // TODO: Support non-trivial layouts
218         layer = !!(Source->State & 3);
219         
220         // Do translation
221         if( flag == KEY_ACTION_RELEASE )
222                 trans = 0;
223         else {  
224                 
225                 // Translate the keysym into a character
226                 if( layer >= Source->Keymap->nLayers )
227                         trans = 0;
228                 else if( HIDKeySym >= Source->Keymap->Layers[layer]->nSyms )
229                         trans = 0;
230                 else
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];
235         }
236
237         // Call callback (only if the action is valid)
238         if( flag != -1 )
239         {
240                 tKeybardCallback Callback = (void*)Source->Node->ImplInt;
241                 Callback( HIDKeySym | KEY_ACTION_RAWSYM );
242                 Callback( flag | trans );
243         }
244
245         // TODO: Translate this into agnostic code
246         switch( HIDKeySym )
247         {
248         case KEYSYM_LEFTSHIFT:
249                 if(bPressed) Source->State |= 1;
250                 else Source->State &= ~1;
251                 break;
252         case KEYSYM_RIGHTSHIFT:
253                 if(bPressed) Source->State |= 2;
254                 else Source->State &= ~2;
255                 break;
256         }
257
258         // Magic debug hooks
259         #if USE_KERNEL_MAGIC
260         if(bPressed && IsPressed(Source, KEYSYM_LEFTCTRL) && IsPressed(Source, KEYSYM_LEFTALT))
261         {
262                 if( trans == '~' ) {
263                         // TODO: Latch mode
264                 }
265                 else {
266                         char    str[5]; // utf8 only supports 8 bytes
267                         size_t  len = WriteUTF8((Uint8*)str, trans);
268                         str[len] = '\0';
269                         DebugHook_HandleInput(&gKB_DebugHookInfo, len, str);
270                 }
271                 return ;
272         }
273         #endif
274
275         // Ctrl-Alt-Del == Reboot
276         #if defined(ARCHDIR_is_x86) || defined(ARCHDIR_is_x86_64)
277         if(bPressed
278           && (IsPressed(Source, KEYSYM_LEFTCTRL) || IsPressed(Source, KEYSYM_RIGHTCTRL))
279           && (IsPressed(Source, KEYSYM_LEFTALT)  || IsPressed(Source, KEYSYM_LEFTALT))
280           )
281         {
282                 if( HIDKeySym == KEYSYM_DELETE )
283                 {
284                         // Trigger triple fault
285                         __asm__ __volatile__ ("lgdt (%esp) ; int $0x0");
286                         for(;;);
287                 }
288         }
289         #endif
290
291 }
292

UCC git Repository :: git.ucc.asn.au