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

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