rpms/xorg-x11-drv-evdev/devel evdev-2.0.4-cache-info.patch, NONE, 1.1 evdev-2.0.4-reopen-device.patch, NONE, 1.1 xorg-x11-drv-evdev.spec, 1.29, 1.30

Peter Hutterer whot at fedoraproject.org
Thu Aug 28 02:27:09 UTC 2008


Author: whot

Update of /cvs/pkgs/rpms/xorg-x11-drv-evdev/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv975

Modified Files:
	xorg-x11-drv-evdev.spec 
Added Files:
	evdev-2.0.4-cache-info.patch evdev-2.0.4-reopen-device.patch 
Log Message:
* Thu Aug 28 2008 Peter Hutterer <peter.hutterer at redhat.com> 2.0.4-2
- evdev-2.0.4-reopen-device.patch: try to reopen devices if a read error
  occurs on the fd.
- evdev-2.0.4-cache-info.patch: cache device info to ensure reopened device
  isn't different to previous one.



evdev-2.0.4-cache-info.patch:

--- NEW FILE evdev-2.0.4-cache-info.patch ---
>From 441a97c22933db462dd53e000d1cb269dab6e825 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer at redhat.com>
Date: Thu, 28 Aug 2008 10:29:26 +0930
Subject: [PATCH] Cache device information and compare against info after re-open.

This way we ensure that if the topology changes under us, we don't open a
completely different device. If a device has changed, we disable it.
(cherry picked from commit 3bb7d100570134058eb4c906d4902c655148a8be)

Conflicts:

	src/evdev.c
	src/evdev.h
---
 src/evdev.c |  131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/evdev.h |   12 +++++
 2 files changed, 137 insertions(+), 6 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 16cf67f..ca6da6e 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -98,6 +98,7 @@ static const char *evdevDefaults[] = {
 };
 
 static int EvdevOn(DeviceIntPtr);
+static int EvdevCacheCompare(InputInfoPtr pInfo, Bool compare);
 
 static void
 SetXkbOption(InputInfoPtr pInfo, char *name, char **option)
@@ -176,11 +177,19 @@ EvdevReopenTimer(OsTimerPtr timer, CARD32 time, pointer arg)
 
     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;
-        EvdevOn(pInfo->dev);
+
+        if (EvdevCacheCompare(pInfo, TRUE) == Success)
+        {
+            xf86Msg(X_INFO, "%s: Device reopened after %d attempts.\n", pInfo->name,
+                    pEvdev->reopen_attempts - pEvdev->reopen_left);
+            EvdevOn(pInfo->dev);
+        } else
+        {
+            xf86Msg(X_ERROR, "%s: Device has changed - disabling.\n",
+                    pInfo->name);
+            DisableDevice(pInfo->dev);
+        }
         return 0;
     }
 
@@ -368,8 +377,6 @@ EvdevReadInput(InputInfoPtr pInfo)
     }
 }
 
-#define LONG_BITS (sizeof(long) * 8)
-#define NBITS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
 #define TestBit(bit, array) (array[(bit) / LONG_BITS]) & (1 << ((bit) % LONG_BITS))
 
 static void
@@ -994,6 +1001,116 @@ EvdevConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
     return TRUE;
 }
 
+/**
+ * Get as much information as we can from the fd and cache it.
+ * If compare is True, then the information retrieved will be compared to the
+ * one already cached. If the information does not match, then this function
+ * returns an error.
+ *
+ * @return Success if the information was cached, or !Success otherwise.
+ */
+static int
+EvdevCacheCompare(InputInfoPtr pInfo, Bool compare)
+{
+    int i;
+    EvdevPtr pEvdev = pInfo->private;
+    char name[1024]                  = {0};
+    long bitmask[NBITS(EV_MAX)]      = {0};
+    long key_bitmask[NBITS(KEY_MAX)] = {0};
+    long rel_bitmask[NBITS(REL_MAX)] = {0};
+    long abs_bitmask[NBITS(ABS_MAX)] = {0};
+    long led_bitmask[NBITS(LED_MAX)] = {0};
+    struct input_absinfo absinfo[ABS_MAX];
+
+    if (ioctl(pInfo->fd,
+              EVIOCGNAME(sizeof(name) - 1), name) < 0) {
+        xf86Msg(X_ERROR, "ioctl EVIOCGNAME failed: %s\n", strerror(errno));
+        goto error;
+    }
+
+    if (compare && strcmp(pEvdev->name, name))
+        goto error;
+
+    if (ioctl(pInfo->fd,
+              EVIOCGBIT(0, sizeof(bitmask)), bitmask) < 0) {
+        xf86Msg(X_ERROR, "ioctl EVIOCGNAME failed: %s\n", strerror(errno));
+        goto error;
+    }
+
+    if (compare && memcmp(pEvdev->bitmask, bitmask, sizeof(bitmask)))
+        goto error;
+
+
+    if (ioctl(pInfo->fd,
+              EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) < 0) {
+        xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
+        goto error;
+    }
+
+    if (compare && memcmp(pEvdev->rel_bitmask, rel_bitmask, sizeof(rel_bitmask)))
+        goto error;
+
+    if (ioctl(pInfo->fd,
+              EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) < 0) {
+        xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
+        goto error;
+    }
+
+    if (compare && memcmp(pEvdev->abs_bitmask, abs_bitmask, sizeof(abs_bitmask)))
+        goto error;
+
+    if (ioctl(pInfo->fd,
+              EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) < 0) {
+        xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
+        goto error;
+    }
+
+    if (compare && memcmp(pEvdev->key_bitmask, key_bitmask, sizeof(key_bitmask)))
+        goto error;
+
+    if (ioctl(pInfo->fd,
+              EVIOCGBIT(EV_LED, sizeof(led_bitmask)), led_bitmask) < 0) {
+        xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
+        goto error;
+    }
+
+    if (compare && memcmp(pEvdev->led_bitmask, led_bitmask, sizeof(led_bitmask)))
+        goto error;
+
+    memset(absinfo, 0, sizeof(absinfo));
+
+    for (i = 0; i < ABS_MAX; i++)
+    {
+        if (TestBit(i, abs_bitmask))
+        {
+            if (ioctl(pInfo->fd, EVIOCGABS(i), &absinfo[i]) < 0) {
+                xf86Msg(X_ERROR, "ioctl EVIOCGABS failed: %s\n", strerror(errno));
+                goto error;
+            }
+        }
+    }
+
+    if (compare && memcmp(pEvdev->absinfo, absinfo, sizeof(absinfo)))
+            goto error;
+
+    /* cache info */
+    if (!compare)
+    {
+        strcpy(pEvdev->name, name);
+        memcpy(pEvdev->bitmask, bitmask, sizeof(bitmask));
+        memcpy(pEvdev->key_bitmask, key_bitmask, sizeof(key_bitmask));
+        memcpy(pEvdev->rel_bitmask, rel_bitmask, sizeof(rel_bitmask));
+        memcpy(pEvdev->abs_bitmask, abs_bitmask, sizeof(abs_bitmask));
+        memcpy(pEvdev->led_bitmask, led_bitmask, sizeof(led_bitmask));
+        memcpy(pEvdev->absinfo, absinfo, sizeof(absinfo));
+    }
+
+    return Success;
+
+error:
+    return !Success;
+}
+
 static int
 EvdevProbe(InputInfoPtr pInfo)
 {
@@ -1173,6 +1290,8 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
         return NULL;
     }
 
+    EvdevCacheCompare(pInfo, FALSE); /* cache device data */
+
     return pInfo;
 }
 
diff --git a/src/evdev.h b/src/evdev.h
index 0f8cf4b..47bbff2 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -40,6 +40,9 @@
 #include <X11/extensions/XKBstr.h>
 #endif
 
+#define LONG_BITS (sizeof(long) * 8)
+#define NBITS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
+
 typedef struct {
     const char *device;
     int kernel24;
@@ -71,6 +74,15 @@ typedef struct {
 
     int reopen_attempts; /* max attempts to re-open after read failure */
     int reopen_left;     /* number of attempts left to re-open the device */
+
+    /* Cached info from device. */
+    char name[1024];
+    long bitmask[NBITS(EV_MAX)];
+    long key_bitmask[NBITS(KEY_MAX)];
+    long rel_bitmask[NBITS(REL_MAX)];
+    long abs_bitmask[NBITS(ABS_MAX)];
+    long led_bitmask[NBITS(LED_MAX)];
+    struct input_absinfo absinfo[ABS_MAX];
 } EvdevRec, *EvdevPtr;
 
 /* Middle Button emulation */
-- 
1.5.6.4


evdev-2.0.4-reopen-device.patch:

--- NEW FILE evdev-2.0.4-reopen-device.patch ---
>From 188f07089d9c91d503391d05f0c3776360d7446b Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer at redhat.com>
Date: Thu, 28 Aug 2008 10:24:33 +0930
Subject: [PATCH] Attempt to re-open devices on read errors.

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.

Adds option "ReopenAttempts" <int>
(cherry picked from commit b41d39a745cce9e91241453935ea4c702772c5da)

Conflicts:

	man/evdev.man
	src/evdev.c
	src/evdev.h
---
 man/evdev.man |    5 ++
 src/evdev.c   |  130 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 src/evdev.h   |    4 ++
 3 files changed, 120 insertions(+), 19 deletions(-)

diff --git a/man/evdev.man b/man/evdev.man
index f438f78..530f979 100644
--- a/man/evdev.man
+++ b/man/evdev.man
@@ -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 --git a/src/evdev.c b/src/evdev.c
index a857db3..16cf67f 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -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,46 @@ PostKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
     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;
+        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);
+        return 0;
+    }
+
+    return 100; /* come back in 100 ms */
+}
+
 static void
 EvdevReadInput(InputInfoPtr pInfo)
 {
@@ -173,6 +216,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;
+                TimerSet(NULL, 0, 100, EvdevReopenTimer, pInfo);
+            }
             break;
         }
 
@@ -836,6 +888,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;
+        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 +944,26 @@ 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 (pInfo->fd != -1)
+            close(pInfo->fd);
 	break;
     }
 
@@ -1060,11 +1149,12 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
         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 +1162,8 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
         return NULL;
     }
 
+    pEvdev->reopen_attempts = xf86SetIntOption(pInfo->options, "ReopenAttempts", 10);
+
     pEvdev->noXkb = noXkbExtension;
     /* parse the XKB options during kbd setup */
 
diff --git a/src/evdev.h b/src/evdev.h
index cad1eed..0f8cf4b 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -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,9 @@ 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 */
 } EvdevRec, *EvdevPtr;
 
 /* Middle Button emulation */
-- 
1.5.6.4



Index: xorg-x11-drv-evdev.spec
===================================================================
RCS file: /cvs/pkgs/rpms/xorg-x11-drv-evdev/devel/xorg-x11-drv-evdev.spec,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- xorg-x11-drv-evdev.spec	25 Aug 2008 05:00:19 -0000	1.29
+++ xorg-x11-drv-evdev.spec	28 Aug 2008 02:26:38 -0000	1.30
@@ -7,7 +7,7 @@
 Summary:    Xorg X11 evdev input driver
 Name:	    xorg-x11-drv-evdev
 Version:    2.0.4
-Release:    1%{?dist}
+Release:    2%{?dist}
 URL:	    http://www.x.org
 License:    MIT
 Group:	    User Interface/X Hardware Support
@@ -17,6 +17,9 @@
 #Source0:    %{tarball}-%{gitdate}.tar.bz2
 Source1:    make-git-snapshot.sh
 
+Patch001:  evdev-2.0.4-reopen-device.patch
+Patch002:  evdev-2.0.4-cache-info.patch
+
 ExcludeArch: s390 s390x
 
 BuildRequires: autoconf automake libtool
@@ -31,6 +34,9 @@
 #%setup -q -n %{tarball}-%{gitdate}
 %setup -q -n %{tarball}-%{version}
 
+# apply patches
+%patch1 -p1 -b .reopen-device.patch
+%patch2 -p1 -b .cache-info.patch
 
 %build
 autoreconf -v --install || exit 1
@@ -55,6 +61,12 @@
 %{_mandir}/man4/evdev.4*
 
 %changelog
+* Thu Aug 28 2008 Peter Hutterer <peter.hutterer at redhat.com> 2.0.4-2
+- evdev-2.0.4-reopen-device.patch: try to reopen devices if a read error
+  occurs on the fd.
+- evdev-2.0.4-cache-info.patch: cache device info to ensure reopened device
+  isn't different to previous one.
+
 * Mon Aug 25 2008 Peter Hutterer <peter.hutterer at redhat.com> 2.0.4-1
 - evdev 2.0.4
 




More information about the fedora-extras-commits mailing list