Merge branch 'master' of ted.mutabah.net:acess2
[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         bPressed = !(HIDKeySym & (1 << 31));
168         HIDKeySym &= 0x7FFFFFFF;
169
170         // - Determine the action (Press, Release or Refire)
171         {
172                 Uint8   mask = 1 << (HIDKeySym&7);
173                  int    ofs = HIDKeySym / 8;
174                  int    oldstate = !!(Source->KeyStates[ofs] & mask);
175                 
176                 // Get the state of all other devices attached
177                  int    otherstate = 0;
178                 for( tKeyboard *kb = Source->Node->ImplPtr; kb; kb = kb->Next )
179                 {
180                         if( kb == Source )      continue ;
181                         if( kb->MaxKeysym <= HIDKeySym )        continue ;
182                         otherstate = otherstate || (kb->KeyStates[ofs] & mask);
183                 }
184                 
185                 // Update key state
186                 if( bPressed )
187                         Source->KeyStates[ ofs ] |= mask;
188                 else
189                         Source->KeyStates[ ofs ] &= ~mask;
190                 
191                 // Get the final flag
192                 if( bPressed )
193                 {
194                         if( !oldstate && !otherstate )
195                                 flag = KEY_ACTION_PRESS; // Down
196                         else
197                                 flag = KEY_ACTION_REFIRE; // Refire
198                 }
199                 else
200                 {
201                         if( !otherstate )
202                                 flag = KEY_ACTION_RELEASE; // Up
203                         else
204                                 flag = -1; // Do nothing
205                 }
206         }
207
208         // Translate \a State into layer
209         // TODO: Support non-trivial layouts
210         layer = !!(Source->State & 3);
211         
212         // Do translation
213         if( flag == KEY_ACTION_RELEASE )
214                 trans = 0;
215         else {  
216                 
217                 // Translate the keysym into a character
218                 if( layer >= Source->Keymap->nLayers )
219                         trans = 0;
220                 else if( HIDKeySym >= Source->Keymap->Layers[layer]->nSyms )
221                         trans = 0;
222                 else
223                         trans = Source->Keymap->Layers[layer]->Sym[HIDKeySym];
224                 // - No translation in \a layer, fall back to layer=0
225                 if(!trans && HIDKeySym < Source->Keymap->Layers[0]->nSyms)
226                         trans = Source->Keymap->Layers[0]->Sym[HIDKeySym];
227         }
228
229         // Call callback (only if the action is valid)
230         if( flag != -1 )
231         {
232                 tKeybardCallback Callback = (void*)Source->Node->ImplInt;
233                 Callback( HIDKeySym | KEY_ACTION_RAWSYM );
234                 Callback( flag | trans );
235         }
236
237         // TODO: Translate this into agnostic code
238         switch( HIDKeySym )
239         {
240         case KEYSYM_LEFTSHIFT:
241                 if(bPressed) Source->State |= 1;
242                 else Source->State &= ~1;
243                 break;
244         case KEYSYM_RIGHTSHIFT:
245                 if(bPressed) Source->State |= 2;
246                 else Source->State &= ~2;
247                 break;
248         }
249
250         // --- Check for Kernel Magic Combos
251         #if USE_KERNEL_MAGIC
252         if(bPressed
253         && Source->KeyStates[KEYSYM_LEFTCTRL/8] & (1 << (KEYSYM_LEFTCTRL&7))
254         && Source->KeyStates[KEYSYM_LEFTALT/8]  & (1 << (KEYSYM_LEFTALT &7)) )
255         {
256                  int    val;
257                 switch(trans)
258                 {
259                 case '0': val = 0;  goto _av;   case '1': val = 1;  goto _av;
260                 case '2': val = 2;  goto _av;   case '3': val = 3;  goto _av;
261                 case '4': val = 4;  goto _av;   case '5': val = 5;  goto _av;
262                 case '6': val = 6;  goto _av;   case '7': val = 7;  goto _av;
263                 case '8': val = 8;  goto _av;   case '9': val = 9;  goto _av;
264                 case 'a': val = 10; goto _av;   case 'b': val = 11; goto _av;
265                 case 'c': val = 12; goto _av;   case 'd': val = 13; goto _av;
266                 case 'e': val = 14; goto _av;   case 'f': val = 15; goto _av;
267                 _av:
268                         if(giKB_MagicAddressPos == BITS/4)      break;
269                         giKB_MagicAddress |= (Uint)val << giKB_MagicAddressPos;
270                         giKB_MagicAddressPos ++;
271                         break;
272                 
273                 // Instruction Tracing
274                 case 't':
275                         Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
276                         Threads_ToggleTrace( giKB_MagicAddress );
277                         giKB_MagicAddress = 0;  giKB_MagicAddressPos = 0;
278                         return;
279                 
280                 // Thread List Dump
281                 case 'p':       Threads_Dump(); return;
282                 // Heap Statistics
283                 case 'h':       Heap_Stats();   return;
284                 // PMem Statistics
285                 case 'm':       MM_DumpStatistics();    return;
286                 // Dump Structure
287                 case 's':       return;
288                 }
289         }
290         #endif
291
292 }
293

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