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

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