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\\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
;
428 RtlCopyMemory(IoStack
->Parameters
.DeviceCapabilities
.Capabilities
, &PDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
429 Status
= STATUS_SUCCESS
;
432 case IRP_MN_QUERY_BUS_INFORMATION
:
437 BusInformation
= (PPNP_BUS_INFORMATION
)ExAllocatePool(NonPagedPool
, sizeof(PNP_BUS_INFORMATION
));
442 RtlCopyMemory(&BusInformation
->BusTypeGuid
, &GUID_BUS_TYPE_HID
, sizeof(GUID
));
443 BusInformation
->LegacyBusType
= PNPBus
;
444 BusInformation
->BusNumber
= 0; //FIXME
449 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInformation
;
450 Status
= STATUS_SUCCESS
;
453 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
456 // FIXME set flags when driver fails / disabled
458 Status
= STATUS_SUCCESS
;
461 case IRP_MN_QUERY_DEVICE_RELATIONS
:
464 // only target relations are supported
466 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
471 Status
= Irp
->IoStatus
.Status
;
476 // allocate device relations
478 DeviceRelation
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_RELATIONS
));
484 Status
= STATUS_INSUFFICIENT_RESOURCES
;
489 // init device relation
491 DeviceRelation
->Count
= 1;
492 DeviceRelation
->Objects
[0] = DeviceObject
;
493 ObReferenceObject(DeviceRelation
->Objects
[0]);
498 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelation
;
499 Status
= STATUS_SUCCESS
;
502 case IRP_MN_START_DEVICE
:
505 // FIXME: support polled devices
507 ASSERT(PDODeviceExtension
->Common
.DriverExtension
->DevicesArePolled
== FALSE
);
510 // now register the device interface
512 Status
= IoRegisterDeviceInterface(PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
, &GUID_DEVINTERFACE_HID
, NULL
, &PDODeviceExtension
->DeviceInterface
);
513 DPRINT1("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status
);
514 if (NT_SUCCESS(Status
))
517 // enable device interface
519 Status
= IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, TRUE
);
520 DPRINT1("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status
);
526 Status
= STATUS_SUCCESS
;
529 case IRP_MN_REMOVE_DEVICE
:
531 /* Disable the device interface */
532 if (PDODeviceExtension
->DeviceInterface
.Length
!= 0)
533 IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, FALSE
);
536 // remove us from the fdo's pdo list
539 for(Index
= 0; Index
< PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Count
; Index
++)
541 if (PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Objects
[Index
] == DeviceObject
)
547 PDODeviceExtension
->FDODeviceExtension
->DeviceRelations
->Objects
[Index
] = NULL
;
552 /* Complete the IRP */
553 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
554 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
558 /* Delete our device object*/
559 IoDeleteDevice(DeviceObject
);
562 return STATUS_SUCCESS
;
564 case IRP_MN_QUERY_INTERFACE
:
566 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
572 Status
= Irp
->IoStatus
.Status
;
575 case IRP_MN_QUERY_REMOVE_DEVICE
:
576 case IRP_MN_CANCEL_STOP_DEVICE
:
577 case IRP_MN_QUERY_STOP_DEVICE
:
578 case IRP_MN_CANCEL_REMOVE_DEVICE
:
583 Status
= STATUS_SUCCESS
;
591 Status
= Irp
->IoStatus
.Status
;
599 if (Status
!= STATUS_PENDING
)
604 Irp
->IoStatus
.Status
= Status
;
609 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
619 HidClassPDO_CreatePDO(
620 IN PDEVICE_OBJECT DeviceObject
,
621 OUT PDEVICE_RELATIONS
*OutDeviceRelations
)
623 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
625 PDEVICE_OBJECT PDODeviceObject
;
626 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
628 PDEVICE_RELATIONS DeviceRelations
;
632 // get device extension
634 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
635 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
638 // first allocate device relations
640 Length
= sizeof(DEVICE_RELATIONS
) + sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
;
641 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, Length
);
642 if (!DeviceRelations
)
647 return STATUS_INSUFFICIENT_RESOURCES
;
651 // zero device relations
653 RtlZeroMemory(DeviceRelations
, Length
);
656 // lets create a PDO for top level collection
662 // lets create the device object
664 Status
= IoCreateDevice(FDODeviceExtension
->Common
.DriverExtension
->DriverObject
, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_UNKNOWN
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &PDODeviceObject
);
665 if (!NT_SUCCESS(Status
))
668 // failed to create device
670 DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status
);
677 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
680 // get device extension
682 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)PDODeviceObject
->DeviceExtension
;
685 // init device extension
687 PDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
= FDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
;
688 PDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
;
689 PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
;
690 PDODeviceExtension
->Common
.IsFDO
= FALSE
;
691 PDODeviceExtension
->FDODeviceExtension
= FDODeviceExtension
;
692 PDODeviceExtension
->FDODeviceObject
= DeviceObject
;
693 PDODeviceExtension
->Common
.DriverExtension
= FDODeviceExtension
->Common
.DriverExtension
;
694 PDODeviceExtension
->CollectionNumber
= FDODeviceExtension
->Common
.DeviceDescription
.CollectionDesc
[Index
].CollectionNumber
;
699 RtlCopyMemory(&PDODeviceExtension
->Common
.Attributes
, &FDODeviceExtension
->Common
.Attributes
, sizeof(HID_DEVICE_ATTRIBUTES
));
700 RtlCopyMemory(&PDODeviceExtension
->Common
.DeviceDescription
, &FDODeviceExtension
->Common
.DeviceDescription
, sizeof(HIDP_DEVICE_DESC
));
701 RtlCopyMemory(&PDODeviceExtension
->Capabilities
, &FDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
706 PDODeviceObject
->Flags
|= DO_MAP_IO_BUFFER
;
709 // device is initialized
711 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
714 // store device object in device relations
716 DeviceRelations
->Objects
[Index
] = PDODeviceObject
;
717 DeviceRelations
->Count
++;
724 }while(Index
< FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
);
728 // check if creating succeeded
730 if (!NT_SUCCESS(Status
))
735 for(Index
= 0; Index
< DeviceRelations
->Count
; Index
++)
740 IoDeleteDevice(DeviceRelations
->Objects
[Index
]);
744 // free device relations
746 ExFreePool(DeviceRelations
);
751 // store device relations
753 *OutDeviceRelations
= DeviceRelations
;
758 return STATUS_SUCCESS
;