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

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