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)
18 HidClassFDO_QueryCapabilitiesCompletionRoutine(
19 IN PDEVICE_OBJECT DeviceObject
,
26 KeSetEvent(Context
, 0, FALSE
);
29 // completion is done in the HidClassFDO_QueryCapabilities routine
31 return STATUS_MORE_PROCESSING_REQUIRED
;
35 HidClassFDO_QueryCapabilities(
36 IN PDEVICE_OBJECT DeviceObject
,
37 IN OUT PDEVICE_CAPABILITIES Capabilities
)
42 PIO_STACK_LOCATION IoStack
;
43 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
46 // get device extension
48 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
49 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
54 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
57 // now allocate the irp
59 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
65 return STATUS_INSUFFICIENT_RESOURCES
;
69 // get next stack location
71 IoStack
= IoGetNextIrpStackLocation(Irp
);
74 // init stack location
76 IoStack
->MajorFunction
= IRP_MJ_PNP
;
77 IoStack
->MinorFunction
= IRP_MN_QUERY_CAPABILITIES
;
78 IoStack
->Parameters
.DeviceCapabilities
.Capabilities
= Capabilities
;
81 // set completion routine
83 IoSetCompletionRoutine(Irp
, HidClassFDO_QueryCapabilitiesCompletionRoutine
, &Event
, TRUE
, TRUE
, TRUE
);
88 RtlZeroMemory(Capabilities
, sizeof(DEVICE_CAPABILITIES
));
89 Capabilities
->Size
= sizeof(DEVICE_CAPABILITIES
);
90 Capabilities
->Version
= 1; // FIXME hardcoded constant
91 Capabilities
->Address
= MAXULONG
;
92 Capabilities
->UINumber
= MAXULONG
;
95 // pnp irps have default completion code
97 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
102 Status
= IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
103 if (Status
== STATUS_PENDING
)
106 // wait for completion
108 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
114 Status
= Irp
->IoStatus
.Status
;
129 HidClassFDO_DispatchRequestSynchronousCompletion(
130 IN PDEVICE_OBJECT DeviceObject
,
137 KeSetEvent(Context
, 0, FALSE
);
142 return STATUS_MORE_PROCESSING_REQUIRED
;
147 HidClassFDO_DispatchRequestSynchronous(
148 IN PDEVICE_OBJECT DeviceObject
,
152 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
154 PIO_STACK_LOCATION IoStack
;
159 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
162 // get device extension
164 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
167 // set completion routine
169 IoSetCompletionRoutine(Irp
, HidClassFDO_DispatchRequestSynchronousCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
171 ASSERT(Irp
->CurrentLocation
> 0);
173 // create stack location
175 IoSetNextIrpStackLocation(Irp
);
178 // get next stack location
180 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
183 // store device object
185 IoStack
->DeviceObject
= DeviceObject
;
190 ASSERT(CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
] != NULL
);
193 // call minidriver (hidusb)
195 Status
= CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
](DeviceObject
, Irp
);
198 // wait for the request to finish
200 if (Status
== STATUS_PENDING
)
202 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
207 Status
= Irp
->IoStatus
.Status
;
217 HidClassFDO_DispatchRequest(
218 IN PDEVICE_OBJECT DeviceObject
,
221 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
223 PIO_STACK_LOCATION IoStack
;
226 // get device extension
228 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
230 ASSERT(Irp
->CurrentLocation
> 0);
233 // create stack location
235 IoSetNextIrpStackLocation(Irp
);
238 // get next stack location
240 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
243 // store device object
245 IoStack
->DeviceObject
= DeviceObject
;
250 ASSERT(CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
] != NULL
);
255 Status
= CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
](DeviceObject
, Irp
);
264 HidClassFDO_GetDescriptors(
265 IN PDEVICE_OBJECT DeviceObject
)
267 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
269 PIO_STACK_LOCATION IoStack
;
273 // get device extension
275 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
276 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
279 // let's allocate irp
281 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
287 return STATUS_INSUFFICIENT_RESOURCES
;
291 // get stack location
293 IoStack
= IoGetNextIrpStackLocation(Irp
);
296 // init stack location
298 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
299 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_DEVICE_DESCRIPTOR
;
300 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(HID_DESCRIPTOR
);
301 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
302 IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= NULL
;
303 Irp
->UserBuffer
= &FDODeviceExtension
->HidDescriptor
;
308 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
309 if (!NT_SUCCESS(Status
))
312 // failed to get device descriptor
314 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status
);
320 // let's get device attributes
322 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_DEVICE_ATTRIBUTES
;
323 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(HID_DEVICE_ATTRIBUTES
);
324 Irp
->UserBuffer
= &FDODeviceExtension
->Common
.Attributes
;
329 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
330 if (!NT_SUCCESS(Status
))
333 // failed to get device descriptor
335 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status
);
343 ASSERT(FDODeviceExtension
->HidDescriptor
.bLength
== sizeof(HID_DESCRIPTOR
));
344 ASSERT(FDODeviceExtension
->HidDescriptor
.bNumDescriptors
> 0);
345 ASSERT(FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
> 0);
346 ASSERT(FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
);
349 // now allocate space for the report descriptor
351 FDODeviceExtension
->ReportDescriptor
= ExAllocatePoolWithTag(NonPagedPool
,
352 FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
,
354 if (!FDODeviceExtension
->ReportDescriptor
)
360 return STATUS_INSUFFICIENT_RESOURCES
;
364 // init stack location
366 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_REPORT_DESCRIPTOR
;
367 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
;
368 Irp
->UserBuffer
= FDODeviceExtension
->ReportDescriptor
;
373 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
374 if (!NT_SUCCESS(Status
))
377 // failed to get device descriptor
379 DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status
);
385 // completed successfully
388 return STATUS_SUCCESS
;
393 HidClassFDO_StartDevice(
394 IN PDEVICE_OBJECT DeviceObject
,
398 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
401 // get device extension
403 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
404 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
407 // query capabilities
409 Status
= HidClassFDO_QueryCapabilities(DeviceObject
, &FDODeviceExtension
->Capabilities
);
410 if (!NT_SUCCESS(Status
))
412 DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status
);
413 Irp
->IoStatus
.Status
= Status
;
414 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
419 // let's start the lower device too
421 IoSkipCurrentIrpStackLocation(Irp
);
422 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
423 if (!NT_SUCCESS(Status
))
425 DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status
);
426 Irp
->IoStatus
.Status
= Status
;
427 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
432 // let's get the descriptors
434 Status
= HidClassFDO_GetDescriptors(DeviceObject
);
435 if (!NT_SUCCESS(Status
))
437 DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status
);
438 Irp
->IoStatus
.Status
= Status
;
439 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
444 // now get the the collection description
446 Status
= HidP_GetCollectionDescription(FDODeviceExtension
->ReportDescriptor
, FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
, NonPagedPool
, &FDODeviceExtension
->Common
.DeviceDescription
);
447 if (!NT_SUCCESS(Status
))
449 DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status
);
450 Irp
->IoStatus
.Status
= Status
;
451 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
458 Irp
->IoStatus
.Status
= Status
;
459 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
464 HidClassFDO_RemoveDevice(
465 IN PDEVICE_OBJECT DeviceObject
,
469 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
472 // get device extension
474 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
475 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
480 // dispatch to minidriver
482 IoSkipCurrentIrpStackLocation(Irp
);
483 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
488 Irp
->IoStatus
.Status
= Status
;
489 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
492 // detach and delete device
494 IoDetachDevice(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
);
495 IoDeleteDevice(DeviceObject
);
501 HidClassFDO_CopyDeviceRelations(
502 IN PDEVICE_OBJECT DeviceObject
,
503 OUT PDEVICE_RELATIONS
*OutRelations
)
505 PDEVICE_RELATIONS DeviceRelations
;
506 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
510 // get device extension
512 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
513 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
518 DeviceRelations
= ExAllocatePoolWithTag(NonPagedPool
,
519 sizeof(DEVICE_RELATIONS
) + (FDODeviceExtension
->DeviceRelations
->Count
- 1) * sizeof(PDEVICE_OBJECT
),
521 if (!DeviceRelations
)
526 *OutRelations
= NULL
;
527 return STATUS_INSUFFICIENT_RESOURCES
;
531 // copy device objects
533 for (Index
= 0; Index
< FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
538 ObReferenceObject(FDODeviceExtension
->DeviceRelations
->Objects
[Index
]);
543 DeviceRelations
->Objects
[Index
] = FDODeviceExtension
->DeviceRelations
->Objects
[Index
];
549 DeviceRelations
->Count
= FDODeviceExtension
->DeviceRelations
->Count
;
554 *OutRelations
= DeviceRelations
;
555 return STATUS_SUCCESS
;
559 HidClassFDO_DeviceRelations(
560 IN PDEVICE_OBJECT DeviceObject
,
563 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
564 PIO_STACK_LOCATION IoStack
;
566 PDEVICE_RELATIONS DeviceRelations
;
569 // get device extension
571 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
572 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
575 // get current irp stack location
577 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
580 // check relations type
582 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
585 // only bus relations are handled
587 IoSkipCurrentIrpStackLocation(Irp
);
588 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
591 if (FDODeviceExtension
->DeviceRelations
== NULL
)
594 // time to create the pdos
596 Status
= HidClassPDO_CreatePDO(DeviceObject
, &FDODeviceExtension
->DeviceRelations
);
597 if (!NT_SUCCESS(Status
))
602 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status
);
603 Irp
->IoStatus
.Status
= Status
;
604 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
605 return STATUS_SUCCESS
;
610 ASSERT(FDODeviceExtension
->DeviceRelations
->Count
> 0);
614 // now copy device relations
616 Status
= HidClassFDO_CopyDeviceRelations(DeviceObject
, &DeviceRelations
);
620 Irp
->IoStatus
.Status
= Status
;
621 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
626 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
632 IN PDEVICE_OBJECT DeviceObject
,
635 PIO_STACK_LOCATION IoStack
;
636 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
640 // get device extension
642 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
643 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
646 // get current irp stack location
648 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
649 switch (IoStack
->MinorFunction
)
651 case IRP_MN_START_DEVICE
:
653 return HidClassFDO_StartDevice(DeviceObject
, Irp
);
655 case IRP_MN_REMOVE_DEVICE
:
657 return HidClassFDO_RemoveDevice(DeviceObject
, Irp
);
659 case IRP_MN_QUERY_DEVICE_RELATIONS
:
661 return HidClassFDO_DeviceRelations(DeviceObject
, Irp
);
663 case IRP_MN_QUERY_REMOVE_DEVICE
:
664 case IRP_MN_QUERY_STOP_DEVICE
:
665 case IRP_MN_CANCEL_REMOVE_DEVICE
:
666 case IRP_MN_CANCEL_STOP_DEVICE
:
669 // set status to success and fall through
671 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
676 // dispatch to mini driver
678 IoCopyCurrentIrpStackLocationToNext(Irp
);
679 Status
= HidClassFDO_DispatchRequest(DeviceObject
, Irp
);