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)
13 HidClassPDO_GetCollectionDescription(
14 PHIDP_DEVICE_DESC DeviceDescription
,
15 ULONG CollectionNumber
)
19 for(Index
= 0; Index
< DeviceDescription
->CollectionDescLength
; Index
++)
21 if (DeviceDescription
->CollectionDesc
[Index
].CollectionNumber
== CollectionNumber
)
26 return &DeviceDescription
->CollectionDesc
[Index
];
31 // failed to find collection
33 DPRINT1("[HIDCLASS] GetCollectionDescription CollectionNumber %x not found\n", CollectionNumber
);
39 HidClassPDO_GetReportDescription(
40 PHIDP_DEVICE_DESC DeviceDescription
,
41 ULONG CollectionNumber
)
45 for(Index
= 0; Index
< DeviceDescription
->ReportIDsLength
; Index
++)
47 if (DeviceDescription
->ReportIDs
[Index
].CollectionNumber
== CollectionNumber
)
52 return &DeviceDescription
->ReportIDs
[Index
];
57 // failed to find collection
59 DPRINT1("[HIDCLASS] GetReportDescription CollectionNumber %x not found\n", CollectionNumber
);
65 HidClassPDO_HandleQueryDeviceId(
66 IN PDEVICE_OBJECT DeviceObject
,
71 LPWSTR NewBuffer
, Ptr
;
75 // copy current stack location
77 IoCopyCurrentIrpStackLocationToNext(Irp
);
82 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
83 if (!NT_SUCCESS(Status
))
94 Buffer
= (LPWSTR
)Irp
->IoStatus
.Information
;
95 Length
= wcslen(Buffer
);
98 // allocate new buffer
100 NewBuffer
= (LPWSTR
)ExAllocatePool(NonPagedPool
, (Length
+ 1) * sizeof(WCHAR
));
104 // failed to allocate buffer
106 return STATUS_INSUFFICIENT_RESOURCES
;
112 wcscpy(NewBuffer
, L
"HID\\");
115 // get offset to first '\\'
117 Ptr
= wcschr(Buffer
, L
'\\');
123 wcscat(NewBuffer
, Ptr
+ 1);
134 DPRINT1("NewBuffer %S\n", NewBuffer
);
135 Irp
->IoStatus
.Information
= (ULONG_PTR
)NewBuffer
;
136 return STATUS_SUCCESS
;
140 HidClassPDO_HandleQueryHardwareId(
141 IN PDEVICE_OBJECT DeviceObject
,
145 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
149 PHIDP_COLLECTION_DESC CollectionDescription
;
152 // get device extension
154 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
155 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
158 // copy current stack location
160 IoCopyCurrentIrpStackLocationToNext(Irp
);
165 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
166 if (!NT_SUCCESS(Status
))
174 if (PDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
> 1)
179 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;
180 Offset
+= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x&Col%02x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
, PDODeviceExtension
->CollectionNumber
) + 1;
187 Offset
= swprintf(&Buffer
[Offset
], L
"HID\\Vix_%04x&Pid_%04x&Rev_%04x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
, PDODeviceExtension
->Common
.Attributes
.VersionNumber
) + 1;
188 Offset
+= swprintf(&Buffer
[Offset
], L
"HID\\Vix_%04x&Pid_%04x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
) + 1;
192 // get collection description
194 CollectionDescription
= HidClassPDO_GetCollectionDescription(&PDODeviceExtension
->Common
.DeviceDescription
, PDODeviceExtension
->CollectionNumber
);
195 ASSERT(CollectionDescription
);
197 if (CollectionDescription
->UsagePage
== HID_USAGE_PAGE_GENERIC
)
199 switch(CollectionDescription
->Usage
)
201 case HID_USAGE_GENERIC_POINTER
:
202 case HID_USAGE_GENERIC_MOUSE
:
206 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_MOUSE") + 1;
208 case HID_USAGE_GENERIC_GAMEPAD
:
209 case HID_USAGE_GENERIC_JOYSTICK
:
211 // Joystick / Gamepad
213 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_GAME") + 1;
215 case HID_USAGE_GENERIC_KEYBOARD
:
216 case HID_USAGE_GENERIC_KEYPAD
:
220 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_KEYBOARD") + 1;
222 case HID_USAGE_GENERIC_SYSTEM_CTL
:
226 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_CONTROL") + 1;
230 else if (CollectionDescription
->UsagePage
== HID_USAGE_PAGE_CONSUMER
&& CollectionDescription
->Usage
== HID_USAGE_CONSUMERCTRL
)
233 // Consumer Audio Control
235 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_CONSUMER") + 1;
239 // FIXME: add 'HID_DEVICE_UP:0001_U:0002'
245 Offset
+=swprintf(&Buffer
[Offset
], L
"HID_DEVICE") + 1;
250 ExFreePool((PVOID
)Irp
->IoStatus
.Information
);
255 Ptr
= (LPWSTR
)ExAllocatePool(NonPagedPool
, (Offset
+1)* sizeof(WCHAR
));
261 Irp
->IoStatus
.Information
= 0;
262 return STATUS_INSUFFICIENT_RESOURCES
;
268 RtlCopyMemory(Ptr
, Buffer
, Offset
* sizeof(WCHAR
));
269 Ptr
[Offset
] = UNICODE_NULL
;
274 Irp
->IoStatus
.Information
= (ULONG_PTR
)Ptr
;
275 return STATUS_SUCCESS
;
279 HidClassPDO_HandleQueryInstanceId(
280 IN PDEVICE_OBJECT DeviceObject
,
286 // copy current stack location
288 IoCopyCurrentIrpStackLocationToNext(Irp
);
293 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
294 if (!NT_SUCCESS(Status
))
301 DPRINT1("HidClassPDO_HandleQueryInstanceId Buffer %S\n", Irp
->IoStatus
.Information
);
306 HidClassPDO_HandleQueryCompatibleId(
307 IN PDEVICE_OBJECT DeviceObject
,
312 Buffer
= (LPWSTR
)ExAllocatePool(NonPagedPool
, 2 * sizeof(WCHAR
));
318 return STATUS_INSUFFICIENT_RESOURCES
;
330 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
331 return STATUS_SUCCESS
;
337 IN PDEVICE_OBJECT DeviceObject
,
340 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
341 PIO_STACK_LOCATION IoStack
;
343 PPNP_BUS_INFORMATION BusInformation
;
344 PDEVICE_RELATIONS DeviceRelation
;
347 // get device extension
349 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
350 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
353 // get current irp stack location
355 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
360 switch(IoStack
->MinorFunction
)
362 case IRP_MN_QUERY_ID
:
364 if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryDeviceID
)
367 // handle query device id
369 Status
= HidClassPDO_HandleQueryDeviceId(DeviceObject
, Irp
);
372 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryHardwareIDs
)
375 // handle instance id
377 Status
= HidClassPDO_HandleQueryHardwareId(DeviceObject
, Irp
);
380 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryInstanceID
)
383 // handle instance id
385 Status
= HidClassPDO_HandleQueryInstanceId(DeviceObject
, Irp
);
388 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryCompatibleIDs
)
391 // handle instance id
393 Status
= HidClassPDO_HandleQueryCompatibleId(DeviceObject
, Irp
);
397 DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack
->Parameters
.QueryId
.IdType
);
398 Status
= STATUS_NOT_SUPPORTED
;
399 Irp
->IoStatus
.Information
= 0;
402 case IRP_MN_QUERY_CAPABILITIES
:
404 if (IoStack
->Parameters
.DeviceCapabilities
.Capabilities
== NULL
)
409 Status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
415 RtlCopyMemory(IoStack
->Parameters
.DeviceCapabilities
.Capabilities
, &PDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
416 Status
= STATUS_SUCCESS
;
419 case IRP_MN_QUERY_BUS_INFORMATION
:
424 BusInformation
= (PPNP_BUS_INFORMATION
)ExAllocatePool(NonPagedPool
, sizeof(PNP_BUS_INFORMATION
));
429 RtlCopyMemory(&BusInformation
->BusTypeGuid
, &GUID_BUS_TYPE_HID
, sizeof(GUID
));
430 BusInformation
->LegacyBusType
= PNPBus
;
431 BusInformation
->BusNumber
= 0; //FIXME
436 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInformation
;
437 Status
= STATUS_SUCCESS
;
440 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
443 // FIXME set flags when driver fails / disabled
445 Status
= STATUS_SUCCESS
;
448 case IRP_MN_QUERY_DEVICE_RELATIONS
:
451 // only target relations are supported
453 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
458 Status
= Irp
->IoStatus
.Status
;
463 // allocate device relations
465 DeviceRelation
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_RELATIONS
));
471 Status
= STATUS_INSUFFICIENT_RESOURCES
;
476 // init device relation
478 DeviceRelation
->Count
= 1;
479 DeviceRelation
->Objects
[0] = DeviceObject
;
480 ObReferenceObject(DeviceRelation
->Objects
[0]);
485 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelation
;
486 Status
= STATUS_SUCCESS
;
489 case IRP_MN_START_DEVICE
:
492 // FIXME: support polled devices
494 ASSERT(PDODeviceExtension
->Common
.DriverExtension
->DevicesArePolled
== FALSE
);
497 // now register the device interface
499 Status
= IoRegisterDeviceInterface(PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
, &GUID_DEVINTERFACE_HID
, NULL
, &PDODeviceExtension
->DeviceInterface
);
500 DPRINT1("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status
);
501 if (NT_SUCCESS(Status
))
504 // enable device interface
506 Status
= IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, TRUE
);
507 DPRINT1("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status
);
509 ASSERT(Status
== STATUS_SUCCESS
);
515 case IRP_MN_REMOVE_DEVICE
:
517 DPRINT1("[HIDCLASS] PDO IRP_MN_REMOVE_DEVICE not implemented\n");
523 Status
= STATUS_SUCCESS
; //Irp->IoStatus.Status;
526 case IRP_MN_QUERY_INTERFACE
:
528 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
534 Status
= Irp
->IoStatus
.Status
;
542 Status
= Irp
->IoStatus
.Status
;
550 if (Status
!= STATUS_PENDING
)
555 Irp
->IoStatus
.Status
= Status
;
560 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
570 HidClassPDO_CreatePDO(
571 IN PDEVICE_OBJECT DeviceObject
,
572 OUT PDEVICE_RELATIONS
*OutDeviceRelations
)
574 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
576 PDEVICE_OBJECT PDODeviceObject
;
577 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
579 PDEVICE_RELATIONS DeviceRelations
;
583 // get device extension
585 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
586 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
589 // first allocate device relations
591 Length
= sizeof(DEVICE_RELATIONS
) + sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
;
592 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, Length
);
593 if (!DeviceRelations
)
598 return STATUS_INSUFFICIENT_RESOURCES
;
602 // zero device relations
604 RtlZeroMemory(DeviceRelations
, Length
);
607 // lets create a PDO for top level collection
613 // lets create the device object
615 Status
= IoCreateDevice(FDODeviceExtension
->Common
.DriverExtension
->DriverObject
, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_UNKNOWN
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &PDODeviceObject
);
616 if (!NT_SUCCESS(Status
))
619 // failed to create device
621 DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status
);
628 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
631 // get device extension
633 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)PDODeviceObject
->DeviceExtension
;
636 // init device extension
638 PDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
= FDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
;
639 PDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
;
640 PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
;
641 PDODeviceExtension
->Common
.IsFDO
= FALSE
;
642 PDODeviceExtension
->FDODeviceObject
= DeviceObject
;
643 PDODeviceExtension
->Common
.DriverExtension
= FDODeviceExtension
->Common
.DriverExtension
;
644 PDODeviceExtension
->CollectionNumber
= FDODeviceExtension
->Common
.DeviceDescription
.CollectionDesc
[Index
].CollectionNumber
;
649 RtlCopyMemory(&PDODeviceExtension
->Common
.Attributes
, &FDODeviceExtension
->Common
.Attributes
, sizeof(HID_DEVICE_ATTRIBUTES
));
650 RtlCopyMemory(&PDODeviceExtension
->Common
.DeviceDescription
, &FDODeviceExtension
->Common
.DeviceDescription
, sizeof(HIDP_DEVICE_DESC
));
651 RtlCopyMemory(&PDODeviceExtension
->Capabilities
, &FDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
656 PDODeviceObject
->Flags
|= DO_MAP_IO_BUFFER
;
659 // device is initialized
661 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
664 // store device object in device relations
666 DeviceRelations
->Objects
[Index
] = PDODeviceObject
;
667 DeviceRelations
->Count
++;
674 }while(Index
< FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
);
678 // check if creating succeeded
680 if (!NT_SUCCESS(Status
))
685 for(Index
= 0; Index
< DeviceRelations
->Count
; Index
++)
690 IoDeleteDevice(DeviceRelations
->Objects
[Index
]);
694 // free device relations
696 ExFreePool(DeviceRelations
);
701 // store device relations
703 *OutDeviceRelations
= DeviceRelations
;
708 return STATUS_SUCCESS
;