Based on contributions from Andrew Conrad, Arkadiusz Hiler, Ivo Ivanov, and Kai Krakow.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winebus.sys/bus_sdl.c | 20 +++++++++++------ dlls/winebus.sys/bus_udev.c | 13 ++++++----- dlls/winebus.sys/unixlib.c | 44 ++++++++++++++++++++++--------------- 3 files changed, 46 insertions(+), 31 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 71f91162fb1..822b91fcba0 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -443,17 +443,12 @@ static void sdl_device_destroy(struct unix_device *iface) static NTSTATUS sdl_device_start(struct unix_device *iface) { struct sdl_device *impl = impl_from_unix_device(iface); - NTSTATUS status;
pthread_mutex_lock(&sdl_cs); - - if (impl->sdl_controller) status = build_controller_report_descriptor(iface); - else status = build_joystick_report_descriptor(iface); - impl->started = !status; - + impl->started = TRUE; pthread_mutex_unlock(&sdl_cs);
- return status; + return STATUS_SUCCESS; }
static void sdl_device_stop(struct unix_device *iface) @@ -1006,6 +1001,8 @@ static void sdl_add_device(unsigned int index)
for (axis_offset = 0; axis_offset < axis_count; axis_offset += (options.split_controllers ? 6 : axis_count)) { + NTSTATUS status; + if (!axis_offset) strcpy(buffer, product); else snprintf(buffer, ARRAY_SIZE(buffer), "%s %d", product, axis_offset / 6); ntdll_umbstowcs(buffer, strlen(buffer) + 1, desc.product, ARRAY_SIZE(desc.product)); @@ -1019,6 +1016,15 @@ static void sdl_add_device(unsigned int index) impl->id = id; impl->axis_offset = axis_offset;
+ if (impl->sdl_controller) status = build_controller_report_descriptor(&impl->unix_device); + else status = build_joystick_report_descriptor(&impl->unix_device); + if (status) + { + list_remove(&impl->unix_device.entry); + impl->unix_device.vtbl->destroy(&impl->unix_device); + return; + } + bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc); } } diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 30c44979992..cb16dd39451 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -728,12 +728,6 @@ static void lnxev_device_destroy(struct unix_device *iface)
static NTSTATUS lnxev_device_start(struct unix_device *iface) { - struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); - NTSTATUS status; - - if ((status = build_report_descriptor(iface, impl->base.udev_device))) - return status; - pthread_mutex_lock(&udev_cs); start_polling_device(iface); pthread_mutex_unlock(&udev_cs); @@ -1321,6 +1315,13 @@ static void udev_add_device(struct udev_device *dev, int fd) strcpy(impl->devnode, devnode); impl->device_fd = fd;
+ if (build_report_descriptor(&impl->unix_device, impl->udev_device)) + { + list_remove(&impl->unix_device.entry); + impl->unix_device.vtbl->destroy(&impl->unix_device); + return; + } + bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc); } #endif diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 2668468305c..bd4351f059c 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -49,14 +49,6 @@ static void mouse_destroy(struct unix_device *iface)
static NTSTATUS mouse_start(struct unix_device *iface) { - const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_MOUSE}; - if (!hid_device_begin_report_descriptor(iface, &device_usage)) - return STATUS_NO_MEMORY; - if (!hid_device_add_buttons(iface, HID_USAGE_PAGE_BUTTON, 1, 3)) - return STATUS_NO_MEMORY; - if (!hid_device_end_report_descriptor(iface)) - return STATUS_NO_MEMORY; - return STATUS_SUCCESS; }
@@ -123,9 +115,21 @@ static const struct device_desc mouse_device_desc =
static NTSTATUS mouse_device_create(void *args) { + const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_MOUSE}; struct device_create_params *params = args; + struct unix_device *iface; + + if (!(iface = hid_device_create(&mouse_vtbl, sizeof(struct mouse_device)))) + return STATUS_NO_MEMORY; + if (!hid_device_begin_report_descriptor(iface, &device_usage)) + return STATUS_NO_MEMORY; + if (!hid_device_add_buttons(iface, HID_USAGE_PAGE_BUTTON, 1, 3)) + return STATUS_NO_MEMORY; + if (!hid_device_end_report_descriptor(iface)) + return STATUS_NO_MEMORY; + params->desc = mouse_device_desc; - params->device = (UINT_PTR)hid_device_create(&mouse_vtbl, sizeof(struct mouse_device)); + params->device = (UINT_PTR)iface; return STATUS_SUCCESS; }
@@ -140,14 +144,6 @@ static void keyboard_destroy(struct unix_device *iface)
static NTSTATUS keyboard_start(struct unix_device *iface) { - const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_KEYBOARD}; - if (!hid_device_begin_report_descriptor(iface, &device_usage)) - return STATUS_NO_MEMORY; - if (!hid_device_add_buttons(iface, HID_USAGE_PAGE_KEYBOARD, 0, 101)) - return STATUS_NO_MEMORY; - if (!hid_device_end_report_descriptor(iface)) - return STATUS_NO_MEMORY; - return STATUS_SUCCESS; }
@@ -214,9 +210,21 @@ static const struct device_desc keyboard_device_desc =
static NTSTATUS keyboard_device_create(void *args) { + const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_KEYBOARD}; struct device_create_params *params = args; + struct unix_device *iface; + + if (!(iface = hid_device_create(&keyboard_vtbl, sizeof(struct keyboard_device)))) + return STATUS_NO_MEMORY; + if (!hid_device_begin_report_descriptor(iface, &device_usage)) + return STATUS_NO_MEMORY; + if (!hid_device_add_buttons(iface, HID_USAGE_PAGE_KEYBOARD, 0, 101)) + return STATUS_NO_MEMORY; + if (!hid_device_end_report_descriptor(iface)) + return STATUS_NO_MEMORY; + params->desc = keyboard_device_desc; - params->device = (UINT_PTR)hid_device_create(&keyboard_vtbl, sizeof(struct keyboard_device)); + params->device = (UINT_PTR)iface; return STATUS_SUCCESS; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winebus.sys/bus_iohid.c | 9 +++++---- dlls/winebus.sys/bus_sdl.c | 4 ---- dlls/winebus.sys/bus_udev.c | 3 --- dlls/winebus.sys/main.c | 12 +++++++----- dlls/winebus.sys/unixlib.h | 5 ++--- 5 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/dlls/winebus.sys/bus_iohid.c b/dlls/winebus.sys/bus_iohid.c index 45cca15c82a..5a210fc6bbd 100644 --- a/dlls/winebus.sys/bus_iohid.c +++ b/dlls/winebus.sys/bus_iohid.c @@ -275,10 +275,11 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void * .serialnumber = {'0','0','0','0',0}, }; struct iohid_device *impl; + USAGE_AND_PAGE usages; CFStringRef str;
- desc.usages.UsagePage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsagePageKey))); - desc.usages.Usage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsageKey))); + usages.UsagePage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsagePageKey))); + usages.Usage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsageKey)));
desc.vid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDVendorIDKey))); desc.pid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDProductIDKey))); @@ -289,8 +290,8 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void * desc.is_bluetooth = !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothValue), 0) || !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothLowEnergyValue), 0);
- if (desc.usages.UsagePage != HID_USAGE_PAGE_GENERIC || - !(desc.usages.Usage == HID_USAGE_GENERIC_JOYSTICK || desc.usages.Usage == HID_USAGE_GENERIC_GAMEPAD)) + if (usages.UsagePage != HID_USAGE_PAGE_GENERIC || + !(usages.Usage == HID_USAGE_GENERIC_JOYSTICK || usages.Usage == HID_USAGE_GENERIC_GAMEPAD)) { /* winebus isn't currently meant to handle anything but these, and * opening keyboards, mice, or the Touch Bar on older MacBooks triggers diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 822b91fcba0..b2c60e94f07 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -986,8 +986,6 @@ static void sdl_add_device(unsigned int index) if (controller) { desc.is_gamepad = TRUE; - desc.usages.UsagePage = HID_USAGE_PAGE_GENERIC; - desc.usages.Usage = HID_USAGE_GENERIC_GAMEPAD; axis_count = 6; } else @@ -995,8 +993,6 @@ static void sdl_add_device(unsigned int index) int button_count = pSDL_JoystickNumButtons(joystick); axis_count = pSDL_JoystickNumAxes(joystick); desc.is_gamepad = (axis_count == 6 && button_count >= 14); - desc.usages.UsagePage = HID_USAGE_PAGE_GENERIC; - desc.usages.Usage = HID_USAGE_GENERIC_JOYSTICK; }
for (axis_offset = 0; axis_offset < axis_count; axis_offset += (options.split_controllers ? 6 : axis_count)) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index cb16dd39451..561f0cdc0e4 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1248,7 +1248,6 @@ static void udev_add_device(struct udev_device *dev, int fd) #ifdef HAS_PROPER_INPUT_HEADER else if (!strcmp(subsystem, "input")) { - const USAGE_AND_PAGE device_usage = *what_am_I(dev, fd); static const WCHAR evdev[] = {'e','v','d','e','v',0}; struct input_id device_id = {0}; char buffer[MAX_PATH]; @@ -1269,8 +1268,6 @@ static void udev_add_device(struct udev_device *dev, int fd)
if (!desc.serialnumber[0] && ioctl(fd, EVIOCGUNIQ(sizeof(buffer)), buffer) >= 0) ntdll_umbstowcs(buffer, strlen(buffer) + 1, desc.serialnumber, ARRAY_SIZE(desc.serialnumber)); - - desc.usages = device_usage; } #endif
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 5128f737af1..d267606b2cf 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -684,7 +684,7 @@ static NTSTATUS get_device_descriptors(UINT64 unix_device, BYTE **report_desc, U return STATUS_SUCCESS; }
-static USAGE_AND_PAGE get_hidraw_device_usages(UINT64 unix_device) +static USAGE_AND_PAGE get_device_usages(UINT64 unix_device) { HIDP_DEVICE_DESC device_desc; USAGE_AND_PAGE usages = {0}; @@ -749,18 +749,20 @@ static DWORD CALLBACK bus_main_thread(void *args) case BUS_EVENT_TYPE_DEVICE_CREATED: { struct device_desc desc = event->device_created.desc; - if (desc.is_hidraw && !desc.usages.UsagePage) desc.usages = get_hidraw_device_usages(event->device); - if (!desc.is_hidraw != !is_hidraw_enabled(desc.vid, desc.pid, &desc.usages)) + USAGE_AND_PAGE usages; + + usages = get_device_usages(event->device); + if (!desc.is_hidraw != !is_hidraw_enabled(desc.vid, desc.pid, &usages)) { struct device_remove_params params = {.device = event->device}; WARN("ignoring %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-", - desc.vid, desc.pid, desc.usages.UsagePage, desc.usages.Usage); + desc.vid, desc.pid, usages.UsagePage, usages.Usage); winebus_call(device_remove, ¶ms); break; }
TRACE("creating %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-", - desc.vid, desc.pid, desc.usages.UsagePage, desc.usages.Usage); + desc.vid, desc.pid, usages.UsagePage, usages.Usage);
device = bus_create_hid_device(&event->device_created.desc, event->device); if (device) IoInvalidateDeviceRelations(bus_pdo, BusRelations); diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h index b38382cda2c..02e7a1c6953 100644 --- a/dlls/winebus.sys/unixlib.h +++ b/dlls/winebus.sys/unixlib.h @@ -38,7 +38,6 @@ struct device_desc UINT version; UINT input; UINT uid; - USAGE_AND_PAGE usages; BOOL is_gamepad; BOOL is_hidraw; BOOL is_bluetooth; @@ -151,8 +150,8 @@ enum unix_funcs static inline const char *debugstr_device_desc(struct device_desc *desc) { if (!desc) return "(null)"; - return wine_dbg_sprintf("{vid %04x, pid %04x, version %04x, input %d, uid %08x, usage %04x:%04x, is_gamepad %u, is_hidraw %u, is_bluetooth %u}", - desc->vid, desc->pid, desc->version, desc->input, desc->uid, desc->usages.UsagePage, desc->usages.Usage, + return wine_dbg_sprintf("{vid %04x, pid %04x, version %04x, input %d, uid %08x, is_gamepad %u, is_hidraw %u, is_bluetooth %u}", + desc->vid, desc->pid, desc->version, desc->input, desc->uid, desc->is_gamepad, desc->is_hidraw, desc->is_bluetooth); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winebus.sys/main.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index d267606b2cf..9c43df09910 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -417,7 +417,7 @@ static DWORD check_bus_option(const WCHAR *option, DWORD default_value) return default_value; }
-static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages) +static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages, UINT buttons) { char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024])]; KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; @@ -684,22 +684,41 @@ static NTSTATUS get_device_descriptors(UINT64 unix_device, BYTE **report_desc, U return STATUS_SUCCESS; }
-static USAGE_AND_PAGE get_device_usages(UINT64 unix_device) +static USAGE_AND_PAGE get_device_usages(UINT64 unix_device, UINT *buttons) { HIDP_DEVICE_DESC device_desc; USAGE_AND_PAGE usages = {0}; - UINT report_desc_length; + UINT i, count = 0, report_desc_length; + HIDP_BUTTON_CAPS *button_caps; BYTE *report_desc; NTSTATUS status; + HIDP_CAPS caps;
if (!(status = get_device_descriptors(unix_device, &report_desc, &report_desc_length, &device_desc))) { + PHIDP_PREPARSED_DATA preparsed = device_desc.CollectionDesc[0].PreparsedData; usages.UsagePage = device_desc.CollectionDesc[0].UsagePage; usages.Usage = device_desc.CollectionDesc[0].Usage; + + if ((status = HidP_GetCaps(preparsed, &caps)) == HIDP_STATUS_SUCCESS && + (button_caps = malloc(sizeof(*button_caps) * caps.NumberInputButtonCaps))) + { + status = HidP_GetButtonCaps(HidP_Input, button_caps, &caps.NumberInputButtonCaps, preparsed); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetButtonCaps returned %#lx\n", status); + else for (i = 0; i < caps.NumberInputButtonCaps; i++) + { + if (button_caps[i].UsagePage != HID_USAGE_PAGE_BUTTON) continue; + if (button_caps[i].IsRange) count = max(count, button_caps[i].Range.UsageMax); + else count = max(count, button_caps[i].NotRange.Usage); + } + free(button_caps); + } + HidP_FreeCollectionDescription(&device_desc); RtlFreeHeap(GetProcessHeap(), 0, report_desc); }
+ *buttons = count; return usages; }
@@ -750,9 +769,10 @@ static DWORD CALLBACK bus_main_thread(void *args) { struct device_desc desc = event->device_created.desc; USAGE_AND_PAGE usages; + UINT buttons;
- usages = get_device_usages(event->device); - if (!desc.is_hidraw != !is_hidraw_enabled(desc.vid, desc.pid, &usages)) + usages = get_device_usages(event->device, &buttons); + if (!desc.is_hidraw != !is_hidraw_enabled(desc.vid, desc.pid, &usages, buttons)) { struct device_remove_params params = {.device = event->device}; WARN("ignoring %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-",
From: Rémi Bernon rbernon@codeweavers.com
Based on contributions from Andrew Conrad, Arkadiusz Hiler, Ivo Ivanov, and Kai Krakow. --- dlls/winebus.sys/main.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 9c43df09910..2522e2e6b8b 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -436,6 +436,48 @@ static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages, if (is_dualshock4_gamepad(vid, pid)) prefer_hidraw = TRUE; if (is_dualsense_gamepad(vid, pid)) prefer_hidraw = TRUE;
+ switch (vid) + { + case 0x044f: + if (pid == 0xb679) prefer_hidraw = TRUE; /* ThrustMaster T-Rudder */ + if (pid == 0xb687) prefer_hidraw = TRUE; /* ThrustMaster TWCS Throttle */ + if (pid == 0xb10a) prefer_hidraw = TRUE; /* ThrustMaster T.16000M Joystick */ + break; + case 0x16d0: + if (pid == 0x0d61) prefer_hidraw = TRUE; /* Simucube 2 Sport */ + if (pid == 0x0d60) prefer_hidraw = TRUE; /* Simucube 2 Pro */ + if (pid == 0x0d5f) prefer_hidraw = TRUE; /* Simucube 2 Ultimate */ + if (pid == 0x0d5a) prefer_hidraw = TRUE; /* Simucube 1 */ + break; + case 0x0eb7: + if (pid == 0x183b) prefer_hidraw = TRUE; /* Fanatec ClubSport Pedals v3 */ + if (pid == 0x1839) prefer_hidraw = TRUE; /* Fanatec ClubSport Pedals v1/v2 */ + break; + case 0x231d: + /* comes with 128 buttons in the default configuration */ + if (buttons == 128) prefer_hidraw = TRUE; + /* if customized, less than 128 buttons may be shown, decide by PID */ + if (pid == 0x0200) prefer_hidraw = TRUE; /* VKBsim Gladiator EVO Right Grip */ + if (pid == 0x0201) prefer_hidraw = TRUE; /* VKBsim Gladiator EVO Left Grip */ + if (pid == 0x0126) prefer_hidraw = TRUE; /* VKB-Sim Space Gunfighter */ + if (pid == 0x0127) prefer_hidraw = TRUE; /* VKB-Sim Space Gunfighter L */ + break; + case 0x3344: + /* comes with 31 buttons in the default configuration, or 128 max */ + if ((buttons == 31) || (buttons == 128)) prefer_hidraw = TRUE; + /* users may have configured button limits, usually 32/50/64 */ + if ((buttons == 32) || (buttons == 50) || (buttons == 64)) prefer_hidraw = TRUE; + /* if customized, arbitrary amount of buttons may be shown, decide by PID */ + if (pid == 0x412f) prefer_hidraw = TRUE; /* Virpil Constellation ALPHA-R */ + if (pid == 0x812c) prefer_hidraw = TRUE; /* Virpil Constellation ALPHA-L */ + break; + case 0x03eb: + /* users may have configured button limits, usually 32/50/64 */ + if ((buttons == 32) || (buttons == 50) || (buttons == 64)) prefer_hidraw = TRUE; + if (pid == 0x2055) prefer_hidraw = TRUE; /* ATMEL/VIRPIL/200325 VPC Throttle MT-50 CM2 */ + break; + } + RtlInitUnicodeString(&str, L"EnableHidraw"); if (!NtQueryValueKey(driver_key, &str, KeyValuePartialInformation, info, sizeof(buffer) - sizeof(WCHAR), &size))