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

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