Attempt to add support for multi [toplevel-collections](https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/hidclass-hard...) (TLCs) in HID descriptors.
TLCs are found by iterating over the descriptor once. HID descriptor parser is then called for each TLC individually (no changes in the parser itself). HID reports are bound to their TLC. A child-pdo is created for each TLC. Each child-pdo registers its input report-id for `pending_reads` in winbus.sys.
-- v2: winebus.sys: Store pending reads per report-id. hidclass.sys: Create child-pdo per TLC. hidparse.sys: Pre-process descriptor to find toplevel-collections (TLCs), parse TLCs into CollectionDesc array. dinput/tests: remove todo for HID multi-tlc tests
From: Matthias Gorzellik matthias.gorzellik@gmail.com
--- dlls/dinput/tests/hid.c | 3 --- 1 file changed, 3 deletions(-)
diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 4dc3a60cdff..fb5a3bb457d 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -730,7 +730,6 @@ void hid_device_stop( struct hid_device_desc *desc, UINT count ) for (i = 0; i < count; ++i) { ret = WaitForSingleObject( device_removed, i > 0 ? 500 : 5000 ); - todo_wine_if(i > 0) ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); } } @@ -755,7 +754,6 @@ BOOL hid_device_start_( struct hid_device_desc *desc, UINT count, DWORD timeout for (i = 0; i < count; ++i) { ret = WaitForSingleObject( device_added, timeout ); - todo_wine_if(i > 0) ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); }
@@ -4049,7 +4047,6 @@ static void test_hid_multiple_tlc(void) swprintf( device_path, MAX_PATH, L"\\?\hid#vid_%04x&pid_%04x&col01", desc.attributes.VendorID, desc.attributes.ProductID ); ret = find_hid_device_path( device_path ); - todo_wine ok( ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) ); if (!ret) goto done;
From: Matthias Gorzellik matthias.gorzellik@gmail.com
--- dlls/hidparse.sys/main.c | 133 ++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 45 deletions(-)
diff --git a/dlls/hidparse.sys/main.c b/dlls/hidparse.sys/main.c index feb5b3531a4..e46640ebe4b 100644 --- a/dlls/hidparse.sys/main.c +++ b/dlls/hidparse.sys/main.c @@ -647,67 +647,110 @@ done: NTSTATUS WINAPI HidP_GetCollectionDescription( PHIDP_REPORT_DESCRIPTOR report_desc, ULONG report_desc_len, POOL_TYPE pool_type, HIDP_DEVICE_DESC *device_desc ) { - ULONG i, len, report_count = 0, input_len[256] = {0}, output_len[256] = {0}, feature_len[256] = {0}; + ULONG i, len, report_count = 0, input_len[256] = {0}, output_len[256] = {0}, feature_len[256] = {0}, collection[256] = {0}; struct hid_value_caps *caps, *caps_end; struct hid_preparsed_data *preparsed; + BYTE *ptr, *end; + UINT32 size, depth = 0; + // FIXME: how many TLCs are allowed? + BYTE *toplevel_collections[10];
TRACE( "report_desc %p, report_desc_len %lu, pool_type %u, device_desc %p.\n", report_desc, report_desc_len, pool_type, device_desc );
memset( device_desc, 0, sizeof(*device_desc) );
- if (!(preparsed = parse_descriptor( report_desc, report_desc_len, pool_type ))) - return HIDP_STATUS_INTERNAL_ERROR; - - if (!(device_desc->CollectionDesc = ExAllocatePool( pool_type, sizeof(*device_desc->CollectionDesc) ))) + toplevel_collections[0] = report_desc; + for (ptr = report_desc, end = report_desc + report_desc_len; ptr != end; ptr += size + 1) { - free( preparsed ); - return STATUS_NO_MEMORY; - } + size = (*ptr & 0x03); + if (size == 3) size = 4; + if (ptr + size > end) + { + ERR( "Need %d bytes to read item value\n", size ); + return HIDP_STATUS_INTERNAL_ERROR; + }
- len = preparsed->caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) + - preparsed->number_link_collection_nodes * sizeof(struct hid_collection_node); - - device_desc->CollectionDescLength = 1; - device_desc->CollectionDesc[0].UsagePage = preparsed->usage_page; - device_desc->CollectionDesc[0].Usage = preparsed->usage; - device_desc->CollectionDesc[0].CollectionNumber = 1; - device_desc->CollectionDesc[0].InputLength = preparsed->input_report_byte_length; - device_desc->CollectionDesc[0].OutputLength = preparsed->output_report_byte_length; - device_desc->CollectionDesc[0].FeatureLength = preparsed->feature_report_byte_length; - device_desc->CollectionDesc[0].PreparsedDataLength = len; - device_desc->CollectionDesc[0].PreparsedData = (PHIDP_PREPARSED_DATA)preparsed; - - caps = HID_INPUT_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->input_caps_end - preparsed->input_caps_start; - for (; caps != caps_end; ++caps) - { - len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; - if (!input_len[caps->report_id]) report_count++; - input_len[caps->report_id] = max(input_len[caps->report_id], len); +#define SHORT_ITEM( tag, type ) (((tag) << 4) | ((type) << 2)) + switch (*ptr & SHORT_ITEM( 0xf, 0x3 )) + { + case SHORT_ITEM( TAG_MAIN_COLLECTION, TAG_TYPE_MAIN ): + depth++; + break; + case SHORT_ITEM( TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN ): + if (--depth == 0) { + device_desc->CollectionDescLength++; + if (device_desc->CollectionDescLength < ARRAY_SIZE(toplevel_collections)) + toplevel_collections[device_desc->CollectionDescLength] = ptr + size + 1; + else { + ERR( "Too many toplevel collections." ); + return HIDP_STATUS_INTERNAL_ERROR; + } + } + break; + default: + break; + } }
- caps = HID_OUTPUT_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->output_caps_end - preparsed->output_caps_start; - for (; caps != caps_end; ++caps) - { - len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; - if (!input_len[caps->report_id] && !output_len[caps->report_id]) report_count++; - output_len[caps->report_id] = max(output_len[caps->report_id], len); - } + if (!(device_desc->CollectionDesc = ExAllocatePool( pool_type, device_desc->CollectionDescLength * sizeof(*device_desc->CollectionDesc) ))) + return STATUS_NO_MEMORY;
- caps = HID_FEATURE_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->feature_caps_end - preparsed->feature_caps_start; - for (; caps != caps_end; ++caps) - { - len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; - if (!input_len[caps->report_id] && !output_len[caps->report_id] && !feature_len[caps->report_id]) report_count++; - feature_len[caps->report_id] = max(feature_len[caps->report_id], len); + for (i = 0; i < device_desc->CollectionDescLength; ++i) { + + TRACE( "num tlcs %lu, tlc %lu, start %p, end %p\n", device_desc->CollectionDescLength, i, toplevel_collections[i], toplevel_collections[i+1]); + + if (!(preparsed = parse_descriptor( toplevel_collections[i], toplevel_collections[i+1] - toplevel_collections[i], pool_type ))) + return HIDP_STATUS_INTERNAL_ERROR; + + len = preparsed->caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) + + preparsed->number_link_collection_nodes * sizeof(struct hid_collection_node); + + device_desc->CollectionDesc[i].UsagePage = preparsed->usage_page; + device_desc->CollectionDesc[i].Usage = preparsed->usage; + device_desc->CollectionDesc[i].CollectionNumber = i + 1; + device_desc->CollectionDesc[i].InputLength = preparsed->input_report_byte_length; + device_desc->CollectionDesc[i].OutputLength = preparsed->output_report_byte_length; + device_desc->CollectionDesc[i].FeatureLength = preparsed->feature_report_byte_length; + device_desc->CollectionDesc[i].PreparsedDataLength = len; + device_desc->CollectionDesc[i].PreparsedData = (PHIDP_PREPARSED_DATA)preparsed; + + caps = HID_INPUT_VALUE_CAPS( preparsed ); + caps_end = caps + preparsed->input_caps_end - preparsed->input_caps_start; + for (; caps != caps_end; ++caps) + { + len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; + if (!input_len[caps->report_id]) + report_count++; + input_len[caps->report_id] = max(input_len[caps->report_id], len); + collection[caps->report_id] = i; + } + + caps = HID_OUTPUT_VALUE_CAPS( preparsed ); + caps_end = caps + preparsed->output_caps_end - preparsed->output_caps_start; + for (; caps != caps_end; ++caps) + { + len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; + if (!input_len[caps->report_id] && !output_len[caps->report_id]) report_count++; + output_len[caps->report_id] = max(output_len[caps->report_id], len); + collection[caps->report_id] = i; + } + + caps = HID_FEATURE_VALUE_CAPS( preparsed ); + caps_end = caps + preparsed->feature_caps_end - preparsed->feature_caps_start; + for (; caps != caps_end; ++caps) + { + len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; + if (!input_len[caps->report_id] && !output_len[caps->report_id] && !feature_len[caps->report_id]) report_count++; + feature_len[caps->report_id] = max(feature_len[caps->report_id], len); + collection[caps->report_id] = i; + } }
if (!(device_desc->ReportIDs = ExAllocatePool( pool_type, sizeof(*device_desc->ReportIDs) * report_count ))) { - free( preparsed ); + for (i = 0; i < device_desc->CollectionDescLength; ++i) + free( device_desc->CollectionDesc[i].PreparsedData ); ExFreePool( device_desc->CollectionDesc ); return STATUS_NO_MEMORY; } @@ -716,7 +759,7 @@ NTSTATUS WINAPI HidP_GetCollectionDescription( PHIDP_REPORT_DESCRIPTOR report_de { if (!input_len[i] && !output_len[i] && !feature_len[i]) continue; device_desc->ReportIDs[report_count].ReportID = i; - device_desc->ReportIDs[report_count].CollectionNumber = 1; + device_desc->ReportIDs[report_count].CollectionNumber = collection[i] + 1; device_desc->ReportIDs[report_count].InputLength = (input_len[i] + 7) / 8; device_desc->ReportIDs[report_count].OutputLength = (output_len[i] + 7) / 8; device_desc->ReportIDs[report_count].FeatureLength = (feature_len[i] + 7) / 8;
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;
From: Matthias Gorzellik matthias.gorzellik@gmail.com
--- dlls/winebus.sys/main.c | 43 +++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index f7a634dbfe2..fe73ec603cf 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -87,7 +87,7 @@ struct device_extension
struct hid_report *last_reports[256]; struct list reports; - IRP *pending_read; + IRP *pending_reads[256];
UINT32 report_fixups; UINT64 unix_device; @@ -252,13 +252,13 @@ static WCHAR *get_compatible_ids(DEVICE_OBJECT *device) return dst; }
-static IRP *pop_pending_read(struct device_extension *ext) +static IRP *pop_pending_read(struct device_extension *ext, ULONG report_id) { IRP *pending;
RtlEnterCriticalSection(&ext->cs); - pending = ext->pending_read; - ext->pending_read = NULL; + pending = ext->pending_reads[report_id]; + ext->pending_reads[report_id] = NULL; RtlLeaveCriticalSection(&ext->cs);
return pending; @@ -268,12 +268,16 @@ static void remove_pending_irps(DEVICE_OBJECT *device) { struct device_extension *ext = device->DeviceExtension; IRP *pending; + UINT i;
- if ((pending = pop_pending_read(ext))) + for ( i = 0; i < ARRAY_SIZE(ext->pending_reads); ++i ) { - pending->IoStatus.Status = STATUS_DELETE_PENDING; - pending->IoStatus.Information = 0; - IoCompleteRequest(pending, IO_NO_INCREMENT); + if ((pending = pop_pending_read(ext, i))) + { + pending->IoStatus.Status = STATUS_DELETE_PENDING; + pending->IoStatus.Information = 0; + IoCompleteRequest(pending, IO_NO_INCREMENT); + } } }
@@ -478,6 +482,7 @@ static void process_hid_report(DEVICE_OBJECT *device, BYTE *report_buf, DWORD re ULONG size = offsetof(struct hid_report, buffer[report_len]); struct hid_report *report, *last_report; IRP *irp; + UINT i, j;
if (!(report = RtlAllocateHeap(GetProcessHeap(), 0, size))) return; memcpy(report->buffer, report_buf, report_len); @@ -539,11 +544,20 @@ static void process_hid_report(DEVICE_OBJECT *device, BYTE *report_buf, DWORD re RtlEnterCriticalSection(&ext->cs); list_add_tail(&ext->reports, &report->entry);
- if (!ext->collection_desc.ReportIDs[0].ReportID) last_report = ext->last_reports[0]; - else last_report = ext->last_reports[report_buf[0]]; - memcpy(last_report->buffer, report_buf, report_len); + for ( i = 0; i < ext->collection_desc.CollectionDescLength; ++i ) + { + HIDP_COLLECTION_DESC *desc = &ext->collection_desc.CollectionDesc[i]; + for ( j = 0; j < ext->collection_desc.ReportIDsLength; ++j ) + { + if (ext->collection_desc.ReportIDs[j].CollectionNumber != desc->CollectionNumber) continue; + if (!ext->collection_desc.ReportIDs[j].ReportID) last_report = ext->last_reports[0]; + else last_report = ext->last_reports[report_buf[0]]; + memcpy(last_report->buffer, report_buf, report_len); + break; + } + }
- if ((irp = pop_pending_read(ext))) + if ((irp = pop_pending_read(ext, report_buf[0]))) { deliver_next_report(ext, irp); IoCompleteRequest(irp, IO_NO_INCREMENT); @@ -1259,9 +1273,10 @@ static NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp) { if (!deliver_next_report(ext, irp)) { + UCHAR reportId = ((PUCHAR)irp->UserBuffer)[0]; /* hidclass.sys should guarantee this */ - assert(!ext->pending_read); - ext->pending_read = irp; + assert(!ext->pending_reads[reportId]); + ext->pending_reads[reportId] = irp; IoMarkIrpPending(irp); irp->IoStatus.Status = STATUS_PENDING; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147198
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: input.c:4305: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 0000000000F300DA, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032