diff -up xf86-input-evdev-2.0.4/src/evdev.c.jx xf86-input-evdev-2.0.4/src/evdev.c --- xf86-input-evdev-2.0.4/src/evdev.c.jx 2008-09-12 16:04:34.000000000 -0400 +++ xf86-input-evdev-2.0.4/src/evdev.c 2008-09-12 16:04:56.000000000 -0400 @@ -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,12 +177,19 @@ EvdevReopenTimer(OsTimerPtr timer, CARD3 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); + 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; } @@ -370,8 +378,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 @@ -1000,6 +1006,116 @@ EvdevConvert(InputInfoPtr pInfo, int fir 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) { @@ -1179,6 +1295,8 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr return NULL; } + EvdevCacheCompare(pInfo, FALSE); /* cache device data */ + return pInfo; } diff -up xf86-input-evdev-2.0.4/src/evdev.h.jx xf86-input-evdev-2.0.4/src/evdev.h --- xf86-input-evdev-2.0.4/src/evdev.h.jx 2008-09-12 16:04:34.000000000 -0400 +++ xf86-input-evdev-2.0.4/src/evdev.h 2008-09-12 16:04:56.000000000 -0400 @@ -40,6 +40,9 @@ #include #endif +#define LONG_BITS (sizeof(long) * 8) +#define NBITS(x) (((x) + LONG_BITS - 1) / LONG_BITS) + typedef struct { const char *device; int kernel24; @@ -72,6 +75,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 */ OsTimerPtr reopen_timer; + + /* 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 */