aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-11-02 23:11:55 -0800
committerPeter Hutterer <peter.hutterer@who-t.net>2009-11-20 11:17:42 +1000
commit175af93bdb5928236e5c402a77d164313497d72a (patch)
tree5f28c70d4d30cd8d1abfaa62d738cf11ba2d9d97
parentFix drag-lock property handler for multiple draglock buttons. (diff)
downloadxf86-input-evdev-175af93bdb5928236e5c402a77d164313497d72a.tar.gz
xf86-input-evdev-175af93bdb5928236e5c402a77d164313497d72a.tar.bz2
xf86-input-evdev-175af93bdb5928236e5c402a77d164313497d72a.zip
Relax checks when reopening devices
When checking whether we are dealing with the same device as before when we try to reopen it evdev should not require exact match of entire keymap. Users should be allowed to adjust keymaps to better match their hardware even after X starts. However we don't expect changes in [BTN_MISC, KEY_OK) range since these codes are reserved for mice, joysticks, tablets and so forth, so we will limit the check to this range. The same goes for absinfo - limits can change and it should not result in device being disabled. Also check the length of the data returned by ioctl and don't try to compare more than we were given. [peter: moved the key comparison below the led+abs comparison] Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> (cherry picked from commit a0f7f34dc5effc5822c618bfbf3a0872669c30ad)
-rw-r--r--src/evdev.c126
1 files changed, 71 insertions, 55 deletions
diff --git a/src/evdev.c b/src/evdev.c
index 0dff271..894aca4 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1671,6 +1671,7 @@ static int
EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare)
{
EvdevPtr pEvdev = pInfo->private;
+ size_t len;
int i;
char name[1024] = {0};
@@ -1679,107 +1680,122 @@ EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare)
unsigned long rel_bitmask[NLONGS(REL_CNT)] = {0};
unsigned long abs_bitmask[NLONGS(ABS_CNT)] = {0};
unsigned long led_bitmask[NLONGS(LED_CNT)] = {0};
- struct input_absinfo absinfo[ABS_CNT];
- if (ioctl(pInfo->fd,
- EVIOCGNAME(sizeof(name) - 1), name) < 0) {
+ 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)) {
- xf86Msg(X_ERROR, "%s: device name changed: %s != %s\n", pInfo->name, pEvdev->name, name);
+ if (!compare) {
+ strcpy(pEvdev->name, name);
+ } else if (strcmp(pEvdev->name, name)) {
+ xf86Msg(X_ERROR, "%s: device name changed: %s != %s\n",
+ pInfo->name, pEvdev->name, name);
goto error;
}
- if (ioctl(pInfo->fd,
- EVIOCGBIT(0, sizeof(bitmask)), bitmask) < 0) {
- xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n", pInfo->name, strerror(errno));
+ len = ioctl(pInfo->fd, EVIOCGBIT(0, sizeof(bitmask)), bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
goto error;
}
- if (compare && memcmp(pEvdev->bitmask, bitmask, sizeof(bitmask))) {
+ if (!compare) {
+ memcpy(pEvdev->bitmask, bitmask, len);
+ } else if (memcmp(pEvdev->bitmask, bitmask, len)) {
xf86Msg(X_ERROR, "%s: device bitmask has changed\n", pInfo->name);
goto error;
}
-
- if (ioctl(pInfo->fd,
- EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) < 0) {
- xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n", pInfo->name, strerror(errno));
+ len = ioctl(pInfo->fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
goto error;
}
- if (compare && memcmp(pEvdev->rel_bitmask, rel_bitmask, sizeof(rel_bitmask))) {
+ if (!compare) {
+ memcpy(pEvdev->rel_bitmask, rel_bitmask, len);
+ } else if (memcmp(pEvdev->rel_bitmask, rel_bitmask, len)) {
xf86Msg(X_ERROR, "%s: device rel_bitmask has changed\n", pInfo->name);
goto error;
}
- if (ioctl(pInfo->fd,
- EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) < 0) {
- xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n", pInfo->name, strerror(errno));
+ len = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
goto error;
}
- if (compare && memcmp(pEvdev->abs_bitmask, abs_bitmask, sizeof(abs_bitmask))) {
+ if (!compare) {
+ memcpy(pEvdev->abs_bitmask, abs_bitmask, len);
+ } else if (memcmp(pEvdev->abs_bitmask, abs_bitmask, len)) {
xf86Msg(X_ERROR, "%s: device abs_bitmask has changed\n", pInfo->name);
goto error;
}
- if (ioctl(pInfo->fd,
- EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) < 0) {
- xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n", pInfo->name, strerror(errno));
- goto error;
- }
-
- if (compare && memcmp(pEvdev->key_bitmask, key_bitmask, sizeof(key_bitmask))) {
- xf86Msg(X_ERROR, "%s: device key_bitmask has changed\n", pInfo->name);
- goto error;
- }
-
- if (ioctl(pInfo->fd,
- EVIOCGBIT(EV_LED, sizeof(led_bitmask)), led_bitmask) < 0) {
- xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n", pInfo->name, strerror(errno));
+ len = ioctl(pInfo->fd, EVIOCGBIT(EV_LED, sizeof(led_bitmask)), led_bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
goto error;
}
- if (compare && memcmp(pEvdev->led_bitmask, led_bitmask, sizeof(led_bitmask))) {
+ if (!compare) {
+ memcpy(pEvdev->led_bitmask, led_bitmask, len);
+ } else if (memcmp(pEvdev->led_bitmask, led_bitmask, len)) {
xf86Msg(X_ERROR, "%s: device led_bitmask has changed\n", pInfo->name);
goto error;
}
- memset(absinfo, 0, sizeof(absinfo));
-
- for (i = ABS_X; i <= ABS_MAX; i++)
- {
- if (TestBit(i, abs_bitmask))
- {
- if (ioctl(pInfo->fd, EVIOCGABS(i), &absinfo[i]) < 0) {
- xf86Msg(X_ERROR, "%s: ioctl EVIOCGABS failed: %s\n", pInfo->name, strerror(errno));
+ /*
+ * Do not try to validate absinfo data since it is not expected
+ * to be static, always refresh it in evdev structure.
+ */
+ for (i = ABS_X; i <= ABS_MAX; i++) {
+ if (TestBit(i, abs_bitmask)) {
+ len = ioctl(pInfo->fd, EVIOCGABS(i), &pEvdev->absinfo[i]);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGABSi(%d) failed: %s\n",
+ pInfo->name, i, strerror(errno));
goto error;
}
- /* ignore current position (value) in comparison (bug #19819) */
- absinfo[i].value = pEvdev->absinfo[i].value;
}
}
- if (compare && memcmp(pEvdev->absinfo, absinfo, sizeof(absinfo))) {
- xf86Msg(X_ERROR, "%s: device absinfo has changed\n", pInfo->name);
+ len = ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
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));
+ if (compare) {
+ /*
+ * Keys are special as user can adjust keymap at any time (on
+ * devices that support EVIOCSKEYCODE. However we do not expect
+ * buttons reserved for mice/tablets/digitizers and so on to
+ * appear/disappear so we will check only those in
+ * [BTN_MISC, KEY_OK) range.
+ */
+ size_t start_word = BTN_MISC / LONG_BITS;
+ size_t start_byte = start_word * sizeof(unsigned long);
+ size_t end_word = KEY_OK / LONG_BITS;
+ size_t end_byte = end_word * sizeof(unsigned long);
+
+ if (len >= start_byte &&
+ memcmp(&pEvdev->key_bitmask[start_word], &key_bitmask[start_word],
+ min(len, end_byte) - start_byte + 1)) {
+ xf86Msg(X_ERROR, "%s: device key_bitmask has changed\n", pInfo->name);
+ goto error;
+ }
}
+ /* Copy the data so we have reasonably up-to-date info */
+ memcpy(pEvdev->key_bitmask, key_bitmask, len);
+
return Success;
error: