1/* 2 * Copyright � 1997 C. Scott Ananian 3 * Copyright � 1998-2000 Bruce Kalk 4 * Copyright � 2001 Stefan Gmeiner 5 * Copyright � 2002 Linuxcare Inc. David Kennedy 6 * Copyright � 2003 Fred Hucht <fred@thp.Uni-Duisburg.de> 7 * 8 * Permission to use, copy, modify, distribute, and sell this software 9 * and its documentation for any purpose is hereby granted without 10 * fee, provided that the above copyright notice appear in all copies 11 * and that both that copyright notice and this permission notice 12 * appear in supporting documentation, and that the name of Red Hat 13 * not be used in advertising or publicity pertaining to distribution 14 * of the software without specific, written prior permission. Red 15 * Hat makes no representations about the suitability of this software 16 * for any purpose. It is provided "as is" without express or implied 17 * warranty. 18 * 19 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 21 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 23 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 24 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 25 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 26 * 27 * Authors: 28 * Stefan Gmeiner (riddlebox@freesurf.ch) 29 * C. Scott Ananian (cananian@alumni.priceton.edu) 30 * Bruce Kalk (kall@compass.com) 31 * Linuxcare Inc. David Kennedy (dkennedy@linuxcare.com) 32 * Fred Hucht (fred@thp.Uni-Duisburg.de) 33 */ 34 35#ifdef HAVE_CONFIG_H 36#include "config.h" 37#endif 38 39#include <xorg-server.h> 40#include "synproto.h" 41#include "synapticsstr.h" 42#include "ps2comm.h" 43#include <xf86.h> 44 45#define MAX_UNSYNC_PACKETS 10 /* i.e. 10 to 60 bytes */ 46/* 47 * The x/y limits are taken from the Synaptics TouchPad interfacing Guide, 48 * section 2.3.2, which says that they should be valid regardless of the 49 * actual size of the sensor. 50 */ 51#define XMIN_NOMINAL 1472 52#define XMAX_NOMINAL 5472 53#define YMIN_NOMINAL 1408 54#define YMAX_NOMINAL 4448 55 56#define XMAX_VALID 6143 57 58/* synaptics queries */ 59#define SYN_QUE_IDENTIFY 0x00 60#define SYN_QUE_MODES 0x01 61#define SYN_QUE_CAPABILITIES 0x02 62#define SYN_QUE_MODEL 0x03 63#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06 64#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07 65#define SYN_QUE_RESOLUTION 0x08 66#define SYN_QUE_EXT_CAPAB 0x09 67 68/* status request response bits (PS2_CMD_STATUS_REQUEST) */ 69#define PS2_RES_REMOTE(r) ((r) & (1 << 22)) 70#define PS2_RES_ENABLE(r) ((r) & (1 << 21)) 71#define PS2_RES_SCALING(r) ((r) & (1 << 20)) 72#define PS2_RES_LEFT(r) ((r) & (1 << 18)) 73#define PS2_RES_MIDDLE(r) ((r) & (1 << 17)) 74#define PS2_RES_RIGHT(r) ((r) & (1 << 16)) 75#define PS2_RES_RESOLUTION(r) (((r) >> 8) & 0x03) 76#define PS2_RES_SAMPLE_RATE(r) ((r) & 0xff) 77 78#ifdef DEBUG 79#define PS2DBG(...) ErrorF(__VA_ARGS__) 80#else 81#define PS2DBG(...) 82#endif 83 84/***************************************************************************** 85 * PS/2 Utility functions. 86 * Many parts adapted from tpconfig.c by C. Scott Ananian 87 ****************************************************************************/ 88 89/* 90 * Read a byte from the ps/2 port 91 */ 92static Bool 93ps2_getbyte(int fd, byte * b) 94{ 95 if (xf86WaitForInput(fd, 50000) > 0) { 96 if (xf86ReadSerial(fd, b, 1) != 1) { 97 PS2DBG("ps2_getbyte: No byte read\n"); 98 return FALSE; 99 } 100 PS2DBG("ps2_getbyte: byte %02X read\n", *b); 101 return TRUE; 102 } 103 PS2DBG("ps2_getbyte: timeout xf86WaitForInput\n"); 104 return FALSE; 105} 106 107/* 108 * Write a byte to the ps/2 port, wait for ACK 109 */ 110Bool 111ps2_putbyte(int fd, byte b) 112{ 113 byte ack; 114 115 if (xf86WriteSerial(fd, &b, 1) != 1) { 116 PS2DBG("ps2_putbyte: error xf86WriteSerial\n"); 117 return FALSE; 118 } 119 PS2DBG("ps2_putbyte: byte %02X send\n", b); 120 /* wait for an ACK */ 121 if (!ps2_getbyte(fd, &ack)) { 122 return FALSE; 123 } 124 if (ack != PS2_ACK) { 125 PS2DBG("ps2_putbyte: wrong acknowledge 0x%02x\n", ack); 126 return FALSE; 127 } 128 return TRUE; 129} 130 131/* 132 * Use the Synaptics extended ps/2 syntax to write a special command byte. Needed by 133 * ps2_send_cmd and ps2_set_mode. 134 * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu 135 * is the command. A 0xF3 or 0xE9 must follow (see ps2_send_cmd, ps2_set_mode) 136 */ 137static Bool 138ps2_special_cmd(int fd, byte cmd) 139{ 140 int i; 141 142 /* initialize with 'inert' command */ 143 if (!ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1)) 144 return FALSE; 145 146 /* send 4x 2-bits with set resolution command */ 147 for (i = 0; i < 4; i++) { 148 if (!ps2_putbyte(fd, PS2_CMD_SET_RESOLUTION) || 149 !ps2_putbyte(fd, (cmd >> 6) & 0x3)) 150 return FALSE; 151 cmd <<= 2; 152 } 153 return TRUE; 154} 155 156/* 157 * Send a command to the synpatics touchpad by special commands 158 */ 159static Bool 160ps2_send_cmd(int fd, byte c) 161{ 162 PS2DBG("send command: 0x%02X\n", c); 163 return (ps2_special_cmd(fd, c) && ps2_putbyte(fd, PS2_CMD_STATUS_REQUEST)); 164} 165 166/***************************************************************************** 167 * Synaptics communications functions 168 ****************************************************************************/ 169 170/* 171 * Set the synaptics touchpad mode byte by special commands 172 */ 173static Bool 174ps2_synaptics_set_mode(int fd, byte mode) 175{ 176 PS2DBG("set mode byte to: 0x%02X\n", mode); 177 return (ps2_special_cmd(fd, mode) && 178 ps2_putbyte(fd, PS2_CMD_SET_SAMPLE_RATE) && ps2_putbyte(fd, 0x14)); 179} 180 181/* 182 * reset the touchpad 183 */ 184static Bool 185ps2_synaptics_reset(int fd) 186{ 187 byte r[2]; 188 189 xf86FlushInput(fd); 190 PS2DBG("Reset the Touchpad...\n"); 191 if (!ps2_putbyte(fd, PS2_CMD_RESET)) { 192 PS2DBG("...failed\n"); 193 return FALSE; 194 } 195 xf86WaitForInput(fd, 4000000); 196 if (ps2_getbyte(fd, &r[0]) && ps2_getbyte(fd, &r[1])) { 197 if (r[0] == 0xAA && r[1] == 0x00) { 198 PS2DBG("...done\n"); 199 return TRUE; 200 } 201 else { 202 PS2DBG("...failed. Wrong reset ack 0x%02x, 0x%02x\n", r[0], r[1]); 203 return FALSE; 204 } 205 } 206 PS2DBG("...failed\n"); 207 return FALSE; 208} 209 210/* 211 * Read the model-id bytes from the touchpad 212 * see also SYN_MODEL_* macros 213 */ 214static Bool 215ps2_synaptics_model_id(int fd, struct PS2SynapticsHwInfo *synhw) 216{ 217 byte mi[3]; 218 219 PS2DBG("Read mode id...\n"); 220 221 synhw->model_id = 0; 222 if (ps2_send_cmd(fd, SYN_QUE_MODEL) && 223 ps2_getbyte(fd, &mi[0]) && 224 ps2_getbyte(fd, &mi[1]) && ps2_getbyte(fd, &mi[2])) { 225 synhw->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2]; 226 PS2DBG("model-id %06X\n", synhw->model_id); 227 PS2DBG("...done.\n"); 228 return TRUE; 229 } 230 PS2DBG("...failed.\n"); 231 return FALSE; 232} 233 234/* 235 * Read the capability-bits from the touchpad 236 * see also the SYN_CAP_* macros 237 */ 238static Bool 239ps2_synaptics_capability(int fd, struct PS2SynapticsHwInfo *synhw) 240{ 241 byte cap[3]; 242 243 PS2DBG("Read capabilites...\n"); 244 245 synhw->capabilities = 0; 246 synhw->ext_cap = 0; 247 if (ps2_send_cmd(fd, SYN_QUE_CAPABILITIES) && 248 ps2_getbyte(fd, &cap[0]) && 249 ps2_getbyte(fd, &cap[1]) && ps2_getbyte(fd, &cap[2])) { 250 synhw->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; 251 PS2DBG("capabilities %06X\n", synhw->capabilities); 252 if (SYN_CAP_VALID(synhw)) { 253 if (SYN_EXT_CAP_REQUESTS(synhw)) { 254 if (ps2_send_cmd(fd, SYN_QUE_EXT_CAPAB) && 255 ps2_getbyte(fd, &cap[0]) && 256 ps2_getbyte(fd, &cap[1]) && ps2_getbyte(fd, &cap[2])) { 257 synhw->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; 258 PS2DBG("ext-capability %06X\n", synhw->ext_cap); 259 } 260 else { 261 PS2DBG("synaptics says, that it has extended-capabilities, " 262 "but I cannot read them."); 263 } 264 } 265 PS2DBG("...done.\n"); 266 return TRUE; 267 } 268 } 269 PS2DBG("...failed.\n"); 270 return FALSE; 271} 272 273/* 274 * Identify Touchpad 275 * See also the SYN_ID_* macros 276 */ 277static Bool 278ps2_synaptics_identify(int fd, struct PS2SynapticsHwInfo *synhw) 279{ 280 byte id[3]; 281 282 PS2DBG("Identify Touchpad...\n"); 283 284 synhw->identity = 0; 285 if (ps2_send_cmd(fd, SYN_QUE_IDENTIFY) && 286 ps2_getbyte(fd, &id[0]) && 287 ps2_getbyte(fd, &id[1]) && ps2_getbyte(fd, &id[2])) { 288 synhw->identity = (id[0] << 16) | (id[1] << 8) | id[2]; 289 PS2DBG("ident %06X\n", synhw->identity); 290 if (SYN_ID_IS_SYNAPTICS(synhw)) { 291 PS2DBG("...done.\n"); 292 return TRUE; 293 } 294 } 295 PS2DBG("...failed.\n"); 296 return FALSE; 297} 298 299static Bool 300ps2_synaptics_enable_device(int fd) 301{ 302 return ps2_putbyte(fd, PS2_CMD_ENABLE); 303} 304 305static Bool 306ps2_synaptics_disable_device(int fd) 307{ 308 xf86FlushInput(fd); 309 return ps2_putbyte(fd, PS2_CMD_DISABLE); 310} 311 312static Bool 313ps2_query_is_synaptics(InputInfoPtr pInfo, int fd, 314 struct PS2SynapticsHwInfo *synhw) 315{ 316 int i; 317 318 for (i = 0; i < 3; i++) { 319 if (ps2_synaptics_disable_device(fd)) 320 break; 321 } 322 323 xf86WaitForInput(fd, 20000); 324 xf86FlushInput(fd); 325 if (ps2_synaptics_identify(fd, synhw)) { 326 return TRUE; 327 } 328 else { 329 xf86IDrvMsg(pInfo, X_ERROR, "Query no Synaptics: %06X\n", 330 synhw->identity); 331 return FALSE; 332 } 333} 334 335void 336ps2_print_ident(InputInfoPtr pInfo, const struct PS2SynapticsHwInfo *synhw) 337{ 338 xf86IDrvMsg(pInfo, X_PROBED, " Synaptics Touchpad, model: %d\n", 339 SYN_ID_MODEL(synhw)); 340 xf86IDrvMsg(pInfo, X_PROBED, " Firmware: %d.%d\n", SYN_ID_MAJOR(synhw), 341 SYN_ID_MINOR(synhw)); 342 343 if (SYN_MODEL_ROT180(synhw)) 344 xf86IDrvMsg(pInfo, X_PROBED, " 180 degree mounted touchpad\n"); 345 if (SYN_MODEL_PORTRAIT(synhw)) 346 xf86IDrvMsg(pInfo, X_PROBED, " portrait touchpad\n"); 347 xf86IDrvMsg(pInfo, X_PROBED, " Sensor: %d\n", SYN_MODEL_SENSOR(synhw)); 348 if (SYN_MODEL_NEWABS(synhw)) 349 xf86IDrvMsg(pInfo, X_PROBED, " new absolute packet format\n"); 350 if (SYN_MODEL_PEN(synhw)) 351 xf86IDrvMsg(pInfo, X_PROBED, " pen detection\n"); 352 353 if (SYN_CAP_EXTENDED(synhw)) { 354 xf86IDrvMsg(pInfo, X_PROBED, 355 " Touchpad has extended capability bits\n"); 356 if (SYN_CAP_MULTI_BUTTON_NO(synhw)) 357 xf86IDrvMsg(pInfo, X_PROBED, 358 " -> %d multi buttons, i.e. besides standard buttons\n", 359 (int) (SYN_CAP_MULTI_BUTTON_NO(synhw))); 360 if (SYN_CAP_MIDDLE_BUTTON(synhw)) 361 xf86IDrvMsg(pInfo, X_PROBED, " -> middle button\n"); 362 if (SYN_CAP_FOUR_BUTTON(synhw)) 363 xf86IDrvMsg(pInfo, X_PROBED, " -> four buttons\n"); 364 if (SYN_CAP_MULTIFINGER(synhw)) 365 xf86IDrvMsg(pInfo, X_PROBED, " -> multifinger detection\n"); 366 if (SYN_CAP_PALMDETECT(synhw)) 367 xf86IDrvMsg(pInfo, X_PROBED, " -> palm detection\n"); 368 if (SYN_CAP_PASSTHROUGH(synhw)) 369 xf86IDrvMsg(pInfo, X_PROBED, " -> pass-through port\n"); 370 } 371} 372 373static Bool 374PS2DeviceOffHook(InputInfoPtr pInfo) 375{ 376 ps2_synaptics_reset(pInfo->fd); 377 ps2_synaptics_enable_device(pInfo->fd); 378 379 return TRUE; 380} 381 382static Bool 383PS2QueryHardware(InputInfoPtr pInfo) 384{ 385 int mode; 386 SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private; 387 struct PS2SynapticsHwInfo *synhw; 388 389 if (!priv->proto_data) 390 priv->proto_data = calloc(1, sizeof(struct PS2SynapticsHwInfo)); 391 synhw = (struct PS2SynapticsHwInfo *) priv->proto_data; 392 393 /* is the synaptics touchpad active? */ 394 if (!ps2_query_is_synaptics(pInfo, pInfo->fd, synhw)) 395 return FALSE; 396 397 xf86IDrvMsg(pInfo, X_PROBED, "synaptics touchpad found\n"); 398 399 if (!ps2_synaptics_reset(pInfo->fd)) 400 xf86IDrvMsg(pInfo, X_ERROR, "reset failed\n"); 401 402 if (!ps2_synaptics_identify(pInfo->fd, synhw)) 403 return FALSE; 404 405 if (!ps2_synaptics_model_id(pInfo->fd, synhw)) 406 return FALSE; 407 408 if (!ps2_synaptics_capability(pInfo->fd, synhw)) 409 return FALSE; 410 411 mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE; 412 if (SYN_ID_MAJOR(synhw) >= 4) 413 mode |= SYN_BIT_DISABLE_GESTURE; 414 if (SYN_CAP_EXTENDED(synhw)) 415 mode |= SYN_BIT_W_MODE; 416 if (!ps2_synaptics_set_mode(pInfo->fd, mode)) 417 return FALSE; 418 419 ps2_synaptics_enable_device(pInfo->fd); 420 421 ps2_print_ident(pInfo, synhw); 422 423 return TRUE; 424} 425 426/* 427 * Decide if the current packet stored in priv->protoBuf is valid. 428 */ 429static Bool 430ps2_packet_ok(struct PS2SynapticsHwInfo *synhw, struct CommData *comm) 431{ 432 unsigned char *buf = comm->protoBuf; 433 int newabs = SYN_MODEL_NEWABS(synhw); 434 435 if (newabs ? ((buf[0] & 0xC0) != 0x80) : ((buf[0] & 0xC0) != 0xC0)) { 436 PS2DBG("Synaptics driver lost sync at 1st byte\n"); 437 return FALSE; 438 } 439 440 if (!newabs && ((buf[1] & 0x60) != 0x00)) { 441 PS2DBG("Synaptics driver lost sync at 2nd byte\n"); 442 return FALSE; 443 } 444 445 if ((newabs ? ((buf[3] & 0xC0) != 0xC0) : ((buf[3] & 0xC0) != 0x80))) { 446 PS2DBG("Synaptics driver lost sync at 4th byte\n"); 447 return FALSE; 448 } 449 450 if (!newabs && ((buf[4] & 0x60) != 0x00)) { 451 PS2DBG("Synaptics driver lost sync at 5th byte\n"); 452 return FALSE; 453 } 454 455 return TRUE; 456} 457 458static Bool 459ps2_synaptics_get_packet(InputInfoPtr pInfo, struct PS2SynapticsHwInfo *synhw, 460 struct SynapticsProtocolOperations *proto_ops, 461 struct CommData *comm) 462{ 463 int count = 0; 464 int c; 465 unsigned char u; 466 467 while ((c = XisbRead(comm->buffer)) >= 0) { 468 u = (unsigned char) c; 469 470 /* test if there is a reset sequence received */ 471 if ((c == 0x00) && (comm->lastByte == 0xAA)) { 472 if (xf86WaitForInput(pInfo->fd, 50000) == 0) { 473 PS2DBG("Reset received\n"); 474 proto_ops->QueryHardware(pInfo); 475 } 476 else 477 PS2DBG("faked reset received\n"); 478 } 479 comm->lastByte = u; 480 481 /* to avoid endless loops */ 482 if (count++ > 30) { 483 LogMessageVerbSigSafe(X_ERROR, 0, 484 "Synaptics driver lost sync... got gigantic packet!\n"); 485 return FALSE; 486 } 487 488 comm->protoBuf[comm->protoBufTail++] = u; 489 490 /* Check that we have a valid packet. If not, we are out of sync, 491 so we throw away the first byte in the packet. */ 492 if (comm->protoBufTail >= 6) { 493 if (!ps2_packet_ok(synhw, comm)) { 494 int i; 495 496 for (i = 0; i < comm->protoBufTail - 1; i++) 497 comm->protoBuf[i] = comm->protoBuf[i + 1]; 498 comm->protoBufTail--; 499 comm->outOfSync++; 500 if (comm->outOfSync > MAX_UNSYNC_PACKETS) { 501 comm->outOfSync = 0; 502 PS2DBG("Synaptics synchronization lost too long -> reset touchpad.\n"); 503 proto_ops->QueryHardware(pInfo); /* including a reset */ 504 continue; 505 } 506 } 507 } 508 509 if (comm->protoBufTail >= 6) { /* Full packet received */ 510 if (comm->outOfSync > 0) { 511 comm->outOfSync = 0; 512 PS2DBG("Synaptics driver resynced.\n"); 513 } 514 comm->protoBufTail = 0; 515 return TRUE; 516 } 517 } 518 519 return FALSE; 520} 521 522Bool 523PS2ReadHwStateProto(InputInfoPtr pInfo, 524 struct SynapticsProtocolOperations *proto_ops, 525 struct CommData *comm, struct SynapticsHwState *hwRet) 526{ 527 unsigned char *buf = comm->protoBuf; 528 struct SynapticsHwState *hw = comm->hwState; 529 SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private; 530 SynapticsParameters *para = &priv->synpara; 531 struct PS2SynapticsHwInfo *synhw; 532 int newabs; 533 int w, i; 534 535 synhw = (struct PS2SynapticsHwInfo *) priv->proto_data; 536 if (!synhw) { 537 LogMessageVerbSigSafe(X_ERROR, 0, 538 "PS2ReadHwState, synhw is NULL. This is a bug.\n"); 539 return FALSE; 540 } 541 542 newabs = SYN_MODEL_NEWABS(synhw); 543 544 if (!ps2_synaptics_get_packet(pInfo, synhw, proto_ops, comm)) 545 return FALSE; 546 547 /* Handle normal packets */ 548 hw->x = hw->y = hw->z = hw->numFingers = hw->fingerWidth = 0; 549 hw->left = hw->right = hw->up = hw->down = hw->middle = FALSE; 550 for (i = 0; i < 8; i++) 551 hw->multi[i] = FALSE; 552 553 if (newabs) { /* newer protos... */ 554 PS2DBG("using new protocols\n"); 555 hw->x = (((buf[3] & 0x10) << 8) | ((buf[1] & 0x0f) << 8) | buf[4]); 556 hw->y = (((buf[3] & 0x20) << 7) | ((buf[1] & 0xf0) << 4) | buf[5]); 557 558 hw->z = buf[2]; 559 w = (((buf[0] & 0x30) >> 2) | 560 ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); 561 562 hw->left = (buf[0] & 0x01) ? 1 : 0; 563 hw->right = (buf[0] & 0x02) ? 1 : 0; 564 565 if (SYN_CAP_EXTENDED(synhw)) { 566 if (SYN_CAP_MIDDLE_BUTTON(synhw)) { 567 hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; 568 } 569 if (SYN_CAP_FOUR_BUTTON(synhw)) { 570 hw->up = ((buf[3] & 0x01)) ? 1 : 0; 571 if (hw->left) 572 hw->up = !hw->up; 573 hw->down = ((buf[3] & 0x02)) ? 1 : 0; 574 if (hw->right) 575 hw->down = !hw->down; 576 } 577 if (SYN_CAP_MULTI_BUTTON_NO(synhw)) { 578 if ((buf[3] & 2) ? !hw->right : hw->right) { 579 switch (SYN_CAP_MULTI_BUTTON_NO(synhw) & ~0x01) { 580 default: 581 break; 582 case 8: 583 hw->multi[7] = ((buf[5] & 0x08)) ? 1 : 0; 584 hw->multi[6] = ((buf[4] & 0x08)) ? 1 : 0; 585 case 6: 586 hw->multi[5] = ((buf[5] & 0x04)) ? 1 : 0; 587 hw->multi[4] = ((buf[4] & 0x04)) ? 1 : 0; 588 case 4: 589 hw->multi[3] = ((buf[5] & 0x02)) ? 1 : 0; 590 hw->multi[2] = ((buf[4] & 0x02)) ? 1 : 0; 591 case 2: 592 hw->multi[1] = ((buf[5] & 0x01)) ? 1 : 0; 593 hw->multi[0] = ((buf[4] & 0x01)) ? 1 : 0; 594 } 595 } 596 } 597 } 598 } 599 else { /* old proto... */ 600 PS2DBG("using old protocol\n"); 601 hw->x = (((buf[1] & 0x1F) << 8) | buf[2]); 602 hw->y = (((buf[4] & 0x1F) << 8) | buf[5]); 603 604 hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F)); 605 w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1)); 606 607 hw->left = (buf[0] & 0x01) ? 1 : 0; 608 hw->right = (buf[0] & 0x02) ? 1 : 0; 609 } 610 611 hw->y = YMAX_NOMINAL + YMIN_NOMINAL - hw->y; 612 613 if (hw->z >= para->finger_high) { 614 int w_ok = 0; 615 616 /* 617 * Use capability bits to decide if the w value is valid. 618 * If not, set it to 5, which corresponds to a finger of 619 * normal width. 620 */ 621 if (SYN_CAP_EXTENDED(synhw)) { 622 if ((w >= 0) && (w <= 1)) { 623 w_ok = SYN_CAP_MULTIFINGER(synhw); 624 } 625 else if (w == 2) { 626 w_ok = SYN_MODEL_PEN(synhw); 627 } 628 else if ((w >= 4) && (w <= 15)) { 629 w_ok = SYN_CAP_PALMDETECT(synhw); 630 } 631 } 632 if (!w_ok) 633 w = 5; 634 635 switch (w) { 636 case 0: 637 hw->numFingers = 2; 638 hw->fingerWidth = 5; 639 break; 640 case 1: 641 hw->numFingers = 3; 642 hw->fingerWidth = 5; 643 break; 644 default: 645 hw->numFingers = 1; 646 hw->fingerWidth = w; 647 break; 648 } 649 } 650 hw->millis = GetTimeInMillis(); 651 SynapticsCopyHwState(hwRet, hw); 652 return TRUE; 653} 654 655static Bool 656PS2ReadHwState(InputInfoPtr pInfo, 657 struct CommData *comm, struct SynapticsHwState *hwRet) 658{ 659 return PS2ReadHwStateProto(pInfo, &psaux_proto_operations, comm, hwRet); 660} 661 662struct SynapticsProtocolOperations psaux_proto_operations = { 663 NULL, 664 PS2DeviceOffHook, 665 PS2QueryHardware, 666 PS2ReadHwState, 667 NULL, 668 NULL 669}; 670