aboutsummaryrefslogtreecommitdiff
path: root/src/evdev_brain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/evdev_brain.c')
-rw-r--r--src/evdev_brain.c277
1 files changed, 229 insertions, 48 deletions
diff --git a/src/evdev_brain.c b/src/evdev_brain.c
index feafc34..7a20c68 100644
--- a/src/evdev_brain.c
+++ b/src/evdev_brain.c
@@ -106,75 +106,232 @@ evdevGetFDForDevice (evdevDevicePtr device)
driver->devices = device; \
} while (0)
+typedef struct {
+ int fd;
+ evdevBitsRec bits;
+ char name[256];
+ char phys[256];
+ char dev[256];
+ struct input_id id;
+} evdevDevInfoRec, *evdevDevInfoPtr;
+
+static Bool
+MatchAll (long *dev, long *match, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if ((dev[i] & match[i]) != match[i])
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool
+MatchNot (long *dev, long *match, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if ((dev[i] & match[i]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool
+MatchAny (long *dev, long *match, int len)
+{
+ int i, found = 0;
+
+ for (i = 0; i < len; i++)
+ if (match[i]) {
+ found = 1;
+ if ((dev[i] & match[i]))
+ return TRUE;
+ }
+
+ if (found)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+static Bool
+MatchDriver (evdevDriverPtr driver, evdevDevInfoPtr info)
+{
+ if (driver->name && glob_match(driver->name, info->name))
+ return FALSE;
+ if (driver->phys && glob_match(driver->phys, info->phys))
+ return FALSE;
+ if (driver->device && glob_match(driver->device, info->dev))
+ return FALSE;
+
+ if (driver->id.bustype && driver->id.bustype != info->id.bustype)
+ return FALSE;
+ if (driver->id.vendor && driver->id.vendor != info->id.vendor)
+ return FALSE;
+ if (driver->id.product && driver->id.product != info->id.product)
+ return FALSE;
+ if (driver->id.version && driver->id.version != info->id.version)
+ return FALSE;
+
+#define match(which) \
+ if (!MatchAll(info->bits.which, driver->all_bits.which, \
+ sizeof(driver->all_bits.which) / \
+ sizeof(driver->all_bits.which[0]))) \
+ return FALSE; \
+ if (!MatchNot(info->bits.which, driver->not_bits.which, \
+ sizeof(driver->not_bits.which) / \
+ sizeof(driver->not_bits.which[0]))) \
+ return FALSE; \
+ if (!MatchAny(info->bits.which, driver->any_bits.which, \
+ sizeof(driver->any_bits.which) / \
+ sizeof(driver->any_bits.which[0]))) \
+ return FALSE;
+
+ match(ev)
+ match(key)
+ match(rel)
+ match(abs)
+ match(msc)
+ match(led)
+ match(snd)
+ match(ff)
+
+#undef match
+
+ return TRUE;
+}
+
+static Bool
+MatchDevice (evdevDevicePtr device, evdevDevInfoPtr info)
+{
+ int i, len;
+
+ if (device->id.bustype != info->id.bustype)
+ return FALSE;
+ if (device->id.vendor != info->id.vendor)
+ return FALSE;
+ if (device->id.product != info->id.product)
+ return FALSE;
+ if (device->id.version != info->id.version)
+ return FALSE;
+
+ if (strcmp(device->name, info->name))
+ return FALSE;
+
+ len = sizeof(info->bits.ev) / sizeof(info->bits.ev[0]);
+ for (i = 0; i < len; i++)
+ if (device->bits.ev[i] != info->bits.ev[i])
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool
+evdevScanDevice (evdevDriverPtr driver, evdevDevInfoPtr info)
+{
+ evdevDevicePtr device;
+ int found;
+
+ if (!MatchDriver (driver, info))
+ return FALSE;
+
+ found = 0;
+ for (device = driver->devices; device; device = device->next) {
+ if (MatchDevice (device, info)) {
+ if (device->seen != (evdev_seq - 1)) {
+ device->device = xstrdup(info->dev);
+ device->phys = xstrdup(info->phys);
+ device->callback(device->pInfo->dev, DEVICE_ON);
+ }
+
+ device->seen = evdev_seq;
+
+ return TRUE;
+ }
+ }
+
+ device = Xcalloc (sizeof (evdevDeviceRec));
+
+ device->device = xstrdup(info->dev);
+ device->name = xstrdup(info->name);
+ device->phys = xstrdup(info->phys);
+ device->id.bustype = info->id.bustype;
+ device->id.vendor = info->id.vendor;
+ device->id.product = info->id.product;
+ device->id.version = info->id.version;
+ device->seen = evdev_seq;
+ device_add(driver, device);
+ driver->callback(driver, device);
+
+ return TRUE;
+}
+
+
+static Bool
+FillDevInfo (char *dev, evdevDevInfoPtr info)
+{
+ int fd;
+
+ SYSCALL(fd = open (dev, O_RDWR | O_NONBLOCK));
+ if (fd == -1)
+ return FALSE;
+
+ if (ioctl(fd, EVIOCGNAME(sizeof(info->name)), info->name) == -1)
+ info->name[0] = '\0';
+ if (ioctl(fd, EVIOCGPHYS(sizeof(info->phys)), info->phys) == -1)
+ info->phys[0] = '\0';
+ if (ioctl(fd, EVIOCGID, &info->id) == -1) {
+ close (fd);
+ return FALSE;
+ }
+ if (!evdevGetBits (fd, &info->bits)) {
+ close (fd);
+ return FALSE;
+ }
+
+ strncpy (info->dev, dev, sizeof(info->dev));
+ info->fd = fd;
+
+ return TRUE;
+}
+
static void
evdevRescanDevices (InputInfoPtr pInfo)
{
char dev[20];
- char name[256], phys[256];
- int fd, i;
- int old_seq = evdev_seq;
+ int i, j, found;
evdevDriverPtr driver;
evdevDevicePtr device;
- Bool found;
+ evdevDevInfoRec info;
evdev_seq++;
xf86Msg(X_INFO, "%s: Rescanning devices (%d).\n", pInfo->name, evdev_seq);
for (i = 0; i < 32; i++) {
snprintf(dev, sizeof(dev), "/dev/input/event%d", i);
- SYSCALL(fd = open (dev, O_RDWR | O_NONBLOCK));
- if (fd == -1)
- continue;
- if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) == -1)
- name[0] = '\0';
- if (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) == -1)
- phys[0] = '\0';
-
- for (driver = evdev_drivers; driver; driver = driver->next) {
- if (driver->name && glob_match(driver->name, name))
- continue;
- if (driver->phys && glob_match(driver->phys, phys))
- continue;
- if (driver->device && glob_match(driver->device, dev))
- continue;
-
- found = 0;
- for (device = driver->devices; device; device = device->next) {
- xf86Msg(X_INFO, "%s: %s %d -> %s %d.\n", pInfo->name, name, evdev_seq, device->name, device->seen);
- if (!strcmp(device->name, name)) {
- if (device->seen != old_seq) {
- device->device = xstrdup(dev);
- device->phys = xstrdup(phys);
- device->callback(device->pInfo->dev, DEVICE_ON);
- }
-
- device->seen = evdev_seq;
- found = 1;
- break;
- }
- }
+ if (!FillDevInfo (dev, &info))
+ continue;
- if (!found) {
- device = Xcalloc (sizeof (evdevDeviceRec));
+ found = 0;
- device->device = xstrdup(dev);
- device->name = xstrdup(name);
- device->phys = xstrdup(phys);
- device->seen = evdev_seq;
- device_add(driver, device);
- driver->callback(driver, device);
+ for (j = 0; j <= 3 && !found; j++) {
+ for (driver = evdev_drivers; driver && !found; driver = driver->next) {
+ if ((driver->pass == j) && (found = evdevScanDevice (driver, &info)))
+ break;
}
-
- device->seen = evdev_seq;
- break;
}
- close (fd);
+
+ if (!found)
+ close (info.fd);
}
for (driver = evdev_drivers; driver; driver = driver->next)
for (device = driver->devices; device; device = device->next)
- if (device->seen == old_seq) {
+ if (device->seen == (evdev_seq - 1)) {
device->callback(device->pInfo->dev, DEVICE_OFF);
if (device->device)
@@ -282,3 +439,27 @@ evdevNewDriver (evdevDriverPtr driver)
driver->configured = TRUE;
return TRUE;
}
+
+Bool
+evdevGetBits (int fd, evdevBitsPtr bits)
+{
+#define get_bitmask(fd, which, where) \
+ if (ioctl(fd, EVIOCGBIT(which, sizeof (where)), where) < 0) { \
+ xf86Msg(X_ERROR, "ioctl EVIOCGBIT %s failed: %s\n", #which, strerror(errno)); \
+ return FALSE; \
+ }
+
+ get_bitmask (fd, 0, bits->ev);
+ get_bitmask (fd, EV_KEY, bits->key);
+ get_bitmask (fd, EV_REL, bits->rel);
+ get_bitmask (fd, EV_ABS, bits->abs);
+ get_bitmask (fd, EV_MSC, bits->msc);
+ get_bitmask (fd, EV_LED, bits->led);
+ get_bitmask (fd, EV_SND, bits->snd);
+ get_bitmask (fd, EV_FF, bits->ff);
+
+#undef get_bitmask
+
+ return TRUE;
+}
+