xorg-x11-drv-evdev/evdev-2.0.4-reopen-device.patch
Adam Jackson a7b51f43ac - evdev-2.0.4-reopen-device.patch: When arming the reopen timer, stash it
in the driver private, and explicitly cancel it if the server decides
    to close the device for real.
- evdev-2.0.4-cache-info.patch: Rebase to account for same.
2008-09-12 20:08:52 +00:00

243 lines
7.7 KiB
Diff

diff -up xf86-input-evdev-2.0.4/man/evdev.man.reopen-device xf86-input-evdev-2.0.4/man/evdev.man
--- xf86-input-evdev-2.0.4/man/evdev.man.reopen-device 2008-08-14 22:27:13.000000000 -0400
+++ xf86-input-evdev-2.0.4/man/evdev.man 2008-09-12 15:45:50.000000000 -0400
@@ -67,6 +67,11 @@ button event is registered.
Sets the timeout (in milliseconds) that the driver waits before deciding
if two buttons where pressed "simultaneously" when 3 button emulation is
enabled. Default: 50.
+.TP 7
+.BI "Option \*qReopenAttempts\*q \*q" integer \*q
+Number of reopen attempts after a read error occurs on the device (e.g. after
+waking up from suspend). In between each attempt is a 100ms wait. Default: 10.
+
.SH AUTHORS
Kristian Høgsberg.
.SH "SEE ALSO"
diff -up xf86-input-evdev-2.0.4/src/evdev.c.reopen-device xf86-input-evdev-2.0.4/src/evdev.c
--- xf86-input-evdev-2.0.4/src/evdev.c.reopen-device 2008-08-14 22:27:13.000000000 -0400
+++ xf86-input-evdev-2.0.4/src/evdev.c 2008-09-12 15:55:42.000000000 -0400
@@ -73,6 +73,7 @@
#define EVDEV_RELATIVE_EVENTS (1 << 2)
#define EVDEV_ABSOLUTE_EVENTS (1 << 3)
#define EVDEV_TOUCHPAD (1 << 4)
+#define EVDEV_INITIALIZED (1 << 5) /* WheelInit etc. called already? */
#define MIN_KEYCODE 8
#define GLYPHS_PER_KEY 2
@@ -96,6 +97,8 @@ static const char *evdevDefaults[] = {
NULL
};
+static int EvdevOn(DeviceIntPtr);
+
static void
SetXkbOption(InputInfoPtr pInfo, char *name, char **option)
{
@@ -154,6 +157,48 @@ PostKbdEvent(InputInfoPtr pInfo, struct
xf86PostKeyboardEvent(pInfo->dev, code, value);
}
+
+/**
+ * Coming back from resume may leave us with a file descriptor that can be
+ * opened but fails on the first read (ENODEV).
+ * In this case, try to open the device until it becomes available or until
+ * the predefined count expires.
+ */
+static CARD32
+EvdevReopenTimer(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+ InputInfoPtr pInfo = (InputInfoPtr)arg;
+ EvdevPtr pEvdev = pInfo->private;
+
+ do {
+ pInfo->fd = open(pEvdev->device, O_RDWR, 0);
+ } while (pInfo->fd < 0 && errno == EINTR);
+
+ if (pInfo->fd != -1)
+ {
+ xf86Msg(X_INFO, "%s: Device reopened after %d attempts.\n", pInfo->name,
+ pEvdev->reopen_attempts - pEvdev->reopen_left);
+
+ pEvdev->reopen_left = 0;
+ pEvdev->reopen_timer = NULL;
+ EvdevOn(pInfo->dev);
+ return 0;
+ }
+
+ pEvdev->reopen_left--;
+
+ if (!pEvdev->reopen_left)
+ {
+ xf86Msg(X_ERROR, "%s: Failed to reopen device after %d attempts.\n",
+ pInfo->name, pEvdev->reopen_attempts);
+ DisableDevice(pInfo->dev);
+ pEvdev->reopen_timer = NULL;
+ return 0;
+ }
+
+ return 100; /* come back in 100 ms */
+}
+
static void
EvdevReadInput(InputInfoPtr pInfo)
{
@@ -173,6 +218,15 @@ EvdevReadInput(InputInfoPtr pInfo)
/* The kernel promises that we always only read a complete
* event, so len != sizeof ev is an error. */
xf86Msg(X_ERROR, "%s: Read error: %s\n", pInfo->name, strerror(errno));
+
+ if (errno == ENODEV) /* May happen after resume */
+ {
+ xf86RemoveEnabledDevice(pInfo);
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ pEvdev->reopen_left = pEvdev->reopen_attempts;
+ pEvdev->reopen_timer = TimerSet(NULL, 0, 100, EvdevReopenTimer, pInfo);
+ }
break;
}
@@ -836,6 +890,47 @@ EvdevInit(DeviceIntPtr device)
return Success;
}
+/**
+ * Init all extras (wheel emulation, etc.) and grab the device.
+ *
+ * Coming from a resume, the grab may fail with ENODEV. In this case, we set a
+ * timer to wake up and try to reopen the device later.
+ */
+static int
+EvdevOn(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ if (!pEvdev->kernel24 && ioctl(pInfo->fd, EVIOCGRAB, (void *)1))
+ xf86Msg(X_WARNING, "%s: Grab failed (%s)\n", pInfo->name,
+ strerror(errno));
+
+ if (errno == ENODEV) /* may happen after resume */
+ {
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ pEvdev->reopen_left = pEvdev->reopen_attempts;
+ pEvdev->reopen_timer = TimerSet(NULL, 0, 100, EvdevReopenTimer, pInfo);
+ } else
+ {
+ xf86AddEnabledDevice(pInfo);
+ if ((pEvdev->flags & EVDEV_BUTTON_EVENTS) &&
+ !(pEvdev->flags & EVDEV_INITIALIZED))
+ {
+ EvdevMBEmuPreInit(pInfo);
+ }
+ pEvdev->flags |= EVDEV_INITIALIZED;
+ device->public.on = TRUE;
+ }
+
+ return Success;
+}
+
+
static int
EvdevProc(DeviceIntPtr device, int what)
{
@@ -851,30 +946,30 @@ EvdevProc(DeviceIntPtr device, int what)
return EvdevInit(device);
case DEVICE_ON:
- if (!pEvdev->kernel24 && ioctl(pInfo->fd, EVIOCGRAB, (void *)1))
- xf86Msg(X_WARNING, "%s: Grab failed (%s)\n", pInfo->name,
- strerror(errno));
- if (errno != ENODEV)
- {
- xf86AddEnabledDevice(pInfo);
- if (pEvdev->flags & EVDEV_BUTTON_EVENTS)
- EvdevMBEmuPreInit(pInfo);
- device->public.on = TRUE;
- }
- break;
+ return EvdevOn(device);
case DEVICE_OFF:
- if (!pEvdev->kernel24 && ioctl(pInfo->fd, EVIOCGRAB, (void *)0))
- xf86Msg(X_WARNING, "%s: Release failed (%s)\n", pInfo->name,
- strerror(errno));
- xf86RemoveEnabledDevice(pInfo);
- EvdevMBEmuFinalize(pInfo);
+ if (pInfo->fd != -1)
+ {
+ if (!pEvdev->kernel24 && ioctl(pInfo->fd, EVIOCGRAB, (void *)0))
+ xf86Msg(X_WARNING, "%s: Release failed (%s)\n", pInfo->name,
+ strerror(errno));
+ xf86RemoveEnabledDevice(pInfo);
+ }
+ if (pEvdev->flags & EVDEV_INITIALIZED)
+ EvdevMBEmuFinalize(pInfo);
+ pEvdev->flags &= ~EVDEV_INITIALIZED;
device->public.on = FALSE;
break;
case DEVICE_CLOSE:
xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
- close(pInfo->fd);
+ if (pEvdev->reopen_timer) {
+ TimerCancel(pEvdev->reopen_timer);
+ pEvdev->reopen_timer = NULL;
+ }
+ if (pInfo->fd != -1)
+ close(pInfo->fd);
break;
}
@@ -1060,11 +1155,12 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr
return NULL;
}
+ pEvdev->device = device;
+
xf86Msg(deviceFrom, "%s: Device: \"%s\"\n", pInfo->name, device);
do {
pInfo->fd = open(device, O_RDWR, 0);
- }
- while (pInfo->fd < 0 && errno == EINTR);
+ } while (pInfo->fd < 0 && errno == EINTR);
if (pInfo->fd < 0) {
xf86Msg(X_ERROR, "Unable to open evdev device \"%s\".\n", device);
@@ -1072,6 +1168,8 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr
return NULL;
}
+ pEvdev->reopen_attempts = xf86SetIntOption(pInfo->options, "ReopenAttempts", 10);
+
pEvdev->noXkb = noXkbExtension;
/* parse the XKB options during kbd setup */
diff -up xf86-input-evdev-2.0.4/src/evdev.h.reopen-device xf86-input-evdev-2.0.4/src/evdev.h
--- xf86-input-evdev-2.0.4/src/evdev.h.reopen-device 2008-08-14 22:27:13.000000000 -0400
+++ xf86-input-evdev-2.0.4/src/evdev.h 2008-09-12 15:55:44.000000000 -0400
@@ -41,6 +41,7 @@
#endif
typedef struct {
+ const char *device;
int kernel24;
int screen;
int min_x, min_y, max_x, max_y;
@@ -67,6 +68,10 @@ typedef struct {
Time expires; /* time of expiry */
Time timeout;
} emulateMB;
+
+ int reopen_attempts; /* max attempts to re-open after read failure */
+ int reopen_left; /* number of attempts left to re-open the device */
+ OsTimerPtr reopen_timer;
} EvdevRec, *EvdevPtr;
/* Middle Button emulation */