LCOV - code coverage report
Current view: top level - dev/pckbc - pms.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1257 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 69 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13