From: Matthias Gorzellik matthias.gorzellik@gmail.com
--- dlls/hidclass.sys/device.c | 10 +-- dlls/hidclass.sys/hid.h | 4 +- dlls/hidclass.sys/pnp.c | 133 ++++++++++++++++++++++--------------- 3 files changed, 87 insertions(+), 60 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index e6b34077a77..a2100a8d238 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -219,7 +219,7 @@ static struct hid_report *hid_queue_pop_report( struct hid_queue *queue ) static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *packet ) { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; + HIDP_COLLECTION_DESC *desc = &ext->u.pdo.device_desc.CollectionDesc[ext->u.pdo.desc_number]; const BOOL polled = ext->u.pdo.information.Polled; ULONG size, report_len = polled ? packet->reportBufferLen : desc->InputLength; struct hid_report *last_report, *report; @@ -297,11 +297,13 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack
static HIDP_REPORT_IDS *find_report_with_type_and_id( BASE_DEVICE_EXTENSION *ext, BYTE type, BYTE id, BOOL any_id ) { + HIDP_COLLECTION_DESC *desc = &ext->u.pdo.device_desc.CollectionDesc[ext->u.pdo.desc_number]; HIDP_REPORT_IDS *report, *reports = ext->u.pdo.device_desc.ReportIDs; ULONG report_count = ext->u.pdo.device_desc.ReportIDsLength;
for (report = reports; report != reports + report_count; report++) { + if (desc->CollectionNumber != report->CollectionNumber) continue; if (!any_id && report->ReportID && report->ReportID != id) continue; if (type == HidP_Input && report->InputLength) return report; if (type == HidP_Output && report->OutputLength) return report; @@ -315,7 +317,7 @@ static DWORD CALLBACK hid_device_thread(void *args) { DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; + HIDP_COLLECTION_DESC *desc = &ext->u.pdo.device_desc.CollectionDesc[ext->u.pdo.desc_number]; BOOL polled = ext->u.pdo.information.Polled; HIDP_REPORT_IDS *report; HID_XFER_PACKET *packet; @@ -618,7 +620,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) } case IOCTL_HID_GET_COLLECTION_DESCRIPTOR: { - HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; + HIDP_COLLECTION_DESC *desc = &ext->u.pdo.device_desc.CollectionDesc[ext->u.pdo.desc_number];
irp->IoStatus.Information = desc->PreparsedDataLength; if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < desc->PreparsedDataLength) @@ -694,7 +696,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) { struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; + HIDP_COLLECTION_DESC *desc = &ext->u.pdo.device_desc.CollectionDesc[ext->u.pdo.desc_number]; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); struct hid_report *report; BOOL removed; diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 7b5d5f19298..1d35ed9f115 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -48,7 +48,8 @@ typedef struct _BASE_DEVICE_EXTENSION /* this must be the first member */ HID_DEVICE_EXTENSION hid_ext;
- DEVICE_OBJECT *child_pdo; + DEVICE_OBJECT *child_pdos[10]; + UINT32 num_childs; } fdo;
struct @@ -57,6 +58,7 @@ typedef struct _BASE_DEVICE_EXTENSION
HID_COLLECTION_INFORMATION information; HIDP_DEVICE_DESC device_desc; + UINT32 desc_number;
ULONG poll_interval; HANDLE halt_event; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index ddccffb91e2..9203d9fd00a 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -113,7 +113,7 @@ C_ASSERT(offsetof(RAWINPUT, data.hid.bRawData[2 * sizeof(USAGE)]) < sizeof(RAWIN
static void send_wm_input_device_change(BASE_DEVICE_EXTENSION *ext, LPARAM param) { - HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; + HIDP_COLLECTION_DESC *desc = &ext->u.pdo.device_desc.CollectionDesc[ext->u.pdo.desc_number]; INPUT input = {.type = INPUT_HARDWARE}; struct hid_packet hid = {0};
@@ -195,6 +195,7 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) HID_DEVICE_ATTRIBUTES attr = {0}; HID_DESCRIPTOR descriptor = {0}; HIDP_COLLECTION_DESC *desc; + HIDP_DEVICE_DESC device_desc; DEVICE_OBJECT *child_pdo; BYTE *reportDescriptor; UNICODE_STRING string; @@ -203,43 +204,28 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) USAGE page, usage; NTSTATUS status; INT i; + WCHAR serialnumber[255]; + ULONG index = HID_STRING_ID_ISERIALNUMBER;
- call_minidriver( IOCTL_HID_GET_DEVICE_ATTRIBUTES, fdo, NULL, 0, &attr, sizeof(attr), &io ); + call_minidriver( IOCTL_HID_GET_STRING, fdo, ULongToPtr( index ), sizeof(index), + &serialnumber, sizeof(serialnumber), &io ); if (io.Status != STATUS_SUCCESS) { ERR( "Minidriver failed to get attributes, status %#lx.\n", io.Status ); return; }
- swprintf(pdo_name, ARRAY_SIZE(pdo_name), L"\Device\HID#%p&%p", fdo->DriverObject, - fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject); - RtlInitUnicodeString(&string, pdo_name); - if ((status = IoCreateDevice(fdo->DriverObject, sizeof(*pdo_ext), &string, 0, 0, FALSE, &child_pdo))) + call_minidriver( IOCTL_HID_GET_DEVICE_ATTRIBUTES, fdo, NULL, 0, &attr, sizeof(attr), &io ); + if (io.Status != STATUS_SUCCESS) { - ERR( "Failed to create child PDO, status %#lx.\n", io.Status ); + ERR( "Minidriver failed to get attributes, status %#lx.\n", io.Status ); return; } - fdo_ext->u.fdo.child_pdo = child_pdo; - - pdo_ext = child_pdo->DeviceExtension; - pdo_ext->u.pdo.parent_fdo = fdo; - list_init( &pdo_ext->u.pdo.queues ); - KeInitializeSpinLock( &pdo_ext->u.pdo.queues_lock ); - wcscpy(pdo_ext->device_id, fdo_ext->device_id); - wcscpy(pdo_ext->instance_id, fdo_ext->instance_id); - wcscpy(pdo_ext->container_id, fdo_ext->container_id); - pdo_ext->class_guid = fdo_ext->class_guid; - - pdo_ext->u.pdo.information.VendorID = attr.VendorID; - pdo_ext->u.pdo.information.ProductID = attr.ProductID; - pdo_ext->u.pdo.information.VersionNumber = attr.VersionNumber; - pdo_ext->u.pdo.information.Polled = minidriver->minidriver.DevicesArePolled;
call_minidriver( IOCTL_HID_GET_DEVICE_DESCRIPTOR, fdo, NULL, 0, &descriptor, sizeof(descriptor), &io ); if (io.Status != STATUS_SUCCESS) { - ERR( "Cannot get Device Descriptor, status %#lx\n", status ); - IoDeleteDevice(child_pdo); + ERR( "Cannot get Device Descriptor, status %#lx\n", io.Status ); return; } for (i = 0; i < descriptor.bNumDescriptors; i++) @@ -249,7 +235,6 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) if (i >= descriptor.bNumDescriptors) { ERR("No Report Descriptor found in reply\n"); - IoDeleteDevice(child_pdo); return; }
@@ -258,43 +243,79 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) descriptor.DescriptorList[i].wReportLength, &io ); if (io.Status != STATUS_SUCCESS) { - ERR( "Cannot get Report Descriptor, status %#lx\n", status ); + ERR( "Cannot get Report Descriptor, status %#lx\n", io.Status ); free(reportDescriptor); - IoDeleteDevice(child_pdo); return; }
io.Status = HidP_GetCollectionDescription( reportDescriptor, descriptor.DescriptorList[i].wReportLength, - PagedPool, &pdo_ext->u.pdo.device_desc ); + PagedPool, &device_desc ); free(reportDescriptor); if (io.Status != HIDP_STATUS_SUCCESS) { ERR("Cannot parse Report Descriptor\n"); - IoDeleteDevice(child_pdo); return; }
- desc = pdo_ext->u.pdo.device_desc.CollectionDesc; - pdo_ext->u.pdo.information.DescriptorSize = desc->PreparsedDataLength; + for (i = 0; i < device_desc.CollectionDescLength; ++i) { + swprintf(pdo_name, ARRAY_SIZE(pdo_name), L"\Device\HID#%p&%p&%d", fdo->DriverObject, + fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject, i); + RtlInitUnicodeString(&string, pdo_name); + if ((status = IoCreateDevice(fdo->DriverObject, sizeof(*pdo_ext), &string, 0, 0, FALSE, &child_pdo))) + { + ERR( "Failed to create child PDO, status %#lx.\n", status ); + return; + } + + fdo_ext->u.fdo.child_pdos[i] = child_pdo; + fdo_ext->u.fdo.num_childs++; + + pdo_ext = child_pdo->DeviceExtension; + pdo_ext->u.pdo.parent_fdo = fdo; + list_init( &pdo_ext->u.pdo.queues ); + KeInitializeSpinLock( &pdo_ext->u.pdo.queues_lock ); + if (device_desc.CollectionDescLength > 1) { + swprintf(pdo_ext->device_id, ARRAY_SIZE(pdo_ext->device_id), L"%s&Col%02d", + fdo_ext->device_id, device_desc.CollectionDesc[i].CollectionNumber); + swprintf(pdo_ext->instance_id, ARRAY_SIZE(pdo_ext->instance_id), L"%u&%s&%x&%u&%04u", + attr.VersionNumber, serialnumber, 0, 0, i); + } else { + wcscpy(pdo_ext->device_id, fdo_ext->device_id); + wcscpy(pdo_ext->instance_id, fdo_ext->instance_id); + } + wcscpy(pdo_ext->container_id, fdo_ext->container_id); + pdo_ext->class_guid = fdo_ext->class_guid;
- page = desc->UsagePage; - usage = desc->Usage; - if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_MOUSE) - pdo_ext->u.pdo.rawinput_handle = WINE_MOUSE_HANDLE; - else if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_KEYBOARD) - pdo_ext->u.pdo.rawinput_handle = WINE_KEYBOARD_HANDLE; - else - pdo_ext->u.pdo.rawinput_handle = alloc_rawinput_handle(); + pdo_ext->u.pdo.information.VendorID = attr.VendorID; + pdo_ext->u.pdo.information.ProductID = attr.ProductID; + pdo_ext->u.pdo.information.VersionNumber = attr.VersionNumber; + pdo_ext->u.pdo.information.Polled = minidriver->minidriver.DevicesArePolled;
- IoInvalidateDeviceRelations(fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject, BusRelations); + memcpy(&pdo_ext->u.pdo.device_desc, &device_desc, sizeof(HIDP_DEVICE_DESC)); + pdo_ext->u.pdo.desc_number = i;
- pdo_ext->u.pdo.poll_interval = DEFAULT_POLL_INTERVAL; + desc = &pdo_ext->u.pdo.device_desc.CollectionDesc[i]; + pdo_ext->u.pdo.information.DescriptorSize = desc->PreparsedDataLength;
- HID_StartDeviceThread(child_pdo); + page = desc->UsagePage; + usage = desc->Usage; + if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_MOUSE) + pdo_ext->u.pdo.rawinput_handle = WINE_MOUSE_HANDLE; + else if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_KEYBOARD) + pdo_ext->u.pdo.rawinput_handle = WINE_KEYBOARD_HANDLE; + else + pdo_ext->u.pdo.rawinput_handle = alloc_rawinput_handle();
- send_wm_input_device_change(pdo_ext, GIDC_ARRIVAL); + pdo_ext->u.pdo.poll_interval = DEFAULT_POLL_INTERVAL;
- TRACE( "created device %p, rawinput handle %#x\n", pdo_ext, pdo_ext->u.pdo.rawinput_handle ); + HID_StartDeviceThread(child_pdo); + + send_wm_input_device_change(pdo_ext, GIDC_ARRIVAL); + + TRACE( "created device %p, rawinput handle %#x\n", pdo_ext, pdo_ext->u.pdo.rawinput_handle ); + } + + IoInvalidateDeviceRelations(fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject, BusRelations); }
static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp) @@ -311,26 +332,28 @@ static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp) { DEVICE_RELATIONS *devices; DEVICE_OBJECT *child; + UINT32 i;
if (stack->Parameters.QueryDeviceRelations.Type != BusRelations) return minidriver->PNPDispatch(device, irp);
- if (!(devices = ExAllocatePool(PagedPool, offsetof(DEVICE_RELATIONS, Objects[1])))) + if (!(devices = ExAllocatePool(PagedPool, + offsetof(DEVICE_RELATIONS, Objects[ext->u.fdo.num_childs])))) { irp->IoStatus.Status = STATUS_NO_MEMORY; IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_NO_MEMORY; }
- if ((child = ext->u.fdo.child_pdo)) + devices->Count = 0; + for ( i = 0; i < ext->u.fdo.num_childs; ++i ) { - devices->Objects[0] = ext->u.fdo.child_pdo; - call_fastcall_func1(ObfReferenceObject, ext->u.fdo.child_pdo); - devices->Count = 1; - } - else - { - devices->Count = 0; + if ((child = ext->u.fdo.child_pdos[i])) + { + devices->Objects[i] = child; + call_fastcall_func1(ObfReferenceObject, child); + devices->Count++; + } }
irp->IoStatus.Information = (ULONG_PTR)devices; @@ -373,7 +396,7 @@ static WCHAR *query_hardware_ids(DEVICE_OBJECT *device) static const WCHAR hid_format[] = L"HID_DEVICE";
BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; + HIDP_COLLECTION_DESC *desc = &ext->u.pdo.device_desc.CollectionDesc[ext->u.pdo.desc_number]; HID_COLLECTION_INFORMATION *info = &ext->u.pdo.information; WCHAR *dst; DWORD size; @@ -443,7 +466,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; + HIDP_COLLECTION_DESC *desc = &ext->u.pdo.device_desc.CollectionDesc[ext->u.pdo.desc_number]; NTSTATUS status = irp->IoStatus.Status; struct hid_queue *queue, *next; KIRQL irql;