1 /* $OpenBSD: pms.c,v 1.99 2024/08/18 15:09:49 deraadt Exp $ */ 2 /* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */ 3 4 /*- 5 * Copyright (c) 1994 Charles M. Hannum. 6 * Copyright (c) 1992, 1993 Erik Forsberg. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 18 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/rwlock.h> 30 #include <sys/device.h> 31 #include <sys/ioctl.h> 32 #include <sys/malloc.h> 33 #include <sys/task.h> 34 #include <sys/timeout.h> 35 36 #include <machine/bus.h> 37 38 #include <dev/ic/pckbcvar.h> 39 40 #include <dev/pckbc/pmsreg.h> 41 42 #include <dev/wscons/wsconsio.h> 43 #include <dev/wscons/wsmousevar.h> 44 45 #if defined(__i386__) || defined(__amd64__) 46 #include "acpi.h" 47 #endif 48 49 #if !defined(SMALL_KERNEL) && NACPI > 0 50 extern int mouse_has_softbtn; 51 #else 52 int mouse_has_softbtn; 53 #endif 54 55 #ifdef DEBUG 56 #define DPRINTF(x...) do { printf(x); } while (0); 57 #else 58 #define DPRINTF(x...) 59 #endif 60 61 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 62 63 #define WSMOUSE_BUTTON(x) (1 << ((x) - 1)) 64 65 struct pms_softc; 66 67 struct pms_protocol { 68 int type; 69 #define PMS_STANDARD 0 70 #define PMS_INTELLI 1 71 #define PMS_SYNAPTICS 2 72 #define PMS_ALPS 3 73 #define PMS_ELANTECH_V1 4 74 #define PMS_ELANTECH_V2 5 75 #define PMS_ELANTECH_V3 6 76 #define PMS_ELANTECH_V4 7 77 u_int packetsize; 78 int (*enable)(struct pms_softc *); 79 int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *); 80 int (*sync)(struct pms_softc *, int); 81 void (*proc)(struct pms_softc *); 82 void (*disable)(struct pms_softc *); 83 }; 84 85 struct synaptics_softc { 86 int identify; 87 int capabilities, ext_capabilities, ext2_capabilities; 88 int model, ext_model; 89 int modes; 90 91 int mode; 92 93 int mask; 94 #define SYNAPTICS_MASK_NEWABS_STRICT 0xc8 95 #define SYNAPTICS_MASK_NEWABS_RELAXED 0xc0 96 #define SYNAPTICS_VALID_NEWABS_FIRST 0x80 97 #define SYNAPTICS_VALID_NEWABS_NEXT 0xc0 98 99 u_int sec_buttons; 100 101 #define SYNAPTICS_PRESSURE_HI 30 102 #define SYNAPTICS_PRESSURE_LO 25 103 #define SYNAPTICS_PRESSURE SYNAPTICS_PRESSURE_HI 104 #define SYNAPTICS_SCALE 4 105 #define SYNAPTICS_MAX_FINGERS 3 106 }; 107 108 struct alps_softc { 109 int model; 110 #define ALPS_GLIDEPOINT (1 << 1) 111 #define ALPS_DUALPOINT (1 << 2) 112 #define ALPS_PASSTHROUGH (1 << 3) 113 #define ALPS_INTERLEAVED (1 << 4) 114 115 int mask; 116 int version; 117 118 u_int gesture; 119 120 u_int sec_buttons; /* trackpoint */ 121 122 int old_x, old_y; 123 #define ALPS_PRESSURE 40 124 }; 125 126 struct elantech_softc { 127 int flags; 128 #define ELANTECH_F_REPORTS_PRESSURE 0x01 129 #define ELANTECH_F_HAS_ROCKER 0x02 130 #define ELANTECH_F_2FINGER_PACKET 0x04 131 #define ELANTECH_F_HW_V1_OLD 0x08 132 #define ELANTECH_F_CRC_ENABLED 0x10 133 #define ELANTECH_F_TRACKPOINT 0x20 134 int fw_version; 135 136 u_int mt_slots; 137 138 int width; 139 140 u_char parity[256]; 141 u_char p1, p2, p3; 142 143 int max_x, max_y; 144 int old_x, old_y; 145 int initial_pkt; 146 }; 147 #define ELANTECH_IS_CLICKPAD(sc) (((sc)->elantech->fw_version & 0x1000) != 0) 148 149 struct pms_softc { /* driver status information */ 150 struct device sc_dev; 151 152 pckbc_tag_t sc_kbctag; 153 154 int sc_state; 155 #define PMS_STATE_DISABLED 0 156 #define PMS_STATE_ENABLED 1 157 #define PMS_STATE_SUSPENDED 2 158 159 struct rwlock sc_state_lock; 160 161 int sc_dev_enable; 162 #define PMS_DEV_IGNORE 0x00 163 #define PMS_DEV_PRIMARY 0x01 164 #define PMS_DEV_SECONDARY 0x02 165 166 struct task sc_rsttask; 167 struct timeout sc_rsttimo; 168 int sc_rststate; 169 #define PMS_RST_COMMENCE 0x01 170 #define PMS_RST_ANNOUNCED 0x02 171 172 int poll; 173 int inputstate; 174 175 const struct pms_protocol *protocol; 176 struct synaptics_softc *synaptics; 177 struct alps_softc *alps; 178 struct elantech_softc *elantech; 179 180 u_char packet[8]; 181 182 struct device *sc_wsmousedev; 183 struct device *sc_sec_wsmousedev; 184 }; 185 186 static const u_int butmap[8] = { 187 0, 188 WSMOUSE_BUTTON(1), 189 WSMOUSE_BUTTON(3), 190 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(3), 191 WSMOUSE_BUTTON(2), 192 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2), 193 WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3), 194 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3) 195 }; 196 197 static const struct alps_model { 198 int version; 199 int mask; 200 int model; 201 } alps_models[] = { 202 { 0x2021, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 203 { 0x2221, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 204 { 0x2222, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 205 { 0x3222, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 206 { 0x5212, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED }, 207 { 0x5321, 0xf8, ALPS_GLIDEPOINT }, 208 { 0x5322, 0xf8, ALPS_GLIDEPOINT }, 209 { 0x603b, 0xf8, ALPS_GLIDEPOINT }, 210 { 0x6222, 0xcf, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED }, 211 { 0x6321, 0xf8, ALPS_GLIDEPOINT }, 212 { 0x6322, 0xf8, ALPS_GLIDEPOINT }, 213 { 0x6323, 0xf8, ALPS_GLIDEPOINT }, 214 { 0x6324, 0x8f, ALPS_GLIDEPOINT }, 215 { 0x6325, 0xef, ALPS_GLIDEPOINT }, 216 { 0x6326, 0xf8, ALPS_GLIDEPOINT }, 217 { 0x7301, 0xf8, ALPS_DUALPOINT }, 218 { 0x7321, 0xf8, ALPS_GLIDEPOINT }, 219 { 0x7322, 0xf8, ALPS_GLIDEPOINT }, 220 { 0x7325, 0xcf, ALPS_GLIDEPOINT }, 221 #if 0 222 /* 223 * This model has a clitpad sending almost compatible PS2 224 * packets but not compatible enough to be used with the 225 * ALPS protocol. 226 */ 227 { 0x633b, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 228 229 { 0x7326, 0, 0 }, /* XXX Uses unknown v3 protocol */ 230 231 { 0x7331, 0x8f, ALPS_DUALPOINT }, /* not supported */ 232 #endif 233 }; 234 235 static struct wsmouse_param synaptics_params[] = { 236 { WSMOUSECFG_PRESSURE_LO, SYNAPTICS_PRESSURE_LO }, 237 { WSMOUSECFG_PRESSURE_HI, SYNAPTICS_PRESSURE_HI } 238 }; 239 240 static struct wsmouse_param alps_params[] = { 241 { WSMOUSECFG_SMOOTHING, 3 } 242 }; 243 244 int pmsprobe(struct device *, void *, void *); 245 void pmsattach(struct device *, struct device *, void *); 246 int pmsactivate(struct device *, int); 247 248 void pmsinput(void *, int); 249 250 int pms_change_state(struct pms_softc *, int, int); 251 252 int pms_ioctl(void *, u_long, caddr_t, int, struct proc *); 253 int pms_enable(void *); 254 void pms_disable(void *); 255 256 int pms_sec_ioctl(void *, u_long, caddr_t, int, struct proc *); 257 int pms_sec_enable(void *); 258 void pms_sec_disable(void *); 259 260 int pms_cmd(struct pms_softc *, u_char *, int, u_char *, int); 261 int pms_spec_cmd(struct pms_softc *, int); 262 int pms_get_devid(struct pms_softc *, u_char *); 263 int pms_get_status(struct pms_softc *, u_char *); 264 int pms_set_rate(struct pms_softc *, int); 265 int pms_set_resolution(struct pms_softc *, int); 266 int pms_set_scaling(struct pms_softc *, int); 267 int pms_reset(struct pms_softc *); 268 int pms_dev_enable(struct pms_softc *); 269 int pms_dev_disable(struct pms_softc *); 270 void pms_protocol_lookup(struct pms_softc *); 271 void pms_reset_detect(struct pms_softc *, int); 272 void pms_reset_task(void *); 273 void pms_reset_timo(void *); 274 275 int pms_enable_intelli(struct pms_softc *); 276 277 int pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *); 278 int pms_sync_mouse(struct pms_softc *, int); 279 void pms_proc_mouse(struct pms_softc *); 280 281 int pms_enable_synaptics(struct pms_softc *); 282 int pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *); 283 int pms_sync_synaptics(struct pms_softc *, int); 284 void pms_proc_synaptics(struct pms_softc *); 285 void pms_disable_synaptics(struct pms_softc *); 286 287 int pms_enable_alps(struct pms_softc *); 288 int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *); 289 int pms_sync_alps(struct pms_softc *, int); 290 void pms_proc_alps(struct pms_softc *); 291 292 int pms_enable_elantech_v1(struct pms_softc *); 293 int pms_enable_elantech_v2(struct pms_softc *); 294 int pms_enable_elantech_v3(struct pms_softc *); 295 int pms_enable_elantech_v4(struct pms_softc *); 296 int pms_ioctl_elantech(struct pms_softc *, u_long, caddr_t, int, 297 struct proc *); 298 int pms_sync_elantech_v1(struct pms_softc *, int); 299 int pms_sync_elantech_v2(struct pms_softc *, int); 300 int pms_sync_elantech_v3(struct pms_softc *, int); 301 int pms_sync_elantech_v4(struct pms_softc *, int); 302 void pms_proc_elantech_v1(struct pms_softc *); 303 void pms_proc_elantech_v2(struct pms_softc *); 304 void pms_proc_elantech_v3(struct pms_softc *); 305 void pms_proc_elantech_v4(struct pms_softc *); 306 307 int synaptics_knock(struct pms_softc *); 308 int synaptics_set_mode(struct pms_softc *, int, int); 309 int synaptics_query(struct pms_softc *, int, int *); 310 int synaptics_get_hwinfo(struct pms_softc *); 311 void synaptics_sec_proc(struct pms_softc *); 312 313 int alps_sec_proc(struct pms_softc *); 314 int alps_get_hwinfo(struct pms_softc *); 315 316 int elantech_knock(struct pms_softc *); 317 int elantech_get_hwinfo_v1(struct pms_softc *); 318 int elantech_get_hwinfo_v2(struct pms_softc *); 319 int elantech_get_hwinfo_v3(struct pms_softc *); 320 int elantech_get_hwinfo_v4(struct pms_softc *); 321 int elantech_ps2_cmd(struct pms_softc *, u_char); 322 int elantech_set_absolute_mode_v1(struct pms_softc *); 323 int elantech_set_absolute_mode_v2(struct pms_softc *); 324 int elantech_set_absolute_mode_v3(struct pms_softc *); 325 int elantech_set_absolute_mode_v4(struct pms_softc *); 326 327 const struct cfattach pms_ca = { 328 sizeof(struct pms_softc), pmsprobe, pmsattach, NULL, 329 pmsactivate 330 }; 331 332 struct cfdriver pms_cd = { 333 NULL, "pms", DV_DULL 334 }; 335 336 const struct wsmouse_accessops pms_accessops = { 337 pms_enable, 338 pms_ioctl, 339 pms_disable, 340 }; 341 342 const struct wsmouse_accessops pms_sec_accessops = { 343 pms_sec_enable, 344 pms_sec_ioctl, 345 pms_sec_disable, 346 }; 347 348 const struct pms_protocol pms_protocols[] = { 349 /* Generic PS/2 mouse */ 350 { 351 PMS_STANDARD, 3, 352 NULL, 353 pms_ioctl_mouse, 354 pms_sync_mouse, 355 pms_proc_mouse, 356 NULL 357 }, 358 /* Synaptics touchpad */ 359 { 360 PMS_SYNAPTICS, 6, 361 pms_enable_synaptics, 362 pms_ioctl_synaptics, 363 pms_sync_synaptics, 364 pms_proc_synaptics, 365 pms_disable_synaptics 366 }, 367 /* ALPS touchpad */ 368 { 369 PMS_ALPS, 6, 370 pms_enable_alps, 371 pms_ioctl_alps, 372 pms_sync_alps, 373 pms_proc_alps, 374 NULL 375 }, 376 /* Elantech touchpad (hardware version 1) */ 377 { 378 PMS_ELANTECH_V1, 4, 379 pms_enable_elantech_v1, 380 pms_ioctl_elantech, 381 pms_sync_elantech_v1, 382 pms_proc_elantech_v1, 383 NULL 384 }, 385 /* Elantech touchpad (hardware version 2) */ 386 { 387 PMS_ELANTECH_V2, 6, 388 pms_enable_elantech_v2, 389 pms_ioctl_elantech, 390 pms_sync_elantech_v2, 391 pms_proc_elantech_v2, 392 NULL 393 }, 394 /* Elantech touchpad (hardware version 3) */ 395 { 396 PMS_ELANTECH_V3, 6, 397 pms_enable_elantech_v3, 398 pms_ioctl_elantech, 399 pms_sync_elantech_v3, 400 pms_proc_elantech_v3, 401 NULL 402 }, 403 /* Elantech touchpad (hardware version 4) */ 404 { 405 PMS_ELANTECH_V4, 6, 406 pms_enable_elantech_v4, 407 pms_ioctl_elantech, 408 pms_sync_elantech_v4, 409 pms_proc_elantech_v4, 410 NULL 411 }, 412 /* Microsoft IntelliMouse */ 413 { 414 PMS_INTELLI, 4, 415 pms_enable_intelli, 416 pms_ioctl_mouse, 417 pms_sync_mouse, 418 pms_proc_mouse, 419 NULL 420 }, 421 }; 422 423 int 424 pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen) 425 { 426 if (sc->poll) { 427 return pckbc_poll_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT, 428 cmd, len, resplen, resp, 1); 429 } else { 430 return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT, 431 cmd, len, resplen, 1, resp); 432 } 433 } 434 435 int 436 pms_spec_cmd(struct pms_softc *sc, int cmd) 437 { 438 if (pms_set_scaling(sc, 1) || 439 pms_set_resolution(sc, (cmd >> 6) & 0x03) || 440 pms_set_resolution(sc, (cmd >> 4) & 0x03) || 441 pms_set_resolution(sc, (cmd >> 2) & 0x03) || 442 pms_set_resolution(sc, (cmd >> 0) & 0x03)) 443 return (-1); 444 return (0); 445 } 446 447 int 448 pms_get_devid(struct pms_softc *sc, u_char *resp) 449 { 450 u_char cmd[1]; 451 452 cmd[0] = PMS_SEND_DEV_ID; 453 return (pms_cmd(sc, cmd, 1, resp, 1)); 454 } 455 456 int 457 pms_get_status(struct pms_softc *sc, u_char *resp) 458 { 459 u_char cmd[1]; 460 461 cmd[0] = PMS_SEND_DEV_STATUS; 462 return (pms_cmd(sc, cmd, 1, resp, 3)); 463 } 464 465 int 466 pms_set_rate(struct pms_softc *sc, int value) 467 { 468 u_char cmd[2]; 469 470 cmd[0] = PMS_SET_SAMPLE; 471 cmd[1] = value; 472 return (pms_cmd(sc, cmd, 2, NULL, 0)); 473 } 474 475 int 476 pms_set_resolution(struct pms_softc *sc, int value) 477 { 478 u_char cmd[2]; 479 480 cmd[0] = PMS_SET_RES; 481 cmd[1] = value; 482 return (pms_cmd(sc, cmd, 2, NULL, 0)); 483 } 484 485 int 486 pms_set_scaling(struct pms_softc *sc, int scale) 487 { 488 u_char cmd[1]; 489 490 switch (scale) { 491 case 1: 492 default: 493 cmd[0] = PMS_SET_SCALE11; 494 break; 495 case 2: 496 cmd[0] = PMS_SET_SCALE21; 497 break; 498 } 499 return (pms_cmd(sc, cmd, 1, NULL, 0)); 500 } 501 502 int 503 pms_reset(struct pms_softc *sc) 504 { 505 u_char cmd[1], resp[2]; 506 int res; 507 508 cmd[0] = PMS_RESET; 509 res = pms_cmd(sc, cmd, 1, resp, 2); 510 #ifdef DEBUG 511 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) 512 printf("%s: reset error %d (response 0x%02x, type 0x%02x)\n", 513 DEVNAME(sc), res, resp[0], resp[1]); 514 #endif 515 return (res); 516 } 517 518 int 519 pms_dev_enable(struct pms_softc *sc) 520 { 521 u_char cmd[1]; 522 int res; 523 524 cmd[0] = PMS_DEV_ENABLE; 525 res = pms_cmd(sc, cmd, 1, NULL, 0); 526 if (res) 527 printf("%s: enable error\n", DEVNAME(sc)); 528 return (res); 529 } 530 531 int 532 pms_dev_disable(struct pms_softc *sc) 533 { 534 u_char cmd[1]; 535 int res; 536 537 cmd[0] = PMS_DEV_DISABLE; 538 res = pms_cmd(sc, cmd, 1, NULL, 0); 539 if (res) 540 printf("%s: disable error\n", DEVNAME(sc)); 541 return (res); 542 } 543 544 void 545 pms_protocol_lookup(struct pms_softc *sc) 546 { 547 int i; 548 549 sc->protocol = &pms_protocols[0]; 550 for (i = 1; i < nitems(pms_protocols); i++) { 551 pms_reset(sc); 552 if (pms_protocols[i].enable(sc)) { 553 sc->protocol = &pms_protocols[i]; 554 break; 555 } 556 } 557 558 DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type); 559 } 560 561 /* 562 * Detect reset announcement ([0xaa, 0x0]). 563 * The sequence will be sent as input on rare occasions when the touchpad was 564 * reset due to a power failure. 565 */ 566 void 567 pms_reset_detect(struct pms_softc *sc, int data) 568 { 569 switch (sc->sc_rststate) { 570 case PMS_RST_COMMENCE: 571 if (data == 0x0) { 572 sc->sc_rststate = PMS_RST_ANNOUNCED; 573 timeout_add_msec(&sc->sc_rsttimo, 100); 574 } else if (data != PMS_RSTDONE) { 575 sc->sc_rststate = 0; 576 } 577 break; 578 default: 579 if (data == PMS_RSTDONE) 580 sc->sc_rststate = PMS_RST_COMMENCE; 581 else 582 sc->sc_rststate = 0; 583 } 584 } 585 586 void 587 pms_reset_timo(void *v) 588 { 589 struct pms_softc *sc = v; 590 int s = spltty(); 591 592 /* 593 * Do nothing if the reset was a false positive or if the device already 594 * is disabled. 595 */ 596 if (sc->sc_rststate == PMS_RST_ANNOUNCED && 597 sc->sc_state != PMS_STATE_DISABLED) 598 task_add(systq, &sc->sc_rsttask); 599 600 splx(s); 601 } 602 603 void 604 pms_reset_task(void *v) 605 { 606 struct pms_softc *sc = v; 607 int s = spltty(); 608 609 #ifdef DIAGNOSTIC 610 printf("%s: device reset (state = %d)\n", DEVNAME(sc), sc->sc_rststate); 611 #endif 612 613 rw_enter_write(&sc->sc_state_lock); 614 615 if (sc->sc_sec_wsmousedev != NULL) 616 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY); 617 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY); 618 619 pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY); 620 if (sc->sc_sec_wsmousedev != NULL) 621 pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY); 622 623 rw_exit_write(&sc->sc_state_lock); 624 splx(s); 625 } 626 627 int 628 pms_enable_intelli(struct pms_softc *sc) 629 { 630 u_char resp; 631 632 /* the special sequence to enable the third button and the roller */ 633 if (pms_set_rate(sc, PMS_INTELLI_MAGIC1) || 634 pms_set_rate(sc, PMS_INTELLI_MAGIC2) || 635 pms_set_rate(sc, PMS_INTELLI_MAGIC3) || 636 pms_get_devid(sc, &resp) || 637 resp != PMS_INTELLI_ID) 638 return (0); 639 640 return (1); 641 } 642 643 int 644 pms_ioctl_mouse(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 645 struct proc *p) 646 { 647 int i; 648 649 switch (cmd) { 650 case WSMOUSEIO_GTYPE: 651 *(u_int *)data = WSMOUSE_TYPE_PS2; 652 break; 653 case WSMOUSEIO_SRES: 654 i = ((int) *(u_int *)data - 12) / 25; 655 /* valid values are {0,1,2,3} */ 656 if (i < 0) 657 i = 0; 658 if (i > 3) 659 i = 3; 660 661 if (pms_set_resolution(sc, i)) 662 printf("%s: SET_RES command error\n", DEVNAME(sc)); 663 break; 664 default: 665 return (-1); 666 } 667 return (0); 668 } 669 670 int 671 pms_sync_mouse(struct pms_softc *sc, int data) 672 { 673 if (sc->inputstate != 0) 674 return (0); 675 676 switch (sc->protocol->type) { 677 case PMS_STANDARD: 678 if ((data & 0xc0) != 0) 679 return (-1); 680 break; 681 case PMS_INTELLI: 682 if ((data & 0x08) != 0x08) 683 return (-1); 684 break; 685 } 686 687 return (0); 688 } 689 690 void 691 pms_proc_mouse(struct pms_softc *sc) 692 { 693 u_int buttons; 694 int dx, dy, dz; 695 696 buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; 697 dx = (sc->packet[0] & PMS_PS2_XNEG) ? 698 (int)sc->packet[1] - 256 : sc->packet[1]; 699 dy = (sc->packet[0] & PMS_PS2_YNEG) ? 700 (int)sc->packet[2] - 256 : sc->packet[2]; 701 702 if (sc->protocol->type == PMS_INTELLI) 703 dz = (signed char)sc->packet[3]; 704 else 705 dz = 0; 706 707 WSMOUSE_INPUT(sc->sc_wsmousedev, buttons, dx, dy, dz, 0); 708 } 709 710 int 711 pmsprobe(struct device *parent, void *match, void *aux) 712 { 713 struct pckbc_attach_args *pa = aux; 714 u_char cmd[1], resp[2]; 715 int res; 716 717 if (pa->pa_slot != PCKBC_AUX_SLOT) 718 return (0); 719 720 /* Flush any garbage. */ 721 pckbc_flush(pa->pa_tag, pa->pa_slot); 722 723 /* reset the device */ 724 cmd[0] = PMS_RESET; 725 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1); 726 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) { 727 #ifdef DEBUG 728 printf("pms: reset error %d (response 0x%02x, type 0x%02x)\n", 729 res, resp[0], resp[1]); 730 #endif 731 return (0); 732 } 733 734 return (1); 735 } 736 737 void 738 pmsattach(struct device *parent, struct device *self, void *aux) 739 { 740 struct pms_softc *sc = (void *)self; 741 struct pckbc_attach_args *pa = aux; 742 struct wsmousedev_attach_args a; 743 744 sc->sc_kbctag = pa->pa_tag; 745 746 pckbc_set_inputhandler(sc->sc_kbctag, PCKBC_AUX_SLOT, 747 pmsinput, sc, DEVNAME(sc)); 748 749 printf("\n"); 750 751 a.accessops = &pms_accessops; 752 a.accesscookie = sc; 753 754 rw_init(&sc->sc_state_lock, "pmsst"); 755 756 /* 757 * Attach the wsmouse, saving a handle to it. 758 * Note that we don't need to check this pointer against NULL 759 * here or in pmsintr, because if this fails pms_enable() will 760 * never be called, so pmsinput() will never be called. 761 */ 762 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 763 764 task_set(&sc->sc_rsttask, pms_reset_task, sc); 765 timeout_set(&sc->sc_rsttimo, pms_reset_timo, sc); 766 767 sc->poll = 1; 768 sc->sc_dev_enable = 0; 769 770 /* See if the device understands an extended (touchpad) protocol. */ 771 pms_protocol_lookup(sc); 772 773 /* no interrupts until enabled */ 774 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE); 775 } 776 777 int 778 pmsactivate(struct device *self, int act) 779 { 780 struct pms_softc *sc = (struct pms_softc *)self; 781 int rv; 782 783 switch (act) { 784 case DVACT_SUSPEND: 785 rv = config_activate_children(self, act); 786 if (sc->sc_state == PMS_STATE_ENABLED) 787 pms_change_state(sc, PMS_STATE_SUSPENDED, 788 PMS_DEV_IGNORE); 789 break; 790 case DVACT_RESUME: 791 if (sc->sc_state == PMS_STATE_SUSPENDED) 792 pms_change_state(sc, PMS_STATE_ENABLED, 793 PMS_DEV_IGNORE); 794 rv = config_activate_children(self, act); 795 break; 796 default: 797 rv = config_activate_children(self, act); 798 break; 799 } 800 return (rv); 801 } 802 803 int 804 pms_change_state(struct pms_softc *sc, int newstate, int dev) 805 { 806 if (dev != PMS_DEV_IGNORE) { 807 switch (newstate) { 808 case PMS_STATE_ENABLED: 809 if (sc->sc_dev_enable & dev) 810 return (EBUSY); 811 812 sc->sc_dev_enable |= dev; 813 814 if (sc->sc_state == PMS_STATE_ENABLED) 815 return (0); 816 817 break; 818 case PMS_STATE_DISABLED: 819 sc->sc_dev_enable &= ~dev; 820 821 if (sc->sc_dev_enable) 822 return (0); 823 824 break; 825 } 826 } 827 828 switch (newstate) { 829 case PMS_STATE_ENABLED: 830 sc->inputstate = 0; 831 sc->sc_rststate = 0; 832 833 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1); 834 835 if (sc->poll) 836 pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT); 837 838 pms_reset(sc); 839 if (sc->protocol->enable != NULL && 840 sc->protocol->enable(sc) == 0) 841 pms_protocol_lookup(sc); 842 843 pms_dev_enable(sc); 844 break; 845 case PMS_STATE_DISABLED: 846 case PMS_STATE_SUSPENDED: 847 pms_dev_disable(sc); 848 849 if (sc->protocol->disable) 850 sc->protocol->disable(sc); 851 852 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0); 853 break; 854 } 855 856 sc->sc_state = newstate; 857 sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0; 858 859 return (0); 860 } 861 862 int 863 pms_enable(void *v) 864 { 865 struct pms_softc *sc = v; 866 int rv; 867 868 rw_enter_write(&sc->sc_state_lock); 869 rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY); 870 rw_exit_write(&sc->sc_state_lock); 871 872 return (rv); 873 } 874 875 void 876 pms_disable(void *v) 877 { 878 struct pms_softc *sc = v; 879 880 rw_enter_write(&sc->sc_state_lock); 881 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY); 882 rw_exit_write(&sc->sc_state_lock); 883 } 884 885 int 886 pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 887 { 888 struct pms_softc *sc = v; 889 890 if (sc->protocol->ioctl) 891 return (sc->protocol->ioctl(sc, cmd, data, flag, p)); 892 else 893 return (-1); 894 } 895 896 int 897 pms_sec_enable(void *v) 898 { 899 struct pms_softc *sc = v; 900 int rv; 901 902 rw_enter_write(&sc->sc_state_lock); 903 rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY); 904 rw_exit_write(&sc->sc_state_lock); 905 906 return (rv); 907 } 908 909 void 910 pms_sec_disable(void *v) 911 { 912 struct pms_softc *sc = v; 913 914 rw_enter_write(&sc->sc_state_lock); 915 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY); 916 rw_exit_write(&sc->sc_state_lock); 917 } 918 919 int 920 pms_sec_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 921 { 922 switch (cmd) { 923 case WSMOUSEIO_GTYPE: 924 *(u_int *)data = WSMOUSE_TYPE_PS2; 925 break; 926 default: 927 return (-1); 928 } 929 return (0); 930 } 931 932 #ifdef DIAGNOSTIC 933 static inline void 934 pms_print_packet(struct pms_softc *sc) 935 { 936 int i, state, size; 937 938 state = sc->inputstate; 939 size = sc->protocol->packetsize; 940 for (i = 0; i < size; i++) 941 printf(i == state ? " %02x |" : " %02x", sc->packet[i]); 942 } 943 #endif 944 945 void 946 pmsinput(void *vsc, int data) 947 { 948 struct pms_softc *sc = vsc; 949 950 if (sc->sc_state != PMS_STATE_ENABLED) { 951 /* Interrupts are not expected. Discard the byte. */ 952 return; 953 } 954 955 sc->packet[sc->inputstate] = data; 956 pms_reset_detect(sc, data); 957 if (sc->protocol->sync(sc, data)) { 958 #ifdef DIAGNOSTIC 959 printf("%s: not in sync yet, discard input " 960 "(state = %d,", 961 DEVNAME(sc), sc->inputstate); 962 pms_print_packet(sc); 963 printf(")\n"); 964 #endif 965 966 sc->inputstate = 0; 967 return; 968 } 969 970 sc->inputstate++; 971 972 if (sc->inputstate != sc->protocol->packetsize) 973 return; 974 975 sc->inputstate = 0; 976 sc->protocol->proc(sc); 977 } 978 979 int 980 synaptics_set_mode(struct pms_softc *sc, int mode, int rate) 981 { 982 struct synaptics_softc *syn = sc->synaptics; 983 984 if (pms_spec_cmd(sc, mode) || 985 pms_set_rate(sc, rate == 0 ? SYNAPTICS_CMD_SET_MODE : rate)) 986 return (-1); 987 988 /* 989 * Make sure that the set mode command has finished. 990 * Otherwise enabling the device before that will make it fail. 991 */ 992 delay(10000); 993 994 if (rate == 0) 995 syn->mode = mode; 996 997 return (0); 998 } 999 1000 int 1001 synaptics_query(struct pms_softc *sc, int query, int *val) 1002 { 1003 u_char resp[3]; 1004 1005 if (pms_spec_cmd(sc, query) || 1006 pms_get_status(sc, resp)) 1007 return (-1); 1008 1009 if (val) 1010 *val = (resp[0] << 16) | (resp[1] << 8) | resp[2]; 1011 1012 return (0); 1013 } 1014 1015 int 1016 synaptics_get_hwinfo(struct pms_softc *sc) 1017 { 1018 struct synaptics_softc *syn = sc->synaptics; 1019 struct wsmousehw *hw; 1020 int resolution = 0, max_coords = 0, min_coords = 0; 1021 1022 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1023 1024 if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY, &syn->identify)) 1025 return (-1); 1026 if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES, 1027 &syn->capabilities)) 1028 return (-1); 1029 if (synaptics_query(sc, SYNAPTICS_QUE_MODEL, &syn->model)) 1030 return (-1); 1031 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 1) && 1032 synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL, &syn->ext_model)) 1033 return (-1); 1034 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 4) && 1035 synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES, 1036 &syn->ext_capabilities)) 1037 return (-1); 1038 if ((SYNAPTICS_ID_MAJOR(syn->identify) >= 4) && 1039 synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION, &resolution)) 1040 return (-1); 1041 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 5) && 1042 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_COORDS) && 1043 synaptics_query(sc, SYNAPTICS_QUE_EXT_MAX_COORDS, &max_coords)) 1044 return (-1); 1045 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 7 || 1046 SYNAPTICS_ID_FULL(syn->identify) == 0x801) && 1047 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MIN_COORDS) && 1048 synaptics_query(sc, SYNAPTICS_QUE_EXT_MIN_COORDS, &min_coords)) 1049 return (-1); 1050 1051 if (SYNAPTICS_ID_FULL(syn->identify) >= 0x705) { 1052 if (synaptics_query(sc, SYNAPTICS_QUE_MODES, &syn->modes)) 1053 return (-1); 1054 if ((syn->modes & SYNAPTICS_EXT2_CAP) && 1055 synaptics_query(sc, SYNAPTICS_QUE_EXT2_CAPABILITIES, 1056 &syn->ext2_capabilities)) 1057 return (-1); 1058 } 1059 1060 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) && 1061 !(syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) 1062 && mouse_has_softbtn) 1063 hw->type = WSMOUSE_TYPE_SYNAP_SBTN; 1064 else 1065 hw->type = WSMOUSE_TYPE_SYNAPTICS; 1066 1067 hw->hw_type = (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) 1068 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD; 1069 1070 if (resolution & SYNAPTICS_RESOLUTION_VALID) { 1071 hw->h_res = SYNAPTICS_RESOLUTION_X(resolution); 1072 hw->v_res = SYNAPTICS_RESOLUTION_Y(resolution); 1073 } 1074 1075 hw->x_min = (min_coords ? 1076 SYNAPTICS_X_LIMIT(min_coords) : SYNAPTICS_XMIN_BEZEL); 1077 hw->y_min = (min_coords ? 1078 SYNAPTICS_Y_LIMIT(min_coords) : SYNAPTICS_YMIN_BEZEL); 1079 hw->x_max = (max_coords ? 1080 SYNAPTICS_X_LIMIT(max_coords) : SYNAPTICS_XMAX_BEZEL); 1081 hw->y_max = (max_coords ? 1082 SYNAPTICS_Y_LIMIT(max_coords) : SYNAPTICS_YMAX_BEZEL); 1083 1084 if ((syn->capabilities & SYNAPTICS_CAP_MULTIFINGER) || 1085 SYNAPTICS_SUPPORTS_AGM(syn->ext_capabilities)) 1086 hw->contacts_max = SYNAPTICS_MAX_FINGERS; 1087 else 1088 hw->contacts_max = 1; 1089 1090 syn->sec_buttons = 0; 1091 1092 if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) > 8) 1093 syn->ext_model &= ~0xf000; 1094 1095 if ((syn->model & SYNAPTICS_MODEL_NEWABS) == 0) { 1096 printf("%s: don't support Synaptics OLDABS\n", DEVNAME(sc)); 1097 return (-1); 1098 } 1099 1100 if ((SYNAPTICS_ID_MAJOR(syn->identify) == 5) && 1101 (SYNAPTICS_ID_MINOR(syn->identify) == 9)) 1102 syn->mask = SYNAPTICS_MASK_NEWABS_RELAXED; 1103 else 1104 syn->mask = SYNAPTICS_MASK_NEWABS_STRICT; 1105 1106 return (0); 1107 } 1108 1109 void 1110 synaptics_sec_proc(struct pms_softc *sc) 1111 { 1112 struct synaptics_softc *syn = sc->synaptics; 1113 u_int buttons; 1114 int dx, dy; 1115 1116 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0) 1117 return; 1118 1119 buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK]; 1120 buttons |= syn->sec_buttons; 1121 dx = (sc->packet[1] & PMS_PS2_XNEG) ? 1122 (int)sc->packet[4] - 256 : sc->packet[4]; 1123 dy = (sc->packet[1] & PMS_PS2_YNEG) ? 1124 (int)sc->packet[5] - 256 : sc->packet[5]; 1125 1126 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0); 1127 } 1128 1129 int 1130 synaptics_knock(struct pms_softc *sc) 1131 { 1132 u_char resp[3]; 1133 1134 if (pms_set_resolution(sc, 0) || 1135 pms_set_resolution(sc, 0) || 1136 pms_set_resolution(sc, 0) || 1137 pms_set_resolution(sc, 0) || 1138 pms_get_status(sc, resp) || 1139 resp[1] != SYNAPTICS_ID_MAGIC) 1140 return (-1); 1141 1142 return (0); 1143 } 1144 1145 int 1146 pms_enable_synaptics(struct pms_softc *sc) 1147 { 1148 struct synaptics_softc *syn = sc->synaptics; 1149 struct wsmousedev_attach_args a; 1150 int mode, i; 1151 1152 if (synaptics_knock(sc)) { 1153 if (sc->synaptics == NULL) 1154 goto err; 1155 /* 1156 * Some synaptics touchpads don't resume quickly. 1157 * Retry a few times. 1158 */ 1159 for (i = 10; i > 0; --i) { 1160 printf("%s: device not resuming, retrying\n", 1161 DEVNAME(sc)); 1162 pms_reset(sc); 1163 if (synaptics_knock(sc) == 0) 1164 break; 1165 delay(100000); 1166 } 1167 if (i == 0) { 1168 printf("%s: lost device\n", DEVNAME(sc)); 1169 goto err; 1170 } 1171 } 1172 1173 if (sc->synaptics == NULL) { 1174 sc->synaptics = syn = malloc(sizeof(struct synaptics_softc), 1175 M_DEVBUF, M_WAITOK | M_ZERO); 1176 if (syn == NULL) { 1177 printf("%s: synaptics: not enough memory\n", 1178 DEVNAME(sc)); 1179 goto err; 1180 } 1181 1182 if (synaptics_get_hwinfo(sc)) { 1183 free(sc->synaptics, M_DEVBUF, 1184 sizeof(struct synaptics_softc)); 1185 sc->synaptics = NULL; 1186 goto err; 1187 } 1188 1189 /* enable pass-through PS/2 port if supported */ 1190 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) { 1191 a.accessops = &pms_sec_accessops; 1192 a.accesscookie = sc; 1193 sc->sc_sec_wsmousedev = config_found((void *)sc, &a, 1194 wsmousedevprint); 1195 } 1196 1197 if (wsmouse_configure(sc->sc_wsmousedev, synaptics_params, 1198 nitems(synaptics_params))) 1199 goto err; 1200 1201 printf("%s: Synaptics %s, firmware %d.%d, " 1202 "0x%x 0x%x 0x%x 0x%x 0x%x\n", 1203 DEVNAME(sc), 1204 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD ? 1205 "clickpad" : "touchpad"), 1206 SYNAPTICS_ID_MAJOR(syn->identify), 1207 SYNAPTICS_ID_MINOR(syn->identify), 1208 syn->model, syn->ext_model, syn->modes, 1209 syn->capabilities, syn->ext_capabilities); 1210 } 1211 1212 /* 1213 * Enable absolute mode, plain W-mode and "advanced gesture mode" 1214 * (AGM), if possible. AGM, which seems to be a prerequisite for the 1215 * extended W-mode, might not always be necessary here, but at least 1216 * some older Synaptics models do not report finger counts without it. 1217 */ 1218 mode = SYNAPTICS_ABSOLUTE_MODE | SYNAPTICS_HIGH_RATE; 1219 if (syn->capabilities & SYNAPTICS_CAP_EXTENDED) 1220 mode |= SYNAPTICS_W_MODE; 1221 else if (SYNAPTICS_ID_MAJOR(syn->identify) >= 4) 1222 mode |= SYNAPTICS_DISABLE_GESTURE; 1223 if (synaptics_set_mode(sc, mode, 0)) 1224 goto err; 1225 1226 if (SYNAPTICS_SUPPORTS_AGM(syn->ext_capabilities) && 1227 synaptics_set_mode(sc, SYNAPTICS_QUE_MODEL, 1228 SYNAPTICS_CMD_SET_ADV_GESTURE_MODE)) 1229 goto err; 1230 1231 return (1); 1232 1233 err: 1234 pms_reset(sc); 1235 1236 return (0); 1237 } 1238 1239 int 1240 pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 1241 struct proc *p) 1242 { 1243 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 1244 struct wsmousehw *hw; 1245 int wsmode; 1246 1247 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1248 switch (cmd) { 1249 case WSMOUSEIO_GTYPE: 1250 *(u_int *)data = hw->type; 1251 break; 1252 case WSMOUSEIO_GCALIBCOORDS: 1253 wsmc->minx = hw->x_min; 1254 wsmc->maxx = hw->x_max; 1255 wsmc->miny = hw->y_min; 1256 wsmc->maxy = hw->y_max; 1257 wsmc->swapxy = 0; 1258 wsmc->resx = hw->h_res; 1259 wsmc->resy = hw->v_res; 1260 break; 1261 case WSMOUSEIO_SETMODE: 1262 wsmode = *(u_int *)data; 1263 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 1264 return (EINVAL); 1265 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 1266 break; 1267 default: 1268 return (-1); 1269 } 1270 return (0); 1271 } 1272 1273 int 1274 pms_sync_synaptics(struct pms_softc *sc, int data) 1275 { 1276 struct synaptics_softc *syn = sc->synaptics; 1277 1278 switch (sc->inputstate) { 1279 case 0: 1280 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_FIRST) 1281 return (-1); 1282 break; 1283 case 3: 1284 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_NEXT) 1285 return (-1); 1286 break; 1287 } 1288 1289 return (0); 1290 } 1291 1292 void 1293 pms_proc_synaptics(struct pms_softc *sc) 1294 { 1295 struct synaptics_softc *syn = sc->synaptics; 1296 u_int buttons; 1297 int x, y, z, w, fingerwidth; 1298 1299 w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) | 1300 ((sc->packet[3] & 0x04) >> 2); 1301 z = sc->packet[2]; 1302 1303 if ((syn->capabilities & SYNAPTICS_CAP_EXTENDED) == 0) { 1304 /* 1305 * Emulate W mode for models that don't provide it. Bit 3 1306 * of the w-input signals a touch ("finger"), Bit 2 and 1307 * the "gesture" bits 1-0 can be ignored. 1308 */ 1309 if (w & 8) 1310 w = 4; 1311 else 1312 z = w = 0; 1313 } 1314 1315 1316 if (w == 3) { 1317 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) 1318 synaptics_sec_proc(sc); 1319 return; 1320 } 1321 1322 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 1323 return; 1324 1325 if (w == 2) 1326 return; /* EW-mode packets are not expected here. */ 1327 1328 x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) | 1329 sc->packet[4]; 1330 y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) | 1331 sc->packet[5]; 1332 1333 buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ? 1334 WSMOUSE_BUTTON(1) : 0; 1335 buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ? 1336 WSMOUSE_BUTTON(3) : 0; 1337 1338 if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) { 1339 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1340 WSMOUSE_BUTTON(1) : 0; 1341 } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON) { 1342 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1343 WSMOUSE_BUTTON(2) : 0; 1344 } 1345 1346 if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON) { 1347 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1348 WSMOUSE_BUTTON(4) : 0; 1349 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ? 1350 WSMOUSE_BUTTON(5) : 0; 1351 } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) && 1352 ((sc->packet[0] ^ sc->packet[3]) & 0x02)) { 1353 if (syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) { 1354 /* 1355 * Trackstick buttons on this machine are wired to the 1356 * trackpad as extra buttons, so route the event 1357 * through the trackstick interface as normal buttons 1358 */ 1359 syn->sec_buttons = 1360 (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(1) : 0; 1361 syn->sec_buttons |= 1362 (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(3) : 0; 1363 syn->sec_buttons |= 1364 (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(2) : 0; 1365 wsmouse_buttons( 1366 sc->sc_sec_wsmousedev, syn->sec_buttons); 1367 wsmouse_input_sync(sc->sc_sec_wsmousedev); 1368 return; 1369 } 1370 1371 buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6) : 0; 1372 buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7) : 0; 1373 buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8) : 0; 1374 buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9) : 0; 1375 buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10) : 0; 1376 buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11) : 0; 1377 buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12) : 0; 1378 buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13) : 0; 1379 x &= ~0x0f; 1380 y &= ~0x0f; 1381 } 1382 1383 if (z) { 1384 fingerwidth = max(w, 4); 1385 w = (w < 2 ? w + 2 : 1); 1386 } else { 1387 fingerwidth = 0; 1388 w = 0; 1389 } 1390 wsmouse_set(sc->sc_wsmousedev, WSMOUSE_TOUCH_WIDTH, fingerwidth, 0); 1391 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 1392 } 1393 1394 void 1395 pms_disable_synaptics(struct pms_softc *sc) 1396 { 1397 struct synaptics_softc *syn = sc->synaptics; 1398 1399 if (syn->capabilities & SYNAPTICS_CAP_SLEEP) 1400 synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE | 1401 SYNAPTICS_DISABLE_GESTURE, 0); 1402 } 1403 1404 int 1405 alps_sec_proc(struct pms_softc *sc) 1406 { 1407 struct alps_softc *alps = sc->alps; 1408 int dx, dy, pos = 0; 1409 1410 if ((sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) { 1411 /* 1412 * We need to keep buttons states because interleaved 1413 * packets only signalize x/y movements. 1414 */ 1415 alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; 1416 } else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK) == 1417 PMS_ALPS_INTERLEAVED_VALID) { 1418 sc->inputstate = 3; 1419 pos = 3; 1420 } else { 1421 return (0); 1422 } 1423 1424 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0) 1425 return (1); 1426 1427 dx = (sc->packet[pos] & PMS_PS2_XNEG) ? 1428 (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1]; 1429 dy = (sc->packet[pos] & PMS_PS2_YNEG) ? 1430 (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2]; 1431 1432 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, alps->sec_buttons, dx, dy, 0, 0); 1433 1434 return (1); 1435 } 1436 1437 int 1438 alps_get_hwinfo(struct pms_softc *sc) 1439 { 1440 struct alps_softc *alps = sc->alps; 1441 u_char resp[3]; 1442 int i; 1443 struct wsmousehw *hw; 1444 1445 if (pms_set_resolution(sc, 0) || 1446 pms_set_scaling(sc, 2) || 1447 pms_set_scaling(sc, 2) || 1448 pms_set_scaling(sc, 2) || 1449 pms_get_status(sc, resp)) { 1450 DPRINTF("%s: alps: model query error\n", DEVNAME(sc)); 1451 return (-1); 1452 } 1453 1454 alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1); 1455 1456 for (i = 0; i < nitems(alps_models); i++) 1457 if (alps->version == alps_models[i].version) { 1458 alps->model = alps_models[i].model; 1459 alps->mask = alps_models[i].mask; 1460 1461 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1462 hw->type = WSMOUSE_TYPE_ALPS; 1463 hw->hw_type = WSMOUSEHW_TOUCHPAD; 1464 hw->x_min = ALPS_XMIN_BEZEL; 1465 hw->y_min = ALPS_YMIN_BEZEL; 1466 hw->x_max = ALPS_XMAX_BEZEL; 1467 hw->y_max = ALPS_YMAX_BEZEL; 1468 hw->contacts_max = 1; 1469 1470 return (0); 1471 } 1472 1473 return (-1); 1474 } 1475 1476 int 1477 pms_enable_alps(struct pms_softc *sc) 1478 { 1479 struct alps_softc *alps = sc->alps; 1480 struct wsmousedev_attach_args a; 1481 u_char resp[3]; 1482 1483 if (pms_set_resolution(sc, 0) || 1484 pms_set_scaling(sc, 1) || 1485 pms_set_scaling(sc, 1) || 1486 pms_set_scaling(sc, 1) || 1487 pms_get_status(sc, resp) || 1488 resp[0] != PMS_ALPS_MAGIC1 || 1489 resp[1] != PMS_ALPS_MAGIC2 || 1490 (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2 && 1491 resp[2] != PMS_ALPS_MAGIC3_3)) 1492 goto err; 1493 1494 if (sc->alps == NULL) { 1495 sc->alps = alps = malloc(sizeof(struct alps_softc), 1496 M_DEVBUF, M_WAITOK | M_ZERO); 1497 if (alps == NULL) { 1498 printf("%s: alps: not enough memory\n", DEVNAME(sc)); 1499 goto err; 1500 } 1501 1502 if (alps_get_hwinfo(sc)) { 1503 free(sc->alps, M_DEVBUF, sizeof(struct alps_softc)); 1504 sc->alps = NULL; 1505 goto err; 1506 } 1507 1508 if (wsmouse_configure(sc->sc_wsmousedev, alps_params, 1509 nitems(alps_params))) { 1510 free(sc->alps, M_DEVBUF, sizeof(struct alps_softc)); 1511 sc->alps = NULL; 1512 printf("%s: setup failed\n", DEVNAME(sc)); 1513 goto err; 1514 } 1515 1516 printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc), 1517 (alps->model & ALPS_DUALPOINT ? "Dualpoint" : "Glidepoint"), 1518 alps->version); 1519 1520 1521 if (alps->model & ALPS_DUALPOINT) { 1522 a.accessops = &pms_sec_accessops; 1523 a.accesscookie = sc; 1524 sc->sc_sec_wsmousedev = config_found((void *)sc, &a, 1525 wsmousedevprint); 1526 } 1527 } 1528 1529 if (alps->model == 0) 1530 goto err; 1531 1532 if ((alps->model & ALPS_PASSTHROUGH) && 1533 (pms_set_scaling(sc, 2) || 1534 pms_set_scaling(sc, 2) || 1535 pms_set_scaling(sc, 2) || 1536 pms_dev_disable(sc))) { 1537 DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc)); 1538 goto err; 1539 } 1540 1541 if (pms_dev_disable(sc) || 1542 pms_dev_disable(sc) || 1543 pms_set_rate(sc, 0x0a)) { 1544 DPRINTF("%s: alps: tapping error\n", DEVNAME(sc)); 1545 goto err; 1546 } 1547 1548 if (pms_dev_disable(sc) || 1549 pms_dev_disable(sc) || 1550 pms_dev_disable(sc) || 1551 pms_dev_disable(sc) || 1552 pms_dev_enable(sc)) { 1553 DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc)); 1554 goto err; 1555 } 1556 1557 if ((alps->model & ALPS_PASSTHROUGH) && 1558 (pms_set_scaling(sc, 1) || 1559 pms_set_scaling(sc, 1) || 1560 pms_set_scaling(sc, 1) || 1561 pms_dev_disable(sc))) { 1562 DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc)); 1563 goto err; 1564 } 1565 1566 alps->sec_buttons = 0; 1567 1568 return (1); 1569 1570 err: 1571 pms_reset(sc); 1572 1573 return (0); 1574 } 1575 1576 int 1577 pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 1578 struct proc *p) 1579 { 1580 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 1581 int wsmode; 1582 struct wsmousehw *hw; 1583 1584 switch (cmd) { 1585 case WSMOUSEIO_GTYPE: 1586 *(u_int *)data = WSMOUSE_TYPE_ALPS; 1587 break; 1588 case WSMOUSEIO_GCALIBCOORDS: 1589 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1590 wsmc->minx = hw->x_min; 1591 wsmc->maxx = hw->x_max; 1592 wsmc->miny = hw->y_min; 1593 wsmc->maxy = hw->y_max; 1594 wsmc->swapxy = 0; 1595 break; 1596 case WSMOUSEIO_SETMODE: 1597 wsmode = *(u_int *)data; 1598 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 1599 return (EINVAL); 1600 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 1601 break; 1602 default: 1603 return (-1); 1604 } 1605 return (0); 1606 } 1607 1608 int 1609 pms_sync_alps(struct pms_softc *sc, int data) 1610 { 1611 struct alps_softc *alps = sc->alps; 1612 1613 if ((alps->model & ALPS_DUALPOINT) && 1614 (sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) { 1615 if (sc->inputstate == 2) 1616 sc->inputstate += 3; 1617 return (0); 1618 } 1619 1620 switch (sc->inputstate) { 1621 case 0: 1622 if ((data & alps->mask) != alps->mask) 1623 return (-1); 1624 break; 1625 case 1: 1626 case 2: 1627 case 3: 1628 if ((data & PMS_ALPS_MASK) != PMS_ALPS_VALID) 1629 return (-1); 1630 break; 1631 case 4: 1632 case 5: 1633 if ((alps->model & ALPS_INTERLEAVED) == 0 && 1634 (data & PMS_ALPS_MASK) != PMS_ALPS_VALID) 1635 return (-1); 1636 break; 1637 } 1638 1639 return (0); 1640 } 1641 1642 void 1643 pms_proc_alps(struct pms_softc *sc) 1644 { 1645 struct alps_softc *alps = sc->alps; 1646 int x, y, z, dx, dy; 1647 u_int buttons, gesture; 1648 1649 if ((alps->model & ALPS_DUALPOINT) && alps_sec_proc(sc)) 1650 return; 1651 1652 x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4); 1653 y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3); 1654 z = sc->packet[5]; 1655 1656 buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) | 1657 ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) | 1658 ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0); 1659 1660 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) && z == ALPS_Z_MAGIC) { 1661 dx = (x > ALPS_XSEC_BEZEL / 2) ? (x - ALPS_XSEC_BEZEL) : x; 1662 dy = (y > ALPS_YSEC_BEZEL / 2) ? (y - ALPS_YSEC_BEZEL) : y; 1663 1664 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0); 1665 1666 return; 1667 } 1668 1669 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 1670 return; 1671 1672 /* 1673 * XXX The Y-axis is in the oposit direction compared to 1674 * Synaptics touchpads and PS/2 mouses. 1675 * It's why we need to translate the y value here for both 1676 * NATIVE and COMPAT modes. 1677 */ 1678 y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL; 1679 1680 if (alps->gesture == ALPS_TAP) { 1681 /* Report a touch with the tap coordinates. */ 1682 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, 1683 alps->old_x, alps->old_y, ALPS_PRESSURE, 0); 1684 if (z > 0) { 1685 /* 1686 * The hardware doesn't send a null pressure 1687 * event when dragging starts. 1688 */ 1689 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, 1690 alps->old_x, alps->old_y, 0, 0); 1691 } 1692 } 1693 1694 gesture = sc->packet[2] & 0x03; 1695 if (gesture != ALPS_TAP) 1696 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, 0); 1697 1698 if (alps->gesture != ALPS_DRAG || gesture != ALPS_TAP) 1699 alps->gesture = gesture; 1700 1701 alps->old_x = x; 1702 alps->old_y = y; 1703 } 1704 1705 int 1706 elantech_set_absolute_mode_v1(struct pms_softc *sc) 1707 { 1708 int i; 1709 u_char resp[3]; 1710 1711 /* Enable absolute mode. Magic numbers from Linux driver. */ 1712 if (pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1713 pms_spec_cmd(sc, 0x10) || 1714 pms_spec_cmd(sc, 0x16) || 1715 pms_set_scaling(sc, 1) || 1716 pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1717 pms_spec_cmd(sc, 0x11) || 1718 pms_spec_cmd(sc, 0x8f) || 1719 pms_set_scaling(sc, 1)) 1720 return (-1); 1721 1722 /* Read back reg 0x10 to ensure hardware is ready. */ 1723 for (i = 0; i < 5; i++) { 1724 if (pms_spec_cmd(sc, ELANTECH_CMD_READ_REG) || 1725 pms_spec_cmd(sc, 0x10) || 1726 pms_get_status(sc, resp) == 0) 1727 break; 1728 delay(2000); 1729 } 1730 if (i == 5) 1731 return (-1); 1732 1733 if ((resp[0] & ELANTECH_ABSOLUTE_MODE) == 0) 1734 return (-1); 1735 1736 return (0); 1737 } 1738 1739 int 1740 elantech_set_absolute_mode_v2(struct pms_softc *sc) 1741 { 1742 int i; 1743 u_char resp[3]; 1744 u_char reg10 = (sc->elantech->fw_version == 0x20030 ? 0x54 : 0xc4); 1745 1746 /* Enable absolute mode. Magic numbers from Linux driver. */ 1747 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1748 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1749 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1750 elantech_ps2_cmd(sc, 0x10) || 1751 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1752 elantech_ps2_cmd(sc, reg10) || 1753 pms_set_scaling(sc, 1) || 1754 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1755 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1756 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1757 elantech_ps2_cmd(sc, 0x11) || 1758 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1759 elantech_ps2_cmd(sc, 0x88) || 1760 pms_set_scaling(sc, 1)) 1761 return (-1); 1762 1763 /* Read back reg 0x10 to ensure hardware is ready. */ 1764 for (i = 0; i < 5; i++) { 1765 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1766 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_REG) || 1767 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1768 elantech_ps2_cmd(sc, 0x10) || 1769 pms_get_status(sc, resp) == 0) 1770 break; 1771 delay(2000); 1772 } 1773 if (i == 5) 1774 return (-1); 1775 1776 return (0); 1777 } 1778 1779 int 1780 elantech_set_absolute_mode_v3(struct pms_softc *sc) 1781 { 1782 int i; 1783 u_char resp[3]; 1784 1785 /* Enable absolute mode. Magic numbers from Linux driver. */ 1786 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1787 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1788 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1789 elantech_ps2_cmd(sc, 0x10) || 1790 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1791 elantech_ps2_cmd(sc, 0x0b) || 1792 pms_set_scaling(sc, 1)) 1793 return (-1); 1794 1795 /* Read back reg 0x10 to ensure hardware is ready. */ 1796 for (i = 0; i < 5; i++) { 1797 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1798 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1799 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1800 elantech_ps2_cmd(sc, 0x10) || 1801 pms_get_status(sc, resp) == 0) 1802 break; 1803 delay(2000); 1804 } 1805 if (i == 5) 1806 return (-1); 1807 1808 return (0); 1809 } 1810 1811 int 1812 elantech_set_absolute_mode_v4(struct pms_softc *sc) 1813 { 1814 /* Enable absolute mode. Magic numbers from Linux driver. */ 1815 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1816 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1817 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1818 elantech_ps2_cmd(sc, 0x07) || 1819 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1820 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1821 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1822 elantech_ps2_cmd(sc, 0x01) || 1823 pms_set_scaling(sc, 1)) 1824 return (-1); 1825 1826 /* v4 has no register 0x10 to read response from */ 1827 1828 return (0); 1829 } 1830 1831 int 1832 elantech_get_hwinfo_v1(struct pms_softc *sc) 1833 { 1834 struct elantech_softc *elantech = sc->elantech; 1835 struct wsmousehw *hw; 1836 int fw_version; 1837 u_char capabilities[3]; 1838 1839 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1840 return (-1); 1841 1842 if (fw_version < 0x20030 || fw_version == 0x20600) { 1843 if (fw_version < 0x20000) 1844 elantech->flags |= ELANTECH_F_HW_V1_OLD; 1845 } else 1846 return (-1); 1847 1848 elantech->fw_version = fw_version; 1849 1850 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1851 pms_get_status(sc, capabilities)) 1852 return (-1); 1853 1854 if (capabilities[0] & ELANTECH_CAP_HAS_ROCKER) 1855 elantech->flags |= ELANTECH_F_HAS_ROCKER; 1856 1857 if (elantech_set_absolute_mode_v1(sc)) 1858 return (-1); 1859 1860 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1861 hw->type = WSMOUSE_TYPE_ELANTECH; 1862 hw->hw_type = WSMOUSEHW_TOUCHPAD; 1863 hw->x_min = ELANTECH_V1_X_MIN; 1864 hw->x_max = ELANTECH_V1_X_MAX; 1865 hw->y_min = ELANTECH_V1_Y_MIN; 1866 hw->y_max = ELANTECH_V1_Y_MAX; 1867 1868 return (0); 1869 } 1870 1871 int 1872 elantech_get_hwinfo_v2(struct pms_softc *sc) 1873 { 1874 struct elantech_softc *elantech = sc->elantech; 1875 struct wsmousehw *hw; 1876 int fw_version, ic_ver; 1877 u_char capabilities[3]; 1878 int i, fixed_dpi; 1879 u_char resp[3]; 1880 1881 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1882 return (-1); 1883 1884 ic_ver = (fw_version & 0x0f0000) >> 16; 1885 if (ic_ver != 2 && ic_ver != 4) 1886 return (-1); 1887 1888 elantech->fw_version = fw_version; 1889 if (fw_version >= 0x20800) 1890 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1891 1892 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1893 pms_get_status(sc, capabilities)) 1894 return (-1); 1895 1896 if (elantech_set_absolute_mode_v2(sc)) 1897 return (-1); 1898 1899 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1900 hw->type = WSMOUSE_TYPE_ELANTECH; 1901 hw->hw_type = WSMOUSEHW_TOUCHPAD; 1902 1903 if (fw_version == 0x20800 || fw_version == 0x20b00 || 1904 fw_version == 0x20030) { 1905 hw->x_max = ELANTECH_V2_X_MAX; 1906 hw->y_max = ELANTECH_V2_Y_MAX; 1907 } else { 1908 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 1909 pms_get_status(sc, resp)) 1910 return (-1); 1911 fixed_dpi = resp[1] & 0x10; 1912 i = (fw_version > 0x20800 && fw_version < 0x20900) ? 1 : 2; 1913 if ((fw_version >> 16) == 0x14 && fixed_dpi) { 1914 if (pms_spec_cmd(sc, ELANTECH_QUE_SAMPLE) || 1915 pms_get_status(sc, resp)) 1916 return (-1); 1917 hw->x_max = (capabilities[1] - i) * resp[1] / 2; 1918 hw->y_max = (capabilities[2] - i) * resp[2] / 2; 1919 } else if (fw_version == 0x040216) { 1920 hw->x_max = 819; 1921 hw->y_max = 405; 1922 } else if (fw_version == 0x040219 || fw_version == 0x040215) { 1923 hw->x_max = 900; 1924 hw->y_max = 500; 1925 } else { 1926 hw->x_max = (capabilities[1] - i) * 64; 1927 hw->y_max = (capabilities[2] - i) * 64; 1928 } 1929 } 1930 1931 return (0); 1932 } 1933 1934 int 1935 elantech_get_hwinfo_v3(struct pms_softc *sc) 1936 { 1937 struct elantech_softc *elantech = sc->elantech; 1938 struct wsmousehw *hw; 1939 int fw_version; 1940 u_char resp[3]; 1941 1942 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1943 return (-1); 1944 1945 if (((fw_version & 0x0f0000) >> 16) != 5) 1946 return (-1); 1947 1948 elantech->fw_version = fw_version; 1949 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1950 1951 if ((fw_version & 0x4000) == 0x4000) 1952 elantech->flags |= ELANTECH_F_CRC_ENABLED; 1953 1954 if (elantech_set_absolute_mode_v3(sc)) 1955 return (-1); 1956 1957 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 1958 pms_get_status(sc, resp)) 1959 return (-1); 1960 1961 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1962 hw->x_max = elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1]; 1963 hw->y_max = elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2]; 1964 1965 hw->type = WSMOUSE_TYPE_ELANTECH; 1966 hw->hw_type = WSMOUSEHW_TOUCHPAD; 1967 1968 return (0); 1969 } 1970 1971 int 1972 elantech_get_hwinfo_v4(struct pms_softc *sc) 1973 { 1974 struct elantech_softc *elantech = sc->elantech; 1975 struct wsmousehw *hw; 1976 int fw_version; 1977 u_char capabilities[3]; 1978 u_char resp[3]; 1979 1980 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1981 return (-1); 1982 1983 if ((fw_version & 0x0f0000) >> 16 < 6) 1984 return (-1); 1985 1986 elantech->fw_version = fw_version; 1987 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1988 1989 if ((fw_version & 0x4000) == 0x4000) 1990 elantech->flags |= ELANTECH_F_CRC_ENABLED; 1991 1992 if (elantech_set_absolute_mode_v4(sc)) 1993 return (-1); 1994 1995 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1996 pms_get_status(sc, capabilities)) 1997 return (-1); 1998 1999 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 2000 pms_get_status(sc, resp)) 2001 return (-1); 2002 2003 hw = wsmouse_get_hw(sc->sc_wsmousedev); 2004 hw->x_max = (resp[0] & 0x0f) << 8 | resp[1]; 2005 hw->y_max = (resp[0] & 0xf0) << 4 | resp[2]; 2006 2007 if ((capabilities[1] < 2) || (capabilities[1] > hw->x_max)) 2008 return (-1); 2009 2010 if (capabilities[0] & ELANTECH_CAP_TRACKPOINT) 2011 elantech->flags |= ELANTECH_F_TRACKPOINT; 2012 2013 hw->type = WSMOUSE_TYPE_ELANTECH; 2014 hw->hw_type = (ELANTECH_IS_CLICKPAD(sc) 2015 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD); 2016 hw->mt_slots = ELANTECH_MAX_FINGERS; 2017 2018 elantech->width = hw->x_max / (capabilities[1] - 1); 2019 2020 return (0); 2021 } 2022 2023 int 2024 elantech_ps2_cmd(struct pms_softc *sc, u_char command) 2025 { 2026 u_char cmd[1]; 2027 2028 cmd[0] = command; 2029 return (pms_cmd(sc, cmd, 1, NULL, 0)); 2030 } 2031 2032 int 2033 elantech_knock(struct pms_softc *sc) 2034 { 2035 u_char resp[3]; 2036 2037 if (pms_dev_disable(sc) || 2038 pms_set_scaling(sc, 1) || 2039 pms_set_scaling(sc, 1) || 2040 pms_set_scaling(sc, 1) || 2041 pms_get_status(sc, resp) || 2042 resp[0] != PMS_ELANTECH_MAGIC1 || 2043 resp[1] != PMS_ELANTECH_MAGIC2 || 2044 (resp[2] != PMS_ELANTECH_MAGIC3_1 && 2045 resp[2] != PMS_ELANTECH_MAGIC3_2)) 2046 return (-1); 2047 2048 return (0); 2049 } 2050 2051 int 2052 pms_enable_elantech_v1(struct pms_softc *sc) 2053 { 2054 struct elantech_softc *elantech = sc->elantech; 2055 int i; 2056 2057 if (elantech_knock(sc)) 2058 goto err; 2059 2060 if (sc->elantech == NULL) { 2061 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2062 M_DEVBUF, M_WAITOK | M_ZERO); 2063 if (elantech == NULL) { 2064 printf("%s: elantech: not enough memory\n", 2065 DEVNAME(sc)); 2066 goto err; 2067 } 2068 2069 if (elantech_get_hwinfo_v1(sc)) { 2070 free(sc->elantech, M_DEVBUF, 2071 sizeof(struct elantech_softc)); 2072 sc->elantech = NULL; 2073 goto err; 2074 } 2075 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { 2076 free(sc->elantech, M_DEVBUF, 2077 sizeof(struct elantech_softc)); 2078 sc->elantech = NULL; 2079 printf("%s: elantech: setup failed\n", DEVNAME(sc)); 2080 goto err; 2081 } 2082 2083 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 2084 DEVNAME(sc), 1, sc->elantech->fw_version); 2085 } else if (elantech_set_absolute_mode_v1(sc)) 2086 goto err; 2087 2088 for (i = 0; i < nitems(sc->elantech->parity); i++) 2089 sc->elantech->parity[i] = sc->elantech->parity[i & (i - 1)] ^ 1; 2090 2091 return (1); 2092 2093 err: 2094 pms_reset(sc); 2095 2096 return (0); 2097 } 2098 2099 int 2100 pms_enable_elantech_v2(struct pms_softc *sc) 2101 { 2102 struct elantech_softc *elantech = sc->elantech; 2103 2104 if (elantech_knock(sc)) 2105 goto err; 2106 2107 if (sc->elantech == NULL) { 2108 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2109 M_DEVBUF, M_WAITOK | M_ZERO); 2110 if (elantech == NULL) { 2111 printf("%s: elantech: not enough memory\n", 2112 DEVNAME(sc)); 2113 goto err; 2114 } 2115 2116 if (elantech_get_hwinfo_v2(sc)) { 2117 free(sc->elantech, M_DEVBUF, 2118 sizeof(struct elantech_softc)); 2119 sc->elantech = NULL; 2120 goto err; 2121 } 2122 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { 2123 free(sc->elantech, M_DEVBUF, 2124 sizeof(struct elantech_softc)); 2125 sc->elantech = NULL; 2126 printf("%s: elantech: setup failed\n", DEVNAME(sc)); 2127 goto err; 2128 } 2129 2130 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 2131 DEVNAME(sc), 2, sc->elantech->fw_version); 2132 } else if (elantech_set_absolute_mode_v2(sc)) 2133 goto err; 2134 2135 return (1); 2136 2137 err: 2138 pms_reset(sc); 2139 2140 return (0); 2141 } 2142 2143 int 2144 pms_enable_elantech_v3(struct pms_softc *sc) 2145 { 2146 struct elantech_softc *elantech = sc->elantech; 2147 2148 if (elantech_knock(sc)) 2149 goto err; 2150 2151 if (sc->elantech == NULL) { 2152 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2153 M_DEVBUF, M_WAITOK | M_ZERO); 2154 if (elantech == NULL) { 2155 printf("%s: elantech: not enough memory\n", 2156 DEVNAME(sc)); 2157 goto err; 2158 } 2159 2160 if (elantech_get_hwinfo_v3(sc)) { 2161 free(sc->elantech, M_DEVBUF, 2162 sizeof(struct elantech_softc)); 2163 sc->elantech = NULL; 2164 goto err; 2165 } 2166 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { 2167 free(sc->elantech, M_DEVBUF, 2168 sizeof(struct elantech_softc)); 2169 sc->elantech = NULL; 2170 printf("%s: elantech: setup failed\n", DEVNAME(sc)); 2171 goto err; 2172 } 2173 2174 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 2175 DEVNAME(sc), 3, sc->elantech->fw_version); 2176 } else if (elantech_set_absolute_mode_v3(sc)) 2177 goto err; 2178 2179 return (1); 2180 2181 err: 2182 pms_reset(sc); 2183 2184 return (0); 2185 } 2186 2187 int 2188 pms_enable_elantech_v4(struct pms_softc *sc) 2189 { 2190 struct elantech_softc *elantech = sc->elantech; 2191 struct wsmousedev_attach_args a; 2192 2193 if (elantech_knock(sc)) 2194 goto err; 2195 2196 if (sc->elantech == NULL) { 2197 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2198 M_DEVBUF, M_WAITOK | M_ZERO); 2199 if (elantech == NULL) { 2200 printf("%s: elantech: not enough memory\n", 2201 DEVNAME(sc)); 2202 goto err; 2203 } 2204 2205 if (elantech_get_hwinfo_v4(sc)) { 2206 free(sc->elantech, M_DEVBUF, 2207 sizeof(struct elantech_softc)); 2208 sc->elantech = NULL; 2209 goto err; 2210 } 2211 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { 2212 free(sc->elantech, M_DEVBUF, 2213 sizeof(struct elantech_softc)); 2214 sc->elantech = NULL; 2215 printf("%s: elantech: setup failed\n", DEVNAME(sc)); 2216 goto err; 2217 } 2218 2219 printf("%s: Elantech %s, version 4, firmware 0x%x\n", 2220 DEVNAME(sc), (ELANTECH_IS_CLICKPAD(sc) ? "Clickpad" 2221 : "Touchpad"), sc->elantech->fw_version); 2222 2223 if (sc->elantech->flags & ELANTECH_F_TRACKPOINT) { 2224 a.accessops = &pms_sec_accessops; 2225 a.accesscookie = sc; 2226 sc->sc_sec_wsmousedev = config_found((void *) sc, &a, 2227 wsmousedevprint); 2228 } 2229 2230 } else if (elantech_set_absolute_mode_v4(sc)) 2231 goto err; 2232 2233 return (1); 2234 2235 err: 2236 pms_reset(sc); 2237 2238 return (0); 2239 } 2240 2241 int 2242 pms_ioctl_elantech(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 2243 struct proc *p) 2244 { 2245 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 2246 struct wsmousehw *hw; 2247 int wsmode; 2248 2249 switch (cmd) { 2250 case WSMOUSEIO_GTYPE: 2251 *(u_int *)data = WSMOUSE_TYPE_ELANTECH; 2252 break; 2253 case WSMOUSEIO_GCALIBCOORDS: 2254 hw = wsmouse_get_hw(sc->sc_wsmousedev); 2255 wsmc->minx = hw->x_min; 2256 wsmc->maxx = hw->x_max; 2257 wsmc->miny = hw->y_min; 2258 wsmc->maxy = hw->y_max; 2259 wsmc->swapxy = 0; 2260 wsmc->resx = hw->h_res; 2261 wsmc->resy = hw->v_res; 2262 break; 2263 case WSMOUSEIO_SETMODE: 2264 wsmode = *(u_int *)data; 2265 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 2266 return (EINVAL); 2267 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 2268 break; 2269 default: 2270 return (-1); 2271 } 2272 return (0); 2273 } 2274 2275 int 2276 pms_sync_elantech_v1(struct pms_softc *sc, int data) 2277 { 2278 struct elantech_softc *elantech = sc->elantech; 2279 u_char p; 2280 2281 switch (sc->inputstate) { 2282 case 0: 2283 if (elantech->flags & ELANTECH_F_HW_V1_OLD) { 2284 elantech->p1 = (data & 0x20) >> 5; 2285 elantech->p2 = (data & 0x10) >> 4; 2286 } else { 2287 elantech->p1 = (data & 0x10) >> 4; 2288 elantech->p2 = (data & 0x20) >> 5; 2289 } 2290 elantech->p3 = (data & 0x04) >> 2; 2291 return (0); 2292 case 1: 2293 p = elantech->p1; 2294 break; 2295 case 2: 2296 p = elantech->p2; 2297 break; 2298 case 3: 2299 p = elantech->p3; 2300 break; 2301 default: 2302 return (-1); 2303 } 2304 2305 if (data < 0 || data >= nitems(elantech->parity) || 2306 /* 2307 * FW 0x20022 sends inverted parity bits on cold boot, returning 2308 * to normal after suspend & resume, so the parity check is 2309 * disabled for this one. 2310 */ 2311 (elantech->fw_version != 0x20022 && elantech->parity[data] != p)) 2312 return (-1); 2313 2314 return (0); 2315 } 2316 2317 int 2318 pms_sync_elantech_v2(struct pms_softc *sc, int data) 2319 { 2320 struct elantech_softc *elantech = sc->elantech; 2321 2322 /* Variants reporting pressure always have the same constant bits. */ 2323 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) { 2324 if (sc->inputstate == 0 && (data & 0x0c) != 0x04) 2325 return (-1); 2326 if (sc->inputstate == 3 && (data & 0x0f) != 0x02) 2327 return (-1); 2328 return (0); 2329 } 2330 2331 /* For variants not reporting pressure, 1 and 3 finger touch packets 2332 * have different constant bits than 2 finger touch packets. */ 2333 switch (sc->inputstate) { 2334 case 0: 2335 if ((data & 0xc0) == 0x80) { 2336 if ((data & 0x0c) != 0x0c) 2337 return (-1); 2338 elantech->flags |= ELANTECH_F_2FINGER_PACKET; 2339 } else { 2340 if ((data & 0x3c) != 0x3c) 2341 return (-1); 2342 elantech->flags &= ~ELANTECH_F_2FINGER_PACKET; 2343 } 2344 break; 2345 case 1: 2346 case 4: 2347 if (elantech->flags & ELANTECH_F_2FINGER_PACKET) 2348 break; 2349 if ((data & 0xf0) != 0x00) 2350 return (-1); 2351 break; 2352 case 3: 2353 if (elantech->flags & ELANTECH_F_2FINGER_PACKET) { 2354 if ((data & 0x0e) != 0x08) 2355 return (-1); 2356 } else { 2357 if ((data & 0x3e) != 0x38) 2358 return (-1); 2359 } 2360 break; 2361 default: 2362 break; 2363 } 2364 2365 return (0); 2366 } 2367 2368 int 2369 pms_sync_elantech_v3(struct pms_softc *sc, int data) 2370 { 2371 struct elantech_softc *elantech = sc->elantech; 2372 2373 switch (sc->inputstate) { 2374 case 0: 2375 if (elantech->flags & ELANTECH_F_CRC_ENABLED) 2376 break; 2377 if ((data & 0x0c) != 0x04 && (data & 0x0c) != 0x0c) 2378 return (-1); 2379 break; 2380 case 3: 2381 if (elantech->flags & ELANTECH_F_CRC_ENABLED) { 2382 if ((data & 0x09) != 0x08 && (data & 0x09) != 0x09) 2383 return (-1); 2384 } else { 2385 if ((data & 0xcf) != 0x02 && (data & 0xce) != 0x0c) 2386 return (-1); 2387 } 2388 break; 2389 } 2390 2391 return (0); 2392 } 2393 2394 /* Extract the type bits from packet[3]. */ 2395 static inline int 2396 elantech_packet_type(struct elantech_softc *elantech, u_char b) 2397 { 2398 /* 2399 * This looks dubious, but in the "crc-enabled" format bit 2 may 2400 * be set even in MOTION packets. 2401 */ 2402 if ((elantech->flags & ELANTECH_F_TRACKPOINT) && ((b & 0x0f) == 0x06)) 2403 return (ELANTECH_PKT_TRACKPOINT); 2404 else 2405 return (b & 0x03); 2406 } 2407 2408 int 2409 pms_sync_elantech_v4(struct pms_softc *sc, int data) 2410 { 2411 if (sc->inputstate == 0) 2412 return ((data & 0x08) == 0 ? 0 : -1); 2413 2414 if (sc->inputstate == 3) { 2415 switch (elantech_packet_type(sc->elantech, data)) { 2416 case ELANTECH_V4_PKT_STATUS: 2417 case ELANTECH_V4_PKT_HEAD: 2418 case ELANTECH_V4_PKT_MOTION: 2419 if (sc->elantech->flags & ELANTECH_F_CRC_ENABLED) 2420 return ((data & 0x08) == 0 ? 0 : -1); 2421 else 2422 return ((data & 0x1c) == 0x10 ? 0 : -1); 2423 case ELANTECH_PKT_TRACKPOINT: 2424 return ((sc->packet[0] & 0xc8) == 0 2425 && sc->packet[1] == ((data & 0x10) << 3) 2426 && sc->packet[2] == ((data & 0x20) << 2) 2427 && (data ^ (sc->packet[0] & 0x30)) == 0x36 2428 ? 0 : -1); 2429 } 2430 return (-1); 2431 } 2432 return (0); 2433 } 2434 2435 void 2436 pms_proc_elantech_v1(struct pms_softc *sc) 2437 { 2438 struct elantech_softc *elantech = sc->elantech; 2439 int x, y, w, z; 2440 u_int buttons; 2441 2442 buttons = butmap[sc->packet[0] & 3]; 2443 2444 if (elantech->flags & ELANTECH_F_HAS_ROCKER) { 2445 if (sc->packet[0] & 0x40) /* up */ 2446 buttons |= WSMOUSE_BUTTON(4); 2447 if (sc->packet[0] & 0x80) /* down */ 2448 buttons |= WSMOUSE_BUTTON(5); 2449 } 2450 2451 if (elantech->flags & ELANTECH_F_HW_V1_OLD) 2452 w = ((sc->packet[1] & 0x80) >> 7) + 2453 ((sc->packet[1] & 0x30) >> 4); 2454 else 2455 w = (sc->packet[0] & 0xc0) >> 6; 2456 2457 /* 2458 * Firmwares 0x20022 and 0x20600 have a bug, position data in the 2459 * first two reports for single-touch contacts may be corrupt. 2460 */ 2461 if (elantech->fw_version == 0x20022 || 2462 elantech->fw_version == 0x20600) { 2463 if (w == 1) { 2464 if (elantech->initial_pkt < 2) { 2465 elantech->initial_pkt++; 2466 return; 2467 } 2468 } else if (elantech->initial_pkt) { 2469 elantech->initial_pkt = 0; 2470 } 2471 } 2472 2473 /* Hardware version 1 doesn't report pressure. */ 2474 if (w) { 2475 x = ((sc->packet[1] & 0x0c) << 6) | sc->packet[2]; 2476 y = ((sc->packet[1] & 0x03) << 8) | sc->packet[3]; 2477 z = SYNAPTICS_PRESSURE; 2478 } else { 2479 x = y = z = 0; 2480 } 2481 2482 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 2483 } 2484 2485 void 2486 pms_proc_elantech_v2(struct pms_softc *sc) 2487 { 2488 const u_char debounce_pkt[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff }; 2489 struct elantech_softc *elantech = sc->elantech; 2490 int x, y, w, z; 2491 u_int buttons; 2492 2493 /* 2494 * The hardware sends this packet when in debounce state. 2495 * The packet should be ignored. 2496 */ 2497 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))) 2498 return; 2499 2500 buttons = butmap[sc->packet[0] & 3]; 2501 2502 w = (sc->packet[0] & 0xc0) >> 6; 2503 if (w == 1 || w == 3) { 2504 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2]; 2505 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5]; 2506 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) 2507 z = ((sc->packet[1] & 0xf0) | 2508 (sc->packet[4] & 0xf0) >> 4); 2509 else 2510 z = SYNAPTICS_PRESSURE; 2511 } else if (w == 2) { 2512 x = (((sc->packet[0] & 0x10) << 4) | sc->packet[1]) << 2; 2513 y = (((sc->packet[0] & 0x20) << 3) | sc->packet[2]) << 2; 2514 z = SYNAPTICS_PRESSURE; 2515 } else { 2516 x = y = z = 0; 2517 } 2518 2519 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 2520 } 2521 2522 void 2523 pms_proc_elantech_v3(struct pms_softc *sc) 2524 { 2525 const u_char debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff }; 2526 struct elantech_softc *elantech = sc->elantech; 2527 int x, y, w, z; 2528 u_int buttons; 2529 2530 buttons = butmap[sc->packet[0] & 3]; 2531 2532 x = ((sc->packet[1] & 0x0f) << 8 | sc->packet[2]); 2533 y = ((sc->packet[4] & 0x0f) << 8 | sc->packet[5]); 2534 z = 0; 2535 w = (sc->packet[0] & 0xc0) >> 6; 2536 if (w == 2) { 2537 /* 2538 * Two-finger touch causes two packets -- a head packet 2539 * and a tail packet. We report a single event and ignore 2540 * the tail packet. 2541 */ 2542 if (elantech->flags & ELANTECH_F_CRC_ENABLED) { 2543 if ((sc->packet[3] & 0x09) != 0x08) 2544 return; 2545 } else { 2546 /* The hardware sends this packet when in debounce state. 2547 * The packet should be ignored. */ 2548 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))) 2549 return; 2550 if ((sc->packet[0] & 0x0c) != 0x04 && 2551 (sc->packet[3] & 0xcf) != 0x02) { 2552 /* not the head packet -- ignore */ 2553 return; 2554 } 2555 } 2556 } 2557 2558 /* Prevent jumping cursor if pad isn't touched or reports garbage. */ 2559 if (w == 0 || 2560 ((x == 0 || y == 0 || x == elantech->max_x || y == elantech->max_y) 2561 && (x != elantech->old_x || y != elantech->old_y))) { 2562 x = elantech->old_x; 2563 y = elantech->old_y; 2564 } 2565 2566 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) 2567 z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4); 2568 else if (w) 2569 z = SYNAPTICS_PRESSURE; 2570 2571 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 2572 elantech->old_x = x; 2573 elantech->old_y = y; 2574 } 2575 2576 void 2577 pms_proc_elantech_v4(struct pms_softc *sc) 2578 { 2579 struct elantech_softc *elantech = sc->elantech; 2580 struct device *sc_wsmousedev = sc->sc_wsmousedev; 2581 int id, weight, n, x, y, z; 2582 u_int buttons, slots; 2583 2584 switch (elantech_packet_type(elantech, sc->packet[3])) { 2585 case ELANTECH_V4_PKT_STATUS: 2586 slots = elantech->mt_slots; 2587 elantech->mt_slots = sc->packet[1] & 0x1f; 2588 slots &= ~elantech->mt_slots; 2589 for (id = 0; slots; id++, slots >>= 1) { 2590 if (slots & 1) 2591 wsmouse_mtstate(sc_wsmousedev, id, 0, 0, 0); 2592 } 2593 break; 2594 2595 case ELANTECH_V4_PKT_HEAD: 2596 id = ((sc->packet[3] & 0xe0) >> 5) - 1; 2597 if (id > -1 && id < ELANTECH_MAX_FINGERS) { 2598 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2]; 2599 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5]; 2600 z = (sc->packet[1] & 0xf0) 2601 | ((sc->packet[4] & 0xf0) >> 4); 2602 wsmouse_mtstate(sc_wsmousedev, id, x, y, z); 2603 } 2604 break; 2605 2606 case ELANTECH_V4_PKT_MOTION: 2607 weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE : 1; 2608 for (n = 0; n < 6; n += 3) { 2609 id = ((sc->packet[n] & 0xe0) >> 5) - 1; 2610 if (id < 0 || id >= ELANTECH_MAX_FINGERS) 2611 continue; 2612 x = weight * (signed char)sc->packet[n + 1]; 2613 y = weight * (signed char)sc->packet[n + 2]; 2614 z = WSMOUSE_DEFAULT_PRESSURE; 2615 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_X, x, id); 2616 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_Y, y, id); 2617 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_PRESSURE, z, id); 2618 } 2619 break; 2620 2621 case ELANTECH_PKT_TRACKPOINT: 2622 if (sc->sc_dev_enable & PMS_DEV_SECONDARY) { 2623 /* 2624 * This firmware misreport coordinates for trackpoint 2625 * occasionally. Discard packets outside of [-127, 127] range 2626 * to prevent cursor jumps. 2627 */ 2628 if (sc->packet[4] == 0x80 || sc->packet[5] == 0x80 || 2629 sc->packet[1] >> 7 == sc->packet[4] >> 7 || 2630 sc->packet[2] >> 7 == sc->packet[5] >> 7) 2631 return; 2632 2633 x = sc->packet[4] - 0x100 + (sc->packet[1] << 1); 2634 y = sc->packet[5] - 0x100 + (sc->packet[2] << 1); 2635 buttons = butmap[sc->packet[0] & 7]; 2636 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, 2637 buttons, x, y, 0, 0); 2638 } 2639 return; 2640 2641 default: 2642 printf("%s: unknown packet type 0x%x\n", DEVNAME(sc), 2643 sc->packet[3] & 0x1f); 2644 return; 2645 } 2646 2647 buttons = butmap[sc->packet[0] & 3]; 2648 wsmouse_buttons(sc_wsmousedev, buttons); 2649 2650 wsmouse_input_sync(sc_wsmousedev); 2651 } 2652