2 * PROJECT: ReactOS HID Stack
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/hid/kbdhid/kbdhid.c
5 * PURPOSE: Keyboard HID Driver
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
14 KbdHid_DispatchInputData(
15 IN PKBDHID_DEVICE_EXTENSION DeviceExtension
,
16 IN PKEYBOARD_INPUT_DATA InputData
,
17 IN ULONG InputDataLength
)
20 ULONG InputDataConsumed
;
22 if (!DeviceExtension
->ClassService
)
26 ASSERT(DeviceExtension
->ClassService
);
27 ASSERT(DeviceExtension
->ClassDeviceObject
);
30 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
32 /* dispatch input data */
33 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ClassService
)(DeviceExtension
->ClassDeviceObject
, InputData
, InputData
+ InputDataLength
+ 1, &InputDataConsumed
);
35 /* lower irql to previous level */
41 KbdHid_ReadCompletion(
42 IN PDEVICE_OBJECT DeviceObject
,
46 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
48 /* get device extension */
49 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)Context
;
51 if (Irp
->IoStatus
.Status
== STATUS_PRIVILEGE_NOT_HELD
||
52 Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_CONNECTED
||
53 Irp
->IoStatus
.Status
== STATUS_CANCELLED
||
54 DeviceExtension
->StopReadReport
)
56 /* failed to read or should be stopped*/
57 DPRINT1("[KBDHID] ReadCompletion terminating read Status %x\n", Irp
->IoStatus
.Status
);
59 /* report no longer active */
60 DeviceExtension
->ReadReportActive
= FALSE
;
62 /* request stopping of the report cycle */
63 DeviceExtension
->StopReadReport
= FALSE
;
65 /* signal completion event */
66 KeSetEvent(&DeviceExtension
->ReadCompletionEvent
, 0, 0);
67 return STATUS_MORE_PROCESSING_REQUIRED
;
73 /* dispatch mouse action */
74 //KbdHid_DispatchInputData(DeviceExtension, &InputData);
77 KbdHid_InitiateRead(DeviceExtension
);
80 return STATUS_MORE_PROCESSING_REQUIRED
;
85 IN PKBDHID_DEVICE_EXTENSION DeviceExtension
)
87 PIO_STACK_LOCATION IoStack
;
91 IoReuseIrp(DeviceExtension
->Irp
, STATUS_SUCCESS
);
94 DeviceExtension
->Irp
->MdlAddress
= DeviceExtension
->ReportMDL
;
96 /* get next stack location */
97 IoStack
= IoGetNextIrpStackLocation(DeviceExtension
->Irp
);
99 /* init stack location */
100 IoStack
->Parameters
.Read
.Length
= DeviceExtension
->ReportLength
;
101 IoStack
->Parameters
.Read
.Key
= 0;
102 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= 0LL;
103 IoStack
->MajorFunction
= IRP_MJ_READ
;
104 IoStack
->FileObject
= DeviceExtension
->FileObject
;
106 /* set completion routine */
107 IoSetCompletionRoutine(DeviceExtension
->Irp
, KbdHid_ReadCompletion
, DeviceExtension
, TRUE
, TRUE
, TRUE
);
110 DeviceExtension
->ReadReportActive
= TRUE
;
113 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, DeviceExtension
->Irp
);
121 KbdHid_CreateCompletion(
122 IN PDEVICE_OBJECT DeviceObject
,
126 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
127 return STATUS_MORE_PROCESSING_REQUIRED
;
134 IN PDEVICE_OBJECT DeviceObject
,
137 PIO_STACK_LOCATION IoStack
;
140 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
142 DPRINT1("[KBDHID]: IRP_MJ_CREATE\n");
144 /* get device extension */
145 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
147 /* get stack location */
148 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
150 /* copy stack location to next */
151 IoCopyCurrentIrpStackLocationToNext(Irp
);
154 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
157 IoSetCompletionRoutine(Irp
, KbdHid_CreateCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
159 /* call lower driver */
160 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
161 if (Status
== STATUS_PENDING
)
163 /* request pending */
164 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
167 /* check for success */
168 if (!NT_SUCCESS(Status
))
171 Irp
->IoStatus
.Status
= Status
;
172 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
176 /* is the driver already in use */
177 if (DeviceExtension
->FileObject
== NULL
)
179 /* did the caller specify correct attributes */
180 ASSERT(IoStack
->Parameters
.Create
.SecurityContext
);
181 if (IoStack
->Parameters
.Create
.SecurityContext
->DesiredAccess
)
183 /* store file object */
184 DeviceExtension
->FileObject
= IoStack
->FileObject
;
187 KeResetEvent(&DeviceExtension
->ReadCompletionEvent
);
189 /* initiating read */
190 Status
= KbdHid_InitiateRead(DeviceExtension
);
191 DPRINT1("[KBDHID] KbdHid_InitiateRead: status %x\n", Status
);
192 if (Status
== STATUS_PENDING
)
194 /* report irp is pending */
195 Status
= STATUS_SUCCESS
;
200 /* complete request */
201 Irp
->IoStatus
.Status
= Status
;
202 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
210 IN PDEVICE_OBJECT DeviceObject
,
213 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
215 /* get device extension */
216 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
218 DPRINT("[KBDHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
220 if (DeviceExtension
->ReadReportActive
)
222 /* request stopping of the report cycle */
223 DeviceExtension
->StopReadReport
= TRUE
;
225 /* wait until the reports have been read */
226 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
229 IoCancelIrp(DeviceExtension
->Irp
);
232 DPRINT("[KBDHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
234 /* remove file object */
235 DeviceExtension
->FileObject
= NULL
;
238 IoSkipCurrentIrpStackLocation(Irp
);
240 /* pass irp to down the stack */
241 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
246 KbdHid_InternalDeviceControl(
247 IN PDEVICE_OBJECT DeviceObject
,
250 PIO_STACK_LOCATION IoStack
;
251 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
253 /* get current stack location */
254 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
256 DPRINT1("[KBDHID] InternalDeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
258 /* get device extension */
259 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
261 DPRINT1("[KBDHID] Unknown DeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
264 /* unknown request not supported */
265 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
266 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
267 return STATUS_NOT_SUPPORTED
;
272 KbdHid_DeviceControl(
273 IN PDEVICE_OBJECT DeviceObject
,
276 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
278 /* get device extension */
279 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
281 /* skip stack location */
282 IoSkipCurrentIrpStackLocation(Irp
);
284 /* pass and forget */
285 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
291 IN PDEVICE_OBJECT DeviceObject
,
295 return STATUS_NOT_IMPLEMENTED
;
299 KbdHid_SubmitRequest(
300 PDEVICE_OBJECT DeviceObject
,
302 ULONG InputBufferSize
,
304 ULONG OutputBufferSize
,
308 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
311 IO_STATUS_BLOCK IoStatus
;
313 /* get device extension */
314 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
317 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
320 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
, DeviceExtension
->NextDeviceObject
, InputBuffer
, InputBufferSize
, OutputBuffer
, OutputBufferSize
, FALSE
, &Event
, &IoStatus
);
324 return STATUS_INSUFFICIENT_RESOURCES
;
328 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
329 if (Status
== STATUS_PENDING
)
331 /* wait for request to complete */
332 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
333 Status
= IoStatus
.Status
;
343 IN PDEVICE_OBJECT DeviceObject
)
347 HID_COLLECTION_INFORMATION Information
;
348 PHIDP_PREPARSED_DATA PreparsedData
;
349 HIDP_CAPS Capabilities
;
350 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
351 PUSAGE_AND_PAGE Buffer
;
353 /* get device extension */
354 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
356 /* query collection information */
357 Status
= KbdHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_INFORMATION
, 0, NULL
, sizeof(HID_COLLECTION_INFORMATION
), &Information
);
358 if (!NT_SUCCESS(Status
))
360 /* failed to query collection information */
361 DPRINT1("[KBDHID] failed to obtain collection information with %x\n", Status
);
365 /* lets allocate space for preparsed data */
366 PreparsedData
= (PHIDP_PREPARSED_DATA
)ExAllocatePool(NonPagedPool
, Information
.DescriptorSize
);
370 DPRINT1("[KBDHID] no memory size %u\n", Information
.DescriptorSize
);
371 return STATUS_INSUFFICIENT_RESOURCES
;
374 /* now obtain the preparsed data */
375 Status
= KbdHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_DESCRIPTOR
, 0, NULL
, Information
.DescriptorSize
, PreparsedData
);
376 if (!NT_SUCCESS(Status
))
378 /* failed to get preparsed data */
379 DPRINT1("[KBDHID] failed to obtain collection information with %x\n", Status
);
380 ExFreePool(PreparsedData
);
384 /* lets get the caps */
385 Status
= HidP_GetCaps(PreparsedData
, &Capabilities
);
386 if (Status
!= HIDP_STATUS_SUCCESS
)
388 /* failed to get capabilities */
389 DPRINT1("[KBDHID] failed to obtain caps with %x\n", Status
);
390 ExFreePool(PreparsedData
);
394 DPRINT1("[KBDHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities
.Usage
, Capabilities
.UsagePage
, Capabilities
.InputReportByteLength
);
396 /* init input report*/
397 DeviceExtension
->ReportLength
= Capabilities
.InputReportByteLength
;
398 ASSERT(DeviceExtension
->ReportLength
);
399 DeviceExtension
->Report
= (PUCHAR
)ExAllocatePool(NonPagedPool
, DeviceExtension
->ReportLength
);
400 ASSERT(DeviceExtension
->Report
);
401 RtlZeroMemory(DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
404 DeviceExtension
->ReportMDL
= IoAllocateMdl(DeviceExtension
->Report
, DeviceExtension
->ReportLength
, FALSE
, FALSE
, NULL
);
405 ASSERT(DeviceExtension
->ReportMDL
);
408 MmBuildMdlForNonPagedPool(DeviceExtension
->ReportMDL
);
410 /* get max number of buttons */
411 Buttons
= HidP_MaxUsageListLength(HidP_Input
, HID_USAGE_PAGE_BUTTON
, PreparsedData
);
412 DPRINT1("[KBDHID] Buttons %lu\n", Buttons
);
415 /* now allocate an array for those buttons */
416 Buffer
= (PUSAGE_AND_PAGE
)ExAllocatePool(NonPagedPool
, sizeof(USAGE_AND_PAGE
) * 4 * Buttons
);
420 ExFreePool(PreparsedData
);
421 return STATUS_INSUFFICIENT_RESOURCES
;
424 /* init usage lists */
425 RtlZeroMemory(Buffer
, sizeof(USAGE_AND_PAGE
) * 4 * Buttons
);
426 DeviceExtension
->CurrentUsageList
= Buffer
;
428 DeviceExtension
->PreviousUsageList
= Buffer
;
430 DeviceExtension
->MakeUsageList
= Buffer
;
432 DeviceExtension
->BreakUsageList
= Buffer
;
435 // FIMXE: implement device hacks
438 // KeyboardTypeOverride
439 // KeyboardSubTypeOverride
440 // KeyboardNumberTotalKeysOverride
441 // KeyboardNumberFunctionKeysOverride
442 // KeyboardNumberIndicatorsOverride
444 /* store number of buttons */
445 DeviceExtension
->UsageListLength
= (USHORT
)Buttons
;
447 /* store preparsed data */
448 DeviceExtension
->PreparsedData
= PreparsedData
;
450 /* completed successfully */
451 return STATUS_SUCCESS
;
456 KbdHid_StartDeviceCompletion(
457 IN PDEVICE_OBJECT DeviceObject
,
461 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
462 return STATUS_MORE_PROCESSING_REQUIRED
;
468 IN PDEVICE_OBJECT DeviceObject
,
471 PIO_STACK_LOCATION IoStack
;
472 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
474 /* get device extension */
475 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
477 /* skip current stack location */
478 IoSkipCurrentIrpStackLocation(Irp
);
480 /* get next stack location */
481 IoStack
= IoGetNextIrpStackLocation(Irp
);
483 /* change request to hid flush queue request */
484 IoStack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
485 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_FLUSH_QUEUE
;
488 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
494 IN PDEVICE_OBJECT DeviceObject
,
497 PIO_STACK_LOCATION IoStack
;
500 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
502 /* get device extension */
503 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
505 /* get current irp stack */
506 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
507 DPRINT1("[KBDHID] IRP_MJ_PNP Request: %x\n", IoStack
->MinorFunction
);
509 if (IoStack
->MinorFunction
== IRP_MN_STOP_DEVICE
|| IoStack
->MinorFunction
== IRP_MN_CANCEL_REMOVE_DEVICE
|| IoStack
->MinorFunction
== IRP_MN_QUERY_STOP_DEVICE
|| IoStack
->MinorFunction
== IRP_MN_CANCEL_STOP_DEVICE
)
511 /* indicate success */
512 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
514 /* skip irp stack location */
515 IoSkipCurrentIrpStackLocation(Irp
);
517 /* dispatch to lower device */
518 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
520 else if (IoStack
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
522 /* FIXME synchronization */
525 IoCancelIrp(DeviceExtension
->Irp
);
527 /* indicate success */
528 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
530 /* skip irp stack location */
531 IoSkipCurrentIrpStackLocation(Irp
);
533 /* dispatch to lower device */
534 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
536 IoFreeIrp(DeviceExtension
->Irp
);
537 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
538 IoDeleteDevice(DeviceObject
);
541 else if (IoStack
->MinorFunction
== IRP_MN_START_DEVICE
)
544 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
546 /* copy stack location */
547 IoCopyCurrentIrpStackLocationToNext (Irp
);
549 /* set completion routine */
550 IoSetCompletionRoutine(Irp
, KbdHid_StartDeviceCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
551 Irp
->IoStatus
.Status
= 0;
554 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
555 if (Status
== STATUS_PENDING
)
557 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
558 Status
= Irp
->IoStatus
.Status
;
561 if (!NT_SUCCESS(Status
))
564 Irp
->IoStatus
.Status
= Status
;
565 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
569 /* lets start the device */
570 Status
= KbdHid_StartDevice(DeviceObject
);
571 DPRINT1("KbdHid_StartDevice %x\n", Status
);
573 /* complete request */
574 Irp
->IoStatus
.Status
= Status
;
575 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
582 /* skip irp stack location */
583 IoSkipCurrentIrpStackLocation(Irp
);
585 /* dispatch to lower device */
586 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
593 IN PDRIVER_OBJECT DriverObject
,
594 IN PDEVICE_OBJECT PhysicalDeviceObject
)
597 PDEVICE_OBJECT DeviceObject
, NextDeviceObject
;
598 PKBDHID_DEVICE_EXTENSION DeviceExtension
;
601 /* create device object */
602 Status
= IoCreateDevice(DriverObject
, sizeof(KBDHID_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_KEYBOARD
, 0, FALSE
, &DeviceObject
);
603 if (!NT_SUCCESS(Status
))
605 /* failed to create device object */
610 NextDeviceObject
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
611 if (!NextDeviceObject
)
613 /* failed to attach */
614 IoDeleteDevice(DeviceObject
);
615 return STATUS_DEVICE_NOT_CONNECTED
;
618 /* get device extension */
619 DeviceExtension
= (PKBDHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
622 RtlZeroMemory(DeviceExtension
, sizeof(KBDHID_DEVICE_EXTENSION
));
624 /* init device extension */
625 DeviceExtension
->NextDeviceObject
= NextDeviceObject
;
626 KeInitializeEvent(&DeviceExtension
->ReadCompletionEvent
, NotificationEvent
, FALSE
);
627 DeviceExtension
->Irp
= IoAllocateIrp(NextDeviceObject
->StackSize
, FALSE
);
629 /* FIXME handle allocation error */
630 ASSERT(DeviceExtension
->Irp
);
632 /* set power state to D0 */
633 State
.DeviceState
= PowerDeviceD0
;
634 PoSetPowerState(DeviceObject
, DevicePowerState
, State
);
636 /* init device object */
637 DeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
638 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
640 /* completed successfully */
641 return STATUS_SUCCESS
;
647 IN PDRIVER_OBJECT DriverObject
)
656 IN PDRIVER_OBJECT DriverObject
,
657 IN PUNICODE_STRING RegPath
)
659 /* initialize driver object */
660 DriverObject
->DriverUnload
= KbdHid_Unload
;
661 DriverObject
->DriverExtension
->AddDevice
= KbdHid_AddDevice
;
662 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = KbdHid_Create
;
663 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = KbdHid_Close
;
664 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = KbdHid_Flush
;
665 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = KbdHid_DeviceControl
;
666 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = KbdHid_InternalDeviceControl
;
667 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = KbdHid_Power
;
668 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = KbdHid_Pnp
;
669 DriverObject
->DriverUnload
= KbdHid_Unload
;
670 DriverObject
->DriverExtension
->AddDevice
= KbdHid_AddDevice
;
673 return STATUS_SUCCESS
;