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)
10 /* INCLUDES ****************************************************************/
12 #define NTOS_KERNEL_MODE
14 #include <ntos/keyboard.h>
15 #include <ddk/ntddkbd.h>
16 #include <ddk/ntdd8042.h>
18 #include <ntos/minmax.h>
25 /* GLOBALS *******************************************************************/
31 static KEY_EVENT_RECORD kbdBuffer
[KBD_BUFFER_SIZE
];
32 static int bufHead
,bufTail
;
33 static int keysInBuffer
;
35 static BYTE ledStatus
;
36 static BYTE capsDown
,numDown
,scrollDown
;
37 static DWORD ctrlKeyState
;
38 static PKINTERRUPT KbdInterrupt
;
40 static BOOLEAN AlreadyOpened
= FALSE
;
43 * PURPOSE: Current irp being processed
45 static PIRP CurrentIrp
;
48 * PURPOSE: Number of keys that have been read into the current irp's buffer
50 static ULONG KeysRead
;
51 static ULONG KeysRequired
;
54 * Virtual key codes table
58 * * Alt+PrtSc (SysRq) = VK_EXECUTE
62 static const WORD vkTable
[128]=
64 /* 00 - 07 */ 0, VK_ESCAPE
, VK_1
, VK_2
, VK_3
, VK_4
, VK_5
, VK_6
,
65 /* 08 - 0F */ VK_7
, VK_8
, VK_9
, VK_0
, 189, 187, VK_BACK
, VK_TAB
,
66 /* 10 - 17 */ VK_Q
, VK_W
, VK_E
, VK_R
, VK_T
, VK_Y
, VK_U
, VK_I
,
67 /* 18 - 1F */ VK_O
, VK_P
, 219, 221, VK_RETURN
, VK_CONTROL
, VK_A
, VK_S
,
68 /* 20 - 27 */ VK_D
, VK_F
, VK_G
, VK_H
, VK_J
, VK_K
, VK_L
, 186,
69 /* 28 - 2F */ 222, 192, VK_SHIFT
, 220, VK_Z
, VK_X
, VK_C
, VK_V
,
70 /* 30 - 37 */ VK_B
, VK_N
, VK_M
, 188, 190, 191, VK_SHIFT
, VK_MULTIPLY
,
71 /* 38 - 3F */ VK_MENU
, VK_SPACE
, VK_CAPITAL
, VK_F1
, VK_F2
, VK_F3
, VK_F4
, VK_F5
,
72 /* 40 - 47 */ VK_F6
, VK_F7
, VK_F8
, VK_F9
, VK_F10
, VK_NUMLOCK
, VK_SCROLL
, VK_HOME
,
73 /* 48 - 4F */ VK_UP
, VK_PRIOR
, VK_SUBTRACT
, VK_LEFT
, VK_CLEAR
, VK_RIGHT
, VK_ADD
, VK_END
,
74 /* 50 - 57 */ VK_DOWN
, VK_NEXT
, VK_INSERT
, VK_DELETE
, VK_EXECUTE
, 0, 0, VK_F11
,
75 /* 58 - 5F */ VK_F12
, 0, 0, 91, 92, 93, 0, 0,
76 /* 60 - 67 */ 0, 0, 0, 0, 0, 0, 0, 0,
77 /* 68 - 6F */ 0, 0, 0, 0, 0, 0, 0, 0,
78 /* 70 - 77 */ 0, 0, 0, 0, 0, 0, 0, 0,
79 /* 78 - 7F */ 0, 0, 0, 0, 0, 0, 0, VK_PAUSE
81 static const WORD vkKeypadTable
[13]= /* 47 - 53 */
83 VK_NUMPAD7
, VK_NUMPAD8
, VK_NUMPAD9
, VK_SUBTRACT
,
84 VK_NUMPAD4
, VK_NUMPAD5
, VK_NUMPAD6
, VK_ADD
,
85 VK_NUMPAD1
, VK_NUMPAD2
, VK_NUMPAD3
, VK_NUMPAD0
, VK_DECIMAL
90 * ASCII translation tables
93 static const BYTE asciiTable1
[10]=
95 ')','!','@','#','$','%','^','&','*','('
97 static const BYTE asciiTable2
[16]=
99 '0','1','2','3','4','5','6','7','8','9','*','+',0,'-','.','/'
101 static const BYTE asciiTable3
[37]=
103 ';','=',',','-','.','/','`', 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 static const BYTE asciiTable4
[37]=
109 ':','+','<','_','>','?','~', 0, 0, 0, 0, 0, 0, 0, 0,
110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 KdSystemDebugControl(ULONG Code
);
117 static LONG DoSystemDebug
= -1;
118 static BOOLEAN InSysRq
= FALSE
;
120 /* FUNCTIONS *****************************************************************/
122 static void KbdWrite(int addr
,BYTE data
)
124 * FUNCTION: Write data to keyboard
131 status
=READ_PORT_UCHAR((PUCHAR
)KBD_CTRL_PORT
); // Wait until input buffer empty
132 } while(status
& KBD_IBF
);
133 WRITE_PORT_UCHAR((PUCHAR
)addr
,data
);
136 static int KbdReadData(void)
138 * FUNCTION: Read data from port 0x60
147 status
=READ_PORT_UCHAR((PUCHAR
)KBD_CTRL_PORT
);
148 if (!(status
& KBD_OBF
)) // Check if data available
150 data
=READ_PORT_UCHAR((PUCHAR
)KBD_DATA_PORT
);
151 if (status
& (KBD_GTO
| KBD_PERR
)) // Check for timeout error
155 return -1; // Timed out
163 static void SetKeyboardLEDs(BYTE status
)
165 KbdWrite(KBD_DATA_PORT
,0xED);
166 if (KbdReadData()!=KBD_ACK
) // Error
168 KbdWrite(KBD_DATA_PORT
,status
);
177 static void ProcessScanCode(BYTE scanCode
,BOOL isDown
)
185 ctrlKeyState
|=RIGHT_CTRL_PRESSED
;
187 ctrlKeyState
&=~RIGHT_CTRL_PRESSED
;
192 ctrlKeyState
|=LEFT_CTRL_PRESSED
;
194 ctrlKeyState
&=~LEFT_CTRL_PRESSED
;
197 case 0x2A: // Left shift
198 case 0x36: // Right shift
200 ctrlKeyState
|=SHIFT_PRESSED
;
202 ctrlKeyState
&=~SHIFT_PRESSED
;
208 ctrlKeyState
|=RIGHT_ALT_PRESSED
;
210 ctrlKeyState
&=~RIGHT_ALT_PRESSED
;
215 ctrlKeyState
|=LEFT_ALT_PRESSED
;
217 ctrlKeyState
&=~LEFT_ALT_PRESSED
;
220 case 0x3A: // CapsLock
221 if (ctrlKeyState
& CTRL_PRESSED
)
228 if (ctrlKeyState
& CAPSLOCK_ON
)
230 ledStatus
&=~KBD_LED_CAPS
;
231 ctrlKeyState
&=~CAPSLOCK_ON
;
235 ledStatus
|=KBD_LED_CAPS
;
236 ctrlKeyState
|=CAPSLOCK_ON
;
238 SetKeyboardLEDs(ledStatus
);
246 case 0x45: // NumLock
247 if (ctrlKeyState
& CTRL_PRESSED
)
254 if (ctrlKeyState
& NUMLOCK_ON
)
256 ledStatus
&=~KBD_LED_NUM
;
257 ctrlKeyState
&=~NUMLOCK_ON
;
261 ledStatus
|=KBD_LED_NUM
;
262 ctrlKeyState
|=NUMLOCK_ON
;
264 SetKeyboardLEDs(ledStatus
);
272 case 0x46: // ScrollLock
273 if (ctrlKeyState
& CTRL_PRESSED
)
280 if (ctrlKeyState
& SCROLLLOCK_ON
)
282 ledStatus
&=~KBD_LED_SCROLL
;
283 ctrlKeyState
&=~SCROLLLOCK_ON
;
287 ledStatus
|=KBD_LED_SCROLL
;
288 ctrlKeyState
|=SCROLLLOCK_ON
;
290 SetKeyboardLEDs(ledStatus
);
305 * Translate virtual key code to ASCII
308 static BYTE
VirtualToAscii(WORD keyCode
,BOOL isDown
)
310 if ((ctrlKeyState
& ALT_PRESSED
)&&(ctrlKeyState
& CTRL_PRESSED
))
311 return 0; // Ctrl+Alt+char always 0
312 if ((!isDown
)&&(ctrlKeyState
& ALT_PRESSED
))
313 return 0; // Alt+char is 0 when key is released
315 if (ctrlKeyState
& CTRL_PRESSED
)
317 if ((keyCode
>=VK_A
)&&(keyCode
<=VK_Z
))
318 return keyCode
-VK_A
+1;
328 if (ctrlKeyState
& SHIFT_PRESSED
)
332 if (ctrlKeyState
& SHIFT_PRESSED
)
336 if (ctrlKeyState
& SHIFT_PRESSED
)
344 if ((keyCode
>=VK_A
)&&(keyCode
<=VK_Z
))
346 if (ctrlKeyState
& CAPSLOCK_ON
)
347 if (ctrlKeyState
& SHIFT_PRESSED
)
348 return keyCode
-VK_A
+'a';
350 return keyCode
-VK_A
+'A';
352 if (ctrlKeyState
& SHIFT_PRESSED
)
353 return keyCode
-VK_A
+'A';
355 return keyCode
-VK_A
+'a';
358 if ((keyCode
>=VK_0
)&&(keyCode
<=VK_9
))
360 if (ctrlKeyState
& SHIFT_PRESSED
)
361 return asciiTable1
[keyCode
-VK_0
];
363 return keyCode
-VK_0
+'0';
366 if ((keyCode
>=VK_NUMPAD0
)&&(keyCode
<=VK_DIVIDE
))
367 return asciiTable2
[keyCode
-VK_NUMPAD0
];
369 if ((keyCode
>=186)&&(keyCode
<=222))
371 if (ctrlKeyState
& SHIFT_PRESSED
)
372 return asciiTable4
[keyCode
-186];
374 return asciiTable3
[keyCode
-186];
393 * Translate scan code to virtual key code
396 static WORD
ScanToVirtual(BYTE scanCode
)
398 if ((scanCode
>=0x47)&&(scanCode
<=0x53)&&(ctrlKeyState
& NUMLOCK_ON
)&&
399 (!extKey
)&&(!(ctrlKeyState
& SHIFT_PRESSED
)))
400 return vkKeypadTable
[scanCode
-0x47];
401 if ((scanCode
==0x35)&&(extKey
)) // Gray divide
403 if ((scanCode
==0x37)&&(extKey
)) // Print screen
405 return vkTable
[scanCode
];
410 * Keyboard IRQ handler
414 KbdDpcRoutine(PKDPC Dpc
,
415 PVOID DeferredContext
,
416 PVOID SystemArgument1
,
417 PVOID SystemArgument2
)
419 PIRP Irp
= (PIRP
)SystemArgument2
;
420 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)SystemArgument1
;
422 if (SystemArgument1
== NULL
&& DoSystemDebug
!= -1)
424 KdSystemDebugControl(DoSystemDebug
);
430 DPRINT("KbdDpcRoutine(DeviceObject %x, Irp %x)\n",
432 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
433 Irp
->IoStatus
.Information
= 0;
434 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
435 IoStartNextPacket(DeviceObject
,FALSE
);
438 static BOOLEAN STDCALL
439 KeyboardHandler(PKINTERRUPT Interrupt
,
446 PDEVICE_OBJECT deviceObject
= (PDEVICE_OBJECT
) Context
;
447 PDEVICE_EXTENSION deviceExtension
= (PDEVICE_EXTENSION
) deviceObject
->DeviceExtension
;
454 Status
= READ_PORT_UCHAR((PUCHAR
)KBD_CTRL_PORT
);
455 if (!(Status
& KBD_OBF
))
461 thisKey
=READ_PORT_UCHAR((PUCHAR
)KBD_DATA_PORT
);
463 // Call hook routine. May change scancode value.
464 if (deviceExtension
->IsrHookCallback
) {
465 BOOLEAN cont
= FALSE
, ret
;
466 //BUG BUG: rewrite to have valid CurrentScanState!!!
467 ret
= (*deviceExtension
->IsrHookCallback
)(
469 NULL
,//&deviceExtension->CurrentInput,
470 NULL
,//&deviceExtension->CurrentOutput,
472 &thisKey
, //&scanCode,
474 NULL
//&deviceExtension->CurrentScanState
483 if ((thisKey
==0xE0)||(thisKey
==0xE1)) // Extended key
485 extKey
=1; // Wait for next byte
490 isDown
=!(thisKey
& 0x80);
493 // The keyboard maintains its own internal caps lock and num lock
494 // statuses. In caps lock mode E0 AA precedes make code and
495 // E0 2A follow break code. In num lock mode, E0 2A precedes
496 // make code and E0 AA follow break code. We maintain our own caps lock
497 // and num lock statuses, so we will just ignore these.
498 // Some keyboards have L-Shift/R-Shift modes instead of caps lock
499 // mode. If right shift pressed, E0 B6 / E0 36 pairs generated.
500 if (extKey
& ((thisKey
==0x2A)||(thisKey
==0x36)))
506 // Check for PAUSE sequence
507 if (extKey
&& (lastKey
==0xE1))
510 lastKey
=0xFF; // Sequence is OK
515 if (extKey
&& (lastKey
==0xFF))
519 extKey
=0; // Bad sequence
522 thisKey
=0x7F; // Pseudo-code for PAUSE
525 ProcessScanCode(thisKey
,isDown
);
527 // DbgPrint("Key: %c\n",VirtualToAscii(ScanToVirtual(thisKey),isDown));
528 // DbgPrint("Key: %x\n",ScanToVirtual(thisKey));
529 if (ScanToVirtual(thisKey
) == VK_TAB
&& isDown
)
533 else if (ScanToVirtual(thisKey
) == VK_TAB
&& !isDown
)
537 else if (InSysRq
== TRUE
&& ScanToVirtual(thisKey
) >= VK_A
&&
538 ScanToVirtual(thisKey
) <= VK_Z
&& isDown
)
540 DoSystemDebug
= ScanToVirtual(thisKey
) - VK_A
;
541 KeInsertQueueDpc(&KbdDpc
, NULL
, NULL
);
545 if (CurrentIrp
!=NULL
)
547 KEY_EVENT_RECORD
* rec
= (KEY_EVENT_RECORD
*)
548 CurrentIrp
->AssociatedIrp
.SystemBuffer
;
549 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation(CurrentIrp
);
553 rec
[KeysRead
].bKeyDown
=isDown
;
554 rec
[KeysRead
].wRepeatCount
=1;
555 rec
[KeysRead
].wVirtualKeyCode
=ScanToVirtual(thisKey
);
556 rec
[KeysRead
].wVirtualScanCode
=thisKey
;
557 rec
[KeysRead
].uChar
.AsciiChar
=VirtualToAscii(rec
->wVirtualKeyCode
,isDown
);
558 rec
[KeysRead
].dwControlKeyState
=ctrlKeyState
;
561 rec
[KeysRead
].dwControlKeyState
|=ENHANCED_KEY
;
564 DPRINT("KeysRequired %d KeysRead %x\n",KeysRequired
,KeysRead
);
565 if (KeysRead
==KeysRequired
)
567 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
) Context
;
568 KeInsertQueueDpc(&KbdDpc
,DeviceObject
,CurrentIrp
);
576 if (keysInBuffer
==KBD_BUFFER_SIZE
) // Buffer is full
581 kbdBuffer
[bufHead
].bKeyDown
=isDown
;
582 kbdBuffer
[bufHead
].wRepeatCount
=1;
583 kbdBuffer
[bufHead
].wVirtualKeyCode
=ScanToVirtual(thisKey
);
584 kbdBuffer
[bufHead
].wVirtualScanCode
=thisKey
;
585 kbdBuffer
[bufHead
].uChar
.UnicodeChar
=0;
586 // kbdBuffer[bufHead].uChar.AsciiChar=TranslateScanCode(thisKey);
587 kbdBuffer
[bufHead
].uChar
.AsciiChar
=VirtualToAscii(kbdBuffer
[bufHead
].wVirtualKeyCode
,isDown
);
588 kbdBuffer
[bufHead
].dwControlKeyState
=ctrlKeyState
;
590 kbdBuffer
[bufHead
].dwControlKeyState
|=ENHANCED_KEY
;
592 bufHead
&=KBD_WRAP_MASK
; // Modulo KBD_BUFFER_SIZE
600 // Initialize keyboard
602 static void KeyboardConnectInterrupt(PDEVICE_OBJECT DeviceObject
)
609 MappedIrq
= HalGetInterruptVector(Internal
,
615 Status
= IoConnectInterrupt(&KbdInterrupt
,
634 for (i
= 0; i
< 100; i
++)
636 Status
= READ_PORT_UCHAR((PUCHAR
)KBD_CTRL_PORT
);
637 if (!(Status
& KBD_OBF
))
641 (VOID
)READ_PORT_UCHAR((PUCHAR
)KBD_DATA_PORT
);
645 static int InitializeKeyboard(PDEVICE_OBJECT DeviceObject
)
647 // Initialize variables
659 KeyboardConnectInterrupt(DeviceObject
);
660 KeInitializeDpc(&KbdDpc
,KbdDpcRoutine
,NULL
);
665 * Read data from keyboard buffer
668 KbdSynchronizeRoutine(PVOID Context
)
670 PIRP Irp
= (PIRP
)Context
;
671 KEY_EVENT_RECORD
* rec
= (KEY_EVENT_RECORD
*)Irp
->AssociatedIrp
.SystemBuffer
;
672 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation(Irp
);
673 ULONG NrToRead
= stk
->Parameters
.Read
.Length
/sizeof(KEY_EVENT_RECORD
);
676 DPRINT("NrToRead %d keysInBuffer %d\n",NrToRead
,keysInBuffer
);
677 NrToRead
= min(NrToRead
,keysInBuffer
);
679 DPRINT("NrToRead %d stk->Parameters.Read.Length %d\n",
680 NrToRead
,stk
->Parameters
.Read
.Length
);
681 DPRINT("sizeof(KEY_EVENT_RECORD) %d\n",sizeof(KEY_EVENT_RECORD
));
682 for (i
=0;i
<NrToRead
;i
++)
684 memcpy(&rec
[i
],&kbdBuffer
[bufTail
],sizeof(KEY_EVENT_RECORD
));
686 bufTail
&=KBD_WRAP_MASK
;
689 if ((stk
->Parameters
.Read
.Length
/sizeof(KEY_EVENT_RECORD
))==NrToRead
)
694 KeysRequired
=stk
->Parameters
.Read
.Length
/sizeof(KEY_EVENT_RECORD
);
701 VOID STDCALL
KbdStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
704 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation(Irp
);
707 DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
709 if (KeSynchronizeExecution(KbdInterrupt
, KbdSynchronizeRoutine
, Irp
))
711 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
712 Irp
->IoStatus
.Information
= 0;
713 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
714 IoStartNextPacket(DeviceObject
, FALSE
);
717 DPRINT("stk->Parameters.Read.Length %d\n",stk
->Parameters
.Read
.Length
);
718 DPRINT("KeysRequired %d\n",KeysRequired
);
721 NTSTATUS
KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
723 PIO_STACK_LOCATION stk
;
724 PINTERNAL_I8042_HOOK_KEYBOARD hookKeyboard
;
725 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
726 NTSTATUS status
= STATUS_INVALID_DEVICE_REQUEST
;
728 Irp
->IoStatus
.Information
= 0;
729 stk
= IoGetCurrentIrpStackLocation(Irp
);
731 switch (stk
->Parameters
.DeviceIoControl
.IoControlCode
)
733 /*-----------------11/29/2001 4:12PM----------------
734 * This internal ioctrl belongs in i8042 driver. Should be
735 * moved to the appropriate driver later.
736 * --------------------------------------------------*/
737 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
:
739 if (stk
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(INTERNAL_I8042_HOOK_KEYBOARD
))
741 DPRINT(("Keyboard IOCTL_INTERNAL_I8042_HOOK_KEYBOARD invalid buffer size\n"));
742 status
= STATUS_INVALID_PARAMETER
;
746 // Copy the values if they are filled in
748 hookKeyboard
= (PINTERNAL_I8042_HOOK_KEYBOARD
)
749 stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
751 DevExt
->HookContext
= hookKeyboard
->Context
;
752 if (hookKeyboard
->InitializationRoutine
) {
753 DbgPrint("Keyboard: InitializationHookCallback NOT IMPLEMENTED\n");
754 DevExt
->InitializationHookCallback
=
755 hookKeyboard
->InitializationRoutine
;
758 if (hookKeyboard
->IsrRoutine
) {
759 DevExt
->IsrHookCallback
= hookKeyboard
->IsrRoutine
;
762 status
= STATUS_SUCCESS
;
766 status
= STATUS_INVALID_DEVICE_REQUEST
;
770 Irp
->IoStatus
.Status
= status
;
771 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
775 NTSTATUS STDCALL
KbdDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
777 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation(Irp
);
780 DPRINT("DeviceObject %x\n",DeviceObject
);
781 DPRINT("Irp %x\n",Irp
);
783 DPRINT("IRP_MJ_CREATE %d stk->MajorFunction %d\n",
784 IRP_MJ_CREATE
, stk
->MajorFunction
);
785 DPRINT("AlreadyOpened %d\n",AlreadyOpened
);
787 switch (stk
->MajorFunction
)
790 if (AlreadyOpened
== TRUE
)
793 // Status = STATUS_UNSUCCESSFUL;
794 Status
= STATUS_SUCCESS
;
799 Status
= STATUS_SUCCESS
;
800 AlreadyOpened
= TRUE
;
805 Status
= STATUS_SUCCESS
;
809 DPRINT("Handling Read request\n");
810 DPRINT("Queueing packet\n");
811 IoMarkIrpPending(Irp
);
812 IoStartPacket(DeviceObject
,Irp
,NULL
,NULL
);
813 return(STATUS_PENDING
);
816 Status
= STATUS_NOT_IMPLEMENTED
;
820 Irp
->IoStatus
.Status
= Status
;
821 Irp
->IoStatus
.Information
= 0;
822 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
823 DPRINT("Status %d\n",Status
);
827 NTSTATUS STDCALL
DriverEntry(PDRIVER_OBJECT DriverObject
,
828 PUNICODE_STRING RegistryPath
)
830 * FUNCTION: Module entry point
833 PDEVICE_OBJECT DeviceObject
;
834 UNICODE_STRING DeviceName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\Keyboard");
835 UNICODE_STRING SymlinkName
= UNICODE_STRING_INITIALIZER(L
"\\??\\Keyboard");
837 DPRINT("Keyboard Driver 0.0.4\n");
839 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = KbdDispatch
;
840 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = KbdDispatch
;
841 DriverObject
->MajorFunction
[IRP_MJ_READ
] = KbdDispatch
;
842 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = KbdInternalDeviceControl
;
844 DriverObject
->DriverStartIo
= KbdStartIo
;
846 IoCreateDevice(DriverObject
,
847 sizeof(DEVICE_EXTENSION
),
849 FILE_DEVICE_KEYBOARD
,
854 RtlZeroMemory(DeviceObject
->DeviceExtension
, sizeof(DEVICE_EXTENSION
));
856 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
857 InitializeKeyboard( DeviceObject
);
859 IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
861 return(STATUS_SUCCESS
);