2 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/input/i8042prt/keyboard.c
5 * PURPOSE: Keyboard specific functions
6 * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
7 Copyright Jason Filby (jasonfilby@yahoo.com)
8 Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
9 Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
12 /* INCLUDES ****************************************************************/
16 /* GLOBALS *******************************************************************/
18 static IO_WORKITEM_ROUTINE i8042PowerWorkItem
;
20 /* This structure starts with the same layout as KEYBOARD_INDICATOR_TRANSLATION */
21 typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION
{
22 USHORT NumberOfIndicatorKeys
;
23 INDICATOR_LIST IndicatorList
[3];
24 } LOCAL_KEYBOARD_INDICATOR_TRANSLATION
, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION
;
26 static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation
= { 3, {
27 {0x3A, KEYBOARD_CAPS_LOCK_ON
},
28 {0x45, KEYBOARD_NUM_LOCK_ON
},
29 {0x46, KEYBOARD_SCROLL_LOCK_ON
}}};
31 /* FUNCTIONS *****************************************************************/
34 * These functions are callbacks for filter driver custom interrupt
42 PI8042_KEYBOARD_EXTENSION DeviceExtension;
44 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
46 if (DeviceExtension->KeyboardHook.IsrWritePort)
48 DeviceExtension->KeyboardHook.IsrWritePort(
49 DeviceExtension->KeyboardHook.CallContext,
53 i8042IsrWritePort(Context, Value, 0);
60 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
62 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
64 DeviceExtension
->KeyComplete
= TRUE
;
65 DeviceExtension
->KeysInBuffer
++;
66 if (DeviceExtension
->KeysInBuffer
> DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
)
68 WARN_(I8042PRT
, "Keyboard buffer overflow\n");
69 DeviceExtension
->KeysInBuffer
--;
72 TRACE_(I8042PRT
, "Irq completes key\n");
73 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
77 * These functions are callbacks for filter driver custom
78 * initialization routines.
81 i8042SynchWritePortKbd(
84 IN BOOLEAN WaitForAck
)
86 return i8042SynchWritePort(
87 (PPORT_DEVICE_EXTENSION
)Context
,
94 * Process the keyboard internal device requests
98 IN PDEVICE_OBJECT DeviceObject
,
101 PIO_STACK_LOCATION Stack
;
102 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
103 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
105 Stack
= IoGetCurrentIrpStackLocation(Irp
);
106 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
107 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
109 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
111 case IOCTL_KEYBOARD_SET_INDICATORS
:
113 TRACE_(I8042PRT
, "IOCTL_KEYBOARD_SET_INDICATORS\n");
114 INFO_(I8042PRT
, "Leds: {%s%s%s }\n",
115 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
? " CAPSLOCK" : "",
116 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
? " NUMLOCK" : "",
117 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
? " SCROLLLOCK" : "");
119 PortDeviceExtension
->PacketBuffer
[0] = KBD_CMD_SET_LEDS
;
120 PortDeviceExtension
->PacketBuffer
[1] = 0;
121 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
)
122 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_CAPS
;
124 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
)
125 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_NUM
;
127 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
)
128 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_SCROLL
;
132 &DeviceExtension
->Common
,
133 PortDeviceExtension
->PacketBuffer
,
140 ERR_(I8042PRT
, "Unknown ioctl code 0x%lx\n",
141 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
149 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
151 BOOLEAN FinishIrp
= FALSE
;
153 NTSTATUS Result
= STATUS_INTERNAL_ERROR
; /* Shouldn't happen */
155 /* If the interrupt happens before this is setup, the key
156 * was already in the buffer. Too bad! */
157 if (!DeviceExtension
->HighestDIRQLInterrupt
)
160 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
162 if (DeviceExtension
->Packet
.State
== Idle
163 && DeviceExtension
->PacketComplete
)
166 Result
= DeviceExtension
->PacketResult
;
167 DeviceExtension
->PacketComplete
= FALSE
;
170 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
175 if (DeviceExtension
->CurrentIrp
)
177 DeviceExtension
->CurrentIrp
->IoStatus
.Status
= Result
;
178 IoCompleteRequest(DeviceExtension
->CurrentIrp
, IO_NO_INCREMENT
);
179 IoStartNextPacket(DeviceExtension
->CurrentIrpDevice
, FALSE
);
180 DeviceExtension
->CurrentIrp
= NULL
;
181 DeviceExtension
->CurrentIrpDevice
= NULL
;
187 IN PDEVICE_OBJECT DeviceObject
,
190 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
194 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
196 UNREFERENCED_PARAMETER(DeviceObject
);
198 /* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */
200 /* Register GUID_DEVICE_SYS_BUTTON interface and report capability */
201 if (DeviceExtension
->NewCaps
!= DeviceExtension
->ReportedCaps
)
203 WaitingIrp
= InterlockedExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
);
206 /* Cancel the current power irp, as capability changed */
207 WaitingIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
208 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
209 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
212 if (DeviceExtension
->PowerInterfaceName
.MaximumLength
== 0)
214 /* We have never registred this interface ; do it */
215 Status
= IoRegisterDeviceInterface(
216 DeviceExtension
->Common
.Pdo
,
217 &GUID_DEVICE_SYS_BUTTON
,
219 &DeviceExtension
->PowerInterfaceName
);
220 if (!NT_SUCCESS(Status
))
222 /* We can't do more yet, ignore the keypress... */
223 WARN_(I8042PRT
, "IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n",
225 DeviceExtension
->PowerInterfaceName
.MaximumLength
= 0;
231 /* Disable the interface. Once activated again, capabilities would be asked again */
232 Status
= IoSetDeviceInterfaceState(
233 &DeviceExtension
->PowerInterfaceName
,
235 if (!NT_SUCCESS(Status
))
237 /* Ignore the key press... */
238 WARN_(I8042PRT
, "Disabling interface %wZ failed with status 0x%08lx\n",
239 &DeviceExtension
->PowerInterfaceName
, Status
);
243 /* Enable the interface. This leads to receving a IOCTL_GET_SYS_BUTTON_CAPS,
244 * so we can report new capability */
245 Status
= IoSetDeviceInterfaceState(
246 &DeviceExtension
->PowerInterfaceName
,
248 if (!NT_SUCCESS(Status
))
250 /* Ignore the key press... */
251 WARN_(I8042PRT
, "Enabling interface %wZ failed with status 0x%08lx\n",
252 &DeviceExtension
->PowerInterfaceName
, Status
);
257 /* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
258 WaitingIrp
= InterlockedExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
);
261 PULONG pEvent
= (PULONG
)WaitingIrp
->AssociatedIrp
.SystemBuffer
;
263 WaitingIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
264 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
265 *pEvent
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
266 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
270 /* Return TRUE if it was a power key */
273 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
)
275 PKEYBOARD_INPUT_DATA InputData
;
278 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
- 1;
279 if (!(InputData
->Flags
& KEY_E0
))
282 switch (InputData
->MakeCode
)
284 case KEYBOARD_POWER_CODE
:
285 KeyPress
= SYS_BUTTON_POWER
;
287 case KEYBOARD_SLEEP_CODE
:
288 KeyPress
= SYS_BUTTON_SLEEP
;
290 case KEYBOARD_WAKE_CODE
:
291 KeyPress
= SYS_BUTTON_WAKE
;
297 if (InputData
->Flags
& KEY_BREAK
)
298 /* We already took care of the key press */
301 /* Our work can only be done at passive level, so use a workitem */
302 DeviceExtension
->NewCaps
|= KeyPress
;
303 InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, KeyPress
);
305 DeviceExtension
->PowerWorkItem
,
315 IN PVOID DeferredContext
,
316 IN PVOID SystemArgument1
,
317 IN PVOID SystemArgument2
)
319 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
320 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
321 ULONG KeysTransferred
= 0;
322 ULONG KeysInBufferCopy
;
325 UNREFERENCED_PARAMETER(Dpc
);
326 UNREFERENCED_PARAMETER(SystemArgument1
);
327 UNREFERENCED_PARAMETER(SystemArgument2
);
329 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeferredContext
;
330 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
332 if (HandlePowerKeys(DeviceExtension
))
334 DeviceExtension
->KeyComplete
= FALSE
;
338 i8042PacketDpc(PortDeviceExtension
);
339 if (!DeviceExtension
->KeyComplete
)
341 /* We got the interrupt as it was being enabled, too bad */
342 if (!PortDeviceExtension
->HighestDIRQLInterrupt
)
345 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
347 DeviceExtension
->KeyComplete
= FALSE
;
348 KeysInBufferCopy
= DeviceExtension
->KeysInBuffer
;
350 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
352 TRACE_(I8042PRT
, "Send a key\n");
354 if (!DeviceExtension
->KeyboardData
.ClassService
)
357 INFO_(I8042PRT
, "Sending %lu key(s)\n", KeysInBufferCopy
);
358 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->KeyboardData
.ClassService
)(
359 DeviceExtension
->KeyboardData
.ClassDeviceObject
,
360 DeviceExtension
->KeyboardBuffer
,
361 DeviceExtension
->KeyboardBuffer
+ KeysInBufferCopy
,
364 KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
365 DeviceExtension
->KeysInBuffer
-= KeysTransferred
;
366 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
370 * Runs the keyboard IOCTL dispatch.
373 i8042KbdDeviceControl(
374 IN PDEVICE_OBJECT DeviceObject
,
377 PIO_STACK_LOCATION Stack
;
378 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
381 Stack
= IoGetCurrentIrpStackLocation(Irp
);
382 Irp
->IoStatus
.Information
= 0;
383 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
385 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
387 case IOCTL_GET_SYS_BUTTON_CAPS
:
389 /* Part of GUID_DEVICE_SYS_BUTTON interface */
391 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_CAPS\n");
393 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
394 Status
= STATUS_INVALID_PARAMETER
;
397 pCaps
= (PULONG
)Irp
->AssociatedIrp
.SystemBuffer
;
398 *pCaps
= DeviceExtension
->NewCaps
;
399 DeviceExtension
->ReportedCaps
= DeviceExtension
->NewCaps
;
400 Irp
->IoStatus
.Information
= sizeof(ULONG
);
401 Status
= STATUS_SUCCESS
;
405 case IOCTL_GET_SYS_BUTTON_EVENT
:
407 /* Part of GUID_DEVICE_SYS_BUTTON interface */
409 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_EVENT\n");
411 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
412 Status
= STATUS_INVALID_PARAMETER
;
415 WaitingIrp
= InterlockedCompareExchangePointer(
416 (PVOID
)&DeviceExtension
->PowerIrp
,
419 /* Check if an Irp is already pending */
422 /* Unable to have a 2nd pending IRP for this IOCTL */
423 WARN_(I8042PRT
, "Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
424 Status
= STATUS_INVALID_PARAMETER
;
425 Irp
->IoStatus
.Status
= Status
;
426 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
431 PowerKey
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
434 (VOID
)InterlockedCompareExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
, Irp
);
435 *(PULONG
)Irp
->AssociatedIrp
.SystemBuffer
= PowerKey
;
436 Status
= STATUS_SUCCESS
;
437 Irp
->IoStatus
.Status
= Status
;
438 Irp
->IoStatus
.Information
= sizeof(ULONG
);
439 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
443 TRACE_(I8042PRT
, "Pending IOCTL_GET_SYS_BUTTON_EVENT\n");
444 Status
= STATUS_PENDING
;
445 Irp
->IoStatus
.Status
= Status
;
446 IoMarkIrpPending(Irp
);
455 ERR_(I8042PRT
, "IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
456 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
458 return ForwardIrpAndForget(DeviceObject
, Irp
);
462 Irp
->IoStatus
.Status
= Status
;
463 if (Status
== STATUS_PENDING
)
464 IoMarkIrpPending(Irp
);
466 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
472 * Runs the keyboard IOCTL_INTERNAL dispatch.
475 i8042KbdInternalDeviceControl(
476 IN PDEVICE_OBJECT DeviceObject
,
479 PIO_STACK_LOCATION Stack
;
480 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
483 Stack
= IoGetCurrentIrpStackLocation(Irp
);
484 Irp
->IoStatus
.Information
= 0;
485 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
487 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
489 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
492 PIO_WORKITEM WorkItem
= NULL
;
493 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
495 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
496 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
498 Status
= STATUS_INVALID_PARAMETER
;
502 DeviceExtension
->KeyboardData
=
503 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
505 /* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */
506 WorkItem
= IoAllocateWorkItem(DeviceObject
);
509 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
510 Status
= STATUS_INSUFFICIENT_RESOURCES
;
513 WorkItemData
= ExAllocatePoolWithTag(
515 sizeof(I8042_HOOK_WORKITEM
),
519 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
520 Status
= STATUS_NO_MEMORY
;
523 WorkItemData
->WorkItem
= WorkItem
;
524 WorkItemData
->Irp
= Irp
;
526 /* Initialize extension */
527 DeviceExtension
->Common
.Type
= Keyboard
;
528 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
);
529 DeviceExtension
->KeyboardBuffer
= ExAllocatePoolWithTag(
533 if (!DeviceExtension
->KeyboardBuffer
)
535 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
536 Status
= STATUS_NO_MEMORY
;
539 RtlZeroMemory(DeviceExtension
->KeyboardBuffer
, Size
);
541 &DeviceExtension
->DpcKeyboard
,
544 DeviceExtension
->PowerWorkItem
= IoAllocateWorkItem(DeviceObject
);
545 if (!DeviceExtension
->PowerWorkItem
)
547 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
548 Status
= STATUS_INSUFFICIENT_RESOURCES
;
551 DeviceExtension
->DebugWorkItem
= IoAllocateWorkItem(DeviceObject
);
552 if (!DeviceExtension
->DebugWorkItem
)
554 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
555 Status
= STATUS_INSUFFICIENT_RESOURCES
;
558 DeviceExtension
->Common
.PortDeviceExtension
->KeyboardExtension
= DeviceExtension
;
559 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= KEYBOARD_CONNECTED
;
561 IoMarkIrpPending(Irp
);
562 /* FIXME: DeviceExtension->KeyboardHook.IsrWritePort = ; */
563 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket
= i8042KbdQueuePacket
;
564 DeviceExtension
->KeyboardHook
.CallContext
= DeviceExtension
;
565 IoQueueWorkItem(WorkItem
,
566 i8042SendHookWorkItem
,
569 Status
= STATUS_PENDING
;
573 if (DeviceExtension
->KeyboardBuffer
)
574 ExFreePoolWithTag(DeviceExtension
->KeyboardBuffer
, I8042PRT_TAG
);
575 if (DeviceExtension
->PowerWorkItem
)
576 IoFreeWorkItem(DeviceExtension
->PowerWorkItem
);
577 if (DeviceExtension
->DebugWorkItem
)
578 IoFreeWorkItem(DeviceExtension
->DebugWorkItem
);
580 IoFreeWorkItem(WorkItem
);
582 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
585 case IOCTL_INTERNAL_KEYBOARD_DISCONNECT
:
587 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n");
588 /* MSDN says that operation is to implemented.
589 * To implement it, we just have to do:
590 * DeviceExtension->KeyboardData.ClassService = NULL;
592 Status
= STATUS_NOT_IMPLEMENTED
;
595 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
:
597 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n");
598 /* Nothing to do here */
599 Status
= STATUS_SUCCESS
;
602 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
604 DPRINT1("IOCTL_KEYBOARD_QUERY_ATTRIBUTES not implemented\n");
606 /* FIXME: KeyboardAttributes are not initialized anywhere */
607 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
608 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KEYBOARD_ATTRIBUTES
))
610 Status
= STATUS_BUFFER_TOO_SMALL
;
614 *(PKEYBOARD_ATTRIBUTES
) Irp
->AssociatedIrp
.SystemBuffer
= DeviceExtension
->KeyboardAttributes
;
615 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_ATTRIBUTES
);
616 Status
= STATUS_SUCCESS
;
619 Status
= STATUS_NOT_IMPLEMENTED
;
622 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
624 DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n");
625 Status
= STATUS_NOT_IMPLEMENTED
;
628 case IOCTL_KEYBOARD_SET_TYPEMATIC
:
630 DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n");
631 Status
= STATUS_NOT_IMPLEMENTED
;
634 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
636 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
638 /* We should check the UnitID, but it's kind of pointless as
639 * all keyboards are supposed to have the same one
641 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
))
643 Status
= STATUS_BUFFER_TOO_SMALL
;
648 Irp
->AssociatedIrp
.SystemBuffer
,
649 &IndicatorTranslation
,
650 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
));
651 Irp
->IoStatus
.Information
= sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
);
652 Status
= STATUS_SUCCESS
;
656 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
658 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
660 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
662 Status
= STATUS_BUFFER_TOO_SMALL
;
667 Irp
->AssociatedIrp
.SystemBuffer
,
668 &DeviceExtension
->KeyboardIndicators
,
669 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
670 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INDICATOR_PARAMETERS
);
671 Status
= STATUS_SUCCESS
;
675 case IOCTL_KEYBOARD_SET_INDICATORS
:
677 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n");
679 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
681 Status
= STATUS_BUFFER_TOO_SMALL
;
686 &DeviceExtension
->KeyboardIndicators
,
687 Irp
->AssociatedIrp
.SystemBuffer
,
688 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
689 Status
= STATUS_PENDING
;
690 IoMarkIrpPending(Irp
);
691 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
697 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
698 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
700 return ForwardIrpAndForget(DeviceObject
, Irp
);
704 Irp
->IoStatus
.Status
= Status
;
705 if (Status
!= STATUS_PENDING
)
706 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
711 * Call the customization hook. The ToReturn parameter is about wether
712 * we should go on with the interrupt. The return value is what
713 * we should return (indicating to the system wether someone else
714 * should try to handle the interrupt)
718 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
,
721 OUT PBOOLEAN ToReturn
)
723 BOOLEAN HookReturn
, HookContinue
;
725 HookContinue
= FALSE
;
727 if (DeviceExtension
->KeyboardHook
.IsrRoutine
)
729 HookReturn
= DeviceExtension
->KeyboardHook
.IsrRoutine(
730 DeviceExtension
->KeyboardHook
.Context
,
731 DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
,
732 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
736 &DeviceExtension
->KeyboardScanState
);
740 *ToReturn
= HookReturn
;
748 i8042KbdInterruptService(
749 IN PKINTERRUPT Interrupt
,
752 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
753 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
754 PKEYBOARD_INPUT_DATA InputData
;
756 UCHAR PortStatus
= 0, Output
= 0;
757 BOOLEAN ToReturn
= FALSE
;
760 UNREFERENCED_PARAMETER(Interrupt
);
762 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
763 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
764 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
;
765 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
769 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
770 if (!NT_SUCCESS(Status
))
772 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
775 Status
= i8042ReadKeyboardData(PortDeviceExtension
, &Output
);
776 if (NT_SUCCESS(Status
))
778 KeStallExecutionProcessor(1);
783 WARN_(I8042PRT
, "Spurious i8042 keyboard interrupt\n");
787 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
789 if (PortDeviceExtension
->Settings
.CrashOnCtrlScroll
)
791 /* Test for CTRL + SCROLL LOCK twice */
792 static const UCHAR ScanCodes
[] = { 0x1d, 0x46, 0xc6, 0x46, 0 };
794 if (Output
== ScanCodes
[DeviceExtension
->ComboPosition
])
796 DeviceExtension
->ComboPosition
++;
797 if (ScanCodes
[DeviceExtension
->ComboPosition
] == 0)
798 KeBugCheck(MANUALLY_INITIATED_CRASH
);
800 else if (Output
== 0xfa)
804 else if (Output
== ScanCodes
[0])
805 DeviceExtension
->ComboPosition
= 1;
807 DeviceExtension
->ComboPosition
= 0;
809 /* Test for TAB + key combination */
810 if (InputData
->MakeCode
== 0x0F)
811 DeviceExtension
->TabPressed
= !(InputData
->Flags
& KEY_BREAK
);
812 else if (DeviceExtension
->TabPressed
)
814 DeviceExtension
->TabPressed
= FALSE
;
816 /* Check which action to do */
817 if (InputData
->MakeCode
== 0x25)
822 else if (InputData
->MakeCode
== 0x30)
825 KeBugCheck(MANUALLY_INITIATED_CRASH
);
829 /* Send request to the kernel debugger.
830 * Unknown requests will be ignored. */
831 KdSystemDebugControl(' soR',
832 (PVOID
)(ULONG_PTR
)InputData
->MakeCode
,
842 if (i8042KbdCallIsrHook(DeviceExtension
, PortStatus
, Output
, &ToReturn
))
845 if (i8042PacketIsr(PortDeviceExtension
, Output
))
847 if (PortDeviceExtension
->PacketComplete
)
849 TRACE_(I8042PRT
, "Packet complete\n");
850 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
852 TRACE_(I8042PRT
, "Irq eaten by packet\n");
856 TRACE_(I8042PRT
, "Irq is keyboard input\n");
858 if (DeviceExtension
->KeyboardScanState
== Normal
)
863 DeviceExtension
->KeyboardScanState
= GotE0
;
866 DeviceExtension
->KeyboardScanState
= GotE1
;
873 /* Update InputData */
874 InputData
->Flags
= 0;
875 switch (DeviceExtension
->KeyboardScanState
)
878 InputData
->Flags
|= KEY_E0
;
881 InputData
->Flags
|= KEY_E1
;
886 DeviceExtension
->KeyboardScanState
= Normal
;
888 InputData
->Flags
|= KEY_BREAK
;
890 InputData
->Flags
|= KEY_MAKE
;
891 InputData
->MakeCode
= Output
& 0x7f;
892 InputData
->Reserved
= 0;
894 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket(DeviceExtension
->KeyboardHook
.CallContext
);