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