Usermode/libc - Fix strchr and strrchr behavior
[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 extern void     Validate_VirtualMemoryUsage(void);
24
25 // === PROTOTYPES ===
26  int    Keyboard_Install(char **Arguments);
27  int    Keyboard_Cleanup(void);
28 // - Internal
29 tKeymap *Keyboard_LoadMap(const char *Name);
30 void    Keyboard_FreeMap(tKeymap *Keymap);
31 // - "User" side (Actually VT)
32  int    Keyboard_IOCtl(tVFS_Node *Node, int ID, void *Data);
33 // - Device Side
34 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name);
35 void    Keyboard_RemoveInstance(tKeyboard *Instance);
36 void    Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym);
37
38 // === GLOBALS ===
39 MODULE_DEFINE(0, VERSION, Keyboard, Keyboard_Install, Keyboard_Cleanup, NULL);
40 tVFS_NodeType   gKB_NodeType = {
41         .IOCtl = Keyboard_IOCtl
42 };
43 tDevFS_Driver   gKB_DevInfo = {
44         NULL, "Keyboard",
45         { .Type = &gKB_NodeType }
46 };
47 #if USE_KERNEL_MAGIC
48 tDebugHook      gKB_DebugHookInfo;
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         size_t  sym_bitmap_size = (MaxSym + 7)/8;
121         size_t  string_size = strlen(Name) + 1;
122
123         tKeyboard *ret = calloc( 1, sizeof(tKeyboard) + sym_bitmap_size + string_size );
124         if( !ret ) {
125                 return NULL;
126         }
127         // Set name
128         ret->Name = (char*)( &ret->KeyStates[sym_bitmap_size] );
129         strcpy(ret->Name, Name);
130         // Set node and default keymap
131         ret->Node = &gKB_DevInfo.RootNode;
132         ret->Keymap = &gKeymap_KBDUS;
133
134         return ret;
135 }
136
137 /*
138  * Destroy a keyboard instance
139  * - See Input/Keyboard/include/keyboard.h
140  */
141 void Keyboard_RemoveInstance(tKeyboard *Instance)
142 {
143         // TODO: Implement
144         Log_Error("Keyboard", "TODO: Implement Keyboard_RemoveInstance");
145 }
146
147 inline bool IsPressed(tKeyboard *Kb, Uint8 KeySym)
148 {
149         return !!(Kb->KeyStates[KeySym/8] & (1 << (KeySym&7)));
150 }
151
152 /*
153  * Handle a key press/release event
154  * - See Input/Keyboard/include/keyboard.h
155  */
156 void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym)
157 {
158          int    bPressed;
159         Uint32  trans;
160         Uint32  flag;
161         Uint8   layer;
162         
163         if( !Source ) {
164                 Log_Error("Keyboard", "Passed NULL handle");
165                 return ;
166         }
167         if( !Source->Node ) {
168                 Log_Error("Keyboard", "Passed handle with NULL node");
169                 return ;
170         }
171         
172         bPressed = !(HIDKeySym & (1 << 31));
173         HIDKeySym &= 0x7FFFFFFF;
174
175         // - Determine the action (Press, Release or Refire)
176         {
177                 Uint8   mask = 1 << (HIDKeySym&7);
178                  int    ofs = HIDKeySym / 8;
179                  int    oldstate = !!(Source->KeyStates[ofs] & mask);
180                 
181                 // Get the state of all other devices attached
182                  int    otherstate = 0;
183                 for( tKeyboard *kb = Source->Node->ImplPtr; kb; kb = kb->Next )
184                 {
185                         if( kb == Source )      continue ;
186                         if( kb->MaxKeysym <= HIDKeySym )        continue ;
187                         otherstate = otherstate || (kb->KeyStates[ofs] & mask);
188                 }
189                 
190                 // Update key state
191                 if( bPressed )
192                         Source->KeyStates[ ofs ] |= mask;
193                 else
194                         Source->KeyStates[ ofs ] &= ~mask;
195                 
196                 // Get the final flag
197                 if( bPressed )
198                 {
199                         if( !oldstate && !otherstate )
200                                 flag = KEY_ACTION_PRESS; // Down
201                         else
202                                 flag = KEY_ACTION_REFIRE; // Refire
203                 }
204                 else
205                 {
206                         if( !otherstate )
207                                 flag = KEY_ACTION_RELEASE; // Up
208                         else
209                                 flag = -1; // Do nothing
210                 }
211         }
212
213         // Translate \a State into layer
214         // TODO: Support non-trivial layouts
215         layer = !!(Source->State & 3);
216         
217         // Do translation
218         if( flag == KEY_ACTION_RELEASE )
219                 trans = 0;
220         else {  
221                 
222                 // Translate the keysym into a character
223                 if( layer >= Source->Keymap->nLayers )
224                         trans = 0;
225                 else if( HIDKeySym >= Source->Keymap->Layers[layer]->nSyms )
226                         trans = 0;
227                 else
228                         trans = Source->Keymap->Layers[layer]->Sym[HIDKeySym];
229                 // - No translation in \a layer, fall back to layer=0
230                 if(!trans && HIDKeySym < Source->Keymap->Layers[0]->nSyms)
231                         trans = Source->Keymap->Layers[0]->Sym[HIDKeySym];
232         }
233
234         // Call callback (only if the action is valid)
235         if( flag != -1 )
236         {
237                 tKeybardCallback Callback = (void*)Source->Node->ImplInt;
238                 Callback( HIDKeySym | KEY_ACTION_RAWSYM );
239                 Callback( flag | trans );
240         }
241
242         // TODO: Translate this into agnostic code
243         switch( HIDKeySym )
244         {
245         case KEYSYM_LEFTSHIFT:
246                 if(bPressed) Source->State |= 1;
247                 else Source->State &= ~1;
248                 break;
249         case KEYSYM_RIGHTSHIFT:
250                 if(bPressed) Source->State |= 2;
251                 else Source->State &= ~2;
252                 break;
253         }
254
255         // Magic debug hooks
256         #if USE_KERNEL_MAGIC
257         if(bPressed && IsPressed(Source, KEYSYM_LEFTCTRL) && IsPressed(Source, KEYSYM_LEFTALT))
258         {
259                 if( trans == '~' ) {
260                         // TODO: Latch mode
261                 }
262                 else {
263                         char    str[5]; // utf8 only supports 8 bytes
264                         size_t  len = WriteUTF8((Uint8*)str, trans);
265                         str[len] = '\0';
266                         DebugHook_HandleInput(&gKB_DebugHookInfo, len, str);
267                 }
268                 return ;
269         }
270         #endif
271
272         // Ctrl-Alt-Del == Reboot
273         #if defined(ARCHDIR_is_x86) || defined(ARCHDIR_is_x86_64)
274         if(bPressed
275           && (IsPressed(Source, KEYSYM_LEFTCTRL) || IsPressed(Source, KEYSYM_RIGHTCTRL))
276           && (IsPressed(Source, KEYSYM_LEFTALT)  || IsPressed(Source, KEYSYM_LEFTALT))
277           )
278         {
279                 if( HIDKeySym == KEYSYM_DELETE )
280                 {
281                         // Trigger triple fault
282                         __asm__ __volatile__ ("lgdt (%esp) ; int $0x0");
283                         for(;;);
284                 }
285         }
286         #endif
287
288 }
289

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