2 * Copyright © 2004-2007 Peter Osterlund
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
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.
24 * Peter Osterlund (petero2@telia.com)
31 #include <xorg-server.h>
32 #include "eventcomm.h"
34 #include <sys/types.h>
41 #include "synaptics.h"
42 #include "synapticsstr.h"
46 #define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
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)
54 /*****************************************************************************
55 * Function Definitions
56 ****************************************************************************/
59 EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters *para)
61 SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
64 if (!priv->proto_data)
65 priv->proto_data = calloc(1, sizeof(BOOL));
67 need_grab = (BOOL*)priv->proto_data;
69 if (para->grab_event_device) {
70 /* Try to grab the event device so that data don't leak to /dev/input/mice */
72 SYSCALL(ret = ioctl(pInfo->fd, EVIOCGRAB, (pointer)1));
74 xf86Msg(X_WARNING, "%s can't grab event device, errno=%d\n",
83 event_query_is_touchpad(int fd, BOOL grab)
86 unsigned long evbits[NBITS(EV_MAX)] = {0};
87 unsigned long absbits[NBITS(ABS_MAX)] = {0};
88 unsigned long keybits[NBITS(KEY_MAX)] = {0};
92 SYSCALL(rc = ioctl(fd, EVIOCGRAB, (pointer)1));
97 /* Check for ABS_X, ABS_Y, ABS_PRESSURE and BTN_TOOL_FINGER */
99 SYSCALL(rc = ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits));
102 if (!TEST_BIT(EV_SYN, evbits) ||
103 !TEST_BIT(EV_ABS, evbits) ||
104 !TEST_BIT(EV_KEY, evbits))
107 SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
110 if (!TEST_BIT(ABS_X, absbits) ||
111 !TEST_BIT(ABS_Y, absbits))
114 SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
118 /* we expect touchpad either report raw pressure or touches */
119 if (!TEST_BIT(ABS_PRESSURE, absbits) && !TEST_BIT(BTN_TOUCH, keybits))
121 /* all Synaptics-like touchpad report BTN_TOOL_FINGER */
122 if (!TEST_BIT(BTN_TOOL_FINGER, keybits))
124 if (TEST_BIT(BTN_TOOL_PEN, keybits))
125 goto unwind; /* Don't match wacom tablets */
131 SYSCALL(ioctl(fd, EVIOCGRAB, (pointer)0));
133 return (ret == TRUE);
139 enum TouchpadModel model;
141 #define PRODUCT_ANY 0x0000
143 static model_lookup_t model_lookup_table[] = {
144 {0x0002, 0x0007, MODEL_SYNAPTICS},
145 {0x0002, 0x0008, MODEL_ALPS},
146 {0x05ac, PRODUCT_ANY, MODEL_APPLETOUCH},
151 event_query_info(InputInfoPtr pInfo)
153 SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
156 model_lookup_t *model_lookup;
158 SYSCALL(rc = ioctl(pInfo->fd, EVIOCGID, id));
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;
169 /* Query device for axis ranges */
171 event_query_axis_ranges(InputInfoPtr pInfo)
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};
180 SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_X), &abs));
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. */
191 priv->synpara.hyst_x = abs.fuzz;
192 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
193 priv->resx = abs.resolution;
196 xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", pInfo->name,
199 SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_Y), &abs));
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 */
208 priv->synpara.hyst_y = abs.fuzz;
209 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
210 priv->resy = abs.resolution;
213 xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", pInfo->name,
216 priv->has_pressure = FALSE;
217 priv->has_width = FALSE;
218 SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
221 priv->has_pressure = (TEST_BIT(ABS_PRESSURE, absbits) != 0);
222 priv->has_width = (TEST_BIT(ABS_TOOL_WIDTH, absbits) != 0);
225 xf86Msg(X_ERROR, "%s: failed to query ABS bits (%s)\n", pInfo->name,
228 if (priv->has_pressure)
230 SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_PRESSURE), &abs));
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;
240 "%s: device does not report pressure, will use touch data.\n",
245 SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_TOOL_WIDTH), &abs));
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;
255 SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
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");
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))
275 priv->has_scrollbuttons = 1;
276 strcat(buf, " scroll-buttons");
279 xf86Msg(X_PROBED, "%s: buttons:%s\n", pInfo->name, buf);
284 EventQueryHardware(InputInfoPtr pInfo)
286 SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
287 BOOL *need_grab = (BOOL*)priv->proto_data;
289 if (!event_query_is_touchpad(pInfo->fd, (need_grab) ? *need_grab : TRUE))
292 xf86Msg(X_PROBED, "%s: touchpad found\n", pInfo->name);
298 SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
303 len = read(pInfo->fd, ev, sizeof(*ev));
306 /* We use X_NONE here because it doesn't alloc */
308 xf86MsgVerb(X_NONE, 0, "%s: Read error %s\n", pInfo->name, strerror(errno));
310 } else if (len % sizeof(*ev)) {
311 xf86MsgVerb(X_NONE, 0, "%s: Read error, invalid number of bytes.", pInfo->name);
318 EventReadHwState(InputInfoPtr pInfo,
319 struct SynapticsProtocolOperations *proto_ops,
320 struct CommData *comm, struct SynapticsHwState *hwRet)
322 struct input_event ev;
324 struct SynapticsHwState *hw = &(comm->hwState);
325 SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
326 SynapticsParameters *para = &priv->synpara;
328 while (SynapticsReadEvent(pInfo, &ev)) {
335 else if (comm->twoFingers)
337 else if (comm->threeFingers)
345 v = (ev.value ? TRUE : FALSE);
386 case BTN_TOOL_FINGER:
389 case BTN_TOOL_DOUBLETAP:
390 comm->twoFingers = v;
392 case BTN_TOOL_TRIPLETAP:
393 comm->threeFingers = v;
396 if (!priv->has_pressure)
397 hw->z = v ? para->finger_high + 1 : 0;
413 hw->fingerWidth = ev.value;
422 /* filter for the AutoDevProbe scandir on /dev/input */
423 static int EventDevOnly(const struct dirent *dir) {
424 return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
428 * Probe the open device for dimensions.
431 EventReadDevDimensions(InputInfoPtr pInfo)
433 SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
434 BOOL *need_grab = (BOOL*)priv->proto_data;
436 if (event_query_is_touchpad(pInfo->fd, (need_grab) ? *need_grab : TRUE))
437 event_query_axis_ranges(pInfo);
438 event_query_info(pInfo);
442 EventAutoDevProbe(InputInfoPtr pInfo)
444 /* We are trying to find the right eventX device or fall back to
445 the psaux protocol and the given device from XF86Config */
447 Bool touchpad_found = FALSE;
448 struct dirent **namelist;
450 i = scandir(DEV_INPUT_EVENT, &namelist, EventDevOnly, alphasort);
452 xf86Msg(X_ERROR, "Couldn't open %s\n", DEV_INPUT_EVENT);
456 xf86Msg(X_ERROR, "%s The /dev/input/event* device nodes seem to be missing\n",
466 if (!touchpad_found) {
467 sprintf(fname, "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
468 SYSCALL(fd = open(fname, O_RDONLY));
472 if (event_query_is_touchpad(fd, TRUE)) {
473 touchpad_found = TRUE;
474 xf86Msg(X_PROBED, "%s auto-dev sets device to %s\n",
477 xf86ReplaceStrOption(pInfo->options, "Device", fname);
485 if (!touchpad_found) {
486 xf86Msg(X_ERROR, "%s no synaptics event device found\n", pInfo->name);
492 struct SynapticsProtocolOperations event_proto_operations = {
498 EventReadDevDimensions