Kernel - Change virtual memory API to use void* for virtual addresses
[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 <hal_proc.h>
20 #include <debug_hooks.h>
21
22 #define USE_KERNEL_MAGIC        1
23
24 // === PROTOTYPES ===
25  int    Keyboard_Install(char **Arguments);
26  int    Keyboard_Cleanup(void);
27 // - Internal
28 tKeymap *Keyboard_LoadMap(const char *Name);
29 void    Keyboard_FreeMap(tKeymap *Keymap);
30 // - "User" side (Actually VT)
31  int    Keyboard_IOCtl(tVFS_Node *Node, int ID, void *Data);
32 // - Device Side
33 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name);
34 void    Keyboard_RemoveInstance(tKeyboard *Instance);
35 void    Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym);
36
37 // === GLOBALS ===
38 MODULE_DEFINE(0, VERSION, Keyboard, Keyboard_Install, Keyboard_Cleanup, NULL);
39 tVFS_NodeType   gKB_NodeType = {
40         .IOCtl = Keyboard_IOCtl
41 };
42 tDevFS_Driver   gKB_DevInfo = {
43         NULL, "Keyboard",
44         { .Type = &gKB_NodeType }
45 };
46 #if USE_KERNEL_MAGIC
47  int    giKB_MagicAddress = 0;
48  int    giKB_MagicAddressPos = 0;
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 /*
151  * Handle a key press/release event
152  * - See Input/Keyboard/include/keyboard.h
153  */
154 void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym)
155 {
156          int    bPressed;
157         Uint32  trans;
158         Uint32  flag;
159         Uint8   layer;
160         
161         if( !Source ) {
162                 Log_Error("Keyboard", "Passed NULL handle");
163                 return ;
164         }
165         if( !Source->Node ) {
166                 Log_Error("Keyboard", "Passed handle with NULL node");
167                 return ;
168         }
169         
170         bPressed = !(HIDKeySym & (1 << 31));
171         HIDKeySym &= 0x7FFFFFFF;
172
173         // - Determine the action (Press, Release or Refire)
174         {
175                 Uint8   mask = 1 << (HIDKeySym&7);
176                  int    ofs = HIDKeySym / 8;
177                  int    oldstate = !!(Source->KeyStates[ofs] & mask);
178                 
179                 // Get the state of all other devices attached
180                  int    otherstate = 0;
181                 for( tKeyboard *kb = Source->Node->ImplPtr; kb; kb = kb->Next )
182                 {
183                         if( kb == Source )      continue ;
184                         if( kb->MaxKeysym <= HIDKeySym )        continue ;
185                         otherstate = otherstate || (kb->KeyStates[ofs] & mask);
186                 }
187                 
188                 // Update key state
189                 if( bPressed )
190                         Source->KeyStates[ ofs ] |= mask;
191                 else
192                         Source->KeyStates[ ofs ] &= ~mask;
193                 
194                 // Get the final flag
195                 if( bPressed )
196                 {
197                         if( !oldstate && !otherstate )
198                                 flag = KEY_ACTION_PRESS; // Down
199                         else
200                                 flag = KEY_ACTION_REFIRE; // Refire
201                 }
202                 else
203                 {
204                         if( !otherstate )
205                                 flag = KEY_ACTION_RELEASE; // Up
206                         else
207                                 flag = -1; // Do nothing
208                 }
209         }
210
211         // Translate \a State into layer
212         // TODO: Support non-trivial layouts
213         layer = !!(Source->State & 3);
214         
215         // Do translation
216         if( flag == KEY_ACTION_RELEASE )
217                 trans = 0;
218         else {  
219                 
220                 // Translate the keysym into a character
221                 if( layer >= Source->Keymap->nLayers )
222                         trans = 0;
223                 else if( HIDKeySym >= Source->Keymap->Layers[layer]->nSyms )
224                         trans = 0;
225                 else
226                         trans = Source->Keymap->Layers[layer]->Sym[HIDKeySym];
227                 // - No translation in \a layer, fall back to layer=0
228                 if(!trans && HIDKeySym < Source->Keymap->Layers[0]->nSyms)
229                         trans = Source->Keymap->Layers[0]->Sym[HIDKeySym];
230         }
231
232         // Call callback (only if the action is valid)
233         if( flag != -1 )
234         {
235                 tKeybardCallback Callback = (void*)Source->Node->ImplInt;
236                 Callback( HIDKeySym | KEY_ACTION_RAWSYM );
237                 Callback( flag | trans );
238         }
239
240         // TODO: Translate this into agnostic code
241         switch( HIDKeySym )
242         {
243         case KEYSYM_LEFTSHIFT:
244                 if(bPressed) Source->State |= 1;
245                 else Source->State &= ~1;
246                 break;
247         case KEYSYM_RIGHTSHIFT:
248                 if(bPressed) Source->State |= 2;
249                 else Source->State &= ~2;
250                 break;
251         }
252
253         // --- Check for Kernel Magic Combos
254         #if USE_KERNEL_MAGIC
255         if(bPressed
256         && Source->KeyStates[KEYSYM_LEFTCTRL/8] & (1 << (KEYSYM_LEFTCTRL&7))
257         && Source->KeyStates[KEYSYM_LEFTALT/8]  & (1 << (KEYSYM_LEFTALT &7)) )
258         {
259                  int    val;
260                 switch(trans)
261                 {
262                 case '0': val = 0;  goto _av;   case '1': val = 1;  goto _av;
263                 case '2': val = 2;  goto _av;   case '3': val = 3;  goto _av;
264                 case '4': val = 4;  goto _av;   case '5': val = 5;  goto _av;
265                 case '6': val = 6;  goto _av;   case '7': val = 7;  goto _av;
266                 case '8': val = 8;  goto _av;   case '9': val = 9;  goto _av;
267                 case 'a': val = 10; goto _av;   case 'b': val = 11; goto _av;
268                 case 'c': val = 12; goto _av;   case 'd': val = 13; goto _av;
269                 case 'e': val = 14; goto _av;   case 'f': val = 15; goto _av;
270                 _av:
271                         if(giKB_MagicAddressPos == BITS/4)      break;
272                         giKB_MagicAddress |= (Uint)val << giKB_MagicAddressPos;
273                         giKB_MagicAddressPos ++;
274                         break;
275                 
276                 // Instruction Tracing
277                 case 't':
278                         Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
279                         Threads_ToggleTrace( giKB_MagicAddress );
280                         giKB_MagicAddress = 0;  giKB_MagicAddressPos = 0;
281                         return;
282                 
283                 // Thread List Dump
284                 case 'p':       Threads_Dump(); return;
285                 // Heap Statistics
286                 case 'h':       Heap_Stats();   return;
287                 // PMem Statistics
288                 case 'm':       MM_DumpStatistics();    return;
289                 // Dump Structure
290                 case 's':       return;
291                 }
292         }
293         #endif
294
295         #if defined(ARCHDIR_is_x86) || defined(ARCHDIR_is_x86_64)
296         if(bPressed
297         && Source->KeyStates[KEYSYM_LEFTCTRL/8] & (1 << (KEYSYM_LEFTCTRL&7))
298         && Source->KeyStates[KEYSYM_LEFTALT/8]  & (1 << (KEYSYM_LEFTALT &7)) )
299         {
300                 if( HIDKeySym == KEYSYM_DELETE )
301                 {
302                         // Trigger triple fault
303                         __asm__ __volatile__ ("lgdt (%esp) ; int $0x0");
304                         for(;;);
305                 }
306         }
307         #endif
308
309 }
310

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