Aric Stewart : winebus.sys: Implement IOCTL_HID_GET_DEVICE_DESCRIPTOR for hidraw.
Alexandre Julliard
julliard at winehq.org
Tue Oct 11 15:21:11 CDT 2016
Module: wine
Branch: master
Commit: eac738b95f8b26b9e5f59e0e51d33ecb5eb91594
URL: http://source.winehq.org/git/wine.git/?a=commit;h=eac738b95f8b26b9e5f59e0e51d33ecb5eb91594
Author: Aric Stewart <aric at 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 at codeweavers.com>
Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
Signed-off-by: Alexandre Julliard <julliard at 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
More information about the wine-cvs
mailing list