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