summaryrefslogtreecommitdiff
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-05 08:41:59 +1000
commita0f7f34dc5effc5822c618bfbf3a0872669c30ad (patch)
treec3e6b621915741f50dc1e913a18fe6cb31f5dd01
parent11669d82790fd7c94c44c0d487d3fa5e203528e9 (diff)
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>
-rw-r--r--src/evdev.c126
1 files changed, 71 insertions, 55 deletions
diff --git a/src/evdev.c b/src/evdev.c
index 7013400..06ea83b 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1586,6 +1586,7 @@ static int
EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare)
{
EvdevPtr pEvdev = pInfo->private;
+ size_t len;
int i;
char name[1024] = {0};
@@ -1594,107 +1595,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: