The per-device/vendor option list is allocated on the PE side and shared with the unix, it should be alright to access linked list from both side as winebus should not need and doesn't implement WOW64.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winebus.sys/bus_iohid.c | 4 +- dlls/winebus.sys/bus_sdl.c | 18 ++++---- dlls/winebus.sys/bus_udev.c | 32 +++++++------ dlls/winebus.sys/main.c | 88 ++++++++++++++++++------------------ dlls/winebus.sys/unixlib.h | 18 ++------ 5 files changed, 78 insertions(+), 82 deletions(-)
diff --git a/dlls/winebus.sys/bus_iohid.c b/dlls/winebus.sys/bus_iohid.c index 5a210fc6bbd..67276a26c48 100644 --- a/dlls/winebus.sys/bus_iohid.c +++ b/dlls/winebus.sys/bus_iohid.c @@ -106,7 +106,7 @@ static IOHIDManagerRef hid_manager; static CFRunLoopRef run_loop; static struct list event_queue = LIST_INIT(event_queue); static struct list device_list = LIST_INIT(device_list); -static struct iohid_bus_options options; +static const struct bus_options *options;
struct iohid_device { @@ -352,7 +352,7 @@ NTSTATUS iohid_bus_init(void *args) { TRACE("args %p\n", args);
- options = *(struct iohid_bus_options *)args; + options = args;
if (!(hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, 0L))) { diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 5cec049a845..2c49f0f408b 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -61,7 +61,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(hid); #ifdef SONAME_LIBSDL2
static pthread_mutex_t sdl_cs = PTHREAD_MUTEX_INITIALIZER; -static struct sdl_bus_options options; +static const struct bus_options *options;
static void *sdl_handle = NULL; static UINT quit_event = -1; @@ -283,7 +283,7 @@ static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface) USAGE_AND_PAGE physical_usage;
axis_count = pSDL_JoystickNumAxes(impl->sdl_joystick); - if (options.split_controllers) axis_count = min(6, axis_count - impl->axis_offset); + if (options->split_controllers) axis_count = min(6, axis_count - impl->axis_offset); if (axis_count > ARRAY_SIZE(absolute_axis_usages)) { FIXME("More than %zu absolute axes found, ignoring.\n", ARRAY_SIZE(absolute_axis_usages)); @@ -952,7 +952,7 @@ static void sdl_add_device(unsigned int index) return; }
- if (options.map_controllers && pSDL_IsGameController(index)) + if (options->map_controllers && pSDL_IsGameController(index)) controller = pSDL_GameControllerOpen(index);
if (controller) product = pSDL_GameControllerName(controller); @@ -1027,7 +1027,7 @@ static void sdl_add_device(unsigned int index) }
bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc); - axis_offset += (options.split_controllers ? 6 : axis_count); + axis_offset += (options->split_controllers ? 6 : axis_count); } while (axis_offset < axis_count); } @@ -1050,7 +1050,7 @@ static void process_device_event(SDL_Event *event) if (impl) bus_event_queue_device_removed(&event_queue, &impl->unix_device); else WARN("Failed to find device with id %d\n", id); } - else if (event->type == SDL_JOYAXISMOTION && options.split_controllers) + else if (event->type == SDL_JOYAXISMOTION && options->split_controllers) { id = event->jaxis.which; impl = find_device_from_id_and_axis(id, event->jaxis.axis); @@ -1089,7 +1089,7 @@ NTSTATUS sdl_bus_init(void *args)
TRACE("args %p\n", args);
- options = *(struct sdl_bus_options *)args; + options = (struct bus_options *)args;
if (!(sdl_handle = dlopen(SONAME_LIBSDL2, RTLD_NOW))) { @@ -1182,10 +1182,10 @@ NTSTATUS sdl_bus_init(void *args) if (pSDL_GameControllerAddMapping(mapping) < 0) WARN("Failed to add environment mapping %s\n", pSDL_GetError()); } - else for (i = 0; i < options.mappings_count; ++i) + else for (i = 0; i < options->mappings_count; ++i) { - TRACE("Setting registry mapping %s\n", debugstr_a(options.mappings[i])); - if (pSDL_GameControllerAddMapping(options.mappings[i]) < 0) + TRACE("Setting registry mapping %s\n", debugstr_a(options->mappings[i])); + if (pSDL_GameControllerAddMapping(options->mappings[i]) < 0) WARN("Failed to add registry mapping %s\n", pSDL_GetError()); } } diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 39b810b7588..3f9a4fe43b9 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -99,7 +99,7 @@ static struct udev_monitor *udev_monitor; static int deviceloop_control[2]; static struct list event_queue = LIST_INIT(event_queue); static struct list device_list = LIST_INIT(device_list); -static struct udev_bus_options options; +static const struct bus_options *options;
struct base_device { @@ -1408,7 +1408,7 @@ static void build_initial_deviceset_direct(void) int n, len; DIR *dir;
- if (!options.disable_hidraw) + if (!options->disable_hidraw) { TRACE("Initial enumeration of /dev/hidraw*\n"); if (!(dir = opendir("/dev"))) WARN("Unable to open /dev: %s\n", strerror(errno)); @@ -1425,7 +1425,7 @@ static void build_initial_deviceset_direct(void) } } #ifdef HAS_PROPER_INPUT_HEADER - if (!options.disable_input) + if (!options->disable_input) { TRACE("Initial enumeration of /dev/input/event*\n"); if (!(dir = opendir("/dev/input"))) WARN("Unable to open /dev/input: %s\n", strerror(errno)); @@ -1454,7 +1454,7 @@ static int create_inotify(void) return fd; }
- if (!options.disable_hidraw) + if (!options->disable_hidraw) { /* We need to watch for attribute changes in addition to * creation, because when a device is first created, it has @@ -1466,7 +1466,7 @@ static int create_inotify(void) else systems++; } #ifdef HAS_PROPER_INPUT_HEADER - if (!options.disable_input) + if (!options->disable_input) { devinput_watch = inotify_add_watch(fd, "/dev/input", flags); if (devinput_watch < 0) WARN("Unable to initialize inotify for /dev/input: %s\n", strerror(errno)); @@ -1562,11 +1562,11 @@ static void build_initial_deviceset_udevd(void) return; }
- if (!options.disable_hidraw) + if (!options->disable_hidraw) if (udev_enumerate_add_match_subsystem(enumerate, "hidraw") < 0) WARN("Failed to add subsystem 'hidraw' to enumeration\n"); #ifdef HAS_PROPER_INPUT_HEADER - if (!options.disable_input) + if (!options->disable_input) { if (udev_enumerate_add_match_subsystem(enumerate, "input") < 0) WARN("Failed to add subsystem 'input' to enumeration\n"); @@ -1605,7 +1605,7 @@ static struct udev_monitor *create_monitor(int *fd) return NULL; }
- if (!options.disable_hidraw) + if (!options->disable_hidraw) { if (udev_monitor_filter_add_match_subsystem_devtype(monitor, "hidraw", NULL) < 0) WARN("Failed to add 'hidraw' subsystem to monitor\n"); @@ -1613,7 +1613,7 @@ static struct udev_monitor *create_monitor(int *fd) systems++; } #ifdef HAS_PROPER_INPUT_HEADER - if (!options.disable_input) + if (!options->disable_input) { if (udev_monitor_filter_add_match_subsystem_devtype(monitor, "input", NULL) < 0) WARN("Failed to add 'input' subsystem to monitor\n"); @@ -1685,10 +1685,12 @@ static void process_monitor_event(struct udev_monitor *monitor) NTSTATUS udev_bus_init(void *args) { int monitor_fd = -1; + BOOL disable_udevd;
TRACE("args %p\n", args);
- options = *(struct udev_bus_options *)args; + options = (struct bus_options *)args; + disable_udevd = options->disable_udevd;
if (pipe(deviceloop_control) != 0) { @@ -1703,11 +1705,11 @@ NTSTATUS udev_bus_init(void *args) }
#ifdef HAVE_SYS_INOTIFY_H - if (options.disable_udevd) monitor_fd = create_inotify(); - if (monitor_fd < 0) options.disable_udevd = FALSE; + if (disable_udevd) monitor_fd = create_inotify(); + if (monitor_fd < 0) disable_udevd = FALSE; #else - if (options.disable_udevd) ERR("inotify support not compiled in!\n"); - options.disable_udevd = FALSE; + if (disable_udevd) ERR("inotify support not compiled in!\n"); + disable_udevd = FALSE; #endif
if (monitor_fd < 0 && !(udev_monitor = create_monitor(&monitor_fd))) @@ -1726,7 +1728,7 @@ NTSTATUS udev_bus_init(void *args) poll_fds[1].revents = 0; poll_count = 2;
- if (!options.disable_udevd) build_initial_deviceset_udevd(); + if (!disable_udevd) build_initial_deviceset_udevd(); #ifdef HAVE_SYS_INOTIFY_H else build_initial_deviceset_direct(); #endif diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index e7f16d26a92..fec0c20ed68 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -51,6 +51,7 @@ static DEVICE_OBJECT *keyboard_obj; static DEVICE_OBJECT *bus_pdo; static DEVICE_OBJECT *bus_fdo;
+static struct bus_options options; static HANDLE driver_key;
struct hid_report @@ -426,7 +427,7 @@ static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages, UNICODE_STRING str; DWORD size;
- if (check_bus_option(L"DisableHidraw", FALSE)) return FALSE; + if (options.disable_hidraw) return FALSE;
if (usages->UsagePage == HID_USAGE_PAGE_DIGITIZER) { @@ -441,9 +442,7 @@ static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages, } if (usages->Usage != HID_USAGE_GENERIC_GAMEPAD && usages->Usage != HID_USAGE_GENERIC_JOYSTICK) return TRUE;
- if (!check_bus_option(L"Enable SDL", 1) && check_bus_option(L"DisableInput", 0)) - prefer_hidraw = TRUE; - + if (options.disable_sdl && options.disable_input) prefer_hidraw = TRUE; if (is_dualshock4_gamepad(vid, pid)) prefer_hidraw = TRUE; if (is_dualsense_gamepad(vid, pid)) prefer_hidraw = TRUE;
@@ -911,7 +910,7 @@ static NTSTATUS bus_main_thread_start(struct bus_main_params *bus) return status; }
-static void sdl_bus_free_mappings(struct sdl_bus_options *options) +static void sdl_bus_free_mappings(struct bus_options *options) { DWORD count = options->mappings_count; char **mappings = options->mappings; @@ -920,7 +919,7 @@ static void sdl_bus_free_mappings(struct sdl_bus_options *options) RtlFreeHeap(GetProcessHeap(), 0, mappings); }
-static void sdl_bus_load_mappings(struct sdl_bus_options *options) +static void sdl_bus_load_mappings(struct bus_options *options) { ULONG idx = 0, len, count = 0, capacity, info_size, info_max_size; UNICODE_STRING path = RTL_CONSTANT_STRING(L"map"); @@ -987,74 +986,74 @@ done: NtClose(key); }
+static void bus_options_init(void) +{ + options.disable_sdl = !check_bus_option(L"Enable SDL", 1); + if (options.disable_sdl) TRACE("SDL devices disabled in registry\n"); + options.disable_hidraw = check_bus_option(L"DisableHidraw", 0); + if (options.disable_hidraw) TRACE("UDEV hidraw devices disabled in registry\n"); + options.disable_input = check_bus_option(L"DisableInput", 0); + if (options.disable_input) TRACE("UDEV input devices disabled in registry\n"); + options.disable_udevd = check_bus_option(L"DisableUdevd", 0); + if (options.disable_udevd) TRACE("UDEV udevd use disabled in registry\n"); + + if (!options.disable_sdl) + { + options.split_controllers = check_bus_option(L"Split Controllers", 0); + if (options.split_controllers) TRACE("SDL controller splitting enabled\n"); + options.map_controllers = check_bus_option(L"Map Controllers", 1); + if (!options.map_controllers) TRACE("SDL controller to XInput HID gamepad mapping disabled\n"); + sdl_bus_load_mappings(&options); + } +} + +static void bus_options_cleanup(void) +{ + if (!options.disable_sdl) sdl_bus_free_mappings(&options); + memset(&options, 0, sizeof(options)); +} + static NTSTATUS sdl_driver_init(void) { - struct sdl_bus_options bus_options; struct bus_main_params bus = { .name = L"SDL", - .init_args = &bus_options, + .init_args = &options, .init_code = sdl_init, .wait_code = sdl_wait, }; - NTSTATUS status; - - bus_options.split_controllers = check_bus_option(L"Split Controllers", 0); - if (bus_options.split_controllers) TRACE("SDL controller splitting enabled\n"); - bus_options.map_controllers = check_bus_option(L"Map Controllers", 1); - if (!bus_options.map_controllers) TRACE("SDL controller to XInput HID gamepad mapping disabled\n"); - sdl_bus_load_mappings(&bus_options); - - status = bus_main_thread_start(&bus); - sdl_bus_free_mappings(&bus_options); - return status; + if (options.disable_sdl) return STATUS_SUCCESS; + return bus_main_thread_start(&bus); }
-static NTSTATUS udev_driver_init(BOOL enable_sdl) +static NTSTATUS udev_driver_init(void) { - struct udev_bus_options bus_options; struct bus_main_params bus = { .name = L"UDEV", - .init_args = &bus_options, + .init_args = &options, .init_code = udev_init, .wait_code = udev_wait, }; - - bus_options.disable_hidraw = check_bus_option(L"DisableHidraw", 0); - if (bus_options.disable_hidraw) TRACE("UDEV hidraw devices disabled in registry\n"); - bus_options.disable_input = check_bus_option(L"DisableInput", 0) || enable_sdl; - if (bus_options.disable_input) TRACE("UDEV input devices disabled in registry\n"); - bus_options.disable_udevd = check_bus_option(L"DisableUdevd", 0); - if (bus_options.disable_udevd) TRACE("UDEV udevd use disabled in registry\n"); - return bus_main_thread_start(&bus); }
static NTSTATUS iohid_driver_init(void) { - struct iohid_bus_options bus_options; struct bus_main_params bus = { .name = L"IOHID", - .init_args = &bus_options, + .init_args = &options, .init_code = iohid_init, .wait_code = iohid_wait, }; - - if (check_bus_option(L"DisableHidraw", FALSE)) - { - TRACE("IOHID hidraw devices disabled in registry\n"); - return STATUS_SUCCESS; - } - + if (options.disable_hidraw) return STATUS_SUCCESS; return bus_main_thread_start(&bus); }
static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); - BOOL enable_sdl; NTSTATUS ret;
switch (irpsp->MinorFunction) @@ -1063,12 +1062,13 @@ static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) irp->IoStatus.Status = handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp); break; case IRP_MN_START_DEVICE: + bus_options_init(); + mouse_device_create(); keyboard_device_create();
- if ((enable_sdl = check_bus_option(L"Enable SDL", 1))) - enable_sdl = !sdl_driver_init(); - udev_driver_init(enable_sdl); + if (!sdl_driver_init()) options.disable_input = TRUE; + udev_driver_init(); iohid_driver_init();
irp->IoStatus.Status = STATUS_SUCCESS; @@ -1089,6 +1089,8 @@ static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) ret = IoCallDriver(bus_pdo, irp); IoDetachDevice(bus_pdo); IoDeleteDevice(device); + + bus_options_cleanup(); return ret; default: FIXME("Unhandled minor function %#x.\n", irpsp->MinorFunction); diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h index 02e7a1c6953..8064cfe6ffa 100644 --- a/dlls/winebus.sys/unixlib.h +++ b/dlls/winebus.sys/unixlib.h @@ -47,26 +47,18 @@ struct device_desc WCHAR serialnumber[MAX_PATH]; };
-struct sdl_bus_options +struct bus_options { + BOOL disable_sdl; + BOOL disable_hidraw; + BOOL disable_input; + BOOL disable_udevd; BOOL split_controllers; BOOL map_controllers; - /* freed after bus_init */ UINT mappings_count; char **mappings; };
-struct udev_bus_options -{ - BOOL disable_hidraw; - BOOL disable_input; - BOOL disable_udevd; -}; - -struct iohid_bus_options -{ -}; - enum bus_event_type { BUS_EVENT_TYPE_NONE,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winebus.sys/main.c | 111 ++++++++++++++++++++++++++++++++++++- dlls/winebus.sys/unixlib.h | 9 +++ 2 files changed, 118 insertions(+), 2 deletions(-)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index fec0c20ed68..a9f634a8e42 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -19,6 +19,7 @@ */
#include <stdarg.h> +#include <stdlib.h> #include <assert.h>
#include "ntstatus.h" @@ -51,7 +52,7 @@ static DEVICE_OBJECT *keyboard_obj; static DEVICE_OBJECT *bus_pdo; static DEVICE_OBJECT *bus_fdo;
-static struct bus_options options; +static struct bus_options options = {.devices = LIST_INIT(options.devices)}; static HANDLE driver_key;
struct hid_report @@ -408,8 +409,8 @@ static DWORD check_bus_option(const WCHAR *option, DWORD default_value) UNICODE_STRING str; DWORD size;
+ /* @@ Wine registry key: HKLM\System\CurrentControlSet\Services\WineBus */ RtlInitUnicodeString(&str, option); - if (NtQueryValueKey(driver_key, &str, KeyValuePartialInformation, info, sizeof(buffer), &size) == STATUS_SUCCESS) { if (info->Type == REG_DWORD) return *(DWORD *)info->Data; @@ -422,6 +423,7 @@ static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages, { char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024])]; KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + struct device_options *device; WCHAR vidpid[MAX_PATH], *tmp; BOOL prefer_hidraw = FALSE; UNICODE_STRING str; @@ -429,6 +431,14 @@ static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages,
if (options.disable_hidraw) return FALSE;
+ LIST_FOR_EACH_ENTRY(device, &options.devices, struct device_options, entry) + { + if (device->vid != vid) continue; + if (device->pid != -1 && device->pid != pid) continue; + if (device->hidraw == -1) continue; + return !!device->hidraw; + } + if (usages->UsagePage == HID_USAGE_PAGE_DIGITIZER) { WARN("Ignoring unsupported %04X:%04X hidraw touchscreen\n", vid, pid); @@ -986,6 +996,91 @@ done: NtClose(key); }
+static struct device_options *add_device_options(UINT vid, UINT pid) +{ + struct device_options *device, *next; + + LIST_FOR_EACH_ENTRY(device, &options.devices, struct device_options, entry) + if (device->vid == vid && device->pid == pid) return device; + + if (!(device = calloc(1, sizeof(*device)))) return NULL; + device->vid = vid; + device->pid = pid; + device->hidraw = -1; + + LIST_FOR_EACH_ENTRY(next, &options.devices, struct device_options, entry) + if (next->vid > vid || (next->vid == vid && next->pid > pid)) break; + list_add_before(&next->entry, &device->entry); + + return device; +} + +static void load_device_options(void) +{ + char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024])]; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + UNICODE_STRING path = RTL_CONSTANT_STRING(L"Devices"); + ULONG idx = 0, size, name_max_size; + OBJECT_ATTRIBUTES attr = {0}; + KEY_NAME_INFORMATION *name; + WCHAR name_buffer[32]; + HANDLE key, subkey; + NTSTATUS status; + + /* @@ Wine registry key: HKLM\System\CurrentControlSet\Services\WineBus\Devices */ + InitializeObjectAttributes(&attr, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, driver_key, NULL); + status = NtOpenKey(&key, KEY_ALL_ACCESS, &attr); + if (status) return; + + name_max_size = offsetof(KEY_NAME_INFORMATION, Name) + 512; + name = RtlAllocateHeap(GetProcessHeap(), 0, name_max_size); + + while (!status && name) + { + static const UNICODE_STRING hidraw = RTL_CONSTANT_STRING(L"Hidraw"); + static const UNICODE_STRING backslash = RTL_CONSTANT_STRING(L"\"); + struct device_options *device; + UNICODE_STRING name_str; + UINT vid, pid; + USHORT pos; + int ret; + + status = NtEnumerateKey(key, idx, KeyNameInformation, name, name_max_size, &size); + while (status == STATUS_BUFFER_OVERFLOW) + { + name_max_size = size; + if (!(name = RtlReAllocateHeap(GetProcessHeap(), 0, name, name_max_size))) break; + status = NtEnumerateKey(key, idx, KeyNameInformation, name, name_max_size, &size); + } + if (status == STATUS_NO_MORE_ENTRIES) break; + idx++; + + /* @@ Wine registry key: HKLM\System\CurrentControlSet\Services\WineBus\Devices<VID[/PID]> */ + name_str.Buffer = name->Name; + name_str.Length = name->NameLength; + InitializeObjectAttributes(&attr, &name_str, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL); + if (NtOpenKey(&subkey, KEY_ALL_ACCESS, &attr)) continue; + + if (!RtlFindCharInUnicodeString(1, &name_str, &backslash, &pos)) pos += sizeof(WCHAR); + if (name->NameLength - pos >= sizeof(name_buffer)) continue; + + memcpy(name_buffer, name->Name + pos / sizeof(WCHAR), name->NameLength - pos); + name_buffer[(name->NameLength - pos) / sizeof(WCHAR)] = 0; + + if ((ret = swscanf(name_buffer, L"%04x/%04x", &vid, &pid)) < 1) continue; + if (!(device = add_device_options(vid, ret == 1 ? -1 : pid))) continue; + + if (!NtQueryValueKey(subkey, &hidraw, KeyValuePartialInformation, info, sizeof(buffer), &size) && info->Type == REG_DWORD) + device->hidraw = *(DWORD *)info->Data; + if (device->hidraw != -1) TRACE("- %04x/%04x: %sabling hidraw\n", device->vid, device->pid, device->hidraw ? "en" : "dis"); + + NtClose(subkey); + } + + RtlFreeHeap(GetProcessHeap(), 0, name); + NtClose(key); +} + static void bus_options_init(void) { options.disable_sdl = !check_bus_option(L"Enable SDL", 1); @@ -1005,12 +1100,24 @@ static void bus_options_init(void) if (!options.map_controllers) TRACE("SDL controller to XInput HID gamepad mapping disabled\n"); sdl_bus_load_mappings(&options); } + + load_device_options(); }
static void bus_options_cleanup(void) { + struct device_options *device, *next; + if (!options.disable_sdl) sdl_bus_free_mappings(&options); + + LIST_FOR_EACH_ENTRY_SAFE(device, next, &options.devices, struct device_options, entry) + { + list_remove(&device->entry); + free(device); + } + memset(&options, 0, sizeof(options)); + list_init(&options.devices); }
static NTSTATUS sdl_driver_init(void) diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h index 8064cfe6ffa..8dab8af0d57 100644 --- a/dlls/winebus.sys/unixlib.h +++ b/dlls/winebus.sys/unixlib.h @@ -47,6 +47,14 @@ struct device_desc WCHAR serialnumber[MAX_PATH]; };
+struct device_options +{ + struct list entry; + UINT vid; + UINT pid; + INT hidraw; +}; + struct bus_options { BOOL disable_sdl; @@ -56,6 +64,7 @@ struct bus_options BOOL split_controllers; BOOL map_controllers; UINT mappings_count; + struct list devices; char **mappings; };
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winebus.sys/bus_sdl.c | 24 ++++++++++++++++++++++-- dlls/winebus.sys/bus_udev.c | 23 +++++++++++++++-------- dlls/winebus.sys/hid.c | 31 +++++++++++++++++++++++++++++++ dlls/winebus.sys/main.c | 18 +++++++++++++++++- dlls/winebus.sys/unix_private.h | 3 +++ dlls/winebus.sys/unixlib.h | 4 ++++ 6 files changed, 92 insertions(+), 11 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 2c49f0f408b..7269399ff85 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -79,6 +79,7 @@ MAKE_FUNCPTR(SDL_JoystickInstanceID); MAKE_FUNCPTR(SDL_JoystickName); MAKE_FUNCPTR(SDL_JoystickNumAxes); MAKE_FUNCPTR(SDL_JoystickOpen); +MAKE_FUNCPTR(SDL_JoystickPath); MAKE_FUNCPTR(SDL_WaitEventTimeout); MAKE_FUNCPTR(SDL_JoystickNumButtons); MAKE_FUNCPTR(SDL_JoystickNumBalls); @@ -136,6 +137,7 @@ static const char *(*pSDL_JoystickGetSerial)(SDL_Joystick * joystick); struct sdl_device { struct unix_device unix_device; + struct device_options options;
SDL_Joystick *sdl_joystick; SDL_GameController *sdl_controller; @@ -531,6 +533,20 @@ static NTSTATUS sdl_device_haptics_stop(struct unix_device *iface) return STATUS_SUCCESS; }
+static void sdl_device_set_autocenter(struct sdl_device *impl, BOOL enabled) +{ + BYTE percent; + + TRACE("impl %p, enabled %u.\n", impl, enabled); + + if (impl->options.autocenter == AUTOCENTER_DISABLE) return; + + if (enabled) percent = HIWORD(impl->options.autocenter) * 100 / 0xffff; + else percent = LOWORD(impl->options.autocenter) * 100 / 0xffff; + + pSDL_HapticSetAutocenter(impl->sdl_haptic, percent); +} + static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, USAGE control) { struct sdl_device *impl = impl_from_unix_device(iface); @@ -550,7 +566,7 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US return STATUS_SUCCESS; case PID_USAGE_DC_STOP_ALL_EFFECTS: pSDL_HapticStopAll(impl->sdl_haptic); - pSDL_HapticSetAutocenter(impl->sdl_haptic, 0); + sdl_device_set_autocenter(impl, FALSE); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_RESET: pSDL_HapticStopAll(impl->sdl_haptic); @@ -560,7 +576,7 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US pSDL_HapticDestroyEffect(impl->sdl_haptic, impl->effect_ids[i]); impl->effect_ids[i] = -1; } - pSDL_HapticSetAutocenter(impl->sdl_haptic, 100); + sdl_device_set_autocenter(impl, TRUE); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_PAUSE: pSDL_HapticPause(impl->sdl_haptic); @@ -1016,6 +1032,9 @@ static void sdl_add_device(unsigned int index) impl->sdl_controller = controller; impl->id = id; impl->axis_offset = axis_offset; + impl->options.autocenter = MAKELONG(0, get_devnode_autocenter(pSDL_JoystickPath(joystick))); + if (impl->options.autocenter == AUTOCENTER_DISABLE) WARN("Cannot read default autocenter, disabling\n"); + get_device_options(options, desc.vid, desc.pid, &impl->options);
if (impl->sdl_controller) status = build_controller_report_descriptor(&impl->unix_device); else status = build_joystick_report_descriptor(&impl->unix_device); @@ -1112,6 +1131,7 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_JoystickName); LOAD_FUNCPTR(SDL_JoystickNumAxes); LOAD_FUNCPTR(SDL_JoystickOpen); + LOAD_FUNCPTR(SDL_JoystickPath); LOAD_FUNCPTR(SDL_WaitEventTimeout); LOAD_FUNCPTR(SDL_JoystickNumButtons); LOAD_FUNCPTR(SDL_JoystickNumBalls); diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 3f9a4fe43b9..cdfa8f04ea9 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -104,6 +104,8 @@ static const struct bus_options *options; struct base_device { struct unix_device unix_device; + struct device_options options; + void (*read_report)(struct unix_device *iface); BOOL started;
@@ -850,22 +852,21 @@ static NTSTATUS lnxev_device_physical_effect_run(struct lnxev_device *impl, BYTE return STATUS_SUCCESS; }
-static NTSTATUS lnxev_device_physical_device_set_autocenter(struct unix_device *iface, BYTE percent) +static void lnxev_device_set_autocenter(struct lnxev_device *impl, BOOL enabled) { - struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); struct input_event ie = { .type = EV_FF, .code = FF_AUTOCENTER, - .value = 0xffff * percent / 100, };
- TRACE("iface %p, percent %#x.\n", iface, percent); + if (impl->base.options.autocenter == AUTOCENTER_DISABLE) return; + + if (enabled) ie.value = HIWORD(impl->base.options.autocenter); + else ie.value = LOWORD(impl->base.options.autocenter);
if (write(impl->base.device_fd, &ie, sizeof(ie)) == -1) WARN("write failed %d %s\n", errno, strerror(errno)); - - return STATUS_SUCCESS; }
static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, USAGE control) @@ -911,7 +912,7 @@ static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, if (impl->effect_ids[i] < 0) continue; lnxev_device_physical_effect_run(impl, i, 0); } - lnxev_device_physical_device_set_autocenter(iface, 0); + lnxev_device_set_autocenter(impl, FALSE); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_RESET: for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) @@ -921,7 +922,7 @@ static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, WARN("couldn't free effect, EVIOCRMFF ioctl failed: %d %s\n", errno, strerror(errno)); impl->effect_ids[i] = -1; } - lnxev_device_physical_device_set_autocenter(iface, 100); + lnxev_device_set_autocenter(impl, TRUE); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_PAUSE: WARN("device pause not supported\n"); @@ -1309,6 +1310,9 @@ static void udev_add_device(struct udev_device *dev, int fd) impl->udev_device = udev_device_ref(dev); strcpy(impl->devnode, devnode); impl->device_fd = fd; + impl->options.autocenter = MAKELONG(0, get_devnode_autocenter(devnode)); + if (impl->options.autocenter == AUTOCENTER_DISABLE) WARN("Cannot read default autocenter, disabling\n"); + get_device_options(options, desc.vid, desc.pid, &impl->options);
bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc); } @@ -1321,6 +1325,9 @@ static void udev_add_device(struct udev_device *dev, int fd) impl->udev_device = udev_device_ref(dev); strcpy(impl->devnode, devnode); impl->device_fd = fd; + impl->options.autocenter = MAKELONG(0, get_devnode_autocenter(devnode)); + if (impl->options.autocenter == AUTOCENTER_DISABLE) WARN("Cannot read default autocenter, disabling\n"); + get_device_options(options, desc.vid, desc.pid, &impl->options);
if (build_report_descriptor(&impl->unix_device, impl->udev_device)) { diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index e2f667fd1ea..234fd63f969 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -25,6 +25,8 @@ #include <stdarg.h> #include <stdlib.h> #include <assert.h> +#include <fcntl.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -41,6 +43,35 @@
WINE_DEFAULT_DEBUG_CHANNEL(hid);
+void get_device_options(const struct bus_options *options, UINT vid, UINT pid, struct device_options *opts) +{ + struct device_options *device; + + LIST_FOR_EACH_ENTRY(device, &options->devices, struct device_options, entry) + { + if (device->vid != vid) continue; + if (device->pid != -1 && device->pid != pid) continue; + if (device->hidraw != -1) opts->hidraw = device->hidraw; + if (device->autocenter != -1) opts->autocenter = device->autocenter; + } +} + +USHORT get_devnode_autocenter(const char *devnode) +{ + char syslink[MAX_PATH], buffer[64] = {0}; + int fd; + + if (!devnode || strncmp(devnode, "/dev/input", 10)) return 0; + + snprintf(syslink, sizeof(syslink), "/sys/class/%s/autocenter", devnode + 5); + if ((fd = open(devnode, O_RDONLY)) < 0) return 0; + read(fd, &buffer, sizeof(buffer) - 1); + close(fd); + + TRACE("Read autocenter gain %s from %s\n", debugstr_a(buffer), debugstr_a(syslink)); + return atoi(buffer); +} + static BOOL hid_report_descriptor_append(struct hid_report_descriptor *desc, const BYTE *buffer, SIZE_T size) { BYTE *tmp = desc->data; diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index a9f634a8e42..7a11d3fc965 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -1007,6 +1007,7 @@ static struct device_options *add_device_options(UINT vid, UINT pid) device->vid = vid; device->pid = pid; device->hidraw = -1; + device->autocenter = -1;
LIST_FOR_EACH_ENTRY(next, &options.devices, struct device_options, entry) if (next->vid > vid || (next->vid == vid && next->pid > pid)) break; @@ -1037,13 +1038,14 @@ static void load_device_options(void)
while (!status && name) { + static const UNICODE_STRING autocenter = RTL_CONSTANT_STRING(L"Autocenter"); static const UNICODE_STRING hidraw = RTL_CONSTANT_STRING(L"Hidraw"); static const UNICODE_STRING backslash = RTL_CONSTANT_STRING(L"\"); struct device_options *device; UNICODE_STRING name_str; + int ret, on, off; UINT vid, pid; USHORT pos; - int ret;
status = NtEnumerateKey(key, idx, KeyNameInformation, name, name_max_size, &size); while (status == STATUS_BUFFER_OVERFLOW) @@ -1074,6 +1076,20 @@ static void load_device_options(void) device->hidraw = *(DWORD *)info->Data; if (device->hidraw != -1) TRACE("- %04x/%04x: %sabling hidraw\n", device->vid, device->pid, device->hidraw ? "en" : "dis");
+ if (!NtQueryValueKey(subkey, &autocenter, KeyValuePartialInformation, info, sizeof(buffer), &size) && info->Type == REG_SZ) + { + if (!wcsnicmp((WCHAR *)info->Data, L"enable", 4)) device->autocenter = AUTOCENTER_DEFAULT; + else if (!wcsnicmp((WCHAR *)info->Data, L"disable", 6)) device->autocenter = AUTOCENTER_DISABLE; + else if ((ret = swscanf((WCHAR *)info->Data, L"%d/%d", &on, &off))) + { + if (ret == 2) device->autocenter = MAKELONG(off,on); + else device->autocenter = MAKELONG(on,on); + } + } + + if (device->autocenter == AUTOCENTER_DISABLE) TRACE("- %04x/%04x: disabling autocenter\n", device->vid, device->pid); + else TRACE("- %04x/%04x: using autocenter %d-%d\n", device->vid, device->pid, LOWORD(device->autocenter), HIWORD(device->autocenter)); + NtClose(subkey); }
diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 5c39cae1409..492ec439146 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -242,6 +242,9 @@ extern BOOL bus_event_queue_input_report(struct list *queue, struct unix_device BYTE *report, USHORT length); extern BOOL bus_event_queue_pop(struct list *queue, struct bus_event *event);
+extern void get_device_options(const struct bus_options *options, UINT vid, UINT pid, struct device_options *opts); +extern USHORT get_devnode_autocenter(const char *devnode); + extern BOOL hid_device_begin_report_descriptor(struct unix_device *iface, const USAGE_AND_PAGE *device_usage); extern BOOL hid_device_end_report_descriptor(struct unix_device *iface);
diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h index 8dab8af0d57..e1cbd2985a3 100644 --- a/dlls/winebus.sys/unixlib.h +++ b/dlls/winebus.sys/unixlib.h @@ -47,12 +47,16 @@ struct device_desc WCHAR serialnumber[MAX_PATH]; };
+#define AUTOCENTER_DISABLE MAKELONG(0,0) +#define AUTOCENTER_DEFAULT MAKELONG(0,0xffff) + struct device_options { struct list entry; UINT vid; UINT pid; INT hidraw; + INT autocenter; };
struct bus_options