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 if (!NT_SUCCESS(Status
))
355 DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status
);
356 Irp
->IoStatus
.Status
= Status
;
357 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
362 // lets start the lower device too
364 IoSkipCurrentIrpStackLocation(Irp
);
365 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
366 if (!NT_SUCCESS(Status
))
368 DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status
);
369 Irp
->IoStatus
.Status
= Status
;
370 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
375 // lets get the descriptors
377 Status
= HidClassFDO_GetDescriptors(DeviceObject
);
378 if (!NT_SUCCESS(Status
))
380 DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status
);
381 Irp
->IoStatus
.Status
= Status
;
382 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
387 // now get the the collection description
389 Status
= HidP_GetCollectionDescription(FDODeviceExtension
->ReportDescriptor
, FDODeviceExtension
->HidDescriptor
.DescriptorList
[0].wReportLength
, NonPagedPool
, &FDODeviceExtension
->Common
.DeviceDescription
);
390 if (!NT_SUCCESS(Status
))
392 DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status
);
393 Irp
->IoStatus
.Status
= Status
;
394 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
401 Irp
->IoStatus
.Status
= Status
;
402 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
407 HidClassFDO_RemoveDevice(
408 IN PDEVICE_OBJECT DeviceObject
,
416 // dispatch to minidriver
418 IoSkipCurrentIrpStackLocation(Irp
);
419 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
424 Irp
->IoStatus
.Status
= Status
;
425 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
430 HidClassFDO_CopyDeviceRelations(
431 IN PDEVICE_OBJECT DeviceObject
,
432 OUT PDEVICE_RELATIONS
*OutRelations
)
434 PDEVICE_RELATIONS DeviceRelations
;
435 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
439 // get device extension
441 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
442 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
447 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_RELATIONS
) + (FDODeviceExtension
->DeviceRelations
->Count
-1) * sizeof(PDEVICE_OBJECT
));
448 if (!DeviceRelations
)
453 *OutRelations
= NULL
;
454 return STATUS_INSUFFICIENT_RESOURCES
;
458 // copy device objects
460 for(Index
= 0; Index
< FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
465 ObReferenceObject(FDODeviceExtension
->DeviceRelations
->Objects
[Index
]);
470 DeviceRelations
->Objects
[Index
] = FDODeviceExtension
->DeviceRelations
->Objects
[Index
];
476 DeviceRelations
->Count
= FDODeviceExtension
->DeviceRelations
->Count
;
481 *OutRelations
= DeviceRelations
;
482 return STATUS_SUCCESS
;
486 HidClassFDO_DeviceRelations(
487 IN PDEVICE_OBJECT DeviceObject
,
490 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
491 PIO_STACK_LOCATION IoStack
;
493 PDEVICE_RELATIONS DeviceRelations
;
496 // get device extension
498 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
499 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
502 // get current irp stack location
504 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
507 // check relations type
509 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
512 // only bus relations are handled
514 IoSkipCurrentIrpStackLocation(Irp
);
515 return IoCallDriver(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
, Irp
);
518 if (FDODeviceExtension
->DeviceRelations
== NULL
)
521 // time to create the pdos
523 Status
= HidClassPDO_CreatePDO(DeviceObject
, &FDODeviceExtension
->DeviceRelations
);
524 if (!NT_SUCCESS(Status
))
529 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status
);
530 Irp
->IoStatus
.Status
= Status
;
531 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
532 return STATUS_SUCCESS
;
537 ASSERT(FDODeviceExtension
->DeviceRelations
->Count
> 0);
541 // now copy device relations
543 Status
= HidClassFDO_CopyDeviceRelations(DeviceObject
, &DeviceRelations
);
547 Irp
->IoStatus
.Status
= Status
;
548 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
553 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
559 IN PDEVICE_OBJECT DeviceObject
,
562 PIO_STACK_LOCATION IoStack
;
563 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
567 // get device extension
569 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
570 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
573 // get current irp stack location
575 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
576 switch(IoStack
->MinorFunction
)
578 case IRP_MN_START_DEVICE
:
580 return HidClassFDO_StartDevice(DeviceObject
, Irp
);
582 case IRP_MN_REMOVE_DEVICE
:
584 return HidClassFDO_RemoveDevice(DeviceObject
, Irp
);
586 case IRP_MN_QUERY_DEVICE_RELATIONS
:
588 return HidClassFDO_DeviceRelations(DeviceObject
, Irp
);
590 case IRP_MN_QUERY_REMOVE_DEVICE
:
591 case IRP_MN_QUERY_STOP_DEVICE
:
592 case IRP_MN_CANCEL_REMOVE_DEVICE
:
593 case IRP_MN_CANCEL_STOP_DEVICE
:
596 // set status to success and fall through
598 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
603 // dispatch to mini driver
605 IoSkipCurrentIrpStackLocation(Irp
);
606 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
611 Irp
->IoStatus
.Status
= Status
;
612 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);