eventcomm.c revision b85037db
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)] & (1 << OFF(bit)))
53
54/*****************************************************************************
55 *	Function Definitions
56 ****************************************************************************/
57
58static void
59EventDeviceOnHook(LocalDevicePtr local, SynapticsParameters *para)
60{
61    SynapticsPrivate *priv = (SynapticsPrivate *)local->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(local->fd, EVIOCGRAB, (pointer)1));
73	if (ret < 0) {
74	    xf86Msg(X_WARNING, "%s can't grab event device, errno=%d\n",
75		    local->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(LocalDevicePtr local)
152{
153    SynapticsPrivate *priv = (SynapticsPrivate *)local->private;
154    short id[4];
155    int rc;
156    model_lookup_t *model_lookup;
157
158    SYSCALL(rc = ioctl(local->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(LocalDevicePtr local)
172{
173    SynapticsPrivate *priv = (SynapticsPrivate *)local->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(local->fd, EVIOCGABS(ABS_X), &abs));
181    if (rc >= 0)
182    {
183	xf86Msg(X_PROBED, "%s: x-axis range %d - %d\n", local->name,
184		abs.minimum, abs.maximum);
185	priv->minx = abs.minimum;
186	priv->maxx = abs.maximum;
187#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
188	priv->resx = abs.resolution;
189#endif
190    } else
191	xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", local->name,
192		strerror(errno));
193
194    SYSCALL(rc = ioctl(local->fd, EVIOCGABS(ABS_Y), &abs));
195    if (rc >= 0)
196    {
197	xf86Msg(X_PROBED, "%s: y-axis range %d - %d\n", local->name,
198		abs.minimum, abs.maximum);
199	priv->miny = abs.minimum;
200	priv->maxy = abs.maximum;
201#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
202	priv->resy = abs.resolution;
203#endif
204    } else
205	xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", local->name,
206		strerror(errno));
207
208    priv->has_pressure = FALSE;
209    priv->has_width = FALSE;
210    SYSCALL(rc = ioctl(local->fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
211    if (rc >= 0)
212    {
213	priv->has_pressure = (TEST_BIT(ABS_PRESSURE, absbits) != 0);
214	priv->has_width = (TEST_BIT(ABS_TOOL_WIDTH, absbits) != 0);
215    }
216    else
217	xf86Msg(X_ERROR, "%s: failed to query ABS bits (%s)\n", local->name,
218		strerror(errno));
219
220    if (priv->has_pressure)
221    {
222	SYSCALL(rc = ioctl(local->fd, EVIOCGABS(ABS_PRESSURE), &abs));
223	if (rc >= 0)
224	{
225	    xf86Msg(X_PROBED, "%s: pressure range %d - %d\n", local->name,
226		    abs.minimum, abs.maximum);
227	    priv->minp = abs.minimum;
228	    priv->maxp = abs.maximum;
229	}
230    } else
231	xf86Msg(X_INFO,
232		"%s: device does not report pressure, will use touch data.\n",
233		local->name);
234
235    if (priv->has_width)
236    {
237	SYSCALL(rc = ioctl(local->fd, EVIOCGABS(ABS_TOOL_WIDTH), &abs));
238	if (rc >= 0)
239	{
240	    xf86Msg(X_PROBED, "%s: finger width range %d - %d\n", local->name,
241		    abs.minimum, abs.maximum);
242	    priv->minw = abs.minimum;
243	    priv->maxw = abs.maximum;
244	}
245    }
246
247    SYSCALL(rc = ioctl(local->fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
248    if (rc >= 0)
249    {
250	buf[0] = 0;
251	if ((priv->has_left = (TEST_BIT(BTN_LEFT, keybits) != 0)))
252	   strcat(buf, " left");
253	if ((priv->has_right = (TEST_BIT(BTN_RIGHT, keybits) != 0)))
254	   strcat(buf, " right");
255	if ((priv->has_middle = (TEST_BIT(BTN_MIDDLE, keybits) != 0)))
256	   strcat(buf, " middle");
257	if ((priv->has_double = (TEST_BIT(BTN_TOOL_DOUBLETAP, keybits) != 0)))
258	   strcat(buf, " double");
259	if ((priv->has_triple = (TEST_BIT(BTN_TOOL_TRIPLETAP, keybits) != 0)))
260	   strcat(buf, " triple");
261
262	if ((TEST_BIT(BTN_0, keybits) != 0) ||
263	    (TEST_BIT(BTN_1, keybits) != 0) ||
264	    (TEST_BIT(BTN_2, keybits) != 0) ||
265	    (TEST_BIT(BTN_3, keybits) != 0))
266	{
267	    priv->has_scrollbuttons = 1;
268	    strcat(buf, " scroll-buttons");
269	}
270
271	xf86Msg(X_PROBED, "%s: buttons:%s\n", local->name, buf);
272    }
273}
274
275static Bool
276EventQueryHardware(LocalDevicePtr local)
277{
278    SynapticsPrivate *priv = (SynapticsPrivate *)local->private;
279    BOOL *need_grab = (BOOL*)priv->proto_data;
280
281    if (!event_query_is_touchpad(local->fd, (need_grab) ? *need_grab : TRUE))
282	return FALSE;
283
284    xf86Msg(X_PROBED, "%s: touchpad found\n", local->name);
285
286    return TRUE;
287}
288
289static Bool
290SynapticsReadEvent(LocalDevicePtr local, struct input_event *ev)
291{
292    int rc = TRUE;
293    ssize_t len;
294
295    len = read(local->fd, ev, sizeof(*ev));
296    if (len <= 0)
297    {
298        /* We use X_NONE here because it doesn't alloc */
299        if (errno != EAGAIN)
300            xf86MsgVerb(X_NONE, 0, "%s: Read error %s\n", local->name, strerror(errno));
301        rc = FALSE;
302    } else if (len % sizeof(*ev)) {
303        xf86MsgVerb(X_NONE, 0, "%s: Read error, invalid number of bytes.", local->name);
304        rc = FALSE;
305    }
306    return rc;
307}
308
309static Bool
310EventReadHwState(LocalDevicePtr local,
311		 struct SynapticsProtocolOperations *proto_ops,
312		 struct CommData *comm, struct SynapticsHwState *hwRet)
313{
314    struct input_event ev;
315    Bool v;
316    struct SynapticsHwState *hw = &(comm->hwState);
317    SynapticsPrivate *priv = (SynapticsPrivate *)local->private;
318    SynapticsParameters *para = &priv->synpara;
319
320    while (SynapticsReadEvent(local, &ev)) {
321	switch (ev.type) {
322	case EV_SYN:
323	    switch (ev.code) {
324	    case SYN_REPORT:
325		if (comm->oneFinger)
326		    hw->numFingers = 1;
327		else if (comm->twoFingers)
328		    hw->numFingers = 2;
329		else if (comm->threeFingers)
330		    hw->numFingers = 3;
331		else
332		    hw->numFingers = 0;
333		*hwRet = *hw;
334		return TRUE;
335	    }
336	case EV_KEY:
337	    v = (ev.value ? TRUE : FALSE);
338	    switch (ev.code) {
339	    case BTN_LEFT:
340		hw->left = v;
341		break;
342	    case BTN_RIGHT:
343		hw->right = v;
344		break;
345	    case BTN_MIDDLE:
346		hw->middle = v;
347		break;
348	    case BTN_FORWARD:
349		hw->up = v;
350		break;
351	    case BTN_BACK:
352		hw->down = v;
353		break;
354	    case BTN_0:
355		hw->multi[0] = v;
356		break;
357	    case BTN_1:
358		hw->multi[1] = v;
359		break;
360	    case BTN_2:
361		hw->multi[2] = v;
362		break;
363	    case BTN_3:
364		hw->multi[3] = v;
365		break;
366	    case BTN_4:
367		hw->multi[4] = v;
368		break;
369	    case BTN_5:
370		hw->multi[5] = v;
371		break;
372	    case BTN_6:
373		hw->multi[6] = v;
374		break;
375	    case BTN_7:
376		hw->multi[7] = v;
377		break;
378	    case BTN_TOOL_FINGER:
379		comm->oneFinger = v;
380		break;
381	    case BTN_TOOL_DOUBLETAP:
382		comm->twoFingers = v;
383		break;
384	    case BTN_TOOL_TRIPLETAP:
385		comm->threeFingers = v;
386		break;
387	    case BTN_TOUCH:
388		if (!priv->has_pressure)
389			hw->z = v ? para->finger_high + 1 : 0;
390		break;
391	    }
392	    break;
393	case EV_ABS:
394	    switch (ev.code) {
395	    case ABS_X:
396		hw->x = ev.value;
397		break;
398	    case ABS_Y:
399		hw->y = ev.value;
400		break;
401	    case ABS_PRESSURE:
402		hw->z = ev.value;
403		break;
404	    case ABS_TOOL_WIDTH:
405		hw->fingerWidth = ev.value;
406		break;
407	    }
408	    break;
409	}
410    }
411    return FALSE;
412}
413
414/* filter for the AutoDevProbe scandir on /dev/input */
415static int EventDevOnly(const struct dirent *dir) {
416	return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
417}
418
419/**
420 * Probe the open device for dimensions.
421 */
422static void
423EventReadDevDimensions(LocalDevicePtr local)
424{
425    SynapticsPrivate *priv = (SynapticsPrivate *)local->private;
426    BOOL *need_grab = (BOOL*)priv->proto_data;
427
428    if (event_query_is_touchpad(local->fd, (need_grab) ? *need_grab : TRUE))
429	event_query_axis_ranges(local);
430    event_query_info(local);
431}
432
433static Bool
434EventAutoDevProbe(LocalDevicePtr local)
435{
436    /* We are trying to find the right eventX device or fall back to
437       the psaux protocol and the given device from XF86Config */
438    int i;
439    Bool touchpad_found = FALSE;
440    struct dirent **namelist;
441
442    i = scandir(DEV_INPUT_EVENT, &namelist, EventDevOnly, alphasort);
443    if (i < 0) {
444		xf86Msg(X_ERROR, "Couldn't open %s\n", DEV_INPUT_EVENT);
445		return FALSE;
446    }
447    else if (i == 0) {
448		xf86Msg(X_ERROR, "%s The /dev/input/event* device nodes seem to be missing\n",
449				local->name);
450		free(namelist);
451		return FALSE;
452    }
453
454    while (i--) {
455		char fname[64];
456		int fd = -1;
457
458		if (!touchpad_found) {
459			sprintf(fname, "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
460			SYSCALL(fd = open(fname, O_RDONLY));
461			if (fd < 0)
462				continue;
463
464			if (event_query_is_touchpad(fd, TRUE)) {
465				touchpad_found = TRUE;
466			    xf86Msg(X_PROBED, "%s auto-dev sets device to %s\n",
467				    local->name, fname);
468			    local->options =
469			    	xf86ReplaceStrOption(local->options, "Device", fname);
470			}
471			SYSCALL(close(fd));
472		}
473		free(namelist[i]);
474    }
475	free(namelist);
476
477	if (!touchpad_found) {
478		xf86Msg(X_ERROR, "%s no synaptics event device found\n", local->name);
479		return FALSE;
480	}
481    return TRUE;
482}
483
484struct SynapticsProtocolOperations event_proto_operations = {
485    EventDeviceOnHook,
486    NULL,
487    EventQueryHardware,
488    EventReadHwState,
489    EventAutoDevProbe,
490    EventReadDevDimensions
491};
492