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