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

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