ba9eb72cdeda37aeaad1ed40ba6cdd6ce403049a
[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         //Log("KB_IRQHandler: scancode = 0x%02x", scancode);
92
93         // Ignore ACKs
94         if(scancode == 0xFA) {
95                 // Oh man! This is anachic (I'm leaving it here to represent the
96                 // mess that Acess once was)
97                 //kb_lastChar = KB_ACK;
98                 return;
99         }
100
101         // Layer +1
102         if(scancode == 0xE0) {
103                 giKB_KeyLayer = 1;
104                 return;
105         }
106         // Layer +2
107         if(scancode == 0xE1) {
108                 giKB_KeyLayer = 2;
109                 return;
110         }
111
112         #if KB_ALT_SCANCODES
113         if(scancode == 0xF0)
114         {
115                 gbKB_KeyUp = 1;
116                 return;
117         }
118         #else
119         if(scancode & 0x80)
120         {
121                 scancode &= 0x7F;
122                 gbKB_KeyUp = 1;
123         }
124         #endif
125
126         // Translate
127         ch = gpKB_Map[giKB_KeyLayer][scancode];
128         //keyNum = giKB_KeyLayer * 256 + scancode;
129         // Check for unknown key
130         if(!ch && !gbKB_KeyUp)
131                 Log_Warning("Keyboard", "UNK %i %x", giKB_KeyLayer, scancode);
132
133         // Key Up?
134         if (gbKB_KeyUp)
135         {
136                 gbKB_KeyUp = 0;
137                 gbaKB_States[giKB_KeyLayer][scancode] = 0;      // Unset key state flag
138
139                 #if USE_KERNEL_MAGIC
140                 if(ch == KEY_LCTRL)     gbKB_MagicState &= ~1;
141                 if(ch == KEY_LALT)      gbKB_MagicState &= ~2;
142                 #endif
143
144                 if(ch == KEY_LSHIFT)    gbKB_ShiftState &= ~1;
145                 if(ch == KEY_RSHIFT)    gbKB_ShiftState &= ~2;
146
147                 // Call callback
148                 if(ch != 0 && gKB_Callback)
149                         gKB_Callback( ch & 0x80000000 );
150
151                 // Reset Layer
152                 giKB_KeyLayer = 0;
153                 return;
154         }
155
156         // Set the bit relating to the key
157         gbaKB_States[giKB_KeyLayer][scancode] = 1;
158         // Set shift key bits
159         if(ch == KEY_LSHIFT)    gbKB_ShiftState |= 1;
160         if(ch == KEY_RSHIFT)    gbKB_ShiftState |= 2;
161
162         // Check for Caps Lock
163         if(ch == KEY_CAPSLOCK) {
164                 gbKB_CapsState = !gbKB_CapsState;
165                 KB_UpdateLEDs();
166         }
167
168         // Reset Layer
169         giKB_KeyLayer = 0;
170
171         // Ignore Non-Printable Characters
172         if(ch == 0)             return;
173
174         // --- Check for Kernel Magic Combos
175         #if USE_KERNEL_MAGIC
176         if(ch == KEY_LCTRL) {
177                 gbKB_MagicState |= 1;
178                 //Log_Log("Keyboard", "Kernel Magic LCTRL Down\n");
179         }
180         if(ch == KEY_LALT) {
181                 gbKB_MagicState |= 2;
182                 //Log_Log("Keyboard", "Kernel Magic LALT Down\n");
183         }
184         if(gbKB_MagicState == 3)
185         {
186                 switch(ch)
187                 {
188                 case 'd':       __asm__ __volatile__ ("xchg %bx, %bx"); break;
189                 case 'p':       Threads_Dump(); break;
190                 }
191         }
192         #endif
193
194         // Is shift pressed
195         // - Darn ugly hacks !(!x) means (bool)x
196         if( !(!gbKB_ShiftState) ^ gbKB_CapsState)
197         {
198                 switch(ch)
199                 {
200                 case 0: break;
201                 case '`':       ch = '~';       break;
202                 case '1':       ch = '!';       break;
203                 case '2':       ch = '@';       break;
204                 case '3':       ch = '#';       break;
205                 case '4':       ch = '$';       break;
206                 case '5':       ch = '%';       break;
207                 case '6':       ch = '^';       break;
208                 case '7':       ch = '&';       break;
209                 case '8':       ch = '*';       break;
210                 case '9':       ch = '(';       break;
211                 case '0':       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                 case '.':       ch = '>';       break;
221                 case '/':       ch = '?';       break;
222                 default:
223                         if('a' <= ch && ch <= 'z')
224                                 ch -= 0x20;
225                         break;
226                 }
227         }
228
229         if(gKB_Callback && ch != 0)     gKB_Callback(ch);
230 }
231
232 /**
233  * \fn void KB_UpdateLEDs()
234  * \brief Updates the status of the keyboard LEDs
235  */
236 void KB_UpdateLEDs()
237 {
238         Uint8   leds;
239
240         leds = (gbKB_CapsState ? 4 : 0);
241
242         while( inb(0x64) & 2 ); // Wait for bit 2 to unset
243         outb(0x60, 0xED);       // Send update command
244
245         while( inb(0x64) & 2 ); // Wait for bit 2 to unset
246         outb(0x60, leds);
247 }
248
249 /**
250  * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
251  * \brief Calls an IOCtl Command
252  */
253 int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
254 {
255         switch(Id)
256         {
257         case DRV_IOCTL_TYPE:    return DRV_TYPE_KEYBOARD;
258         case DRV_IOCTL_IDENT:   memcpy(Data, "KB\0\0", 4);      return 1;
259         case DRV_IOCTL_VERSION: return 0x100;
260         case DRV_IOCTL_LOOKUP:  return 0;
261
262         // Sets the Keyboard Callback
263         case KB_IOCTL_SETCALLBACK:
264                 // Sanity Check
265                 if((Uint)Data < KERNEL_BASE)    return 0;
266                 // Can only be set once
267                 if(gKB_Callback != NULL)        return 0;
268                 // Set Callback
269                 gKB_Callback = Data;
270                 return 1;
271
272         default:
273                 return 0;
274         }
275 }

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