Commit e48296c2 authored by Aric Stewart's avatar Aric Stewart Committed by Alexandre Julliard

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

parent 8a167d85
......@@ -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;
......@@ -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)
......
......@@ -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
......
......@@ -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};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment