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