mirror of
https://github.com/X11Libre/xf86-input-evdev.git
synced 2026-04-14 11:44:16 +00:00
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:
@@ -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
|
||||
|
||||
228
src/evdev.c
228
src/evdev.c
@@ -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
|
||||
|
||||
79
src/evdev.h
79
src/evdev.h
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user