[1/2] winebus.sys: Implement IOCTL_HID_GET_DEVICE_DESCRIPTOR for hidraw. (v3)

Sebastian Lackner sebastian at fds-team.de
Tue Oct 11 07:09:35 CDT 2016


From: Aric Stewart <aric at codeweavers.com>

Signed-off-by: Aric Stewart <aric at codeweavers.com>
Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---

Changes in v3:
* Remove autogenerated changes from patch.
* Do not rely on "length" not changing in call, instead explicitly check status.
* Change "length" to unsigned types (like in the Windows and Linux structures).
* Rename "extension" -> "ext" for consistency reasons.
* Use "private" instead of "ext" when referring to platform private data pointers.
* Some style fixes.

 configure.ac                |    1 
 dlls/winebus.sys/bus.h      |    1 
 dlls/winebus.sys/bus_udev.c |   53 +++++++++++++++++++++++++++++++++++++++++---
 dlls/winebus.sys/main.c     |   46 +++++++++++++++++++++++++++++++++-----
 4 files changed, 92 insertions(+), 9 deletions(-)

diff --git a/configure.ac b/configure.ac
index 741a4ef..eb328a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -426,6 +426,7 @@ AC_CHECK_HEADERS(\
 	linux/compiler.h \
 	linux/filter.h \
 	linux/hdreg.h \
+	linux/hidraw.h \
 	linux/input.h \
 	linux/ioctl.h \
 	linux/joystick.h \
diff --git a/dlls/winebus.sys/bus.h b/dlls/winebus.sys/bus.h
index 342a66b..9ab242c 100644
--- a/dlls/winebus.sys/bus.h
+++ b/dlls/winebus.sys/bus.h
@@ -23,6 +23,7 @@ NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry
 typedef struct
 {
     int (*compare_platform_device)(DEVICE_OBJECT *device, void *platform_dev);
+    NTSTATUS (*get_reportdescriptor)(DEVICE_OBJECT *device, BYTE *buffer, DWORD length, DWORD *out_length);
 } platform_vtbl;
 
 void *get_platform_private(DEVICE_OBJECT *device) DECLSPEC_HIDDEN;
diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c
index a01d88e..22ea07d 100644
--- a/dlls/winebus.sys/bus_udev.c
+++ b/dlls/winebus.sys/bus_udev.c
@@ -35,6 +35,12 @@
 #ifdef HAVE_LIBUDEV_H
 # include <libudev.h>
 #endif
+#ifdef HAVE_LINUX_HIDRAW_H
+# include <linux/hidraw.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
 
 #define NONAMELESSUNION
 
@@ -64,6 +70,7 @@ DEFINE_GUID(GUID_DEVCLASS_HIDRAW, 0x3def44ad,0x242e,0x46e5,0x82,0x6d,0x70,0x72,0
 struct platform_private
 {
     struct udev_device *udev_device;
+    int device_fd;
 };
 
 static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
@@ -105,9 +112,42 @@ static int compare_platform_device(DEVICE_OBJECT *device, void *platform_dev)
     return strcmp(udev_device_get_syspath(dev1), udev_device_get_syspath(dev2));
 }
 
+static NTSTATUS hidraw_get_reportdescriptor(DEVICE_OBJECT *device, BYTE *buffer, DWORD length, DWORD *out_length)
+{
+#ifdef HAVE_LINUX_HIDRAW_H
+    struct hidraw_report_descriptor descriptor;
+    struct platform_private *private = impl_from_DEVICE_OBJECT(device);
+
+    if (ioctl(private->device_fd, HIDIOCGRDESCSIZE, &descriptor.size) == -1)
+    {
+        WARN("ioctl(HIDIOCGRDESCSIZE) failed: %d %s\n", errno, strerror(errno));
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    *out_length = descriptor.size;
+
+    if (length < descriptor.size)
+        return STATUS_BUFFER_TOO_SMALL;
+    if (!descriptor.size)
+        return STATUS_SUCCESS;
+
+    if (ioctl(private->device_fd, HIDIOCGRDESC, &descriptor) == -1)
+    {
+        WARN("ioctl(HIDIOCGRDESC) failed: %d %s\n", errno, strerror(errno));
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    memcpy(buffer, descriptor.value, descriptor.size);
+    return STATUS_SUCCESS;
+#else
+    return STATUS_NOT_IMPLEMENTED;
+#endif
+}
+
 static const platform_vtbl hidraw_vtbl =
 {
     compare_platform_device,
+    hidraw_get_reportdescriptor,
 };
 
 static void try_add_device(struct udev_device *dev)
@@ -128,7 +168,6 @@ static void try_add_device(struct udev_device *dev)
         WARN("Unable to open udev device %s: %s\n", debugstr_a(devnode), strerror(errno));
         return;
     }
-    close(fd);
 
     usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
     if (usbdev)
@@ -151,11 +190,16 @@ static void try_add_device(struct udev_device *dev)
 
     if (device)
     {
-        impl_from_DEVICE_OBJECT(device)->udev_device = udev_device_ref(dev);
+        struct platform_private *private = impl_from_DEVICE_OBJECT(device);
+        private->udev_device = udev_device_ref(dev);
+        private->device_fd = fd;
         IoInvalidateDeviceRelations(device, BusRelations);
     }
     else
+    {
         WARN("Ignoring device %s with subsystem %s\n", debugstr_a(devnode), subsystem);
+        close(fd);
+    }
 
     HeapFree(GetProcessHeap(), 0, serial);
 }
@@ -163,9 +207,12 @@ static void try_add_device(struct udev_device *dev)
 static void try_remove_device(struct udev_device *dev)
 {
     DEVICE_OBJECT *device = bus_find_hid_device(&hidraw_vtbl, dev);
+    struct platform_private *private;
     if (!device) return;
 
-    dev = impl_from_DEVICE_OBJECT(device)->udev_device;
+    private = impl_from_DEVICE_OBJECT(device);
+    dev = private->udev_device;
+    close(private->device_fd);
     bus_remove_hid_device(device);
     udev_device_unref(dev);
 }
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c
index eaa0b93..bf7071d 100644
--- a/dlls/winebus.sys/main.c
+++ b/dlls/winebus.sys/main.c
@@ -352,7 +352,7 @@ NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp)
 {
     NTSTATUS status = irp->IoStatus.u.Status;
     IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
-    struct device_extension *extension = (struct device_extension *)device->DeviceExtension;
+    struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
 
     TRACE("(%p, %p)\n", device, irp);
 
@@ -370,12 +370,46 @@ NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp)
             }
 
             memset(attr, 0, sizeof(*attr));
-            attr->Size = sizeof(HID_DEVICE_ATTRIBUTES);
-            attr->VendorID = extension->vid;
-            attr->ProductID = extension->pid;
-            attr->VersionNumber = extension->version;
+            attr->Size = sizeof(*attr);
+            attr->VendorID = ext->vid;
+            attr->ProductID = ext->pid;
+            attr->VersionNumber = ext->version;
+
+            irp->IoStatus.u.Status = status = STATUS_SUCCESS;
+            irp->IoStatus.Information = sizeof(*attr);
+            break;
+        }
+        case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
+        {
+            HID_DESCRIPTOR *descriptor = (HID_DESCRIPTOR *)irp->UserBuffer;
+            DWORD length;
+            TRACE("IOCTL_HID_GET_DEVICE_DESCRIPTOR\n");
+
+            if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*descriptor))
+            {
+                irp->IoStatus.u.Status = status = STATUS_BUFFER_TOO_SMALL;
+                break;
+            }
+
+            status = ext->vtbl->get_reportdescriptor(device, NULL, 0, &length);
+            if (status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
+            {
+                WARN("Failed to get platform report descriptor length\n");
+                irp->IoStatus.u.Status = status;
+                break;
+            }
+
+            memset(descriptor, 0, sizeof(*descriptor));
+            descriptor->bLength = sizeof(*descriptor);
+            descriptor->bDescriptorType = HID_HID_DESCRIPTOR_TYPE;
+            descriptor->bcdHID = HID_REVISION;
+            descriptor->bCountry = 0;
+            descriptor->bNumDescriptors = 1;
+            descriptor->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE;
+            descriptor->DescriptorList[0].wReportLength = length;
+
             irp->IoStatus.u.Status = status = STATUS_SUCCESS;
-            irp->IoStatus.Information = sizeof(HID_DEVICE_ATTRIBUTES);
+            irp->IoStatus.Information = sizeof(*descriptor);
             break;
         }
         default:
-- 
2.9.0



More information about the wine-patches mailing list