mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
241 lines
8.1 KiB
Diff
241 lines
8.1 KiB
Diff
From e72af998f5382092726cfdb4d57c3b5f8b7d5401 Mon Sep 17 00:00:00 2001
|
|
From: Andrew Church <achurch@achurch.org>
|
|
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 b5418d805cc..2434af600ac 100644
|
|
--- a/dlls/dinput/joystick_linuxinput.c
|
|
+++ b/dlls/dinput/joystick_linuxinput.c
|
|
@@ -84,6 +84,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);
|
|
@@ -123,6 +130,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];
|
|
@@ -473,6 +481,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);
|
|
@@ -680,38 +689,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
|
|
{
|
|
@@ -726,18 +712,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;
|
|
}
|
|
|
|
@@ -775,6 +796,7 @@ static HRESULT WINAPI JoystickWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
|
|
|
|
close(This->joyfd);
|
|
This->joyfd = -1;
|
|
+ This->joyfd_state = WINE_FD_STATE_CLOSED;
|
|
}
|
|
return res;
|
|
}
|
|
@@ -819,23 +841,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) {
|
|
--
|
|
2.17.1
|
|
|