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