Many changes, Mostly working on improving the BootConf script engine.
[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();
18
19 // === PROTOTYPES ===
20  int    KB_Install(char **Arguments);
21 void    KB_IRQHandler();
22 void    KB_AddBuffer(char ch);
23 Uint64  KB_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Dest);
24 void    KB_UpdateLEDs();
25  int    KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
26
27 // === GLOBALS ===
28 MODULE_DEFINE(0, 0x0100, PS2Keyboard, KB_Install, NULL, NULL);
29 tDevFS_Driver   gKB_DevInfo = {
30         NULL, "PS2Keyboard",
31         {
32         .NumACLs = 0,
33         .Size = 0,
34         //.Read = KB_Read,
35         .IOCtl = KB_IOCtl
36         }
37 };
38 tKeybardCallback        gKB_Callback = NULL;
39 Uint32  **gpKB_Map = gpKBDUS;
40 Uint8   gbaKB_States[3][256];
41  int    gbKB_ShiftState = 0;
42  int    gbKB_CapsState = 0;
43  int    gbKB_KeyUp = 0;
44  int    giKB_KeyLayer = 0;
45 #if USE_KERNEL_MAGIC
46  int    gbKB_MagicState = 0;
47 #endif
48 //Uint64        giKB_ReadBase = 0;
49 //Uint32        gaKB_Buffer[KB_BUFFER_SIZE];    //!< Keyboard Ring Buffer
50 //volatile int  giKB_InsertPoint = 0;   //!< Writing location marker
51 //volatile int  giKB_ReadPoint = 0;     //!< Reading location marker
52 //volatile int  giKB_InUse = 0;         //!< Lock marker
53
54 // === CODE ===
55 /**
56  * \fn int KB_Install(char **Arguments)
57  */
58 int KB_Install(char **Arguments)
59 {
60         Uint8   temp;
61         
62         // Attempt to get around a strange bug in Bochs/Qemu by toggling
63         // the controller on and off
64         temp = inb(0x61);
65         outb(0x61, temp | 0x80);
66         outb(0x61, temp & 0x7F);
67         inb(0x60);      // Clear keyboard buffer
68         
69         IRQ_AddHandler(1, KB_IRQHandler);
70         DevFS_AddDevice( &gKB_DevInfo );
71         //Log("KB_Install: Installed");
72         return MODULE_ERR_OK;
73 }
74
75 /**
76  * \fn void KB_IRQHandler()
77  * \brief Called on a keyboard IRQ
78  */
79 void KB_IRQHandler()
80 {
81         Uint8   scancode;
82         Uint32  ch;
83         // int  keyNum;
84
85         // Check port 0x64 to tell if this is from the aux port
86         if( inb(0x64) & 0x20 )  return;
87
88         scancode = inb(0x60); // Read from the keyboard's data buffer
89         //Log_Debug("Keyboard", "scancode = %02x", scancode);
90
91         // Ignore ACKs
92         if(scancode == 0xFA) {
93                 // Oh man! This is anarchic (I'm leaving it here to represent
94                 // the mess that Acess once was)
95                 //kb_lastChar = KB_ACK;
96                 return;
97         }
98
99         // Layer +1
100         if(scancode == 0xE0) {
101                 giKB_KeyLayer = 1;
102                 return;
103         }
104         // Layer +2
105         if(scancode == 0xE1) {
106                 giKB_KeyLayer = 2;
107                 return;
108         }
109
110         #if KB_ALT_SCANCODES
111         if(scancode == 0xF0)
112         {
113                 gbKB_KeyUp = 1;
114                 return;
115         }
116         #else
117         if(scancode & 0x80)
118         {
119                 scancode &= 0x7F;
120                 gbKB_KeyUp = 1;
121         }
122         #endif
123
124         // Translate
125         ch = gpKB_Map[giKB_KeyLayer][scancode];
126         //keyNum = giKB_KeyLayer * 256 + 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 'd':       __asm__ __volatile__ ("xchg %bx, %bx"); break;
187                 case 'p':       Threads_Dump(); break;
188                 }
189         }
190         #endif
191
192         // Is shift pressed
193         // - Darn ugly hacks !(!x) means (bool)x
194         if( !(!gbKB_ShiftState) ^ gbKB_CapsState)
195         {
196                 switch(ch)
197                 {
198                 case 0: break;
199                 case '`':       ch = '~';       break;
200                 case '1':       ch = '!';       break;
201                 case '2':       ch = '@';       break;
202                 case '3':       ch = '#';       break;
203                 case '4':       ch = '$';       break;
204                 case '5':       ch = '%';       break;
205                 case '6':       ch = '^';       break;
206                 case '7':       ch = '&';       break;
207                 case '8':       ch = '*';       break;
208                 case '9':       ch = '(';       break;
209                 case '0':       ch = ')';       break;
210                 case '-':       ch = '_';       break;
211                 case '=':       ch = '+';       break;
212                 case '[':       ch = '{';       break;
213                 case ']':       ch = '}';       break;
214                 case '\\':      ch = '|';       break;
215                 case ';':       ch = ':';       break;
216                 case '\'':      ch = '"';       break;
217                 case ',':       ch = '<';       break;
218                 case '.':       ch = '>';       break;
219                 case '/':       ch = '?';       break;
220                 default:
221                         if('a' <= ch && ch <= 'z')
222                                 ch -= 0x20;
223                         break;
224                 }
225         }
226
227         if(gKB_Callback && ch != 0)     gKB_Callback(ch);
228 }
229
230 /**
231  * \fn void KB_UpdateLEDs()
232  * \brief Updates the status of the keyboard LEDs
233  */
234 void KB_UpdateLEDs()
235 {
236         Uint8   leds;
237
238         leds = (gbKB_CapsState ? 4 : 0);
239
240         while( inb(0x64) & 2 ); // Wait for bit 2 to unset
241         outb(0x60, 0xED);       // Send update command
242
243         while( inb(0x64) & 2 ); // Wait for bit 2 to unset
244         outb(0x60, leds);
245 }
246
247 /**
248  * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
249  * \brief Calls an IOCtl Command
250  */
251 int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
252 {
253         switch(Id)
254         {
255         case DRV_IOCTL_TYPE:    return DRV_TYPE_KEYBOARD;
256         case DRV_IOCTL_IDENT:   memcpy(Data, "KB\0\0", 4);      return 1;
257         case DRV_IOCTL_VERSION: return 0x100;
258         case DRV_IOCTL_LOOKUP:  return 0;
259
260         // Sets the Keyboard Callback
261         case KB_IOCTL_SETCALLBACK:
262                 // Sanity Check
263                 if((Uint)Data < KERNEL_BASE)    return 0;
264                 // Can only be set once
265                 if(gKB_Callback != NULL)        return 0;
266                 // Set Callback
267                 gKB_Callback = Data;
268                 return 1;
269
270         default:
271                 return 0;
272         }
273 }

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