2 * PROJECT: ReactOS Universal Serial Bus Human Interface Device Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/hid/hidclass/fdo.c
5 * PURPOSE: HID Class Driver
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
15 HidClassFDO_QueryCapabilitiesCompletionRoutine(
16 IN PDEVICE_OBJECT DeviceObject
,
23 KeSetEvent(Context
, 0, FALSE
);
26 // completion is done in the HidClassFDO_QueryCapabilities routine
28 return STATUS_MORE_PROCESSING_REQUIRED
;
32 HidClassFDO_QueryCapabilities(
33 IN PDEVICE_OBJECT DeviceObject
,
34 IN OUT PDEVICE_CAPABILITIES Capabilities
)
39 PIO_STACK_LOCATION IoStack
;
40 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
43 // get device extension
45 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
46 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
51 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
54 // now allocte the irp
56 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
62 return STATUS_INSUFFICIENT_RESOURCES
;
66 // get next stack location
68 IoStack
= IoGetNextIrpStackLocation(Irp
);
71 // init stack location
73 IoStack
->MajorFunction
= IRP_MJ_PNP
;
74 IoStack
->MinorFunction
= IRP_MN_QUERY_CAPABILITIES
;
75 IoStack
->Parameters
.DeviceCapabilities
.Capabilities
= Capabilities
;
78 // set completion routine
80 IoSetCompletionRoutine(Irp
, HidClassFDO_QueryCapabilitiesCompletionRoutine
, &Event
, TRUE
, TRUE
, TRUE
);
85 RtlZeroMemory(Capabilities
, sizeof(DEVICE_CAPABILITIES
));
86 Capabilities
->Size
= sizeof(DEVICE_CAPABILITIES
);
87 Capabilities
->Version
= 1; // FIXME hardcoded constant
88 Capabilities
->Address
= MAXULONG
;
89 Capabilities
->UINumber
= MAXULONG
;
92 // pnp irps have default completion code
94 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
99 Status
= IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
100 if (Status
== STATUS_PENDING
)
103 // wait for completion
105 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
111 Status
= Irp
->IoStatus
.Status
;
126 HidClassFDO_DispatchRequestSynchronousCompletion(
127 IN PDEVICE_OBJECT DeviceObject
,
134 KeSetEvent(Context
, 0, FALSE
);
139 return STATUS_MORE_PROCESSING_REQUIRED
;
144 HidClassFDO_DispatchRequestSynchronous(
145 IN PDEVICE_OBJECT DeviceObject
,
149 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
151 PIO_STACK_LOCATION IoStack
;
156 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
159 // get device extension
161 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
164 // set completion routine
166 IoSetCompletionRoutine(Irp
, HidClassFDO_DispatchRequestSynchronousCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
168 ASSERT(Irp
->CurrentLocation
> 0);
170 // create stack location
172 IoSetNextIrpStackLocation(Irp
);
175 // get next stack location
177 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
180 // store device object
182 IoStack
->DeviceObject
= DeviceObject
;
187 ASSERT(CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
] != NULL
);
190 // call minidriver (hidusb)
192 Status
= CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
](DeviceObject
, Irp
);
195 // wait for the request to finish
197 if (Status
== STATUS_PENDING
)
199 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
204 Status
= Irp
->IoStatus
.Status
;
214 HidClassFDO_DispatchRequest(
215 IN PDEVICE_OBJECT DeviceObject
,
218 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
220 PIO_STACK_LOCATION IoStack
;
223 // get device extension
225 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
227 ASSERT(Irp
->CurrentLocation
> 0);
230 // create stack location
232 IoSetNextIrpStackLocation(Irp
);
235 // get next stack location
237 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
240 // store device object
242 IoStack
->DeviceObject
= DeviceObject
;
247 ASSERT(CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
] != NULL
);
252 Status
= CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
](DeviceObject
, Irp
);
261 HidClassFDO_GetDescriptors(
262 IN PDEVICE_OBJECT DeviceObject
)
264 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
266 PIO_STACK_LOCATION IoStack
;
270 // get device extension
272 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
273 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
276 // let's allocate irp
278 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
284 return STATUS_INSUFFICIENT_RESOURCES
;
288 // get stack location
290 IoStack
= IoGetNextIrpStackLocation(Irp
);
293 // init stack location
295 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
296 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_DEVICE_DESCRIPTOR
;
297 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(HID_DESCRIPTOR
);
298 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
299 IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= NULL
;
300 Irp
->UserBuffer
= &FDODeviceExtension
->HidDescriptor
;
305 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
306 if (!NT_SUCCESS(Status
))
309 // failed to get device descriptor
311 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status
);
317 // let's get device attributes
319 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_DEVICE_ATTRIBUTES
;
320 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(HID_DEVICE_ATTRIBUTES
);
321 Irp
->UserBuffer
= &FDODeviceExtension
->Common
.Attributes
;
326 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
327 if (!NT_SUCCESS(Status
))
330 // failed to get device descriptor
332 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status
);
340 ASSERT(FDODeviceExtension
->HidDescriptor
.bLength
== sizeof(HID_DESCRIPTOR
));
341 ASSERT(FDODeviceExtension
->HidDescriptor
.bNumDescriptors
> 0);
342 ASSERT(FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
> 0);
343 ASSERT(FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
);
346 // now allocate space for the report descriptor
348 FDODeviceExtension
->ReportDescriptor
= ExAllocatePoolWithTag(NonPagedPool
,
349 FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
,
351 if (!FDODeviceExtension
->ReportDescriptor
)
357 return STATUS_INSUFFICIENT_RESOURCES
;
361 // init stack location
363 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_REPORT_DESCRIPTOR
;
364 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
;
365 Irp
->UserBuffer
= FDODeviceExtension
->ReportDescriptor
;
370 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
371 if (!NT_SUCCESS(Status
))
374 // failed to get device descriptor
376 DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status
);
382 // completed successfully
384 return STATUS_SUCCESS
;
389 HidClassFDO_StartDevice(
390 IN PDEVICE_OBJECT DeviceObject
,
394 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
397 // get device extension
399 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
400 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
403 // query capabilities
405 Status
= HidClassFDO_QueryCapabilities(DeviceObject
, &FDODeviceExtension
->Capabilities
);
406 if (!NT_SUCCESS(Status
))
408 DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status
);
409 Irp
->IoStatus
.Status
= Status
;
410 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
415 // let's start the lower device too
417 IoSkipCurrentIrpStackLocation(Irp
);
418 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
419 if (!NT_SUCCESS(Status
))
421 DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status
);
422 Irp
->IoStatus
.Status
= Status
;
423 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
428 // let's get the descriptors
430 Status
= HidClassFDO_GetDescriptors(DeviceObject
);
431 if (!NT_SUCCESS(Status
))
433 DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status
);
434 Irp
->IoStatus
.Status
= Status
;
435 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
440 // now get the the collection description
442 Status
= HidP_GetCollectionDescription(FDODeviceExtension
->ReportDescriptor
, FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
, NonPagedPool
, &FDODeviceExtension
->Common
.DeviceDescription
);
443 if (!NT_SUCCESS(Status
))
445 DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status
);
446 Irp
->IoStatus
.Status
= Status
;
447 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
454 Irp
->IoStatus
.Status
= Status
;
455 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
460 HidClassFDO_RemoveDevice(
461 IN PDEVICE_OBJECT DeviceObject
,
465 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
468 // get device extension
470 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
471 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
476 // dispatch to minidriver
478 IoSkipCurrentIrpStackLocation(Irp
);
479 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
484 Irp
->IoStatus
.Status
= Status
;
485 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
488 // detach and delete device
490 IoDetachDevice(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
);
491 IoDeleteDevice(DeviceObject
);
497 HidClassFDO_CopyDeviceRelations(
498 IN PDEVICE_OBJECT DeviceObject
,
499 OUT PDEVICE_RELATIONS
*OutRelations
)
501 PDEVICE_RELATIONS DeviceRelations
;
502 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
506 // get device extension
508 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
509 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
514 DeviceRelations
= ExAllocatePoolWithTag(NonPagedPool
,
515 sizeof(DEVICE_RELATIONS
) + (FDODeviceExtension
->DeviceRelations
->Count
- 1) * sizeof(PDEVICE_OBJECT
),
517 if (!DeviceRelations
)
522 *OutRelations
= NULL
;
523 return STATUS_INSUFFICIENT_RESOURCES
;
527 // copy device objects
529 for (Index
= 0; Index
< FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
534 ObReferenceObject(FDODeviceExtension
->DeviceRelations
->Objects
[Index
]);
539 DeviceRelations
->Objects
[Index
] = FDODeviceExtension
->DeviceRelations
->Objects
[Index
];
545 DeviceRelations
->Count
= FDODeviceExtension
->DeviceRelations
->Count
;
550 *OutRelations
= DeviceRelations
;
551 return STATUS_SUCCESS
;
555 HidClassFDO_DeviceRelations(
556 IN PDEVICE_OBJECT DeviceObject
,
559 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
560 PIO_STACK_LOCATION IoStack
;
562 PDEVICE_RELATIONS DeviceRelations
;
565 // get device extension
567 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
568 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
571 // get current irp stack location
573 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
576 // check relations type
578 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
581 // only bus relations are handled
583 IoSkipCurrentIrpStackLocation(Irp
);
584 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
587 if (FDODeviceExtension
->DeviceRelations
== NULL
)
590 // time to create the pdos
592 Status
= HidClassPDO_CreatePDO(DeviceObject
, &FDODeviceExtension
->DeviceRelations
);
593 if (!NT_SUCCESS(Status
))
598 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status
);
599 Irp
->IoStatus
.Status
= Status
;
600 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
601 return STATUS_SUCCESS
;
606 ASSERT(FDODeviceExtension
->DeviceRelations
->Count
> 0);
610 // now copy device relations
612 Status
= HidClassFDO_CopyDeviceRelations(DeviceObject
, &DeviceRelations
);
616 Irp
->IoStatus
.Status
= Status
;
617 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
622 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
628 IN PDEVICE_OBJECT DeviceObject
,
631 PIO_STACK_LOCATION IoStack
;
632 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
636 // get device extension
638 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
639 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
642 // get current irp stack location
644 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
645 switch (IoStack
->MinorFunction
)
647 case IRP_MN_START_DEVICE
:
649 return HidClassFDO_StartDevice(DeviceObject
, Irp
);
651 case IRP_MN_REMOVE_DEVICE
:
653 return HidClassFDO_RemoveDevice(DeviceObject
, Irp
);
655 case IRP_MN_QUERY_DEVICE_RELATIONS
:
657 return HidClassFDO_DeviceRelations(DeviceObject
, Irp
);
659 case IRP_MN_QUERY_REMOVE_DEVICE
:
660 case IRP_MN_QUERY_STOP_DEVICE
:
661 case IRP_MN_CANCEL_REMOVE_DEVICE
:
662 case IRP_MN_CANCEL_STOP_DEVICE
:
665 // set status to success and fall through
667 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
672 // dispatch to mini driver
674 IoCopyCurrentIrpStackLocationToNext(Irp
);
675 Status
= HidClassFDO_DispatchRequest(DeviceObject
, Irp
);