x-input-evdev: Branch 'evdev-modular' - configure.ac Makefile.am man/evdevlib.man man/.gitignore man/Makefile.am src/evdev.c src/Makefile.am src/Xevdev.h src/xorg/evdev_axes.c src/xorg/evdev_brain.c src/xorg/evdev_btn.c src/xorg/evdev.c src/xorg/evdev.h src/xorg/evdev_key.c src/xorg/inotify.h src/xorg/inotify-syscalls.h src/xorg/Makefile.am TODO

Tiago Vignatti vignatti at kemper.freedesktop.org
Thu Aug 17 19:28:14 EEST 2006


 Makefile.am                 |   31 +-
 TODO                        |    3 
 configure.ac                |   58 ++-
 man/.gitignore              |    3 
 man/Makefile.am             |   59 +++
 man/evdevlib.man            |  322 +++++++++++++++++++++
 src/Makefile.am             |   10 
 src/Xevdev.h                |   16 -
 src/evdev.c                 |  228 ---------------
 src/xorg/Makefile.am        |   32 ++
 src/xorg/evdev.c            |  495 ++++++++++++++++++++++++++++++++
 src/xorg/evdev.h            |  275 ++++++++++++++++++
 src/xorg/evdev_axes.c       |  664 ++++++++++++++++++++++++++++++++++++++++++++
 src/xorg/evdev_brain.c      |  487 ++++++++++++++++++++++++++++++++
 src/xorg/evdev_btn.c        |  367 ++++++++++++++++++++++++
 src/xorg/evdev_key.c        |  451 +++++++++++++++++++++++++++++
 src/xorg/inotify-syscalls.h |   79 +++++
 src/xorg/inotify.h          |   60 +++
 18 files changed, 3355 insertions(+), 285 deletions(-)

New commits:
diff-tree e77b6a0ba2e557809950d986e3caa4a2989b9930 (from dd29d058e1e9da0cb11bc697510ddb22b16ef8cd)
Author: Tiago Vignatti <tv02 at c3sl.ufpr.br>
Date:   Thu Aug 17 13:25:09 2006 -0300

    The evdev xorg module lives!
    
    	modified: Makefile.am
    	new file: TODO
    	modified: configure.ac
    	new file: man/.gitignore
    	new file: man/Makefile.am
    	new file: man/evdevlib.man
    	modified: src/Makefile.am
    	deleted:  src/Xevdev.h
    	deleted:  src/evdev.c
    	new file: src/xorg/Makefile.am
    	new file: src/xorg/evdev.c
    	new file: src/xorg/evdev.h
    	new file: src/xorg/evdev_axes.c
    	new file: src/xorg/evdev_brain.c
    	new file: src/xorg/evdev_btn.c
    	new file: src/xorg/evdev_key.c
    	new file: src/xorg/inotify-syscalls.h
    	new file: src/xorg/inotify.h

diff --git a/Makefile.am b/Makefile.am
index 02b9b02..c8fa46d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-#  Copyright 2006 Tiago Vignatti.
+#  Copyright 2005 Adam Jackson.
 #
 #  Permission is hereby granted, free of charge, to any person obtaining a
 #  copy of this software and associated documentation files (the "Software"),
@@ -11,18 +11,23 @@
 #  paragraph) shall be included in all copies or substantial portions of the
 #  Software.
 #
-#  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.
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+#  ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+#  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+#  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 AUTOMAKE_OPTIONS = foreign
-SUBDIRS = src
+SUBDIRS = src man
 
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = x-input-evdev.pc
+EXTRA_DIST=ChangeLog
+
+CLEANFILES=ChangeLog
+
+.PHONY: ChangeLog
+
+ChangeLog:
+	git-log > ChangeLog
+
+dist-hook: ChangeLog
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..3534a31
--- /dev/null
+++ b/TODO
@@ -0,0 +1,3 @@
+    Migrate all functions from xf86-input-evdev to x-input-evdev
+    .
+   		
diff --git a/configure.ac b/configure.ac
index 3af2a3b..2682a56 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-#  Copyright 2006 Tiago Vignatti.
+#  Copyright 2005 Adam Jackson.
 #
 #  Permission is hereby granted, free of charge, to any person obtaining a
 #  copy of this software and associated documentation files (the "Software"),
@@ -11,26 +11,22 @@
 #  paragraph) shall be included in all copies or substantial portions of the
 #  Software.
 #
-#  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.
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+#  ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+#  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+#  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #
 # Process this file with autoconf to produce a configure script
 
 AC_PREREQ(2.57)
-
 AC_INIT([x-input-evdev],
-	0.0.1,
-	[https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
-	x-input-evdev)
+        0.0.2,
+        [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
+        x-input-evdev)
 
-LT_CURRENT=1
+LT_CURRENT=2
 LT_REVISION=0
 LT_AGE=0
 
@@ -43,7 +39,7 @@ AM_INIT_AUTOMAKE([dist-bzip2])
 
 AM_MAINTAINER_MODE
 
-DRIVER_NAME=evdev2
+DRIVER_NAME=evdevlib
 AC_SUBST([DRIVER_NAME])
 
 AM_CONFIG_HEADER([config.h])
@@ -56,13 +52,18 @@ AC_PROG_CC
 AH_TOP([#include "xorg-server.h"])
 
 AC_ARG_WITH(xorg-module-dir,
-            AC_HELP_STRING([--with-xorg-module-dir=DIR],
-                           [Default xorg module directory [[default=$libdir/xorg/modules]]]),
-            [moduledir="$withval"],
-            [moduledir="$libdir/xorg/modules"])
+	AC_HELP_STRING([--with-xorg-module-dir=DIR],
+	[Default xorg module directory [[default=$libdir/xorg/modules]]]),
+	[moduledir="$withval"],
+	[moduledir="$libdir/xorg/modules"])
+
 inputdir=${moduledir}/input
 AC_SUBST(inputdir)
 
+# Checks for extensions
+XORG_DRIVER_CHECK_EXT(XKB, kbproto)
+XORG_DRIVER_CHECK_EXT(XINPUT, inputproto)
+
 # Checks for pkg-config packages
 PKG_CHECK_MODULES(XORG, xorg-server xproto $REQUIRED_MODULES)
 sdkdir=$(pkg-config --variable=sdkdir xorg-server)
@@ -70,7 +71,15 @@ sdkdir=$(pkg-config --variable=sdkdir xo
 CFLAGS="$CFLAGS "' -I$(top_srcdir)/src'
 AC_SUBST([CFLAGS])
 
-# Checks for libraries.
+# Evdev modules
+AC_ARG_ENABLE(xorg, AS_HELP_STRING([--enable-xorg],
+		[Build xorg module (default: yes)]),
+		[EVDEV_XORG=$enableval], [EVDEV_XORG=yes])
+AM_CONDITIONAL(EVDEV_XORG, [test "x$EVDEV_XORG" = xyes])
+if test "x$EVDEV_XORG" = "xyes"; then
+	AC_DEFINE(EVDEV_XORG,1,[Enable xorg module])
+	CFLAGS="$CFLAGS $XORG_CFLAGS "' -I$(top_srcdir)/src'
+fi
 
 # Checks for header files.
 AC_HEADER_STDC
@@ -78,4 +87,9 @@ AC_HEADER_STDC
 XORG_MANPAGE_SECTIONS
 XORG_RELEASE_VERSION
 
-AC_OUTPUT([Makefile src/Makefile x-input-evdev.pc])
+
+AC_OUTPUT([
+Makefile
+man/Makefile
+src/Makefile
+src/xorg/Makefile])
diff --git a/man/.gitignore b/man/.gitignore
new file mode 100644
index 0000000..c060ea5
--- /dev/null
+++ b/man/.gitignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+evdev.4
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..bf7ec17
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,59 @@
+# $Id$
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# 
+# 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.
+# 
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+# 
+# Except as contained in this notice, the name of the copyright holders shall
+# not be used in advertising or otherwise to promote the sale, use or
+# other dealings in this Software without prior written authorization
+# from the copyright holders.
+# 
+
+drivermandir = $(DRIVER_MAN_DIR)
+
+driverman_PRE = @DRIVER_NAME at .man
+
+driverman_DATA = $(driverman_PRE:man=@DRIVER_MAN_SUFFIX@)
+
+EXTRA_DIST = @DRIVER_NAME at .man
+
+CLEANFILES = $(driverman_DATA)
+
+SED = sed
+
+# Strings to replace in man pages
+XORGRELSTRING = @PACKAGE_STRING@
+  XORGMANNAME = X Version 11
+
+MAN_SUBSTS = \
+	-e 's|__vendorversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+	-e 's|__xorgversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+	-e 's|__xservername__|Xorg|g' \
+	-e 's|__xconfigfile__|xorg.conf|g' \
+	-e 's|__projectroot__|$(prefix)|g' \
+	-e 's|__appmansuffix__|$(APP_MAN_SUFFIX)|g' \
+	-e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' \
+	-e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' \
+	-e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' \
+	-e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'
+
+SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man
+
+.man.$(DRIVER_MAN_SUFFIX):
+	sed $(MAN_SUBSTS) < $< > $@
diff --git a/man/evdevlib.man b/man/evdevlib.man
new file mode 100644
index 0000000..8c6ed00
--- /dev/null
+++ b/man/evdevlib.man
@@ -0,0 +1,322 @@
+.\" shorthand for double quote that works everywhere.
+.ds q \N'34'
+.TH EVDEV __drivermansuffix__ __vendorversion__
+.SH NAME
+evdev \- Generic Linux input driver
+.SH SYNOPSIS
+.nf
+.B "Section \*qInputDevice\*q"
+.BI "  Identifier \*q" devname \*q
+.B  "  Driver \*qevdev\*q"
+.BI "  Option \*qDevice\*q   \*q" devpath \*q
+\ \ ...
+.B EndSection
+.fi
+.SH DESCRIPTION
+.B evdev 
+is an __xservername__ input driver for Linux\'s generic event devices.  It
+therefore supports all input devices that the kernel knows about, including
+most mice and keyboards.
+.PP
+The 
+.B evdev
+driver can serve as both a pointer and a keyboard input device, and may be
+used as both the core keyboard and the core pointer.  Multiple input devices
+are supported by multiple instances of this driver, with one Load
+directive for evdev in the Module section of your __xconfigfile__ for each
+input device that will use this driver.
+.PP
+.SH SUPPORTED HARDWARE
+In general, any input device that the kernel has a driver for can be accessed
+through the 
+.B evdev
+driver.  See the Linux kernel documentation for a complete list.
+.PP
+.SH CONFIGURATION DETAILS
+Please refer to __xconfigfile__(__filemansuffix__) for general configuration
+details and for options that can be used with all input drivers.  This
+section only covers configuration details specific to this driver.
+.PP
+.SH BASIC CONFIGURATIONS
+Most users of this driver will probably be quite happy with the following for
+all QWERTY keyboards:
+.PP
+.nf
+.B "Section \*qInputDevice\*q"
+.BI "  Identifier \*q" keyboard \*q
+.B  "  Driver \*qevdev\*q"
+.BI  "  Option \*qevBits\*q  \*q" "+1" \*q
+.BI  "  Option \*qkeyBits\*q \*q" "~1-255 ~352-511" \*q
+.BI  "  Option \*qPass\*q    \*q" "3" \*q
+\ \ ...
+.B EndSection
+.fi
+.PP
+And the following for all mice:
+.PP
+.nf
+.B "Section \*qInputDevice\*q"
+.BI "  Identifier \*q" mouse \*q
+.B  "  Driver \*qevdev\*q"
+.BI  "  Option \*qevBits\*q  \*q" "+1-2" \*q
+.BI  "  Option \*qkeyBits\*q \*q" "~272-287" \*q
+.BI  "  Option \*qrelBits\*q \*q" "~0-2 ~6 ~8" \*q
+.BI  "  Option \*qPass\*q    \*q" "3" \*q
+\ \ ...
+.B EndSection
+.fi
+.PP
+To understand what those Bits options do, or for more complex
+configurations, please see
+.BR "ADVANCED OPTIONS"
+below.
+.PP
+.SH ADVANCED OPTIONS
+.SS DEVICE SPECIFICATION
+For this section you'll want to have knowledge of
+.B glob (7)
+and our evil
+.B "BIT MATCHING SPECIFICATION"
+stuff.
+.PP
+The following driver 
+.B Options
+control what devices are accepted:
+
+.TP 7
+.BI "Option \*qDevice\*q \*q" string \*q
+Specifies the device note through which the device can be accessed.
+At this time ONLY /dev/input/event<N>, where <N> is an integer, are
+matched against this this field.
+.fi
+This option uses globbing.
+.fi
+Please note that use of this option is strongly discouraged.
+
+.TP 7
+.BI "Option \*qName\*q \*q" string \*q
+Specifies the device name for the device you wish to use.
+.fi
+The device name is generally the only consistent identifier for devices 
+that are commonly unplugged and plugged back into different ports.
+.fi
+A list of currently plugged in devices and associated device names can be 
+obtained by typing \*qcat /proc/bus/input/devices\*q, the \*qName\*q field 
+is the value you want for this option.
+.fi
+This option uses globbing.
+
+.TP 7
+.BI "Option \*qPhys\*q \*q" string \*q
+Specifies the device phys string for the device you wish to use.
+.fi
+The phys string is generally consistant to the USB port a device is plugged 
+into.
+.fi
+A list of currently plugged in devices and associated device names can be 
+obtained by typing \*qcat /proc/bus/input/devices\*q, the \*qPhys\*q field 
+is the value you want for this option.
+.fi
+This option uses globbing.
+
+.TP 7
+.BI "Option \*q<map>Bits\*q \*q" "bit specifier" \*q
+Specifies device capability bits which must be set, possibly set, or unset.
+.fi
+<map>Bits: Where map is one of ev, key, rel, abs, msc, led, snd, or
+ff.
+.fi
+The bit specifier format is a string consisting of +<n>, -<n>, and ~<n>
+space sepirated specifiers, where <n> is a positive integer or integer range.
+(The latter given in the format of 2-6.)
+.fi
++ specifies bits which must be set.
+.fi
+- specifies bits which must not be set.
+.fi
+~ is a little more complex, it specifies that at least one of the bits given
+with ~ for the field in question must be set, but it doesn't matter how many
+or which of the bits. (It is actually the most useful of the 3 specifiers.)
+.fi
+As an example '+0 +3 -1-2 ~5-10', requires bits 0 and 3 be set,
+bits 1 and 2 to not be set, and at least one bit in the range of 5 to
+10 be set.
+.fi
+An annoyingly formatted set of bitmasks for your devices can be obtained
+by typing \*qcat /proc/bus/input/devices\*q, and
+.B /usr/include/linux/input.h
+should contain the defines which declare what bits are what for each field.
+
+.TP 7
+.BI "Option \*qbustype\*q \*q" integer \*q
+Specifies the bus ID for the device you wish to use.
+.fi
+This is either 0 (the default, matches anything), or the Bus=<n> field in
+.B /proc/bus/input/devices
+for your device.
+.fi
+This value depends on what type of bus your device is connected to.
+
+.TP 7
+.BI "Option \*qvendor\*q \*q" integer \*q
+Specifies the vendor ID for the device you wish to use.
+.fi
+This is either 0 (the default, matches anything), or the Vendor=<n> field in
+.B /proc/bus/input/devices
+for your device.
+.fi
+This value should remain constant barring perhaps firmware updates to the
+device itself.
+
+.TP 7
+.BI "Option \*qversion\*q \*q" integer \*q
+Specifies the version for the device you wish to use.
+.fi
+This is either 0 (the default, matches anything), or the Version=<n> field in
+.B /proc/bus/input/devices
+for your device.
+.fi
+This value should remain constant barring perhaps firmware updates to the
+device itself.
+
+.TP 7
+.BI "Option \*qproduct\*q \*q" integer \*q
+Specifies the product ID for the device you wish to use.
+.fi
+This is either 0 (the default, matches anything), or the Product=<n> field in
+.B /proc/bus/input/devices
+for your device.
+.fi
+This value should remain constant barring perhaps firmware updates to the
+device itself.
+
+.TP 7
+.BI "Option \*qPass\*q \*q" integer \*q
+Specifies the order in which evdev will scan for devices.
+.fi
+This is in the range of 0 to 3, and is used for the case
+where more then one evdev inputsection matches the same device.
+.fi
+An inputsection with a lower pass number will always beat out
+one with a higher pass number.  Order when both sections are
+the same number is undefined.
+.fi
+The default is 0.
+
+
+.PP
+.SS RELATIVE AXIS CONFIGURATION
+The relative axis portion of this driver handle all reported relative axies.
+.fi
+The axies are named X, Y, Z, RX, RY, RZ, HWHEEL, DIAL, WHEEL, MISC, 10, 11,
+12, 13, 14, and 15.
+.fi
+The axies are reported to X as valuators, with the default mapping of axies
+to valuators being the first axies found to the first valuator, the second
+found to the second valuator, and so on, so that if you have axies X, Y,
+HWHEEL, and WHEEL, you would have X=0, Y=1, HWHEEL=2, WHEEL=3.
+.fi
+If the driver is reporting core events, valuators 0 and 1 are always mapped
+to x and y coordinates, respectively.
+.fi
+The following driver 
+.B Options
+control the relative axis portion of the driver:
+.TP 7
+.BI "Option \*q<axis>RelativeAxisMap\*q \*q" number \*q
+This remaps the axis specified to the specified valuator.
+.TP 7
+.BI "Option \*q<axis>RelativeAxisButtons\*q \*q" number " number\*q
+This remaps the axis specified to the specified buttons.
+.fi
+Note that the physical buttons are always remapped around 'fake' buttons 
+created by this option, so that if you have physical buttons 1 2 3 4 5,
+and map the Wheel axis to buttons 4 5, you get buttons 1 2 3
+.B 4 5
+6 7, with buttons 6 and 7 being physical buttons 4 and 5.
+.PP
+.SS ABSOLUTE AXIS CONFIGURATION
+The relative axis portion of this driver handle all reported relative axies.
+.fi
+The axies are named X, Y, Z, RX, RY, RZ, THROTTLE, RUDDER, WHEEL, GAS, BREAK,
+<11-15>, HAT0X, HAT0Y, HAT1X, HAT1Y, HAT2X, HAT2Y, HAT3X, HAT3Y, PRESSURE,
+TILT_X, TILT_Y, TOOL_WIDTH, VOLUME, <29-39>, MISC, <41-62>.
+.fi
+The axies are reported to X as valuators, with the default mapping of axies
+to valuators being the first axies found to the first valuator, the second
+found to the second valuator, and so on, so that if you have axies X, Y,
+TILT_X, and TILT_Y, you would have X=0, Y=1, TILT_X=2, TILT_Y=3.
+.fi
+If the driver is reporting core events, valuators 0 and 1 are always mapped
+to x and y coordinates, respectively.
+.fi
+The following driver 
+.B Options
+control the relative axis portion of the driver:
+.TP 7
+.BI "Option \*q<axis>AbsoluteAxisMap\*q \*q" number \*q
+This remaps the axis specified to the specified valuator.
+.TP 7
+.BI "Option \*qAbsoluteScreen\*q \*q" number \*q
+This binds the device to a specific screen, scaling it to
+the coordinate space of that screen.
+.fi
+The number can either be -1, or a valid screen number.
+.fi
+If -1 or if in relative mode no scaling or screen fixing is done.
+.fi
+This is of most use for digitizers, where the screen and the input
+device are the same surface.
+.TP 7
+.BI "Option \*qMode\*q \*q" <mode>\*q
+This selects the default mode for the device.
+.fi
+Valid values are \*qabsolute\*q and \*qrelative\*q.
+.fi
+This can be set at run time per actual device with the xinput utility.
+.PP
+.SS BUTTON CONFIGURATION
+At the moment, the button portion of this driver only handles buttons
+reported as mouse buttons, that is from BTN_MOUSE to BTN_JOYSTICK - 1.
+.fi
+At this time there are no configuration options for buttens.
+.SS KEYBOARD CONFIGURATION
+The keyboard portion of this driver handles all keys reported and requires 
+XKB support.
+.fi
+The following driver 
+.B Options
+control the relative axis portion of the driver:
+.TP 7
+.BI "Option \*qXkbRules\*q \*q" rules \*q
+specifies which XKB rules file to use for interpreting the
+.BR XkbModel ,
+.BR XkbLayout ,
+.BR XkbVariant ,
+and
+.B XkbOptions
+settings.  Default: "xorg" for most platforms, but "xfree98" for the
+Japanese PC-98 platforms.
+.TP 7
+.BI "Option \*qXkbModel\*q \*q" modelname \*q
+specifies the XKB keyboard model name.  Default: "evdev".
+.TP 7
+.BI "Option \*qXkbLayout\*q \*q" layoutname \*q
+specifies the XKB keyboard layout name.  This is usually the country or
+language type of the keyboard.  Default: "us".
+.TP 7
+.BI "Option \*qXkbVariant\*q \*q" variants \*q
+specifies the XKB keyboard variant components.  These can be used to
+enhance the keyboard layout details.  Default: not set.
+.TP 7
+.BI "Option \*qXkbOptions\*q \*q" options \*q
+specifies the XKB keyboard option components.  These can be used to
+enhance the keyboard behaviour.  Default: not set.
+
+.PP
+.SH AUTHORS
+Zephaniah E. Hull.
+.fi
+Kristian Høgsberg.
+.SH "SEE ALSO"
+__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__).
diff --git a/src/Makefile.am b/src/Makefile.am
index 11b7457..5ec5b29 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,5 @@
-lib_LTLIBRARIES = libXevdev.la
+if EVDEV_XORG
+EVDEV_XORG_SUBDIRS = xorg
+endif
 
-libXevdevincludedir = $(includedir)/X11
-libXevdevinclude_HEADERS = Xevdev.h
-
-libXevdev_la_SOURCES = evdev.c
-libXevdev_la_LDFLAGS = -version-info @VERSION_INFO@
+SUBDIRS = $(EVDEV_XORG_SUBDIRS)
diff --git a/src/Xevdev.h b/src/Xevdev.h
deleted file mode 100644
index 2103e9f..0000000
--- a/src/Xevdev.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef XEVDEV_H
-#define XEVDEV_H
-
-#include <linux/input.h>
-
-typedef void (*EvdevReadInputProc) ();
-
-int      OpenEvdevInput (char		    *kbdEvdev,
-			 char		    *ptrEvdev,
-			 EvdevReadInputProc readInput);
-int      EvdevSetLeds(long int leds);
-void     EvdevGrabKeyboard();
-void     EvdevUngrabKeyboard();
-int      EvdevCheckIfEvent(struct input_event *ie);
-
-#endif  /* XEVDEV_H */
diff --git a/src/evdev.c b/src/evdev.c
deleted file mode 100644
index e6b897f..0000000
--- a/src/evdev.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 2006 by Tiago Vignatti
- *
- * 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:  Tiago Vignatti  (tv02 at c3sl.ufpr.br)
- */
-
-#include "Xevdev.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdio.h>
-
-
-int             kbd_fd,
-                ptr_fd;
-
-static EvdevReadInputProc EvdevReadInput;
-
-static int
-BlockSIGIO(void)
-{
-    sigset_t        set,
-                    old;
-
-    sigemptyset(&set);
-    sigaddset(&set, SIGIO);
-    sigprocmask(SIG_BLOCK, &set, &old);
-    return sigismember(&old, SIGIO);
-}
-
-static void
-UnblockSIGIO(int wasset)
-{
-    sigset_t        set;
-
-    if (!wasset) {
-	sigemptyset(&set);
-	sigaddset(&set, SIGIO);
-	sigprocmask(SIG_UNBLOCK, &set, NULL);
-    }
-}
-
-static void
-EvdevSigioReadInput(int sig)
-{
-    int wasset = BlockSIGIO();
-    (*EvdevReadInput)();
-    UnblockSIGIO(wasset);
-}
-
-#define BITS_PER_LONG          (sizeof(long) * 8)
-#define BIT(x)                 (1UL<<((x)%BITS_PER_LONG))
-
-#define EVIOCGMASK             _IOR('E', 0x91, unsigned long *) 
-#define EVIOCSMASK             _IOW('E', 0x92, unsigned long) 
-#define EVIOCGDMASK            _IOR('E', 0x93, unsigned long *)
-#define EVIOCSDMASK            _IOW('E', 0x94, unsigned long)
-
-int
-OpenEvdevInput (char		   *KbdEvdev,
-		char		   *PtrEvdev,
-		EvdevReadInputProc readInput)
-{
-    static int      already_open = 0;
-    struct sigaction sa;
-    struct sigaction osa;
-
-    if (already_open)
-	return 1;
-
-    EvdevReadInput = readInput;
-
-    kbd_fd = open(KbdEvdev, O_RDWR | O_NONBLOCK);
-    if (kbd_fd == -1) {
-	fprintf(stderr, "Unable to open keyboard device %s.\n", KbdEvdev);	    
-	return 0;
-    }
-    ptr_fd = open(PtrEvdev, O_RDONLY | O_NONBLOCK);
-    if (ptr_fd == -1) {
-	fprintf(stderr, "Unable to open pointer device %s.\n", PtrEvdev);	    
-	return 0;
-    }
-    
-    /*
-     * Register the fd to receive SIGIO signals 
-     */
-    if (fcntl(kbd_fd, F_SETFL, fcntl(kbd_fd, F_GETFL) | O_ASYNC) == -1)
-	fprintf(stderr, "fcntl(%d, O_ASYNC): %s\n", kbd_fd, strerror(errno));
-    if (fcntl(kbd_fd, F_SETOWN, getpid()) == -1)
-	fprintf(stderr, "fcntl(%d, F_SETOWN): %s\n", kbd_fd, strerror(errno));
-
-    /*
-     * Register the fd to receive SIGIO signals 
-     */
-    if (fcntl(ptr_fd, F_SETFL, fcntl(ptr_fd, F_GETFL) | O_ASYNC) == -1)
-	fprintf(stderr, "fcntl(%d, O_ASYNC): %s\n", ptr_fd, strerror(errno));
-    if (fcntl(ptr_fd, F_SETOWN, getpid()) == -1)
-	fprintf(stderr, "fcntl(%d, F_SETOWN): %s\n", ptr_fd, strerror(errno));
-
-    sigemptyset(&sa.sa_mask);
-    sigaddset(&sa.sa_mask, SIGIO);
-    sa.sa_flags = 0;
-    sa.sa_handler = EvdevSigioReadInput;
-    sigaction(SIGIO, &sa, &osa);
-
-    already_open = 1;
-
-    return 1;
-}
-
-static int      grabbed = 0;
-
-void
-EvdevGrabKeyboard()
-{
-    unsigned long   mask;
-
-    if (grabbed)
-	return;
-
-    if (ioctl(kbd_fd, EVIOCGMASK, &mask) < 0) {
-	fprintf (stderr, "unable to use input device masking '%s', trying grabbing.\n", strerror(errno));
-	if (ioctl(kbd_fd, EVIOCGRAB, 1) < 0) 
-            fprintf (stderr, "unable to grab device '%s', you may have problems.\n", strerror(errno));
-	return;
-    }
-
-    mask |= BIT(2);
-    ioctl(kbd_fd, EVIOCSMASK, mask);
-    ioctl(kbd_fd, EVIOCGDMASK, &mask);
-    mask &= ~BIT(0);
-    mask |= BIT(2);
-    ioctl(kbd_fd, EVIOCSDMASK, mask);
-}
-
-
-void
-EvdevUngrabKeyboard()
-{
-    unsigned long mask;
-
-    if (!grabbed)
-	return;
-
-    if (ioctl(kbd_fd, EVIOCGDMASK, &mask) >= 0) {
-	mask |= BIT(0);
-	ioctl(kbd_fd, EVIOCSDMASK, mask);
-    }
-}
-
-int
-EvdevCheckIfEvent(struct input_event *ie)
-{
-    int             result,
-                    nread;
-
-    nread = read(kbd_fd, ie, sizeof(struct input_event));
-
-    if (nread <= 0)
-	nread = read(ptr_fd, ie, sizeof(struct input_event));
-
-    if (nread <= 0)
-	result = 0;
-    else
-	result = 1;
-
-    return result;
-}
-
-int
-EvdevSetLeds(long int leds)
-{
-    struct input_event event;
-    int             i;
-
-    memset(&event, 0, sizeof(event));
-
-    event.type = EV_LED;
-    event.code = LED_CAPSL;
-    event.value = leds & (1 << 0) ? 1 : 0;
-    write(kbd_fd, (char *) &event, sizeof(event));
-
-    event.type = EV_LED;
-    event.code = LED_NUML;
-    event.value = leds & (1 << 1) ? 1 : 0;
-    write(kbd_fd, (char *) &event, sizeof(event));
-
-    event.type = EV_LED;
-    event.code = LED_SCROLLL;
-    event.value = leds & (1 << 2) ? 1 : 0;
-    write(kbd_fd, (char *) &event, sizeof(event));
-
-    event.type = EV_LED;
-    event.code = LED_COMPOSE;
-    event.value = leds & (1 << 3) ? 1 : 0;
-    write(kbd_fd, (char *) &event, sizeof(event));
-
-    return 1;
-}
diff --git a/src/xorg/Makefile.am b/src/xorg/Makefile.am
new file mode 100644
index 0000000..4d97d16
--- /dev/null
+++ b/src/xorg/Makefile.am
@@ -0,0 +1,32 @@
+#  Copyright 2005 Adam Jackson.
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a
+#  copy of this software and associated documentation files (the "Software"),
+#  to deal in the Software without restriction, including without limitation
+#  on the rights to use, copy, modify, merge, publish, distribute, sub
+#  license, and/or sell copies of the Software, and to permit persons to whom
+#  the Software is furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice (including the next
+#  paragraph) shall be included in all copies or substantial portions of the
+#  Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+#  ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+#  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+#  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+# this is obnoxious:
+# -module lets us name the module exactly how we want
+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
+# _ladir passes a dummy rpath to libtool so the thing will actually link
+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+ at DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME at _drv.la
+ at DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
+ at DRIVER_NAME@_drv_la_CFLAGS = -Wall
+ at DRIVER_NAME@_drv_ladir = @inputdir@
+
+ at DRIVER_NAME@_drv_la_SOURCES = evdev.c evdev.h evdev_brain.c evdev_axes.c evdev_btn.c evdev_key.c inotify.h inotify-syscalls.h
diff --git a/src/xorg/evdev.c b/src/xorg/evdev.c
new file mode 100644
index 0000000..2d8d120
--- /dev/null
+++ b/src/xorg/evdev.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 "evdev.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/evdev.h b/src/xorg/evdev.h
new file mode 100644
index 0000000..db33546
--- /dev/null
+++ b/src/xorg/evdev.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/evdev_axes.c b/src/xorg/evdev_axes.c
new file mode 100644
index 0000000..df6eb4b
--- /dev/null
+++ b/src/xorg/evdev_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 "evdev.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/evdev_brain.c b/src/xorg/evdev_brain.c
new file mode 100644
index 0000000..6365577
--- /dev/null
+++ b/src/xorg/evdev_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 "evdev.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/evdev_btn.c b/src/xorg/evdev_btn.c
new file mode 100644
index 0000000..dc9ed67
--- /dev/null
+++ b/src/xorg/evdev_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 "evdev.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/evdev_key.c b/src/xorg/evdev_key.c
new file mode 100644
index 0000000..8917c3b
--- /dev/null
+++ b/src/xorg/evdev_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 "evdev.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);
+}
diff --git a/src/xorg/inotify-syscalls.h b/src/xorg/inotify-syscalls.h
new file mode 100644
index 0000000..7c68bc6
--- /dev/null
+++ b/src/xorg/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/xorg/inotify.h b/src/xorg/inotify.h
new file mode 100644
index 0000000..20d419a
--- /dev/null
+++ b/src/xorg/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 */



More information about the xorg-commit mailing list