Rémi Bernon : winebus.sys: Queue HID reports instead of overwritting the last one.

Alexandre Julliard julliard at winehq.org
Fri Oct 8 14:12:26 CDT 2021


Module: wine
Branch: master
Commit: c9003fab66dbe5311c81ab9198612d746f28f013
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=c9003fab66dbe5311c81ab9198612d746f28f013

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Fri Oct  8 10:01:25 2021 +0200

winebus.sys: Queue HID reports instead of overwritting the last one.

If the hidclass.sys read requests aren't done fast enough.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51824
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winebus.sys/main.c | 100 ++++++++++++++++++------------------------------
 1 file changed, 38 insertions(+), 62 deletions(-)

diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c
index 57a751655cc..16192977bef 100644
--- a/dlls/winebus.sys/main.c
+++ b/dlls/winebus.sys/main.c
@@ -54,6 +54,13 @@ static DEVICE_OBJECT *bus_fdo;
 
 static HANDLE driver_key;
 
+struct hid_report
+{
+    struct list entry;
+    ULONG length;
+    BYTE buffer[1];
+};
+
 enum device_state
 {
     DEVICE_STATE_STOPPED,
@@ -77,10 +84,7 @@ struct device_extension
     HIDP_DEVICE_DESC collection_desc;
 
     BYTE *last_reports[256];
-    BYTE *last_report;
-    DWORD last_report_size;
-    BOOL last_report_read;
-    DWORD buffer_size;
+    struct list reports;
     IRP *pending_read;
 
     struct unix_device *unix_device;
@@ -307,11 +311,8 @@ static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, struct uni
     ext->device             = device;
     ext->desc               = *desc;
     ext->index              = get_device_index(desc);
-    ext->last_report        = NULL;
-    ext->last_report_size   = 0;
-    ext->last_report_read   = TRUE;
-    ext->buffer_size        = 0;
     ext->unix_device        = unix_device;
+    list_init(&ext->reports);
 
     InitializeCriticalSection(&ext->cs);
     ext->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
@@ -397,63 +398,43 @@ static DWORD check_bus_option(const WCHAR *option, DWORD default_value)
     return default_value;
 }
 
-static NTSTATUS deliver_last_report(struct device_extension *ext, DWORD buffer_length, BYTE* buffer, ULONG_PTR *out_length)
+static BOOL deliver_next_report(struct device_extension *ext, IRP *irp)
 {
-    if (buffer_length < ext->last_report_size)
-    {
-        *out_length = 0;
-        return STATUS_BUFFER_TOO_SMALL;
-    }
-    else
-    {
-        if (ext->last_report)
-            memcpy(buffer, ext->last_report, ext->last_report_size);
-        *out_length = ext->last_report_size;
-        return STATUS_SUCCESS;
-    }
+    struct hid_report *report;
+    struct list *entry;
+
+    if (!(entry = list_head(&ext->reports))) return FALSE;
+    report = LIST_ENTRY(entry, struct hid_report, entry);
+    list_remove(&report->entry);
+
+    memcpy(irp->UserBuffer, report->buffer, report->length);
+    irp->IoStatus.Information = report->length;
+    irp->IoStatus.Status = STATUS_SUCCESS;
+
+    RtlFreeHeap(GetProcessHeap(), 0, report);
+    return TRUE;
 }
 
-static void process_hid_report(DEVICE_OBJECT *device, BYTE *report, DWORD length)
+static void process_hid_report(DEVICE_OBJECT *device, BYTE *report_buf, DWORD report_len)
 {
     struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
-    IO_STACK_LOCATION *stack;
-    ULONG buffer_len;
+    ULONG size = offsetof(struct hid_report, buffer[report_len]);
+    struct hid_report *report;
     IRP *irp;
 
-    if (!length || !report)
-        return;
+    if (!(report = RtlAllocateHeap(GetProcessHeap(), 0, size))) return;
+    memcpy(report->buffer, report_buf, report_len);
+    report->length = report_len;
 
     RtlEnterCriticalSection(&ext->cs);
-    if (length > ext->buffer_size)
-    {
-        RtlFreeHeap(GetProcessHeap(), 0, ext->last_report);
-        ext->last_report = RtlAllocateHeap(GetProcessHeap(), 0, length);
-        if (!ext->last_report)
-        {
-            ERR_(hid_report)("Failed to alloc last report\n");
-            ext->buffer_size = 0;
-            ext->last_report_size = 0;
-            ext->last_report_read = TRUE;
-            RtlLeaveCriticalSection(&ext->cs);
-            return;
-        }
-        else
-            ext->buffer_size = length;
-    }
-
-    memcpy(ext->last_report, report, length);
-    ext->last_report_size = length;
-    ext->last_report_read = FALSE;
+    list_add_tail(&ext->reports, &report->entry);
 
-    if (!ext->collection_desc.ReportIDs[0].ReportID) memcpy(ext->last_reports[0], report, length);
-    else memcpy(ext->last_reports[report[0]], report, length);
+    if (!ext->collection_desc.ReportIDs[0].ReportID) memcpy(ext->last_reports[0], report_buf, report_len);
+    else memcpy(ext->last_reports[report_buf[0]], report_buf, report_len);
 
     if ((irp = pop_pending_read(ext)))
     {
-        stack = IoGetCurrentIrpStackLocation(irp);
-        buffer_len = stack->Parameters.DeviceIoControl.OutputBufferLength;
-        irp->IoStatus.Status = deliver_last_report(ext, buffer_len, irp->UserBuffer, &irp->IoStatus.Information);
-        ext->last_report_read = TRUE;
+        deliver_next_report(ext, irp);
         IoCompleteRequest(irp, IO_NO_INCREMENT);
     }
     RtlLeaveCriticalSection(&ext->cs);
@@ -819,6 +800,7 @@ static NTSTATUS pdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
     struct device_extension *ext = device->DeviceExtension;
     NTSTATUS status = irp->IoStatus.Status;
     IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
+    struct hid_report *report, *next;
     HIDP_REPORT_IDS *reports;
     ULONG i, size;
 
@@ -885,11 +867,12 @@ static NTSTATUS pdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
             ext->cs.DebugInfo->Spare[0] = 0;
             DeleteCriticalSection(&ext->cs);
 
-            RtlFreeHeap(GetProcessHeap(), 0, ext->last_report);
-
             irp->IoStatus.Status = STATUS_SUCCESS;
             IoCompleteRequest(irp, IO_NO_INCREMENT);
 
+            LIST_FOR_EACH_ENTRY_SAFE(report, next, &ext->reports, struct hid_report, entry)
+                RtlFreeHeap(GetProcessHeap(), 0, report);
+
             reports = ext->collection_desc.ReportIDs;
             for (i = 0; i < ext->collection_desc.ReportIDsLength; ++i)
             {
@@ -1046,14 +1029,7 @@ static NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp)
         }
         case IOCTL_HID_READ_REPORT:
         {
-            TRACE_(hid_report)("IOCTL_HID_READ_REPORT\n");
-            if (!ext->last_report_read)
-            {
-                irp->IoStatus.Status = deliver_last_report(ext,
-                    buffer_len, irp->UserBuffer, &irp->IoStatus.Information);
-                ext->last_report_read = TRUE;
-            }
-            else
+            if (!deliver_next_report(ext, irp))
             {
                 /* hidclass.sys should guarantee this */
                 assert(!ext->pending_read);




More information about the wine-cvs mailing list