eventcomm.c revision 302b15bd
1/*
2 * Copyright © 2004-2007 Peter Osterlund
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of Red Hat
9 * not be used in advertising or publicity pertaining to distribution
10 * of the software without specific, written prior permission.  Red
11 * Hat makes no representations about the suitability of this software
12 * for any purpose.  It is provided "as is" without express or implied
13 * warranty.
14 *
15 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Authors:
24 *      Peter Osterlund (petero2@telia.com)
25 */
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <xorg-server.h>
32#include "eventcomm.h"
33#include <errno.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <fcntl.h>
37#include <dirent.h>
38#include <string.h>
39#include <stdio.h>
40#include "synproto.h"
41#include "synaptics.h"
42#include "synapticsstr.h"
43#include <xf86.h>
44
45
46#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
47
48#define LONG_BITS (sizeof(long) * 8)
49#define NBITS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
50#define OFF(x)   ((x) % LONG_BITS)
51#define LONG(x)  ((x) / LONG_BITS)
52#define TEST_BIT(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
53
54/*****************************************************************************
55 *	Function Definitions
56 ****************************************************************************/
57
58static void
59EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters *para)
60{
61    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
62    BOOL *need_grab;
63
64    if (!priv->proto_data)
65        priv->proto_data = calloc(1, sizeof(BOOL));
66
67    need_grab = (BOOL*)priv->proto_data;
68
69    if (para->grab_event_device) {
70	/* Try to grab the event device so that data don't leak to /dev/input/mice */
71	int ret;
72	SYSCALL(ret = ioctl(pInfo->fd, EVIOCGRAB, (pointer)1));
73	if (ret < 0) {
74	    xf86Msg(X_WARNING, "%s can't grab event device, errno=%d\n",
75		    pInfo->name, errno);
76	}
77    }
78
79    *need_grab = FALSE;
80}
81
82static Bool
83event_query_is_touchpad(int fd, BOOL grab)
84{
85    int ret = FALSE, rc;
86    unsigned long evbits[NBITS(EV_MAX)] = {0};
87    unsigned long absbits[NBITS(ABS_MAX)] = {0};
88    unsigned long keybits[NBITS(KEY_MAX)] = {0};
89
90    if (grab)
91    {
92        SYSCALL(rc = ioctl(fd, EVIOCGRAB, (pointer)1));
93        if (rc < 0)
94            return FALSE;
95    }
96
97    /* Check for ABS_X, ABS_Y, ABS_PRESSURE and BTN_TOOL_FINGER */
98
99    SYSCALL(rc = ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits));
100    if (rc < 0)
101	goto unwind;
102    if (!TEST_BIT(EV_SYN, evbits) ||
103	!TEST_BIT(EV_ABS, evbits) ||
104	!TEST_BIT(EV_KEY, evbits))
105	goto unwind;
106
107    SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
108    if (rc < 0)
109	goto unwind;
110    if (!TEST_BIT(ABS_X, absbits) ||
111	!TEST_BIT(ABS_Y, absbits))
112	goto unwind;
113
114    SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
115    if (rc < 0)
116	goto unwind;
117
118    /* we expect touchpad either report raw pressure or touches */
119    if (!TEST_BIT(ABS_PRESSURE, absbits) && !TEST_BIT(BTN_TOUCH, keybits))
120	goto unwind;
121    /* all Synaptics-like touchpad report BTN_TOOL_FINGER */
122    if (!TEST_BIT(BTN_TOOL_FINGER, keybits))
123	goto unwind;
124    if (TEST_BIT(BTN_TOOL_PEN, keybits))
125	goto unwind;			    /* Don't match wacom tablets */
126
127    ret = TRUE;
128
129unwind:
130    if (grab)
131        SYSCALL(ioctl(fd, EVIOCGRAB, (pointer)0));
132
133    return (ret == TRUE);
134}
135
136typedef struct {
137	short vendor;
138	short product;
139	enum TouchpadModel model;
140} model_lookup_t;
141#define PRODUCT_ANY 0x0000
142
143static model_lookup_t model_lookup_table[] = {
144	{0x0002, 0x0007, MODEL_SYNAPTICS},
145	{0x0002, 0x0008, MODEL_ALPS},
146	{0x05ac, PRODUCT_ANY, MODEL_APPLETOUCH},
147	{0x0, 0x0, 0x0}
148};
149
150static void
151event_query_info(InputInfoPtr pInfo)
152{
153    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
154    short id[4];
155    int rc;
156    model_lookup_t *model_lookup;
157
158    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGID, id));
159    if (rc < 0)
160        return;
161
162    for(model_lookup = model_lookup_table; model_lookup->vendor; model_lookup++) {
163        if(model_lookup->vendor == id[ID_VENDOR] &&
164           (model_lookup->product == id[ID_PRODUCT] || model_lookup->product == PRODUCT_ANY))
165            priv->model = model_lookup->model;
166    }
167}
168
169/* Query device for axis ranges */
170static void
171event_query_axis_ranges(InputInfoPtr pInfo)
172{
173    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
174    struct input_absinfo abs = {0};
175    unsigned long absbits[NBITS(ABS_MAX)] = {0};
176    unsigned long keybits[NBITS(KEY_MAX)] = {0};
177    char buf[256];
178    int rc;
179
180    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_X), &abs));
181    if (rc >= 0)
182    {
183	xf86Msg(X_PROBED, "%s: x-axis range %d - %d\n", pInfo->name,
184		abs.minimum, abs.maximum);
185	priv->minx = abs.minimum;
186	priv->maxx = abs.maximum;
187	/* The kernel's fuzziness concept seems a bit weird, but it can more or
188	 * less be applied as hysteresis directly, i.e. no factor here. Though,
189	 * we don't trust a zero fuzz as it probably is just a lazy value. */
190	if (abs.fuzz > 0)
191	    priv->synpara.hyst_x = abs.fuzz;
192#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
193	priv->resx = abs.resolution;
194#endif
195    } else
196	xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", pInfo->name,
197		strerror(errno));
198
199    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_Y), &abs));
200    if (rc >= 0)
201    {
202	xf86Msg(X_PROBED, "%s: y-axis range %d - %d\n", pInfo->name,
203		abs.minimum, abs.maximum);
204	priv->miny = abs.minimum;
205	priv->maxy = abs.maximum;
206	/* don't trust a zero fuzz */
207	if (abs.fuzz > 0)
208	    priv->synpara.hyst_y = abs.fuzz;
209#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
210	priv->resy = abs.resolution;
211#endif
212    } else
213	xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", pInfo->name,
214		strerror(errno));
215
216    priv->has_pressure = FALSE;
217    priv->has_width = FALSE;
218    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
219    if (rc >= 0)
220    {
221	priv->has_pressure = (TEST_BIT(ABS_PRESSURE, absbits) != 0);
222	priv->has_width = (TEST_BIT(ABS_TOOL_WIDTH, absbits) != 0);
223    }
224    else
225	xf86Msg(X_ERROR, "%s: failed to query ABS bits (%s)\n", pInfo->name,
226		strerror(errno));
227
228    if (priv->has_pressure)
229    {
230	SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_PRESSURE), &abs));
231	if (rc >= 0)
232	{
233	    xf86Msg(X_PROBED, "%s: pressure range %d - %d\n", pInfo->name,
234		    abs.minimum, abs.maximum);
235	    priv->minp = abs.minimum;
236	    priv->maxp = abs.maximum;
237	}
238    } else
239	xf86Msg(X_INFO,
240		"%s: device does not report pressure, will use touch data.\n",
241		pInfo->name);
242
243    if (priv->has_width)
244    {
245	SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_TOOL_WIDTH), &abs));
246	if (rc >= 0)
247	{
248	    xf86Msg(X_PROBED, "%s: finger width range %d - %d\n", pInfo->name,
249		    abs.minimum, abs.maximum);
250	    priv->minw = abs.minimum;
251	    priv->maxw = abs.maximum;
252	}
253    }
254
255    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
256    if (rc >= 0)
257    {
258	buf[0] = 0;
259	if ((priv->has_left = (TEST_BIT(BTN_LEFT, keybits) != 0)))
260	   strcat(buf, " left");
261	if ((priv->has_right = (TEST_BIT(BTN_RIGHT, keybits) != 0)))
262	   strcat(buf, " right");
263	if ((priv->has_middle = (TEST_BIT(BTN_MIDDLE, keybits) != 0)))
264	   strcat(buf, " middle");
265	if ((priv->has_double = (TEST_BIT(BTN_TOOL_DOUBLETAP, keybits) != 0)))
266	   strcat(buf, " double");
267	if ((priv->has_triple = (TEST_BIT(BTN_TOOL_TRIPLETAP, keybits) != 0)))
268	   strcat(buf, " triple");
269
270	if ((TEST_BIT(BTN_0, keybits) != 0) ||
271	    (TEST_BIT(BTN_1, keybits) != 0) ||
272	    (TEST_BIT(BTN_2, keybits) != 0) ||
273	    (TEST_BIT(BTN_3, keybits) != 0))
274	{
275	    priv->has_scrollbuttons = 1;
276	    strcat(buf, " scroll-buttons");
277	}
278
279	xf86Msg(X_PROBED, "%s: buttons:%s\n", pInfo->name, buf);
280    }
281}
282
283static Bool
284EventQueryHardware(InputInfoPtr pInfo)
285{
286    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
287    BOOL *need_grab = (BOOL*)priv->proto_data;
288
289    if (!event_query_is_touchpad(pInfo->fd, (need_grab) ? *need_grab : TRUE))
290	return FALSE;
291
292    xf86Msg(X_PROBED, "%s: touchpad found\n", pInfo->name);
293
294    return TRUE;
295}
296
297static Bool
298SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
299{
300    int rc = TRUE;
301    ssize_t len;
302
303    len = read(pInfo->fd, ev, sizeof(*ev));
304    if (len <= 0)
305    {
306        /* We use X_NONE here because it doesn't alloc */
307        if (errno != EAGAIN)
308            xf86MsgVerb(X_NONE, 0, "%s: Read error %s\n", pInfo->name, strerror(errno));
309        rc = FALSE;
310    } else if (len % sizeof(*ev)) {
311        xf86MsgVerb(X_NONE, 0, "%s: Read error, invalid number of bytes.", pInfo->name);
312        rc = FALSE;
313    }
314    return rc;
315}
316
317static Bool
318EventReadHwState(InputInfoPtr pInfo,
319		 struct SynapticsProtocolOperations *proto_ops,
320		 struct CommData *comm, struct SynapticsHwState *hwRet)
321{
322    struct input_event ev;
323    Bool v;
324    struct SynapticsHwState *hw = &(comm->hwState);
325    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
326    SynapticsParameters *para = &priv->synpara;
327
328    while (SynapticsReadEvent(pInfo, &ev)) {
329	switch (ev.type) {
330	case EV_SYN:
331	    switch (ev.code) {
332	    case SYN_REPORT:
333		if (comm->oneFinger)
334		    hw->numFingers = 1;
335		else if (comm->twoFingers)
336		    hw->numFingers = 2;
337		else if (comm->threeFingers)
338		    hw->numFingers = 3;
339		else
340		    hw->numFingers = 0;
341		*hwRet = *hw;
342		return TRUE;
343	    }
344	    break;
345	case EV_KEY:
346	    v = (ev.value ? TRUE : FALSE);
347	    switch (ev.code) {
348	    case BTN_LEFT:
349		hw->left = v;
350		break;
351	    case BTN_RIGHT:
352		hw->right = v;
353		break;
354	    case BTN_MIDDLE:
355		hw->middle = v;
356		break;
357	    case BTN_FORWARD:
358		hw->up = v;
359		break;
360	    case BTN_BACK:
361		hw->down = v;
362		break;
363	    case BTN_0:
364		hw->multi[0] = v;
365		break;
366	    case BTN_1:
367		hw->multi[1] = v;
368		break;
369	    case BTN_2:
370		hw->multi[2] = v;
371		break;
372	    case BTN_3:
373		hw->multi[3] = v;
374		break;
375	    case BTN_4:
376		hw->multi[4] = v;
377		break;
378	    case BTN_5:
379		hw->multi[5] = v;
380		break;
381	    case BTN_6:
382		hw->multi[6] = v;
383		break;
384	    case BTN_7:
385		hw->multi[7] = v;
386		break;
387	    case BTN_TOOL_FINGER:
388		comm->oneFinger = v;
389		break;
390	    case BTN_TOOL_DOUBLETAP:
391		comm->twoFingers = v;
392		break;
393	    case BTN_TOOL_TRIPLETAP:
394		comm->threeFingers = v;
395		break;
396	    case BTN_TOUCH:
397		if (!priv->has_pressure)
398			hw->z = v ? para->finger_high + 1 : 0;
399		break;
400	    }
401	    break;
402	case EV_ABS:
403	    switch (ev.code) {
404	    case ABS_X:
405		hw->x = ev.value;
406		break;
407	    case ABS_Y:
408		hw->y = ev.value;
409		break;
410	    case ABS_PRESSURE:
411		hw->z = ev.value;
412		break;
413	    case ABS_TOOL_WIDTH:
414		hw->fingerWidth = ev.value;
415		break;
416	    }
417	    break;
418	}
419    }
420    return FALSE;
421}
422
423/* filter for the AutoDevProbe scandir on /dev/input */
424static int EventDevOnly(const struct dirent *dir) {
425	return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
426}
427
428/**
429 * Probe the open device for dimensions.
430 */
431static void
432EventReadDevDimensions(InputInfoPtr pInfo)
433{
434    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
435    BOOL *need_grab = (BOOL*)priv->proto_data;
436
437    if (event_query_is_touchpad(pInfo->fd, (need_grab) ? *need_grab : TRUE))
438	event_query_axis_ranges(pInfo);
439    event_query_info(pInfo);
440}
441
442static Bool
443EventAutoDevProbe(InputInfoPtr pInfo)
444{
445    /* We are trying to find the right eventX device or fall back to
446       the psaux protocol and the given device from XF86Config */
447    int i;
448    Bool touchpad_found = FALSE;
449    struct dirent **namelist;
450
451    i = scandir(DEV_INPUT_EVENT, &namelist, EventDevOnly, alphasort);
452    if (i < 0) {
453		xf86Msg(X_ERROR, "Couldn't open %s\n", DEV_INPUT_EVENT);
454		return FALSE;
455    }
456    else if (i == 0) {
457		xf86Msg(X_ERROR, "%s The /dev/input/event* device nodes seem to be missing\n",
458				pInfo->name);
459		free(namelist);
460		return FALSE;
461    }
462
463    while (i--) {
464		char fname[64];
465		int fd = -1;
466
467		if (!touchpad_found) {
468			sprintf(fname, "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
469			SYSCALL(fd = open(fname, O_RDONLY));
470			if (fd < 0)
471				continue;
472
473			if (event_query_is_touchpad(fd, TRUE)) {
474				touchpad_found = TRUE;
475			    xf86Msg(X_PROBED, "%s auto-dev sets device to %s\n",
476				    pInfo->name, fname);
477			    pInfo->options =
478			    	xf86ReplaceStrOption(pInfo->options, "Device", fname);
479			}
480			SYSCALL(close(fd));
481		}
482		free(namelist[i]);
483    }
484	free(namelist);
485
486	if (!touchpad_found) {
487		xf86Msg(X_ERROR, "%s no synaptics event device found\n", pInfo->name);
488		return FALSE;
489	}
490    return TRUE;
491}
492
493struct SynapticsProtocolOperations event_proto_operations = {
494    EventDeviceOnHook,
495    NULL,
496    EventQueryHardware,
497    EventReadHwState,
498    EventAutoDevProbe,
499    EventReadDevDimensions
500};
501