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 ****************************************************************/
17 #include <ndk/kdfuncs.h>
21 /* GLOBALS *******************************************************************/
23 static IO_WORKITEM_ROUTINE i8042PowerWorkItem
;
25 /* This structure starts with the same layout as KEYBOARD_INDICATOR_TRANSLATION */
26 typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION
{
27 USHORT NumberOfIndicatorKeys
;
28 INDICATOR_LIST IndicatorList
[3];
29 } LOCAL_KEYBOARD_INDICATOR_TRANSLATION
, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION
;
31 static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation
= { 3, {
32 {0x3A, KEYBOARD_CAPS_LOCK_ON
},
33 {0x45, KEYBOARD_NUM_LOCK_ON
},
34 {0x46, KEYBOARD_SCROLL_LOCK_ON
}}};
36 /* FUNCTIONS *****************************************************************/
39 * These functions are callbacks for filter driver custom interrupt
47 PI8042_KEYBOARD_EXTENSION DeviceExtension;
49 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
51 if (DeviceExtension->KeyboardHook.IsrWritePort)
53 DeviceExtension->KeyboardHook.IsrWritePort(
54 DeviceExtension->KeyboardHook.CallContext,
58 i8042IsrWritePort(Context, Value, 0);
65 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
67 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
69 DeviceExtension
->KeyComplete
= TRUE
;
70 DeviceExtension
->KeysInBuffer
++;
71 if (DeviceExtension
->KeysInBuffer
> DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
)
73 WARN_(I8042PRT
, "Keyboard buffer overflow\n");
74 DeviceExtension
->KeysInBuffer
--;
77 TRACE_(I8042PRT
, "Irq completes key\n");
78 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
82 * These functions are callbacks for filter driver custom
83 * initialization routines.
86 i8042SynchWritePortKbd(
89 IN BOOLEAN WaitForAck
)
91 return i8042SynchWritePort(
92 (PPORT_DEVICE_EXTENSION
)Context
,
99 * Process the keyboard internal device requests
103 IN PDEVICE_OBJECT DeviceObject
,
106 PIO_STACK_LOCATION Stack
;
107 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
108 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
110 Stack
= IoGetCurrentIrpStackLocation(Irp
);
111 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
112 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
114 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
116 case IOCTL_KEYBOARD_SET_INDICATORS
:
118 TRACE_(I8042PRT
, "IOCTL_KEYBOARD_SET_INDICATORS\n");
119 INFO_(I8042PRT
, "Leds: {%s%s%s }\n",
120 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
? " CAPSLOCK" : "",
121 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
? " NUMLOCK" : "",
122 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
? " SCROLLLOCK" : "");
124 PortDeviceExtension
->PacketBuffer
[0] = KBD_CMD_SET_LEDS
;
125 PortDeviceExtension
->PacketBuffer
[1] = 0;
126 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
)
127 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_CAPS
;
129 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
)
130 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_NUM
;
132 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
)
133 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_SCROLL
;
137 &DeviceExtension
->Common
,
138 PortDeviceExtension
->PacketBuffer
,
145 ERR_(I8042PRT
, "Unknown ioctl code 0x%lx\n",
146 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
154 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
156 BOOLEAN FinishIrp
= FALSE
;
158 NTSTATUS Result
= STATUS_INTERNAL_ERROR
; /* Shouldn't happen */
160 /* If the interrupt happens before this is setup, the key
161 * was already in the buffer. Too bad! */
162 if (!DeviceExtension
->HighestDIRQLInterrupt
)
165 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
167 if (DeviceExtension
->Packet
.State
== Idle
168 && DeviceExtension
->PacketComplete
)
171 Result
= DeviceExtension
->PacketResult
;
172 DeviceExtension
->PacketComplete
= FALSE
;
175 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
180 if (DeviceExtension
->CurrentIrp
)
182 DeviceExtension
->CurrentIrp
->IoStatus
.Status
= Result
;
183 IoCompleteRequest(DeviceExtension
->CurrentIrp
, IO_NO_INCREMENT
);
184 IoStartNextPacket(DeviceExtension
->CurrentIrpDevice
, FALSE
);
185 DeviceExtension
->CurrentIrp
= NULL
;
186 DeviceExtension
->CurrentIrpDevice
= NULL
;
192 IN PDEVICE_OBJECT DeviceObject
,
195 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
199 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
201 UNREFERENCED_PARAMETER(DeviceObject
);
203 /* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */
205 /* Register GUID_DEVICE_SYS_BUTTON interface and report capability */
206 if (DeviceExtension
->NewCaps
!= DeviceExtension
->ReportedCaps
)
208 WaitingIrp
= InterlockedExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
);
211 /* Cancel the current power irp, as capability changed */
212 WaitingIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
213 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
214 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
217 if (DeviceExtension
->PowerInterfaceName
.MaximumLength
== 0)
219 /* We have never registred this interface ; do it */
220 Status
= IoRegisterDeviceInterface(
221 DeviceExtension
->Common
.Pdo
,
222 &GUID_DEVICE_SYS_BUTTON
,
224 &DeviceExtension
->PowerInterfaceName
);
225 if (!NT_SUCCESS(Status
))
227 /* We can't do more yet, ignore the keypress... */
228 WARN_(I8042PRT
, "IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n",
230 DeviceExtension
->PowerInterfaceName
.MaximumLength
= 0;
236 /* Disable the interface. Once activated again, capabilities would be asked again */
237 Status
= IoSetDeviceInterfaceState(
238 &DeviceExtension
->PowerInterfaceName
,
240 if (!NT_SUCCESS(Status
))
242 /* Ignore the key press... */
243 WARN_(I8042PRT
, "Disabling interface %wZ failed with status 0x%08lx\n",
244 &DeviceExtension
->PowerInterfaceName
, Status
);
248 /* Enable the interface. This leads to receving a IOCTL_GET_SYS_BUTTON_CAPS,
249 * so we can report new capability */
250 Status
= IoSetDeviceInterfaceState(
251 &DeviceExtension
->PowerInterfaceName
,
253 if (!NT_SUCCESS(Status
))
255 /* Ignore the key press... */
256 WARN_(I8042PRT
, "Enabling interface %wZ failed with status 0x%08lx\n",
257 &DeviceExtension
->PowerInterfaceName
, Status
);
262 /* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
263 WaitingIrp
= InterlockedExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
);
266 PULONG pEvent
= (PULONG
)WaitingIrp
->AssociatedIrp
.SystemBuffer
;
268 WaitingIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
269 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
270 *pEvent
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
271 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
275 /* Return TRUE if it was a power key */
278 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
)
280 PKEYBOARD_INPUT_DATA InputData
;
283 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
- 1;
284 if (!(InputData
->Flags
& KEY_E0
))
287 switch (InputData
->MakeCode
)
289 case KEYBOARD_POWER_CODE
:
290 KeyPress
= SYS_BUTTON_POWER
;
292 case KEYBOARD_SLEEP_CODE
:
293 KeyPress
= SYS_BUTTON_SLEEP
;
295 case KEYBOARD_WAKE_CODE
:
296 KeyPress
= SYS_BUTTON_WAKE
;
302 if (InputData
->Flags
& KEY_BREAK
)
303 /* We already took care of the key press */
306 /* Our work can only be done at passive level, so use a workitem */
307 DeviceExtension
->NewCaps
|= KeyPress
;
308 InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, KeyPress
);
310 DeviceExtension
->PowerWorkItem
,
320 IN PVOID DeferredContext
,
321 IN PVOID SystemArgument1
,
322 IN PVOID SystemArgument2
)
324 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
325 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
326 ULONG KeysTransferred
= 0;
327 ULONG KeysInBufferCopy
;
330 UNREFERENCED_PARAMETER(Dpc
);
331 UNREFERENCED_PARAMETER(SystemArgument1
);
332 UNREFERENCED_PARAMETER(SystemArgument2
);
334 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeferredContext
;
335 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
337 if (HandlePowerKeys(DeviceExtension
))
339 DeviceExtension
->KeyComplete
= FALSE
;
343 i8042PacketDpc(PortDeviceExtension
);
344 if (!DeviceExtension
->KeyComplete
)
346 /* We got the interrupt as it was being enabled, too bad */
347 if (!PortDeviceExtension
->HighestDIRQLInterrupt
)
350 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
352 DeviceExtension
->KeyComplete
= FALSE
;
353 KeysInBufferCopy
= DeviceExtension
->KeysInBuffer
;
355 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
357 TRACE_(I8042PRT
, "Send a key\n");
359 if (!DeviceExtension
->KeyboardData
.ClassService
)
362 INFO_(I8042PRT
, "Sending %lu key(s)\n", KeysInBufferCopy
);
363 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->KeyboardData
.ClassService
)(
364 DeviceExtension
->KeyboardData
.ClassDeviceObject
,
365 DeviceExtension
->KeyboardBuffer
,
366 DeviceExtension
->KeyboardBuffer
+ KeysInBufferCopy
,
369 KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
370 DeviceExtension
->KeysInBuffer
-= KeysTransferred
;
371 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
375 * Runs the keyboard IOCTL dispatch.
378 i8042KbdDeviceControl(
379 IN PDEVICE_OBJECT DeviceObject
,
382 PIO_STACK_LOCATION Stack
;
383 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
386 Stack
= IoGetCurrentIrpStackLocation(Irp
);
387 Irp
->IoStatus
.Information
= 0;
388 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
390 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
392 case IOCTL_GET_SYS_BUTTON_CAPS
:
394 /* Part of GUID_DEVICE_SYS_BUTTON interface */
396 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_CAPS\n");
398 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
399 Status
= STATUS_INVALID_PARAMETER
;
402 pCaps
= (PULONG
)Irp
->AssociatedIrp
.SystemBuffer
;
403 *pCaps
= DeviceExtension
->NewCaps
;
404 DeviceExtension
->ReportedCaps
= DeviceExtension
->NewCaps
;
405 Irp
->IoStatus
.Information
= sizeof(ULONG
);
406 Status
= STATUS_SUCCESS
;
410 case IOCTL_GET_SYS_BUTTON_EVENT
:
412 /* Part of GUID_DEVICE_SYS_BUTTON interface */
414 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_EVENT\n");
416 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
417 Status
= STATUS_INVALID_PARAMETER
;
420 WaitingIrp
= InterlockedCompareExchangePointer(
421 (PVOID
)&DeviceExtension
->PowerIrp
,
424 /* Check if an Irp is already pending */
427 /* Unable to have a 2nd pending IRP for this IOCTL */
428 WARN_(I8042PRT
, "Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
429 Status
= STATUS_INVALID_PARAMETER
;
430 Irp
->IoStatus
.Status
= Status
;
431 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
436 PowerKey
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
439 (VOID
)InterlockedCompareExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
, Irp
);
440 *(PULONG
)Irp
->AssociatedIrp
.SystemBuffer
= PowerKey
;
441 Status
= STATUS_SUCCESS
;
442 Irp
->IoStatus
.Status
= Status
;
443 Irp
->IoStatus
.Information
= sizeof(ULONG
);
444 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
448 TRACE_(I8042PRT
, "Pending IOCTL_GET_SYS_BUTTON_EVENT\n");
449 Status
= STATUS_PENDING
;
450 Irp
->IoStatus
.Status
= Status
;
451 IoMarkIrpPending(Irp
);
460 ERR_(I8042PRT
, "IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
461 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
463 return ForwardIrpAndForget(DeviceObject
, Irp
);
467 Irp
->IoStatus
.Status
= Status
;
468 if (Status
== STATUS_PENDING
)
469 IoMarkIrpPending(Irp
);
471 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
478 i8042InitializeKeyboardAttributes(
479 PI8042_KEYBOARD_EXTENSION DeviceExtension
)
481 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
482 PI8042_SETTINGS Settings
;
483 PKEYBOARD_ATTRIBUTES KeyboardAttributes
;
485 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
486 Settings
= &PortDeviceExtension
->Settings
;
488 KeyboardAttributes
= &DeviceExtension
->KeyboardAttributes
;
490 KeyboardAttributes
->KeyboardIdentifier
.Type
= (UCHAR
)Settings
->OverrideKeyboardType
;
491 KeyboardAttributes
->KeyboardIdentifier
.Subtype
= (UCHAR
)Settings
->OverrideKeyboardSubtype
;
492 KeyboardAttributes
->NumberOfFunctionKeys
= 4;
493 KeyboardAttributes
->NumberOfIndicators
= 3;
494 KeyboardAttributes
->NumberOfKeysTotal
= 101;
495 KeyboardAttributes
->InputDataQueueLength
= Settings
->KeyboardDataQueueSize
;
496 KeyboardAttributes
->KeyRepeatMinimum
.UnitId
= 0;
497 KeyboardAttributes
->KeyRepeatMinimum
.Rate
= (USHORT
)Settings
->SampleRate
;
498 KeyboardAttributes
->KeyRepeatMinimum
.Delay
= 0;
499 KeyboardAttributes
->KeyRepeatMinimum
.UnitId
= 0;
500 KeyboardAttributes
->KeyRepeatMinimum
.Rate
= (USHORT
)Settings
->SampleRate
;
501 KeyboardAttributes
->KeyRepeatMinimum
.Delay
= 0;
505 * Runs the keyboard IOCTL_INTERNAL dispatch.
508 i8042KbdInternalDeviceControl(
509 IN PDEVICE_OBJECT DeviceObject
,
512 PIO_STACK_LOCATION Stack
;
513 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
516 Stack
= IoGetCurrentIrpStackLocation(Irp
);
517 Irp
->IoStatus
.Information
= 0;
518 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
520 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
522 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
525 PIO_WORKITEM WorkItem
= NULL
;
526 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
528 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
529 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
531 Status
= STATUS_INVALID_PARAMETER
;
535 DeviceExtension
->KeyboardData
=
536 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
538 /* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */
539 WorkItem
= IoAllocateWorkItem(DeviceObject
);
542 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
543 Status
= STATUS_INSUFFICIENT_RESOURCES
;
546 WorkItemData
= ExAllocatePoolWithTag(
548 sizeof(I8042_HOOK_WORKITEM
),
552 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
553 Status
= STATUS_NO_MEMORY
;
556 WorkItemData
->WorkItem
= WorkItem
;
557 WorkItemData
->Irp
= Irp
;
559 /* Initialize extension */
560 DeviceExtension
->Common
.Type
= Keyboard
;
561 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
);
562 DeviceExtension
->KeyboardBuffer
= ExAllocatePoolWithTag(
566 if (!DeviceExtension
->KeyboardBuffer
)
568 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
569 Status
= STATUS_NO_MEMORY
;
572 RtlZeroMemory(DeviceExtension
->KeyboardBuffer
, Size
);
574 &DeviceExtension
->DpcKeyboard
,
577 DeviceExtension
->PowerWorkItem
= IoAllocateWorkItem(DeviceObject
);
578 if (!DeviceExtension
->PowerWorkItem
)
580 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
581 Status
= STATUS_INSUFFICIENT_RESOURCES
;
584 DeviceExtension
->DebugWorkItem
= IoAllocateWorkItem(DeviceObject
);
585 if (!DeviceExtension
->DebugWorkItem
)
587 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
588 Status
= STATUS_INSUFFICIENT_RESOURCES
;
591 DeviceExtension
->Common
.PortDeviceExtension
->KeyboardExtension
= DeviceExtension
;
592 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= KEYBOARD_CONNECTED
;
594 i8042InitializeKeyboardAttributes(DeviceExtension
);
596 IoMarkIrpPending(Irp
);
597 /* FIXME: DeviceExtension->KeyboardHook.IsrWritePort = ; */
598 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket
= i8042KbdQueuePacket
;
599 DeviceExtension
->KeyboardHook
.CallContext
= DeviceExtension
;
600 IoQueueWorkItem(WorkItem
,
601 i8042SendHookWorkItem
,
604 Status
= STATUS_PENDING
;
608 if (DeviceExtension
->KeyboardBuffer
)
609 ExFreePoolWithTag(DeviceExtension
->KeyboardBuffer
, I8042PRT_TAG
);
610 if (DeviceExtension
->PowerWorkItem
)
611 IoFreeWorkItem(DeviceExtension
->PowerWorkItem
);
612 if (DeviceExtension
->DebugWorkItem
)
613 IoFreeWorkItem(DeviceExtension
->DebugWorkItem
);
615 IoFreeWorkItem(WorkItem
);
617 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
620 case IOCTL_INTERNAL_KEYBOARD_DISCONNECT
:
622 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n");
623 /* MSDN says that operation is to implemented.
624 * To implement it, we just have to do:
625 * DeviceExtension->KeyboardData.ClassService = NULL;
627 Status
= STATUS_NOT_IMPLEMENTED
;
630 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
:
632 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n");
633 /* Nothing to do here */
634 Status
= STATUS_SUCCESS
;
637 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
639 PKEYBOARD_ATTRIBUTES KeyboardAttributes
;
641 /* FIXME: KeyboardAttributes are not initialized anywhere */
642 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
643 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KEYBOARD_ATTRIBUTES
))
645 Status
= STATUS_BUFFER_TOO_SMALL
;
649 KeyboardAttributes
= Irp
->AssociatedIrp
.SystemBuffer
;
650 *KeyboardAttributes
= DeviceExtension
->KeyboardAttributes
;
652 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_ATTRIBUTES
);
653 Status
= STATUS_SUCCESS
;
656 Status
= STATUS_NOT_IMPLEMENTED
;
659 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
661 DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n");
662 Status
= STATUS_NOT_IMPLEMENTED
;
665 case IOCTL_KEYBOARD_SET_TYPEMATIC
:
667 DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n");
668 Status
= STATUS_NOT_IMPLEMENTED
;
671 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
673 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
675 /* We should check the UnitID, but it's kind of pointless as
676 * all keyboards are supposed to have the same one
678 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
))
680 Status
= STATUS_BUFFER_TOO_SMALL
;
685 Irp
->AssociatedIrp
.SystemBuffer
,
686 &IndicatorTranslation
,
687 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
));
688 Irp
->IoStatus
.Information
= sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
);
689 Status
= STATUS_SUCCESS
;
693 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
695 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
697 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
699 Status
= STATUS_BUFFER_TOO_SMALL
;
704 Irp
->AssociatedIrp
.SystemBuffer
,
705 &DeviceExtension
->KeyboardIndicators
,
706 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
707 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INDICATOR_PARAMETERS
);
708 Status
= STATUS_SUCCESS
;
712 case IOCTL_KEYBOARD_SET_INDICATORS
:
714 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n");
716 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
718 Status
= STATUS_BUFFER_TOO_SMALL
;
723 &DeviceExtension
->KeyboardIndicators
,
724 Irp
->AssociatedIrp
.SystemBuffer
,
725 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
726 Status
= STATUS_PENDING
;
727 IoMarkIrpPending(Irp
);
728 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
734 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
735 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
737 return ForwardIrpAndForget(DeviceObject
, Irp
);
741 Irp
->IoStatus
.Status
= Status
;
742 if (Status
!= STATUS_PENDING
)
743 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
748 * Call the customization hook. The ToReturn parameter is about wether
749 * we should go on with the interrupt. The return value is what
750 * we should return (indicating to the system wether someone else
751 * should try to handle the interrupt)
755 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
,
758 OUT PBOOLEAN ToReturn
)
760 BOOLEAN HookReturn
, HookContinue
;
762 HookContinue
= FALSE
;
764 if (DeviceExtension
->KeyboardHook
.IsrRoutine
)
766 HookReturn
= DeviceExtension
->KeyboardHook
.IsrRoutine(
767 DeviceExtension
->KeyboardHook
.Context
,
768 DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
,
769 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
773 &DeviceExtension
->KeyboardScanState
);
777 *ToReturn
= HookReturn
;
785 i8042KbdInterruptService(
786 IN PKINTERRUPT Interrupt
,
789 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
790 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
791 PKEYBOARD_INPUT_DATA InputData
;
793 UCHAR PortStatus
= 0, Output
= 0;
794 BOOLEAN ToReturn
= FALSE
;
797 UNREFERENCED_PARAMETER(Interrupt
);
799 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
800 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
801 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
;
802 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
806 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
807 if (!NT_SUCCESS(Status
))
809 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
812 Status
= i8042ReadKeyboardData(PortDeviceExtension
, &Output
);
813 if (NT_SUCCESS(Status
))
815 KeStallExecutionProcessor(1);
820 WARN_(I8042PRT
, "Spurious i8042 keyboard interrupt\n");
824 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
826 if (PortDeviceExtension
->Settings
.CrashOnCtrlScroll
)
828 /* Test for CTRL + SCROLL LOCK twice */
829 static const UCHAR ScanCodes
[] = { 0x1d, 0x46, 0xc6, 0x46, 0 };
831 if (Output
== ScanCodes
[DeviceExtension
->ComboPosition
])
833 DeviceExtension
->ComboPosition
++;
834 if (ScanCodes
[DeviceExtension
->ComboPosition
] == 0)
835 KeBugCheck(MANUALLY_INITIATED_CRASH
);
837 else if (Output
== 0xfa)
841 else if (Output
== ScanCodes
[0])
842 DeviceExtension
->ComboPosition
= 1;
844 DeviceExtension
->ComboPosition
= 0;
846 /* Test for TAB + key combination */
847 if (InputData
->MakeCode
== 0x0F)
848 DeviceExtension
->TabPressed
= !(InputData
->Flags
& KEY_BREAK
);
849 else if (DeviceExtension
->TabPressed
)
851 DeviceExtension
->TabPressed
= FALSE
;
853 /* Check which action to do */
854 if (InputData
->MakeCode
== 0x25)
859 else if (InputData
->MakeCode
== 0x30)
862 KeBugCheck(MANUALLY_INITIATED_CRASH
);
866 /* Send request to the kernel debugger.
867 * Unknown requests will be ignored. */
868 KdSystemDebugControl(' soR',
869 (PVOID
)(ULONG_PTR
)InputData
->MakeCode
,
879 if (i8042KbdCallIsrHook(DeviceExtension
, PortStatus
, Output
, &ToReturn
))
882 if (i8042PacketIsr(PortDeviceExtension
, Output
))
884 if (PortDeviceExtension
->PacketComplete
)
886 TRACE_(I8042PRT
, "Packet complete\n");
887 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
889 TRACE_(I8042PRT
, "Irq eaten by packet\n");
893 TRACE_(I8042PRT
, "Irq is keyboard input\n");
895 if (DeviceExtension
->KeyboardScanState
== Normal
)
900 DeviceExtension
->KeyboardScanState
= GotE0
;
903 DeviceExtension
->KeyboardScanState
= GotE1
;
910 /* Update InputData */
911 InputData
->Flags
= 0;
912 switch (DeviceExtension
->KeyboardScanState
)
915 InputData
->Flags
|= KEY_E0
;
918 InputData
->Flags
|= KEY_E1
;
923 DeviceExtension
->KeyboardScanState
= Normal
;
925 InputData
->Flags
|= KEY_BREAK
;
927 InputData
->Flags
|= KEY_MAKE
;
928 InputData
->MakeCode
= Output
& 0x7f;
929 InputData
->Reserved
= 0;
931 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket(DeviceExtension
->KeyboardHook
.CallContext
);