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 DPRINT("IoStack MajorFunction %x MinorFunction %x\n", IoStack
->MajorFunction
, IoStack
->MinorFunction
);
188 Status
= CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
](DeviceObject
, Irp
);
191 // wait for the request to finish
193 if (Status
== STATUS_PENDING
)
195 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
200 Status
= Irp
->IoStatus
.Status
;
210 HidClassFDO_GetDescriptors(
211 IN PDEVICE_OBJECT DeviceObject
)
213 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
215 PIO_STACK_LOCATION IoStack
;
219 // get device extension
221 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
222 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
225 // let's allocate irp
227 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
233 return STATUS_INSUFFICIENT_RESOURCES
;
237 // get stack location
239 IoStack
= IoGetNextIrpStackLocation(Irp
);
242 // init stack location
244 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
245 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_DEVICE_DESCRIPTOR
;
246 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(HID_DESCRIPTOR
);
247 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
248 IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= NULL
;
249 Irp
->UserBuffer
= &FDODeviceExtension
->HidDescriptor
;
254 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
255 if (!NT_SUCCESS(Status
))
258 // failed to get device descriptor
260 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status
);
266 // let's get device attributes
268 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_DEVICE_ATTRIBUTES
;
269 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(HID_DEVICE_ATTRIBUTES
);
270 Irp
->UserBuffer
= &FDODeviceExtension
->Common
.Attributes
;
275 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
276 if (!NT_SUCCESS(Status
))
279 // failed to get device descriptor
281 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status
);
289 ASSERT(FDODeviceExtension
->HidDescriptor
.bLength
== sizeof(HID_DESCRIPTOR
));
290 ASSERT(FDODeviceExtension
->HidDescriptor
.bNumDescriptors
> 0);
291 ASSERT(FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
> 0);
292 ASSERT(FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
);
295 // now allocate space for the report descriptor
297 FDODeviceExtension
->ReportDescriptor
= ExAllocatePoolWithTag(NonPagedPool
,
298 FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
,
300 if (!FDODeviceExtension
->ReportDescriptor
)
306 return STATUS_INSUFFICIENT_RESOURCES
;
310 // init stack location
312 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_REPORT_DESCRIPTOR
;
313 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
;
314 Irp
->UserBuffer
= FDODeviceExtension
->ReportDescriptor
;
319 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
320 if (!NT_SUCCESS(Status
))
323 // failed to get device descriptor
325 DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status
);
331 // completed successfully
333 return STATUS_SUCCESS
;
338 HidClassFDO_StartDevice(
339 IN PDEVICE_OBJECT DeviceObject
,
343 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
346 // get device extension
348 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
349 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
352 // query capabilities
354 Status
= HidClassFDO_QueryCapabilities(DeviceObject
, &FDODeviceExtension
->Capabilities
);
355 if (!NT_SUCCESS(Status
))
357 DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status
);
358 Irp
->IoStatus
.Status
= Status
;
359 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
364 // let's start the lower device too
366 IoSkipCurrentIrpStackLocation(Irp
);
367 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
368 if (!NT_SUCCESS(Status
))
370 DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status
);
371 Irp
->IoStatus
.Status
= Status
;
372 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
377 // let's get the descriptors
379 Status
= HidClassFDO_GetDescriptors(DeviceObject
);
380 if (!NT_SUCCESS(Status
))
382 DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status
);
383 Irp
->IoStatus
.Status
= Status
;
384 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
389 // now get the the collection description
391 Status
= HidP_GetCollectionDescription(FDODeviceExtension
->ReportDescriptor
, FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
, NonPagedPool
, &FDODeviceExtension
->Common
.DeviceDescription
);
392 if (!NT_SUCCESS(Status
))
394 DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status
);
395 Irp
->IoStatus
.Status
= Status
;
396 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
403 Irp
->IoStatus
.Status
= Status
;
404 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
409 HidClassFDO_RemoveDevice(
410 IN PDEVICE_OBJECT DeviceObject
,
414 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
417 // get device extension
419 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
420 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
425 // dispatch to minidriver
427 IoSkipCurrentIrpStackLocation(Irp
);
428 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
433 Irp
->IoStatus
.Status
= Status
;
434 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
437 // detach and delete device
439 IoDetachDevice(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
);
440 IoDeleteDevice(DeviceObject
);
446 HidClassFDO_CopyDeviceRelations(
447 IN PDEVICE_OBJECT DeviceObject
,
448 OUT PDEVICE_RELATIONS
*OutRelations
)
450 PDEVICE_RELATIONS DeviceRelations
;
451 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
455 // get device extension
457 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
458 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
463 DeviceRelations
= ExAllocatePoolWithTag(NonPagedPool
,
464 sizeof(DEVICE_RELATIONS
) + (FDODeviceExtension
->DeviceRelations
->Count
- 1) * sizeof(PDEVICE_OBJECT
),
466 if (!DeviceRelations
)
471 *OutRelations
= NULL
;
472 return STATUS_INSUFFICIENT_RESOURCES
;
476 // copy device objects
478 for (Index
= 0; Index
< FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
483 ObReferenceObject(FDODeviceExtension
->DeviceRelations
->Objects
[Index
]);
488 DeviceRelations
->Objects
[Index
] = FDODeviceExtension
->DeviceRelations
->Objects
[Index
];
494 DeviceRelations
->Count
= FDODeviceExtension
->DeviceRelations
->Count
;
499 *OutRelations
= DeviceRelations
;
500 return STATUS_SUCCESS
;
504 HidClassFDO_DeviceRelations(
505 IN PDEVICE_OBJECT DeviceObject
,
508 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
509 PIO_STACK_LOCATION IoStack
;
511 PDEVICE_RELATIONS DeviceRelations
;
514 // get device extension
516 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
517 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
520 // get current irp stack location
522 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
525 // check relations type
527 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
530 // only bus relations are handled
532 IoSkipCurrentIrpStackLocation(Irp
);
533 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
536 if (FDODeviceExtension
->DeviceRelations
== NULL
)
539 // time to create the pdos
541 Status
= HidClassPDO_CreatePDO(DeviceObject
, &FDODeviceExtension
->DeviceRelations
);
542 if (!NT_SUCCESS(Status
))
547 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status
);
548 Irp
->IoStatus
.Status
= Status
;
549 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
550 return STATUS_SUCCESS
;
555 ASSERT(FDODeviceExtension
->DeviceRelations
->Count
> 0);
559 // now copy device relations
561 Status
= HidClassFDO_CopyDeviceRelations(DeviceObject
, &DeviceRelations
);
565 Irp
->IoStatus
.Status
= Status
;
566 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
571 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
577 IN PDEVICE_OBJECT DeviceObject
,
580 PIO_STACK_LOCATION IoStack
;
581 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
585 // get device extension
587 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
588 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
591 // get current irp stack location
593 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
594 switch (IoStack
->MinorFunction
)
596 case IRP_MN_START_DEVICE
:
598 return HidClassFDO_StartDevice(DeviceObject
, Irp
);
600 case IRP_MN_REMOVE_DEVICE
:
602 return HidClassFDO_RemoveDevice(DeviceObject
, Irp
);
604 case IRP_MN_QUERY_DEVICE_RELATIONS
:
606 return HidClassFDO_DeviceRelations(DeviceObject
, Irp
);
608 case IRP_MN_QUERY_REMOVE_DEVICE
:
609 case IRP_MN_QUERY_STOP_DEVICE
:
610 case IRP_MN_CANCEL_REMOVE_DEVICE
:
611 case IRP_MN_CANCEL_STOP_DEVICE
:
614 // set status to success and fall through
616 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
621 // dispatch to mini driver
623 IoSkipCurrentIrpStackLocation(Irp
);
624 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
629 Irp
->IoStatus
.Status
= Status
;
630 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);