Module: wine Branch: master Commit: e48296c2f02081d224505c90e645985f95b30d1d URL: https://source.winehq.org/git/wine.git/?a=commit;h=e48296c2f02081d224505c90e...
Author: Aric Stewart aric@codeweavers.com Date: Wed Feb 14 12:24:27 2018 -0600
winebus.sys: Be more specific as to what we offer as IG_ enumerated devices.
Signed-off-by: Aric Stewart aric@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/winebus.sys/bus.h | 1 + dlls/winebus.sys/bus_iohid.c | 48 +++++++++++++++++++++++++-- dlls/winebus.sys/bus_udev.c | 79 +++++++++++++++++++++++++++++++++----------- dlls/winebus.sys/main.c | 29 ++++++++++++++++ 4 files changed, 135 insertions(+), 22 deletions(-)
diff --git a/dlls/winebus.sys/bus.h b/dlls/winebus.sys/bus.h index 34783f2..141e6d6 100644 --- a/dlls/winebus.sys/bus.h +++ b/dlls/winebus.sys/bus.h @@ -49,3 +49,4 @@ DEVICE_OBJECT* bus_enumerate_hid_devices(const platform_vtbl *vtbl, enum_func fu
/* General Bus Functions */ DWORD check_bus_option(UNICODE_STRING *registry_path, const UNICODE_STRING *option, DWORD default_value) DECLSPEC_HIDDEN; +BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; diff --git a/dlls/winebus.sys/bus_iohid.c b/dlls/winebus.sys/bus_iohid.c index 10635f8..501a40d 100644 --- a/dlls/winebus.sys/bus_iohid.c +++ b/dlls/winebus.sys/bus_iohid.c @@ -287,7 +287,7 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void * DWORD vid, pid, version; CFStringRef str = NULL; WCHAR serial_string[256]; - BOOL is_gamepad; + BOOL is_gamepad = FALSE;
TRACE("OS/X IOHID Device Added %p\n", IOHIDDevice);
@@ -297,8 +297,50 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void * str = IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDSerialNumberKey)); if (str) CFStringToWSTR(str, serial_string, sizeof(serial_string) / sizeof(WCHAR));
- is_gamepad = (IOHIDDeviceConformsTo(IOHIDDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad) || - IOHIDDeviceConformsTo(IOHIDDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick)); + if (IOHIDDeviceConformsTo(IOHIDDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad) || + IOHIDDeviceConformsTo(IOHIDDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick)) + { + if (is_xbox_gamepad(vid, pid)) + is_gamepad = TRUE; + else + { + int axes=0, buttons=0; + CFArrayRef element_array = IOHIDDeviceCopyMatchingElements( + IOHIDDevice, NULL, kIOHIDOptionsTypeNone); + + if (element_array) { + CFIndex index; + CFIndex count = CFArrayGetCount(element_array); + for (index = 0; index < count; index++) + { + IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(element_array, index); + if (element) + { + int type = IOHIDElementGetType(element); + if (type == kIOHIDElementTypeInput_Button) buttons++; + if (type == kIOHIDElementTypeInput_Axis) axes++; + if (type == kIOHIDElementTypeInput_Misc) + { + uint32_t usage = IOHIDElementGetUsage(element); + switch (usage) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + axes ++; + } + } + } + } + CFRelease(element_array); + } + is_gamepad = (axes == 6 && buttons >= 14); + } + }
device = bus_create_hid_device(iohid_driver_obj, busidW, vid, pid, version, 0, str?serial_string:NULL, is_gamepad, &GUID_DEVCLASS_IOHID, &iohid_vtbl, sizeof(struct platform_private)); if (!device) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index f80c5d7..18e1854 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -439,13 +439,55 @@ static void set_rel_axis_value(struct wine_input_private *ext, int code, int val } }
+static INT count_buttons(int device_fd, BYTE *map) +{ + int i; + int button_count = 0; + BYTE keybits[(KEY_MAX+7)/8]; + + if (ioctl(device_fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits) == -1) + { + WARN("ioctl(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno)); + return FALSE; + } + + for (i = BTN_MISC; i < KEY_MAX; i++) + { + if (test_bit(keybits, i)) + { + if (map) map[i] = button_count; + button_count++; + } + } + return button_count; +} + +static INT count_abs_axis(int device_fd) +{ + BYTE absbits[(ABS_MAX+7)/8]; + int abs_count = 0; + int i; + + if (ioctl(device_fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits) == -1) + { + WARN("ioctl(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno)); + return 0; + } + + for (i = 0; i < HID_ABS_MAX; i++) + if (test_bit(absbits, i) && + (ABS_TO_HID_MAP[i][1] >= HID_USAGE_GENERIC_X && + ABS_TO_HID_MAP[i][1] <= HID_USAGE_GENERIC_WHEEL)) + abs_count++; + return abs_count; +} + static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_device *dev) { int abs_pages[TOP_ABS_PAGE][HID_ABS_MAX+1]; int rel_pages[TOP_REL_PAGE][HID_REL_MAX+1]; BYTE absbits[(ABS_MAX+7)/8]; BYTE relbits[(REL_MAX+7)/8]; - BYTE keybits[(KEY_MAX+7)/8]; BYTE *report_ptr; INT i, descript_size; INT report_size; @@ -462,25 +504,12 @@ static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_ WARN("ioctl(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno)); return FALSE; } - if (ioctl(ext->base.device_fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits) == -1) - { - WARN("ioctl(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno)); - return FALSE; - }
descript_size = sizeof(REPORT_HEADER) + sizeof(REPORT_TAIL); report_size = 0;
/* For now lump all buttons just into incremental usages, Ignore Keys */ - button_count = 0; - for (i = BTN_MISC; i < KEY_MAX; i++) - { - if (test_bit(keybits, i)) - { - ext->button_map[i] = button_count; - button_count++; - } - } + button_count = count_buttons(ext->base.device_fd, ext->button_map); if (button_count) { descript_size += sizeof(REPORT_BUTTONS); @@ -1138,7 +1167,7 @@ static void try_add_device(struct udev_device *dev) const char *subsystem; const char *devnode; WCHAR *serial = NULL; - const char* gamepad = NULL; + BOOL is_gamepad = FALSE; int fd;
if (!(devnode = udev_device_get_devnode(dev))) @@ -1188,7 +1217,6 @@ static void try_add_device(struct udev_device *dev) if (ioctl(fd, EVIOCGUNIQ(254), device_uid) >= 0 && device_uid[0]) serial = strdupAtoW(device_uid);
- gamepad = udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK"); vid = device_id.vendor; pid = device_id.product; version = device_id.version; @@ -1198,18 +1226,31 @@ static void try_add_device(struct udev_device *dev) WARN("Could not get device to query VID, PID, Version and Serial\n"); #endif
+ if (is_xbox_gamepad(vid, pid)) + is_gamepad = TRUE; +#ifdef HAS_PROPER_INPUT_HEADER + else + { + int axes=0, buttons=0; + axes = count_abs_axis(fd); + buttons = count_buttons(fd, NULL); + is_gamepad = (axes == 6 && buttons >= 14); + } +#endif + + TRACE("Found udev device %s (vid %04x, pid %04x, version %u, serial %s)\n", debugstr_a(devnode), vid, pid, version, debugstr_w(serial));
if (strcmp(subsystem, "hidraw") == 0) { - device = bus_create_hid_device(udev_driver_obj, hidraw_busidW, vid, pid, version, 0, serial, FALSE, + device = bus_create_hid_device(udev_driver_obj, hidraw_busidW, vid, pid, version, 0, serial, is_gamepad, &GUID_DEVCLASS_HIDRAW, &hidraw_vtbl, sizeof(struct platform_private)); } #ifdef HAS_PROPER_INPUT_HEADER else if (strcmp(subsystem, "input") == 0) { - device = bus_create_hid_device(udev_driver_obj, lnxev_busidW, vid, pid, version, 0, serial, (gamepad != NULL), + device = bus_create_hid_device(udev_driver_obj, lnxev_busidW, vid, pid, version, 0, serial, is_gamepad, &GUID_DEVCLASS_LINUXEVENT, &lnxev_vtbl, sizeof(struct wine_input_private)); } #endif diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 87d05f0..6334477 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -43,6 +43,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay); WINE_DECLARE_DEBUG_CHANNEL(hid_report);
+#define VID_MICROSOFT 0x045e + +static const WORD PID_XBOX_CONTROLLERS[] = { + 0x0202, /* Xbox Controller */ + 0x0285, /* Xbox Controller S */ + 0x0289, /* Xbox Controller S */ + 0x028e, /* Xbox360 Controller */ + 0x028f, /* Xbox360 Wireless Controller */ + 0x02d1, /* Xbox One Controller */ + 0x02dd, /* Xbox One Controller (Covert Forces/Firmware 2015) */ + 0x02e3, /* Xbox One Elite Controller */ + 0x02e6, /* Wireless XBox Controller Dongle */ + 0x02ea, /* Xbox One S Controller */ + 0x0719, /* Xbox 360 Wireless Adapter */ +}; + struct pnp_device { struct list entry; @@ -673,6 +689,19 @@ DWORD check_bus_option(UNICODE_STRING *registry_path, const UNICODE_STRING *opti return output; }
+BOOL is_xbox_gamepad(WORD vid, WORD pid) +{ + int i; + + if (vid != VID_MICROSOFT) + return FALSE; + + for (i = 0; i < sizeof(PID_XBOX_CONTROLLERS)/sizeof(*PID_XBOX_CONTROLLERS); i++) + if (pid == PID_XBOX_CONTROLLERS[i]) return TRUE; + + return FALSE; +} + NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) { static const WCHAR udevW[] = {'\','D','r','i','v','e','r','\','U','D','E','V',0};