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 HidClassPDO_GetCollectionDescription(
15 PHIDP_DEVICE_DESC DeviceDescription
,
16 ULONG CollectionNumber
)
20 for(Index
= 0; Index
< DeviceDescription
->CollectionDescLength
; Index
++)
22 if (DeviceDescription
->CollectionDesc
[Index
].CollectionNumber
== CollectionNumber
)
27 return &DeviceDescription
->CollectionDesc
[Index
];
32 // failed to find collection
34 DPRINT1("[HIDCLASS] GetCollectionDescription CollectionNumber %x not found\n", CollectionNumber
);
40 HidClassPDO_GetReportDescription(
41 PHIDP_DEVICE_DESC DeviceDescription
,
42 ULONG CollectionNumber
)
46 for (Index
= 0; Index
< DeviceDescription
->ReportIDsLength
; Index
++)
48 if (DeviceDescription
->ReportIDs
[Index
].CollectionNumber
== CollectionNumber
)
53 return &DeviceDescription
->ReportIDs
[Index
];
58 // failed to find collection
60 DPRINT1("[HIDCLASS] GetReportDescription CollectionNumber %x not found\n", CollectionNumber
);
66 HidClassPDO_HandleQueryDeviceId(
67 IN PDEVICE_OBJECT DeviceObject
,
72 LPWSTR NewBuffer
, Ptr
;
76 // copy current stack location
78 IoCopyCurrentIrpStackLocationToNext(Irp
);
83 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
84 if (!NT_SUCCESS(Status
))
95 Buffer
= (LPWSTR
)Irp
->IoStatus
.Information
;
96 Length
= wcslen(Buffer
);
99 // allocate new buffer
101 NewBuffer
= ExAllocatePoolWithTag(NonPagedPool
, (Length
+ 1) * sizeof(WCHAR
), HIDCLASS_TAG
);
105 // failed to allocate buffer
107 return STATUS_INSUFFICIENT_RESOURCES
;
113 wcscpy(NewBuffer
, L
"HID\\");
116 // get offset to first '\\'
118 Ptr
= wcschr(Buffer
, L
'\\');
124 wcscat(NewBuffer
, Ptr
+ 1);
130 ExFreePoolWithTag(Buffer
, 0);
135 DPRINT("NewBuffer %S\n", NewBuffer
);
136 Irp
->IoStatus
.Information
= (ULONG_PTR
)NewBuffer
;
137 return STATUS_SUCCESS
;
141 HidClassPDO_HandleQueryHardwareId(
142 IN PDEVICE_OBJECT DeviceObject
,
146 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
150 PHIDP_COLLECTION_DESC CollectionDescription
;
153 // get device extension
155 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
156 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
159 // copy current stack location
161 IoCopyCurrentIrpStackLocationToNext(Irp
);
166 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
167 if (!NT_SUCCESS(Status
))
175 if (PDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
> 1)
180 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;
181 Offset
+= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x&Col%02x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
, PDODeviceExtension
->CollectionNumber
) + 1;
188 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;
189 Offset
+= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
) + 1;
193 // get collection description
195 CollectionDescription
= HidClassPDO_GetCollectionDescription(&PDODeviceExtension
->Common
.DeviceDescription
, PDODeviceExtension
->CollectionNumber
);
196 ASSERT(CollectionDescription
);
198 if (CollectionDescription
->UsagePage
== HID_USAGE_PAGE_GENERIC
)
200 switch (CollectionDescription
->Usage
)
202 case HID_USAGE_GENERIC_POINTER
:
203 case HID_USAGE_GENERIC_MOUSE
:
207 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_MOUSE") + 1;
209 case HID_USAGE_GENERIC_GAMEPAD
:
210 case HID_USAGE_GENERIC_JOYSTICK
:
212 // Joystick / Gamepad
214 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_GAME") + 1;
216 case HID_USAGE_GENERIC_KEYBOARD
:
217 case HID_USAGE_GENERIC_KEYPAD
:
221 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_KEYBOARD") + 1;
223 case HID_USAGE_GENERIC_SYSTEM_CTL
:
227 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_CONTROL") + 1;
231 else if (CollectionDescription
->UsagePage
== HID_USAGE_PAGE_CONSUMER
&& CollectionDescription
->Usage
== HID_USAGE_CONSUMERCTRL
)
234 // Consumer Audio Control
236 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_CONSUMER") + 1;
240 // add HID_DEVICE_UP:0001_U:0002'
242 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_UP:%04x_U:%04x", CollectionDescription
->UsagePage
, CollectionDescription
->Usage
) + 1;
247 Offset
+=swprintf(&Buffer
[Offset
], L
"HID_DEVICE") + 1;
252 ExFreePoolWithTag((PVOID
)Irp
->IoStatus
.Information
, 0);
257 Ptr
= ExAllocatePoolWithTag(NonPagedPool
, (Offset
+ 1) * sizeof(WCHAR
), HIDCLASS_TAG
);
263 Irp
->IoStatus
.Information
= 0;
264 return STATUS_INSUFFICIENT_RESOURCES
;
270 RtlCopyMemory(Ptr
, Buffer
, Offset
* sizeof(WCHAR
));
271 Ptr
[Offset
] = UNICODE_NULL
;
276 Irp
->IoStatus
.Information
= (ULONG_PTR
)Ptr
;
277 return STATUS_SUCCESS
;
281 HidClassPDO_HandleQueryInstanceId(
282 IN PDEVICE_OBJECT DeviceObject
,
286 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
289 // get device extension
291 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
292 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
297 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, 5 * sizeof(WCHAR
), HIDCLASS_TAG
);
303 return STATUS_INSUFFICIENT_RESOURCES
;
309 swprintf(Buffer
, L
"%04x", PDODeviceExtension
->CollectionNumber
);
310 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
315 return STATUS_SUCCESS
;
319 HidClassPDO_HandleQueryCompatibleId(
320 IN PDEVICE_OBJECT DeviceObject
,
325 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, 2 * sizeof(WCHAR
), HIDCLASS_TAG
);
331 return STATUS_INSUFFICIENT_RESOURCES
;
343 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
344 return STATUS_SUCCESS
;
349 IN PDEVICE_OBJECT DeviceObject
,
352 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
353 PIO_STACK_LOCATION IoStack
;
355 PPNP_BUS_INFORMATION BusInformation
;
356 PDEVICE_RELATIONS DeviceRelation
;
360 // get device extension
362 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
363 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
366 // get current irp stack location
368 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
373 switch (IoStack
->MinorFunction
)
375 case IRP_MN_QUERY_ID
:
377 if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryDeviceID
)
380 // handle query device id
382 Status
= HidClassPDO_HandleQueryDeviceId(DeviceObject
, Irp
);
385 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryHardwareIDs
)
388 // handle instance id
390 Status
= HidClassPDO_HandleQueryHardwareId(DeviceObject
, Irp
);
393 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryInstanceID
)
396 // handle instance id
398 Status
= HidClassPDO_HandleQueryInstanceId(DeviceObject
, Irp
);
401 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryCompatibleIDs
)
404 // handle instance id
406 Status
= HidClassPDO_HandleQueryCompatibleId(DeviceObject
, Irp
);
410 DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack
->Parameters
.QueryId
.IdType
);
411 Status
= STATUS_NOT_SUPPORTED
;
412 Irp
->IoStatus
.Information
= 0;
415 case IRP_MN_QUERY_CAPABILITIES
:
417 if (IoStack
->Parameters
.DeviceCapabilities
.Capabilities
== NULL
)
422 Status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
429 RtlCopyMemory(IoStack
->Parameters
.DeviceCapabilities
.Capabilities
,
430 &PDODeviceExtension
->Capabilities
,
431 sizeof(DEVICE_CAPABILITIES
));
432 Status
= STATUS_SUCCESS
;
435 case IRP_MN_QUERY_BUS_INFORMATION
:
440 BusInformation
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PNP_BUS_INFORMATION
), HIDCLASS_TAG
);
445 RtlCopyMemory(&BusInformation
->BusTypeGuid
, &GUID_BUS_TYPE_HID
, sizeof(GUID
));
446 BusInformation
->LegacyBusType
= PNPBus
;
447 BusInformation
->BusNumber
= 0; //FIXME
452 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInformation
;
453 Status
= STATUS_SUCCESS
;
456 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
459 // FIXME set flags when driver fails / disabled
461 Status
= STATUS_SUCCESS
;
464 case IRP_MN_QUERY_DEVICE_RELATIONS
:
467 // only target relations are supported
469 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
474 Status
= Irp
->IoStatus
.Status
;
479 // allocate device relations
481 DeviceRelation
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_RELATIONS
), HIDCLASS_TAG
);
487 Status
= STATUS_INSUFFICIENT_RESOURCES
;
492 // init device relation
494 DeviceRelation
->Count
= 1;
495 DeviceRelation
->Objects
[0] = DeviceObject
;
496 ObReferenceObject(DeviceRelation
->Objects
[0]);
501 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelation
;
502 Status
= STATUS_SUCCESS
;
505 case IRP_MN_START_DEVICE
:
508 // FIXME: support polled devices
510 ASSERT(PDODeviceExtension
->Common
.DriverExtension
->DevicesArePolled
== FALSE
);
513 // now register the device interface
515 Status
= IoRegisterDeviceInterface(PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
,
516 &GUID_DEVINTERFACE_HID
,
518 &PDODeviceExtension
->DeviceInterface
);
519 DPRINT("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status
);
520 if (NT_SUCCESS(Status
))
523 // enable device interface
525 Status
= IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, TRUE
);
526 DPRINT("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status
);
532 Status
= STATUS_SUCCESS
;
535 case IRP_MN_REMOVE_DEVICE
:
537 /* Disable the device interface */
538 if (PDODeviceExtension
->DeviceInterface
.Length
!= 0)
539 IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, FALSE
);
542 // remove us from the fdo's pdo list
545 for (Index
= 0; Index
< PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
547 if (PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Objects
[Index
] == DeviceObject
)
553 PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Objects
[Index
] = NULL
;
558 /* Complete the IRP */
559 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
560 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
564 /* Delete our device object*/
565 IoDeleteDevice(DeviceObject
);
568 return STATUS_SUCCESS
;
570 case IRP_MN_QUERY_INTERFACE
:
572 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
577 Status
= Irp
->IoStatus
.Status
;
580 case IRP_MN_QUERY_REMOVE_DEVICE
:
581 case IRP_MN_CANCEL_STOP_DEVICE
:
582 case IRP_MN_QUERY_STOP_DEVICE
:
583 case IRP_MN_CANCEL_REMOVE_DEVICE
:
589 Status
= STATUS_SUCCESS
;
591 DPRINT1("Denying removal of HID device due to IRP cancellation bugs\n");
592 Status
= STATUS_UNSUCCESSFUL
;
601 Status
= Irp
->IoStatus
.Status
;
609 if (Status
!= STATUS_PENDING
)
614 Irp
->IoStatus
.Status
= Status
;
619 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
629 HidClassPDO_CreatePDO(
630 IN PDEVICE_OBJECT DeviceObject
,
631 OUT PDEVICE_RELATIONS
*OutDeviceRelations
)
633 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
635 PDEVICE_OBJECT PDODeviceObject
;
636 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
638 PDEVICE_RELATIONS DeviceRelations
;
642 // get device extension
644 FDODeviceExtension
= DeviceObject
->DeviceExtension
;
645 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
648 // first allocate device relations
650 Length
= sizeof(DEVICE_RELATIONS
) + sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
;
651 DeviceRelations
= ExAllocatePoolWithTag(NonPagedPool
, Length
, HIDCLASS_TAG
);
652 if (!DeviceRelations
)
657 return STATUS_INSUFFICIENT_RESOURCES
;
661 // zero device relations
663 RtlZeroMemory(DeviceRelations
, Length
);
666 // let's create a PDO for top level collection
672 // let's create the device object
674 Status
= IoCreateDevice(FDODeviceExtension
->Common
.DriverExtension
->DriverObject
,
675 sizeof(HIDCLASS_PDO_DEVICE_EXTENSION
),
678 FILE_AUTOGENERATED_DEVICE_NAME
,
681 if (!NT_SUCCESS(Status
))
684 // failed to create device
686 DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status
);
693 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
696 // get device extension
698 PDODeviceExtension
= PDODeviceObject
->DeviceExtension
;
701 // init device extension
703 PDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
= FDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
;
704 PDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
;
705 PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
;
706 PDODeviceExtension
->Common
.IsFDO
= FALSE
;
707 PDODeviceExtension
->FDODeviceExtension
= FDODeviceExtension
;
708 PDODeviceExtension
->FDODeviceObject
= DeviceObject
;
709 PDODeviceExtension
->Common
.DriverExtension
= FDODeviceExtension
->Common
.DriverExtension
;
710 PDODeviceExtension
->CollectionNumber
= FDODeviceExtension
->Common
.DeviceDescription
.CollectionDesc
[Index
].CollectionNumber
;
715 RtlCopyMemory(&PDODeviceExtension
->Common
.Attributes
, &FDODeviceExtension
->Common
.Attributes
, sizeof(HID_DEVICE_ATTRIBUTES
));
716 RtlCopyMemory(&PDODeviceExtension
->Common
.DeviceDescription
, &FDODeviceExtension
->Common
.DeviceDescription
, sizeof(HIDP_DEVICE_DESC
));
717 RtlCopyMemory(&PDODeviceExtension
->Capabilities
, &FDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
722 PDODeviceObject
->Flags
|= DO_MAP_IO_BUFFER
;
725 // device is initialized
727 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
730 // store device object in device relations
732 DeviceRelations
->Objects
[Index
] = PDODeviceObject
;
733 DeviceRelations
->Count
++;
740 } while(Index
< FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
);
744 // check if creating succeeded
746 if (!NT_SUCCESS(Status
))
751 for (Index
= 0; Index
< DeviceRelations
->Count
; Index
++)
756 IoDeleteDevice(DeviceRelations
->Objects
[Index
]);
760 // free device relations
762 ExFreePoolWithTag(DeviceRelations
, HIDCLASS_TAG
);
767 // store device relations
769 *OutDeviceRelations
= DeviceRelations
;
774 return STATUS_SUCCESS
;