1 /* $OpenBSD: pms.c,v 1.95 2020/10/23 22:06:27 bru 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 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 782 switch (act) { 783 case DVACT_SUSPEND: 784 if (sc->sc_state == PMS_STATE_ENABLED) 785 pms_change_state(sc, PMS_STATE_SUSPENDED, 786 PMS_DEV_IGNORE); 787 break; 788 case DVACT_RESUME: 789 if (sc->sc_state == PMS_STATE_SUSPENDED) 790 pms_change_state(sc, PMS_STATE_ENABLED, 791 PMS_DEV_IGNORE); 792 break; 793 } 794 return (0); 795 } 796 797 int 798 pms_change_state(struct pms_softc *sc, int newstate, int dev) 799 { 800 if (dev != PMS_DEV_IGNORE) { 801 switch (newstate) { 802 case PMS_STATE_ENABLED: 803 if (sc->sc_dev_enable & dev) 804 return (EBUSY); 805 806 sc->sc_dev_enable |= dev; 807 808 if (sc->sc_state == PMS_STATE_ENABLED) 809 return (0); 810 811 break; 812 case PMS_STATE_DISABLED: 813 sc->sc_dev_enable &= ~dev; 814 815 if (sc->sc_dev_enable) 816 return (0); 817 818 break; 819 } 820 } 821 822 switch (newstate) { 823 case PMS_STATE_ENABLED: 824 sc->inputstate = 0; 825 sc->sc_rststate = 0; 826 827 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1); 828 829 if (sc->poll) 830 pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT); 831 832 pms_reset(sc); 833 if (sc->protocol->enable != NULL && 834 sc->protocol->enable(sc) == 0) 835 pms_protocol_lookup(sc); 836 837 pms_dev_enable(sc); 838 break; 839 case PMS_STATE_DISABLED: 840 case PMS_STATE_SUSPENDED: 841 pms_dev_disable(sc); 842 843 if (sc->protocol->disable) 844 sc->protocol->disable(sc); 845 846 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0); 847 break; 848 } 849 850 sc->sc_state = newstate; 851 sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0; 852 853 return (0); 854 } 855 856 int 857 pms_enable(void *v) 858 { 859 struct pms_softc *sc = v; 860 int rv; 861 862 rw_enter_write(&sc->sc_state_lock); 863 rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY); 864 rw_exit_write(&sc->sc_state_lock); 865 866 return (rv); 867 } 868 869 void 870 pms_disable(void *v) 871 { 872 struct pms_softc *sc = v; 873 874 rw_enter_write(&sc->sc_state_lock); 875 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY); 876 rw_exit_write(&sc->sc_state_lock); 877 } 878 879 int 880 pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 881 { 882 struct pms_softc *sc = v; 883 884 if (sc->protocol->ioctl) 885 return (sc->protocol->ioctl(sc, cmd, data, flag, p)); 886 else 887 return (-1); 888 } 889 890 int 891 pms_sec_enable(void *v) 892 { 893 struct pms_softc *sc = v; 894 int rv; 895 896 rw_enter_write(&sc->sc_state_lock); 897 rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY); 898 rw_exit_write(&sc->sc_state_lock); 899 900 return (rv); 901 } 902 903 void 904 pms_sec_disable(void *v) 905 { 906 struct pms_softc *sc = v; 907 908 rw_enter_write(&sc->sc_state_lock); 909 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY); 910 rw_exit_write(&sc->sc_state_lock); 911 } 912 913 int 914 pms_sec_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 915 { 916 switch (cmd) { 917 case WSMOUSEIO_GTYPE: 918 *(u_int *)data = WSMOUSE_TYPE_PS2; 919 break; 920 default: 921 return (-1); 922 } 923 return (0); 924 } 925 926 #ifdef DIAGNOSTIC 927 static inline void 928 pms_print_packet(struct pms_softc *sc) 929 { 930 int i, state, size; 931 932 state = sc->inputstate; 933 size = sc->protocol->packetsize; 934 for (i = 0; i < size; i++) 935 printf(i == state ? " %02x |" : " %02x", sc->packet[i]); 936 } 937 #endif 938 939 void 940 pmsinput(void *vsc, int data) 941 { 942 struct pms_softc *sc = vsc; 943 944 if (sc->sc_state != PMS_STATE_ENABLED) { 945 /* Interrupts are not expected. Discard the byte. */ 946 return; 947 } 948 949 sc->packet[sc->inputstate] = data; 950 pms_reset_detect(sc, data); 951 if (sc->protocol->sync(sc, data)) { 952 #ifdef DIAGNOSTIC 953 printf("%s: not in sync yet, discard input " 954 "(state = %d,", 955 DEVNAME(sc), sc->inputstate); 956 pms_print_packet(sc); 957 printf(")\n"); 958 #endif 959 960 sc->inputstate = 0; 961 return; 962 } 963 964 sc->inputstate++; 965 966 if (sc->inputstate != sc->protocol->packetsize) 967 return; 968 969 sc->inputstate = 0; 970 sc->protocol->proc(sc); 971 } 972 973 int 974 synaptics_set_mode(struct pms_softc *sc, int mode, int rate) 975 { 976 struct synaptics_softc *syn = sc->synaptics; 977 978 if (pms_spec_cmd(sc, mode) || 979 pms_set_rate(sc, rate == 0 ? SYNAPTICS_CMD_SET_MODE : rate)) 980 return (-1); 981 982 /* 983 * Make sure that the set mode command has finished. 984 * Otherwise enabling the device before that will make it fail. 985 */ 986 delay(10000); 987 988 if (rate == 0) 989 syn->mode = mode; 990 991 return (0); 992 } 993 994 int 995 synaptics_query(struct pms_softc *sc, int query, int *val) 996 { 997 u_char resp[3]; 998 999 if (pms_spec_cmd(sc, query) || 1000 pms_get_status(sc, resp)) 1001 return (-1); 1002 1003 if (val) 1004 *val = (resp[0] << 16) | (resp[1] << 8) | resp[2]; 1005 1006 return (0); 1007 } 1008 1009 int 1010 synaptics_get_hwinfo(struct pms_softc *sc) 1011 { 1012 struct synaptics_softc *syn = sc->synaptics; 1013 struct wsmousehw *hw; 1014 int resolution = 0, max_coords = 0, min_coords = 0; 1015 1016 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1017 1018 if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY, &syn->identify)) 1019 return (-1); 1020 if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES, 1021 &syn->capabilities)) 1022 return (-1); 1023 if (synaptics_query(sc, SYNAPTICS_QUE_MODEL, &syn->model)) 1024 return (-1); 1025 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 1) && 1026 synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL, &syn->ext_model)) 1027 return (-1); 1028 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 4) && 1029 synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES, 1030 &syn->ext_capabilities)) 1031 return (-1); 1032 if ((SYNAPTICS_ID_MAJOR(syn->identify) >= 4) && 1033 synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION, &resolution)) 1034 return (-1); 1035 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 5) && 1036 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_COORDS) && 1037 synaptics_query(sc, SYNAPTICS_QUE_EXT_MAX_COORDS, &max_coords)) 1038 return (-1); 1039 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 7 || 1040 SYNAPTICS_ID_FULL(syn->identify) == 0x801) && 1041 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MIN_COORDS) && 1042 synaptics_query(sc, SYNAPTICS_QUE_EXT_MIN_COORDS, &min_coords)) 1043 return (-1); 1044 1045 if (SYNAPTICS_ID_FULL(syn->identify) >= 0x705) { 1046 if (synaptics_query(sc, SYNAPTICS_QUE_MODES, &syn->modes)) 1047 return (-1); 1048 if ((syn->modes & SYNAPTICS_EXT2_CAP) && 1049 synaptics_query(sc, SYNAPTICS_QUE_EXT2_CAPABILITIES, 1050 &syn->ext2_capabilities)) 1051 return (-1); 1052 } 1053 1054 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) && 1055 !(syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) 1056 && mouse_has_softbtn) 1057 hw->type = WSMOUSE_TYPE_SYNAP_SBTN; 1058 else 1059 hw->type = WSMOUSE_TYPE_SYNAPTICS; 1060 1061 hw->hw_type = (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) 1062 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD; 1063 1064 if (resolution & SYNAPTICS_RESOLUTION_VALID) { 1065 hw->h_res = SYNAPTICS_RESOLUTION_X(resolution); 1066 hw->v_res = SYNAPTICS_RESOLUTION_Y(resolution); 1067 } 1068 1069 hw->x_min = (min_coords ? 1070 SYNAPTICS_X_LIMIT(min_coords) : SYNAPTICS_XMIN_BEZEL); 1071 hw->y_min = (min_coords ? 1072 SYNAPTICS_Y_LIMIT(min_coords) : SYNAPTICS_YMIN_BEZEL); 1073 hw->x_max = (max_coords ? 1074 SYNAPTICS_X_LIMIT(max_coords) : SYNAPTICS_XMAX_BEZEL); 1075 hw->y_max = (max_coords ? 1076 SYNAPTICS_Y_LIMIT(max_coords) : SYNAPTICS_YMAX_BEZEL); 1077 1078 hw->contacts_max = SYNAPTICS_MAX_FINGERS; 1079 1080 syn->sec_buttons = 0; 1081 1082 if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) > 8) 1083 syn->ext_model &= ~0xf000; 1084 1085 if ((syn->model & SYNAPTICS_MODEL_NEWABS) == 0) { 1086 printf("%s: don't support Synaptics OLDABS\n", DEVNAME(sc)); 1087 return (-1); 1088 } 1089 1090 if ((SYNAPTICS_ID_MAJOR(syn->identify) == 5) && 1091 (SYNAPTICS_ID_MINOR(syn->identify) == 9)) 1092 syn->mask = SYNAPTICS_MASK_NEWABS_RELAXED; 1093 else 1094 syn->mask = SYNAPTICS_MASK_NEWABS_STRICT; 1095 1096 return (0); 1097 } 1098 1099 void 1100 synaptics_sec_proc(struct pms_softc *sc) 1101 { 1102 struct synaptics_softc *syn = sc->synaptics; 1103 u_int buttons; 1104 int dx, dy; 1105 1106 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0) 1107 return; 1108 1109 buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK]; 1110 buttons |= syn->sec_buttons; 1111 dx = (sc->packet[1] & PMS_PS2_XNEG) ? 1112 (int)sc->packet[4] - 256 : sc->packet[4]; 1113 dy = (sc->packet[1] & PMS_PS2_YNEG) ? 1114 (int)sc->packet[5] - 256 : sc->packet[5]; 1115 1116 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0); 1117 } 1118 1119 int 1120 synaptics_knock(struct pms_softc *sc) 1121 { 1122 u_char resp[3]; 1123 1124 if (pms_set_resolution(sc, 0) || 1125 pms_set_resolution(sc, 0) || 1126 pms_set_resolution(sc, 0) || 1127 pms_set_resolution(sc, 0) || 1128 pms_get_status(sc, resp) || 1129 resp[1] != SYNAPTICS_ID_MAGIC) 1130 return (-1); 1131 1132 return (0); 1133 } 1134 1135 int 1136 pms_enable_synaptics(struct pms_softc *sc) 1137 { 1138 struct synaptics_softc *syn = sc->synaptics; 1139 struct wsmousedev_attach_args a; 1140 int mode, i; 1141 1142 if (synaptics_knock(sc)) { 1143 if (sc->synaptics == NULL) 1144 goto err; 1145 /* 1146 * Some synaptics touchpads don't resume quickly. 1147 * Retry a few times. 1148 */ 1149 for (i = 10; i > 0; --i) { 1150 printf("%s: device not resuming, retrying\n", 1151 DEVNAME(sc)); 1152 pms_reset(sc); 1153 if (synaptics_knock(sc) == 0) 1154 break; 1155 delay(100000); 1156 } 1157 if (i == 0) { 1158 printf("%s: lost device\n", DEVNAME(sc)); 1159 goto err; 1160 } 1161 } 1162 1163 if (sc->synaptics == NULL) { 1164 sc->synaptics = syn = malloc(sizeof(struct synaptics_softc), 1165 M_DEVBUF, M_WAITOK | M_ZERO); 1166 if (syn == NULL) { 1167 printf("%s: synaptics: not enough memory\n", 1168 DEVNAME(sc)); 1169 goto err; 1170 } 1171 1172 if (synaptics_get_hwinfo(sc)) { 1173 free(sc->synaptics, M_DEVBUF, 1174 sizeof(struct synaptics_softc)); 1175 sc->synaptics = NULL; 1176 goto err; 1177 } 1178 1179 /* enable pass-through PS/2 port if supported */ 1180 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) { 1181 a.accessops = &pms_sec_accessops; 1182 a.accesscookie = sc; 1183 sc->sc_sec_wsmousedev = config_found((void *)sc, &a, 1184 wsmousedevprint); 1185 } 1186 1187 if (wsmouse_configure(sc->sc_wsmousedev, synaptics_params, 1188 nitems(synaptics_params))) 1189 goto err; 1190 1191 printf("%s: Synaptics %s, firmware %d.%d, " 1192 "0x%x 0x%x 0x%x 0x%x 0x%x\n", 1193 DEVNAME(sc), 1194 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD ? 1195 "clickpad" : "touchpad"), 1196 SYNAPTICS_ID_MAJOR(syn->identify), 1197 SYNAPTICS_ID_MINOR(syn->identify), 1198 syn->model, syn->ext_model, syn->modes, 1199 syn->capabilities, syn->ext_capabilities); 1200 } 1201 1202 /* 1203 * Enable absolute mode, plain W-mode and "advanced gesture mode" 1204 * (AGM), if possible. AGM, which seems to be a prerequisite for the 1205 * extended W-mode, might not always be necessary here, but at least 1206 * some older Synaptics models do not report finger counts without it. 1207 */ 1208 mode = SYNAPTICS_ABSOLUTE_MODE | SYNAPTICS_HIGH_RATE; 1209 if (syn->capabilities & SYNAPTICS_CAP_EXTENDED) 1210 mode |= SYNAPTICS_W_MODE; 1211 else if (SYNAPTICS_ID_MAJOR(syn->identify) >= 4) 1212 mode |= SYNAPTICS_DISABLE_GESTURE; 1213 if (synaptics_set_mode(sc, mode, 0)) 1214 goto err; 1215 1216 if (SYNAPTICS_SUPPORTS_AGM(syn->ext_capabilities) && 1217 synaptics_set_mode(sc, SYNAPTICS_QUE_MODEL, 1218 SYNAPTICS_CMD_SET_ADV_GESTURE_MODE)) 1219 goto err; 1220 1221 return (1); 1222 1223 err: 1224 pms_reset(sc); 1225 1226 return (0); 1227 } 1228 1229 int 1230 pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 1231 struct proc *p) 1232 { 1233 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 1234 struct wsmousehw *hw; 1235 int wsmode; 1236 1237 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1238 switch (cmd) { 1239 case WSMOUSEIO_GTYPE: 1240 *(u_int *)data = hw->type; 1241 break; 1242 case WSMOUSEIO_GCALIBCOORDS: 1243 wsmc->minx = hw->x_min; 1244 wsmc->maxx = hw->x_max; 1245 wsmc->miny = hw->y_min; 1246 wsmc->maxy = hw->y_max; 1247 wsmc->swapxy = 0; 1248 wsmc->resx = hw->h_res; 1249 wsmc->resy = hw->v_res; 1250 break; 1251 case WSMOUSEIO_SETMODE: 1252 wsmode = *(u_int *)data; 1253 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 1254 return (EINVAL); 1255 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 1256 break; 1257 default: 1258 return (-1); 1259 } 1260 return (0); 1261 } 1262 1263 int 1264 pms_sync_synaptics(struct pms_softc *sc, int data) 1265 { 1266 struct synaptics_softc *syn = sc->synaptics; 1267 1268 switch (sc->inputstate) { 1269 case 0: 1270 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_FIRST) 1271 return (-1); 1272 break; 1273 case 3: 1274 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_NEXT) 1275 return (-1); 1276 break; 1277 } 1278 1279 return (0); 1280 } 1281 1282 void 1283 pms_proc_synaptics(struct pms_softc *sc) 1284 { 1285 struct synaptics_softc *syn = sc->synaptics; 1286 u_int buttons; 1287 int x, y, z, w, fingerwidth; 1288 1289 w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) | 1290 ((sc->packet[3] & 0x04) >> 2); 1291 z = sc->packet[2]; 1292 1293 if ((syn->capabilities & SYNAPTICS_CAP_EXTENDED) == 0) { 1294 /* 1295 * Emulate W mode for models that don't provide it. Bit 3 1296 * of the w-input signals a touch ("finger"), Bit 2 and 1297 * the "gesture" bits 1-0 can be ignored. 1298 */ 1299 if (w & 8) 1300 w = 4; 1301 else 1302 z = w = 0; 1303 } 1304 1305 1306 if (w == 3) { 1307 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) 1308 synaptics_sec_proc(sc); 1309 return; 1310 } 1311 1312 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 1313 return; 1314 1315 if (w == 2) 1316 return; /* EW-mode packets are not expected here. */ 1317 1318 x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) | 1319 sc->packet[4]; 1320 y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) | 1321 sc->packet[5]; 1322 1323 buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ? 1324 WSMOUSE_BUTTON(1) : 0; 1325 buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ? 1326 WSMOUSE_BUTTON(3) : 0; 1327 1328 if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) { 1329 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1330 WSMOUSE_BUTTON(1) : 0; 1331 } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON) { 1332 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1333 WSMOUSE_BUTTON(2) : 0; 1334 } 1335 1336 if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON) { 1337 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1338 WSMOUSE_BUTTON(4) : 0; 1339 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ? 1340 WSMOUSE_BUTTON(5) : 0; 1341 } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) && 1342 ((sc->packet[0] ^ sc->packet[3]) & 0x02)) { 1343 if (syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) { 1344 /* 1345 * Trackstick buttons on this machine are wired to the 1346 * trackpad as extra buttons, so route the event 1347 * through the trackstick interface as normal buttons 1348 */ 1349 syn->sec_buttons = 1350 (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(1) : 0; 1351 syn->sec_buttons |= 1352 (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(3) : 0; 1353 syn->sec_buttons |= 1354 (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(2) : 0; 1355 wsmouse_buttons( 1356 sc->sc_sec_wsmousedev, syn->sec_buttons); 1357 wsmouse_input_sync(sc->sc_sec_wsmousedev); 1358 return; 1359 } 1360 1361 buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6) : 0; 1362 buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7) : 0; 1363 buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8) : 0; 1364 buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9) : 0; 1365 buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10) : 0; 1366 buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11) : 0; 1367 buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12) : 0; 1368 buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13) : 0; 1369 x &= ~0x0f; 1370 y &= ~0x0f; 1371 } 1372 1373 if (z) { 1374 fingerwidth = max(w, 4); 1375 w = (w < 2 ? w + 2 : 1); 1376 } else { 1377 fingerwidth = 0; 1378 w = 0; 1379 } 1380 wsmouse_set(sc->sc_wsmousedev, WSMOUSE_TOUCH_WIDTH, fingerwidth, 0); 1381 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 1382 } 1383 1384 void 1385 pms_disable_synaptics(struct pms_softc *sc) 1386 { 1387 struct synaptics_softc *syn = sc->synaptics; 1388 1389 if (syn->capabilities & SYNAPTICS_CAP_SLEEP) 1390 synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE | 1391 SYNAPTICS_DISABLE_GESTURE, 0); 1392 } 1393 1394 int 1395 alps_sec_proc(struct pms_softc *sc) 1396 { 1397 struct alps_softc *alps = sc->alps; 1398 int dx, dy, pos = 0; 1399 1400 if ((sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) { 1401 /* 1402 * We need to keep buttons states because interleaved 1403 * packets only signalize x/y movements. 1404 */ 1405 alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; 1406 } else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK) == 1407 PMS_ALPS_INTERLEAVED_VALID) { 1408 sc->inputstate = 3; 1409 pos = 3; 1410 } else { 1411 return (0); 1412 } 1413 1414 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0) 1415 return (1); 1416 1417 dx = (sc->packet[pos] & PMS_PS2_XNEG) ? 1418 (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1]; 1419 dy = (sc->packet[pos] & PMS_PS2_YNEG) ? 1420 (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2]; 1421 1422 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, alps->sec_buttons, dx, dy, 0, 0); 1423 1424 return (1); 1425 } 1426 1427 int 1428 alps_get_hwinfo(struct pms_softc *sc) 1429 { 1430 struct alps_softc *alps = sc->alps; 1431 u_char resp[3]; 1432 int i; 1433 struct wsmousehw *hw; 1434 1435 if (pms_set_resolution(sc, 0) || 1436 pms_set_scaling(sc, 2) || 1437 pms_set_scaling(sc, 2) || 1438 pms_set_scaling(sc, 2) || 1439 pms_get_status(sc, resp)) { 1440 DPRINTF("%s: alps: model query error\n", DEVNAME(sc)); 1441 return (-1); 1442 } 1443 1444 alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1); 1445 1446 for (i = 0; i < nitems(alps_models); i++) 1447 if (alps->version == alps_models[i].version) { 1448 alps->model = alps_models[i].model; 1449 alps->mask = alps_models[i].mask; 1450 1451 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1452 hw->type = WSMOUSE_TYPE_ALPS; 1453 hw->hw_type = WSMOUSEHW_TOUCHPAD; 1454 hw->x_min = ALPS_XMIN_BEZEL; 1455 hw->y_min = ALPS_YMIN_BEZEL; 1456 hw->x_max = ALPS_XMAX_BEZEL; 1457 hw->y_max = ALPS_YMAX_BEZEL; 1458 hw->contacts_max = 1; 1459 1460 return (0); 1461 } 1462 1463 return (-1); 1464 } 1465 1466 int 1467 pms_enable_alps(struct pms_softc *sc) 1468 { 1469 struct alps_softc *alps = sc->alps; 1470 struct wsmousedev_attach_args a; 1471 u_char resp[3]; 1472 1473 if (pms_set_resolution(sc, 0) || 1474 pms_set_scaling(sc, 1) || 1475 pms_set_scaling(sc, 1) || 1476 pms_set_scaling(sc, 1) || 1477 pms_get_status(sc, resp) || 1478 resp[0] != PMS_ALPS_MAGIC1 || 1479 resp[1] != PMS_ALPS_MAGIC2 || 1480 (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2 && 1481 resp[2] != PMS_ALPS_MAGIC3_3)) 1482 goto err; 1483 1484 if (sc->alps == NULL) { 1485 sc->alps = alps = malloc(sizeof(struct alps_softc), 1486 M_DEVBUF, M_WAITOK | M_ZERO); 1487 if (alps == NULL) { 1488 printf("%s: alps: not enough memory\n", DEVNAME(sc)); 1489 goto err; 1490 } 1491 1492 if (alps_get_hwinfo(sc)) { 1493 free(sc->alps, M_DEVBUF, sizeof(struct alps_softc)); 1494 sc->alps = NULL; 1495 goto err; 1496 } 1497 1498 if (wsmouse_configure(sc->sc_wsmousedev, alps_params, 1499 nitems(alps_params))) { 1500 free(sc->alps, M_DEVBUF, sizeof(struct alps_softc)); 1501 sc->alps = NULL; 1502 printf("%s: setup failed\n", DEVNAME(sc)); 1503 goto err; 1504 } 1505 1506 printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc), 1507 (alps->model & ALPS_DUALPOINT ? "Dualpoint" : "Glidepoint"), 1508 alps->version); 1509 1510 1511 if (alps->model & ALPS_DUALPOINT) { 1512 a.accessops = &pms_sec_accessops; 1513 a.accesscookie = sc; 1514 sc->sc_sec_wsmousedev = config_found((void *)sc, &a, 1515 wsmousedevprint); 1516 } 1517 } 1518 1519 if (alps->model == 0) 1520 goto err; 1521 1522 if ((alps->model & ALPS_PASSTHROUGH) && 1523 (pms_set_scaling(sc, 2) || 1524 pms_set_scaling(sc, 2) || 1525 pms_set_scaling(sc, 2) || 1526 pms_dev_disable(sc))) { 1527 DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc)); 1528 goto err; 1529 } 1530 1531 if (pms_dev_disable(sc) || 1532 pms_dev_disable(sc) || 1533 pms_set_rate(sc, 0x0a)) { 1534 DPRINTF("%s: alps: tapping error\n", DEVNAME(sc)); 1535 goto err; 1536 } 1537 1538 if (pms_dev_disable(sc) || 1539 pms_dev_disable(sc) || 1540 pms_dev_disable(sc) || 1541 pms_dev_disable(sc) || 1542 pms_dev_enable(sc)) { 1543 DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc)); 1544 goto err; 1545 } 1546 1547 if ((alps->model & ALPS_PASSTHROUGH) && 1548 (pms_set_scaling(sc, 1) || 1549 pms_set_scaling(sc, 1) || 1550 pms_set_scaling(sc, 1) || 1551 pms_dev_disable(sc))) { 1552 DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc)); 1553 goto err; 1554 } 1555 1556 alps->sec_buttons = 0; 1557 1558 return (1); 1559 1560 err: 1561 pms_reset(sc); 1562 1563 return (0); 1564 } 1565 1566 int 1567 pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 1568 struct proc *p) 1569 { 1570 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 1571 int wsmode; 1572 struct wsmousehw *hw; 1573 1574 switch (cmd) { 1575 case WSMOUSEIO_GTYPE: 1576 *(u_int *)data = WSMOUSE_TYPE_ALPS; 1577 break; 1578 case WSMOUSEIO_GCALIBCOORDS: 1579 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1580 wsmc->minx = hw->x_min; 1581 wsmc->maxx = hw->x_max; 1582 wsmc->miny = hw->y_min; 1583 wsmc->maxy = hw->y_max; 1584 wsmc->swapxy = 0; 1585 break; 1586 case WSMOUSEIO_SETMODE: 1587 wsmode = *(u_int *)data; 1588 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 1589 return (EINVAL); 1590 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 1591 break; 1592 default: 1593 return (-1); 1594 } 1595 return (0); 1596 } 1597 1598 int 1599 pms_sync_alps(struct pms_softc *sc, int data) 1600 { 1601 struct alps_softc *alps = sc->alps; 1602 1603 if ((alps->model & ALPS_DUALPOINT) && 1604 (sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) { 1605 if (sc->inputstate == 2) 1606 sc->inputstate += 3; 1607 return (0); 1608 } 1609 1610 switch (sc->inputstate) { 1611 case 0: 1612 if ((data & alps->mask) != alps->mask) 1613 return (-1); 1614 break; 1615 case 1: 1616 case 2: 1617 case 3: 1618 if ((data & PMS_ALPS_MASK) != PMS_ALPS_VALID) 1619 return (-1); 1620 break; 1621 case 4: 1622 case 5: 1623 if ((alps->model & ALPS_INTERLEAVED) == 0 && 1624 (data & PMS_ALPS_MASK) != PMS_ALPS_VALID) 1625 return (-1); 1626 break; 1627 } 1628 1629 return (0); 1630 } 1631 1632 void 1633 pms_proc_alps(struct pms_softc *sc) 1634 { 1635 struct alps_softc *alps = sc->alps; 1636 int x, y, z, dx, dy; 1637 u_int buttons, gesture; 1638 1639 if ((alps->model & ALPS_DUALPOINT) && alps_sec_proc(sc)) 1640 return; 1641 1642 x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4); 1643 y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3); 1644 z = sc->packet[5]; 1645 1646 buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) | 1647 ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) | 1648 ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0); 1649 1650 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) && z == ALPS_Z_MAGIC) { 1651 dx = (x > ALPS_XSEC_BEZEL / 2) ? (x - ALPS_XSEC_BEZEL) : x; 1652 dy = (y > ALPS_YSEC_BEZEL / 2) ? (y - ALPS_YSEC_BEZEL) : y; 1653 1654 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0); 1655 1656 return; 1657 } 1658 1659 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 1660 return; 1661 1662 /* 1663 * XXX The Y-axis is in the oposit direction compared to 1664 * Synaptics touchpads and PS/2 mouses. 1665 * It's why we need to translate the y value here for both 1666 * NATIVE and COMPAT modes. 1667 */ 1668 y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL; 1669 1670 if (alps->gesture == ALPS_TAP) { 1671 /* Report a touch with the tap coordinates. */ 1672 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, 1673 alps->old_x, alps->old_y, ALPS_PRESSURE, 0); 1674 if (z > 0) { 1675 /* 1676 * The hardware doesn't send a null pressure 1677 * event when dragging starts. 1678 */ 1679 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, 1680 alps->old_x, alps->old_y, 0, 0); 1681 } 1682 } 1683 1684 gesture = sc->packet[2] & 0x03; 1685 if (gesture != ALPS_TAP) 1686 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, 0); 1687 1688 if (alps->gesture != ALPS_DRAG || gesture != ALPS_TAP) 1689 alps->gesture = gesture; 1690 1691 alps->old_x = x; 1692 alps->old_y = y; 1693 } 1694 1695 int 1696 elantech_set_absolute_mode_v1(struct pms_softc *sc) 1697 { 1698 int i; 1699 u_char resp[3]; 1700 1701 /* Enable absolute mode. Magic numbers from Linux driver. */ 1702 if (pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1703 pms_spec_cmd(sc, 0x10) || 1704 pms_spec_cmd(sc, 0x16) || 1705 pms_set_scaling(sc, 1) || 1706 pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1707 pms_spec_cmd(sc, 0x11) || 1708 pms_spec_cmd(sc, 0x8f) || 1709 pms_set_scaling(sc, 1)) 1710 return (-1); 1711 1712 /* Read back reg 0x10 to ensure hardware is ready. */ 1713 for (i = 0; i < 5; i++) { 1714 if (pms_spec_cmd(sc, ELANTECH_CMD_READ_REG) || 1715 pms_spec_cmd(sc, 0x10) || 1716 pms_get_status(sc, resp) == 0) 1717 break; 1718 delay(2000); 1719 } 1720 if (i == 5) 1721 return (-1); 1722 1723 if ((resp[0] & ELANTECH_ABSOLUTE_MODE) == 0) 1724 return (-1); 1725 1726 return (0); 1727 } 1728 1729 int 1730 elantech_set_absolute_mode_v2(struct pms_softc *sc) 1731 { 1732 int i; 1733 u_char resp[3]; 1734 u_char reg10 = (sc->elantech->fw_version == 0x20030 ? 0x54 : 0xc4); 1735 1736 /* Enable absolute mode. Magic numbers from Linux driver. */ 1737 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1738 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1739 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1740 elantech_ps2_cmd(sc, 0x10) || 1741 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1742 elantech_ps2_cmd(sc, reg10) || 1743 pms_set_scaling(sc, 1) || 1744 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1745 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1746 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1747 elantech_ps2_cmd(sc, 0x11) || 1748 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1749 elantech_ps2_cmd(sc, 0x88) || 1750 pms_set_scaling(sc, 1)) 1751 return (-1); 1752 1753 /* Read back reg 0x10 to ensure hardware is ready. */ 1754 for (i = 0; i < 5; i++) { 1755 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1756 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_REG) || 1757 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1758 elantech_ps2_cmd(sc, 0x10) || 1759 pms_get_status(sc, resp) == 0) 1760 break; 1761 delay(2000); 1762 } 1763 if (i == 5) 1764 return (-1); 1765 1766 return (0); 1767 } 1768 1769 int 1770 elantech_set_absolute_mode_v3(struct pms_softc *sc) 1771 { 1772 int i; 1773 u_char resp[3]; 1774 1775 /* Enable absolute mode. Magic numbers from Linux driver. */ 1776 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1777 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1778 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1779 elantech_ps2_cmd(sc, 0x10) || 1780 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1781 elantech_ps2_cmd(sc, 0x0b) || 1782 pms_set_scaling(sc, 1)) 1783 return (-1); 1784 1785 /* Read back reg 0x10 to ensure hardware is ready. */ 1786 for (i = 0; i < 5; i++) { 1787 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1788 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1789 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1790 elantech_ps2_cmd(sc, 0x10) || 1791 pms_get_status(sc, resp) == 0) 1792 break; 1793 delay(2000); 1794 } 1795 if (i == 5) 1796 return (-1); 1797 1798 return (0); 1799 } 1800 1801 int 1802 elantech_set_absolute_mode_v4(struct pms_softc *sc) 1803 { 1804 /* Enable absolute mode. Magic numbers from Linux driver. */ 1805 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1806 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1807 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1808 elantech_ps2_cmd(sc, 0x07) || 1809 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1810 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1811 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1812 elantech_ps2_cmd(sc, 0x01) || 1813 pms_set_scaling(sc, 1)) 1814 return (-1); 1815 1816 /* v4 has no register 0x10 to read response from */ 1817 1818 return (0); 1819 } 1820 1821 int 1822 elantech_get_hwinfo_v1(struct pms_softc *sc) 1823 { 1824 struct elantech_softc *elantech = sc->elantech; 1825 struct wsmousehw *hw; 1826 int fw_version; 1827 u_char capabilities[3]; 1828 1829 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1830 return (-1); 1831 1832 if (fw_version < 0x20030 || fw_version == 0x20600) { 1833 if (fw_version < 0x20000) 1834 elantech->flags |= ELANTECH_F_HW_V1_OLD; 1835 } else 1836 return (-1); 1837 1838 elantech->fw_version = fw_version; 1839 1840 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1841 pms_get_status(sc, capabilities)) 1842 return (-1); 1843 1844 if (capabilities[0] & ELANTECH_CAP_HAS_ROCKER) 1845 elantech->flags |= ELANTECH_F_HAS_ROCKER; 1846 1847 if (elantech_set_absolute_mode_v1(sc)) 1848 return (-1); 1849 1850 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1851 hw->type = WSMOUSE_TYPE_ELANTECH; 1852 hw->hw_type = WSMOUSEHW_TOUCHPAD; 1853 hw->x_min = ELANTECH_V1_X_MIN; 1854 hw->x_max = ELANTECH_V1_X_MAX; 1855 hw->y_min = ELANTECH_V1_Y_MIN; 1856 hw->y_max = ELANTECH_V1_Y_MAX; 1857 1858 return (0); 1859 } 1860 1861 int 1862 elantech_get_hwinfo_v2(struct pms_softc *sc) 1863 { 1864 struct elantech_softc *elantech = sc->elantech; 1865 struct wsmousehw *hw; 1866 int fw_version, ic_ver; 1867 u_char capabilities[3]; 1868 int i, fixed_dpi; 1869 u_char resp[3]; 1870 1871 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1872 return (-1); 1873 1874 ic_ver = (fw_version & 0x0f0000) >> 16; 1875 if (ic_ver != 2 && ic_ver != 4) 1876 return (-1); 1877 1878 elantech->fw_version = fw_version; 1879 if (fw_version >= 0x20800) 1880 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1881 1882 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1883 pms_get_status(sc, capabilities)) 1884 return (-1); 1885 1886 if (elantech_set_absolute_mode_v2(sc)) 1887 return (-1); 1888 1889 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1890 hw->type = WSMOUSE_TYPE_ELANTECH; 1891 hw->hw_type = WSMOUSEHW_TOUCHPAD; 1892 1893 if (fw_version == 0x20800 || fw_version == 0x20b00 || 1894 fw_version == 0x20030) { 1895 hw->x_max = ELANTECH_V2_X_MAX; 1896 hw->y_max = ELANTECH_V2_Y_MAX; 1897 } else { 1898 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 1899 pms_get_status(sc, resp)) 1900 return (-1); 1901 fixed_dpi = resp[1] & 0x10; 1902 i = (fw_version > 0x20800 && fw_version < 0x20900) ? 1 : 2; 1903 if ((fw_version >> 16) == 0x14 && fixed_dpi) { 1904 if (pms_spec_cmd(sc, ELANTECH_QUE_SAMPLE) || 1905 pms_get_status(sc, resp)) 1906 return (-1); 1907 hw->x_max = (capabilities[1] - i) * resp[1] / 2; 1908 hw->y_max = (capabilities[2] - i) * resp[2] / 2; 1909 } else if (fw_version == 0x040216) { 1910 hw->x_max = 819; 1911 hw->y_max = 405; 1912 } else if (fw_version == 0x040219 || fw_version == 0x040215) { 1913 hw->x_max = 900; 1914 hw->y_max = 500; 1915 } else { 1916 hw->x_max = (capabilities[1] - i) * 64; 1917 hw->y_max = (capabilities[2] - i) * 64; 1918 } 1919 } 1920 1921 return (0); 1922 } 1923 1924 int 1925 elantech_get_hwinfo_v3(struct pms_softc *sc) 1926 { 1927 struct elantech_softc *elantech = sc->elantech; 1928 struct wsmousehw *hw; 1929 int fw_version; 1930 u_char resp[3]; 1931 1932 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1933 return (-1); 1934 1935 if (((fw_version & 0x0f0000) >> 16) != 5) 1936 return (-1); 1937 1938 elantech->fw_version = fw_version; 1939 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1940 1941 if ((fw_version & 0x4000) == 0x4000) 1942 elantech->flags |= ELANTECH_F_CRC_ENABLED; 1943 1944 if (elantech_set_absolute_mode_v3(sc)) 1945 return (-1); 1946 1947 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 1948 pms_get_status(sc, resp)) 1949 return (-1); 1950 1951 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1952 hw->x_max = elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1]; 1953 hw->y_max = elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2]; 1954 1955 hw->type = WSMOUSE_TYPE_ELANTECH; 1956 hw->hw_type = WSMOUSEHW_TOUCHPAD; 1957 1958 return (0); 1959 } 1960 1961 int 1962 elantech_get_hwinfo_v4(struct pms_softc *sc) 1963 { 1964 struct elantech_softc *elantech = sc->elantech; 1965 struct wsmousehw *hw; 1966 int fw_version; 1967 u_char capabilities[3]; 1968 u_char resp[3]; 1969 1970 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1971 return (-1); 1972 1973 if ((fw_version & 0x0f0000) >> 16 < 6) 1974 return (-1); 1975 1976 elantech->fw_version = fw_version; 1977 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1978 1979 if ((fw_version & 0x4000) == 0x4000) 1980 elantech->flags |= ELANTECH_F_CRC_ENABLED; 1981 1982 if (elantech_set_absolute_mode_v4(sc)) 1983 return (-1); 1984 1985 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1986 pms_get_status(sc, capabilities)) 1987 return (-1); 1988 1989 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 1990 pms_get_status(sc, resp)) 1991 return (-1); 1992 1993 hw = wsmouse_get_hw(sc->sc_wsmousedev); 1994 hw->x_max = (resp[0] & 0x0f) << 8 | resp[1]; 1995 hw->y_max = (resp[0] & 0xf0) << 4 | resp[2]; 1996 1997 if ((capabilities[1] < 2) || (capabilities[1] > hw->x_max)) 1998 return (-1); 1999 2000 if (capabilities[0] & ELANTECH_CAP_TRACKPOINT) 2001 elantech->flags |= ELANTECH_F_TRACKPOINT; 2002 2003 hw->type = WSMOUSE_TYPE_ELANTECH; 2004 hw->hw_type = (ELANTECH_IS_CLICKPAD(sc) 2005 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD); 2006 hw->mt_slots = ELANTECH_MAX_FINGERS; 2007 2008 elantech->width = hw->x_max / (capabilities[1] - 1); 2009 2010 return (0); 2011 } 2012 2013 int 2014 elantech_ps2_cmd(struct pms_softc *sc, u_char command) 2015 { 2016 u_char cmd[1]; 2017 2018 cmd[0] = command; 2019 return (pms_cmd(sc, cmd, 1, NULL, 0)); 2020 } 2021 2022 int 2023 elantech_knock(struct pms_softc *sc) 2024 { 2025 u_char resp[3]; 2026 2027 if (pms_dev_disable(sc) || 2028 pms_set_scaling(sc, 1) || 2029 pms_set_scaling(sc, 1) || 2030 pms_set_scaling(sc, 1) || 2031 pms_get_status(sc, resp) || 2032 resp[0] != PMS_ELANTECH_MAGIC1 || 2033 resp[1] != PMS_ELANTECH_MAGIC2 || 2034 (resp[2] != PMS_ELANTECH_MAGIC3_1 && 2035 resp[2] != PMS_ELANTECH_MAGIC3_2)) 2036 return (-1); 2037 2038 return (0); 2039 } 2040 2041 int 2042 pms_enable_elantech_v1(struct pms_softc *sc) 2043 { 2044 struct elantech_softc *elantech = sc->elantech; 2045 int i; 2046 2047 if (elantech_knock(sc)) 2048 goto err; 2049 2050 if (sc->elantech == NULL) { 2051 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2052 M_DEVBUF, M_WAITOK | M_ZERO); 2053 if (elantech == NULL) { 2054 printf("%s: elantech: not enough memory\n", 2055 DEVNAME(sc)); 2056 goto err; 2057 } 2058 2059 if (elantech_get_hwinfo_v1(sc)) { 2060 free(sc->elantech, M_DEVBUF, 2061 sizeof(struct elantech_softc)); 2062 sc->elantech = NULL; 2063 goto err; 2064 } 2065 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { 2066 free(sc->elantech, M_DEVBUF, 2067 sizeof(struct elantech_softc)); 2068 sc->elantech = NULL; 2069 printf("%s: elantech: setup failed\n", DEVNAME(sc)); 2070 goto err; 2071 } 2072 2073 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 2074 DEVNAME(sc), 1, sc->elantech->fw_version); 2075 } else if (elantech_set_absolute_mode_v1(sc)) 2076 goto err; 2077 2078 for (i = 0; i < nitems(sc->elantech->parity); i++) 2079 sc->elantech->parity[i] = sc->elantech->parity[i & (i - 1)] ^ 1; 2080 2081 return (1); 2082 2083 err: 2084 pms_reset(sc); 2085 2086 return (0); 2087 } 2088 2089 int 2090 pms_enable_elantech_v2(struct pms_softc *sc) 2091 { 2092 struct elantech_softc *elantech = sc->elantech; 2093 2094 if (elantech_knock(sc)) 2095 goto err; 2096 2097 if (sc->elantech == NULL) { 2098 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2099 M_DEVBUF, M_WAITOK | M_ZERO); 2100 if (elantech == NULL) { 2101 printf("%s: elantech: not enough memory\n", 2102 DEVNAME(sc)); 2103 goto err; 2104 } 2105 2106 if (elantech_get_hwinfo_v2(sc)) { 2107 free(sc->elantech, M_DEVBUF, 2108 sizeof(struct elantech_softc)); 2109 sc->elantech = NULL; 2110 goto err; 2111 } 2112 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { 2113 free(sc->elantech, M_DEVBUF, 2114 sizeof(struct elantech_softc)); 2115 sc->elantech = NULL; 2116 printf("%s: elantech: setup failed\n", DEVNAME(sc)); 2117 goto err; 2118 } 2119 2120 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 2121 DEVNAME(sc), 2, sc->elantech->fw_version); 2122 } else if (elantech_set_absolute_mode_v2(sc)) 2123 goto err; 2124 2125 return (1); 2126 2127 err: 2128 pms_reset(sc); 2129 2130 return (0); 2131 } 2132 2133 int 2134 pms_enable_elantech_v3(struct pms_softc *sc) 2135 { 2136 struct elantech_softc *elantech = sc->elantech; 2137 2138 if (elantech_knock(sc)) 2139 goto err; 2140 2141 if (sc->elantech == NULL) { 2142 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2143 M_DEVBUF, M_WAITOK | M_ZERO); 2144 if (elantech == NULL) { 2145 printf("%s: elantech: not enough memory\n", 2146 DEVNAME(sc)); 2147 goto err; 2148 } 2149 2150 if (elantech_get_hwinfo_v3(sc)) { 2151 free(sc->elantech, M_DEVBUF, 2152 sizeof(struct elantech_softc)); 2153 sc->elantech = NULL; 2154 goto err; 2155 } 2156 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { 2157 free(sc->elantech, M_DEVBUF, 2158 sizeof(struct elantech_softc)); 2159 sc->elantech = NULL; 2160 printf("%s: elantech: setup failed\n", DEVNAME(sc)); 2161 goto err; 2162 } 2163 2164 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 2165 DEVNAME(sc), 3, sc->elantech->fw_version); 2166 } else if (elantech_set_absolute_mode_v3(sc)) 2167 goto err; 2168 2169 return (1); 2170 2171 err: 2172 pms_reset(sc); 2173 2174 return (0); 2175 } 2176 2177 int 2178 pms_enable_elantech_v4(struct pms_softc *sc) 2179 { 2180 struct elantech_softc *elantech = sc->elantech; 2181 struct wsmousedev_attach_args a; 2182 2183 if (elantech_knock(sc)) 2184 goto err; 2185 2186 if (sc->elantech == NULL) { 2187 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2188 M_DEVBUF, M_WAITOK | M_ZERO); 2189 if (elantech == NULL) { 2190 printf("%s: elantech: not enough memory\n", 2191 DEVNAME(sc)); 2192 goto err; 2193 } 2194 2195 if (elantech_get_hwinfo_v4(sc)) { 2196 free(sc->elantech, M_DEVBUF, 2197 sizeof(struct elantech_softc)); 2198 sc->elantech = NULL; 2199 goto err; 2200 } 2201 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { 2202 free(sc->elantech, M_DEVBUF, 2203 sizeof(struct elantech_softc)); 2204 sc->elantech = NULL; 2205 printf("%s: elantech: setup failed\n", DEVNAME(sc)); 2206 goto err; 2207 } 2208 2209 printf("%s: Elantech %s, version 4, firmware 0x%x\n", 2210 DEVNAME(sc), (ELANTECH_IS_CLICKPAD(sc) ? "Clickpad" 2211 : "Touchpad"), sc->elantech->fw_version); 2212 2213 if (sc->elantech->flags & ELANTECH_F_TRACKPOINT) { 2214 a.accessops = &pms_sec_accessops; 2215 a.accesscookie = sc; 2216 sc->sc_sec_wsmousedev = config_found((void *) sc, &a, 2217 wsmousedevprint); 2218 } 2219 2220 } else if (elantech_set_absolute_mode_v4(sc)) 2221 goto err; 2222 2223 return (1); 2224 2225 err: 2226 pms_reset(sc); 2227 2228 return (0); 2229 } 2230 2231 int 2232 pms_ioctl_elantech(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 2233 struct proc *p) 2234 { 2235 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 2236 struct wsmousehw *hw; 2237 int wsmode; 2238 2239 switch (cmd) { 2240 case WSMOUSEIO_GTYPE: 2241 *(u_int *)data = WSMOUSE_TYPE_ELANTECH; 2242 break; 2243 case WSMOUSEIO_GCALIBCOORDS: 2244 hw = wsmouse_get_hw(sc->sc_wsmousedev); 2245 wsmc->minx = hw->x_min; 2246 wsmc->maxx = hw->x_max; 2247 wsmc->miny = hw->y_min; 2248 wsmc->maxy = hw->y_max; 2249 wsmc->swapxy = 0; 2250 wsmc->resx = hw->h_res; 2251 wsmc->resy = hw->v_res; 2252 break; 2253 case WSMOUSEIO_SETMODE: 2254 wsmode = *(u_int *)data; 2255 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 2256 return (EINVAL); 2257 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 2258 break; 2259 default: 2260 return (-1); 2261 } 2262 return (0); 2263 } 2264 2265 int 2266 pms_sync_elantech_v1(struct pms_softc *sc, int data) 2267 { 2268 struct elantech_softc *elantech = sc->elantech; 2269 u_char p; 2270 2271 switch (sc->inputstate) { 2272 case 0: 2273 if (elantech->flags & ELANTECH_F_HW_V1_OLD) { 2274 elantech->p1 = (data & 0x20) >> 5; 2275 elantech->p2 = (data & 0x10) >> 4; 2276 } else { 2277 elantech->p1 = (data & 0x10) >> 4; 2278 elantech->p2 = (data & 0x20) >> 5; 2279 } 2280 elantech->p3 = (data & 0x04) >> 2; 2281 return (0); 2282 case 1: 2283 p = elantech->p1; 2284 break; 2285 case 2: 2286 p = elantech->p2; 2287 break; 2288 case 3: 2289 p = elantech->p3; 2290 break; 2291 default: 2292 return (-1); 2293 } 2294 2295 if (data < 0 || data >= nitems(elantech->parity) || 2296 /* 2297 * FW 0x20022 sends inverted parity bits on cold boot, returning 2298 * to normal after suspend & resume, so the parity check is 2299 * disabled for this one. 2300 */ 2301 (elantech->fw_version != 0x20022 && elantech->parity[data] != p)) 2302 return (-1); 2303 2304 return (0); 2305 } 2306 2307 int 2308 pms_sync_elantech_v2(struct pms_softc *sc, int data) 2309 { 2310 struct elantech_softc *elantech = sc->elantech; 2311 2312 /* Variants reporting pressure always have the same constant bits. */ 2313 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) { 2314 if (sc->inputstate == 0 && (data & 0x0c) != 0x04) 2315 return (-1); 2316 if (sc->inputstate == 3 && (data & 0x0f) != 0x02) 2317 return (-1); 2318 return (0); 2319 } 2320 2321 /* For variants not reporting pressure, 1 and 3 finger touch packets 2322 * have different constant bits than 2 finger touch packets. */ 2323 switch (sc->inputstate) { 2324 case 0: 2325 if ((data & 0xc0) == 0x80) { 2326 if ((data & 0x0c) != 0x0c) 2327 return (-1); 2328 elantech->flags |= ELANTECH_F_2FINGER_PACKET; 2329 } else { 2330 if ((data & 0x3c) != 0x3c) 2331 return (-1); 2332 elantech->flags &= ~ELANTECH_F_2FINGER_PACKET; 2333 } 2334 break; 2335 case 1: 2336 case 4: 2337 if (elantech->flags & ELANTECH_F_2FINGER_PACKET) 2338 break; 2339 if ((data & 0xf0) != 0x00) 2340 return (-1); 2341 break; 2342 case 3: 2343 if (elantech->flags & ELANTECH_F_2FINGER_PACKET) { 2344 if ((data & 0x0e) != 0x08) 2345 return (-1); 2346 } else { 2347 if ((data & 0x3e) != 0x38) 2348 return (-1); 2349 } 2350 break; 2351 default: 2352 break; 2353 } 2354 2355 return (0); 2356 } 2357 2358 int 2359 pms_sync_elantech_v3(struct pms_softc *sc, int data) 2360 { 2361 struct elantech_softc *elantech = sc->elantech; 2362 2363 switch (sc->inputstate) { 2364 case 0: 2365 if (elantech->flags & ELANTECH_F_CRC_ENABLED) 2366 break; 2367 if ((data & 0x0c) != 0x04 && (data & 0x0c) != 0x0c) 2368 return (-1); 2369 break; 2370 case 3: 2371 if (elantech->flags & ELANTECH_F_CRC_ENABLED) { 2372 if ((data & 0x09) != 0x08 && (data & 0x09) != 0x09) 2373 return (-1); 2374 } else { 2375 if ((data & 0xcf) != 0x02 && (data & 0xce) != 0x0c) 2376 return (-1); 2377 } 2378 break; 2379 } 2380 2381 return (0); 2382 } 2383 2384 /* Extract the type bits from packet[3]. */ 2385 static inline int 2386 elantech_packet_type(struct elantech_softc *elantech, u_char b) 2387 { 2388 /* 2389 * This looks dubious, but in the "crc-enabled" format bit 2 may 2390 * be set even in MOTION packets. 2391 */ 2392 if ((elantech->flags & ELANTECH_F_TRACKPOINT) && ((b & 0x0f) == 0x06)) 2393 return (ELANTECH_PKT_TRACKPOINT); 2394 else 2395 return (b & 0x03); 2396 } 2397 2398 int 2399 pms_sync_elantech_v4(struct pms_softc *sc, int data) 2400 { 2401 if (sc->inputstate == 0) 2402 return ((data & 0x08) == 0 ? 0 : -1); 2403 2404 if (sc->inputstate == 3) { 2405 switch (elantech_packet_type(sc->elantech, data)) { 2406 case ELANTECH_V4_PKT_STATUS: 2407 case ELANTECH_V4_PKT_HEAD: 2408 case ELANTECH_V4_PKT_MOTION: 2409 if (sc->elantech->flags & ELANTECH_F_CRC_ENABLED) 2410 return ((data & 0x08) == 0 ? 0 : -1); 2411 else 2412 return ((data & 0x1c) == 0x10 ? 0 : -1); 2413 case ELANTECH_PKT_TRACKPOINT: 2414 return ((sc->packet[0] & 0xc8) == 0 2415 && sc->packet[1] == ((data & 0x10) << 3) 2416 && sc->packet[2] == ((data & 0x20) << 2) 2417 && (data ^ (sc->packet[0] & 0x30)) == 0x36 2418 ? 0 : -1); 2419 } 2420 return (-1); 2421 } 2422 return (0); 2423 } 2424 2425 void 2426 pms_proc_elantech_v1(struct pms_softc *sc) 2427 { 2428 struct elantech_softc *elantech = sc->elantech; 2429 int x, y, w, z; 2430 u_int buttons; 2431 2432 buttons = butmap[sc->packet[0] & 3]; 2433 2434 if (elantech->flags & ELANTECH_F_HAS_ROCKER) { 2435 if (sc->packet[0] & 0x40) /* up */ 2436 buttons |= WSMOUSE_BUTTON(4); 2437 if (sc->packet[0] & 0x80) /* down */ 2438 buttons |= WSMOUSE_BUTTON(5); 2439 } 2440 2441 if (elantech->flags & ELANTECH_F_HW_V1_OLD) 2442 w = ((sc->packet[1] & 0x80) >> 7) + 2443 ((sc->packet[1] & 0x30) >> 4); 2444 else 2445 w = (sc->packet[0] & 0xc0) >> 6; 2446 2447 /* 2448 * Firmwares 0x20022 and 0x20600 have a bug, position data in the 2449 * first two reports for single-touch contacts may be corrupt. 2450 */ 2451 if (elantech->fw_version == 0x20022 || 2452 elantech->fw_version == 0x20600) { 2453 if (w == 1) { 2454 if (elantech->initial_pkt < 2) { 2455 elantech->initial_pkt++; 2456 return; 2457 } 2458 } else if (elantech->initial_pkt) { 2459 elantech->initial_pkt = 0; 2460 } 2461 } 2462 2463 /* Hardware version 1 doesn't report pressure. */ 2464 if (w) { 2465 x = ((sc->packet[1] & 0x0c) << 6) | sc->packet[2]; 2466 y = ((sc->packet[1] & 0x03) << 8) | sc->packet[3]; 2467 z = SYNAPTICS_PRESSURE; 2468 } else { 2469 x = y = z = 0; 2470 } 2471 2472 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 2473 } 2474 2475 void 2476 pms_proc_elantech_v2(struct pms_softc *sc) 2477 { 2478 const u_char debounce_pkt[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff }; 2479 struct elantech_softc *elantech = sc->elantech; 2480 int x, y, w, z; 2481 u_int buttons; 2482 2483 /* 2484 * The hardware sends this packet when in debounce state. 2485 * The packet should be ignored. 2486 */ 2487 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))) 2488 return; 2489 2490 buttons = butmap[sc->packet[0] & 3]; 2491 2492 w = (sc->packet[0] & 0xc0) >> 6; 2493 if (w == 1 || w == 3) { 2494 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2]; 2495 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5]; 2496 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) 2497 z = ((sc->packet[1] & 0xf0) | 2498 (sc->packet[4] & 0xf0) >> 4); 2499 else 2500 z = SYNAPTICS_PRESSURE; 2501 } else if (w == 2) { 2502 x = (((sc->packet[0] & 0x10) << 4) | sc->packet[1]) << 2; 2503 y = (((sc->packet[0] & 0x20) << 3) | sc->packet[2]) << 2; 2504 z = SYNAPTICS_PRESSURE; 2505 } else { 2506 x = y = z = 0; 2507 } 2508 2509 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 2510 } 2511 2512 void 2513 pms_proc_elantech_v3(struct pms_softc *sc) 2514 { 2515 const u_char debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff }; 2516 struct elantech_softc *elantech = sc->elantech; 2517 int x, y, w, z; 2518 u_int buttons; 2519 2520 buttons = butmap[sc->packet[0] & 3]; 2521 2522 x = ((sc->packet[1] & 0x0f) << 8 | sc->packet[2]); 2523 y = ((sc->packet[4] & 0x0f) << 8 | sc->packet[5]); 2524 z = 0; 2525 w = (sc->packet[0] & 0xc0) >> 6; 2526 if (w == 2) { 2527 /* 2528 * Two-finger touch causes two packets -- a head packet 2529 * and a tail packet. We report a single event and ignore 2530 * the tail packet. 2531 */ 2532 if (elantech->flags & ELANTECH_F_CRC_ENABLED) { 2533 if ((sc->packet[3] & 0x09) != 0x08) 2534 return; 2535 } else { 2536 /* The hardware sends this packet when in debounce state. 2537 * The packet should be ignored. */ 2538 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))) 2539 return; 2540 if ((sc->packet[0] & 0x0c) != 0x04 && 2541 (sc->packet[3] & 0xcf) != 0x02) { 2542 /* not the head packet -- ignore */ 2543 return; 2544 } 2545 } 2546 } 2547 2548 /* Prevent jumping cursor if pad isn't touched or reports garbage. */ 2549 if (w == 0 || 2550 ((x == 0 || y == 0 || x == elantech->max_x || y == elantech->max_y) 2551 && (x != elantech->old_x || y != elantech->old_y))) { 2552 x = elantech->old_x; 2553 y = elantech->old_y; 2554 } 2555 2556 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) 2557 z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4); 2558 else if (w) 2559 z = SYNAPTICS_PRESSURE; 2560 2561 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 2562 elantech->old_x = x; 2563 elantech->old_y = y; 2564 } 2565 2566 void 2567 pms_proc_elantech_v4(struct pms_softc *sc) 2568 { 2569 struct elantech_softc *elantech = sc->elantech; 2570 struct device *sc_wsmousedev = sc->sc_wsmousedev; 2571 int id, weight, n, x, y, z; 2572 u_int buttons, slots; 2573 2574 switch (elantech_packet_type(elantech, sc->packet[3])) { 2575 case ELANTECH_V4_PKT_STATUS: 2576 slots = elantech->mt_slots; 2577 elantech->mt_slots = sc->packet[1] & 0x1f; 2578 slots &= ~elantech->mt_slots; 2579 for (id = 0; slots; id++, slots >>= 1) { 2580 if (slots & 1) 2581 wsmouse_mtstate(sc_wsmousedev, id, 0, 0, 0); 2582 } 2583 break; 2584 2585 case ELANTECH_V4_PKT_HEAD: 2586 id = ((sc->packet[3] & 0xe0) >> 5) - 1; 2587 if (id > -1 && id < ELANTECH_MAX_FINGERS) { 2588 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2]; 2589 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5]; 2590 z = (sc->packet[1] & 0xf0) 2591 | ((sc->packet[4] & 0xf0) >> 4); 2592 wsmouse_mtstate(sc_wsmousedev, id, x, y, z); 2593 } 2594 break; 2595 2596 case ELANTECH_V4_PKT_MOTION: 2597 weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE : 1; 2598 for (n = 0; n < 6; n += 3) { 2599 id = ((sc->packet[n] & 0xe0) >> 5) - 1; 2600 if (id < 0 || id >= ELANTECH_MAX_FINGERS) 2601 continue; 2602 x = weight * (signed char)sc->packet[n + 1]; 2603 y = weight * (signed char)sc->packet[n + 2]; 2604 z = WSMOUSE_DEFAULT_PRESSURE; 2605 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_X, x, id); 2606 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_Y, y, id); 2607 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_PRESSURE, z, id); 2608 } 2609 break; 2610 2611 case ELANTECH_PKT_TRACKPOINT: 2612 if (sc->sc_dev_enable & PMS_DEV_SECONDARY) { 2613 x = sc->packet[4] - 0x100 + (sc->packet[1] << 1); 2614 y = sc->packet[5] - 0x100 + (sc->packet[2] << 1); 2615 buttons = butmap[sc->packet[0] & 7]; 2616 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, 2617 buttons, x, y, 0, 0); 2618 } 2619 return; 2620 2621 default: 2622 printf("%s: unknown packet type 0x%x\n", DEVNAME(sc), 2623 sc->packet[3] & 0x1f); 2624 return; 2625 } 2626 2627 buttons = butmap[sc->packet[0] & 3]; 2628 wsmouse_buttons(sc_wsmousedev, buttons); 2629 2630 wsmouse_input_sync(sc_wsmousedev); 2631 } 2632