x-input-evdev: Branch 'evdev-modular' - src/evdev_brain.c src/inotify.h src/inotify-syscalls.h src/xorg/evdevxorg_axes.c src/xorg/evdevxorg_brain.c src/xorg/evdevxorg_btn.c src/xorg/evdevxorg.c src/xorg/evdevxorg.h src/xorg/evdevxorg_key.c
Tiago Vignatti
vignatti at kemper.freedesktop.org
Fri Aug 18 19:25:13 EEST 2006
src/evdev_brain.c | 456 ++++++++++++++++++++++++++++++
src/inotify-syscalls.h | 79 +++++
src/inotify.h | 60 ++++
src/xorg/evdevxorg.c | 495 +++++++++++++++++++++++++++++++++
src/xorg/evdevxorg.h | 275 ++++++++++++++++++
src/xorg/evdevxorg_axes.c | 664 +++++++++++++++++++++++++++++++++++++++++++++
src/xorg/evdevxorg_brain.c | 487 +++++++++++++++++++++++++++++++++
src/xorg/evdevxorg_btn.c | 367 ++++++++++++++++++++++++
src/xorg/evdevxorg_key.c | 451 ++++++++++++++++++++++++++++++
9 files changed, 3334 insertions(+)
New commits:
diff-tree 43fb4717de64b415bbf336213aced0ce8ae3e6d2 (from e77b6a0ba2e557809950d986e3caa4a2989b9930)
Author: Tiago Vignatti <tv02 at c3sl.ufpr.br>
Date: Fri Aug 18 13:24:09 2006 -0300
Rename some files.
diff --git a/src/evdev_brain.c b/src/evdev_brain.c
new file mode 100644
index 0000000..1533733
--- /dev/null
+++ b/src/evdev_brain.c
@@ -0,0 +1,456 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "evdevxorg.h"
+
+#include "xf86_OSlib.h"
+
+#include <xf86.h>
+#include <fnmatch.h>
+#include <sys/poll.h>
+
+#include "inotify.h"
+#include "inotify-syscalls.h"
+
+#ifndef SYSCALL
+#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
+#endif
+
+static Bool evdev_alive = FALSE;
+static InputInfoPtr evdev_pInfo = NULL;
+static evdevDriverPtr evdev_drivers = NULL;
+static int evdev_seq;
+static int evdev_inotify;
+
+int
+evdevGetFDForDevice (evdevDevicePtr device)
+{
+ int fd;
+
+ if (!device)
+ return -1;
+
+
+ if (device->device) {
+ SYSCALL(fd = open (device->device, O_RDWR | O_NONBLOCK));
+ if (fd == -1)
+ xf86Msg(X_ERROR, "%s (%d): Open failed: %s\n", __FILE__, __LINE__, strerror(errno));
+ return fd;
+ } else
+ return -1;
+}
+
+#define device_add(driver,device) do { \
+ device->next = driver->devices; \
+ driver->devices = device; \
+} while (0)
+
+typedef struct {
+ evdevBitsRec bits;
+ char name[256];
+ char phys[256];
+ char dev[256];
+ struct input_id id;
+} evdevDevInfoRec, *evdevDevInfoPtr;
+
+static Bool
+MatchAll (unsigned long *dev, unsigned 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 (unsigned long *dev, unsigned long *match, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if ((dev[i] & match[i]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool
+MatchAny (unsigned long *dev, unsigned 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 && fnmatch(driver->name, info->name, 0))
+ return FALSE;
+ if (driver->phys && fnmatch(driver->phys, info->phys, 0))
+ return FALSE;
+ if (driver->device && fnmatch(driver->device, info->dev, 0))
+ 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));
+ close (fd);
+
+ return TRUE;
+}
+
+static void
+evdevRescanDevices (InputInfoPtr pInfo)
+{
+ char dev[20];
+ int i, j, found;
+ evdevDriverPtr driver;
+ evdevDevicePtr device;
+ 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);
+
+ if (!FillDevInfo (dev, &info))
+ continue;
+
+ found = 0;
+
+ 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;
+ }
+ }
+ }
+
+ for (driver = evdev_drivers; driver; driver = driver->next)
+ for (device = driver->devices; device; device = device->next)
+ if (device->seen == (evdev_seq - 1)) {
+ device->callback(device->pInfo->dev, DEVICE_OFF);
+
+ if (device->device)
+ xfree(device->device);
+ device->device = NULL;
+
+ if (device->phys)
+ xfree(device->phys);
+ device->phys = NULL;
+ }
+}
+
+static void
+evdevReadInput (InputInfoPtr pInfo)
+{
+ int scan = 0, i, len;
+ char buf[4096];
+ struct inotify_event *event;
+
+ if (evdev_inotify) {
+ while ((len = read (pInfo->fd, buf, sizeof(buf))) >= 0) {
+ for (i = 0; i < len; i += sizeof (struct inotify_event) + event->len) {
+ event = (struct inotify_event *) &buf[i];
+ if (!event->len)
+ continue;
+ if (event->mask & IN_ISDIR)
+ continue;
+ if (strncmp("event", event->name, 5))
+ continue;
+ scan = 1;
+ }
+ }
+
+ if (scan)
+ evdevRescanDevices (pInfo);
+ } else {
+ /*
+ * XXX: Freezing the server for a moment is not really friendly.
+ * But we need to wait until udev has actually created the device.
+ */
+ usleep (500000);
+ evdevRescanDevices (pInfo);
+ }
+}
+
+static int
+evdevControl(DeviceIntPtr pPointer, int what)
+{
+ InputInfoPtr pInfo;
+ int i, flags;
+
+ pInfo = pPointer->public.devicePrivate;
+
+ switch (what) {
+ case DEVICE_INIT:
+ pPointer->public.on = FALSE;
+ break;
+
+ case DEVICE_ON:
+ /*
+ * XXX: We do /proc/bus/usb/devices instead of /proc/bus/input/devices
+ * because the only hotplug input devices at the moment are USB...
+ * And because the latter is useless to poll/select against.
+ * FIXME: Get a patch in the kernel which fixes the latter.
+ */
+ evdev_inotify = 1;
+ SYSCALL(pInfo->fd = inotify_init());
+ if (pInfo->fd < 0) {
+ xf86Msg(X_ERROR, "%s: Unable to initialize inotify, using fallback. (errno: %d)\n", pInfo->name, errno);
+ evdev_inotify = 0;
+ }
+ SYSCALL (i = inotify_add_watch (pInfo->fd, "/dev/input/", IN_CREATE | IN_DELETE));
+ if (i < 0) {
+ xf86Msg(X_ERROR, "%s: Unable to initialize inotify, using fallback. (errno: %d)\n", pInfo->name, errno);
+ evdev_inotify = 0;
+ SYSCALL (close (pInfo->fd));
+ pInfo->fd = -1;
+ }
+ if ((flags = fcntl(pInfo->fd, F_GETFL)) < 0) {
+ xf86Msg(X_ERROR, "%s: Unable to NONBLOCK inotify, using fallback. "
+ "(errno: %d)\n", pInfo->name, errno);
+ evdev_inotify = 0;
+ SYSCALL (close (pInfo->fd));
+ pInfo->fd = -1;
+ } else if (fcntl(pInfo->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
+ xf86Msg(X_ERROR, "%s: Unable to NONBLOCK inotify, using fallback. "
+ "(errno: %d)\n", pInfo->name, errno);
+ evdev_inotify = 0;
+ SYSCALL (close (pInfo->fd));
+ pInfo->fd = -1;
+ }
+
+ if (!evdev_inotify) {
+ SYSCALL (pInfo->fd = open ("/proc/bus/usb/devices", O_RDONLY));
+ if (pInfo->fd < 0) {
+ xf86Msg(X_ERROR, "%s: cannot open /proc/bus/usb/devices.\n", pInfo->name);
+ return BadRequest;
+ }
+ }
+ xf86FlushInput(pInfo->fd);
+ AddEnabledDevice(pInfo->fd);
+ pPointer->public.on = TRUE;
+ evdevRescanDevices (pInfo);
+ break;
+
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ if (pInfo->fd != -1) {
+ RemoveEnabledDevice(pInfo->fd);
+ SYSCALL (close (pInfo->fd));
+ pInfo->fd = -1;
+ }
+ pPointer->public.on = FALSE;
+ break;
+ }
+ return Success;
+}
+
+Bool
+evdevStart (InputDriverPtr drv)
+{
+ InputInfoRec *pInfo;
+
+ if (evdev_alive)
+ return TRUE;
+
+ if (!(pInfo = xf86AllocateInput(drv, 0)))
+ return FALSE;
+
+ evdev_alive = TRUE;
+
+ pInfo->name = "evdev brain";
+ pInfo->type_name = "evdev brain";
+ pInfo->device_control = evdevControl;
+ pInfo->read_input = evdevReadInput;
+ pInfo->fd = -1;
+ pInfo->flags = XI86_CONFIGURED | XI86_OPEN_ON_INIT;
+
+ evdev_pInfo = pInfo;
+ return TRUE;
+}
+
+Bool
+evdevNewDriver (evdevDriverPtr driver)
+{
+ if (!evdev_alive)
+ return FALSE;
+ /* FIXME: Make this check valid given all the ways to look. */
+#if 0
+ if (!(driver->name || driver->phys || driver->device))
+ return FALSE;
+#endif
+ if (!driver->callback)
+ return FALSE;
+
+ driver->next = evdev_drivers;
+ evdev_drivers = driver;
+
+ evdevRescanDevices (evdev_pInfo);
+ 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;
+}
+
diff --git a/src/inotify-syscalls.h b/src/inotify-syscalls.h
new file mode 100644
index 0000000..7c68bc6
--- /dev/null
+++ b/src/inotify-syscalls.h
@@ -0,0 +1,79 @@
+#ifndef _LINUX_INOTIFY_SYSCALLS_H
+#define _LINUX_INOTIFY_SYSCALLS_H
+
+#include <sys/syscall.h>
+
+#if defined(__i386__)
+# define __NR_inotify_init 291
+# define __NR_inotify_add_watch 292
+# define __NR_inotify_rm_watch 293
+#elif defined(__x86_64__)
+# define __NR_inotify_init 253
+# define __NR_inotify_add_watch 254
+# define __NR_inotify_rm_watch 255
+#elif defined(__powerpc__) || defined(__powerpc64__)
+# define __NR_inotify_init 275
+# define __NR_inotify_add_watch 276
+# define __NR_inotify_rm_watch 277
+#elif defined (__ia64__)
+# define __NR_inotify_init 1277
+# define __NR_inotify_add_watch 1278
+# define __NR_inotify_rm_watch 1279
+#elif defined (__s390__)
+# define __NR_inotify_init 284
+# define __NR_inotify_add_watch 285
+# define __NR_inotify_rm_watch 286
+#elif defined (__alpha__)
+# define __NR_inotify_init 444
+# define __NR_inotify_add_watch 445
+# define __NR_inotify_rm_watch 446
+#elif defined (__sparc__) || defined (__sparc64__)
+# define __NR_inotify_init 151
+# define __NR_inotify_add_watch 152
+# define __NR_inotify_rm_watch 156
+#elif defined (__arm__)
+# define __NR_inotify_init 316
+# define __NR_inotify_add_watch 317
+# define __NR_inotify_rm_watch 318
+#elif defined (__sh__)
+# define __NR_inotify_init 290
+# define __NR_inotify_add_watch 291
+# define __NR_inotify_rm_watch 292
+#elif defined (__hppa__) || defined (__hppa64__)
+# define __NR_inotify_init 269
+# define __NR_inotify_add_watch 270
+# define __NR_inotify_rm_watch 271
+#elif defined (__mips__)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_inotify_init 4284
+# define __NR_inotify_add_watch 4285
+# define __NR_inotify_rm_watch 4286
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_inotify_init 6247
+# define __NR_inotify_add_watch 6248
+# define __NR_inotify_rm_watch 6249
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_inotify_init 5243
+# define __NR_inotify_add_watch 5244
+# define __NR_inotify_rm_watch 5245
+# endif
+#else
+# error "Unsupported architecture!"
+#endif
+
+static inline int inotify_init (void)
+{
+ return syscall (__NR_inotify_init);
+}
+
+static inline int inotify_add_watch (int fd, const char *name, __u32 mask)
+{
+ return syscall (__NR_inotify_add_watch, fd, name, mask);
+}
+
+static inline int inotify_rm_watch (int fd, __u32 wd)
+{
+ return syscall (__NR_inotify_rm_watch, fd, wd);
+}
+
+#endif /* _LINUX_INOTIFY_SYSCALLS_H */
diff --git a/src/inotify.h b/src/inotify.h
new file mode 100644
index 0000000..20d419a
--- /dev/null
+++ b/src/inotify.h
@@ -0,0 +1,60 @@
+/*
+ * Inode based directory notification for Linux
+ *
+ * Copyright (C) 2005 John McCutchan
+ */
+
+#ifndef _LINUX_INOTIFY_H
+#define _LINUX_INOTIFY_H
+
+#include <linux/types.h>
+
+/*
+ * struct inotify_event - structure read from the inotify device for each event
+ *
+ * When you are watching a directory, you will receive the filename for events
+ * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
+ */
+struct inotify_event {
+ __s32 wd; /* watch descriptor */
+ __u32 mask; /* watch mask */
+ __u32 cookie; /* cookie to synchronize two events */
+ __u32 len; /* length (including nulls) of name */
+ char name[0]; /* stub for possible name */
+};
+
+/* the following are legal, implemented events that user-space can watch for */
+#define IN_ACCESS 0x00000001 /* File was accessed */
+#define IN_MODIFY 0x00000002 /* File was modified */
+#define IN_ATTRIB 0x00000004 /* Metadata changed */
+#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */
+#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
+#define IN_OPEN 0x00000020 /* File was opened */
+#define IN_MOVED_FROM 0x00000040 /* File was moved from X */
+#define IN_MOVED_TO 0x00000080 /* File was moved to Y */
+#define IN_CREATE 0x00000100 /* Subfile was created */
+#define IN_DELETE 0x00000200 /* Subfile was deleted */
+#define IN_DELETE_SELF 0x00000400 /* Self was deleted */
+
+/* the following are legal events. they are sent as needed to any watch */
+#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */
+#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
+#define IN_IGNORED 0x00008000 /* File was ignored */
+
+/* helper events */
+#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */
+#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
+
+/* special flags */
+#define IN_ISDIR 0x40000000 /* event occurred against dir */
+#define IN_ONESHOT 0x80000000 /* only send event once */
+
+/*
+ * All of the events - we build the list by hand so that we can add flags in
+ * the future and not break backward compatibility. Apps will get only the
+ * events that they originally wanted. Be sure to add new events here!
+ */
+#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
+ IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
+ IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF)
+#endif /* _LINUX_INOTIFY_H */
diff --git a/src/xorg/evdevxorg.c b/src/xorg/evdevxorg.c
new file mode 100644
index 0000000..64b7653
--- /dev/null
+++ b/src/xorg/evdevxorg.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp at aehallh.com)
+ */
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Kristian Høgsberg (krh at redhat.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/extensions/XIproto.h>
+
+#include "evdevxorg.h"
+
+#include <xf86.h>
+
+#include <xf86Module.h>
+#include <mipointer.h>
+
+
+#include <xf86_OSproc.h>
+
+/*
+ * FIXME: This should most definitely not be here.
+ * But I need it, even if it _is_ private.
+ */
+
+void xf86ActivateDevice(InputInfoPtr pInfo);
+
+static void
+EvdevReadInput(InputInfoPtr pInfo)
+{
+ struct input_event ev;
+ int len;
+
+ while (xf86WaitForInput (pInfo->fd, 0) > 0) {
+ len = read(pInfo->fd, &ev, sizeof(ev));
+ if (len != sizeof(ev)) {
+ /* The kernel promises that we always only read a complete
+ * event, so len != sizeof ev is an error. */
+ xf86Msg(X_ERROR, "Read error: %s (%d, %d != %ld)\n",
+ strerror(errno), errno, len, sizeof (ev));
+ if (len < 0) {
+ evdevDevicePtr pEvdev = pInfo->private;
+ pEvdev->callback(pEvdev->pInfo->dev, DEVICE_OFF);
+ pEvdev->seen--;
+ }
+ break;
+ }
+
+ switch (ev.type) {
+ case EV_REL:
+ EvdevAxesRelProcess (pInfo, &ev);
+ break;
+
+ case EV_ABS:
+ EvdevAxesAbsProcess (pInfo, &ev);
+ break;
+
+ case EV_KEY:
+ if ((ev.code >= BTN_MISC) && (ev.code < KEY_OK))
+ EvdevBtnProcess (pInfo, &ev);
+ else
+ EvdevKeyProcess (pInfo, &ev);
+ break;
+
+ case EV_SYN:
+ if (ev.code == SYN_REPORT) {
+ EvdevAxesSyn (pInfo);
+ /* EvdevBtnSyn (pInfo); */
+ /* EvdevKeySyn (pInfo); */
+ }
+ break;
+ }
+ }
+}
+
+static void
+EvdevSigioReadInput (int fd, void *data)
+{
+ EvdevReadInput ((InputInfoPtr) data);
+}
+
+static int
+EvdevProc(DeviceIntPtr device, int what)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+
+ if (!pEvdev->device)
+ return BadRequest;
+
+ switch (what)
+ {
+ case DEVICE_INIT:
+ if (pEvdev->state.axes)
+ EvdevAxesInit (device);
+ if (pEvdev->state.btn)
+ EvdevBtnInit (device);
+ if (pEvdev->state.key)
+ EvdevKeyInit (device);
+ xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
+ break;
+
+ case DEVICE_ON:
+ xf86Msg(X_INFO, "%s: On\n", pInfo->name);
+ if (device->public.on)
+ break;
+
+ if ((pInfo->fd = evdevGetFDForDevice (pEvdev)) == -1) {
+ xf86Msg(X_ERROR, "%s: cannot open input device.\n", pInfo->name);
+
+ if (pEvdev->phys)
+ xfree(pEvdev->phys);
+ pEvdev->phys = NULL;
+
+ if (pEvdev->device)
+ xfree(pEvdev->device);
+ pEvdev->device = NULL;
+
+ return BadRequest;
+ }
+
+ if (pEvdev->state.can_grab)
+ if (ioctl(pInfo->fd, EVIOCGRAB, (void *)1))
+ xf86Msg(X_ERROR, "%s: Unable to grab device (%s).\n", pInfo->name, strerror(errno));
+
+ xf86FlushInput (pInfo->fd);
+ if (!xf86InstallSIGIOHandler (pInfo->fd, EvdevSigioReadInput, pInfo))
+ AddEnabledDevice (pInfo->fd);
+
+ device->public.on = TRUE;
+
+ if (pEvdev->state.axes)
+ EvdevAxesOn (device);
+ if (pEvdev->state.btn)
+ EvdevBtnOn (device);
+ if (pEvdev->state.key)
+ EvdevKeyOn (device);
+ break;
+
+ case DEVICE_CLOSE:
+ case DEVICE_OFF:
+ xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
+ if (pInfo->fd != -1) {
+ if (pEvdev->state.can_grab)
+ ioctl(pInfo->fd, EVIOCGRAB, (void *)0);
+
+ RemoveEnabledDevice (pInfo->fd);
+ xf86RemoveSIGIOHandler (pInfo->fd);
+ close (pInfo->fd);
+ pInfo->fd = -1;
+
+ if (pEvdev->state.axes)
+ EvdevAxesOff (device);
+ if (pEvdev->state.btn)
+ EvdevBtnOff (device);
+ if (pEvdev->state.key)
+ EvdevKeyOff (device);
+ }
+
+ device->public.on = FALSE;
+ break;
+ }
+
+ return Success;
+}
+
+static int
+EvdevSwitchMode (ClientPtr client, DeviceIntPtr device, int mode)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+
+ switch (mode)
+ {
+ case Absolute:
+ case Relative:
+ xf86Msg(X_INFO, "%s: Switching mode to %d.\n", pInfo->name, mode);
+ if (state->abs)
+ state->mode = mode;
+ else
+ return !Success;
+ break;
+ case SendCoreEvents:
+ case DontSendCoreEvents:
+ xf86XInputSetSendCoreEvents (pInfo, (mode == SendCoreEvents));
+ break;
+ default:
+ return !Success;
+ }
+
+ return Success;
+}
+
+static Bool
+EvdevNew(evdevDriverPtr driver, evdevDevicePtr device)
+{
+ InputInfoPtr pInfo;
+ char name[512] = {0};
+
+ if (!(pInfo = xf86AllocateInput(driver->drv, 0)))
+ return 0;
+
+ /* Initialise the InputInfoRec. */
+ strncat (name, driver->dev->identifier, sizeof(name));
+ strncat (name, "-", sizeof(name));
+ strncat (name, device->phys, sizeof(name));
+ pInfo->name = xstrdup(name);
+ pInfo->flags = 0;
+ pInfo->type_name = "UNKNOWN";
+ pInfo->device_control = EvdevProc;
+ pInfo->read_input = EvdevReadInput;
+ pInfo->switch_mode = EvdevSwitchMode;
+ pInfo->motion_history_proc = xf86GetMotionEvents;
+ pInfo->conf_idev = driver->dev;
+
+ pInfo->private = device;
+
+ device->callback = EvdevProc;
+ device->pInfo = pInfo;
+
+ xf86CollectInputOptions(pInfo, NULL, NULL);
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
+
+ if ((pInfo->fd = evdevGetFDForDevice (device)) == -1) {
+ xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
+ pInfo->private = NULL;
+ xf86DeleteInput (pInfo, 0);
+ return 0;
+ }
+
+ if (!evdevGetBits (pInfo->fd, &device->bits)) {
+ xf86Msg(X_ERROR, "%s: cannot load bits\n", pInfo->name);
+ pInfo->private = NULL;
+ close (pInfo->fd);
+ xf86DeleteInput (pInfo, 0);
+ return 0;
+ }
+
+ if (ioctl(pInfo->fd, EVIOCGRAB, (void *)1)) {
+ xf86Msg(X_INFO, "%s: Unable to grab device (%s). Cowardly refusing to check use as keyboard.\n", pInfo->name, strerror(errno));
+ device->state.can_grab = 0;
+ } else {
+ device->state.can_grab = 1;
+ ioctl(pInfo->fd, EVIOCGRAB, (void *)0);
+ }
+
+
+ /* XXX: Note, the order of these is (maybe) still important. */
+ EvdevAxesNew0 (pInfo);
+ EvdevBtnNew0 (pInfo);
+
+ EvdevAxesNew1 (pInfo);
+ EvdevBtnNew1 (pInfo);
+
+ if (device->state.can_grab)
+ EvdevKeyNew (pInfo);
+
+ close (pInfo->fd);
+ pInfo->fd = -1;
+
+ pInfo->flags |= XI86_OPEN_ON_INIT;
+ if (!(pInfo->flags & XI86_CONFIGURED)) {
+ xf86Msg(X_ERROR, "%s: Don't know how to use device.\n", pInfo->name);
+ pInfo->private = NULL;
+ close (pInfo->fd);
+ xf86DeleteInput (pInfo, 0);
+ return 0;
+ }
+
+ if (driver->configured) {
+ xf86ActivateDevice (pInfo);
+
+ pInfo->dev->inited = (device->callback(device->pInfo->dev, DEVICE_INIT) == Success);
+ EnableDevice (pInfo->dev);
+ }
+
+ return 1;
+}
+
+static void
+EvdevParseBits (char *in, unsigned long *out, int len)
+{
+ unsigned long v[2];
+ int n, i, max_bits = len * BITS_PER_LONG;
+
+ n = sscanf (in, "%lu-%lu", &v[0], &v[1]);
+ if (!n)
+ return;
+
+ if (v[0] >= max_bits)
+ return;
+
+ if (n == 2) {
+ if (v[1] >= max_bits)
+ v[1] = max_bits - 1;
+
+ for (i = v[0]; i <= v[1]; i++)
+ set_bit (i, out);
+ } else
+ set_bit (v[0], out);
+}
+
+static void
+EvdevParseBitOption (char *opt, unsigned long *all, unsigned long *not, unsigned long *any, int len)
+{
+ char *cur, *next;
+
+ next = opt - 1;
+ while (next) {
+ cur = next + 1;
+ if ((next = strchr(cur, ' ')))
+ *next = '\0';
+
+ switch (cur[0]) {
+ case '+':
+ EvdevParseBits (cur + 1, all, len);
+ break;
+ case '-':
+ EvdevParseBits (cur + 1, not, len);
+ break;
+ case '~':
+ EvdevParseBits (cur + 1, any, len);
+ break;
+ }
+ }
+}
+
+static InputInfoPtr
+EvdevCorePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ evdevDriverPtr pEvdev;
+ char *opt, *tmp;
+
+ if (!(pEvdev = Xcalloc(sizeof(*pEvdev))))
+ return NULL;
+
+ pEvdev->name = xf86CheckStrOption(dev->commonOptions, "Name", NULL);
+ pEvdev->phys = xf86CheckStrOption(dev->commonOptions, "Phys", NULL);
+ pEvdev->device = xf86CheckStrOption(dev->commonOptions, "Device", NULL);
+
+#define bitoption(field) \
+ opt = xf86CheckStrOption(dev->commonOptions, #field "Bits", NULL); \
+ if (opt) { \
+ tmp = strdup(opt); \
+ EvdevParseBitOption (tmp, pEvdev->all_bits.field, \
+ pEvdev->not_bits.field, \
+ pEvdev->any_bits.field, \
+ sizeof(pEvdev->not_bits.field) / sizeof (unsigned long)); \
+ free (tmp); \
+ }
+ bitoption(ev);
+ bitoption(key);
+ bitoption(rel);
+ bitoption(abs);
+ bitoption(msc);
+ bitoption(led);
+ bitoption(snd);
+ bitoption(ff);
+#undef bitoption
+
+ pEvdev->id.bustype = xf86CheckIntOption(dev->commonOptions, "bustype", 0);
+ pEvdev->id.vendor = xf86CheckIntOption(dev->commonOptions, "vendor", 0);
+ pEvdev->id.product = xf86CheckIntOption(dev->commonOptions, "product", 0);
+ pEvdev->id.version = xf86CheckIntOption(dev->commonOptions, "version", 0);
+
+ pEvdev->pass = xf86CheckIntOption(dev->commonOptions, "Pass", 0);
+ if (pEvdev->pass > 3)
+ pEvdev->pass = 3;
+ else if (pEvdev->pass < 0)
+ pEvdev->pass = 0;
+
+
+ pEvdev->callback = EvdevNew;
+
+ pEvdev->dev = dev;
+ pEvdev->drv = drv;
+
+ if (!evdevStart (drv)) {
+ xf86Msg(X_ERROR, "%s: cannot start evdev brain.\n", dev->identifier);
+ xfree(pEvdev);
+ return NULL;
+ }
+
+ evdevNewDriver (pEvdev);
+
+ if (pEvdev->devices && pEvdev->devices->pInfo)
+ return pEvdev->devices->pInfo;
+
+ return NULL;
+}
+
+
+
+_X_EXPORT InputDriverRec EVDEV = {
+ 1,
+ "evdev",
+ NULL,
+ EvdevCorePreInit,
+ NULL,
+ NULL,
+ 0
+};
+
+#ifdef XFree86LOADER
+
+static void
+EvdevUnplug(pointer p)
+{
+}
+
+static pointer
+EvdevPlug(pointer module,
+ pointer options,
+ int *errmaj,
+ int *errmin)
+{
+ xf86AddInputDriver(&EVDEV, module, 0);
+ return module;
+}
+
+static XF86ModuleVersionInfo EvdevVersionRec =
+{
+ "evdev",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ 0, /* Missing from SDK: XORG_VERSION_CURRENT, */
+ 1, 1, 0,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ {0, 0, 0, 0}
+};
+
+_X_EXPORT XF86ModuleData evdevModuleData =
+{
+ &EvdevVersionRec,
+ EvdevPlug,
+ EvdevUnplug
+};
+#endif /* XFree86LOADER */
diff --git a/src/xorg/evdevxorg.h b/src/xorg/evdevxorg.h
new file mode 100644
index 0000000..db33546
--- /dev/null
+++ b/src/xorg/evdevxorg.h
@@ -0,0 +1,275 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp at aehallh.com)
+ */
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Kristian Høgsberg (krh at redhat.com)
+ */
+
+#ifndef EVDEV_BRAIN_H_
+#define EVDEV_BRAIN_H_
+
+#define _XF86_ANSIC_H
+#define XF86_LIBC_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <linux/input.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <xf86Xinput.h>
+
+#ifndef BITS_PER_LONG
+#define BITS_PER_LONG (sizeof(unsigned long) * 8)
+#endif
+
+#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define MASK(x) (1UL << ((x) & (BITS_PER_LONG - 1)))
+
+#ifndef test_bit
+#define test_bit(bit, array) (!!(array[LONG(bit)] & MASK(bit)))
+#endif
+#ifndef set_bit
+#define set_bit(bit, array) (array[LONG(bit)] |= MASK(bit))
+#endif
+#ifndef clear_bit
+#define clear_bit(bit, array) (array[LONG(bit)] &= ~MASK(bit))
+#endif
+
+/* 2.4 compatibility */
+#ifndef EVIOCGSW
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
+
+#define EV_SW 0x05
+#endif
+
+#ifndef EVIOCGRAB
+#define EVIOCGRAB _IOW('E', 0x90, int)
+#endif
+
+#ifndef BTN_TASK
+#define BTN_TASK 0x117
+#endif
+
+#ifndef EV_SYN
+#define EV_SYN EV_RST
+#endif
+/* end compat */
+
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+
+
+/*
+ * Switch events
+ */
+
+#define EV_SW_0 0x00
+#define EV_SW_1 0x01
+#define EV_SW_2 0x02
+#define EV_SW_3 0x03
+#define EV_SW_4 0x04
+#define EV_SW_5 0x05
+#define EV_SW_6 0x06
+#define EV_SW_7 0x07
+#define EV_SW_MAX 0x0f
+
+#define EV_BUS_GSC 0x1A
+
+#define EVDEV_MAXBUTTONS 96
+
+typedef struct {
+ unsigned long ev[NBITS(EV_MAX)];
+ unsigned long key[NBITS(KEY_MAX)];
+ unsigned long rel[NBITS(REL_MAX)];
+ unsigned long abs[NBITS(ABS_MAX)];
+ unsigned long msc[NBITS(MSC_MAX)];
+ unsigned long led[NBITS(LED_MAX)];
+ unsigned long snd[NBITS(SND_MAX)];
+ unsigned long ff[NBITS(FF_MAX)];
+} evdevBitsRec, *evdevBitsPtr;
+
+typedef struct {
+ int real_buttons;
+ int buttons;
+ CARD8 map[EVDEV_MAXBUTTONS];
+ void (*callback[EVDEV_MAXBUTTONS])(InputInfoPtr pInfo, int button, int value);
+} evdevBtnRec, *evdevBtnPtr;
+
+typedef struct {
+ int axes;
+ int v[ABS_MAX];
+ int old_x, old_y;
+ int count;
+ int min[ABS_MAX];
+ int max[ABS_MAX];
+ int map[ABS_MAX];
+ int scale[2];
+ int screen; /* Screen number for this device. */
+ Bool use_touch;
+ Bool touch;
+ Bool reset;
+} evdevAbsRec, *evdevAbsPtr;
+
+typedef struct {
+ int axes;
+ int v[REL_MAX];
+ int count;
+ int map[REL_MAX];
+ int btnMap[REL_MAX][2];
+} evdevRelRec, *evdevRelPtr;
+
+typedef struct {
+ int axes;
+ int v[ABS_MAX];
+} evdevAxesRec, *evdevAxesPtr;
+
+typedef struct {
+ char *xkb_rules;
+ char *xkb_model;
+ char *xkb_layout;
+ char *xkb_variant;
+ char *xkb_options;
+ XkbComponentNamesRec xkbnames;
+} evdevKeyRec, *evdevKeyPtr;
+
+typedef struct _evdevState {
+ Bool can_grab;
+ Bool sync;
+ int mode; /* Either Absolute or Relative. */
+
+ evdevBtnPtr btn;
+ evdevAbsPtr abs;
+ evdevRelPtr rel;
+ evdevKeyPtr key;
+ evdevAxesPtr axes;
+} evdevStateRec, *evdevStatePtr;
+
+typedef struct _evdevDevice {
+ const char *name;
+ const char *phys;
+ const char *device;
+ int seen;
+
+ InputInfoPtr pInfo;
+ int (*callback)(DeviceIntPtr cb_data, int what);
+
+ evdevBitsRec bits;
+ struct input_id id;
+
+ evdevStateRec state;
+
+ struct _evdevDevice *next;
+} evdevDeviceRec, *evdevDevicePtr;
+
+typedef struct _evdevDriver {
+ const char *name;
+ const char *phys;
+ const char *device;
+
+ evdevBitsRec all_bits;
+ evdevBitsRec not_bits;
+ evdevBitsRec any_bits;
+
+ struct input_id id;
+
+ int pass;
+
+ InputDriverPtr drv;
+ IDevPtr dev;
+ Bool (*callback)(struct _evdevDriver *driver, evdevDevicePtr device);
+ evdevDevicePtr devices;
+ Bool configured;
+
+ struct _evdevDriver *next;
+} evdevDriverRec, *evdevDriverPtr;
+
+int evdevGetFDForDevice (evdevDevicePtr driver);
+Bool evdevStart (InputDriverPtr drv);
+Bool evdevNewDriver (evdevDriverPtr driver);
+Bool evdevGetBits (int fd, evdevBitsPtr bits);
+
+int EvdevBtnInit (DeviceIntPtr device);
+int EvdevBtnOn (DeviceIntPtr device);
+int EvdevBtnOff (DeviceIntPtr device);
+int EvdevBtnNew0(InputInfoPtr pInfo);
+int EvdevBtnNew1(InputInfoPtr pInfo);
+void EvdevBtnProcess (InputInfoPtr pInfo, struct input_event *ev);
+void EvdevBtnPostFakeClicks(InputInfoPtr pInfo, int button, int count);
+int EvdevBtnFind (InputInfoPtr pInfo, const char *button);
+int EvdevBtnExists (InputInfoPtr pInfo, int button);
+
+int EvdevAxesInit (DeviceIntPtr device);
+int EvdevAxesOn (DeviceIntPtr device);
+int EvdevAxesOff (DeviceIntPtr device);
+int EvdevAxesNew0(InputInfoPtr pInfo);
+int EvdevAxesNew1(InputInfoPtr pInfo);
+void EvdevAxesAbsProcess (InputInfoPtr pInfo, struct input_event *ev);
+void EvdevAxesRelProcess (InputInfoPtr pInfo, struct input_event *ev);
+void EvdevAxesSyn (InputInfoPtr pInfo);
+
+int EvdevKeyInit (DeviceIntPtr device);
+int EvdevKeyNew (InputInfoPtr pInfo);
+int EvdevKeyOn (DeviceIntPtr device);
+int EvdevKeyOff (DeviceIntPtr device);
+void EvdevKeyProcess (InputInfoPtr pInfo, struct input_event *ev);
+
+#endif /* LNX_EVDEV_H_ */
diff --git a/src/xorg/evdevxorg_axes.c b/src/xorg/evdevxorg_axes.c
new file mode 100644
index 0000000..f4e9a3b
--- /dev/null
+++ b/src/xorg/evdevxorg_axes.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp at aehallh.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/extensions/XIproto.h>
+
+#include <string.h>
+
+#include "evdevxorg.h"
+
+#include <xf86.h>
+
+#include <xf86Module.h>
+#include <mipointer.h>
+
+
+#include <xf86_OSproc.h>
+
+static char *rel_axis_names[] = {
+ "X",
+ "Y",
+ "Z",
+ "RX",
+ "RY",
+ "RZ",
+ "HWHEEL",
+ "DIAL",
+ "WHEEL",
+ "MISC",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ NULL
+};
+
+static char *abs_axis_names[] = {
+ "X",
+ "Y",
+ "Z",
+ "RX",
+ "RY",
+ "RZ",
+ "THROTTLE",
+ "RUDDER",
+ "WHEEL",
+ "GAS",
+ "BRAKE",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "HAT0X",
+ "HAT0Y",
+ "HAT1X",
+ "HAT1Y",
+ "HAT2X",
+ "HAT2Y",
+ "HAT3X",
+ "HAT3Y",
+ "PRESSURE",
+ "TILT_X",
+ "TILT_Y",
+ "TOOL_WIDTH",
+ "VOLUME",
+ "29",
+ "30",
+ "31",
+ "32",
+ "33",
+ "34",
+ "35",
+ "36",
+ "37",
+ "38",
+ "39",
+ "MISC",
+ "41",
+ "42",
+ "43",
+ "44",
+ "45",
+ "46",
+ "47",
+ "48",
+ "49",
+ "50",
+ "51",
+ "52",
+ "53",
+ "54",
+ "55",
+ "56",
+ "57",
+ "58",
+ "59",
+ "60",
+ "61",
+ "62",
+ NULL
+};
+
+static void EvdevAxesTouchCallback (InputInfoPtr pInfo, int button, int value);
+
+static Bool
+EvdevConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
+ int v3, int v4, int v5, int *x, int *y)
+{
+ if (first == 0) {
+ *x = v0;
+ *y = v1;
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+static void
+EvdevAxesRealSyn (InputInfoPtr pInfo, int absolute, int skip_xy)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ evdevAxesPtr axes = state->axes;
+ int i;
+
+ /*
+ if (skip_xy && (axes->v[0] || axes->v[1]))
+ xf86Msg(X_INFO, "%s: skip_xy: %d, x: %d, y: %d.\n", pInfo->name, skip_xy, axes->v[0], axes->v[1]);
+ */
+
+ /* FIXME: This is a truly evil kluge. */
+ if (skip_xy == 1 && state->axes->axes >= 2)
+ xf86PostMotionEvent(pInfo->dev, absolute, 2,
+ state->axes->axes - 2,
+ axes->v[0x02], axes->v[0x03],
+ axes->v[0x04], axes->v[0x05], axes->v[0x06], axes->v[0x07],
+ axes->v[0x08], axes->v[0x09], axes->v[0x0a], axes->v[0x0b],
+ axes->v[0x0c], axes->v[0x0d], axes->v[0x0e], axes->v[0x0f],
+ axes->v[0x10], axes->v[0x11], axes->v[0x12], axes->v[0x13],
+ axes->v[0x14], axes->v[0x15], axes->v[0x16], axes->v[0x17],
+ axes->v[0x18], axes->v[0x19], axes->v[0x1a], axes->v[0x1b],
+ axes->v[0x1c], axes->v[0x1d], axes->v[0x1e], axes->v[0x1f],
+ axes->v[0x20], axes->v[0x21], axes->v[0x22], axes->v[0x23],
+ axes->v[0x24], axes->v[0x25], axes->v[0x26], axes->v[0x27],
+ axes->v[0x28], axes->v[0x29], axes->v[0x2a], axes->v[0x2b],
+ axes->v[0x2c], axes->v[0x2d], axes->v[0x2e], axes->v[0x2f],
+ axes->v[0x30], axes->v[0x31], axes->v[0x32], axes->v[0x33],
+ axes->v[0x34], axes->v[0x35], axes->v[0x36], axes->v[0x37],
+ axes->v[0x38], axes->v[0x39], axes->v[0x3a], axes->v[0x3b],
+ axes->v[0x3c], axes->v[0x3d], axes->v[0x3e], axes->v[0x3f]);
+ else
+ xf86PostMotionEvent(pInfo->dev, absolute, 0,
+ state->axes->axes,
+ axes->v[0x00], axes->v[0x01], axes->v[0x02], axes->v[0x03],
+ axes->v[0x04], axes->v[0x05], axes->v[0x06], axes->v[0x07],
+ axes->v[0x08], axes->v[0x09], axes->v[0x0a], axes->v[0x0b],
+ axes->v[0x0c], axes->v[0x0d], axes->v[0x0e], axes->v[0x0f],
+ axes->v[0x10], axes->v[0x11], axes->v[0x12], axes->v[0x13],
+ axes->v[0x14], axes->v[0x15], axes->v[0x16], axes->v[0x17],
+ axes->v[0x18], axes->v[0x19], axes->v[0x1a], axes->v[0x1b],
+ axes->v[0x1c], axes->v[0x1d], axes->v[0x1e], axes->v[0x1f],
+ axes->v[0x20], axes->v[0x21], axes->v[0x22], axes->v[0x23],
+ axes->v[0x24], axes->v[0x25], axes->v[0x26], axes->v[0x27],
+ axes->v[0x28], axes->v[0x29], axes->v[0x2a], axes->v[0x2b],
+ axes->v[0x2c], axes->v[0x2d], axes->v[0x2e], axes->v[0x2f],
+ axes->v[0x30], axes->v[0x31], axes->v[0x32], axes->v[0x33],
+ axes->v[0x34], axes->v[0x35], axes->v[0x36], axes->v[0x37],
+ axes->v[0x38], axes->v[0x39], axes->v[0x3a], axes->v[0x3b],
+ axes->v[0x3c], axes->v[0x3d], axes->v[0x3e], axes->v[0x3f]);
+
+ if (!skip_xy)
+ for (i = 0; i < ABS_MAX; i++)
+ state->axes->v[i] = 0;
+ else if (skip_xy == 1)
+ for (i = 2; i < ABS_MAX; i++)
+ state->axes->v[i] = 0;
+ else if (skip_xy == 2)
+ for (i = 0; i < 2; i++)
+ state->axes->v[i] = 0;
+}
+
+static void
+EvdevAxesAbsSyn (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int i = 0;
+ Bool skip_xy = 0;
+
+ if (!state->axes || !state->abs || !state->abs->count)
+ return;
+
+ if (state->mode == Relative && state->abs->axes >= 2) {
+ if (!state->abs->use_touch || state->abs->touch) {
+ if (state->abs->reset) {
+ for (i = 0; i < 2; i++)
+ state->axes->v[i] = 0;
+ xf86Msg(X_INFO, "%s: Resetting.\n", pInfo->name);
+ state->abs->reset = 0;
+ } else {
+ state->axes->v[0] = state->abs->v[0] - state->abs->old_x;
+ state->axes->v[1] = state->abs->v[1] - state->abs->old_y;
+ }
+ state->abs->old_x = state->abs->v[0];
+ state->abs->old_y = state->abs->v[1];
+ EvdevAxesRealSyn (pInfo, 0, 2);
+ }
+ skip_xy = 1;
+ } else if (state->mode == Absolute && state->abs->screen != -1 && state->abs->axes >= 2) {
+ int conv_x, conv_y;
+
+ for (i = 0; i < 2; i++)
+ state->axes->v[i] = xf86ScaleAxis (state->abs->v[i],
+ 0, state->abs->scale[i],
+ state->abs->min[i], state->abs->max[i]);
+
+
+ EvdevConvert (pInfo, 0, 2, state->abs->v[0], state->abs->v[1],
+ 0, 0, 0, 0, &conv_x, &conv_y);
+ xf86XInputSetScreen (pInfo, state->abs->screen, conv_x, conv_y);
+ }
+
+ for (; i < ABS_MAX; i++)
+ state->axes->v[i] = state->abs->v[i];
+
+ EvdevAxesRealSyn (pInfo, 1, skip_xy);
+ state->abs->count = 0;
+}
+
+static void
+EvdevAxesRelSyn (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ evdevRelPtr rel = state->rel;
+ int i, btn;
+
+ if (!state->axes || !state->rel || !state->rel->count)
+ return;
+
+ for (i = 0; i < REL_MAX; i++) {
+ if (rel->btnMap[i][0] || rel->btnMap[i][1]) {
+ if ((rel->v[i] > 0) && (btn = rel->btnMap[i][0]))
+ EvdevBtnPostFakeClicks (pInfo, btn, rel->v[i]);
+ else if ((rel->v[i] < 0) && (btn = rel->btnMap[i][1]))
+ EvdevBtnPostFakeClicks (pInfo, btn, -rel->v[i]);
+ }
+
+ state->axes->v[i] = rel->v[i];
+ rel->v[i] = 0;
+ }
+
+ EvdevAxesRealSyn (pInfo, 0, 0);
+ rel->count = 0;
+}
+
+void
+EvdevAxesSyn (InputInfoPtr pInfo)
+{
+ EvdevAxesAbsSyn (pInfo);
+ EvdevAxesRelSyn (pInfo);
+}
+
+void
+EvdevAxesAbsProcess (InputInfoPtr pInfo, struct input_event *ev)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int map;
+
+ if (ev->code >= ABS_MAX)
+ return;
+
+ /* FIXME: Handle inverted axes properly. */
+ map = state->abs->map[ev->code];
+ if (map >= 0)
+ state->abs->v[map] = ev->value;
+ else
+ state->abs->v[-map] = ev->value;
+
+ state->abs->count++;
+
+ if (!state->sync)
+ EvdevAxesAbsSyn (pInfo);
+}
+
+void
+EvdevAxesRelProcess (InputInfoPtr pInfo, struct input_event *ev)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int map;
+
+ if (ev->code >= REL_MAX)
+ return;
+
+ map = state->rel->map[ev->code];
+ if (map >= 0)
+ state->rel->v[map] += ev->value;
+ else
+ state->rel->v[-map] -= ev->value;
+
+ state->rel->count++;
+
+ if (!state->sync)
+ EvdevAxesRelSyn (pInfo);
+}
+
+int
+EvdevAxesOn (DeviceIntPtr device)
+{
+ return Success;
+}
+
+int
+EvdevAxesOff (DeviceIntPtr device)
+{
+ return Success;
+}
+
+static int
+EvdevAxisAbsNew0(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ struct input_absinfo absinfo;
+ char option[64];
+ int i, j, k = 0, real_axes;
+
+ real_axes = 0;
+ for (i = 0; i < ABS_MAX; i++)
+ if (test_bit (i, pEvdev->bits.abs))
+ real_axes++;
+
+ if (!real_axes)
+ return !Success;
+
+ state->abs = Xcalloc (sizeof (evdevAbsRec));
+
+ xf86Msg(X_INFO, "%s: Found %d absolute axes.\n", pInfo->name, real_axes);
+ xf86Msg(X_INFO, "%s: Configuring as pointer.\n", pInfo->name);
+ pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
+ XI86_CONFIGURED;
+ pInfo->type_name = XI_MOUSE;
+ pInfo->conversion_proc = EvdevConvert;
+
+ for (i = 0, j = 0; i < ABS_MAX; i++) {
+ if (!test_bit (i, pEvdev->bits.abs))
+ continue;
+
+ snprintf(option, sizeof(option), "%sAbsoluteAxisMap", abs_axis_names[i]);
+ k = xf86SetIntOption(pInfo->options, option, -1);
+ if (k != -1)
+ state->abs->map[i] = k;
+ else
+ state->abs->map[i] = j;
+
+ if (k != -1)
+ xf86Msg(X_CONFIG, "%s: %s: %d.\n", pInfo->name, option, k);
+
+ if (ioctl (pInfo->fd, EVIOCGABS(i), &absinfo) < 0) {
+ xf86Msg(X_ERROR, "ioctl EVIOCGABS failed: %s\n", strerror(errno));
+ return !Success;
+ }
+ state->abs->min[state->abs->map[i]] = absinfo.minimum;
+ state->abs->max[state->abs->map[i]] = absinfo.maximum;
+
+ j++;
+ }
+
+ state->abs->axes = real_axes;
+ for (i = 0; i < ABS_MAX; i++) {
+ if (state->abs->map[i] > state->abs->axes)
+ state->abs->axes = state->abs->map[i];
+ }
+
+ return Success;
+}
+
+static int
+EvdevAxisAbsNew1(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ char *s;
+ int k = 0;
+
+ if (!state->abs)
+ return !Success;
+
+ xf86Msg(X_CONFIG, "%s: Configuring %d absolute axes.\n", pInfo->name,
+ state->abs->axes);
+
+ {
+ int btn;
+
+ s = xf86SetStrOption(pInfo->options, "AbsoluteTouch", "DIGI_Touch");
+ btn = EvdevBtnFind (pInfo, s);
+ if (btn != -1) {
+ if (EvdevBtnExists (pInfo, btn)) {
+ state->abs->use_touch = 1;
+ xf86Msg(X_ERROR, "%s: Button: %d.\n", pInfo->name, btn);
+ xf86Msg(X_ERROR, "%s: state->btn: %p.\n", pInfo->name, state->btn);
+ state->btn->callback[btn] = &EvdevAxesTouchCallback;
+ } else {
+ xf86Msg(X_ERROR, "%s: AbsoluteTouch: '%s' does not exist.\n", pInfo->name, s);
+ }
+ } else {
+ xf86Msg(X_ERROR, "%s: AbsoluteTouch: '%s' is not a valid button name.\n", pInfo->name, s);
+ }
+ }
+
+ s = xf86SetStrOption(pInfo->options, "Mode", "Absolute");
+ if (!strcasecmp(s, "Absolute")) {
+ state->mode = Absolute;
+ xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
+ } else if (!strcasecmp(s, "Relative")) {
+ state->mode = Relative;
+ xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
+ } else {
+ state->mode = Absolute;
+ xf86Msg(X_CONFIG, "%s: Unknown Mode: %s.\n", pInfo->name, s);
+ }
+
+ if (test_bit (ABS_X, pEvdev->bits.abs) && test_bit (ABS_Y, pEvdev->bits.abs))
+ k = xf86SetIntOption(pInfo->options, "AbsoluteScreen", 0);
+ else
+ k = xf86SetIntOption(pInfo->options, "AbsoluteScreen", -1);
+ if (k < screenInfo.numScreens && k >= 0) {
+ state->abs->screen = k;
+ xf86Msg(X_CONFIG, "%s: AbsoluteScreen: %d.\n", pInfo->name, k);
+
+ state->abs->scale[0] = screenInfo.screens[state->abs->screen]->width;
+ state->abs->scale[1] = screenInfo.screens[state->abs->screen]->height;
+ } else {
+ if (k != -1)
+ xf86Msg(X_CONFIG, "%s: AbsoluteScreen: %d is not a valid screen.\n", pInfo->name, k);
+ state->abs->screen = -1;
+ }
+
+ return Success;
+}
+
+static int
+EvdevAxisRelNew0(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ char *s, option[64];
+ int i, j, k = 0, real_axes;
+
+ real_axes = 0;
+ for (i = 0; i < REL_MAX; i++)
+ if (test_bit (i, pEvdev->bits.rel))
+ real_axes++;
+
+ if (!real_axes && (!state->abs || state->abs->axes < 2))
+ return !Success;
+
+ state->rel = Xcalloc (sizeof (evdevRelRec));
+
+ xf86Msg(X_INFO, "%s: Found %d relative axes.\n", pInfo->name,
+ real_axes);
+ xf86Msg(X_INFO, "%s: Configuring as pointer.\n", pInfo->name);
+ pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
+ XI86_CONFIGURED;
+ pInfo->type_name = XI_MOUSE;
+ pInfo->conversion_proc = EvdevConvert;
+
+ for (i = 0, j = 0; i < REL_MAX; i++) {
+ if (!test_bit (i, pEvdev->bits.rel))
+ continue;
+
+ snprintf(option, sizeof(option), "%sRelativeAxisMap", rel_axis_names[i]);
+ s = xf86SetStrOption(pInfo->options, option, "0");
+ if (s && (k = strtol(s, NULL, 0)))
+ state->rel->map[i] = k;
+ else
+ state->rel->map[i] = j;
+
+ if (s && k)
+ xf86Msg(X_CONFIG, "%s: %s: %d.\n", pInfo->name, option, k);
+
+
+ snprintf(option, sizeof(option), "%sRelativeAxisButtons", rel_axis_names[i]);
+ if (i == REL_WHEEL || i == REL_Z)
+ s = xf86SetStrOption(pInfo->options, option, "4 5");
+ else if (i == REL_HWHEEL)
+ s = xf86SetStrOption(pInfo->options, option, "6 7");
+ else
+ s = xf86SetStrOption(pInfo->options, option, "0 0");
+
+ k = state->rel->map[i];
+
+ if (!s || (sscanf(s, "%d %d", &state->rel->btnMap[k][0],
+ &state->rel->btnMap[k][1]) != 2))
+ state->rel->btnMap[k][0] = state->rel->btnMap[k][1] = 0;
+
+ if (state->rel->btnMap[k][0] || state->rel->btnMap[k][1])
+ xf86Msg(X_CONFIG, "%s: %s: %d %d.\n", pInfo->name, option,
+ state->rel->btnMap[k][0], state->rel->btnMap[k][1]);
+
+ j++;
+ }
+
+ state->rel->axes = real_axes;
+ for (i = 0; i < REL_MAX; i++)
+ if (state->rel->map[i] > state->rel->axes)
+ state->rel->axes = state->rel->map[i];
+
+ if (state->abs && (state->abs->axes >= 2) && (state->rel->axes < 2))
+ state->rel->axes += 2;
+
+ return Success;
+}
+
+static int
+EvdevAxisRelNew1(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+
+ if (!state->rel)
+ return !Success;
+
+ xf86Msg(X_CONFIG, "%s: Configuring %d relative axes.\n", pInfo->name,
+ state->rel->axes);
+
+ return Success;
+}
+
+int
+EvdevAxesNew0 (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int ret = Success;
+
+ state->axes = Xcalloc (sizeof (evdevAxesRec));
+ if (EvdevAxisAbsNew0(pInfo) != Success)
+ ret = !Success;
+ if (EvdevAxisRelNew0(pInfo) != Success)
+ ret = !Success;
+ if (!state->abs && !state->rel) {
+ Xfree (state->axes);
+ state->axes = NULL;
+ }
+
+ return ret;
+}
+
+int
+EvdevAxesNew1 (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int ret = Success;
+
+ state->axes = Xcalloc (sizeof (evdevAxesRec));
+ if (EvdevAxisAbsNew1(pInfo) != Success)
+ ret = !Success;
+ if (EvdevAxisRelNew1(pInfo) != Success)
+ ret = !Success;
+ if (!state->abs && !state->rel) {
+ Xfree (state->axes);
+ state->axes = NULL;
+ }
+
+ return ret;
+}
+
+
+static void
+EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+ /* Nothing to do, dix handles all settings */
+}
+
+int
+EvdevAxesInit (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int i, axes = 0;
+
+ if (state->abs && state->abs->axes > axes)
+ axes = state->abs->axes;
+ if (state->rel && state->rel->axes > axes)
+ axes = state->rel->axes;
+
+ state->axes->axes = axes;
+
+ xf86Msg(X_CONFIG, "%s: %d valuators.\n", pInfo->name,
+ axes);
+ if (!axes)
+ return Success;
+
+ if (!InitValuatorClassDeviceStruct(device, axes,
+ miPointerGetMotionEvents,
+ miPointerGetMotionBufferSize(), 0))
+ return !Success;
+
+ for (i = 0; i < axes; i++) {
+ xf86InitValuatorAxisStruct(device, i, 0, 0, 0, 0, 1);
+ xf86InitValuatorDefaults(device, i);
+ }
+
+ if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
+ return !Success;
+
+ xf86MotionHistoryAllocate (pInfo);
+
+ return Success;
+}
+
+static void
+EvdevAxesTouchCallback (InputInfoPtr pInfo, int button, int value)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+
+ xf86Msg(X_INFO, "%s: Touch callback; %d.\n", pInfo->name, value);
+ if (state->abs->use_touch) {
+ state->abs->touch = !!value;
+ if (value)
+ state->abs->reset = 1;
+ }
+}
diff --git a/src/xorg/evdevxorg_brain.c b/src/xorg/evdevxorg_brain.c
new file mode 100644
index 0000000..8c4497e
--- /dev/null
+++ b/src/xorg/evdevxorg_brain.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp at aehallh.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "evdevxorg.h"
+
+#include "xf86_OSlib.h"
+
+#include <xf86.h>
+#include <fnmatch.h>
+#include <sys/poll.h>
+
+#include "inotify.h"
+#include "inotify-syscalls.h"
+
+#ifndef SYSCALL
+#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
+#endif
+
+static Bool evdev_alive = FALSE;
+static InputInfoPtr evdev_pInfo = NULL;
+static evdevDriverPtr evdev_drivers = NULL;
+static int evdev_seq;
+static int evdev_inotify;
+
+int
+evdevGetFDForDevice (evdevDevicePtr device)
+{
+ int fd;
+
+ if (!device)
+ return -1;
+
+
+ if (device->device) {
+ SYSCALL(fd = open (device->device, O_RDWR | O_NONBLOCK));
+ if (fd == -1)
+ xf86Msg(X_ERROR, "%s (%d): Open failed: %s\n", __FILE__, __LINE__, strerror(errno));
+ return fd;
+ } else
+ return -1;
+}
+
+#define device_add(driver,device) do { \
+ device->next = driver->devices; \
+ driver->devices = device; \
+} while (0)
+
+typedef struct {
+ evdevBitsRec bits;
+ char name[256];
+ char phys[256];
+ char dev[256];
+ struct input_id id;
+} evdevDevInfoRec, *evdevDevInfoPtr;
+
+static Bool
+MatchAll (unsigned long *dev, unsigned 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 (unsigned long *dev, unsigned long *match, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if ((dev[i] & match[i]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool
+MatchAny (unsigned long *dev, unsigned 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 && fnmatch(driver->name, info->name, 0))
+ return FALSE;
+ if (driver->phys && fnmatch(driver->phys, info->phys, 0))
+ return FALSE;
+ if (driver->device && fnmatch(driver->device, info->dev, 0))
+ 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));
+ close (fd);
+
+ return TRUE;
+}
+
+static void
+evdevRescanDevices (InputInfoPtr pInfo)
+{
+ char dev[20];
+ int i, j, found;
+ evdevDriverPtr driver;
+ evdevDevicePtr device;
+ 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);
+
+ if (!FillDevInfo (dev, &info))
+ continue;
+
+ found = 0;
+
+ 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;
+ }
+ }
+ }
+
+ for (driver = evdev_drivers; driver; driver = driver->next)
+ for (device = driver->devices; device; device = device->next)
+ if (device->seen == (evdev_seq - 1)) {
+ device->callback(device->pInfo->dev, DEVICE_OFF);
+
+ if (device->device)
+ xfree(device->device);
+ device->device = NULL;
+
+ if (device->phys)
+ xfree(device->phys);
+ device->phys = NULL;
+ }
+}
+
+static void
+evdevReadInput (InputInfoPtr pInfo)
+{
+ int scan = 0, i, len;
+ char buf[4096];
+ struct inotify_event *event;
+
+ if (evdev_inotify) {
+ while ((len = read (pInfo->fd, buf, sizeof(buf))) >= 0) {
+ for (i = 0; i < len; i += sizeof (struct inotify_event) + event->len) {
+ event = (struct inotify_event *) &buf[i];
+ if (!event->len)
+ continue;
+ if (event->mask & IN_ISDIR)
+ continue;
+ if (strncmp("event", event->name, 5))
+ continue;
+ scan = 1;
+ }
+ }
+
+ if (scan)
+ evdevRescanDevices (pInfo);
+ } else {
+ /*
+ * XXX: Freezing the server for a moment is not really friendly.
+ * But we need to wait until udev has actually created the device.
+ */
+ usleep (500000);
+ evdevRescanDevices (pInfo);
+ }
+}
+
+static int
+evdevControl(DeviceIntPtr pPointer, int what)
+{
+ InputInfoPtr pInfo;
+ int i, flags;
+
+ pInfo = pPointer->public.devicePrivate;
+
+ switch (what) {
+ case DEVICE_INIT:
+ pPointer->public.on = FALSE;
+ break;
+
+ case DEVICE_ON:
+ /*
+ * XXX: We do /proc/bus/usb/devices instead of /proc/bus/input/devices
+ * because the only hotplug input devices at the moment are USB...
+ * And because the latter is useless to poll/select against.
+ * FIXME: Get a patch in the kernel which fixes the latter.
+ */
+ evdev_inotify = 1;
+ SYSCALL(pInfo->fd = inotify_init());
+ if (pInfo->fd < 0) {
+ xf86Msg(X_ERROR, "%s: Unable to initialize inotify, using fallback. (errno: %d)\n", pInfo->name, errno);
+ evdev_inotify = 0;
+ }
+ SYSCALL (i = inotify_add_watch (pInfo->fd, "/dev/input/", IN_CREATE | IN_DELETE));
+ if (i < 0) {
+ xf86Msg(X_ERROR, "%s: Unable to initialize inotify, using fallback. (errno: %d)\n", pInfo->name, errno);
+ evdev_inotify = 0;
+ SYSCALL (close (pInfo->fd));
+ pInfo->fd = -1;
+ }
+ if ((flags = fcntl(pInfo->fd, F_GETFL)) < 0) {
+ xf86Msg(X_ERROR, "%s: Unable to NONBLOCK inotify, using fallback. "
+ "(errno: %d)\n", pInfo->name, errno);
+ evdev_inotify = 0;
+ SYSCALL (close (pInfo->fd));
+ pInfo->fd = -1;
+ } else if (fcntl(pInfo->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
+ xf86Msg(X_ERROR, "%s: Unable to NONBLOCK inotify, using fallback. "
+ "(errno: %d)\n", pInfo->name, errno);
+ evdev_inotify = 0;
+ SYSCALL (close (pInfo->fd));
+ pInfo->fd = -1;
+ }
+
+ if (!evdev_inotify) {
+ SYSCALL (pInfo->fd = open ("/proc/bus/usb/devices", O_RDONLY));
+ if (pInfo->fd < 0) {
+ xf86Msg(X_ERROR, "%s: cannot open /proc/bus/usb/devices.\n", pInfo->name);
+ return BadRequest;
+ }
+ }
+ xf86FlushInput(pInfo->fd);
+ AddEnabledDevice(pInfo->fd);
+ pPointer->public.on = TRUE;
+ evdevRescanDevices (pInfo);
+ break;
+
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ if (pInfo->fd != -1) {
+ RemoveEnabledDevice(pInfo->fd);
+ SYSCALL (close (pInfo->fd));
+ pInfo->fd = -1;
+ }
+ pPointer->public.on = FALSE;
+ break;
+ }
+ return Success;
+}
+
+Bool
+evdevStart (InputDriverPtr drv)
+{
+ InputInfoRec *pInfo;
+
+ if (evdev_alive)
+ return TRUE;
+
+ if (!(pInfo = xf86AllocateInput(drv, 0)))
+ return FALSE;
+
+ evdev_alive = TRUE;
+
+ pInfo->name = "evdev brain";
+ pInfo->type_name = "evdev brain";
+ pInfo->device_control = evdevControl;
+ pInfo->read_input = evdevReadInput;
+ pInfo->fd = -1;
+ pInfo->flags = XI86_CONFIGURED | XI86_OPEN_ON_INIT;
+
+ evdev_pInfo = pInfo;
+ return TRUE;
+}
+
+Bool
+evdevNewDriver (evdevDriverPtr driver)
+{
+ if (!evdev_alive)
+ return FALSE;
+ /* FIXME: Make this check valid given all the ways to look. */
+#if 0
+ if (!(driver->name || driver->phys || driver->device))
+ return FALSE;
+#endif
+ if (!driver->callback)
+ return FALSE;
+
+ driver->next = evdev_drivers;
+ evdev_drivers = driver;
+
+ evdevRescanDevices (evdev_pInfo);
+ 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;
+}
+
diff --git a/src/xorg/evdevxorg_btn.c b/src/xorg/evdevxorg_btn.c
new file mode 100644
index 0000000..f3a09d5
--- /dev/null
+++ b/src/xorg/evdevxorg_btn.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp at aehallh.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "evdevxorg.h"
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/extensions/XIproto.h>
+
+#include <linux/input.h>
+
+#include <misc.h>
+#include <xf86.h>
+#include <xf86str.h>
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <mipointer.h>
+
+#include <xf86Module.h>
+
+static char *button_names[] = {
+ "MISC_0",
+ "MISC_1",
+ "MISC_2",
+ "MISC_3",
+ "MISC_4",
+ "MISC_5",
+ "MISC_6",
+ "MISC_7",
+ "MISC_8",
+ "MISC_9",
+ "MISC_10",
+ "MISC_11",
+ "MISC_12",
+ "MISC_13",
+ "MISC_14",
+ "MISC_15",
+ "MOUSE_LEFT",
+ "MOUSE_RIGHT",
+ "MOUSE_MIDDLE",
+ "MOUSE_SIDE",
+ "MOUSE_EXTRA",
+ "MOUSE_FORWARD",
+ "MOUSE_BACK",
+ "MOUSE_TASK",
+ "MOUSE_8",
+ "MOUSE_9",
+ "MOUSE_10",
+ "MOUSE_12",
+ "MOUSE_13",
+ "MOUSE_14",
+ "MOUSE_15",
+ "JOY_TRIGGER",
+ "JOY_THUMB",
+ "JOY_THUMB2",
+ "JOY_TOP",
+ "JOY_TOP2",
+ "JOY_PINKIE",
+ "JOY_BASE",
+ "JOY_BASE2",
+ "JOY_BASE3",
+ "JOY_BASE4",
+ "JOY_BASE5",
+ "JOY_BASE6",
+ "JOY_12",
+ "JOY_13",
+ "JOY_14",
+ "JOY_DEAD",
+ "GAME_A",
+ "GAME_B",
+ "GAME_C",
+ "GAME_X",
+ "GAME_Y",
+ "GAME_Z",
+ "GAME_TL",
+ "GAME_TR",
+ "GAME_TL2",
+ "GAME_TR2",
+ "GAME_SELECT",
+ "GAME_START",
+ "GAME_MODE",
+ "GAME_THUMBL",
+ "GAME_THUMBR",
+ "GAME_15",
+ "DIGI_TOOL_PEN",
+ "DIGI_TOOL_RUBBER",
+ "DIGI_TOOL_BRUSH",
+ "DIGI_TOOL_PENCIL",
+ "DIGI_TOOL_AIRBRUSH",
+ "DIGI_TOOL_FINGER",
+ "DIGI_TOOL_MOUSE",
+ "DIGI_TOOL_LENS",
+ "DIGI_8",
+ "DIGI_9",
+ "DIGI_TOUCH",
+ "DIGI_STYLUS",
+ "DIGI_STYLUS2",
+ "DIGI_TOOL_DOUBLETAP",
+ "DIGI_TOOL_TRIPLETAP",
+ "DIGI_15",
+ "WHEEL_GEAR_UP",
+ "WHEEL_GEAR_DOWN",
+ NULL
+};
+
+void
+EvdevBtnPostFakeClicks(InputInfoPtr pInfo, int button, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+ xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0);
+ }
+}
+
+int
+EvdevBtnInit (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ CARD8 *map;
+ int i;
+
+ if (!pEvdev->state.btn)
+ return Success;
+
+ map = Xcalloc (sizeof (CARD8) * (pEvdev->state.btn->buttons + 1));
+
+ for (i = 0; i <= pEvdev->state.btn->buttons; i++)
+ map[i] = i;
+
+ xf86Msg(X_CONFIG, "%s (%d): Registering %d buttons.\n", __FILE__, __LINE__,
+ pEvdev->state.btn->buttons);
+ if (!InitButtonClassDeviceStruct (device, pEvdev->state.btn->buttons, map)) {
+ pEvdev->state.btn->buttons = 0;
+
+ return !Success;
+ }
+
+ Xfree (map);
+
+ return Success;
+}
+
+int
+EvdevBtnOn (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ int i, blocked;
+
+ if (!pEvdev->state.btn)
+ return Success;
+
+ blocked = xf86BlockSIGIO ();
+ for (i = 1; i <= pEvdev->state.btn->buttons; i++)
+ xf86PostButtonEvent (device, 0, i, 0, 0, 0);
+ xf86UnblockSIGIO (blocked);
+
+ return Success;
+}
+
+int
+EvdevBtnOff (DeviceIntPtr device)
+{
+ return Success;
+}
+
+/*
+ * Warning, evil lives here.
+ */
+static void
+EvdevBtnCalcRemap (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int i, j, base, clear, fake;
+
+ for (i = 0, base = 1, fake = 0; i < pEvdev->state.btn->real_buttons; i++) {
+ if (state->rel) {
+ do {
+ clear = 1;
+ for (j = 0; j < REL_MAX; j++) {
+ if (state->rel->btnMap[j][0] == (i + base)) {
+ base++;
+ clear = 0;
+ break;
+ }
+ if (state->rel->btnMap[j][1] == (i + base)) {
+ base++;
+ clear = 0;
+ break;
+ }
+ }
+ } while (!clear);
+ }
+
+ if (!fake && base != 1)
+ fake = i;
+
+ state->btn->buttons = state->btn->map[i] = i + base;
+ }
+
+ if (state->btn->real_buttons >= 3 && (!fake || fake >= 3)) {
+ base = state->btn->map[1];
+ state->btn->map[1] = state->btn->map[2];
+ state->btn->map[2] = base;
+ }
+
+ if (state->rel) {
+ for (i = 0; i < REL_MAX; i++) {
+ if (state->rel->btnMap[i][0] > state->btn->buttons)
+ state->btn->buttons = state->rel->btnMap[i][0];
+ if (state->rel->btnMap[i][1] > state->btn->buttons)
+ state->btn->buttons = state->rel->btnMap[i][1];
+ }
+ }
+}
+
+
+int
+EvdevBtnNew0(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int i, bit;
+
+ state->btn = Xcalloc (sizeof (evdevBtnRec));
+
+ for (i = BTN_MISC; i < (KEY_OK - 1); i++)
+ if (test_bit (i, pEvdev->bits.key)) {
+ bit = i;
+ if ((bit >= BTN_MOUSE) && (bit < BTN_JOYSTICK)) {
+ bit -= BTN_MOUSE - BTN_MISC;
+ } else if ((bit >= BTN_MISC) && (bit < BTN_MOUSE)) {
+ bit += BTN_MOUSE - BTN_MISC;
+ }
+ bit -= BTN_MISC;
+ state->btn->real_buttons = bit + 1;
+ }
+
+ if (state->btn->real_buttons)
+ xf86Msg(X_INFO, "%s: Found %d mouse buttons\n", pInfo->name, state->btn->real_buttons);
+
+ return Success;
+}
+
+int
+EvdevBtnNew1(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+
+ if (!state->btn)
+ return !Success;
+
+ EvdevBtnCalcRemap (pInfo);
+
+ if (state->btn->buttons)
+ xf86Msg(X_INFO, "%s: Configured %d mouse buttons\n", pInfo->name, state->btn->buttons);
+ else {
+ Xfree (state->btn);
+ state->btn = NULL;
+ return !Success;
+ }
+
+ pInfo->flags |= XI86_SEND_DRAG_EVENTS | XI86_CONFIGURED;
+ /*
+ * FIXME: Mouse may not be accurate.
+ * Check buttons to see if we're actually a joystick or something.
+ */
+ pInfo->type_name = XI_MOUSE;
+
+ return Success;
+}
+
+void
+EvdevBtnProcess (InputInfoPtr pInfo, struct input_event *ev)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int button;
+
+ if (!state->btn)
+ return;
+
+ button = ev->code;
+
+ if ((ev->code >= BTN_MOUSE) && (ev->code < BTN_JOYSTICK)) {
+ button -= BTN_MOUSE - BTN_MISC;
+ } else if ((ev->code >= BTN_MISC) && (ev->code < BTN_MOUSE)) {
+ button += BTN_MOUSE - BTN_MISC;
+ }
+
+ button -= BTN_MISC;
+
+ if (state->btn->callback[button])
+ state->btn->callback[button](pInfo, button, ev->value);
+
+ button = state->btn->map[button];
+ xf86PostButtonEvent (pInfo->dev, 0, button, ev->value, 0, 0);
+}
+
+int
+EvdevBtnFind (InputInfoPtr pInfo, const char *button)
+{
+ int i;
+
+ for (i = 0; button_names[i]; i++)
+ if (!strcasecmp(button, button_names[i]))
+ return i + 1;
+
+ return -1;
+}
+
+int
+EvdevBtnExists (InputInfoPtr pInfo, int button)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+
+ button += BTN_MISC;
+
+ xf86Msg(X_INFO, "%s: Checking button %s (%d)\n", pInfo->name, button_names[button - BTN_MISC], button);
+
+ if ((button >= BTN_MOUSE) && (button < BTN_JOYSTICK)) {
+ button -= BTN_MOUSE - BTN_MISC;
+ } else if ((button >= BTN_MISC) && (button < BTN_MOUSE)) {
+ button += BTN_MOUSE - BTN_MISC;
+ }
+
+ xf86Msg(X_INFO, "%s: Checking bit %d\n", pInfo->name, button);
+ return test_bit(button, pEvdev->bits.key);
+}
diff --git a/src/xorg/evdevxorg_key.c b/src/xorg/evdevxorg_key.c
new file mode 100644
index 0000000..6dbb68b
--- /dev/null
+++ b/src/xorg/evdevxorg_key.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp at aehallh.com)
+ */
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Kristian Høgsberg (krh at redhat.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "evdevxorg.h"
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/extensions/XIproto.h>
+
+#include <linux/input.h>
+
+#include <misc.h>
+#include <xf86.h>
+#include <xf86str.h>
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <mipointer.h>
+
+#include <xf86Module.h>
+
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+#include <X11/extensions/XKBsrv.h>
+
+
+#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
+
+#define MIN_KEYCODE 8
+#define GLYPHS_PER_KEY 2
+#define AltMask Mod1Mask
+#define NumLockMask Mod2Mask
+#define AltLangMask Mod3Mask
+#define KanaMask Mod4Mask
+#define ScrollLockMask Mod5Mask
+
+#define CAPSFLAG 1
+#define NUMFLAG 2
+#define SCROLLFLAG 4
+#define MODEFLAG 8
+#define COMPOSEFLAG 16
+
+/* FIXME: this map works with evdev keyboards, but all the xkb maps
+ * probably don't. The easiest is to remap the event keycodes. */
+
+static KeySym map[] = {
+ /* 0x00 */ NoSymbol, NoSymbol,
+ /* 0x01 */ XK_Escape, NoSymbol,
+ /* 0x02 */ XK_1, XK_exclam,
+ /* 0x03 */ XK_2, XK_at,
+ /* 0x04 */ XK_3, XK_numbersign,
+ /* 0x05 */ XK_4, XK_dollar,
+ /* 0x06 */ XK_5, XK_percent,
+ /* 0x07 */ XK_6, XK_asciicircum,
+ /* 0x08 */ XK_7, XK_ampersand,
+ /* 0x09 */ XK_8, XK_asterisk,
+ /* 0x0a */ XK_9, XK_parenleft,
+ /* 0x0b */ XK_0, XK_parenright,
+ /* 0x0c */ XK_minus, XK_underscore,
+ /* 0x0d */ XK_equal, XK_plus,
+ /* 0x0e */ XK_BackSpace, NoSymbol,
+ /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,
+ /* 0x10 */ XK_Q, NoSymbol,
+ /* 0x11 */ XK_W, NoSymbol,
+ /* 0x12 */ XK_E, NoSymbol,
+ /* 0x13 */ XK_R, NoSymbol,
+ /* 0x14 */ XK_T, NoSymbol,
+ /* 0x15 */ XK_Y, NoSymbol,
+ /* 0x16 */ XK_U, NoSymbol,
+ /* 0x17 */ XK_I, NoSymbol,
+ /* 0x18 */ XK_O, NoSymbol,
+ /* 0x19 */ XK_P, NoSymbol,
+ /* 0x1a */ XK_bracketleft, XK_braceleft,
+ /* 0x1b */ XK_bracketright,XK_braceright,
+ /* 0x1c */ XK_Return, NoSymbol,
+ /* 0x1d */ XK_Control_L, NoSymbol,
+ /* 0x1e */ XK_A, NoSymbol,
+ /* 0x1f */ XK_S, NoSymbol,
+ /* 0x20 */ XK_D, NoSymbol,
+ /* 0x21 */ XK_F, NoSymbol,
+ /* 0x22 */ XK_G, NoSymbol,
+ /* 0x23 */ XK_H, NoSymbol,
+ /* 0x24 */ XK_J, NoSymbol,
+ /* 0x25 */ XK_K, NoSymbol,
+ /* 0x26 */ XK_L, NoSymbol,
+ /* 0x27 */ XK_semicolon, XK_colon,
+ /* 0x28 */ XK_quoteright, XK_quotedbl,
+ /* 0x29 */ XK_quoteleft, XK_asciitilde,
+ /* 0x2a */ XK_Shift_L, NoSymbol,
+ /* 0x2b */ XK_backslash, XK_bar,
+ /* 0x2c */ XK_Z, NoSymbol,
+ /* 0x2d */ XK_X, NoSymbol,
+ /* 0x2e */ XK_C, NoSymbol,
+ /* 0x2f */ XK_V, NoSymbol,
+ /* 0x30 */ XK_B, NoSymbol,
+ /* 0x31 */ XK_N, NoSymbol,
+ /* 0x32 */ XK_M, NoSymbol,
+ /* 0x33 */ XK_comma, XK_less,
+ /* 0x34 */ XK_period, XK_greater,
+ /* 0x35 */ XK_slash, XK_question,
+ /* 0x36 */ XK_Shift_R, NoSymbol,
+ /* 0x37 */ XK_KP_Multiply, NoSymbol,
+ /* 0x38 */ XK_Alt_L, XK_Meta_L,
+ /* 0x39 */ XK_space, NoSymbol,
+ /* 0x3a */ XK_Caps_Lock, NoSymbol,
+ /* 0x3b */ XK_F1, NoSymbol,
+ /* 0x3c */ XK_F2, NoSymbol,
+ /* 0x3d */ XK_F3, NoSymbol,
+ /* 0x3e */ XK_F4, NoSymbol,
+ /* 0x3f */ XK_F5, NoSymbol,
+ /* 0x40 */ XK_F6, NoSymbol,
+ /* 0x41 */ XK_F7, NoSymbol,
+ /* 0x42 */ XK_F8, NoSymbol,
+ /* 0x43 */ XK_F9, NoSymbol,
+ /* 0x44 */ XK_F10, NoSymbol,
+ /* 0x45 */ XK_Num_Lock, NoSymbol,
+ /* 0x46 */ XK_Scroll_Lock, NoSymbol,
+ /* These KP keys should have the KP_7 keysyms in the numlock
+ * modifer... ? */
+ /* 0x47 */ XK_KP_Home, XK_KP_7,
+ /* 0x48 */ XK_KP_Up, XK_KP_8,
+ /* 0x49 */ XK_KP_Prior, XK_KP_9,
+ /* 0x4a */ XK_KP_Subtract, NoSymbol,
+ /* 0x4b */ XK_KP_Left, XK_KP_4,
+ /* 0x4c */ XK_KP_Begin, XK_KP_5,
+ /* 0x4d */ XK_KP_Right, XK_KP_6,
+ /* 0x4e */ XK_KP_Add, NoSymbol,
+ /* 0x4f */ XK_KP_End, XK_KP_1,
+ /* 0x50 */ XK_KP_Down, XK_KP_2,
+ /* 0x51 */ XK_KP_Next, XK_KP_3,
+ /* 0x52 */ XK_KP_Insert, XK_KP_0,
+ /* 0x53 */ XK_KP_Delete, XK_KP_Decimal,
+ /* 0x54 */ NoSymbol, NoSymbol,
+ /* 0x55 */ XK_F13, NoSymbol,
+ /* 0x56 */ XK_less, XK_greater,
+ /* 0x57 */ XK_F11, NoSymbol,
+ /* 0x58 */ XK_F12, NoSymbol,
+ /* 0x59 */ XK_F14, NoSymbol,
+ /* 0x5a */ XK_F15, NoSymbol,
+ /* 0x5b */ XK_F16, NoSymbol,
+ /* 0x5c */ XK_F17, NoSymbol,
+ /* 0x5d */ XK_F18, NoSymbol,
+ /* 0x5e */ XK_F19, NoSymbol,
+ /* 0x5f */ XK_F20, NoSymbol,
+ /* 0x60 */ XK_KP_Enter, NoSymbol,
+ /* 0x61 */ XK_Control_R, NoSymbol,
+ /* 0x62 */ XK_KP_Divide, NoSymbol,
+ /* 0x63 */ XK_Print, XK_Sys_Req,
+ /* 0x64 */ XK_Alt_R, XK_Meta_R,
+ /* 0x65 */ NoSymbol, NoSymbol, /* KEY_LINEFEED */
+ /* 0x66 */ XK_Home, NoSymbol,
+ /* 0x67 */ XK_Up, NoSymbol,
+ /* 0x68 */ XK_Prior, NoSymbol,
+ /* 0x69 */ XK_Left, NoSymbol,
+ /* 0x6a */ XK_Right, NoSymbol,
+ /* 0x6b */ XK_End, NoSymbol,
+ /* 0x6c */ XK_Down, NoSymbol,
+ /* 0x6d */ XK_Next, NoSymbol,
+ /* 0x6e */ XK_Insert, NoSymbol,
+ /* 0x6f */ XK_Delete, NoSymbol,
+ /* 0x6f */ NoSymbol, NoSymbol, /* KEY_MACRO */
+ /* 0x70 */ NoSymbol, NoSymbol,
+ /* 0x71 */ NoSymbol, NoSymbol,
+ /* 0x72 */ NoSymbol, NoSymbol,
+ /* 0x73 */ NoSymbol, NoSymbol,
+ /* 0x74 */ NoSymbol, NoSymbol,
+ /* 0x75 */ XK_KP_Equal, NoSymbol,
+ /* 0x76 */ NoSymbol, NoSymbol,
+ /* 0x77 */ NoSymbol, NoSymbol,
+ /* 0x78 */ XK_F21, NoSymbol,
+ /* 0x79 */ XK_F22, NoSymbol,
+ /* 0x7a */ XK_F23, NoSymbol,
+ /* 0x7b */ XK_F24, NoSymbol,
+ /* 0x7c */ XK_KP_Separator, NoSymbol,
+ /* 0x7d */ XK_Meta_L, NoSymbol,
+ /* 0x7e */ XK_Meta_R, NoSymbol,
+ /* 0x7f */ XK_Multi_key, NoSymbol,
+};
+
+/*
+ * FIXME: We have no way of ringing the bell ourselves.
+ * So use the system bell for now.
+ */
+static void
+EvdevKbdBell (int percent, DeviceIntPtr device, pointer ctrl, int unused)
+{
+ xf86SoundKbdBell(percent, ((KeybdCtrl*) ctrl)->bell_pitch,
+ ((KeybdCtrl*) ctrl)->bell_duration);
+}
+
+static void
+EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl)
+{
+ static struct { int xbit, code; } bits[] = {
+ { CAPSFLAG, LED_CAPSL },
+ { NUMFLAG, LED_NUML },
+ { SCROLLFLAG, LED_SCROLLL },
+ { MODEFLAG, LED_KANA },
+ { COMPOSEFLAG, LED_COMPOSE }
+ };
+
+ InputInfoPtr pInfo;
+ struct input_event ev[ArrayLength(bits)];
+ int i;
+
+ pInfo = device->public.devicePrivate;
+ for (i = 0; i < ArrayLength(bits); i++) {
+ ev[i].type = EV_LED;
+ ev[i].code = bits[i].code;
+ ev[i].value = (ctrl->leds & bits[i].xbit) > 0;
+
+ write(pInfo->fd, ev, sizeof ev);
+ }
+}
+
+int
+EvdevKeyInit (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ KeySymsRec keySyms;
+ CARD8 modMap[MAP_LENGTH];
+ KeySym sym;
+ int i, j;
+
+ static struct { KeySym keysym; CARD8 mask; } modifiers[] = {
+ { XK_Shift_L, ShiftMask },
+ { XK_Shift_R, ShiftMask },
+ { XK_Control_L, ControlMask },
+ { XK_Control_R, ControlMask },
+ { XK_Caps_Lock, LockMask },
+ { XK_Alt_L, AltMask },
+ { XK_Alt_R, AltMask },
+ { XK_Num_Lock, NumLockMask },
+ { XK_Scroll_Lock, ScrollLockMask },
+ { XK_Mode_switch, AltLangMask }
+ };
+
+ /* TODO:
+ * Ctrl-Alt-Backspace and other Ctrl-Alt-stuff should work
+ * XKB, let's try without the #ifdef nightmare
+ * Get keyboard repeat under control (right now caps lock repeats!)
+ */
+
+ pInfo = device->public.devicePrivate;
+
+ /* Compute the modifier map */
+ memset(modMap, 0, sizeof modMap);
+
+ for (i = 0; i < ArrayLength(map) / GLYPHS_PER_KEY; i++) {
+ sym = map[i * GLYPHS_PER_KEY];
+ for (j = 0; j < ArrayLength(modifiers); j++) {
+ if (modifiers[j].keysym == sym)
+ modMap[i + MIN_KEYCODE] = modifiers[j].mask;
+ }
+ }
+
+ keySyms.map = map;
+ keySyms.mapWidth = GLYPHS_PER_KEY;
+ keySyms.minKeyCode = MIN_KEYCODE;
+ keySyms.maxKeyCode = MIN_KEYCODE + ArrayLength(map) / GLYPHS_PER_KEY - 1;
+
+
+ XkbSetRulesDflts (state->key->xkb_rules, state->key->xkb_model,
+ state->key->xkb_layout, state->key->xkb_variant,
+ state->key->xkb_options);
+
+ XkbInitKeyboardDeviceStruct (device, &state->key->xkbnames, &keySyms, modMap,
+ EvdevKbdBell, EvdevKbdCtrl);
+
+ return Success;
+}
+
+static void
+SetXkbOption(InputInfoPtr pInfo, char *name, char *value, char **option)
+{
+ char *s;
+
+ if ((s = xf86SetStrOption(pInfo->options, name, value))) {
+ if (!s[0]) {
+ xfree(s);
+ *option = NULL;
+ } else {
+ *option = s;
+ }
+ }
+}
+
+int
+EvdevKeyNew (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int i, keys = 0;
+
+ for (i = 0; i <= KEY_UNKNOWN; i++)
+ if (test_bit (i, pEvdev->bits.key)) {
+ keys = 1;
+ break;
+ }
+ if (!keys)
+ for (i = KEY_OK; i <= KEY_MAX; i++)
+ if (test_bit (i, pEvdev->bits.key)) {
+ keys = 1;
+ break;
+ }
+
+ if (!keys)
+ return !Success;
+
+ state->key = Xcalloc (sizeof (evdevKeyRec));
+
+ pInfo->type_name = XI_KEYBOARD;
+
+ pInfo->flags |= XI86_KEYBOARD_CAPABLE | XI86_CONFIGURED;
+
+ SetXkbOption (pInfo, "XkbRules", __XKBDEFRULES__, &state->key->xkb_rules);
+ SetXkbOption (pInfo, "XkbModel", "evdev", &state->key->xkb_model);
+ SetXkbOption (pInfo, "XkbLayout", "us", &state->key->xkb_layout);
+ SetXkbOption (pInfo, "XkbVariant", NULL, &state->key->xkb_variant);
+ SetXkbOption (pInfo, "XkbOptions", NULL, &state->key->xkb_options);
+
+ /*
+ SetXkbOption (pInfo, "XkbKeycodes", NULL, &state->key->xkbnames.keycodes);
+ SetXkbOption (pInfo, "XkbTypes", NULL, &state->key->xkbnames.types);
+ SetXkbOption (pInfo, "XkbCompat", NULL, &state->key->xkbnames.compat);
+ SetXkbOption (pInfo, "XkbSymbols", NULL, &state->key->xkbnames.symbols);
+ SetXkbOption (pInfo, "XkbGeometry", NULL, &state->key->xkbnames.geometry);
+ */
+
+ return Success;
+}
+
+int
+EvdevKeyOn (DeviceIntPtr device)
+{
+ return Success;
+}
+
+int
+EvdevKeyOff (DeviceIntPtr device)
+{
+ unsigned int i;
+ KeyClassRec *keyc = device->key;
+ KeySym *map = keyc->curKeySyms.map;
+
+ /*
+ * A bit of a hack, vaguely stolen from xf86-input-keyboard.
+ *
+ * Don't leave any keys in the down state if we are getting turned
+ * off, as they are likely to be released before we are turned back
+ * on.
+ * (For example, if the user switches VTs, or if we are unplugged.)
+ */
+ for (i = keyc->curKeySyms.minKeyCode, map = keyc->curKeySyms.map;
+ i < keyc->curKeySyms.maxKeyCode;
+ i++, map += keyc->curKeySyms.mapWidth)
+ if ((keyc->down[i >> 3] & (1 << (i & 7))))
+ {
+ switch (*map) {
+ /* Don't release the lock keys */
+ case XK_Caps_Lock:
+ case XK_Shift_Lock:
+ case XK_Num_Lock:
+ case XK_Scroll_Lock:
+ case XK_Kana_Lock:
+ break;
+ default:
+ xf86PostKeyboardEvent(device, i, 0);
+ }
+ }
+ return Success;
+}
+
+void
+EvdevKeyProcess (InputInfoPtr pInfo, struct input_event *ev)
+{
+ int keycode = ev->code + MIN_KEYCODE;
+
+ /* filter repeat events for chording keys */
+ if (ev->value == 2) {
+ DeviceIntPtr device = pInfo->dev;
+ KeyClassRec *keyc = device->key;
+ KbdFeedbackClassRec *kbdfeed = device->kbdfeed;
+ int num = keycode >> 3;
+ int bit = 1 << (keycode & 7);
+
+ if (keyc->modifierMap[keycode] ||
+ !(kbdfeed->ctrl.autoRepeats[num] & bit))
+ return;
+ }
+
+ xf86PostKeyboardEvent(pInfo->dev, keycode, ev->value);
+}
More information about the xorg-commit
mailing list