mirror of
https://github.com/X11Libre/xf86-input-synaptics.git
synced 2026-04-14 11:54:16 +00:00
290 lines
6.4 KiB
C
290 lines
6.4 KiB
C
/*
|
|
* Copyright 2004 Peter Osterlund <petero2@telia.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
#include "eventcomm.h"
|
|
#include "synproto.h"
|
|
#include "synaptics.h"
|
|
#include <xf86.h>
|
|
|
|
|
|
|
|
#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
|
|
|
|
/* list of supported devices */
|
|
static struct device_id_table {
|
|
unsigned short bustype;
|
|
unsigned short vendor;
|
|
unsigned short product;
|
|
} device_id_table[] = {
|
|
{ BUS_I8042, 0x0002, PSMOUSE_SYNAPTICS },
|
|
{ BUS_USB, USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_CPAD },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
|
|
/*****************************************************************************
|
|
* Function Definitions
|
|
****************************************************************************/
|
|
|
|
static void
|
|
EventDeviceOnHook(LocalDevicePtr local)
|
|
{
|
|
/* Try to grab the event device so that data don't leak to /dev/input/mice */
|
|
int ret;
|
|
SYSCALL(ret = ioctl(local->fd, EVIOCGRAB, (pointer)1));
|
|
if (ret < 0) {
|
|
xf86Msg(X_WARNING, "%s can't grab event device, errno=%d\n",
|
|
local->name, errno);
|
|
}
|
|
}
|
|
|
|
static void
|
|
EventDeviceOffHook(LocalDevicePtr local)
|
|
{
|
|
}
|
|
|
|
static Bool
|
|
event_query_is_synaptics(int fd)
|
|
{
|
|
struct input_id id;
|
|
int ret, i;
|
|
|
|
SYSCALL(ret = ioctl(fd, EVIOCGID, &id));
|
|
if (ret >= 0) {
|
|
for (i = 0; device_id_table[i].bustype; i++) {
|
|
if ((id.bustype == device_id_table[i].bustype) &&
|
|
(id.vendor == device_id_table[i].vendor) &&
|
|
(id.product == device_id_table[i].product)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
event_query_is_alps(int fd)
|
|
{
|
|
struct input_id id;
|
|
int ret;
|
|
|
|
SYSCALL(ret = ioctl(fd, EVIOCGID, &id));
|
|
if (ret >= 0) {
|
|
if ((id.bustype == BUS_I8042) &&
|
|
(id.vendor == 0x0002) &&
|
|
(id.product == PSMOUSE_ALPS)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
EventQueryHardware(LocalDevicePtr local, struct SynapticsHwInfo *synhw)
|
|
{
|
|
if (event_query_is_synaptics(local->fd))
|
|
xf86Msg(X_PROBED, "%s synaptics touchpad found\n", local->name);
|
|
else if (event_query_is_alps(local->fd))
|
|
xf86Msg(X_PROBED, "%s ALPS touchpad found\n", local->name);
|
|
|
|
/* Always return true. The device could be an ALPS touchpad in disguise. */
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
SynapticsReadEvent(struct CommData *comm, struct input_event *ev)
|
|
{
|
|
int i, c;
|
|
unsigned char *pBuf, u;
|
|
|
|
for (i = 0; i < sizeof(struct input_event); i++) {
|
|
if ((c = XisbRead(comm->buffer)) < 0)
|
|
return FALSE;
|
|
u = (unsigned char)c;
|
|
pBuf = (unsigned char *)ev;
|
|
pBuf[i] = u;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
EventReadHwState(LocalDevicePtr local, struct SynapticsHwInfo *synhw,
|
|
struct SynapticsProtocolOperations *proto_ops,
|
|
struct CommData *comm, struct SynapticsHwState *hwRet)
|
|
{
|
|
struct input_event ev;
|
|
Bool v;
|
|
struct SynapticsHwState *hw = &(comm->hwState);
|
|
|
|
while (SynapticsReadEvent(comm, &ev)) {
|
|
switch (ev.type) {
|
|
case EV_SYN:
|
|
switch (ev.code) {
|
|
case SYN_REPORT:
|
|
if (comm->oneFinger)
|
|
hw->numFingers = 1;
|
|
else if (comm->twoFingers)
|
|
hw->numFingers = 2;
|
|
else if (comm->threeFingers)
|
|
hw->numFingers = 3;
|
|
else
|
|
hw->numFingers = 0;
|
|
*hwRet = *hw;
|
|
hw->guest_dx = hw->guest_dy = 0;
|
|
return TRUE;
|
|
}
|
|
case EV_KEY:
|
|
v = (ev.value ? TRUE : FALSE);
|
|
switch (ev.code) {
|
|
case BTN_LEFT:
|
|
hw->left = v;
|
|
break;
|
|
case BTN_RIGHT:
|
|
hw->right = v;
|
|
break;
|
|
case BTN_MIDDLE:
|
|
hw->middle = v;
|
|
break;
|
|
case BTN_FORWARD:
|
|
hw->up = v;
|
|
break;
|
|
case BTN_BACK:
|
|
hw->down = v;
|
|
break;
|
|
case BTN_0:
|
|
hw->multi[0] = v;
|
|
break;
|
|
case BTN_1:
|
|
hw->multi[1] = v;
|
|
break;
|
|
case BTN_2:
|
|
hw->multi[2] = v;
|
|
break;
|
|
case BTN_3:
|
|
hw->multi[3] = v;
|
|
break;
|
|
case BTN_4:
|
|
hw->multi[4] = v;
|
|
break;
|
|
case BTN_5:
|
|
hw->multi[5] = v;
|
|
break;
|
|
case BTN_6:
|
|
hw->multi[6] = v;
|
|
break;
|
|
case BTN_7:
|
|
hw->multi[7] = v;
|
|
break;
|
|
case BTN_TOOL_FINGER:
|
|
comm->oneFinger = v;
|
|
break;
|
|
case BTN_TOOL_DOUBLETAP:
|
|
comm->twoFingers = v;
|
|
break;
|
|
case BTN_TOOL_TRIPLETAP:
|
|
comm->threeFingers = v;
|
|
break;
|
|
case BTN_A:
|
|
hw->guest_left = v;
|
|
break;
|
|
case BTN_B:
|
|
hw->guest_right = v;
|
|
break;
|
|
}
|
|
break;
|
|
case EV_ABS:
|
|
switch (ev.code) {
|
|
case ABS_X:
|
|
hw->x = ev.value;
|
|
break;
|
|
case ABS_Y:
|
|
hw->y = ev.value;
|
|
break;
|
|
case ABS_PRESSURE:
|
|
hw->z = ev.value;
|
|
break;
|
|
case ABS_TOOL_WIDTH:
|
|
hw->fingerWidth = ev.value;
|
|
break;
|
|
}
|
|
break;
|
|
case EV_REL:
|
|
switch (ev.code) {
|
|
case REL_X:
|
|
hw->guest_dx = ev.value;
|
|
break;
|
|
case REL_Y:
|
|
hw->guest_dy = ev.value;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
EventAutoDevProbe(LocalDevicePtr local)
|
|
{
|
|
/* We are trying to find the right eventX device or fall back to
|
|
the psaux protocol and the given device from XF86Config */
|
|
int i;
|
|
Bool have_evdev = FALSE;
|
|
|
|
for (i = 0; ; i++) {
|
|
char fname[64];
|
|
int fd = -1;
|
|
Bool is_touchpad;
|
|
|
|
sprintf(fname, "%s/%s%d", DEV_INPUT_EVENT, EVENT_DEV_NAME, i);
|
|
SYSCALL(fd = open(fname, O_RDONLY));
|
|
if (fd < 0) {
|
|
if (errno == ENOENT) {
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
have_evdev = TRUE;
|
|
is_touchpad = (event_query_is_synaptics(fd) ||
|
|
event_query_is_alps(fd));
|
|
SYSCALL(close(fd));
|
|
if (is_touchpad) {
|
|
xf86Msg(X_PROBED, "%s auto-dev sets device to %s\n",
|
|
local->name, fname);
|
|
xf86ReplaceStrOption(local->options, "Device", fname);
|
|
return TRUE;
|
|
}
|
|
}
|
|
ErrorF("%s no synaptics event device found (checked %d nodes)\n",
|
|
local->name, i + 1);
|
|
if (i > 0 && !have_evdev)
|
|
ErrorF("%s The evdev kernel module seems to be missing\n", local->name);
|
|
return FALSE;
|
|
}
|
|
|
|
struct SynapticsProtocolOperations event_proto_operations = {
|
|
EventDeviceOnHook,
|
|
EventDeviceOffHook,
|
|
EventQueryHardware,
|
|
EventReadHwState,
|
|
EventAutoDevProbe
|
|
};
|