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