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 allocte 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
387 return STATUS_SUCCESS
;
392 HidClassFDO_StartDevice(
393 IN PDEVICE_OBJECT DeviceObject
,
397 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
400 // get device extension
402 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
403 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
406 // query capabilities
408 Status
= HidClassFDO_QueryCapabilities(DeviceObject
, &FDODeviceExtension
->Capabilities
);
409 if (!NT_SUCCESS(Status
))
411 DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status
);
412 Irp
->IoStatus
.Status
= Status
;
413 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
418 // let's start the lower device too
420 IoSkipCurrentIrpStackLocation(Irp
);
421 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
422 if (!NT_SUCCESS(Status
))
424 DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status
);
425 Irp
->IoStatus
.Status
= Status
;
426 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
431 // let's get the descriptors
433 Status
= HidClassFDO_GetDescriptors(DeviceObject
);
434 if (!NT_SUCCESS(Status
))
436 DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status
);
437 Irp
->IoStatus
.Status
= Status
;
438 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
443 // now get the the collection description
445 Status
= HidP_GetCollectionDescription(FDODeviceExtension
->ReportDescriptor
, FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
, NonPagedPool
, &FDODeviceExtension
->Common
.DeviceDescription
);
446 if (!NT_SUCCESS(Status
))
448 DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status
);
449 Irp
->IoStatus
.Status
= Status
;
450 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
457 Irp
->IoStatus
.Status
= Status
;
458 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
463 HidClassFDO_RemoveDevice(
464 IN PDEVICE_OBJECT DeviceObject
,
468 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
471 // get device extension
473 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
474 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
479 // dispatch to minidriver
481 IoSkipCurrentIrpStackLocation(Irp
);
482 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
487 Irp
->IoStatus
.Status
= Status
;
488 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
491 // detach and delete device
493 IoDetachDevice(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
);
494 IoDeleteDevice(DeviceObject
);
500 HidClassFDO_CopyDeviceRelations(
501 IN PDEVICE_OBJECT DeviceObject
,
502 OUT PDEVICE_RELATIONS
*OutRelations
)
504 PDEVICE_RELATIONS DeviceRelations
;
505 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
509 // get device extension
511 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
512 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
517 DeviceRelations
= ExAllocatePoolWithTag(NonPagedPool
,
518 sizeof(DEVICE_RELATIONS
) + (FDODeviceExtension
->DeviceRelations
->Count
- 1) * sizeof(PDEVICE_OBJECT
),
520 if (!DeviceRelations
)
525 *OutRelations
= NULL
;
526 return STATUS_INSUFFICIENT_RESOURCES
;
530 // copy device objects
532 for (Index
= 0; Index
< FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
537 ObReferenceObject(FDODeviceExtension
->DeviceRelations
->Objects
[Index
]);
542 DeviceRelations
->Objects
[Index
] = FDODeviceExtension
->DeviceRelations
->Objects
[Index
];
548 DeviceRelations
->Count
= FDODeviceExtension
->DeviceRelations
->Count
;
553 *OutRelations
= DeviceRelations
;
554 return STATUS_SUCCESS
;
558 HidClassFDO_DeviceRelations(
559 IN PDEVICE_OBJECT DeviceObject
,
562 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
563 PIO_STACK_LOCATION IoStack
;
565 PDEVICE_RELATIONS DeviceRelations
;
568 // get device extension
570 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
571 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
574 // get current irp stack location
576 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
579 // check relations type
581 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
584 // only bus relations are handled
586 IoSkipCurrentIrpStackLocation(Irp
);
587 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
590 if (FDODeviceExtension
->DeviceRelations
== NULL
)
593 // time to create the pdos
595 Status
= HidClassPDO_CreatePDO(DeviceObject
, &FDODeviceExtension
->DeviceRelations
);
596 if (!NT_SUCCESS(Status
))
601 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status
);
602 Irp
->IoStatus
.Status
= Status
;
603 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
604 return STATUS_SUCCESS
;
609 ASSERT(FDODeviceExtension
->DeviceRelations
->Count
> 0);
613 // now copy device relations
615 Status
= HidClassFDO_CopyDeviceRelations(DeviceObject
, &DeviceRelations
);
619 Irp
->IoStatus
.Status
= Status
;
620 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
625 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
631 IN PDEVICE_OBJECT DeviceObject
,
634 PIO_STACK_LOCATION IoStack
;
635 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
639 // get device extension
641 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
642 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
645 // get current irp stack location
647 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
648 switch (IoStack
->MinorFunction
)
650 case IRP_MN_START_DEVICE
:
652 return HidClassFDO_StartDevice(DeviceObject
, Irp
);
654 case IRP_MN_REMOVE_DEVICE
:
656 return HidClassFDO_RemoveDevice(DeviceObject
, Irp
);
658 case IRP_MN_QUERY_DEVICE_RELATIONS
:
660 return HidClassFDO_DeviceRelations(DeviceObject
, Irp
);
662 case IRP_MN_QUERY_REMOVE_DEVICE
:
663 case IRP_MN_QUERY_STOP_DEVICE
:
664 case IRP_MN_CANCEL_REMOVE_DEVICE
:
665 case IRP_MN_CANCEL_STOP_DEVICE
:
668 // set status to success and fall through
670 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
675 // dispatch to mini driver
677 IoCopyCurrentIrpStackLocationToNext(Irp
);
678 Status
= HidClassFDO_DispatchRequest(DeviceObject
, Irp
);