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