Remove all of evdev_brain.c and all callers.

Remove the non-functional 2.4 kernel compiling compatibility.

Remove the XInput 1.4+ SendCoreEvents/DontSendCoreEvents define replacements.

Remove evdevDriver, some stuff from evdevDevice, all users.

NOTE: This WILL BREAK all existing configurations.

NOTE: Device read failure segfaults, don't unplug stuff.
This commit is contained in:
Zephaniah E. Hull
2007-04-24 06:49:11 -04:00
parent 3c4a96fbd8
commit a0ea7363f5
4 changed files with 65 additions and 902 deletions

View File

@@ -29,4 +29,4 @@
@DRIVER_NAME@_drv_la_CFLAGS = -Wall
@DRIVER_NAME@_drv_ladir = @inputdir@
@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
@DRIVER_NAME@_drv_la_SOURCES = evdev.c evdev.h evdev_axes.c evdev_btn.c evdev_key.c inotify.h inotify-syscalls.h

View File

@@ -67,6 +67,7 @@
#include <xf86Module.h>
#include <mipointer.h>
#include <xf86_OSlib.h>
#include <xf86_OSproc.h>
@@ -78,6 +79,35 @@
void xf86ActivateDevice(InputInfoPtr pInfo);
/**
* Obtain various information using ioctls on the given socket. This
* information is used to determine if a device has axis, buttons or keys.
*
* @return TRUE on success or FALSE on error.
*/
static 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;
}
static void
EvdevReadInput(InputInfoPtr pInfo)
{
@@ -94,7 +124,6 @@ EvdevReadInput(InputInfoPtr pInfo)
if (len < 0) {
evdevDevicePtr pEvdev = pInfo->private;
pEvdev->callback(pEvdev->pInfo->dev, DEVICE_OFF);
pEvdev->seen--;
}
break;
}
@@ -162,13 +191,10 @@ EvdevProc(DeviceIntPtr device, int what)
if (device->public.on)
break;
if ((pInfo->fd = evdevGetFDForDevice (pEvdev)) == -1) {
SYSCALL(pInfo->fd = open (pEvdev->device, O_RDWR | O_NONBLOCK));
if (pInfo->fd == -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;
@@ -214,8 +240,13 @@ EvdevProc(DeviceIntPtr device, int what)
EvdevKeyOff (device);
}
#if 0
/*
* FIXME: Handle device removal properly.
*/
if (what == DEVICE_CLOSE)
evdevRemoveDevice(pEvdev);
#endif
device->public.on = FALSE;
break;
@@ -241,12 +272,6 @@ EvdevSwitchMode (ClientPtr client, DeviceIntPtr device, int mode)
else
return !Success;
break;
#if 0
case SendCoreEvents:
case DontSendCoreEvents:
xf86XInputSetSendCoreEvents (pInfo, (mode == SendCoreEvents));
break;
#endif
default:
return !Success;
}
@@ -254,20 +279,29 @@ EvdevSwitchMode (ClientPtr client, DeviceIntPtr device, int mode)
return Success;
}
/*
static Bool
EvdevNew(evdevDriverPtr driver, evdevDevicePtr device)
*/
InputInfoPtr
EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
InputInfoPtr pInfo;
char name[512] = {0};
evdevDevicePtr device;
if (!(pInfo = xf86AllocateInput(driver->drv, 0)))
return 0;
if (!(pInfo = xf86AllocateInput(drv, 0)))
return NULL;
device = Xcalloc (sizeof (evdevDeviceRec));
if (!device) {
pInfo->private = NULL;
xf86DeleteInput (pInfo, 0);
return NULL;
}
/* 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->name = xstrdup(dev->identifier);
pInfo->flags = 0;
pInfo->type_name = "UNKNOWN";
pInfo->device_control = EvdevProc;
@@ -276,29 +310,31 @@ EvdevNew(evdevDriverPtr driver, evdevDevicePtr device)
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
pInfo->motion_history_proc = xf86GetMotionEvents;
#endif
pInfo->conf_idev = driver->dev;
pInfo->conf_idev = dev;
pInfo->private = device;
device->callback = EvdevProc;
device->pInfo = pInfo;
device->device = xf86CheckStrOption(dev->commonOptions, "Device", NULL);
xf86CollectInputOptions(pInfo, NULL, NULL);
xf86ProcessCommonOptions(pInfo, pInfo->options);
if ((pInfo->fd = evdevGetFDForDevice (device)) == -1) {
SYSCALL(pInfo->fd = open (device->device, O_RDWR | O_NONBLOCK));
if (pInfo->fd == -1) {
xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
pInfo->private = NULL;
xfree(device);
xf86DeleteInput (pInfo, 0);
return 0;
return NULL;
}
if (!evdevGetBits (pInfo->fd, &device->bits)) {
xf86Msg(X_ERROR, "%s: cannot load bits\n", pInfo->name);
pInfo->private = NULL;
close (pInfo->fd);
xfree(device);
xf86DeleteInput (pInfo, 0);
return 0;
return NULL;
}
if (ioctl(pInfo->fd, EVIOCGRAB, (void *)1)) {
@@ -328,148 +364,12 @@ EvdevNew(evdevDriverPtr driver, evdevDevicePtr device)
xf86Msg(X_ERROR, "%s: Don't know how to use device.\n", pInfo->name);
pInfo->private = NULL;
close (pInfo->fd);
xfree(device);
xf86DeleteInput (pInfo, 0);
return 0;
}
if (driver->configured) {
xf86ActivateDevice (pInfo);
pInfo->dev->inited = (ActivateDevice(pInfo->dev) == Success);
ActivateDevice(pInfo->dev);
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;
}
}
}
/**
* Called during InitInput().
* Starts up the evdev brain device if it hasn't started yet and then causes a
* full rescan of all devices.
*
* @param drv The evdev driver module. Copied version of EVDEV.
* @param dev The device we'd like to initialise.
*
* @return NULL on failure or the InputInfoPtr of the new device.
*/
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;
/* In some cases pEvdev->devices is NULL, but on the next
* evdevRescanDevices the device suddenly appears. If we return NULL here,
* the server will clean up and the sudden appearance of the device will
* segfault. We need to remove the driver from the list to avoid this.
* No. I don't know why it just appears. (whot)
*/
evdevRemoveDriver(pEvdev);
return NULL;
return pInfo;
}
@@ -478,7 +378,7 @@ _X_EXPORT InputDriverRec EVDEV = {
1,
"evdev",
NULL,
EvdevCorePreInit,
EvdevPreInit,
NULL,
NULL,
0

View File

@@ -90,55 +90,10 @@
#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>
/* XInput 1.4+ compatability. */
#ifndef SendCoreEvents
#define SendCoreEvents 59
#define DontSendCoreEvents 60
#endif
/*
* 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
@@ -213,52 +168,18 @@ typedef struct _evdevState {
} 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);
void evdevRemoveDevice (evdevDevicePtr device);
void evdevDeleteDevice (evdevDevicePtr device);
void evdevRemoveDriver (evdevDriverPtr device);
int EvdevBtnInit (DeviceIntPtr device);
int EvdevBtnOn (DeviceIntPtr device);
int EvdevBtnOff (DeviceIntPtr device);

View File

@@ -1,658 +0,0 @@
/*
* 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@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
/**
* Indicate if evdev brain has been started yet.
*/
static Bool evdev_alive = FALSE;
/**
* Pointer to the "evdev brain".
* Note that this is a list, so evdev_pInfo->next will point to other devices
* (albeit not evdev ones).
*/
static InputInfoPtr evdev_pInfo = NULL;
/**
* All drivers that are currently active for one or more devices.
*/
static evdevDriverPtr evdev_drivers = NULL;
/**
* Internal sequence numbering. Increased each time we evdevRescanDevices().
*/
static int evdev_seq;
static int evdev_inotify;
/**
* Open the file descriptor for the given device in rw, nonblocking mode.
*
* @return The FD on success or -1 otherwise.
*/
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;
}
/**
* Compare various fields of the given driver to the matching fields of the
* info struct. Fields include but are not limited to name, phys string and
* device.
* If this function returns TRUE, the given driver is responsible for the
* device with the given info.
*
* @param driver One of the evdev drivers.
* @param info Information obtained using ioctls on the device file.
*
* @return TRUE on match, FALSE otherwise.
*/
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;
}
/**
* Compare various fields of the device with the given info.
* If this function returns true, the device is identical to the device the
* information was obtained from.
*
* @param device The device using some driver.
* @param info Information obtained using ioctls on the device file.
*
* @return TRUE on match, FALSE otherwise.
*/
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;
}
/**
* Figure out if the device has already been initialised previously. If so,
* switch it on. If not, create a new device and call it's callback to set it
* up.
*
* @param driver The driver responsible for the device.
* @param info Information obtained using ioctls on the device file.
*
* @return TRUE if device was switched on or newly created. False if driver
* and info are not matching.
*/
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;
}
/**
* Use various ioctls to get information about the given device file.
* This information is used in evdevScanDevice, MatchDriver and MatchDevice.
*
* @param dev The device file to use.
* @param info The struct to fill with the given info.
*/
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;
}
/**
* Scan all /dev/input/event* devices. If a driver is available for one, try
* to get a device going on it (either creating a new one or switching it on).
* After the scan, switch off all devices that didn't get switched on in the
* previous run through the device files.
*/
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;
}
/**
* Start up the evdev brain device.
* Without the brain device, evdev won't be of a lot of use, so if this method
* fails you just shot yourself in the foot.
*
* If the evdev brain was already started up, this method returns TRUE.
*
* Returns TRUE on success or FALSE otherwise.
*/
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;
}
/**
* Prepend a new driver to the global driver list and rescan all devices.
* evdevStart() must be called before.
*
* @param driver The new driver to be prepended
*
* @return TRUE on success or FALSE if the driver's callback wasn't setup.
*/
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;
}
/**
* Search all drivers for the given device. If it exists, remove the device.
* Note that this does not remove the driver, so after calling this function
* with a valid device, there may be a driver without a device floating
* around.
*
* @param pEvdev The device to remove.
*/
void
evdevRemoveDevice (evdevDevicePtr pEvdev)
{
evdevDriverPtr driver, prev;
evdevDevicePtr *device;
prev = evdev_drivers;
for (driver = evdev_drivers; driver; prev = driver, driver = driver->next) {
for (device = &driver->devices; *device; device = &(*device)->next) {
if (*device == pEvdev) {
*device = pEvdev->next;
pEvdev->next = NULL;
/* driver without device? get rid of it, otherwise it'll
* auto-hotplug when a device is plugged in again.
*/
if (!driver->devices)
{
evdevDeleteDevice(pEvdev);
evdevRemoveDriver(driver);
}
return;
}
}
}
}
/**
* Obtain various information using ioctls on the given socket. This
* information is used to determine if a device has axis, buttons or keys.
*
* @return TRUE on success or FALSE on error.
*/
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;
}
/**
* Free memory associated with device.
*/
void
evdevDeleteDevice(evdevDevicePtr pEvdev)
{
/* pEvdev->pInp is freed in xf86DeleteInput() when
* DeleteInputDeviceRequest is called. */
xfree(pEvdev->name);
xfree(pEvdev->phys);
xfree(pEvdev->device);
xfree(pEvdev);
}
/**
* Remove a driver from the list, free memory.
*/
void evdevRemoveDriver(evdevDriverPtr drv)
{
evdevDriverPtr driver, prev;
evdevDevicePtr device;
if (drv == evdev_drivers)
evdev_drivers = evdev_drivers->next;
else
for (prev = evdev_drivers, driver = prev->next; driver;
prev = driver, driver = driver->next)
{
if (driver == drv)
{
prev->next = driver->next;
}
}
xfree(drv->name);
xfree(drv->phys);
xfree(drv->device);
device = drv->devices;
while(device)
{
evdevDeleteDevice(device);
device = device->next;
}
xfree(drv);
}