Aric Stewart : winebus.sys: Be more specific as to what we offer as IG_ enumerated devices.

Alexandre Julliard julliard at winehq.org
Thu Feb 15 14:42:28 CST 2018


Module: wine
Branch: master
Commit: e48296c2f02081d224505c90e645985f95b30d1d
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=e48296c2f02081d224505c90e645985f95b30d1d

Author: Aric Stewart <aric at 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 at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at 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};




More information about the wine-cvs mailing list