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 DPRINT("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\\Vid_%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\\Vid_%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 // add HID_DEVICE_UP:0001_U:0002'
241 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_UP:%04x_U:%04x", CollectionDescription
->UsagePage
, CollectionDescription
->Usage
) + 1;
246 Offset
+=swprintf(&Buffer
[Offset
], L
"HID_DEVICE") + 1;
251 ExFreePool((PVOID
)Irp
->IoStatus
.Information
);
256 Ptr
= (LPWSTR
)ExAllocatePool(NonPagedPool
, (Offset
+1)* sizeof(WCHAR
));
262 Irp
->IoStatus
.Information
= 0;
263 return STATUS_INSUFFICIENT_RESOURCES
;
269 RtlCopyMemory(Ptr
, Buffer
, Offset
* sizeof(WCHAR
));
270 Ptr
[Offset
] = UNICODE_NULL
;
275 Irp
->IoStatus
.Information
= (ULONG_PTR
)Ptr
;
276 return STATUS_SUCCESS
;
280 HidClassPDO_HandleQueryInstanceId(
281 IN PDEVICE_OBJECT DeviceObject
,
285 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
288 // get device extension
290 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
291 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
297 Buffer
= ExAllocatePool(NonPagedPool
, 5 * sizeof(WCHAR
));
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
= (LPWSTR
)ExAllocatePool(NonPagedPool
, 2 * sizeof(WCHAR
));
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
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)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
, &PDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
430 Status
= STATUS_SUCCESS
;
433 case IRP_MN_QUERY_BUS_INFORMATION
:
438 BusInformation
= (PPNP_BUS_INFORMATION
)ExAllocatePool(NonPagedPool
, sizeof(PNP_BUS_INFORMATION
));
443 RtlCopyMemory(&BusInformation
->BusTypeGuid
, &GUID_BUS_TYPE_HID
, sizeof(GUID
));
444 BusInformation
->LegacyBusType
= PNPBus
;
445 BusInformation
->BusNumber
= 0; //FIXME
450 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInformation
;
451 Status
= STATUS_SUCCESS
;
454 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
457 // FIXME set flags when driver fails / disabled
459 Status
= STATUS_SUCCESS
;
462 case IRP_MN_QUERY_DEVICE_RELATIONS
:
465 // only target relations are supported
467 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
472 Status
= Irp
->IoStatus
.Status
;
477 // allocate device relations
479 DeviceRelation
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_RELATIONS
));
485 Status
= STATUS_INSUFFICIENT_RESOURCES
;
490 // init device relation
492 DeviceRelation
->Count
= 1;
493 DeviceRelation
->Objects
[0] = DeviceObject
;
494 ObReferenceObject(DeviceRelation
->Objects
[0]);
499 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelation
;
500 Status
= STATUS_SUCCESS
;
503 case IRP_MN_START_DEVICE
:
506 // FIXME: support polled devices
508 ASSERT(PDODeviceExtension
->Common
.DriverExtension
->DevicesArePolled
== FALSE
);
511 // now register the device interface
513 Status
= IoRegisterDeviceInterface(PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
, &GUID_DEVINTERFACE_HID
, NULL
, &PDODeviceExtension
->DeviceInterface
);
514 DPRINT("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status
);
515 if (NT_SUCCESS(Status
))
518 // enable device interface
520 Status
= IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, TRUE
);
521 DPRINT("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status
);
527 Status
= STATUS_SUCCESS
;
530 case IRP_MN_REMOVE_DEVICE
:
532 /* Disable the device interface */
533 if (PDODeviceExtension
->DeviceInterface
.Length
!= 0)
534 IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, FALSE
);
537 // remove us from the fdo's pdo list
540 for(Index
= 0; Index
< PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
542 if (PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Objects
[Index
] == DeviceObject
)
548 PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Objects
[Index
] = NULL
;
553 /* Complete the IRP */
554 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
555 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
559 /* Delete our device object*/
560 IoDeleteDevice(DeviceObject
);
563 return STATUS_SUCCESS
;
565 case IRP_MN_QUERY_INTERFACE
:
567 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
573 Status
= Irp
->IoStatus
.Status
;
576 case IRP_MN_QUERY_REMOVE_DEVICE
:
577 case IRP_MN_CANCEL_STOP_DEVICE
:
578 case IRP_MN_QUERY_STOP_DEVICE
:
579 case IRP_MN_CANCEL_REMOVE_DEVICE
:
585 Status
= STATUS_SUCCESS
;
587 DPRINT1("Denying removal of HID device due to IRP cancellation bugs\n");
588 Status
= STATUS_UNSUCCESSFUL
;
597 Status
= Irp
->IoStatus
.Status
;
605 if (Status
!= STATUS_PENDING
)
610 Irp
->IoStatus
.Status
= Status
;
615 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
625 HidClassPDO_CreatePDO(
626 IN PDEVICE_OBJECT DeviceObject
,
627 OUT PDEVICE_RELATIONS
*OutDeviceRelations
)
629 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
631 PDEVICE_OBJECT PDODeviceObject
;
632 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
634 PDEVICE_RELATIONS DeviceRelations
;
638 // get device extension
640 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
641 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
644 // first allocate device relations
646 Length
= sizeof(DEVICE_RELATIONS
) + sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
;
647 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, Length
);
648 if (!DeviceRelations
)
653 return STATUS_INSUFFICIENT_RESOURCES
;
657 // zero device relations
659 RtlZeroMemory(DeviceRelations
, Length
);
662 // lets create a PDO for top level collection
668 // lets create the device object
670 Status
= IoCreateDevice(FDODeviceExtension
->Common
.DriverExtension
->DriverObject
, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_UNKNOWN
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &PDODeviceObject
);
671 if (!NT_SUCCESS(Status
))
674 // failed to create device
676 DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status
);
683 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
686 // get device extension
688 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)PDODeviceObject
->DeviceExtension
;
691 // init device extension
693 PDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
= FDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
;
694 PDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
;
695 PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
;
696 PDODeviceExtension
->Common
.IsFDO
= FALSE
;
697 PDODeviceExtension
->FDODeviceExtension
= FDODeviceExtension
;
698 PDODeviceExtension
->FDODeviceObject
= DeviceObject
;
699 PDODeviceExtension
->Common
.DriverExtension
= FDODeviceExtension
->Common
.DriverExtension
;
700 PDODeviceExtension
->CollectionNumber
= FDODeviceExtension
->Common
.DeviceDescription
.CollectionDesc
[Index
].CollectionNumber
;
705 RtlCopyMemory(&PDODeviceExtension
->Common
.Attributes
, &FDODeviceExtension
->Common
.Attributes
, sizeof(HID_DEVICE_ATTRIBUTES
));
706 RtlCopyMemory(&PDODeviceExtension
->Common
.DeviceDescription
, &FDODeviceExtension
->Common
.DeviceDescription
, sizeof(HIDP_DEVICE_DESC
));
707 RtlCopyMemory(&PDODeviceExtension
->Capabilities
, &FDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
712 PDODeviceObject
->Flags
|= DO_MAP_IO_BUFFER
;
715 // device is initialized
717 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
720 // store device object in device relations
722 DeviceRelations
->Objects
[Index
] = PDODeviceObject
;
723 DeviceRelations
->Count
++;
730 }while(Index
< FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
);
734 // check if creating succeeded
736 if (!NT_SUCCESS(Status
))
741 for(Index
= 0; Index
< DeviceRelations
->Count
; Index
++)
746 IoDeleteDevice(DeviceRelations
->Objects
[Index
]);
750 // free device relations
752 ExFreePool(DeviceRelations
);
757 // store device relations
759 *OutDeviceRelations
= DeviceRelations
;
764 return STATUS_SUCCESS
;