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
;
24 static KDEFERRED_ROUTINE i8042KbdDpcRoutine
;
26 /* This structure starts with the same layout as KEYBOARD_INDICATOR_TRANSLATION */
27 typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION
{
28 USHORT NumberOfIndicatorKeys
;
29 INDICATOR_LIST IndicatorList
[3];
30 } LOCAL_KEYBOARD_INDICATOR_TRANSLATION
, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION
;
32 static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation
= { 3, {
33 {0x3A, KEYBOARD_CAPS_LOCK_ON
},
34 {0x45, KEYBOARD_NUM_LOCK_ON
},
35 {0x46, KEYBOARD_SCROLL_LOCK_ON
}}};
37 /* FUNCTIONS *****************************************************************/
40 * These functions are callbacks for filter driver custom interrupt
48 PI8042_KEYBOARD_EXTENSION DeviceExtension;
50 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
52 if (DeviceExtension->KeyboardHook.IsrWritePort)
54 DeviceExtension->KeyboardHook.IsrWritePort(
55 DeviceExtension->KeyboardHook.CallContext,
59 i8042IsrWritePort(Context, Value, 0);
66 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
68 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)Context
;
70 DeviceExtension
->KeyComplete
= TRUE
;
71 DeviceExtension
->KeysInBuffer
++;
72 if (DeviceExtension
->KeysInBuffer
> DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
)
74 WARN_(I8042PRT
, "Keyboard buffer overflow\n");
75 DeviceExtension
->KeysInBuffer
--;
78 TRACE_(I8042PRT
, "Irq completes key\n");
79 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
83 * These functions are callbacks for filter driver custom
84 * initialization routines.
87 i8042SynchWritePortKbd(
90 IN BOOLEAN WaitForAck
)
92 return i8042SynchWritePort(
93 (PPORT_DEVICE_EXTENSION
)Context
,
100 * Process the keyboard internal device requests
104 IN PDEVICE_OBJECT DeviceObject
,
107 PIO_STACK_LOCATION Stack
;
108 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
109 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
111 Stack
= IoGetCurrentIrpStackLocation(Irp
);
112 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
113 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
115 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
117 case IOCTL_KEYBOARD_SET_INDICATORS
:
119 TRACE_(I8042PRT
, "IOCTL_KEYBOARD_SET_INDICATORS\n");
120 INFO_(I8042PRT
, "Leds: {%s%s%s }\n",
121 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
? " CAPSLOCK" : "",
122 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
? " NUMLOCK" : "",
123 DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
? " SCROLLLOCK" : "");
125 PortDeviceExtension
->PacketBuffer
[0] = KBD_CMD_SET_LEDS
;
126 PortDeviceExtension
->PacketBuffer
[1] = 0;
127 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_CAPS_LOCK_ON
)
128 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_CAPS
;
130 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_NUM_LOCK_ON
)
131 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_NUM
;
133 if (DeviceExtension
->KeyboardIndicators
.LedFlags
& KEYBOARD_SCROLL_LOCK_ON
)
134 PortDeviceExtension
->PacketBuffer
[1] |= KBD_LED_SCROLL
;
138 &DeviceExtension
->Common
,
139 PortDeviceExtension
->PacketBuffer
,
146 ERR_(I8042PRT
, "Unknown ioctl code 0x%lx\n",
147 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
155 IN PPORT_DEVICE_EXTENSION DeviceExtension
)
157 BOOLEAN FinishIrp
= FALSE
;
159 NTSTATUS Result
= STATUS_INTERNAL_ERROR
; /* Shouldn't happen */
161 /* If the interrupt happens before this is setup, the key
162 * was already in the buffer. Too bad! */
163 if (!DeviceExtension
->HighestDIRQLInterrupt
)
166 Irql
= KeAcquireInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
);
168 if (DeviceExtension
->Packet
.State
== Idle
169 && DeviceExtension
->PacketComplete
)
172 Result
= DeviceExtension
->PacketResult
;
173 DeviceExtension
->PacketComplete
= FALSE
;
176 KeReleaseInterruptSpinLock(DeviceExtension
->HighestDIRQLInterrupt
, Irql
);
181 if (DeviceExtension
->CurrentIrp
)
183 DeviceExtension
->CurrentIrp
->IoStatus
.Status
= Result
;
184 IoCompleteRequest(DeviceExtension
->CurrentIrp
, IO_NO_INCREMENT
);
185 IoStartNextPacket(DeviceExtension
->CurrentIrpDevice
, FALSE
);
186 DeviceExtension
->CurrentIrp
= NULL
;
187 DeviceExtension
->CurrentIrpDevice
= NULL
;
193 IN PDEVICE_OBJECT DeviceObject
,
196 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
200 UNREFERENCED_PARAMETER(DeviceObject
);
202 __analysis_assume(Context
!= NULL
);
203 DeviceExtension
= Context
;
205 /* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */
207 /* Register GUID_DEVICE_SYS_BUTTON interface and report capability */
208 if (DeviceExtension
->NewCaps
!= DeviceExtension
->ReportedCaps
)
210 WaitingIrp
= InterlockedExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
);
213 /* Cancel the current power irp, as capability changed */
214 WaitingIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
215 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
216 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
219 if (DeviceExtension
->PowerInterfaceName
.MaximumLength
== 0)
221 /* We have never registered this interface ; do it */
222 Status
= IoRegisterDeviceInterface(
223 DeviceExtension
->Common
.Pdo
,
224 &GUID_DEVICE_SYS_BUTTON
,
226 &DeviceExtension
->PowerInterfaceName
);
227 if (!NT_SUCCESS(Status
))
229 /* We can't do more yet, ignore the keypress... */
230 WARN_(I8042PRT
, "IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n",
232 DeviceExtension
->PowerInterfaceName
.MaximumLength
= 0;
238 /* Disable the interface. Once activated again, capabilities would be asked again */
239 Status
= IoSetDeviceInterfaceState(
240 &DeviceExtension
->PowerInterfaceName
,
242 if (!NT_SUCCESS(Status
))
244 /* Ignore the key press... */
245 WARN_(I8042PRT
, "Disabling interface %wZ failed with status 0x%08lx\n",
246 &DeviceExtension
->PowerInterfaceName
, Status
);
250 /* Enable the interface. This leads to receiving a IOCTL_GET_SYS_BUTTON_CAPS,
251 * so we can report new capability */
252 Status
= IoSetDeviceInterfaceState(
253 &DeviceExtension
->PowerInterfaceName
,
255 if (!NT_SUCCESS(Status
))
257 /* Ignore the key press... */
258 WARN_(I8042PRT
, "Enabling interface %wZ failed with status 0x%08lx\n",
259 &DeviceExtension
->PowerInterfaceName
, Status
);
264 /* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
265 WaitingIrp
= InterlockedExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
);
268 PULONG pEvent
= (PULONG
)WaitingIrp
->AssociatedIrp
.SystemBuffer
;
270 WaitingIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
271 WaitingIrp
->IoStatus
.Information
= sizeof(ULONG
);
272 *pEvent
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
273 IoCompleteRequest(WaitingIrp
, IO_NO_INCREMENT
);
277 /* Return TRUE if it was a power key */
280 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
)
282 PKEYBOARD_INPUT_DATA InputData
;
285 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
- 1;
286 if (!(InputData
->Flags
& KEY_E0
))
289 switch (InputData
->MakeCode
)
291 case KEYBOARD_POWER_CODE
:
292 KeyPress
= SYS_BUTTON_POWER
;
294 case KEYBOARD_SLEEP_CODE
:
295 KeyPress
= SYS_BUTTON_SLEEP
;
297 case KEYBOARD_WAKE_CODE
:
298 KeyPress
= SYS_BUTTON_WAKE
;
304 if (InputData
->Flags
& KEY_BREAK
)
305 /* We already took care of the key press */
308 /* Our work can only be done at passive level, so use a workitem */
309 DeviceExtension
->NewCaps
|= KeyPress
;
310 InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, KeyPress
);
312 DeviceExtension
->PowerWorkItem
,
322 IN PVOID DeferredContext
,
323 IN PVOID SystemArgument1
,
324 IN PVOID SystemArgument2
)
326 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
327 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
328 ULONG KeysTransferred
= 0;
329 ULONG KeysInBufferCopy
;
332 UNREFERENCED_PARAMETER(Dpc
);
333 UNREFERENCED_PARAMETER(SystemArgument1
);
334 UNREFERENCED_PARAMETER(SystemArgument2
);
336 __analysis_assume(DeferredContext
!= NULL
);
337 DeviceExtension
= DeferredContext
;
338 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
340 if (HandlePowerKeys(DeviceExtension
))
342 DeviceExtension
->KeyComplete
= FALSE
;
346 i8042PacketDpc(PortDeviceExtension
);
347 if (!DeviceExtension
->KeyComplete
)
349 /* We got the interrupt as it was being enabled, too bad */
350 if (!PortDeviceExtension
->HighestDIRQLInterrupt
)
353 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
355 DeviceExtension
->KeyComplete
= FALSE
;
356 KeysInBufferCopy
= DeviceExtension
->KeysInBuffer
;
358 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
360 TRACE_(I8042PRT
, "Send a key\n");
362 if (!DeviceExtension
->KeyboardData
.ClassService
)
365 INFO_(I8042PRT
, "Sending %lu key(s)\n", KeysInBufferCopy
);
366 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->KeyboardData
.ClassService
)(
367 DeviceExtension
->KeyboardData
.ClassDeviceObject
,
368 DeviceExtension
->KeyboardBuffer
,
369 DeviceExtension
->KeyboardBuffer
+ KeysInBufferCopy
,
372 /* Validate that the callback didn't change the Irql. */
373 ASSERT(KeGetCurrentIrql() == Irql
);
375 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
376 DeviceExtension
->KeysInBuffer
-= KeysTransferred
;
377 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
381 * Runs the keyboard IOCTL dispatch.
384 i8042KbdDeviceControl(
385 IN PDEVICE_OBJECT DeviceObject
,
388 PIO_STACK_LOCATION Stack
;
389 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
392 Stack
= IoGetCurrentIrpStackLocation(Irp
);
393 Irp
->IoStatus
.Information
= 0;
394 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
396 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
398 case IOCTL_GET_SYS_BUTTON_CAPS
:
400 /* Part of GUID_DEVICE_SYS_BUTTON interface */
402 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_CAPS\n");
404 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
405 Status
= STATUS_INVALID_PARAMETER
;
408 pCaps
= (PULONG
)Irp
->AssociatedIrp
.SystemBuffer
;
409 *pCaps
= DeviceExtension
->NewCaps
;
410 DeviceExtension
->ReportedCaps
= DeviceExtension
->NewCaps
;
411 Irp
->IoStatus
.Information
= sizeof(ULONG
);
412 Status
= STATUS_SUCCESS
;
416 case IOCTL_GET_SYS_BUTTON_EVENT
:
418 /* Part of GUID_DEVICE_SYS_BUTTON interface */
420 TRACE_(I8042PRT
, "IOCTL_GET_SYS_BUTTON_EVENT\n");
422 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= sizeof(ULONG
))
423 Status
= STATUS_INVALID_PARAMETER
;
426 WaitingIrp
= InterlockedCompareExchangePointer(
427 (PVOID
)&DeviceExtension
->PowerIrp
,
430 /* Check if an Irp is already pending */
433 /* Unable to have a 2nd pending IRP for this IOCTL */
434 WARN_(I8042PRT
, "Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
435 Status
= STATUS_INVALID_PARAMETER
;
436 Irp
->IoStatus
.Status
= Status
;
437 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
442 PowerKey
= InterlockedExchange((PLONG
)&DeviceExtension
->LastPowerKey
, 0);
445 (VOID
)InterlockedCompareExchangePointer((PVOID
)&DeviceExtension
->PowerIrp
, NULL
, Irp
);
446 *(PULONG
)Irp
->AssociatedIrp
.SystemBuffer
= PowerKey
;
447 Status
= STATUS_SUCCESS
;
448 Irp
->IoStatus
.Status
= Status
;
449 Irp
->IoStatus
.Information
= sizeof(ULONG
);
450 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
454 TRACE_(I8042PRT
, "Pending IOCTL_GET_SYS_BUTTON_EVENT\n");
455 Status
= STATUS_PENDING
;
456 Irp
->IoStatus
.Status
= Status
;
457 IoMarkIrpPending(Irp
);
466 ERR_(I8042PRT
, "IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
467 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
469 return ForwardIrpAndForget(DeviceObject
, Irp
);
473 if (Status
!= STATUS_PENDING
)
475 Irp
->IoStatus
.Status
= Status
;
476 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
484 i8042InitializeKeyboardAttributes(
485 PI8042_KEYBOARD_EXTENSION DeviceExtension
)
487 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
488 PI8042_SETTINGS Settings
;
489 PKEYBOARD_ATTRIBUTES KeyboardAttributes
;
491 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
492 Settings
= &PortDeviceExtension
->Settings
;
494 KeyboardAttributes
= &DeviceExtension
->KeyboardAttributes
;
496 KeyboardAttributes
->KeyboardIdentifier
.Type
= (UCHAR
)Settings
->OverrideKeyboardType
;
497 KeyboardAttributes
->KeyboardIdentifier
.Subtype
= (UCHAR
)Settings
->OverrideKeyboardSubtype
;
498 KeyboardAttributes
->NumberOfFunctionKeys
= 4;
499 KeyboardAttributes
->NumberOfIndicators
= 3;
500 KeyboardAttributes
->NumberOfKeysTotal
= 101;
501 KeyboardAttributes
->InputDataQueueLength
= Settings
->KeyboardDataQueueSize
;
502 KeyboardAttributes
->KeyRepeatMinimum
.UnitId
= 0;
503 KeyboardAttributes
->KeyRepeatMinimum
.Rate
= (USHORT
)Settings
->SampleRate
;
504 KeyboardAttributes
->KeyRepeatMinimum
.Delay
= 0;
505 KeyboardAttributes
->KeyRepeatMinimum
.UnitId
= 0;
506 KeyboardAttributes
->KeyRepeatMinimum
.Rate
= (USHORT
)Settings
->SampleRate
;
507 KeyboardAttributes
->KeyRepeatMinimum
.Delay
= 0;
511 * Runs the keyboard IOCTL_INTERNAL dispatch.
514 i8042KbdInternalDeviceControl(
515 IN PDEVICE_OBJECT DeviceObject
,
518 PIO_STACK_LOCATION Stack
;
519 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
522 Stack
= IoGetCurrentIrpStackLocation(Irp
);
523 Irp
->IoStatus
.Information
= 0;
524 DeviceExtension
= (PI8042_KEYBOARD_EXTENSION
)DeviceObject
->DeviceExtension
;
526 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
528 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
531 PIO_WORKITEM WorkItem
= NULL
;
532 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
534 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
535 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
537 Status
= STATUS_INVALID_PARAMETER
;
541 DeviceExtension
->KeyboardData
=
542 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
544 /* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */
545 WorkItem
= IoAllocateWorkItem(DeviceObject
);
548 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
549 Status
= STATUS_INSUFFICIENT_RESOURCES
;
552 WorkItemData
= ExAllocatePoolWithTag(
554 sizeof(I8042_HOOK_WORKITEM
),
558 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
559 Status
= STATUS_NO_MEMORY
;
562 WorkItemData
->WorkItem
= WorkItem
;
563 WorkItemData
->Irp
= Irp
;
565 /* Initialize extension */
566 DeviceExtension
->Common
.Type
= Keyboard
;
567 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.KeyboardDataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
);
568 DeviceExtension
->KeyboardBuffer
= ExAllocatePoolWithTag(
572 if (!DeviceExtension
->KeyboardBuffer
)
574 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
575 Status
= STATUS_NO_MEMORY
;
578 RtlZeroMemory(DeviceExtension
->KeyboardBuffer
, Size
);
580 &DeviceExtension
->DpcKeyboard
,
583 DeviceExtension
->PowerWorkItem
= IoAllocateWorkItem(DeviceObject
);
584 if (!DeviceExtension
->PowerWorkItem
)
586 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
587 Status
= STATUS_INSUFFICIENT_RESOURCES
;
590 DeviceExtension
->DebugWorkItem
= IoAllocateWorkItem(DeviceObject
);
591 if (!DeviceExtension
->DebugWorkItem
)
593 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
594 Status
= STATUS_INSUFFICIENT_RESOURCES
;
597 DeviceExtension
->Common
.PortDeviceExtension
->KeyboardExtension
= DeviceExtension
;
598 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= KEYBOARD_CONNECTED
;
600 i8042InitializeKeyboardAttributes(DeviceExtension
);
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 PKEYBOARD_ATTRIBUTES KeyboardAttributes
;
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 KeyboardAttributes
= Irp
->AssociatedIrp
.SystemBuffer
;
656 *KeyboardAttributes
= DeviceExtension
->KeyboardAttributes
;
658 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_ATTRIBUTES
);
659 Status
= STATUS_SUCCESS
;
662 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
664 DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n");
665 Status
= STATUS_NOT_IMPLEMENTED
;
668 case IOCTL_KEYBOARD_SET_TYPEMATIC
:
670 DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n");
671 Status
= STATUS_NOT_IMPLEMENTED
;
674 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
676 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
678 /* We should check the UnitID, but it's kind of pointless as
679 * all keyboards are supposed to have the same one
681 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
))
683 Status
= STATUS_BUFFER_TOO_SMALL
;
688 Irp
->AssociatedIrp
.SystemBuffer
,
689 &IndicatorTranslation
,
690 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
));
691 Irp
->IoStatus
.Information
= sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
);
692 Status
= STATUS_SUCCESS
;
696 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
698 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
700 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
702 Status
= STATUS_BUFFER_TOO_SMALL
;
707 Irp
->AssociatedIrp
.SystemBuffer
,
708 &DeviceExtension
->KeyboardIndicators
,
709 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
710 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INDICATOR_PARAMETERS
);
711 Status
= STATUS_SUCCESS
;
715 case IOCTL_KEYBOARD_SET_INDICATORS
:
717 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n");
719 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KEYBOARD_INDICATOR_PARAMETERS
))
721 Status
= STATUS_BUFFER_TOO_SMALL
;
726 &DeviceExtension
->KeyboardIndicators
,
727 Irp
->AssociatedIrp
.SystemBuffer
,
728 sizeof(KEYBOARD_INDICATOR_PARAMETERS
));
729 Status
= STATUS_PENDING
;
730 IoMarkIrpPending(Irp
);
731 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
737 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
738 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
740 return ForwardIrpAndForget(DeviceObject
, Irp
);
744 if (Status
!= STATUS_PENDING
)
746 Irp
->IoStatus
.Status
= Status
;
747 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
753 * Call the customization hook. The ToReturn parameter is about whether
754 * we should go on with the interrupt. The return value is what
755 * we should return (indicating to the system whether someone else
756 * should try to handle the interrupt)
760 IN PI8042_KEYBOARD_EXTENSION DeviceExtension
,
763 OUT PBOOLEAN ToReturn
)
765 BOOLEAN HookReturn
, HookContinue
;
767 HookContinue
= FALSE
;
769 if (DeviceExtension
->KeyboardHook
.IsrRoutine
)
771 HookReturn
= DeviceExtension
->KeyboardHook
.IsrRoutine(
772 DeviceExtension
->KeyboardHook
.Context
,
773 DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
,
774 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
778 &DeviceExtension
->KeyboardScanState
);
782 *ToReturn
= HookReturn
;
790 i8042KbdInterruptService(
791 IN PKINTERRUPT Interrupt
,
794 PI8042_KEYBOARD_EXTENSION DeviceExtension
;
795 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
796 PKEYBOARD_INPUT_DATA InputData
;
798 UCHAR PortStatus
= 0, Output
= 0;
799 BOOLEAN ToReturn
= FALSE
;
802 UNREFERENCED_PARAMETER(Interrupt
);
804 __analysis_assume(Context
!= NULL
);
805 DeviceExtension
= Context
;
806 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
807 InputData
= DeviceExtension
->KeyboardBuffer
+ DeviceExtension
->KeysInBuffer
;
808 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
812 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
813 if (!NT_SUCCESS(Status
))
815 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
818 Status
= i8042ReadKeyboardData(PortDeviceExtension
, &Output
);
819 if (NT_SUCCESS(Status
))
821 KeStallExecutionProcessor(1);
826 WARN_(I8042PRT
, "Spurious i8042 keyboard interrupt\n");
830 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
832 if (PortDeviceExtension
->Settings
.CrashOnCtrlScroll
)
834 /* Test for CTRL + SCROLL LOCK twice */
835 static const UCHAR ScanCodes
[] = { 0x1d, 0x46, 0xc6, 0x46, 0 };
837 if (Output
== ScanCodes
[DeviceExtension
->ComboPosition
])
839 DeviceExtension
->ComboPosition
++;
840 if (ScanCodes
[DeviceExtension
->ComboPosition
] == 0)
841 KeBugCheck(MANUALLY_INITIATED_CRASH
);
843 else if (Output
== 0xfa)
847 else if (Output
== ScanCodes
[0])
848 DeviceExtension
->ComboPosition
= 1;
850 DeviceExtension
->ComboPosition
= 0;
852 /* Test for TAB + key combination */
853 if (InputData
->MakeCode
== 0x0F)
854 DeviceExtension
->TabPressed
= !(InputData
->Flags
& KEY_BREAK
);
855 else if (DeviceExtension
->TabPressed
)
857 DeviceExtension
->TabPressed
= FALSE
;
859 /* Check which action to do */
860 if (InputData
->MakeCode
== 0x25)
863 DbgBreakPointWithStatus(DBG_STATUS_SYSRQ
);
865 else if (InputData
->MakeCode
== 0x30)
868 KeBugCheck(MANUALLY_INITIATED_CRASH
);
873 /* Send request to the kernel debugger.
874 * Unknown requests will be ignored. */
875 KdSystemDebugControl(' soR',
876 (PVOID
)(ULONG_PTR
)InputData
->MakeCode
,
887 if (i8042KbdCallIsrHook(DeviceExtension
, PortStatus
, Output
, &ToReturn
))
890 if (i8042PacketIsr(PortDeviceExtension
, Output
))
892 if (PortDeviceExtension
->PacketComplete
)
894 TRACE_(I8042PRT
, "Packet complete\n");
895 KeInsertQueueDpc(&DeviceExtension
->DpcKeyboard
, NULL
, NULL
);
897 TRACE_(I8042PRT
, "Irq eaten by packet\n");
901 TRACE_(I8042PRT
, "Irq is keyboard input\n");
903 if (DeviceExtension
->KeyboardScanState
== Normal
)
908 DeviceExtension
->KeyboardScanState
= GotE0
;
911 DeviceExtension
->KeyboardScanState
= GotE1
;
918 /* Update InputData */
919 InputData
->Flags
= 0;
920 switch (DeviceExtension
->KeyboardScanState
)
923 InputData
->Flags
|= KEY_E0
;
926 InputData
->Flags
|= KEY_E1
;
931 DeviceExtension
->KeyboardScanState
= Normal
;
933 InputData
->Flags
|= KEY_BREAK
;
935 InputData
->Flags
|= KEY_MAKE
;
936 InputData
->MakeCode
= Output
& 0x7f;
937 InputData
->Reserved
= 0;
939 DeviceExtension
->KeyboardHook
.QueueKeyboardPacket(DeviceExtension
->KeyboardHook
.CallContext
);