diff --git a/patches/dinput-reconnect-joystick/0001-dinput-Allow-reconnecting-to-disconnected-joysticks.patch b/patches/dinput-reconnect-joystick/0001-dinput-Allow-reconnecting-to-disconnected-joysticks.patch new file mode 100644 index 00000000..db5c7aed --- /dev/null +++ b/patches/dinput-reconnect-joystick/0001-dinput-Allow-reconnecting-to-disconnected-joysticks.patch @@ -0,0 +1,240 @@ +From 47a1e3618a1629a6f7cca1b84f761eaab3627f75 Mon Sep 17 00:00:00 2001 +From: Andrew Church +Date: Mon, 25 Feb 2019 11:23:12 +1100 +Subject: [PATCH] dinput: Allow reconnecting to disconnected joysticks + +Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=34297 +--- + dlls/dinput/joystick_linuxinput.c | 148 +++++++++++++++++++++++++++++--------- + 1 file changed, 113 insertions(+), 35 deletions(-) + +diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c +index ace4641..233dd25 100644 +--- a/dlls/dinput/joystick_linuxinput.c ++++ b/dlls/dinput/joystick_linuxinput.c +@@ -83,6 +83,13 @@ struct wine_input_absinfo { + LONG flat; + }; + ++enum wine_joystick_linuxinput_fd_state { ++ WINE_FD_STATE_CLOSED = 0, /* No device has been opened yet */ ++ WINE_FD_STATE_OK, /* File descriptor is open and ready for reading */ ++ WINE_FD_STATE_DISCONNECTED, /* Read error occurred; might be able to reopen later */ ++ WINE_FD_STATE_INVALID, /* Device is no longer available at original pathname */ ++}; ++ + /* implemented in effect_linuxinput.c */ + HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff); + HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info); +@@ -122,6 +129,7 @@ struct JoystickImpl + + /* joystick private */ + int joyfd; ++ enum wine_joystick_linuxinput_fd_state joyfd_state; + + int dev_axes_to_di[ABS_MAX]; + POINTL povs[4]; +@@ -466,6 +474,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.base.dinput = dinput; + newDevice->generic.joy_polldev = joy_polldev; + newDevice->joyfd = -1; ++ newDevice->joyfd_state = WINE_FD_STATE_CLOSED; + newDevice->joydev = &joydevs[index]; + newDevice->generic.name = newDevice->joydev->name; + list_init(&newDevice->ff_effects); +@@ -669,38 +678,15 @@ static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REF + return DIERR_DEVICENOTREG; + } + +- +-const struct dinput_device joystick_linuxinput_device = { +- "Wine Linux-input joystick driver", +- joydev_enum_deviceA, +- joydev_enum_deviceW, +- joydev_create_device +-}; +- +-/****************************************************************************** +- * Acquire : gets exclusive control of the joystick +- */ +-static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface) ++static int joydev_open_evdev(JoystickImpl *This) + { +- JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); +- HRESULT res; +- +- TRACE("(this=%p)\n",This); ++ int fd; + +- if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK) ++ if ((fd = open(This->joydev->device, O_RDWR)) == -1) + { +- WARN("Failed to acquire: %x\n", res); +- return res; +- } +- +- if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1) +- { +- if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1) ++ if ((fd = open(This->joydev->device, O_RDONLY)) == -1) + { + /* Couldn't open the device at all */ +- ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno)); +- IDirectInputDevice2WImpl_Unacquire(iface); +- return DIERR_NOTFOUND; + } + else + { +@@ -715,18 +701,53 @@ static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface) + event.type = EV_FF; + event.code = FF_GAIN; + event.value = This->ff_gain; +- if (write(This->joyfd, &event, sizeof(event)) == -1) ++ if (write(fd, &event, sizeof(event)) == -1) + ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno)); + if (!This->ff_autocenter) + { + /* Disable autocenter. */ + event.code = FF_AUTOCENTER; + event.value = 0; +- if (write(This->joyfd, &event, sizeof(event)) == -1) ++ if (write(fd, &event, sizeof(event)) == -1) + ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno)); + } + } + ++ return fd; ++} ++ ++ ++const struct dinput_device joystick_linuxinput_device = { ++ "Wine Linux-input joystick driver", ++ joydev_enum_deviceA, ++ joydev_enum_deviceW, ++ joydev_create_device ++}; ++ ++/****************************************************************************** ++ * Acquire : gets exclusive control of the joystick ++ */ ++static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); ++ HRESULT res; ++ ++ TRACE("(this=%p)\n",This); ++ ++ if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK) ++ { ++ WARN("Failed to acquire: %x\n", res); ++ return res; ++ } ++ ++ if ((This->joyfd = joydev_open_evdev(This)) == -1) ++ { ++ ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno)); ++ IDirectInputDevice2WImpl_Unacquire(iface); ++ return DIERR_NOTFOUND; ++ } ++ ++ This->joyfd_state = WINE_FD_STATE_OK; + return DI_OK; + } + +@@ -764,6 +785,7 @@ static HRESULT WINAPI JoystickWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface) + + close(This->joyfd); + This->joyfd = -1; ++ This->joyfd_state = WINE_FD_STATE_CLOSED; + } + return res; + } +@@ -808,23 +830,79 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface) + struct input_event ie; + JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); + +- if (This->joyfd==-1) +- return; ++ if (This->joyfd == -1) ++ { ++ int fd; ++ char namebuf[MAX_PATH + 8]; /* 8 == strlen(EVDEVDRIVER) */ ++ ++ if (This->joyfd_state != WINE_FD_STATE_DISCONNECTED) ++ return; ++ /* Try to reconnect to the device. */ ++ fd = joydev_open_evdev(This); ++ if (fd == -1) ++ return; ++ namebuf[sizeof(namebuf) - strlen(EVDEVDRIVER) - 1] = 0; ++ if (ioctl(fd, EVIOCGNAME(sizeof(namebuf) - strlen(EVDEVDRIVER) - 1), namebuf) == -1) ++ { ++ /* Couldn't get the name; assume it's a different device. */ ++ ERR("EVIOCGNAME(%s) failed: %d %s", This->joydev->device, errno, strerror(errno)); ++ This->joyfd_state = WINE_FD_STATE_INVALID; ++ return; ++ } ++ strcat(namebuf, EVDEVDRIVER); /* Guaranteed to be safe. */ ++ if (strcmp(namebuf, This->joydev->name) != 0) ++ { ++ ERR("Device %s changed from \"%s\" to \"%s\"! Can't reconnect.\n", This->joydev->device, This->joydev->name, namebuf); ++ This->joyfd_state = WINE_FD_STATE_INVALID; ++ return; ++ } ++ if (InterlockedCompareExchange(&This->joyfd, fd, -1) == -1) ++ { ++ This->joyfd_state = WINE_FD_STATE_OK; ++ TRACE("Reconnected to \"%s\" on %s", This->joydev->name, This->joydev->device); ++ } ++ else ++ { ++ /* Somebody beat us to it! Throw away our fd and use theirs. */ ++ close(fd); ++ } ++ } + + while (1) + { + LONG value = 0; + int inst_id = -1; ++ int result; + + plfd.fd = This->joyfd; + plfd.events = POLLIN; + +- if (poll(&plfd,1,0) != 1) +- return; ++ result = poll(&plfd,1,0); ++ if (result != 1) ++ { ++ if (result == -1) ++ { ++ ERR("poll failed: %d %s\n", errno, strerror(errno)); ++ close(This->joyfd); ++ This->joyfd = -1; ++ This->joyfd_state = WINE_FD_STATE_DISCONNECTED; ++ } ++ return; ++ } + + /* we have one event, so we can read */ +- if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie))) +- return; ++ result = read(This->joyfd,&ie,sizeof(ie)); ++ if (result != sizeof(ie)) ++ { ++ if (result == -1) ++ { ++ ERR("read failed: %d %s\n", errno, strerror(errno)); ++ close(This->joyfd); ++ This->joyfd = -1; ++ This->joyfd_state = WINE_FD_STATE_DISCONNECTED; ++ } ++ return; ++ } + + TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value); + switch (ie.type) { +-- +1.9.1 + diff --git a/patches/dinput-reconnect-joystick/definition b/patches/dinput-reconnect-joystick/definition new file mode 100644 index 00000000..4aa535ba --- /dev/null +++ b/patches/dinput-reconnect-joystick/definition @@ -0,0 +1,2 @@ +Fixes: [34297] dinput: Allow reconnecting to disconnected joysticks + diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index b73725db..e150a6b9 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -133,6 +133,7 @@ patch_enable_all () enable_ddraw_version_check="$1" enable_dinput_Deadlock="$1" enable_dinput_Initialize="$1" + enable_dinput_reconnect_joystick="$1" enable_dinput_remap_joystick="$1" enable_dsound_EAX="$1" enable_dsound_Fast_Mixer="$1" @@ -548,6 +549,9 @@ patch_enable () dinput-Initialize) enable_dinput_Initialize="$2" ;; + dinput-reconnect-joystick) + enable_dinput_reconnect_joystick="$2" + ;; dinput-remap-joystick) enable_dinput_remap_joystick="$2" ;; @@ -3235,6 +3239,21 @@ if test "$enable_dinput_Initialize" -eq 1; then ) >> "$patchlist" fi +# Patchset dinput-reconnect-joystick +# | +# | This patchset fixes the following Wine bugs: +# | * [#34297] dinput: Allow reconnecting to disconnected joysticks +# | +# | Modified files: +# | * dlls/dinput/joystick_linuxinput.c +# | +if test "$enable_dinput_reconnect_joystick" -eq 1; then + patch_apply dinput-reconnect-joystick/0001-dinput-Allow-reconnecting-to-disconnected-joysticks.patch + ( + printf '%s\n' '+ { "Andrew Church", "dinput: Allow reconnecting to disconnected joysticks.", 1 },'; + ) >> "$patchlist" +fi + # Patchset dinput-remap-joystick # | # | This patchset fixes the following Wine bugs: