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)
19 HidClassPDO_GetCollectionDescription(
20 PHIDP_DEVICE_DESC DeviceDescription
,
21 ULONG CollectionNumber
)
25 for(Index
= 0; Index
< DeviceDescription
->CollectionDescLength
; Index
++)
27 if (DeviceDescription
->CollectionDesc
[Index
].CollectionNumber
== CollectionNumber
)
32 return &DeviceDescription
->CollectionDesc
[Index
];
37 // failed to find collection
39 DPRINT1("[HIDCLASS] GetCollectionDescription CollectionNumber %x not found\n", CollectionNumber
);
45 HidClassPDO_GetReportDescription(
46 PHIDP_DEVICE_DESC DeviceDescription
,
47 ULONG CollectionNumber
)
51 for (Index
= 0; Index
< DeviceDescription
->ReportIDsLength
; Index
++)
53 if (DeviceDescription
->ReportIDs
[Index
].CollectionNumber
== CollectionNumber
)
58 return &DeviceDescription
->ReportIDs
[Index
];
63 // failed to find collection
65 DPRINT1("[HIDCLASS] GetReportDescription CollectionNumber %x not found\n", CollectionNumber
);
71 HidClassPDO_HandleQueryDeviceId(
72 IN PDEVICE_OBJECT DeviceObject
,
77 LPWSTR NewBuffer
, Ptr
;
81 // copy current stack location
83 IoCopyCurrentIrpStackLocationToNext(Irp
);
88 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
89 if (!NT_SUCCESS(Status
))
100 Buffer
= (LPWSTR
)Irp
->IoStatus
.Information
;
101 Length
= wcslen(Buffer
);
104 // allocate new buffer
106 NewBuffer
= ExAllocatePoolWithTag(NonPagedPool
, (Length
+ 1) * sizeof(WCHAR
), HIDCLASS_TAG
);
110 // failed to allocate buffer
112 return STATUS_INSUFFICIENT_RESOURCES
;
118 wcscpy(NewBuffer
, L
"HID\\");
121 // get offset to first '\\'
123 Ptr
= wcschr(Buffer
, L
'\\');
129 wcscat(NewBuffer
, Ptr
+ 1);
135 ExFreePoolWithTag(Buffer
, 0);
140 DPRINT("NewBuffer %S\n", NewBuffer
);
141 Irp
->IoStatus
.Information
= (ULONG_PTR
)NewBuffer
;
142 return STATUS_SUCCESS
;
146 HidClassPDO_HandleQueryHardwareId(
147 IN PDEVICE_OBJECT DeviceObject
,
151 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
155 PHIDP_COLLECTION_DESC CollectionDescription
;
158 // get device extension
160 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
161 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
164 // copy current stack location
166 IoCopyCurrentIrpStackLocationToNext(Irp
);
171 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
172 if (!NT_SUCCESS(Status
))
180 if (PDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
> 1)
185 Offset
= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x&Rev_%04x&Col%02x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
, PDODeviceExtension
->Common
.Attributes
.VersionNumber
, PDODeviceExtension
->CollectionNumber
) + 1;
186 Offset
+= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x&Col%02x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
, PDODeviceExtension
->CollectionNumber
) + 1;
193 Offset
= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x&Rev_%04x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
, PDODeviceExtension
->Common
.Attributes
.VersionNumber
) + 1;
194 Offset
+= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
) + 1;
198 // get collection description
200 CollectionDescription
= HidClassPDO_GetCollectionDescription(&PDODeviceExtension
->Common
.DeviceDescription
, PDODeviceExtension
->CollectionNumber
);
201 ASSERT(CollectionDescription
);
203 if (CollectionDescription
->UsagePage
== HID_USAGE_PAGE_GENERIC
)
205 switch (CollectionDescription
->Usage
)
207 case HID_USAGE_GENERIC_POINTER
:
208 case HID_USAGE_GENERIC_MOUSE
:
212 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_MOUSE") + 1;
214 case HID_USAGE_GENERIC_GAMEPAD
:
215 case HID_USAGE_GENERIC_JOYSTICK
:
217 // Joystick / Gamepad
219 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_GAME") + 1;
221 case HID_USAGE_GENERIC_KEYBOARD
:
222 case HID_USAGE_GENERIC_KEYPAD
:
226 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_KEYBOARD") + 1;
228 case HID_USAGE_GENERIC_SYSTEM_CTL
:
232 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_CONTROL") + 1;
236 else if (CollectionDescription
->UsagePage
== HID_USAGE_PAGE_CONSUMER
&& CollectionDescription
->Usage
== HID_USAGE_CONSUMERCTRL
)
239 // Consumer Audio Control
241 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_CONSUMER") + 1;
245 // add HID_DEVICE_UP:0001_U:0002'
247 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_UP:%04x_U:%04x", CollectionDescription
->UsagePage
, CollectionDescription
->Usage
) + 1;
252 Offset
+=swprintf(&Buffer
[Offset
], L
"HID_DEVICE") + 1;
257 ExFreePoolWithTag((PVOID
)Irp
->IoStatus
.Information
, 0);
262 Ptr
= ExAllocatePoolWithTag(NonPagedPool
, (Offset
+ 1) * sizeof(WCHAR
), HIDCLASS_TAG
);
268 Irp
->IoStatus
.Information
= 0;
269 return STATUS_INSUFFICIENT_RESOURCES
;
275 RtlCopyMemory(Ptr
, Buffer
, Offset
* sizeof(WCHAR
));
276 Ptr
[Offset
] = UNICODE_NULL
;
281 Irp
->IoStatus
.Information
= (ULONG_PTR
)Ptr
;
282 return STATUS_SUCCESS
;
286 HidClassPDO_HandleQueryInstanceId(
287 IN PDEVICE_OBJECT DeviceObject
,
291 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
294 // get device extension
296 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
297 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
302 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, 5 * sizeof(WCHAR
), HIDCLASS_TAG
);
308 return STATUS_INSUFFICIENT_RESOURCES
;
314 swprintf(Buffer
, L
"%04x", PDODeviceExtension
->CollectionNumber
);
315 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
320 return STATUS_SUCCESS
;
324 HidClassPDO_HandleQueryCompatibleId(
325 IN PDEVICE_OBJECT DeviceObject
,
330 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, 2 * sizeof(WCHAR
), HIDCLASS_TAG
);
336 return STATUS_INSUFFICIENT_RESOURCES
;
348 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
349 return STATUS_SUCCESS
;
354 IN PDEVICE_OBJECT DeviceObject
,
357 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
358 PIO_STACK_LOCATION IoStack
;
360 PPNP_BUS_INFORMATION BusInformation
;
361 PDEVICE_RELATIONS DeviceRelation
;
365 // get device extension
367 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
368 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
371 // get current irp stack location
373 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
378 switch (IoStack
->MinorFunction
)
380 case IRP_MN_QUERY_ID
:
382 if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryDeviceID
)
385 // handle query device id
387 Status
= HidClassPDO_HandleQueryDeviceId(DeviceObject
, Irp
);
390 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryHardwareIDs
)
393 // handle instance id
395 Status
= HidClassPDO_HandleQueryHardwareId(DeviceObject
, Irp
);
398 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryInstanceID
)
401 // handle instance id
403 Status
= HidClassPDO_HandleQueryInstanceId(DeviceObject
, Irp
);
406 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryCompatibleIDs
)
409 // handle instance id
411 Status
= HidClassPDO_HandleQueryCompatibleId(DeviceObject
, Irp
);
415 DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack
->Parameters
.QueryId
.IdType
);
416 Status
= STATUS_NOT_SUPPORTED
;
417 Irp
->IoStatus
.Information
= 0;
420 case IRP_MN_QUERY_CAPABILITIES
:
422 if (IoStack
->Parameters
.DeviceCapabilities
.Capabilities
== NULL
)
427 Status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
434 RtlCopyMemory(IoStack
->Parameters
.DeviceCapabilities
.Capabilities
,
435 &PDODeviceExtension
->Capabilities
,
436 sizeof(DEVICE_CAPABILITIES
));
437 Status
= STATUS_SUCCESS
;
440 case IRP_MN_QUERY_BUS_INFORMATION
:
445 BusInformation
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PNP_BUS_INFORMATION
), HIDCLASS_TAG
);
450 RtlCopyMemory(&BusInformation
->BusTypeGuid
, &GUID_BUS_TYPE_HID
, sizeof(GUID
));
451 BusInformation
->LegacyBusType
= PNPBus
;
452 BusInformation
->BusNumber
= 0; //FIXME
457 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInformation
;
458 Status
= STATUS_SUCCESS
;
461 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
464 // FIXME set flags when driver fails / disabled
466 Status
= STATUS_SUCCESS
;
469 case IRP_MN_QUERY_DEVICE_RELATIONS
:
472 // only target relations are supported
474 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
479 Status
= Irp
->IoStatus
.Status
;
484 // allocate device relations
486 DeviceRelation
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_RELATIONS
), HIDCLASS_TAG
);
492 Status
= STATUS_INSUFFICIENT_RESOURCES
;
497 // init device relation
499 DeviceRelation
->Count
= 1;
500 DeviceRelation
->Objects
[0] = DeviceObject
;
501 ObReferenceObject(DeviceRelation
->Objects
[0]);
506 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelation
;
507 Status
= STATUS_SUCCESS
;
510 case IRP_MN_START_DEVICE
:
513 // FIXME: support polled devices
515 ASSERT(PDODeviceExtension
->Common
.DriverExtension
->DevicesArePolled
== FALSE
);
518 // now register the device interface
520 Status
= IoRegisterDeviceInterface(PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
,
521 &GUID_DEVINTERFACE_HID
,
523 &PDODeviceExtension
->DeviceInterface
);
524 DPRINT("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status
);
525 if (NT_SUCCESS(Status
))
528 // enable device interface
530 Status
= IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, TRUE
);
531 DPRINT("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status
);
537 Status
= STATUS_SUCCESS
;
540 case IRP_MN_REMOVE_DEVICE
:
542 /* Disable the device interface */
543 if (PDODeviceExtension
->DeviceInterface
.Length
!= 0)
544 IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, FALSE
);
547 // remove us from the fdo's pdo list
550 for (Index
= 0; Index
< PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
552 if (PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Objects
[Index
] == DeviceObject
)
558 PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Objects
[Index
] = NULL
;
563 /* Complete the IRP */
564 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
565 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
569 /* Delete our device object*/
570 IoDeleteDevice(DeviceObject
);
573 return STATUS_SUCCESS
;
575 case IRP_MN_QUERY_INTERFACE
:
577 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
582 Status
= Irp
->IoStatus
.Status
;
585 case IRP_MN_QUERY_REMOVE_DEVICE
:
586 case IRP_MN_CANCEL_STOP_DEVICE
:
587 case IRP_MN_QUERY_STOP_DEVICE
:
588 case IRP_MN_CANCEL_REMOVE_DEVICE
:
594 Status
= STATUS_SUCCESS
;
596 DPRINT1("Denying removal of HID device due to IRP cancellation bugs\n");
597 Status
= STATUS_UNSUCCESSFUL
;
606 Status
= Irp
->IoStatus
.Status
;
614 if (Status
!= STATUS_PENDING
)
619 Irp
->IoStatus
.Status
= Status
;
624 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
634 HidClassPDO_CreatePDO(
635 IN PDEVICE_OBJECT DeviceObject
,
636 OUT PDEVICE_RELATIONS
*OutDeviceRelations
)
638 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
640 PDEVICE_OBJECT PDODeviceObject
;
641 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
643 PDEVICE_RELATIONS DeviceRelations
;
647 // get device extension
649 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
650 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
653 // first allocate device relations
655 Length
= sizeof(DEVICE_RELATIONS
) + sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
;
656 DeviceRelations
= ExAllocatePoolWithTag(NonPagedPool
, Length
, HIDCLASS_TAG
);
657 if (!DeviceRelations
)
662 return STATUS_INSUFFICIENT_RESOURCES
;
666 // zero device relations
668 RtlZeroMemory(DeviceRelations
, Length
);
671 // let's create a PDO for top level collection
677 // let's create the device object
679 Status
= IoCreateDevice(FDODeviceExtension
->Common
.DriverExtension
->DriverObject
,
680 sizeof(HIDCLASS_PDO_DEVICE_EXTENSION
),
683 FILE_AUTOGENERATED_DEVICE_NAME
,
686 if (!NT_SUCCESS(Status
))
689 // failed to create device
691 DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status
);
698 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
701 // get device extension
703 PDODeviceExtension
= PDODeviceObject
->DeviceExtension
;
706 // init device extension
708 PDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
= FDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
;
709 PDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
;
710 PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
;
711 PDODeviceExtension
->Common
.IsFDO
= FALSE
;
712 PDODeviceExtension
->FDODeviceExtension
= FDODeviceExtension
;
713 PDODeviceExtension
->FDODeviceObject
= DeviceObject
;
714 PDODeviceExtension
->Common
.DriverExtension
= FDODeviceExtension
->Common
.DriverExtension
;
715 PDODeviceExtension
->CollectionNumber
= FDODeviceExtension
->Common
.DeviceDescription
.CollectionDesc
[Index
].CollectionNumber
;
720 RtlCopyMemory(&PDODeviceExtension
->Common
.Attributes
, &FDODeviceExtension
->Common
.Attributes
, sizeof(HID_DEVICE_ATTRIBUTES
));
721 RtlCopyMemory(&PDODeviceExtension
->Common
.DeviceDescription
, &FDODeviceExtension
->Common
.DeviceDescription
, sizeof(HIDP_DEVICE_DESC
));
722 RtlCopyMemory(&PDODeviceExtension
->Capabilities
, &FDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
727 PDODeviceObject
->Flags
|= DO_MAP_IO_BUFFER
;
730 // device is initialized
732 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
735 // store device object in device relations
737 DeviceRelations
->Objects
[Index
] = PDODeviceObject
;
738 DeviceRelations
->Count
++;
745 } while(Index
< FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
);
749 // check if creating succeeded
751 if (!NT_SUCCESS(Status
))
756 for (Index
= 0; Index
< DeviceRelations
->Count
; Index
++)
761 IoDeleteDevice(DeviceRelations
->Objects
[Index
]);
765 // free device relations
767 ExFreePoolWithTag(DeviceRelations
, HIDCLASS_TAG
);
772 // store device relations
774 *OutDeviceRelations
= DeviceRelations
;
779 return STATUS_SUCCESS
;