Kernel - Fix compilation on x86_64 and armv7 (for MM changes)
[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 // === PROTOTYPES ===
24  int    Keyboard_Install(char **Arguments);
25  int    Keyboard_Cleanup(void);
26 // - Internal
27 tKeymap *Keyboard_LoadMap(const char *Name);
28 void    Keyboard_FreeMap(tKeymap *Keymap);
29 // - "User" side (Actually VT)
30  int    Keyboard_IOCtl(tVFS_Node *Node, int ID, void *Data);
31 // - Device Side
32 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name);
33 void    Keyboard_RemoveInstance(tKeyboard *Instance);
34 void    Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym);
35
36 // === GLOBALS ===
37 MODULE_DEFINE(0, VERSION, Keyboard, Keyboard_Install, Keyboard_Cleanup, NULL);
38 tVFS_NodeType   gKB_NodeType = {
39         .IOCtl = Keyboard_IOCtl
40 };
41 tDevFS_Driver   gKB_DevInfo = {
42         NULL, "Keyboard",
43         { .Type = &gKB_NodeType }
44 };
45 #if USE_KERNEL_MAGIC
46  int    giKB_MagicAddress = 0;
47  int    giKB_MagicAddressPos = 0;
48 #endif
49
50 // === CODE ===
51 /**
52  * \brief Initialise the keyboard driver
53  */
54 int Keyboard_Install(char **Arguments)
55 {
56         /// - Register with DevFS
57         DevFS_AddDevice( &gKB_DevInfo );
58         return 0;
59 }
60
61 /**
62  * \brief Pre-unload cleanup function
63  */
64 int Keyboard_Cleanup(void)
65 {
66         // TODO: Do I need this?
67         return 0;
68 }
69
70 // --- Map Management ---
71 /**
72  * \brief Load an arbitary keyboard map
73  * \param Name  Keymap name (e.g. "en-us")
74  * \return Keymap pointer
75  */
76 tKeymap *Keyboard_int_LoadMap(const char *Name)
77 {
78         Log_Warning("Keyboard", "TOD: Impliment Keyboard_int_LoadMap");
79         return NULL;
80 }
81
82 /**
83  * \brief Unload a keyboard map
84  * \param Keymap        Keymap to unload/free
85  */
86 void Keyboard_int_FreeMap(tKeymap *Keymap)
87 {
88 }
89
90 // --- VFS Interface ---
91 static const char *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
92 /**
93  * \brief Keyboard IOCtl
94  */
95 int Keyboard_IOCtl(tVFS_Node *Node, int Id, void *Data)
96 {
97         switch(Id)
98         {
99         BASE_IOCTLS(DRV_TYPE_KEYBOARD, "Keyboard", 0x100, csaIOCTL_NAMES);
100         
101         case KB_IOCTL_SETCALLBACK:
102                 if( Threads_GetUID() != 0 )     return -1;
103                 if( MM_IsUser( (tVAddr)Data ) ) return -1;
104                 if( Node->ImplInt )     return 0;       // Can only be set once
105                 Node->ImplInt = (Uint)Data;
106                 return 1;
107         }
108         return -1;
109 }
110
111 // --- Device Interface ---
112 /*
113  * Create a new keyboard device instance
114  * TODO: Allow linking to other VFS nodes
115  * See Input/Keyboard/include/keyboard.h
116  */
117 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name)
118 {
119         tKeyboard       *ret;
120          int    sym_bitmap_size = (MaxSym + 7)/8;
121          int    string_size = strlen(Name) + 1;
122
123         ret = malloc( sizeof(tKeyboard) + sym_bitmap_size + string_size );
124         if( !ret ) {
125                 return NULL;
126         }
127         // Clear
128         memset(ret, 0, sizeof(tKeyboard) + sym_bitmap_size );
129         // Set name
130         ret->Name = (char*)ret + sizeof(tKeyboard) + sym_bitmap_size;
131         memcpy(ret->Name, Name, string_size);
132         // Set node and default keymap
133         ret->Node = &gKB_DevInfo.RootNode;
134         ret->Keymap = &gKeymap_KBDUS;
135
136         return ret;
137 }
138
139 /*
140  * Destroy a keyboard instance
141  * - See Input/Keyboard/include/keyboard.h
142  */
143 void Keyboard_RemoveInstance(tKeyboard *Instance)
144 {
145         // TODO: Implement
146         Log_Error("Keyboard", "TODO: Implement Keyboard_RemoveInstance");
147 }
148
149 /*
150  * Handle a key press/release event
151  * - See Input/Keyboard/include/keyboard.h
152  */
153 void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym)
154 {
155          int    bPressed;
156         Uint32  trans;
157         Uint32  flag;
158         Uint8   layer;
159         
160         if( !Source ) {
161                 Log_Error("Keyboard", "Passed NULL handle");
162                 return ;
163         }
164         if( !Source->Node ) {
165                 Log_Error("Keyboard", "Passed handle with NULL node");
166                 return ;
167         }
168         
169         bPressed = !(HIDKeySym & (1 << 31));
170         HIDKeySym &= 0x7FFFFFFF;
171
172         // - Determine the action (Press, Release or Refire)
173         {
174                 Uint8   mask = 1 << (HIDKeySym&7);
175                  int    ofs = HIDKeySym / 8;
176                  int    oldstate = !!(Source->KeyStates[ofs] & mask);
177                 
178                 // Get the state of all other devices attached
179                  int    otherstate = 0;
180                 for( tKeyboard *kb = Source->Node->ImplPtr; kb; kb = kb->Next )
181                 {
182                         if( kb == Source )      continue ;
183                         if( kb->MaxKeysym <= HIDKeySym )        continue ;
184                         otherstate = otherstate || (kb->KeyStates[ofs] & mask);
185                 }
186                 
187                 // Update key state
188                 if( bPressed )
189                         Source->KeyStates[ ofs ] |= mask;
190                 else
191                         Source->KeyStates[ ofs ] &= ~mask;
192                 
193                 // Get the final flag
194                 if( bPressed )
195                 {
196                         if( !oldstate && !otherstate )
197                                 flag = KEY_ACTION_PRESS; // Down
198                         else
199                                 flag = KEY_ACTION_REFIRE; // Refire
200                 }
201                 else
202                 {
203                         if( !otherstate )
204                                 flag = KEY_ACTION_RELEASE; // Up
205                         else
206                                 flag = -1; // Do nothing
207                 }
208         }
209
210         // Translate \a State into layer
211         // TODO: Support non-trivial layouts
212         layer = !!(Source->State & 3);
213         
214         // Do translation
215         if( flag == KEY_ACTION_RELEASE )
216                 trans = 0;
217         else {  
218                 
219                 // Translate the keysym into a character
220                 if( layer >= Source->Keymap->nLayers )
221                         trans = 0;
222                 else if( HIDKeySym >= Source->Keymap->Layers[layer]->nSyms )
223                         trans = 0;
224                 else
225                         trans = Source->Keymap->Layers[layer]->Sym[HIDKeySym];
226                 // - No translation in \a layer, fall back to layer=0
227                 if(!trans && HIDKeySym < Source->Keymap->Layers[0]->nSyms)
228                         trans = Source->Keymap->Layers[0]->Sym[HIDKeySym];
229         }
230
231         // Call callback (only if the action is valid)
232         if( flag != -1 )
233         {
234                 tKeybardCallback Callback = (void*)Source->Node->ImplInt;
235                 Callback( HIDKeySym | KEY_ACTION_RAWSYM );
236                 Callback( flag | trans );
237         }
238
239         // TODO: Translate this into agnostic code
240         switch( HIDKeySym )
241         {
242         case KEYSYM_LEFTSHIFT:
243                 if(bPressed) Source->State |= 1;
244                 else Source->State &= ~1;
245                 break;
246         case KEYSYM_RIGHTSHIFT:
247                 if(bPressed) Source->State |= 2;
248                 else Source->State &= ~2;
249                 break;
250         }
251
252         // --- Check for Kernel Magic Combos
253         #if USE_KERNEL_MAGIC
254         if(bPressed
255         && Source->KeyStates[KEYSYM_LEFTCTRL/8] & (1 << (KEYSYM_LEFTCTRL&7))
256         && Source->KeyStates[KEYSYM_LEFTALT/8]  & (1 << (KEYSYM_LEFTALT &7)) )
257         {
258                  int    val;
259                 switch(trans)
260                 {
261                 case '0': val = 0;  goto _av;   case '1': val = 1;  goto _av;
262                 case '2': val = 2;  goto _av;   case '3': val = 3;  goto _av;
263                 case '4': val = 4;  goto _av;   case '5': val = 5;  goto _av;
264                 case '6': val = 6;  goto _av;   case '7': val = 7;  goto _av;
265                 case '8': val = 8;  goto _av;   case '9': val = 9;  goto _av;
266                 case 'a': val = 10; goto _av;   case 'b': val = 11; goto _av;
267                 case 'c': val = 12; goto _av;   case 'd': val = 13; goto _av;
268                 case 'e': val = 14; goto _av;   case 'f': val = 15; goto _av;
269                 _av:
270                         if(giKB_MagicAddressPos == BITS/4)      break;
271                         giKB_MagicAddress |= (Uint)val << giKB_MagicAddressPos;
272                         giKB_MagicAddressPos ++;
273                         break;
274                 
275                 // Instruction Tracing
276                 case 't':
277                         Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
278                         Threads_ToggleTrace( giKB_MagicAddress );
279                         giKB_MagicAddress = 0;  giKB_MagicAddressPos = 0;
280                         return;
281                 
282                 // Thread List Dump
283                 case 'p':       Threads_Dump(); return;
284                 // Heap Statistics
285                 case 'h':       Heap_Stats();   return;
286                 // PMem Statistics
287                 case 'm':       MM_DumpStatistics();    return;
288                 // Dump Structure
289                 case 's':       return;
290                 }
291         }
292         #endif
293
294         #if defined(ARCHDIR_is_x86) || defined(ARCHDIR_is_x86_64)
295         if(bPressed
296         && Source->KeyStates[KEYSYM_LEFTCTRL/8] & (1 << (KEYSYM_LEFTCTRL&7))
297         && Source->KeyStates[KEYSYM_LEFTALT/8]  & (1 << (KEYSYM_LEFTALT &7)) )
298         {
299                 if( HIDKeySym == KEYSYM_DELETE )
300                 {
301                         // Trigger triple fault
302                         __asm__ __volatile__ ("lgdt (%esp) ; int $0x0");
303                         for(;;);
304                 }
305         }
306         #endif
307
308 }
309

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