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

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