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)
14 HidClassFDO_QueryCapabilitiesCompletionRoutine(
15 IN PDEVICE_OBJECT DeviceObject
,
22 KeSetEvent((PRKEVENT
)Context
, 0, FALSE
);
25 // completion is done in the HidClassFDO_QueryCapabilities routine
27 return STATUS_MORE_PROCESSING_REQUIRED
;
31 HidClassFDO_QueryCapabilities(
32 IN PDEVICE_OBJECT DeviceObject
,
33 IN OUT PDEVICE_CAPABILITIES Capabilities
)
38 PIO_STACK_LOCATION IoStack
;
39 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
42 // get device extension
44 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
45 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
50 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
53 // now allocte the irp
55 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
61 return STATUS_INSUFFICIENT_RESOURCES
;
65 // get next stack location
67 IoStack
= IoGetNextIrpStackLocation(Irp
);
70 // init stack location
72 IoStack
->MajorFunction
= IRP_MJ_PNP
;
73 IoStack
->MinorFunction
= IRP_MN_QUERY_CAPABILITIES
;
74 IoStack
->Parameters
.DeviceCapabilities
.Capabilities
= Capabilities
;
77 // set completion routine
79 IoSetCompletionRoutine(Irp
, HidClassFDO_QueryCapabilitiesCompletionRoutine
, (PVOID
)&Event
, TRUE
, TRUE
, TRUE
);
84 RtlZeroMemory(Capabilities
, sizeof(DEVICE_CAPABILITIES
));
85 Capabilities
->Size
= sizeof(DEVICE_CAPABILITIES
);
86 Capabilities
->Version
= 1; // FIXME hardcoded constant
87 Capabilities
->Address
= MAXULONG
;
88 Capabilities
->UINumber
= MAXULONG
;
91 // pnp irps have default completion code
93 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
98 Status
= IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
99 if (Status
== STATUS_PENDING
)
102 // wait for completion
104 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
110 Status
= Irp
->IoStatus
.Status
;
125 HidClassFDO_DispatchRequestSynchronousCompletion(
126 IN PDEVICE_OBJECT DeviceObject
,
133 KeSetEvent((PRKEVENT
)Context
, 0, FALSE
);
138 return STATUS_MORE_PROCESSING_REQUIRED
;
143 HidClassFDO_DispatchRequestSynchronous(
144 IN PDEVICE_OBJECT DeviceObject
,
148 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
150 PIO_STACK_LOCATION IoStack
;
155 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
158 // get device extension
160 CommonDeviceExtension
= (PHIDCLASS_COMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
163 // set completion routine
165 IoSetCompletionRoutine(Irp
, HidClassFDO_DispatchRequestSynchronousCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
167 ASSERT(Irp
->CurrentLocation
> 0);
169 // create stack location
171 IoSetNextIrpStackLocation(Irp
);
174 // get next stack location
176 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
179 // store device object
181 IoStack
->DeviceObject
= DeviceObject
;
186 DPRINT("IoStack MajorFunction %x MinorFunction %x\n", IoStack
->MajorFunction
, IoStack
->MinorFunction
);
187 Status
= CommonDeviceExtension
->DriverExtension
->MajorFunction
[IoStack
->MajorFunction
](DeviceObject
, Irp
);
190 // wait for the request to finish
192 if (Status
== STATUS_PENDING
)
194 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
199 Status
= Irp
->IoStatus
.Status
;
209 HidClassFDO_GetDescriptors(
210 IN PDEVICE_OBJECT DeviceObject
)
212 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
214 PIO_STACK_LOCATION IoStack
;
218 // get device extension
220 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
221 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
226 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
232 return STATUS_INSUFFICIENT_RESOURCES
;
236 // get stack location
238 IoStack
= IoGetNextIrpStackLocation(Irp
);
241 // init stack location
243 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
244 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_DEVICE_DESCRIPTOR
;
245 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(HID_DESCRIPTOR
);
246 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
247 IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= NULL
;
248 Irp
->UserBuffer
= &FDODeviceExtension
->HidDescriptor
;
253 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
254 if (!NT_SUCCESS(Status
))
257 // failed to get device descriptor
259 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status
);
265 // lets get device attributes
267 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_DEVICE_ATTRIBUTES
;
268 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(HID_DEVICE_ATTRIBUTES
);
269 Irp
->UserBuffer
= &FDODeviceExtension
->Common
.Attributes
;
274 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
275 if (!NT_SUCCESS(Status
))
278 // failed to get device descriptor
280 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status
);
288 ASSERT(FDODeviceExtension
->HidDescriptor
.bLength
== sizeof(HID_DESCRIPTOR
));
289 ASSERT(FDODeviceExtension
->HidDescriptor
.bNumDescriptors
> 0);
290 ASSERT(FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
> 0);
291 ASSERT(FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
);
295 // now allocate space for the report descriptor
297 FDODeviceExtension
->ReportDescriptor
= (PUCHAR
)ExAllocatePool(NonPagedPool
, FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
);
298 if (!FDODeviceExtension
->ReportDescriptor
)
304 return STATUS_INSUFFICIENT_RESOURCES
;
308 // init stack location
310 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_GET_REPORT_DESCRIPTOR
;
311 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
;
312 Irp
->UserBuffer
= FDODeviceExtension
->ReportDescriptor
;
317 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
318 if (!NT_SUCCESS(Status
))
321 // failed to get device descriptor
323 DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status
);
329 // completed successfully
331 return STATUS_SUCCESS
;
336 HidClassFDO_StartDevice(
337 IN PDEVICE_OBJECT DeviceObject
,
341 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
344 // get device extension
346 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
347 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
350 // query capabilities
352 Status
= HidClassFDO_QueryCapabilities(DeviceObject
, &FDODeviceExtension
->Capabilities
);
353 ASSERT(Status
== STATUS_SUCCESS
);
356 // lets start the lower device too
358 IoSkipCurrentIrpStackLocation(Irp
);
359 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
360 ASSERT(Status
== STATUS_SUCCESS
);
363 // lets get the descriptors
365 Status
= HidClassFDO_GetDescriptors(DeviceObject
);
366 ASSERT(Status
== STATUS_SUCCESS
);
369 // now get the the collection description
371 Status
= HidP_GetCollectionDescription(FDODeviceExtension
->ReportDescriptor
, FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
, NonPagedPool
, &FDODeviceExtension
->Common
.DeviceDescription
);
372 ASSERT(Status
== STATUS_SUCCESS
);
377 Irp
->IoStatus
.Status
= Status
;
378 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
383 HidClassFDO_RemoveDevice(
384 IN PDEVICE_OBJECT DeviceObject
,
387 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
= DeviceObject
->DeviceExtension
;
390 /* Pass the IRP down */
391 IoSkipCurrentIrpStackLocation(Irp
);
392 Status
= IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
394 /* Now teardown our portion of the device stack */
395 IoDetachDevice(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
);
396 IoDeleteDevice(DeviceObject
);
402 HidClassFDO_CopyDeviceRelations(
403 IN PDEVICE_OBJECT DeviceObject
,
404 OUT PDEVICE_RELATIONS
*OutRelations
)
406 PDEVICE_RELATIONS DeviceRelations
;
407 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
411 // get device extension
413 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
414 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
419 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_RELATIONS
) + (FDODeviceExtension
->DeviceRelations
->Count
-1) * sizeof(PDEVICE_OBJECT
));
420 if (!DeviceRelations
)
425 *OutRelations
= NULL
;
426 return STATUS_INSUFFICIENT_RESOURCES
;
430 // copy device objects
432 for(Index
= 0; Index
< FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
437 ObReferenceObject(FDODeviceExtension
->DeviceRelations
->Objects
[Index
]);
442 DeviceRelations
->Objects
[Index
] = FDODeviceExtension
->DeviceRelations
->Objects
[Index
];
448 DeviceRelations
->Count
= FDODeviceExtension
->DeviceRelations
->Count
;
453 *OutRelations
= DeviceRelations
;
454 return STATUS_SUCCESS
;
458 HidClassFDO_DeviceRelations(
459 IN PDEVICE_OBJECT DeviceObject
,
462 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
463 PIO_STACK_LOCATION IoStack
;
465 PDEVICE_RELATIONS DeviceRelations
;
468 // get device extension
470 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
471 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
474 // get current irp stack location
476 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
479 // check relations type
481 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
484 // only bus relations are handled
486 IoSkipCurrentIrpStackLocation(Irp
);
487 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
490 if (FDODeviceExtension
->DeviceRelations
== NULL
)
493 // time to create the pdos
495 Status
= HidClassPDO_CreatePDO(DeviceObject
, &FDODeviceExtension
->DeviceRelations
);
496 if (!NT_SUCCESS(Status
))
501 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status
);
502 Irp
->IoStatus
.Status
= Status
;
503 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
504 return STATUS_SUCCESS
;
509 ASSERT(FDODeviceExtension
->DeviceRelations
->Count
> 0);
513 // now copy device relations
515 Status
= HidClassFDO_CopyDeviceRelations(DeviceObject
, &DeviceRelations
);
519 Irp
->IoStatus
.Status
= Status
;
520 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
525 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
531 IN PDEVICE_OBJECT DeviceObject
,
534 PIO_STACK_LOCATION IoStack
;
535 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
538 // get device extension
540 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
541 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
544 // get current irp stack location
546 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
547 switch(IoStack
->MinorFunction
)
549 case IRP_MN_START_DEVICE
:
551 return HidClassFDO_StartDevice(DeviceObject
, Irp
);
553 case IRP_MN_REMOVE_DEVICE
:
555 return HidClassFDO_RemoveDevice(DeviceObject
, Irp
);
557 case IRP_MN_QUERY_REMOVE_DEVICE
:
558 case IRP_MN_QUERY_STOP_DEVICE
:
561 // set status to succes
563 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
566 // forward to lower device
568 IoSkipCurrentIrpStackLocation(Irp
);
569 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
571 case IRP_MN_CANCEL_REMOVE_DEVICE
:
572 case IRP_MN_CANCEL_STOP_DEVICE
:
575 // set status to succes
577 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
580 // forward to lower device
582 IoSkipCurrentIrpStackLocation(Irp
);
583 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
585 case IRP_MN_QUERY_DEVICE_RELATIONS
:
587 return HidClassFDO_DeviceRelations(DeviceObject
, Irp
);
592 // dispatch to lower device
594 IoSkipCurrentIrpStackLocation(Irp
);
595 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);