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 i8042DebugWorkItem
;
19 static IO_WORKITEM_ROUTINE i8042PowerWorkItem
;
21 /* This structure starts with the same layout as KEYBOARD_INDICATOR_TRANSLATION */
22 typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION
{
23 USHORT NumberOfIndicatorKeys
;
24 INDICATOR_LIST IndicatorList
[3];
25 } LOCAL_KEYBOARD_INDICATOR_TRANSLATION
, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION
;
27 static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation
= { 3, {
28 {0x3A, KEYBOARD_CAPS_LOCK_ON
},
29 {0x45, KEYBOARD_NUM_LOCK_ON
},
30 {0x46, KEYBOARD_SCROLL_LOCK_ON
}}};
32 /* FUNCTIONS *****************************************************************/
36 IN PDEVICE_OBJECT DeviceObject
,
39 UNREFERENCED_PARAMETER(DeviceObject
);
40 INFO_(I8042PRT
, "Debug key: p\n", Key
);
45 /* We hope kernel would understand this. If
46 * that's not the case, nothing would happen.
48 KdSystemDebugControl(' soR', Key
, 0, NULL
, 0, NULL
, KernelMode
);
52 * These functions are callbacks for filter driver custom interrupt
60 PI8042_KEYBOARD_EXTENSION DeviceExtension;
62 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
64 if (DeviceExtension->KeyboardHook.IsrWritePort)
66 DeviceExtension->KeyboardHook.IsrWritePort(
67 DeviceExtension->KeyboardHook.CallContext,
71 i8042IsrWritePort(Context, Value, 0);
78 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
80 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
82 DeviceExtension
->KeyComplete
= TRUE
;
83 DeviceExtension
->KeysInBuffer
++;
84 if (DeviceExtension
->KeysInBuffer
> DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
)
86 WARN_(I8042PRT
, "Keyboard buffer overflow\n");
87 DeviceExtension
->KeysInBuffer
--;
90 TRACE_(I8042PRT
, "Irq completes key\n");
91 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
95 * These functions are callbacks for filter driver custom
96 * initialization routines.
99 i8042SynchWritePortKbd(
102 IN BOOLEAN WaitForAck
)
104 return i8042SynchWritePort(
105 (PPORT_DEVICE_EXTENSION
)Context
,
112 * Process the keyboard internal device requests
116 IN PDEVICE_OBJECT DeviceObject
,
119 PIO_STACK_LOCATION Stack
;
120 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
121 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
123 Stack
= IoGetCurrentIrpStackLocation(Irp
);
124 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
125 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
127 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
129 case IOCTL_KEYBOARD_SET_INDICATORS
:
131 TRACE_(I8042PRT
, "IOCTL_KEYBOARD_SET_INDICATORS\n");
132 INFO_(I8042PRT
, "Leds: {%s%s%s }\n",
133 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
? " CAPSLOCK" : "",
134 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
? " NUMLOCK" : "",
135 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
? " SCROLLLOCK" : "");
137 PortDeviceExtension
->PacketBuffer
[0] = KBD_CMD_SET_LEDS
;
138 PortDeviceExtension
->PacketBuffer
[1] = 0;
139 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
)
140 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_CAPS
;
142 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
)
143 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_NUM
;
145 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
)
146 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_SCROLL
;
150 &DeviceExtension
->Common
,
151 PortDeviceExtension
->PacketBuffer
,
158 ERR_(I8042PRT
, "Unknown ioctl code 0x%lx\n",
159 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
167 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
169 BOOLEAN FinishIrp
= FALSE
;
171 NTSTATUS Result
= STATUS_INTERNAL_ERROR
; /* Shouldn't happen */
173 /* If the interrupt happens before this is setup, the key
174 * was already in the buffer. Too bad! */
175 if (!DeviceExtension
->HighestDIRQLInterrupt
)
178 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
180 if (DeviceExtension
->Packet
.State
== Idle
181 && DeviceExtension
->PacketComplete
)
184 Result
= DeviceExtension
->PacketResult
;
185 DeviceExtension
->PacketComplete
= FALSE
;
188 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
193 if (DeviceExtension
->CurrentIrp
)
195 DeviceExtension
->CurrentIrp
->IoStatus
.Status
= Result
;
196 IoCompleteRequest(DeviceExtension
->CurrentIrp
, IO_NO_INCREMENT
);
197 IoStartNextPacket(DeviceExtension
->CurrentIrpDevice
, FALSE
);
198 DeviceExtension
->CurrentIrp
= NULL
;
199 DeviceExtension
->CurrentIrpDevice
= NULL
;
205 IN PDEVICE_OBJECT DeviceObject
,
208 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
212 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
214 UNREFERENCED_PARAMETER(DeviceObject
);
216 /* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */
218 /* Register GUID_DEVICE_SYS_BUTTON interface and report capability */
219 if (DeviceExtension
->NewCaps
!= DeviceExtension
->ReportedCaps
)
221 WaitingIrp
= InterlockedExchangePointer(&DeviceExtension
->PowerIrp
, NULL
);
224 /* Cancel the current power irp, as capability changed */
225 WaitingIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
226 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
227 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
230 if (DeviceExtension
->PowerInterfaceName
.MaximumLength
== 0)
232 /* We have never registred this interface ; do it */
233 Status
= IoRegisterDeviceInterface(
234 DeviceExtension
->Common
.Pdo
,
235 &GUID_DEVICE_SYS_BUTTON
,
237 &DeviceExtension
->PowerInterfaceName
);
238 if (!NT_SUCCESS(Status
))
240 /* We can't do more yet, ignore the keypress... */
241 WARN_(I8042PRT
, "IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n",
243 DeviceExtension
->PowerInterfaceName
.MaximumLength
= 0;
249 /* Disable the interface. Once activated again, capabilities would be asked again */
250 Status
= IoSetDeviceInterfaceState(
251 &DeviceExtension
->PowerInterfaceName
,
253 if (!NT_SUCCESS(Status
))
255 /* Ignore the key press... */
256 WARN_(I8042PRT
, "Disabling interface %wZ failed with status 0x%08lx\n",
257 &DeviceExtension
->PowerInterfaceName
, Status
);
261 /* Enable the interface. This leads to receving a IOCTL_GET_SYS_BUTTON_CAPS,
262 * so we can report new capability */
263 Status
= IoSetDeviceInterfaceState(
264 &DeviceExtension
->PowerInterfaceName
,
266 if (!NT_SUCCESS(Status
))
268 /* Ignore the key press... */
269 WARN_(I8042PRT
, "Enabling interface %wZ failed with status 0x%08lx\n",
270 &DeviceExtension
->PowerInterfaceName
, Status
);
275 /* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
276 WaitingIrp
= InterlockedExchangePointer(&DeviceExtension
->PowerIrp
, NULL
);
279 PULONG pEvent
= (PULONG
)WaitingIrp
->AssociatedIrp
.SystemBuffer
;
281 WaitingIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
282 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
283 *pEvent
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
284 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
288 /* Return TRUE if it was a power key */
291 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
)
293 PKEYBOARD_INPUT_DATA InputData
;
296 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
- 1;
297 if (!(InputData
->Flags
& KEY_E0
))
300 if (InputData
->Flags
& KEY_BREAK
)
301 /* We already took care of the key press */
304 switch (InputData
->MakeCode
)
306 case KEYBOARD_POWER_CODE
:
307 KeyPress
= SYS_BUTTON_POWER
;
309 case KEYBOARD_SLEEP_CODE
:
310 KeyPress
= SYS_BUTTON_SLEEP
;
312 case KEYBOARD_WAKE_CODE
:
313 KeyPress
= SYS_BUTTON_WAKE
;
319 /* Our work can only be done at passive level, so use a workitem */
320 DeviceExtension
->NewCaps
|= KeyPress
;
321 InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, KeyPress
);
323 DeviceExtension
->PowerWorkItem
,
333 IN PVOID DeferredContext
,
334 IN PVOID SystemArgument1
,
335 IN PVOID SystemArgument2
)
337 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
338 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
339 ULONG KeysTransferred
= 0;
340 ULONG KeysInBufferCopy
;
343 UNREFERENCED_PARAMETER(Dpc
);
344 UNREFERENCED_PARAMETER(SystemArgument1
);
345 UNREFERENCED_PARAMETER(SystemArgument2
);
347 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeferredContext
;
348 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
350 if (HandlePowerKeys(DeviceExtension
))
352 DeviceExtension
->KeyComplete
= FALSE
;
356 i8042PacketDpc(PortDeviceExtension
);
357 if (!DeviceExtension
->KeyComplete
)
359 /* We got the interrupt as it was being enabled, too bad */
360 if (!PortDeviceExtension
->HighestDIRQLInterrupt
)
363 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
365 DeviceExtension
->KeyComplete
= FALSE
;
366 KeysInBufferCopy
= DeviceExtension
->KeysInBuffer
;
368 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
370 if (PortDeviceExtension
->Settings
.CrashOnCtrlScroll
)
372 PKEYBOARD_INPUT_DATA InputData
;
373 InputData
= DeviceExtension
->KeyboardBuffer
+ KeysInBufferCopy
- 1;
375 /* Test for TAB + key combination */
376 if (InputData
->MakeCode
== 0x0F)
377 DeviceExtension
->TabPressed
= !(InputData
->Flags
& KEY_BREAK
);
378 else if (DeviceExtension
->TabPressed
)
380 DeviceExtension
->TabPressed
= FALSE
;
383 DeviceExtension
->DebugWorkItem
,
386 (PVOID
)(ULONG_PTR
)InputData
->MakeCode
);
390 TRACE_(I8042PRT
, "Send a key\n");
392 if (!DeviceExtension
->KeyboardData
.ClassService
)
395 INFO_(I8042PRT
, "Sending %lu key(s)\n", KeysInBufferCopy
);
396 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->KeyboardData
.ClassService
)(
397 DeviceExtension
->KeyboardData
.ClassDeviceObject
,
398 DeviceExtension
->KeyboardBuffer
,
399 DeviceExtension
->KeyboardBuffer
+ KeysInBufferCopy
,
402 KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
403 DeviceExtension
->KeysInBuffer
-= KeysTransferred
;
404 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
408 * Runs the keyboard IOCTL dispatch.
411 i8042KbdDeviceControl(
412 IN PDEVICE_OBJECT DeviceObject
,
415 PIO_STACK_LOCATION Stack
;
416 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
419 Stack
= IoGetCurrentIrpStackLocation(Irp
);
420 Irp
->IoStatus
.Information
= 0;
421 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
423 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
425 case IOCTL_GET_SYS_BUTTON_CAPS
:
427 /* Part of GUID_DEVICE_SYS_BUTTON interface */
429 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_CAPS\n");
431 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
432 Status
= STATUS_INVALID_PARAMETER
;
435 pCaps
= (PULONG
)Irp
->AssociatedIrp
.SystemBuffer
;
436 *pCaps
= DeviceExtension
->NewCaps
;
437 DeviceExtension
->ReportedCaps
= DeviceExtension
->NewCaps
;
438 Irp
->IoStatus
.Information
= sizeof(ULONG
);
439 Status
= STATUS_SUCCESS
;
443 case IOCTL_GET_SYS_BUTTON_EVENT
:
445 /* Part of GUID_DEVICE_SYS_BUTTON interface */
447 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_EVENT\n");
449 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
450 Status
= STATUS_INVALID_PARAMETER
;
453 WaitingIrp
= InterlockedCompareExchangePointer(
454 &DeviceExtension
->PowerIrp
,
457 /* Check if an Irp is already pending */
460 /* Unable to have a 2nd pending IRP for this IOCTL */
461 WARN_(I8042PRT
, "Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
462 Status
= STATUS_INVALID_PARAMETER
;
463 Irp
->IoStatus
.Status
= Status
;
464 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
469 PowerKey
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
472 (VOID
)InterlockedCompareExchangePointer(&DeviceExtension
->PowerIrp
, NULL
, Irp
);
473 *(PULONG
)Irp
->AssociatedIrp
.SystemBuffer
= PowerKey
;
474 Status
= STATUS_SUCCESS
;
475 Irp
->IoStatus
.Status
= Status
;
476 Irp
->IoStatus
.Information
= sizeof(ULONG
);
477 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
481 TRACE_(I8042PRT
, "Pending IOCTL_GET_SYS_BUTTON_EVENT\n");
482 Status
= STATUS_PENDING
;
483 Irp
->IoStatus
.Status
= Status
;
484 IoMarkIrpPending(Irp
);
493 ERR_(I8042PRT
, "IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
494 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
496 return ForwardIrpAndForget(DeviceObject
, Irp
);
500 Irp
->IoStatus
.Status
= Status
;
501 if (Status
== STATUS_PENDING
)
502 IoMarkIrpPending(Irp
);
504 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
510 * Runs the keyboard IOCTL_INTERNAL dispatch.
513 i8042KbdInternalDeviceControl(
514 IN PDEVICE_OBJECT DeviceObject
,
517 PIO_STACK_LOCATION Stack
;
518 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
521 Stack
= IoGetCurrentIrpStackLocation(Irp
);
522 Irp
->IoStatus
.Information
= 0;
523 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
525 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
527 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
530 PIO_WORKITEM WorkItem
= NULL
;
531 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
533 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
534 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
536 Status
= STATUS_INVALID_PARAMETER
;
540 DeviceExtension
->KeyboardData
=
541 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
543 /* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */
544 WorkItem
= IoAllocateWorkItem(DeviceObject
);
547 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
548 Status
= STATUS_INSUFFICIENT_RESOURCES
;
551 WorkItemData
= ExAllocatePoolWithTag(
553 sizeof(I8042_HOOK_WORKITEM
),
557 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
558 Status
= STATUS_NO_MEMORY
;
561 WorkItemData
->WorkItem
= WorkItem
;
562 WorkItemData
->Irp
= Irp
;
564 /* Initialize extension */
565 DeviceExtension
->Common
.Type
= Keyboard
;
566 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
);
567 DeviceExtension
->KeyboardBuffer
= ExAllocatePoolWithTag(
571 if (!DeviceExtension
->KeyboardBuffer
)
573 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
574 Status
= STATUS_NO_MEMORY
;
577 RtlZeroMemory(DeviceExtension
->KeyboardBuffer
, Size
);
579 &DeviceExtension
->DpcKeyboard
,
582 DeviceExtension
->PowerWorkItem
= IoAllocateWorkItem(DeviceObject
);
583 if (!DeviceExtension
->PowerWorkItem
)
585 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
586 Status
= STATUS_INSUFFICIENT_RESOURCES
;
589 DeviceExtension
->DebugWorkItem
= IoAllocateWorkItem(DeviceObject
);
590 if (!DeviceExtension
->DebugWorkItem
)
592 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
593 Status
= STATUS_INSUFFICIENT_RESOURCES
;
596 DeviceExtension
->Common
.PortDeviceExtension
->KeyboardExtension
= DeviceExtension
;
597 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= KEYBOARD_CONNECTED
;
599 IoMarkIrpPending(Irp
);
600 /* FIXME: DeviceExtension->KeyboardHook.IsrWritePort = ; */
601 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket
= i8042KbdQueuePacket
;
602 DeviceExtension
->KeyboardHook
.CallContext
= DeviceExtension
;
603 IoQueueWorkItem(WorkItem
,
604 i8042SendHookWorkItem
,
607 Status
= STATUS_PENDING
;
611 if (DeviceExtension
->KeyboardBuffer
)
612 ExFreePoolWithTag(DeviceExtension
->KeyboardBuffer
, I8042PRT_TAG
);
613 if (DeviceExtension
->PowerWorkItem
)
614 IoFreeWorkItem(DeviceExtension
->PowerWorkItem
);
615 if (DeviceExtension
->DebugWorkItem
)
616 IoFreeWorkItem(DeviceExtension
->DebugWorkItem
);
618 IoFreeWorkItem(WorkItem
);
620 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
623 case IOCTL_INTERNAL_KEYBOARD_DISCONNECT
:
625 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n");
626 /* MSDN says that operation is to implemented.
627 * To implement it, we just have to do:
628 * DeviceExtension->KeyboardData.ClassService = NULL;
630 Status
= STATUS_NOT_IMPLEMENTED
;
633 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
:
635 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n");
636 /* Nothing to do here */
637 Status
= STATUS_SUCCESS
;
640 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
642 DPRINT1("IOCTL_KEYBOARD_QUERY_ATTRIBUTES not implemented\n");
644 /* FIXME: KeyboardAttributes are not initialized anywhere */
645 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
646 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KEYBOARD_ATTRIBUTES
))
648 Status
= STATUS_BUFFER_TOO_SMALL
;
652 *(PKEYBOARD_ATTRIBUTES
) Irp
->AssociatedIrp
.SystemBuffer
= DeviceExtension
->KeyboardAttributes
;
653 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_ATTRIBUTES
);
654 Status
= STATUS_SUCCESS
;
657 Status
= STATUS_NOT_IMPLEMENTED
;
660 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
662 DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n");
663 Status
= STATUS_NOT_IMPLEMENTED
;
666 case IOCTL_KEYBOARD_SET_TYPEMATIC
:
668 DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n");
669 Status
= STATUS_NOT_IMPLEMENTED
;
672 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
674 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
676 /* We should check the UnitID, but it's kind of pointless as
677 * all keyboards are supposed to have the same one
679 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
))
681 Status
= STATUS_BUFFER_TOO_SMALL
;
686 Irp
->AssociatedIrp
.SystemBuffer
,
687 &IndicatorTranslation
,
688 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
));
689 Irp
->IoStatus
.Information
= sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
);
690 Status
= STATUS_SUCCESS
;
694 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
696 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
698 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
700 Status
= STATUS_BUFFER_TOO_SMALL
;
705 Irp
->AssociatedIrp
.SystemBuffer
,
706 &DeviceExtension
->KeyboardIndicators
,
707 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
708 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INDICATOR_PARAMETERS
);
709 Status
= STATUS_SUCCESS
;
713 case IOCTL_KEYBOARD_SET_INDICATORS
:
715 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n");
717 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
719 Status
= STATUS_BUFFER_TOO_SMALL
;
724 &DeviceExtension
->KeyboardIndicators
,
725 Irp
->AssociatedIrp
.SystemBuffer
,
726 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
727 Status
= STATUS_PENDING
;
728 IoMarkIrpPending(Irp
);
729 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
735 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
736 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
738 return ForwardIrpAndForget(DeviceObject
, Irp
);
742 Irp
->IoStatus
.Status
= Status
;
743 if (Status
!= STATUS_PENDING
)
744 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
749 * Call the customization hook. The ToReturn parameter is about wether
750 * we should go on with the interrupt. The return value is what
751 * we should return (indicating to the system wether someone else
752 * should try to handle the interrupt)
756 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
,
759 OUT PBOOLEAN ToReturn
)
761 BOOLEAN HookReturn
, HookContinue
;
763 HookContinue
= FALSE
;
765 if (DeviceExtension
->KeyboardHook
.IsrRoutine
)
767 HookReturn
= DeviceExtension
->KeyboardHook
.IsrRoutine(
768 DeviceExtension
->KeyboardHook
.Context
,
769 DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
,
770 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
774 &DeviceExtension
->KeyboardScanState
);
778 *ToReturn
= HookReturn
;
786 i8042KbdInterruptService(
787 IN PKINTERRUPT Interrupt
,
790 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
791 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
792 PKEYBOARD_INPUT_DATA InputData
;
794 UCHAR PortStatus
= 0, Output
= 0;
795 BOOLEAN ToReturn
= FALSE
;
798 UNREFERENCED_PARAMETER(Interrupt
);
800 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
801 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
802 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
;
803 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
807 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
808 if (!NT_SUCCESS(Status
))
810 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
813 Status
= i8042ReadKeyboardData(PortDeviceExtension
, &Output
);
814 if (NT_SUCCESS(Status
))
816 KeStallExecutionProcessor(1);
821 WARN_(I8042PRT
, "Spurious i8042 keyboard interrupt\n");
825 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
827 if (PortDeviceExtension
->Settings
.CrashOnCtrlScroll
)
829 /* Test for CTRL + SCROLL LOCK twice */
830 static const UCHAR ScanCodes
[] = { 0xe0, 0x1d, 0x46, 0xc6, 0x46, 0 };
832 if (Output
== ScanCodes
[DeviceExtension
->ComboPosition
])
834 DeviceExtension
->ComboPosition
++;
835 if (ScanCodes
[DeviceExtension
->ComboPosition
] == 0)
836 KeBugCheck(MANUALLY_INITIATED_CRASH
);
838 else if (Output
== ScanCodes
[0])
839 DeviceExtension
->ComboPosition
= 1;
841 DeviceExtension
->ComboPosition
= 0;
844 if (i8042KbdCallIsrHook(DeviceExtension
, PortStatus
, Output
, &ToReturn
))
847 if (i8042PacketIsr(PortDeviceExtension
, Output
))
849 if (PortDeviceExtension
->PacketComplete
)
851 TRACE_(I8042PRT
, "Packet complete\n");
852 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
854 TRACE_(I8042PRT
, "Irq eaten by packet\n");
858 TRACE_(I8042PRT
, "Irq is keyboard input\n");
860 if (DeviceExtension
->KeyboardScanState
== Normal
)
865 DeviceExtension
->KeyboardScanState
= GotE0
;
868 DeviceExtension
->KeyboardScanState
= GotE1
;
875 /* Update InputData */
876 InputData
->Flags
= 0;
877 switch (DeviceExtension
->KeyboardScanState
)
880 InputData
->Flags
|= KEY_E0
;
883 InputData
->Flags
|= KEY_E1
;
888 DeviceExtension
->KeyboardScanState
= Normal
;
890 InputData
->Flags
|= KEY_BREAK
;
892 InputData
->Flags
|= KEY_MAKE
;
893 InputData
->MakeCode
= Output
& 0x7f;
894 InputData
->Reserved
= 0;
896 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket(DeviceExtension
->KeyboardHook
.CallContext
);