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 *****************************************************************/
35 #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
39 IN PDEVICE_OBJECT DeviceObject
,
42 UNREFERENCED_PARAMETER(DeviceObject
);
43 INFO_(I8042PRT
, "Debug key: p\n", Key
);
48 /* We hope kernel would understand this. If
49 * that's not the case, nothing would happen.
51 KdSystemDebugControl(TAG('R', 'o', 's', ' '), Key
, 0, NULL
, 0, NULL
, KernelMode
);
55 * These functions are callbacks for filter driver custom interrupt
63 PI8042_KEYBOARD_EXTENSION DeviceExtension;
65 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
67 if (DeviceExtension->KeyboardHook.IsrWritePort)
69 DeviceExtension->KeyboardHook.IsrWritePort(
70 DeviceExtension->KeyboardHook.CallContext,
74 i8042IsrWritePort(Context, Value, 0);
81 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
83 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
85 DeviceExtension
->KeyComplete
= TRUE
;
86 DeviceExtension
->KeysInBuffer
++;
87 if (DeviceExtension
->KeysInBuffer
> DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
)
89 WARN_(I8042PRT
, "Keyboard buffer overflow\n");
90 DeviceExtension
->KeysInBuffer
--;
93 TRACE_(I8042PRT
, "Irq completes key\n");
94 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
98 * These functions are callbacks for filter driver custom
99 * initialization routines.
102 i8042SynchWritePortKbd(
105 IN BOOLEAN WaitForAck
)
107 return i8042SynchWritePort(
108 (PPORT_DEVICE_EXTENSION
)Context
,
115 * Process the keyboard internal device requests
119 IN PDEVICE_OBJECT DeviceObject
,
122 PIO_STACK_LOCATION Stack
;
123 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
124 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
126 Stack
= IoGetCurrentIrpStackLocation(Irp
);
127 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
128 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
130 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
132 case IOCTL_KEYBOARD_SET_INDICATORS
:
134 TRACE_(I8042PRT
, "IOCTL_KEYBOARD_SET_INDICATORS\n");
135 INFO_(I8042PRT
, "Leds: {%s%s%s }\n",
136 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
? " CAPSLOCK" : "",
137 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
? " NUMLOCK" : "",
138 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
? " SCROLLLOCK" : "");
140 PortDeviceExtension
->PacketBuffer
[0] = KBD_CMD_SET_LEDS
;
141 PortDeviceExtension
->PacketBuffer
[1] = 0;
142 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
)
143 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_CAPS
;
145 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
)
146 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_NUM
;
148 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
)
149 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_SCROLL
;
153 &DeviceExtension
->Common
,
154 PortDeviceExtension
->PacketBuffer
,
161 ERR_(I8042PRT
, "Unknown ioctl code 0x%lx\n",
162 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
170 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
172 BOOLEAN FinishIrp
= FALSE
;
174 NTSTATUS Result
= STATUS_INTERNAL_ERROR
; /* Shouldn't happen */
176 /* If the interrupt happens before this is setup, the key
177 * was already in the buffer. Too bad! */
178 if (!DeviceExtension
->HighestDIRQLInterrupt
)
181 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
183 if (DeviceExtension
->Packet
.State
== Idle
184 && DeviceExtension
->PacketComplete
)
187 Result
= DeviceExtension
->PacketResult
;
188 DeviceExtension
->PacketComplete
= FALSE
;
191 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
196 if (DeviceExtension
->CurrentIrp
)
198 DeviceExtension
->CurrentIrp
->IoStatus
.Status
= Result
;
199 IoCompleteRequest(DeviceExtension
->CurrentIrp
, IO_NO_INCREMENT
);
200 IoStartNextPacket(DeviceExtension
->CurrentIrpDevice
, FALSE
);
201 DeviceExtension
->CurrentIrp
= NULL
;
202 DeviceExtension
->CurrentIrpDevice
= NULL
;
208 IN PDEVICE_OBJECT DeviceObject
,
211 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
215 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
217 UNREFERENCED_PARAMETER(DeviceObject
);
219 /* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */
221 /* Register GUID_DEVICE_SYS_BUTTON interface and report capability */
222 if (DeviceExtension
->NewCaps
!= DeviceExtension
->ReportedCaps
)
224 WaitingIrp
= InterlockedExchangePointer(&DeviceExtension
->PowerIrp
, NULL
);
227 /* Cancel the current power irp, as capability changed */
228 WaitingIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
229 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
230 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
233 if (DeviceExtension
->PowerInterfaceName
.MaximumLength
== 0)
235 /* We have never registred this interface ; do it */
236 Status
= IoRegisterDeviceInterface(
237 DeviceExtension
->Common
.Pdo
,
238 &GUID_DEVICE_SYS_BUTTON
,
240 &DeviceExtension
->PowerInterfaceName
);
241 if (!NT_SUCCESS(Status
))
243 /* We can't do more yet, ignore the keypress... */
244 WARN_(I8042PRT
, "IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n",
246 DeviceExtension
->PowerInterfaceName
.MaximumLength
= 0;
252 /* Disable the interface. Once activated again, capabilities would be asked again */
253 Status
= IoSetDeviceInterfaceState(
254 &DeviceExtension
->PowerInterfaceName
,
256 if (!NT_SUCCESS(Status
))
258 /* Ignore the key press... */
259 WARN_(I8042PRT
, "Disabling interface %wZ failed with status 0x%08lx\n",
260 &DeviceExtension
->PowerInterfaceName
, Status
);
264 /* Enable the interface. This leads to receving a IOCTL_GET_SYS_BUTTON_CAPS,
265 * so we can report new capability */
266 Status
= IoSetDeviceInterfaceState(
267 &DeviceExtension
->PowerInterfaceName
,
269 if (!NT_SUCCESS(Status
))
271 /* Ignore the key press... */
272 WARN_(I8042PRT
, "Enabling interface %wZ failed with status 0x%08lx\n",
273 &DeviceExtension
->PowerInterfaceName
, Status
);
278 /* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
279 WaitingIrp
= InterlockedExchangePointer(&DeviceExtension
->PowerIrp
, NULL
);
282 PULONG pEvent
= (PULONG
)WaitingIrp
->AssociatedIrp
.SystemBuffer
;
284 WaitingIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
285 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
286 *pEvent
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
287 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
291 /* Return TRUE if it was a power key */
294 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
)
296 PKEYBOARD_INPUT_DATA InputData
;
299 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
- 1;
300 if (!(InputData
->Flags
& KEY_E0
))
303 if (InputData
->Flags
& KEY_BREAK
)
304 /* We already took care of the key press */
307 switch (InputData
->MakeCode
)
309 case KEYBOARD_POWER_CODE
:
310 KeyPress
= SYS_BUTTON_POWER
;
312 case KEYBOARD_SLEEP_CODE
:
313 KeyPress
= SYS_BUTTON_SLEEP
;
315 case KEYBOARD_WAKE_CODE
:
316 KeyPress
= SYS_BUTTON_WAKE
;
322 /* Our work can only be done at passive level, so use a workitem */
323 DeviceExtension
->NewCaps
|= KeyPress
;
324 InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, KeyPress
);
326 DeviceExtension
->PowerWorkItem
,
336 IN PVOID DeferredContext
,
337 IN PVOID SystemArgument1
,
338 IN PVOID SystemArgument2
)
340 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
341 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
342 ULONG KeysTransferred
= 0;
343 ULONG KeysInBufferCopy
;
346 UNREFERENCED_PARAMETER(Dpc
);
347 UNREFERENCED_PARAMETER(SystemArgument1
);
348 UNREFERENCED_PARAMETER(SystemArgument2
);
350 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeferredContext
;
351 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
353 if (HandlePowerKeys(DeviceExtension
))
355 DeviceExtension
->KeyComplete
= FALSE
;
359 i8042PacketDpc(PortDeviceExtension
);
360 if (!DeviceExtension
->KeyComplete
)
362 /* We got the interrupt as it was being enabled, too bad */
363 if (!PortDeviceExtension
->HighestDIRQLInterrupt
)
366 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
368 DeviceExtension
->KeyComplete
= FALSE
;
369 KeysInBufferCopy
= DeviceExtension
->KeysInBuffer
;
371 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
373 if (PortDeviceExtension
->Settings
.CrashOnCtrlScroll
)
375 PKEYBOARD_INPUT_DATA InputData
;
376 InputData
= DeviceExtension
->KeyboardBuffer
+ KeysInBufferCopy
- 1;
378 /* Test for TAB + key combination */
379 if (InputData
->MakeCode
== 0x0F)
380 DeviceExtension
->TabPressed
= !(InputData
->Flags
& KEY_BREAK
);
381 else if (DeviceExtension
->TabPressed
)
383 DeviceExtension
->TabPressed
= FALSE
;
386 DeviceExtension
->DebugWorkItem
,
389 (PVOID
)(ULONG_PTR
)InputData
->MakeCode
);
393 TRACE_(I8042PRT
, "Send a key\n");
395 if (!DeviceExtension
->KeyboardData
.ClassService
)
398 INFO_(I8042PRT
, "Sending %lu key(s)\n", KeysInBufferCopy
);
399 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->KeyboardData
.ClassService
)(
400 DeviceExtension
->KeyboardData
.ClassDeviceObject
,
401 DeviceExtension
->KeyboardBuffer
,
402 DeviceExtension
->KeyboardBuffer
+ KeysInBufferCopy
,
405 KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
406 DeviceExtension
->KeysInBuffer
-= KeysTransferred
;
407 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
411 * Runs the keyboard IOCTL dispatch.
414 i8042KbdDeviceControl(
415 IN PDEVICE_OBJECT DeviceObject
,
418 PIO_STACK_LOCATION Stack
;
419 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
422 Stack
= IoGetCurrentIrpStackLocation(Irp
);
423 Irp
->IoStatus
.Information
= 0;
424 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
426 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
428 case IOCTL_GET_SYS_BUTTON_CAPS
:
430 /* Part of GUID_DEVICE_SYS_BUTTON interface */
432 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_CAPS\n");
434 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
435 Status
= STATUS_INVALID_PARAMETER
;
438 pCaps
= (PULONG
)Irp
->AssociatedIrp
.SystemBuffer
;
439 *pCaps
= DeviceExtension
->NewCaps
;
440 DeviceExtension
->ReportedCaps
= DeviceExtension
->NewCaps
;
441 Irp
->IoStatus
.Information
= sizeof(ULONG
);
442 Status
= STATUS_SUCCESS
;
446 case IOCTL_GET_SYS_BUTTON_EVENT
:
448 /* Part of GUID_DEVICE_SYS_BUTTON interface */
450 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_EVENT\n");
452 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
453 Status
= STATUS_INVALID_PARAMETER
;
456 WaitingIrp
= InterlockedCompareExchangePointer(
457 &DeviceExtension
->PowerIrp
,
460 /* Check if an Irp is already pending */
463 /* Unable to have a 2nd pending IRP for this IOCTL */
464 WARN_(I8042PRT
, "Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
465 Status
= STATUS_INVALID_PARAMETER
;
466 Irp
->IoStatus
.Status
= Status
;
467 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
472 PowerKey
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
475 (VOID
)InterlockedCompareExchangePointer(&DeviceExtension
->PowerIrp
, NULL
, Irp
);
476 *(PULONG
)Irp
->AssociatedIrp
.SystemBuffer
= PowerKey
;
477 Status
= STATUS_SUCCESS
;
478 Irp
->IoStatus
.Status
= Status
;
479 Irp
->IoStatus
.Information
= sizeof(ULONG
);
480 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
484 TRACE_(I8042PRT
, "Pending IOCTL_GET_SYS_BUTTON_EVENT\n");
485 Status
= STATUS_PENDING
;
486 Irp
->IoStatus
.Status
= Status
;
487 IoMarkIrpPending(Irp
);
496 ERR_(I8042PRT
, "IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
497 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
499 return ForwardIrpAndForget(DeviceObject
, Irp
);
503 Irp
->IoStatus
.Status
= Status
;
504 if (Status
== STATUS_PENDING
)
505 IoMarkIrpPending(Irp
);
507 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
513 * Runs the keyboard IOCTL_INTERNAL dispatch.
516 i8042KbdInternalDeviceControl(
517 IN PDEVICE_OBJECT DeviceObject
,
520 PIO_STACK_LOCATION Stack
;
521 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
524 Stack
= IoGetCurrentIrpStackLocation(Irp
);
525 Irp
->IoStatus
.Information
= 0;
526 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
528 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
530 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
533 PIO_WORKITEM WorkItem
= NULL
;
534 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
536 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
537 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
539 Status
= STATUS_INVALID_PARAMETER
;
543 DeviceExtension
->KeyboardData
=
544 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
546 /* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */
547 WorkItem
= IoAllocateWorkItem(DeviceObject
);
550 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
551 Status
= STATUS_INSUFFICIENT_RESOURCES
;
554 WorkItemData
= ExAllocatePoolWithTag(
556 sizeof(I8042_HOOK_WORKITEM
),
560 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
561 Status
= STATUS_NO_MEMORY
;
564 WorkItemData
->WorkItem
= WorkItem
;
565 WorkItemData
->Irp
= Irp
;
567 /* Initialize extension */
568 DeviceExtension
->Common
.Type
= Keyboard
;
569 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
);
570 DeviceExtension
->KeyboardBuffer
= ExAllocatePoolWithTag(
574 if (!DeviceExtension
->KeyboardBuffer
)
576 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
577 Status
= STATUS_NO_MEMORY
;
580 RtlZeroMemory(DeviceExtension
->KeyboardBuffer
, Size
);
582 &DeviceExtension
->DpcKeyboard
,
585 DeviceExtension
->PowerWorkItem
= IoAllocateWorkItem(DeviceObject
);
586 if (!DeviceExtension
->PowerWorkItem
)
588 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
589 Status
= STATUS_INSUFFICIENT_RESOURCES
;
592 DeviceExtension
->DebugWorkItem
= IoAllocateWorkItem(DeviceObject
);
593 if (!DeviceExtension
->DebugWorkItem
)
595 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
596 Status
= STATUS_INSUFFICIENT_RESOURCES
;
599 DeviceExtension
->Common
.PortDeviceExtension
->KeyboardExtension
= DeviceExtension
;
600 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= KEYBOARD_CONNECTED
;
602 IoMarkIrpPending(Irp
);
603 /* FIXME: DeviceExtension->KeyboardHook.IsrWritePort = ; */
604 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket
= i8042KbdQueuePacket
;
605 DeviceExtension
->KeyboardHook
.CallContext
= DeviceExtension
;
606 IoQueueWorkItem(WorkItem
,
607 i8042SendHookWorkItem
,
610 Status
= STATUS_PENDING
;
614 if (DeviceExtension
->KeyboardBuffer
)
615 ExFreePoolWithTag(DeviceExtension
->KeyboardBuffer
, I8042PRT_TAG
);
616 if (DeviceExtension
->PowerWorkItem
)
617 IoFreeWorkItem(DeviceExtension
->PowerWorkItem
);
618 if (DeviceExtension
->DebugWorkItem
)
619 IoFreeWorkItem(DeviceExtension
->DebugWorkItem
);
621 IoFreeWorkItem(WorkItem
);
623 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
626 case IOCTL_INTERNAL_KEYBOARD_DISCONNECT
:
628 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n");
629 /* MSDN says that operation is to implemented.
630 * To implement it, we just have to do:
631 * DeviceExtension->KeyboardData.ClassService = NULL;
633 Status
= STATUS_NOT_IMPLEMENTED
;
636 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
:
638 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n");
639 /* Nothing to do here */
640 Status
= STATUS_SUCCESS
;
643 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
645 DPRINT1("IOCTL_KEYBOARD_QUERY_ATTRIBUTES not implemented\n");
647 /* FIXME: KeyboardAttributes are not initialized anywhere */
648 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
649 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KEYBOARD_ATTRIBUTES
))
651 Status
= STATUS_BUFFER_TOO_SMALL
;
655 *(PKEYBOARD_ATTRIBUTES
) Irp
->AssociatedIrp
.SystemBuffer
= DeviceExtension
->KeyboardAttributes
;
656 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_ATTRIBUTES
);
657 Status
= STATUS_SUCCESS
;
660 Status
= STATUS_NOT_IMPLEMENTED
;
663 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
665 DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n");
666 Status
= STATUS_NOT_IMPLEMENTED
;
669 case IOCTL_KEYBOARD_SET_TYPEMATIC
:
671 DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n");
672 Status
= STATUS_NOT_IMPLEMENTED
;
675 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
677 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
679 /* We should check the UnitID, but it's kind of pointless as
680 * all keyboards are supposed to have the same one
682 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
))
684 Status
= STATUS_BUFFER_TOO_SMALL
;
689 Irp
->AssociatedIrp
.SystemBuffer
,
690 &IndicatorTranslation
,
691 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
));
692 Irp
->IoStatus
.Information
= sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
);
693 Status
= STATUS_SUCCESS
;
697 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
699 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
701 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
703 Status
= STATUS_BUFFER_TOO_SMALL
;
708 Irp
->AssociatedIrp
.SystemBuffer
,
709 &DeviceExtension
->KeyboardIndicators
,
710 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
711 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INDICATOR_PARAMETERS
);
712 Status
= STATUS_SUCCESS
;
716 case IOCTL_KEYBOARD_SET_INDICATORS
:
718 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n");
720 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
722 Status
= STATUS_BUFFER_TOO_SMALL
;
727 &DeviceExtension
->KeyboardIndicators
,
728 Irp
->AssociatedIrp
.SystemBuffer
,
729 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
730 Status
= STATUS_PENDING
;
731 IoMarkIrpPending(Irp
);
732 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
738 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
739 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
741 return ForwardIrpAndForget(DeviceObject
, Irp
);
745 Irp
->IoStatus
.Status
= Status
;
746 if (Status
!= STATUS_PENDING
)
747 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
752 * Call the customization hook. The ToReturn parameter is about wether
753 * we should go on with the interrupt. The return value is what
754 * we should return (indicating to the system wether someone else
755 * should try to handle the interrupt)
759 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
,
762 OUT PBOOLEAN ToReturn
)
764 BOOLEAN HookReturn
, HookContinue
;
766 HookContinue
= FALSE
;
768 if (DeviceExtension
->KeyboardHook
.IsrRoutine
)
770 HookReturn
= DeviceExtension
->KeyboardHook
.IsrRoutine(
771 DeviceExtension
->KeyboardHook
.Context
,
772 DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
,
773 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
777 &DeviceExtension
->KeyboardScanState
);
781 *ToReturn
= HookReturn
;
789 i8042KbdInterruptService(
790 IN PKINTERRUPT Interrupt
,
793 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
794 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
795 PKEYBOARD_INPUT_DATA InputData
;
797 UCHAR PortStatus
= 0, Output
= 0;
798 BOOLEAN ToReturn
= FALSE
;
801 UNREFERENCED_PARAMETER(Interrupt
);
803 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
804 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
805 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
;
806 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
810 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
811 if (!NT_SUCCESS(Status
))
813 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
816 Status
= i8042ReadKeyboardData(PortDeviceExtension
, &Output
);
817 if (NT_SUCCESS(Status
))
819 KeStallExecutionProcessor(1);
824 WARN_(I8042PRT
, "Spurious i8042 keyboard interrupt\n");
828 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
830 if (PortDeviceExtension
->Settings
.CrashOnCtrlScroll
)
832 /* Test for CTRL + SCROLL LOCK twice */
833 static const UCHAR ScanCodes
[] = { 0xe0, 0x1d, 0x46, 0xc6, 0x46, 0 };
835 if (Output
== ScanCodes
[DeviceExtension
->ComboPosition
])
837 DeviceExtension
->ComboPosition
++;
838 if (ScanCodes
[DeviceExtension
->ComboPosition
] == 0)
839 KeBugCheck(MANUALLY_INITIATED_CRASH
);
841 else if (Output
== ScanCodes
[0])
842 DeviceExtension
->ComboPosition
= 1;
844 DeviceExtension
->ComboPosition
= 0;
847 if (i8042KbdCallIsrHook(DeviceExtension
, PortStatus
, Output
, &ToReturn
))
850 if (i8042PacketIsr(PortDeviceExtension
, Output
))
852 if (PortDeviceExtension
->PacketComplete
)
854 TRACE_(I8042PRT
, "Packet complete\n");
855 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
857 TRACE_(I8042PRT
, "Irq eaten by packet\n");
861 TRACE_(I8042PRT
, "Irq is keyboard input\n");
863 if (DeviceExtension
->KeyboardScanState
== Normal
)
868 DeviceExtension
->KeyboardScanState
= GotE0
;
871 DeviceExtension
->KeyboardScanState
= GotE1
;
878 /* Update InputData */
879 InputData
->Flags
= 0;
880 switch (DeviceExtension
->KeyboardScanState
)
883 InputData
->Flags
|= KEY_E0
;
886 InputData
->Flags
|= KEY_E1
;
891 DeviceExtension
->KeyboardScanState
= Normal
;
893 InputData
->Flags
|= KEY_BREAK
;
895 InputData
->Flags
|= KEY_MAKE
;
896 InputData
->MakeCode
= Output
& 0x7f;
897 InputData
->Reserved
= 0;
899 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket(DeviceExtension
->KeyboardHook
.CallContext
);