forked from Mirrors/wine-wine
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>oldstable
parent
53943a4c31
commit
eac738b95f
|
@ -6805,6 +6805,7 @@ for ac_header in \
|
||||||
linux/compiler.h \
|
linux/compiler.h \
|
||||||
linux/filter.h \
|
linux/filter.h \
|
||||||
linux/hdreg.h \
|
linux/hdreg.h \
|
||||||
|
linux/hidraw.h \
|
||||||
linux/input.h \
|
linux/input.h \
|
||||||
linux/ioctl.h \
|
linux/ioctl.h \
|
||||||
linux/joystick.h \
|
linux/joystick.h \
|
||||||
|
|
|
@ -426,6 +426,7 @@ AC_CHECK_HEADERS(\
|
||||||
linux/compiler.h \
|
linux/compiler.h \
|
||||||
linux/filter.h \
|
linux/filter.h \
|
||||||
linux/hdreg.h \
|
linux/hdreg.h \
|
||||||
|
linux/hidraw.h \
|
||||||
linux/input.h \
|
linux/input.h \
|
||||||
linux/ioctl.h \
|
linux/ioctl.h \
|
||||||
linux/joystick.h \
|
linux/joystick.h \
|
||||||
|
|
|
@ -23,6 +23,7 @@ NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int (*compare_platform_device)(DEVICE_OBJECT *device, void *platform_dev);
|
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;
|
} platform_vtbl;
|
||||||
|
|
||||||
void *get_platform_private(DEVICE_OBJECT *device) DECLSPEC_HIDDEN;
|
void *get_platform_private(DEVICE_OBJECT *device) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -35,6 +35,12 @@
|
||||||
#ifdef HAVE_LIBUDEV_H
|
#ifdef HAVE_LIBUDEV_H
|
||||||
# include <libudev.h>
|
# include <libudev.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LINUX_HIDRAW_H
|
||||||
|
# include <linux/hidraw.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SYS_IOCTL_H
|
||||||
|
# include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define NONAMELESSUNION
|
#define NONAMELESSUNION
|
||||||
|
|
||||||
|
@ -64,6 +70,7 @@ DEFINE_GUID(GUID_DEVCLASS_HIDRAW, 0x3def44ad,0x242e,0x46e5,0x82,0x6d,0x70,0x72,0
|
||||||
struct platform_private
|
struct platform_private
|
||||||
{
|
{
|
||||||
struct udev_device *udev_device;
|
struct udev_device *udev_device;
|
||||||
|
int device_fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
|
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));
|
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 =
|
static const platform_vtbl hidraw_vtbl =
|
||||||
{
|
{
|
||||||
compare_platform_device,
|
compare_platform_device,
|
||||||
|
hidraw_get_reportdescriptor,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void try_add_device(struct udev_device *dev)
|
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));
|
WARN("Unable to open udev device %s: %s\n", debugstr_a(devnode), strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
close(fd);
|
|
||||||
|
|
||||||
usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
|
usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
|
||||||
if (usbdev)
|
if (usbdev)
|
||||||
|
@ -151,11 +190,16 @@ static void try_add_device(struct udev_device *dev)
|
||||||
|
|
||||||
if (device)
|
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);
|
IoInvalidateDeviceRelations(device, BusRelations);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
WARN("Ignoring device %s with subsystem %s\n", debugstr_a(devnode), subsystem);
|
WARN("Ignoring device %s with subsystem %s\n", debugstr_a(devnode), subsystem);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, serial);
|
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)
|
static void try_remove_device(struct udev_device *dev)
|
||||||
{
|
{
|
||||||
DEVICE_OBJECT *device = bus_find_hid_device(&hidraw_vtbl, dev);
|
DEVICE_OBJECT *device = bus_find_hid_device(&hidraw_vtbl, dev);
|
||||||
|
struct platform_private *private;
|
||||||
if (!device) return;
|
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);
|
bus_remove_hid_device(device);
|
||||||
udev_device_unref(dev);
|
udev_device_unref(dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,7 +352,7 @@ NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp)
|
||||||
{
|
{
|
||||||
NTSTATUS status = irp->IoStatus.u.Status;
|
NTSTATUS status = irp->IoStatus.u.Status;
|
||||||
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
|
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);
|
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));
|
memset(attr, 0, sizeof(*attr));
|
||||||
attr->Size = sizeof(HID_DEVICE_ATTRIBUTES);
|
attr->Size = sizeof(*attr);
|
||||||
attr->VendorID = extension->vid;
|
attr->VendorID = ext->vid;
|
||||||
attr->ProductID = extension->pid;
|
attr->ProductID = ext->pid;
|
||||||
attr->VersionNumber = extension->version;
|
attr->VersionNumber = ext->version;
|
||||||
|
|
||||||
irp->IoStatus.u.Status = status = STATUS_SUCCESS;
|
irp->IoStatus.u.Status = status = STATUS_SUCCESS;
|
||||||
irp->IoStatus.Information = sizeof(HID_DEVICE_ATTRIBUTES);
|
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(*descriptor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -435,6 +435,9 @@
|
||||||
/* Define to 1 if you have the <linux/hdreg.h> header file. */
|
/* Define to 1 if you have the <linux/hdreg.h> header file. */
|
||||||
#undef HAVE_LINUX_HDREG_H
|
#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. */
|
/* Define to 1 if you have the <linux/input.h> header file. */
|
||||||
#undef HAVE_LINUX_INPUT_H
|
#undef HAVE_LINUX_INPUT_H
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue