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 Irp
->IoStatus
.Information
= (ULONG_PTR
)NewBuffer
;
135 return STATUS_SUCCESS
;
139 HidClassPDO_HandleQueryHardwareId(
140 IN PDEVICE_OBJECT DeviceObject
,
144 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
148 PHIDP_COLLECTION_DESC CollectionDescription
;
151 // get device extension
153 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
154 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
157 // copy current stack location
159 IoCopyCurrentIrpStackLocationToNext(Irp
);
164 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
165 if (!NT_SUCCESS(Status
))
173 if (PDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
> 1)
178 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;
179 Offset
+= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x&Col%02x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
, PDODeviceExtension
->CollectionNumber
) + 1;
186 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;
187 Offset
+= swprintf(&Buffer
[Offset
], L
"HID\\Vid_%04x&Pid_%04x", PDODeviceExtension
->Common
.Attributes
.VendorID
, PDODeviceExtension
->Common
.Attributes
.ProductID
) + 1;
191 // get collection description
193 CollectionDescription
= HidClassPDO_GetCollectionDescription(&PDODeviceExtension
->Common
.DeviceDescription
, PDODeviceExtension
->CollectionNumber
);
194 ASSERT(CollectionDescription
);
196 if (CollectionDescription
->UsagePage
== HID_USAGE_PAGE_GENERIC
)
198 switch(CollectionDescription
->Usage
)
200 case HID_USAGE_GENERIC_POINTER
:
201 case HID_USAGE_GENERIC_MOUSE
:
205 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_MOUSE") + 1;
207 case HID_USAGE_GENERIC_GAMEPAD
:
208 case HID_USAGE_GENERIC_JOYSTICK
:
210 // Joystick / Gamepad
212 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_GAME") + 1;
214 case HID_USAGE_GENERIC_KEYBOARD
:
215 case HID_USAGE_GENERIC_KEYPAD
:
219 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_KEYBOARD") + 1;
221 case HID_USAGE_GENERIC_SYSTEM_CTL
:
225 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_CONTROL") + 1;
229 else if (CollectionDescription
->UsagePage
== HID_USAGE_PAGE_CONSUMER
&& CollectionDescription
->Usage
== HID_USAGE_CONSUMERCTRL
)
232 // Consumer Audio Control
234 Offset
+= swprintf(&Buffer
[Offset
], L
"HID_DEVICE_SYSTEM_CONSUMER") + 1;
238 // FIXME: add 'HID_DEVICE_UP:0001_U:0002'
244 Offset
+=swprintf(&Buffer
[Offset
], L
"HID_DEVICE") + 1;
249 ExFreePool((PVOID
)Irp
->IoStatus
.Information
);
254 Ptr
= (LPWSTR
)ExAllocatePool(NonPagedPool
, (Offset
+1)* sizeof(WCHAR
));
260 Irp
->IoStatus
.Information
= 0;
261 return STATUS_INSUFFICIENT_RESOURCES
;
267 RtlCopyMemory(Ptr
, Buffer
, Offset
* sizeof(WCHAR
));
268 Ptr
[Offset
] = UNICODE_NULL
;
273 Irp
->IoStatus
.Information
= (ULONG_PTR
)Ptr
;
274 return STATUS_SUCCESS
;
278 HidClassPDO_HandleQueryInstanceId(
279 IN PDEVICE_OBJECT DeviceObject
,
285 // copy current stack location
287 IoCopyCurrentIrpStackLocationToNext(Irp
);
292 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
293 if (!NT_SUCCESS(Status
))
300 DPRINT1("HidClassPDO_HandleQueryInstanceId Buffer %S\n", Irp
->IoStatus
.Information
);
302 //TODO implement instance id
304 // HID\VID_045E&PID_0047\8&1A0700BC&0&0000
305 return STATUS_NOT_IMPLEMENTED
;
309 HidClassPDO_HandleQueryCompatibleId(
310 IN PDEVICE_OBJECT DeviceObject
,
316 // copy current stack location
318 IoCopyCurrentIrpStackLocationToNext(Irp
);
323 Status
= HidClassFDO_DispatchRequestSynchronous(DeviceObject
, Irp
);
324 if (!NT_SUCCESS(Status
))
333 // FIXME: implement me
335 return STATUS_NOT_IMPLEMENTED
;
341 IN PDEVICE_OBJECT DeviceObject
,
344 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
345 PIO_STACK_LOCATION IoStack
;
347 PPNP_BUS_INFORMATION BusInformation
;
348 PDEVICE_RELATIONS DeviceRelation
;
351 // get device extension
353 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
354 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
357 // get current irp stack location
359 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
364 switch(IoStack
->MinorFunction
)
366 case IRP_MN_QUERY_ID
:
368 if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryDeviceID
)
371 // handle query device id
373 Status
= HidClassPDO_HandleQueryDeviceId(DeviceObject
, Irp
);
376 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryHardwareIDs
)
379 // handle instance id
381 Status
= HidClassPDO_HandleQueryHardwareId(DeviceObject
, Irp
);
384 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryInstanceID
)
387 // handle instance id
389 Status
= HidClassPDO_HandleQueryInstanceId(DeviceObject
, Irp
);
392 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryCompatibleIDs
)
395 // handle instance id
397 Status
= HidClassPDO_HandleQueryCompatibleId(DeviceObject
, Irp
);
401 DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack
->Parameters
.QueryId
.IdType
);
402 Status
= STATUS_NOT_SUPPORTED
;
403 Irp
->IoStatus
.Information
= 0;
406 case IRP_MN_QUERY_CAPABILITIES
:
408 if (IoStack
->Parameters
.DeviceCapabilities
.Capabilities
== NULL
)
413 Status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
419 RtlCopyMemory(IoStack
->Parameters
.DeviceCapabilities
.Capabilities
, &PDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
420 Status
= STATUS_SUCCESS
;
423 case IRP_MN_QUERY_BUS_INFORMATION
:
428 BusInformation
= (PPNP_BUS_INFORMATION
)ExAllocatePool(NonPagedPool
, sizeof(PNP_BUS_INFORMATION
));
433 RtlCopyMemory(&BusInformation
->BusTypeGuid
, &GUID_BUS_TYPE_HID
, sizeof(GUID
));
434 BusInformation
->LegacyBusType
= PNPBus
;
435 BusInformation
->BusNumber
= 0; //FIXME
440 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInformation
;
441 Status
= STATUS_SUCCESS
;
444 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
447 // FIXME set flags when driver fails / disabled
449 Status
= STATUS_SUCCESS
;
452 case IRP_MN_QUERY_DEVICE_RELATIONS
:
455 // only target relations are supported
457 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
462 Status
= Irp
->IoStatus
.Status
;
467 // allocate device relations
469 DeviceRelation
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_RELATIONS
));
475 Status
= STATUS_INSUFFICIENT_RESOURCES
;
480 // init device relation
482 DeviceRelation
->Count
= 1;
483 DeviceRelation
->Objects
[0] = DeviceObject
;
484 ObReferenceObject(DeviceRelation
->Objects
[0]);
489 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelation
;
490 Status
= STATUS_SUCCESS
;
493 case IRP_MN_START_DEVICE
:
496 // FIXME: support polled devices
498 ASSERT(PDODeviceExtension
->Common
.DriverExtension
->DevicesArePolled
== FALSE
);
501 // now register the device interface
503 Status
= IoRegisterDeviceInterface(PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
, &GUID_DEVINTERFACE_HID
, NULL
, &PDODeviceExtension
->DeviceInterface
);
504 DPRINT1("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status
);
505 if (NT_SUCCESS(Status
))
508 // enable device interface
510 Status
= IoSetDeviceInterfaceState(&PDODeviceExtension
->DeviceInterface
, TRUE
);
511 DPRINT1("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status
);
513 ASSERT(Status
== STATUS_SUCCESS
);
519 case IRP_MN_REMOVE_DEVICE
:
521 DPRINT1("[HIDCLASS] PDO IRP_MN_REMOVE_DEVICE not implemented\n");
527 Status
= STATUS_SUCCESS
; //Irp->IoStatus.Status;
530 case IRP_MN_QUERY_INTERFACE
:
532 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
538 Status
= Irp
->IoStatus
.Status
;
546 Status
= Irp
->IoStatus
.Status
;
554 if (Status
!= STATUS_PENDING
)
559 Irp
->IoStatus
.Status
= Status
;
564 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
574 HidClassPDO_CreatePDO(
575 IN PDEVICE_OBJECT DeviceObject
,
576 OUT PDEVICE_RELATIONS
*OutDeviceRelations
)
578 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
580 PDEVICE_OBJECT PDODeviceObject
;
581 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
583 PDEVICE_RELATIONS DeviceRelations
;
587 // get device extension
589 FDODeviceExtension
= (PHIDCLASS_FDO_EXTENSION
)DeviceObject
->DeviceExtension
;
590 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
593 // first allocate device relations
595 Length
= sizeof(DEVICE_RELATIONS
) + sizeof(PDEVICE_OBJECT
) * FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
;
596 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(NonPagedPool
, Length
);
597 if (!DeviceRelations
)
602 return STATUS_INSUFFICIENT_RESOURCES
;
606 // zero device relations
608 RtlZeroMemory(DeviceRelations
, Length
);
611 // lets create a PDO for top level collection
617 // lets create the device object
619 Status
= IoCreateDevice(FDODeviceExtension
->Common
.DriverExtension
->DriverObject
, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_UNKNOWN
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &PDODeviceObject
);
620 if (!NT_SUCCESS(Status
))
623 // failed to create device
625 DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status
);
632 PDODeviceObject
->StackSize
= DeviceObject
->StackSize
+ 1;
635 // get device extension
637 PDODeviceExtension
= (PHIDCLASS_PDO_DEVICE_EXTENSION
)PDODeviceObject
->DeviceExtension
;
640 // init device extension
642 PDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
= FDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
;
643 PDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
;
644 PDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
= FDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
;
645 PDODeviceExtension
->Common
.IsFDO
= FALSE
;
646 PDODeviceExtension
->FDODeviceObject
= DeviceObject
;
647 PDODeviceExtension
->Common
.DriverExtension
= FDODeviceExtension
->Common
.DriverExtension
;
648 PDODeviceExtension
->CollectionNumber
= FDODeviceExtension
->Common
.DeviceDescription
.CollectionDesc
[Index
].CollectionNumber
;
653 RtlCopyMemory(&PDODeviceExtension
->Common
.Attributes
, &FDODeviceExtension
->Common
.Attributes
, sizeof(HID_DEVICE_ATTRIBUTES
));
654 RtlCopyMemory(&PDODeviceExtension
->Common
.DeviceDescription
, &FDODeviceExtension
->Common
.DeviceDescription
, sizeof(HIDP_DEVICE_DESC
));
655 RtlCopyMemory(&PDODeviceExtension
->Capabilities
, &FDODeviceExtension
->Capabilities
, sizeof(DEVICE_CAPABILITIES
));
660 PDODeviceObject
->Flags
|= DO_MAP_IO_BUFFER
;
663 // device is initialized
665 PDODeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
668 // store device object in device relations
670 DeviceRelations
->Objects
[Index
] = PDODeviceObject
;
671 DeviceRelations
->Count
++;
678 }while(Index
< FDODeviceExtension
->Common
.DeviceDescription
.CollectionDescLength
);
682 // check if creating succeeded
684 if (!NT_SUCCESS(Status
))
689 for(Index
= 0; Index
< DeviceRelations
->Count
; Index
++)
694 IoDeleteDevice(DeviceRelations
->Objects
[Index
]);
698 // free device relations
700 ExFreePool(DeviceRelations
);
705 // store device relations
707 *OutDeviceRelations
= DeviceRelations
;
712 return STATUS_SUCCESS
;