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

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