Renamed tpl_drv_* to api_drv_* (a more fitting name)
[tpg/acess2.git] / Modules / Input / PS2KbMouse / kb.c
1 /*
2  * Acess2
3  * PS2 Keyboard Driver
4  */
5 #include <acess.h>
6 #include <modules.h>
7 #include <fs_devfs.h>
8 #include <api_drv_common.h>
9 #include <api_drv_keyboard.h>
10 #include "kb_kbdus.h"
11
12 // === CONSTANTS ===
13 #define KB_BUFFER_SIZE  1024
14 #define USE_KERNEL_MAGIC        1
15
16 // === IMPORTS ===
17 extern void     Threads_ToggleTrace(int TID);
18 extern void     Threads_Dump(void);
19 extern void     Heap_Stats(void);
20
21 // === PROTOTYPES ===
22  int    KB_Install(char **Arguments);
23 void    KB_IRQHandler(int IRQNum);
24 void    KB_AddBuffer(char ch);
25 Uint64  KB_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Dest);
26 void    KB_UpdateLEDs(void);
27  int    KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
28
29 // === GLOBALS ===
30 tDevFS_Driver   gKB_DevInfo = {
31         NULL, "PS2Keyboard",
32         {
33         .NumACLs = 0,
34         .Size = 0,
35         //.Read = KB_Read,
36         .IOCtl = KB_IOCtl
37         }
38 };
39 tKeybardCallback        gKB_Callback = NULL;
40 Uint32  **gpKB_Map = gpKBDUS;
41 Uint8   gbaKB_States[3][256];
42  int    gbKB_ShiftState = 0;
43  int    gbKB_CapsState = 0;
44  int    gbKB_KeyUp = 0;
45  int    giKB_KeyLayer = 0;
46 #if USE_KERNEL_MAGIC
47  int    gbKB_MagicState = 0;
48  int    giKB_MagicAddress = 0;
49  int    giKB_MagicAddressPos = 0;
50 #endif
51
52 // === CODE ===
53 /**
54  * \brief Install the keyboard driver
55  */
56 int KB_Install(char **Arguments)
57 {
58         
59         IRQ_AddHandler(1, KB_IRQHandler);
60         
61         {
62                 Uint8   temp;
63                 // Attempt to get around a strange bug in Bochs/Qemu by toggling
64                 // the controller on and off
65                 temp = inb(0x61);
66                 outb(0x61, temp | 0x80);
67                 outb(0x61, temp & 0x7F);
68                 inb(0x60);      // Clear keyboard buffer
69         }
70         
71         DevFS_AddDevice( &gKB_DevInfo );
72         //Log("KB_Install: Installed");
73         return MODULE_ERR_OK;
74 }
75
76 /**
77  * \brief Called on a keyboard IRQ
78  * \param IRQNum        IRQ number (unused)
79  */
80 void KB_IRQHandler(int IRQNum)
81 {
82         Uint8   scancode;
83         Uint32  ch;
84         // int  keyNum;
85
86         // Check port 0x64 to tell if this is from the aux port
87         //if( inb(0x64) & 0x20 )        return;
88
89         scancode = inb(0x60); // Read from the keyboard's data buffer
90         //Log_Debug("Keyboard", "scancode = %02x", scancode);
91
92         // Ignore ACKs
93         if(scancode == 0xFA) {
94                 // Oh man! This is anarchic (I'm leaving it here to represent
95                 // the mess that Acess once was)
96                 //kb_lastChar = KB_ACK;
97                 return;
98         }
99
100         // Layer +1
101         if(scancode == 0xE0) {
102                 giKB_KeyLayer = 1;
103                 return;
104         }
105         // Layer +2
106         if(scancode == 0xE1) {
107                 giKB_KeyLayer = 2;
108                 return;
109         }
110
111         #if KB_ALT_SCANCODES
112         if(scancode == 0xF0)
113         {
114                 gbKB_KeyUp = 1;
115                 return;
116         }
117         #else
118         if(scancode & 0x80)
119         {
120                 scancode &= 0x7F;
121                 gbKB_KeyUp = 1;
122         }
123         #endif
124
125         // Translate
126         ch = gpKB_Map[giKB_KeyLayer][scancode];
127         // Check for unknown key
128         if(!ch && !gbKB_KeyUp)
129                 Log_Warning("Keyboard", "UNK %i %x", giKB_KeyLayer, scancode);
130
131         // Key Up?
132         if (gbKB_KeyUp)
133         {
134                 gbKB_KeyUp = 0;
135                 gbaKB_States[giKB_KeyLayer][scancode] = 0;      // Unset key state flag
136
137                 #if USE_KERNEL_MAGIC
138                 if(ch == KEY_LCTRL)     gbKB_MagicState &= ~1;
139                 if(ch == KEY_LALT)      gbKB_MagicState &= ~2;
140                 #endif
141
142                 if(ch == KEY_LSHIFT)    gbKB_ShiftState &= ~1;
143                 if(ch == KEY_RSHIFT)    gbKB_ShiftState &= ~2;
144
145                 // Call callback
146                 if(ch != 0 && gKB_Callback)
147                         gKB_Callback( ch & 0x80000000 );
148
149                 // Reset Layer
150                 giKB_KeyLayer = 0;
151                 return;
152         }
153
154         // Set the bit relating to the key
155         gbaKB_States[giKB_KeyLayer][scancode] = 1;
156         // Set shift key bits
157         if(ch == KEY_LSHIFT)    gbKB_ShiftState |= 1;
158         if(ch == KEY_RSHIFT)    gbKB_ShiftState |= 2;
159
160         // Check for Caps Lock
161         if(ch == KEY_CAPSLOCK) {
162                 gbKB_CapsState = !gbKB_CapsState;
163                 KB_UpdateLEDs();
164         }
165
166         // Reset Layer
167         giKB_KeyLayer = 0;
168
169         // Ignore Non-Printable Characters
170         if(ch == 0)             return;
171
172         // --- Check for Kernel Magic Combos
173         #if USE_KERNEL_MAGIC
174         if(ch == KEY_LCTRL) {
175                 gbKB_MagicState |= 1;
176                 //Log_Log("Keyboard", "Kernel Magic LCTRL Down\n");
177         }
178         if(ch == KEY_LALT) {
179                 gbKB_MagicState |= 2;
180                 //Log_Log("Keyboard", "Kernel Magic LALT Down\n");
181         }
182         if(gbKB_MagicState == 3)
183         {
184                 switch(ch)
185                 {
186                 case '0':       case '1':       case '2':       case '3':
187                 case '4':       case '5':       case '6':       case '7':
188                 case '8':       case '9':       case 'a':       case 'b':
189                 case 'c':       case 'd':       case 'e':       case 'f':
190                         {
191                         char    str[4] = {'0', 'x', ch, 0};
192                         if(giKB_MagicAddressPos == BITS/4)      return;
193                         giKB_MagicAddress |= atoi(str) << giKB_MagicAddressPos;
194                         giKB_MagicAddressPos ++;
195                         }
196                         return;
197                 
198                 // Instruction Tracing
199                 case 't':
200                         Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
201                         Threads_ToggleTrace( giKB_MagicAddress );
202                         giKB_MagicAddress = 0;  giKB_MagicAddressPos = 0;
203                         return;
204                 
205                 // Thread List Dump
206                 case 'p':       Threads_Dump(); return;
207                 // Heap Statistics
208                 case 'h':       Heap_Stats();   return;
209                 // Dump Structure
210                 case 's':       return;
211                 }
212         }
213         #endif
214
215         // Capitals required?
216         if( (gbKB_ShiftState != 0) != (gbKB_CapsState != 0))
217         {
218                 // TODO: Move this to the keyboard map header
219                 switch(ch)
220                 {
221                 case 0: break;
222                 case '`':       ch = '~';       break;
223                 case '1':       ch = '!';       break;
224                 case '2':       ch = '@';       break;
225                 case '3':       ch = '#';       break;
226                 case '4':       ch = '$';       break;
227                 case '5':       ch = '%';       break;
228                 case '6':       ch = '^';       break;
229                 case '7':       ch = '&';       break;
230                 case '8':       ch = '*';       break;
231                 case '9':       ch = '(';       break;
232                 case '0':       ch = ')';       break;
233                 case '-':       ch = '_';       break;
234                 case '=':       ch = '+';       break;
235                 case '[':       ch = '{';       break;
236                 case ']':       ch = '}';       break;
237                 case '\\':      ch = '|';       break;
238                 case ';':       ch = ':';       break;
239                 case '\'':      ch = '"';       break;
240                 case ',':       ch = '<';       break;
241                 case '.':       ch = '>';       break;
242                 case '/':       ch = '?';       break;
243                 default:
244                         if('a' <= ch && ch <= 'z')
245                                 ch -= 0x20;
246                         break;
247                 }
248         }
249
250         if(gKB_Callback && ch != 0)     gKB_Callback(ch);
251 }
252
253 /**
254  * \fn void KB_UpdateLEDs(void)
255  * \brief Updates the status of the keyboard LEDs
256  */
257 void KB_UpdateLEDs(void)
258 {
259         Uint8   leds;
260
261         leds = (gbKB_CapsState ? 4 : 0);
262
263         while( inb(0x64) & 2 ); // Wait for bit 2 to unset
264         outb(0x60, 0xED);       // Send update command
265
266         while( inb(0x64) & 2 ); // Wait for bit 2 to unset
267         outb(0x60, leds);
268 }
269
270 static const char       *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
271
272 /**
273  * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
274  * \brief Calls an IOCtl Command
275  */
276 int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
277 {
278         switch(Id)
279         {
280         BASE_IOCTLS(DRV_TYPE_KEYBOARD, "KB", 0x100, csaIOCTL_NAMES);
281         
282         // Sets the Keyboard Callback
283         case KB_IOCTL_SETCALLBACK:
284                 // Sanity Check
285                 if((Uint)Data < KERNEL_BASE)    return 0;
286                 // Can only be set once
287                 if(gKB_Callback != NULL)        return 0;
288                 // Set Callback
289                 gKB_Callback = Data;
290                 return 1;
291
292         default:
293                 return 0;
294         }
295 }

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