2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/input/i8042prt/keyboard.c
5 * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
7 * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
8 * Jason Filby (jasonfilby@yahoo.com)
12 /* INCLUDES ****************************************************************/
14 #include <ddk/ntddk.h>
16 #include <ntos/keyboard.h>
17 #include <ntos/minmax.h>
18 #include <rosrtl/string.h>
20 #include <ddk/ntddkbd.h>
21 #include <ddk/ntdd8042.h>
28 /* GLOBALS *******************************************************************/
30 static BYTE TypematicTable
[] = {
31 0x00, 0x00, 0x00, 0x05, 0x08, 0x0B, 0x0D, 0x0F, 0x10, 0x12, /* 0-9 */
32 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1A, /* 10-19 */
33 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E };
35 typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION
{
36 USHORT NumberOfIndicatorKeys
;
37 INDICATOR_LIST IndicatorList
[3];
38 } LOCAL_KEYBOARD_INDICATOR_TRANSLATION
, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION
;
40 static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation
= { 3, {
41 {0x3A, KEYBOARD_CAPS_LOCK_ON
},
42 {0x45, KEYBOARD_NUM_LOCK_ON
},
43 {0x46, KEYBOARD_SCROLL_LOCK_ON
}}};
45 static VOID STDCALL
I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject
,
48 /* FUNCTIONS *****************************************************************/
51 * These functions are callbacks for filter driver custom interrupt
54 VOID STDCALL
I8042IsrWritePortKbd(PVOID Context
,
57 I8042IsrWritePort(Context
, Value
, 0);
60 static VOID STDCALL
I8042QueueKeyboardPacket(PVOID Context
)
62 PDEVICE_OBJECT DeviceObject
= Context
;
63 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
64 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
66 DevExt
->KeyComplete
= TRUE
;
67 DevExt
->KeysInBuffer
++;
68 if (DevExt
->KeysInBuffer
>
69 DevExt
->KeyboardAttributes
.InputDataQueueLength
) {
70 DPRINT1("Keyboard buffer overflow\n");
71 DevExt
->KeysInBuffer
--;
74 DPRINT("Irq completes key\n");
75 KeInsertQueueDpc(&DevExt
->DpcKbd
, DevExt
, NULL
);
79 * These functions are callbacks for filter driver custom
80 * initialization routines.
82 NTSTATUS STDCALL
I8042SynchWritePortKbd(PVOID Context
,
86 return I8042SynchWritePort((PDEVICE_EXTENSION
)Context
,
92 BOOLEAN STDCALL
I8042InterruptServiceKbd(struct _KINTERRUPT
*Interrupt
,
98 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
) Context
;
99 BOOLEAN HookContinue
= FALSE
, HookReturn
;
102 KEYBOARD_INPUT_DATA
*InputData
=
103 DevExt
->KeyboardBuffer
+ DevExt
->KeysInBuffer
;
106 Status
= I8042ReadStatus(&PortStatus
);
107 DPRINT("PortStatus: %x\n", PortStatus
);
108 Status
= I8042ReadData(&Output
);
110 if (STATUS_SUCCESS
== Status
)
112 KeStallExecutionProcessor(1);
113 } while (Iterations
< DevExt
->Settings
.PollStatusIterations
);
115 if (STATUS_SUCCESS
!= Status
) {
116 DPRINT1("Spurious I8042 interrupt\n");
120 DPRINT("Got: %x\n", Output
);
122 if (DevExt
->KeyboardHook
.IsrRoutine
) {
123 HookReturn
= DevExt
->KeyboardHook
.IsrRoutine(
124 DevExt
->KeyboardHook
.Context
,
130 &DevExt
->KeyboardScanState
);
136 if (I8042PacketIsr(DevExt
, Output
)) {
137 if (DevExt
->PacketComplete
) {
138 DPRINT("Packet complete\n");
139 KeInsertQueueDpc(&DevExt
->DpcKbd
, DevExt
, NULL
);
141 DPRINT("Irq eaten by packet\n");
145 DPRINT("Irq is keyboard input\n");
147 if (Normal
== DevExt
->KeyboardScanState
) {
150 DevExt
->KeyboardScanState
= GotE0
;
153 DevExt
->KeyboardScanState
= GotE1
;
160 InputData
->Flags
= 0;
162 switch (DevExt
->KeyboardScanState
) {
164 InputData
->Flags
|= KEY_E0
;
167 InputData
->Flags
|= KEY_E1
;
172 DevExt
->KeyboardScanState
= Normal
;
175 InputData
->Flags
|= KEY_BREAK
;
177 InputData
->Flags
|= KEY_MAKE
;
179 InputData
->MakeCode
= Output
& 0x7f;
181 I8042QueueKeyboardPacket(DevExt
->KeyboardObject
);
186 VOID STDCALL
I8042DpcRoutineKbd(PKDPC Dpc
,
187 PVOID DeferredContext
,
188 PVOID SystemArgument1
,
189 PVOID SystemArgument2
)
191 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
)SystemArgument1
;
192 ULONG KeysTransferred
= 0;
193 ULONG KeysInBufferCopy
;
196 I8042PacketDpc(DevExt
);
198 if (!DevExt
->KeyComplete
)
201 /* We got the interrupt as it was being enabled, too bad */
202 if (!DevExt
->HighestDIRQLInterrupt
)
205 Irql
= KeAcquireInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
);
207 DevExt
->KeyComplete
= FALSE
;
208 KeysInBufferCopy
= DevExt
->KeysInBuffer
;
210 KeReleaseInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
, Irql
);
212 /* Test for TAB (debugging) */
213 if (DevExt
->Settings
.CrashSysRq
) {
214 PKEYBOARD_INPUT_DATA InputData
= DevExt
->KeyboardBuffer
+
215 KeysInBufferCopy
- 1;
216 if (InputData
->MakeCode
== 0x0F) {
218 DevExt
->TabPressed
= !(InputData
->Flags
& KEY_BREAK
);
219 } else if (DevExt
->TabPressed
) {
220 DPRINT ("Queueing work item %x\n", DevExt
->DebugWorkItem
);
221 DevExt
->DebugKey
= InputData
->MakeCode
;
222 DevExt
->TabPressed
= FALSE
;
224 IoQueueWorkItem(DevExt
->DebugWorkItem
,
225 &(I8042DebugWorkItem
),
231 DPRINT ("Send a key\n");
233 if (!DevExt
->KeyboardData
.ClassService
)
236 ((KEYBOARD_CLASS_SERVICE_CALLBACK
) DevExt
->KeyboardData
.ClassService
)(
237 DevExt
->KeyboardData
.ClassDeviceObject
,
238 DevExt
->KeyboardBuffer
,
239 DevExt
->KeyboardBuffer
+ KeysInBufferCopy
,
242 Irql
= KeAcquireInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
);
243 DevExt
->KeysInBuffer
-= KeysTransferred
;
244 KeReleaseInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
, Irql
);
247 /* You have to send the rate/delay in a somewhat awkward format */
248 static USHORT
I8042GetTypematicByte(USHORT Rate
, USHORT Delay
)
254 } else if (Rate
> 26) {
257 ret
= TypematicTable
[Rate
];
262 } else if (Delay
< 625) {
264 } else if (Delay
< 875) {
272 * Process the keyboard internal device requests
273 * returns FALSE if it doesn't understand the
274 * call so someone else can handle it.
276 BOOLEAN STDCALL
I8042StartIoKbd(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
278 PIO_STACK_LOCATION Stk
;
279 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
280 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
282 Stk
= IoGetCurrentIrpStackLocation(Irp
);
284 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
) {
285 case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER
:
289 Stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
290 Stk
->Parameters
.DeviceIoControl
.InputBufferLength
,
294 case IOCTL_KEYBOARD_SET_INDICATORS
:
295 DevExt
->PacketBuffer
[0] = 0xED;
296 DevExt
->PacketBuffer
[1] = 0;
297 if (DevExt
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
)
298 DevExt
->PacketBuffer
[1] |= 0x04;
300 if (DevExt
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
)
301 DevExt
->PacketBuffer
[1] |= 0x02;
303 if (DevExt
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
)
304 DevExt
->PacketBuffer
[1] |= 0x01;
306 I8042StartPacket(DevExt
,
308 DevExt
->PacketBuffer
,
312 case IOCTL_KEYBOARD_SET_TYPEMATIC
:
313 DevExt
->PacketBuffer
[0] = 0xF3;
314 DevExt
->PacketBuffer
[1] = I8042GetTypematicByte(
315 DevExt
->KeyboardTypematic
.Rate
,
316 DevExt
->KeyboardTypematic
.Delay
);
318 I8042StartPacket(DevExt
,
320 DevExt
->PacketBuffer
,
332 * Runs the keyboard IOCTL_INTERNAL dispatch.
333 * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
334 * so someone else can have a try at it.
336 NTSTATUS STDCALL
I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
338 PIO_STACK_LOCATION Stk
;
339 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
340 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
342 DPRINT("InternalDeviceControl\n");
344 Irp
->IoStatus
.Information
= 0;
345 Stk
= IoGetCurrentIrpStackLocation(Irp
);
347 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
) {
349 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
350 DPRINT("IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
351 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
352 sizeof(CONNECT_DATA
)) {
353 DPRINT1("Keyboard IOCTL_INTERNAL_KEYBOARD_CONNECT "
354 "invalid buffer size\n");
355 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
359 if (!DevExt
->KeyboardExists
) {
360 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_CONNECTED
;
364 if (DevExt
->KeyboardClaimed
) {
365 DPRINT1("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
366 "Keyboard is already claimed\n");
367 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
371 memcpy(&DevExt
->KeyboardData
,
372 Stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
373 sizeof(CONNECT_DATA
));
374 DevExt
->KeyboardHook
.IsrWritePort
= I8042IsrWritePortKbd
;
375 DevExt
->KeyboardHook
.QueueKeyboardPacket
=
376 I8042QueueKeyboardPacket
;
377 DevExt
->KeyboardHook
.CallContext
= DevExt
;
380 PIO_WORKITEM WorkItem
;
381 PI8042_HOOK_WORKITEM WorkItemData
;
383 WorkItem
= IoAllocateWorkItem(DeviceObject
);
385 DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
386 "Can't allocate work item\n");
387 Irp
->IoStatus
.Status
=
388 STATUS_INSUFFICIENT_RESOURCES
;
392 WorkItemData
= ExAllocatePoolWithTag(
394 sizeof(I8042_HOOK_WORKITEM
),
397 DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
398 "Can't allocate work item data\n");
399 Irp
->IoStatus
.Status
=
400 STATUS_INSUFFICIENT_RESOURCES
;
401 IoFreeWorkItem(WorkItem
);
404 WorkItemData
->WorkItem
= WorkItem
;
405 WorkItemData
->Target
=
406 DevExt
->KeyboardData
.ClassDeviceObject
;
407 WorkItemData
->Irp
= Irp
;
409 IoMarkIrpPending(Irp
);
410 IoQueueWorkItem(WorkItem
,
411 I8042SendHookWorkItem
,
415 Irp
->IoStatus
.Status
= STATUS_PENDING
;
419 case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER
:
420 DPRINT("IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER\n");
421 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
< 1) {
422 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
425 if (!DevExt
->KeyboardInterruptObject
) {
426 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
430 IoMarkIrpPending(Irp
);
431 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
432 Irp
->IoStatus
.Status
= STATUS_PENDING
;
435 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
436 DPRINT("IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
437 if (Stk
->Parameters
.DeviceIoControl
.OutputBufferLength
<
438 sizeof(KEYBOARD_ATTRIBUTES
)) {
439 DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_ATTRIBUTES "
440 "invalid buffer size\n");
441 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
444 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
445 &DevExt
->KeyboardAttributes
,
446 sizeof(KEYBOARD_ATTRIBUTES
));
448 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
450 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
451 DPRINT("IOCTL_KEYBOARD_QUERY_INDICATORS\n");
452 if (Stk
->Parameters
.DeviceIoControl
.OutputBufferLength
<
453 sizeof(KEYBOARD_INDICATOR_PARAMETERS
)) {
454 DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_INDICATORS "
455 "invalid buffer size\n");
456 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
459 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
460 &DevExt
->KeyboardIndicators
,
461 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
463 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
465 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
466 DPRINT("IOCTL_KEYBOARD_QUERY_TYPEMATIC\n");
467 if (Stk
->Parameters
.DeviceIoControl
.OutputBufferLength
<
468 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS
)) {
469 DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_TYPEMATIC "
470 "invalid buffer size\n");
471 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
474 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
475 &DevExt
->KeyboardTypematic
,
476 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS
));
478 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
480 case IOCTL_KEYBOARD_SET_INDICATORS
:
481 DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
482 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
483 sizeof(KEYBOARD_INDICATOR_PARAMETERS
)) {
484 DPRINT("Keyboard IOCTL_KEYBOARD_SET_INDICTATORS "
485 "invalid buffer size\n");
486 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
490 memcpy(&DevExt
->KeyboardIndicators
,
491 Irp
->AssociatedIrp
.SystemBuffer
,
492 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
494 DPRINT("%x\n", DevExt
->KeyboardIndicators
.LedFlags
);
496 IoMarkIrpPending(Irp
);
497 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
498 Irp
->IoStatus
.Status
= STATUS_PENDING
;
501 case IOCTL_KEYBOARD_SET_TYPEMATIC
:
502 DPRINT("IOCTL_KEYBOARD_SET_TYPEMATIC\n");
503 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
504 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS
)) {
505 DPRINT("Keyboard IOCTL_KEYBOARD_SET_TYPEMATIC "
506 "invalid buffer size\n");
507 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
511 memcpy(&DevExt
->KeyboardTypematic
,
512 Irp
->AssociatedIrp
.SystemBuffer
,
513 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS
));
515 IoMarkIrpPending(Irp
);
516 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
517 Irp
->IoStatus
.Status
= STATUS_PENDING
;
520 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
521 /* We should check the UnitID, but it's kind of pointless as
522 * all keyboards are supposed to have the same one
524 if (Stk
->Parameters
.DeviceIoControl
.OutputBufferLength
<
525 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
)) {
526 DPRINT("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: "
527 "invalid buffer size (expected)\n");
528 /* It's to query the buffer size */
529 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
532 Irp
->IoStatus
.Information
=
533 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
);
535 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
536 &IndicatorTranslation
,
537 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
));
539 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
541 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
:
542 /* Nothing to do here */
543 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
546 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
551 return Irp
->IoStatus
.Status
;
554 BOOLEAN STDCALL
I8042KeyboardEnable(PDEVICE_EXTENSION DevExt
)
556 DPRINT("Enabling keyboard\n");
557 if (STATUS_SUCCESS
!= I8042SynchWritePort(DevExt
,
561 DPRINT("Can't enable keyboard\n");
567 BOOLEAN STDCALL
I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt
)
572 DPRINT("Enabling keyboard interrupt\n");
574 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_READ_MODE
)) {
575 DPRINT1("Can't read i8042 mode\n");
579 Status
= I8042ReadDataWait(DevExt
, &Value
);
580 if (Status
!= STATUS_SUCCESS
) {
581 DPRINT1("No response after read i8042 mode\n");
585 Value
&= ~(0x10); // don't disable keyboard
586 Value
|= 0x01; // enable keyboard interrupts
588 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_WRITE_MODE
)) {
589 DPRINT1("Can't set i8042 mode\n");
593 if (!I8042Write(DevExt
, I8042_DATA_PORT
, Value
)) {
594 DPRINT1("Can't send i8042 mode\n");
601 BOOLEAN STDCALL
I8042DetectKeyboard(PDEVICE_EXTENSION DevExt
)
605 UINT RetryCount
= 10;
607 DPRINT("Detecting keyboard\n");
610 Status
= I8042SynchWritePort(DevExt
, 0, KBD_GET_ID
, TRUE
);
611 } while (STATUS_TIMEOUT
== Status
&& RetryCount
--);
613 if (Status
!= STATUS_SUCCESS
) {
614 DPRINT("Can't write GET_ID (%x)\n", Status
);
618 Status
= I8042ReadDataWait(DevExt
, &Value
);
619 if (Status
!= STATUS_SUCCESS
) {
620 DPRINT1("No response after GET_ID\n");
621 /* Could be an AT keyboard */
622 DevExt
->KeyboardIsAT
= TRUE
;
625 DevExt
->KeyboardIsAT
= FALSE
;
627 if (Value
!= 0xAB && Value
!= 0xAC) {
628 DPRINT("Bad ID: %x\n", Value
);
629 /* This is certainly not a keyboard */
633 DPRINT("Keyboard ID: %x", Value
);
635 Status
= I8042ReadDataWait(DevExt
, &Value
);
636 if (Status
!= STATUS_SUCCESS
) {
637 DPRINT("Partial ID\n");
641 DPRINT ("%x\n", Value
);
644 Status
= I8042SynchWritePort(DevExt
, 0, KBD_SET_LEDS
, TRUE
);
645 if (Status
!= STATUS_SUCCESS
) {
646 DPRINT("Can't write SET_LEDS (%x)\n", Status
);
649 Status
= I8042SynchWritePort(DevExt
, 0, 0, TRUE
);
650 if (Status
!= STATUS_SUCCESS
) {
651 DPRINT("Can't finish SET_LEDS (%x)\n", Status
);
655 // Turn on translation
657 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_READ_MODE
)) {
658 DPRINT1("Can't read i8042 mode\n");
662 Status
= I8042ReadDataWait(DevExt
, &Value
);
663 if (Status
!= STATUS_SUCCESS
) {
664 DPRINT1("No response after read i8042 mode\n");
668 Value
|= 0x40; // enable keyboard translation
670 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_WRITE_MODE
)) {
671 DPRINT1("Can't set i8042 mode\n");
675 if (!I8042Write(DevExt
, I8042_DATA_PORT
, Value
)) {
676 DPRINT1("Can't send i8042 mode\n");
685 KdpServiceDispatcher(ULONG Code
, PVOID Context1
, PVOID Context2
);
687 static VOID STDCALL
I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject
,
691 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
692 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
694 Key
= InterlockedExchange(&DevExt
->DebugKey
, 0);
695 DPRINT("Debug key: %x\n", Key
);
700 KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID
)Key
, NULL
);