Little KDB update ;-) If you have any problems and/or questions let me know. I hope...
[reactos.git] / reactos / drivers / input / keyboard / keyboard.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: services/dd/keyboard/keyboard.c
5 * PURPOSE: Keyboard driver
6 * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
7 * Jason Filby (jasonfilby@yahoo.com)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ddk/ntddk.h>
13 #include <string.h>
14 #include <ntos/keyboard.h>
15 #include <ntos/minmax.h>
16 #include <rosrtl/string.h>
17
18 #include <ddk/ntddkbd.h>
19 #include <ddk/ntdd8042.h>
20
21 #define NDEBUG
22 #include <debug.h>
23
24 #include "keyboard.h"
25
26 /* GLOBALS *******************************************************************/
27
28 /*
29 * Driver data
30 */
31
32 static KEY_EVENT_RECORD kbdBuffer[KBD_BUFFER_SIZE];
33 static int bufHead,bufTail;
34 static int keysInBuffer;
35 static int extKey;
36 static BYTE ledStatus;
37 static BYTE capsDown,numDown,scrollDown;
38 static DWORD ctrlKeyState;
39 static PKINTERRUPT KbdInterrupt;
40 static KDPC KbdDpc;
41 static PIO_WORKITEM KbdWorkItem = NULL;
42 static BOOLEAN AlreadyOpened = FALSE;
43
44 /*
45 * PURPOSE: Current irp being processed
46 */
47 static PIRP CurrentIrp;
48
49 /*
50 * PURPOSE: Number of keys that have been read into the current irp's buffer
51 */
52 static ULONG KeysRead;
53 static ULONG KeysRequired;
54
55 /*
56 * Virtual key codes table
57 *
58 * Comments:
59 * * PrtSc = VK_PRINT
60 * * Alt+PrtSc (SysRq) = VK_EXECUTE
61 * * Alt = VK_MENU
62 */
63
64 static const WORD vkTable[128]=
65 {
66 /* 00 - 07 */ 0, VK_ESCAPE, VK_1, VK_2, VK_3, VK_4, VK_5, VK_6,
67 /* 08 - 0F */ VK_7, VK_8, VK_9, VK_0, 189, 187, VK_BACK, VK_TAB,
68 /* 10 - 17 */ VK_Q, VK_W, VK_E, VK_R, VK_T, VK_Y, VK_U, VK_I,
69 /* 18 - 1F */ VK_O, VK_P, 219, 221, VK_RETURN, VK_CONTROL, VK_A, VK_S,
70 /* 20 - 27 */ VK_D, VK_F, VK_G, VK_H, VK_J, VK_K, VK_L, 186,
71 /* 28 - 2F */ 222, 192, VK_SHIFT, 220, VK_Z, VK_X, VK_C, VK_V,
72 /* 30 - 37 */ VK_B, VK_N, VK_M, 188, 190, 191, VK_SHIFT, VK_MULTIPLY,
73 /* 38 - 3F */ VK_MENU, VK_SPACE, VK_CAPITAL, VK_F1, VK_F2, VK_F3, VK_F4, VK_F5,
74 /* 40 - 47 */ VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, VK_NUMLOCK, VK_SCROLL, VK_HOME,
75 /* 48 - 4F */ VK_UP, VK_PRIOR, VK_SUBTRACT, VK_LEFT, VK_CLEAR, VK_RIGHT, VK_ADD, VK_END,
76 /* 50 - 57 */ VK_DOWN, VK_NEXT, VK_INSERT, VK_DELETE, VK_EXECUTE, 0, 0, VK_F11,
77 /* 58 - 5F */ VK_F12, 0, 0, 91, 92, 93, 0, 0,
78 /* 60 - 67 */ 0, 0, 0, 0, 0, 0, 0, 0,
79 /* 68 - 6F */ 0, 0, 0, 0, 0, 0, 0, 0,
80 /* 70 - 77 */ 0, 0, 0, 0, 0, 0, 0, 0,
81 /* 78 - 7F */ 0, 0, 0, 0, 0, 0, 0, VK_PAUSE
82 };
83 static const WORD vkKeypadTable[13]= /* 47 - 53 */
84 {
85 VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_SUBTRACT,
86 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_ADD,
87 VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD0, VK_DECIMAL
88 };
89
90
91 /*
92 * ASCII translation tables
93 */
94
95 static const BYTE asciiTable1[10]=
96 {
97 ')','!','@','#','$','%','^','&','*','('
98 };
99 static const BYTE asciiTable2[16]=
100 {
101 '0','1','2','3','4','5','6','7','8','9','*','+',0,'-','.','/'
102 };
103 static const BYTE asciiTable3[37]=
104 {
105 ';','=',',','-','.','/','`', 0, 0, 0, 0, 0, 0, 0, 0,
106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 '[', '\\', ']', '\''
108 };
109 static const BYTE asciiTable4[37]=
110 {
111 ':','+','<','_','>','?','~', 0, 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 '{', '|', '}', '"'
114 };
115
116 VOID STDCALL
117 KdSystemDebugControl(ULONG Code);
118
119 static LONG DoSystemDebug = -1;
120 static BOOLEAN InSysRq = FALSE;
121
122 /* FUNCTIONS *****************************************************************/
123
124 static void KbdWrite(int addr,BYTE data)
125 /*
126 * FUNCTION: Write data to keyboard
127 */
128 {
129 BYTE status;
130
131 do
132 {
133 status=READ_PORT_UCHAR((PUCHAR)KBD_CTRL_PORT); // Wait until input buffer empty
134 } while(status & KBD_IBF);
135 WRITE_PORT_UCHAR((PUCHAR)addr,data);
136 }
137
138 static int KbdReadData(void)
139 /*
140 * FUNCTION: Read data from port 0x60
141 */
142 {
143 int i;
144 BYTE status,data;
145
146 i=500000;
147 do
148 {
149 status=READ_PORT_UCHAR((PUCHAR)KBD_CTRL_PORT);
150 if (!(status & KBD_OBF)) // Check if data available
151 continue;
152 data=READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
153 if (status & (KBD_GTO | KBD_PERR)) // Check for timeout error
154 continue;
155 return data;
156 } while(--i);
157 return -1; // Timed out
158 }
159
160
161 /*
162 * Set keyboard LED's
163 */
164
165 static void SetKeyboardLEDs(BYTE status)
166 {
167 KbdWrite(KBD_DATA_PORT,0xED);
168 if (KbdReadData()!=KBD_ACK) // Error
169 return;
170 KbdWrite(KBD_DATA_PORT,status);
171 KbdReadData();
172 }
173
174
175 /*
176 * Process scan code
177 */
178
179 static void ProcessScanCode(BYTE scanCode,BOOL isDown)
180 {
181 switch(scanCode)
182 {
183 case 0x1D: // Ctrl
184 if (extKey)
185 {
186 if (isDown)
187 ctrlKeyState|=RIGHT_CTRL_PRESSED;
188 else
189 ctrlKeyState&=~RIGHT_CTRL_PRESSED;
190 }
191 else
192 {
193 if (isDown)
194 ctrlKeyState|=LEFT_CTRL_PRESSED;
195 else
196 ctrlKeyState&=~LEFT_CTRL_PRESSED;
197 }
198 break;
199 case 0x2A: // Left shift
200 case 0x36: // Right shift
201 if (isDown)
202 ctrlKeyState|=SHIFT_PRESSED;
203 else
204 ctrlKeyState&=~SHIFT_PRESSED;
205 break;
206 case 0x38: // Alt
207 if (extKey)
208 {
209 if (isDown)
210 ctrlKeyState|=RIGHT_ALT_PRESSED;
211 else
212 ctrlKeyState&=~RIGHT_ALT_PRESSED;
213 }
214 else
215 {
216 if (isDown)
217 ctrlKeyState|=LEFT_ALT_PRESSED;
218 else
219 ctrlKeyState&=~LEFT_ALT_PRESSED;
220 }
221 break;
222 case 0x3A: // CapsLock
223 if (ctrlKeyState & CTRL_PRESSED)
224 break;
225 if (isDown)
226 {
227 if (!capsDown)
228 {
229 capsDown=1;
230 if (ctrlKeyState & CAPSLOCK_ON)
231 {
232 ledStatus&=~KBD_LED_CAPS;
233 ctrlKeyState&=~CAPSLOCK_ON;
234 }
235 else
236 {
237 ledStatus|=KBD_LED_CAPS;
238 ctrlKeyState|=CAPSLOCK_ON;
239 }
240 SetKeyboardLEDs(ledStatus);
241 }
242 }
243 else
244 {
245 capsDown=0;
246 }
247 break;
248 case 0x45: // NumLock
249 if (ctrlKeyState & CTRL_PRESSED)
250 break;
251 if (isDown)
252 {
253 if (!numDown)
254 {
255 numDown=1;
256 if (ctrlKeyState & NUMLOCK_ON)
257 {
258 ledStatus&=~KBD_LED_NUM;
259 ctrlKeyState&=~NUMLOCK_ON;
260 }
261 else
262 {
263 ledStatus|=KBD_LED_NUM;
264 ctrlKeyState|=NUMLOCK_ON;
265 }
266 SetKeyboardLEDs(ledStatus);
267 }
268 }
269 else
270 {
271 numDown=0;
272 }
273 break;
274 case 0x46: // ScrollLock
275 if (ctrlKeyState & CTRL_PRESSED)
276 break;
277 if (isDown)
278 {
279 if (!scrollDown)
280 {
281 scrollDown=1;
282 if (ctrlKeyState & SCROLLLOCK_ON)
283 {
284 ledStatus&=~KBD_LED_SCROLL;
285 ctrlKeyState&=~SCROLLLOCK_ON;
286 }
287 else
288 {
289 ledStatus|=KBD_LED_SCROLL;
290 ctrlKeyState|=SCROLLLOCK_ON;
291 }
292 SetKeyboardLEDs(ledStatus);
293 }
294 }
295 else
296 {
297 scrollDown=0;
298 }
299 break;
300 default:
301 break;
302 }
303 }
304
305
306 /*
307 * Translate virtual key code to ASCII
308 */
309
310 static BYTE VirtualToAscii(WORD keyCode,BOOL isDown)
311 {
312 if ((ctrlKeyState & ALT_PRESSED)&&(ctrlKeyState & CTRL_PRESSED))
313 return 0; // Ctrl+Alt+char always 0
314 if ((!isDown)&&(ctrlKeyState & ALT_PRESSED))
315 return 0; // Alt+char is 0 when key is released
316
317 if (ctrlKeyState & CTRL_PRESSED)
318 {
319 if ((keyCode>=VK_A)&&(keyCode<=VK_Z))
320 return keyCode-VK_A+1;
321 switch(keyCode)
322 {
323 case VK_SPACE:
324 return ' ';
325 case VK_BACK:
326 return 127;
327 case VK_RETURN:
328 return '\r';
329 case 219: /* [ */
330 if (ctrlKeyState & SHIFT_PRESSED)
331 return 0;
332 return 27;
333 case 220: /* \ */
334 if (ctrlKeyState & SHIFT_PRESSED)
335 return 0;
336 return 28;
337 case 221: /* ] */
338 if (ctrlKeyState & SHIFT_PRESSED)
339 return 0;
340 return 29;
341 default:
342 return 0;
343 }
344 }
345
346 if ((keyCode>=VK_A)&&(keyCode<=VK_Z))
347 {
348 if (ctrlKeyState & CAPSLOCK_ON)
349 if (ctrlKeyState & SHIFT_PRESSED)
350 return keyCode-VK_A+'a';
351 else
352 return keyCode-VK_A+'A';
353 else
354 if (ctrlKeyState & SHIFT_PRESSED)
355 return keyCode-VK_A+'A';
356 else
357 return keyCode-VK_A+'a';
358 }
359
360 if ((keyCode>=VK_0)&&(keyCode<=VK_9))
361 {
362 if (ctrlKeyState & SHIFT_PRESSED)
363 return asciiTable1[keyCode-VK_0];
364 else
365 return keyCode-VK_0+'0';
366 }
367
368 if ((keyCode>=VK_NUMPAD0)&&(keyCode<=VK_DIVIDE))
369 return asciiTable2[keyCode-VK_NUMPAD0];
370
371 if ((keyCode>=186)&&(keyCode<=222))
372 {
373 if (ctrlKeyState & SHIFT_PRESSED)
374 return asciiTable4[keyCode-186];
375 else
376 return asciiTable3[keyCode-186];
377 }
378
379 switch(keyCode)
380 {
381 case VK_SPACE:
382 return ' ';
383 case VK_RETURN:
384 return '\r';
385 case VK_BACK:
386 return 8;
387 case VK_TAB:
388 return 9;
389 }
390 return 0;
391 }
392
393
394 /*
395 * Translate scan code to virtual key code
396 */
397
398 static WORD ScanToVirtual(BYTE scanCode)
399 {
400 if ((scanCode>=0x47)&&(scanCode<=0x53)&&(ctrlKeyState & NUMLOCK_ON)&&
401 (!extKey)&&(!(ctrlKeyState & SHIFT_PRESSED)))
402 return vkKeypadTable[scanCode-0x47];
403 if ((scanCode==0x35)&&(extKey)) // Gray divide
404 return VK_DIVIDE;
405 if ((scanCode==0x37)&&(extKey)) // Print screen
406 return VK_PRINT;
407 return vkTable[scanCode];
408 }
409
410
411 /*
412 * Debug request handler
413 */
414
415 static VOID STDCALL
416 KbdWorkItemRoutine(IN PDEVICE_OBJECT DeviceObject,
417 IN PVOID Context)
418 {
419 LONG Debug;
420
421 Debug = InterlockedExchange(&DoSystemDebug, -1);
422 if (Debug != -1)
423 {
424 KdSystemDebugControl(Debug);
425 }
426 }
427
428
429 /*
430 * Keyboard IRQ handler
431 */
432
433 static VOID STDCALL
434 KbdDpcRoutine(PKDPC Dpc,
435 PVOID DeferredContext,
436 PVOID SystemArgument1,
437 PVOID SystemArgument2)
438 {
439 PIRP Irp = (PIRP)SystemArgument2;
440 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)SystemArgument1;
441
442 if (SystemArgument1 == NULL && DoSystemDebug != -1)
443 {
444 if (KbdWorkItem != NULL)
445 {
446 IoQueueWorkItem(KbdWorkItem, (PIO_WORKITEM_ROUTINE)KbdWorkItemRoutine, DelayedWorkQueue, NULL);
447 }
448 else
449 {
450 KdSystemDebugControl(DoSystemDebug);
451 DoSystemDebug = -1;
452 }
453 return;
454 }
455
456 CHECKPOINT;
457 DPRINT("KbdDpcRoutine(DeviceObject %x, Irp %x)\n",
458 DeviceObject,Irp);
459 Irp->IoStatus.Status = STATUS_SUCCESS;
460 Irp->IoStatus.Information = 0;
461 IoCompleteRequest(Irp,IO_NO_INCREMENT);
462 IoStartNextPacket(DeviceObject,FALSE);
463 }
464
465
466 static BOOLEAN STDCALL
467 KeyboardHandler(PKINTERRUPT Interrupt,
468 PVOID Context)
469 {
470 BYTE thisKey;
471 BOOL isDown;
472 static BYTE lastKey;
473 CHAR Status;
474 PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
475 PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
476
477 CHECKPOINT;
478
479 /*
480 * Check status
481 */
482 Status = READ_PORT_UCHAR((PUCHAR)KBD_CTRL_PORT);
483 if (!(Status & KBD_OBF))
484 {
485 return (FALSE);
486 }
487
488 // Read scan code
489 thisKey=READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
490
491 // Call hook routine. May change scancode value.
492 if (deviceExtension->IsrHookCallback) {
493 BOOLEAN cont = FALSE, ret;
494 //BUG BUG: rewrite to have valid CurrentScanState!!!
495 ret = (*deviceExtension->IsrHookCallback)(
496 deviceObject,
497 NULL,//&deviceExtension->CurrentInput,
498 NULL,//&deviceExtension->CurrentOutput,
499 Status,
500 &thisKey, //&scanCode,
501 &cont,
502 NULL //&deviceExtension->CurrentScanState
503 );
504
505 if (!cont) {
506 return ret;
507 }
508 }
509
510
511 if ((thisKey==0xE0)||(thisKey==0xE1)) // Extended key
512 {
513 extKey=1; // Wait for next byte
514 lastKey=thisKey;
515 return FALSE;
516 }
517
518 isDown=!(thisKey & 0x80);
519 thisKey&=0x7F;
520
521 // The keyboard maintains its own internal caps lock and num lock
522 // statuses. In caps lock mode E0 AA precedes make code and
523 // E0 2A follow break code. In num lock mode, E0 2A precedes
524 // make code and E0 AA follow break code. We maintain our own caps lock
525 // and num lock statuses, so we will just ignore these.
526 // Some keyboards have L-Shift/R-Shift modes instead of caps lock
527 // mode. If right shift pressed, E0 B6 / E0 36 pairs generated.
528 if (extKey & ((thisKey==0x2A)||(thisKey==0x36)))
529 {
530 extKey=0;
531 return FALSE;
532 }
533
534 // Check for PAUSE sequence
535 if (extKey && (lastKey==0xE1))
536 {
537 if (thisKey==0x1D)
538 lastKey=0xFF; // Sequence is OK
539 else
540 extKey=0;
541 return FALSE;
542 }
543 if (extKey && (lastKey==0xFF))
544 {
545 if (thisKey!=0x45)
546 {
547 extKey=0; // Bad sequence
548 return FALSE;
549 }
550 thisKey=0x7F; // Pseudo-code for PAUSE
551 }
552
553 ProcessScanCode(thisKey,isDown);
554
555 // DbgPrint("Key: %c\n",VirtualToAscii(ScanToVirtual(thisKey),isDown));
556 // DbgPrint("Key: %x\n",ScanToVirtual(thisKey));
557 if (ScanToVirtual(thisKey) == VK_TAB && isDown)
558 {
559 InSysRq = TRUE;
560 }
561 else if (ScanToVirtual(thisKey) == VK_TAB && !isDown)
562 {
563 InSysRq = FALSE;
564 }
565 else if (InSysRq == TRUE && ScanToVirtual(thisKey) >= VK_A &&
566 ScanToVirtual(thisKey) <= VK_Z && isDown)
567 {
568 InterlockedExchange(&DoSystemDebug, ScanToVirtual(thisKey) - VK_A);
569 KeInsertQueueDpc(&KbdDpc, NULL, NULL);
570 return(TRUE);
571 }
572
573 if (CurrentIrp!=NULL)
574 {
575 KEY_EVENT_RECORD* rec = (KEY_EVENT_RECORD *)
576 CurrentIrp->AssociatedIrp.SystemBuffer;
577
578 CHECKPOINT;
579
580 rec[KeysRead].bKeyDown=isDown;
581 rec[KeysRead].wRepeatCount=1;
582 rec[KeysRead].wVirtualKeyCode=ScanToVirtual(thisKey);
583 rec[KeysRead].wVirtualScanCode=thisKey;
584 rec[KeysRead].uChar.AsciiChar=VirtualToAscii(rec->wVirtualKeyCode,isDown);
585 rec[KeysRead].dwControlKeyState=ctrlKeyState;
586 if (extKey)
587 {
588 rec[KeysRead].dwControlKeyState|=ENHANCED_KEY;
589 extKey = 0;
590 }
591 KeysRead++;
592 DPRINT("KeysRequired %d KeysRead %x\n",KeysRequired,KeysRead);
593 if (KeysRead==KeysRequired)
594 {
595 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT) Context;
596 KeInsertQueueDpc(&KbdDpc,DeviceObject,CurrentIrp);
597 CurrentIrp=NULL;
598 }
599 CHECKPOINT;
600 return TRUE;
601 }
602
603 // Buffer is full ?
604 if (keysInBuffer==KBD_BUFFER_SIZE) // Buffer is full
605 {
606 extKey=0;
607 return(TRUE);
608 }
609 kbdBuffer[bufHead].bKeyDown=isDown;
610 kbdBuffer[bufHead].wRepeatCount=1;
611 kbdBuffer[bufHead].wVirtualKeyCode=ScanToVirtual(thisKey);
612 kbdBuffer[bufHead].wVirtualScanCode=thisKey;
613 kbdBuffer[bufHead].uChar.UnicodeChar=0;
614 // kbdBuffer[bufHead].uChar.AsciiChar=TranslateScanCode(thisKey);
615 kbdBuffer[bufHead].uChar.AsciiChar=VirtualToAscii(kbdBuffer[bufHead].wVirtualKeyCode,isDown);
616 kbdBuffer[bufHead].dwControlKeyState=ctrlKeyState;
617 if (extKey)
618 kbdBuffer[bufHead].dwControlKeyState|=ENHANCED_KEY;
619 bufHead++;
620 bufHead&=KBD_WRAP_MASK; // Modulo KBD_BUFFER_SIZE
621 keysInBuffer++;
622 extKey=0;
623 return TRUE;
624 }
625
626
627 //
628 // Initialize keyboard
629 //
630 static void KeyboardConnectInterrupt(PDEVICE_OBJECT DeviceObject)
631 {
632 ULONG MappedIrq;
633 KIRQL Dirql;
634 KAFFINITY Affinity;
635 NTSTATUS Status;
636
637 MappedIrq = HalGetInterruptVector(Internal,
638 0,
639 0,
640 KEYBOARD_IRQ,
641 &Dirql,
642 &Affinity);
643 Status = IoConnectInterrupt(&KbdInterrupt,
644 KeyboardHandler,
645 (PVOID)DeviceObject,
646 NULL,
647 MappedIrq,
648 Dirql,
649 Dirql,
650 0,
651 FALSE,
652 Affinity,
653 FALSE);
654 }
655
656 VOID
657 KbdClearInput(VOID)
658 {
659 ULONG i;
660 CHAR Status;
661
662 for (i = 0; i < 100; i++)
663 {
664 Status = READ_PORT_UCHAR((PUCHAR)KBD_CTRL_PORT);
665 if (!(Status & KBD_OBF))
666 {
667 return;
668 }
669 (VOID)READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
670 }
671 }
672
673 static int InitializeKeyboard(PDEVICE_OBJECT DeviceObject)
674 {
675 // Initialize variables
676 bufHead=0;
677 bufTail=0;
678 keysInBuffer=0;
679 ledStatus=0;
680 capsDown=0;
681 numDown=0;
682 scrollDown=0;
683 ctrlKeyState=0;
684 extKey=0;
685
686 KbdClearInput();
687 KeyboardConnectInterrupt(DeviceObject);
688 KeInitializeDpc(&KbdDpc,KbdDpcRoutine,NULL);
689 KbdWorkItem = IoAllocateWorkItem(DeviceObject);
690 if (KbdWorkItem == NULL)
691 {
692 DPRINT("Warning: Couldn't allocate work item!\n");
693 }
694 return 0;
695 }
696
697 /*
698 * Read data from keyboard buffer
699 */
700 BOOLEAN STDCALL
701 KbdSynchronizeRoutine(PVOID Context)
702 {
703 PIRP Irp = (PIRP)Context;
704 KEY_EVENT_RECORD* rec = (KEY_EVENT_RECORD *)Irp->AssociatedIrp.SystemBuffer;
705 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
706 ULONG NrToRead = stk->Parameters.Read.Length/sizeof(KEY_EVENT_RECORD);
707 int i;
708
709 DPRINT("NrToRead %d keysInBuffer %d\n",NrToRead,keysInBuffer);
710 NrToRead = min(NrToRead,keysInBuffer);
711
712 DPRINT("NrToRead %d stk->Parameters.Read.Length %d\n",
713 NrToRead,stk->Parameters.Read.Length);
714 DPRINT("sizeof(KEY_EVENT_RECORD) %d\n",sizeof(KEY_EVENT_RECORD));
715 for (i=0;i<NrToRead;i++)
716 {
717 memcpy(&rec[i],&kbdBuffer[bufTail],sizeof(KEY_EVENT_RECORD));
718 bufTail++;
719 bufTail&=KBD_WRAP_MASK;
720 keysInBuffer--;
721 }
722 if ((stk->Parameters.Read.Length/sizeof(KEY_EVENT_RECORD))==NrToRead)
723 {
724 return(TRUE);
725 }
726
727 KeysRequired=stk->Parameters.Read.Length/sizeof(KEY_EVENT_RECORD);
728 KeysRead=NrToRead;
729 CurrentIrp=Irp;
730
731 return(FALSE);
732 }
733
734 VOID STDCALL KbdStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
735 {
736 #ifndef NDEBUG
737 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
738 #endif
739
740 DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
741
742 if (KeSynchronizeExecution(KbdInterrupt, KbdSynchronizeRoutine, Irp))
743 {
744 KIRQL oldIrql;
745 Irp->IoStatus.Status = STATUS_SUCCESS;
746 Irp->IoStatus.Information = 0;
747 IoCompleteRequest(Irp, IO_NO_INCREMENT);
748 oldIrql = KeGetCurrentIrql();
749 if (oldIrql < DISPATCH_LEVEL)
750 {
751 KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
752 IoStartNextPacket (DeviceObject, FALSE);
753 KeLowerIrql(oldIrql);
754 }
755 else
756 {
757 IoStartNextPacket (DeviceObject, FALSE);
758 }
759 }
760
761 DPRINT("stk->Parameters.Read.Length %d\n",stk->Parameters.Read.Length);
762 DPRINT("KeysRequired %d\n",KeysRequired);
763 }
764
765 NTSTATUS STDCALL KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
766 {
767 PIO_STACK_LOCATION stk;
768 PINTERNAL_I8042_HOOK_KEYBOARD hookKeyboard;
769 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
770 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
771
772 Irp->IoStatus.Information = 0;
773 stk = IoGetCurrentIrpStackLocation(Irp);
774
775 switch (stk->Parameters.DeviceIoControl.IoControlCode)
776 {
777 /*-----------------11/29/2001 4:12PM----------------
778 * This internal ioctrl belongs in i8042 driver. Should be
779 * moved to the appropriate driver later.
780 * --------------------------------------------------*/
781 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
782
783 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(INTERNAL_I8042_HOOK_KEYBOARD))
784 {
785 DPRINT(("Keyboard IOCTL_INTERNAL_I8042_HOOK_KEYBOARD invalid buffer size\n"));
786 status = STATUS_INVALID_PARAMETER;
787 }
788 else {
789 //
790 // Copy the values if they are filled in
791 //
792 hookKeyboard = (PINTERNAL_I8042_HOOK_KEYBOARD)
793 stk->Parameters.DeviceIoControl.Type3InputBuffer;
794
795 DevExt->HookContext = hookKeyboard->Context;
796 if (hookKeyboard->InitializationRoutine) {
797 DbgPrint("Keyboard: InitializationHookCallback NOT IMPLEMENTED\n");
798 DevExt->InitializationHookCallback =
799 hookKeyboard->InitializationRoutine;
800 }
801
802 if (hookKeyboard->IsrRoutine) {
803 DevExt->IsrHookCallback = hookKeyboard->IsrRoutine;
804 }
805
806 status = STATUS_SUCCESS;
807 }
808 break;
809 default:
810 status = STATUS_INVALID_DEVICE_REQUEST;
811 break;
812 }
813
814 Irp->IoStatus.Status = status;
815 IoCompleteRequest(Irp, IO_NO_INCREMENT);
816 return status;
817 }
818
819 NTSTATUS STDCALL KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
820 {
821 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
822 NTSTATUS Status;
823
824 DPRINT("DeviceObject %x\n",DeviceObject);
825 DPRINT("Irp %x\n",Irp);
826
827 DPRINT("IRP_MJ_CREATE %d stk->MajorFunction %d\n",
828 IRP_MJ_CREATE, stk->MajorFunction);
829 DPRINT("AlreadyOpened %d\n",AlreadyOpened);
830
831 switch (stk->MajorFunction)
832 {
833 case IRP_MJ_CREATE:
834 if (AlreadyOpened == TRUE)
835 {
836 CHECKPOINT;
837 // Status = STATUS_UNSUCCESSFUL;
838 Status = STATUS_SUCCESS;
839 }
840 else
841 {
842 CHECKPOINT;
843 Status = STATUS_SUCCESS;
844 AlreadyOpened = TRUE;
845 }
846 break;
847
848 case IRP_MJ_CLOSE:
849 Status = STATUS_SUCCESS;
850 break;
851
852 case IRP_MJ_READ:
853 DPRINT("Handling Read request\n");
854 DPRINT("Queueing packet\n");
855 IoMarkIrpPending(Irp);
856 IoStartPacket(DeviceObject,Irp,NULL,NULL);
857 return(STATUS_PENDING);
858
859 default:
860 Status = STATUS_NOT_IMPLEMENTED;
861 break;
862 }
863
864 Irp->IoStatus.Status = Status;
865 Irp->IoStatus.Information = 0;
866 IoCompleteRequest(Irp,IO_NO_INCREMENT);
867 DPRINT("Status %d\n",Status);
868 return(Status);
869 }
870
871 NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
872 PUNICODE_STRING RegistryPath)
873 /*
874 * FUNCTION: Module entry point
875 */
876 {
877 PDEVICE_OBJECT DeviceObject;
878 UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\Keyboard");
879 UNICODE_STRING SymlinkName = ROS_STRING_INITIALIZER(L"\\??\\Keyboard");
880
881 DPRINT("Keyboard Driver 0.0.4\n");
882
883 DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdDispatch;
884 DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdDispatch;
885 DriverObject->MajorFunction[IRP_MJ_READ] = KbdDispatch;
886 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
887 KbdInternalDeviceControl;
888
889 DriverObject->DriverStartIo = KbdStartIo;
890
891 IoCreateDevice(DriverObject,
892 sizeof(DEVICE_EXTENSION),
893 &DeviceName,
894 FILE_DEVICE_KEYBOARD,
895 0,
896 TRUE,
897 &DeviceObject);
898
899 RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
900
901 DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
902 InitializeKeyboard( DeviceObject );
903
904 IoCreateSymbolicLink(&SymlinkName, &DeviceName);
905
906 return(STATUS_SUCCESS);
907 }