Module: wine Branch: master Commit: eac738b95f8b26b9e5f59e0e51d33ecb5eb91594 URL: http://source.winehq.org/git/wine.git/?a=commit;h=eac738b95f8b26b9e5f59e0e51...
Author: Aric Stewart aric@codeweavers.com Date: Tue Oct 11 14:09:35 2016 +0200
winebus.sys: Implement IOCTL_HID_GET_DEVICE_DESCRIPTOR for hidraw.
Signed-off-by: Aric Stewart aric@codeweavers.com Signed-off-by: Sebastian Lackner sebastian@fds-team.de Signed-off-by: Alexandre Julliard julliard@winehq.org
---
configure | 1 + configure.ac | 1 + dlls/winebus.sys/bus.h | 1 + dlls/winebus.sys/bus_udev.c | 53 ++++++++++++++++++++++++++++++++++++++++++--- dlls/winebus.sys/main.c | 46 ++++++++++++++++++++++++++++++++++----- include/config.h.in | 3 +++ 6 files changed, 96 insertions(+), 9 deletions(-)
diff --git a/configure b/configure index e3181e0..bd0a1b9 100755 --- a/configure +++ b/configure @@ -6805,6 +6805,7 @@ for ac_header in \ linux/compiler.h \ linux/filter.h \ linux/hdreg.h \ + linux/hidraw.h \ linux/input.h \ linux/ioctl.h \ linux/joystick.h \ 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: diff --git a/include/config.h.in b/include/config.h.in index bcee452..40909fe 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -435,6 +435,9 @@ /* Define to 1 if you have the <linux/hdreg.h> header file. */ #undef HAVE_LINUX_HDREG_H
+/* Define to 1 if you have the <linux/hidraw.h> header file. */ +#undef HAVE_LINUX_HIDRAW_H + /* Define to 1 if you have the <linux/input.h> header file. */ #undef HAVE_LINUX_INPUT_H