Advertisement
Guest User

Untitled

a guest
Jan 12th, 2019
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 225.31 KB | None | 0 0
  1. /*-
  2.  * Copyright (c) 1992, 1993 Erik Forsberg.
  3.  * Copyright (c) 1996, 1997 Kazutaka YOKOTA.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  *
  12.  * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
  13.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  14.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  15.  * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  16.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  17.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  18.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  19.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  20.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22.  */
  23. /*
  24.  *  Ported to 386bsd Oct 17, 1992
  25.  *  Sandi Donno, Computer Science, University of Cape Town, South Africa
  26.  *  Please send bug reports to sandi@cs.uct.ac.za
  27.  *
  28.  *  Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
  29.  *  although I was only partially successful in getting the alpha release
  30.  *  of his "driver for the Logitech and ATI Inport Bus mice for use with
  31.  *  386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
  32.  *  found his code to be an invaluable reference when porting this driver
  33.  *  to 386bsd.
  34. v *
  35.  *  Further modifications for latest 386BSD+patchkit and port to NetBSD,
  36.  *  Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
  37.  *
  38.  *  Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
  39.  *  Andrew Herbert - 12 June 1993
  40.  *
  41.  *  Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
  42.  *  - 13 June 1993
  43.  *
  44.  *  Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
  45.  *  - 24 October 1993
  46.  *
  47.  *  Hardware access routines and probe logic rewritten by
  48.  *  Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
  49.  *  - 3, 14, 22 October 1996.
  50.  *  - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
  51.  *  - 14, 30 November 1996. Uses `kbdio.c'.
  52.  *  - 13 December 1996. Uses queuing version of `kbdio.c'.
  53.  *  - January/February 1997. Tweaked probe logic for
  54.  *    HiNote UltraII/Latitude/Armada laptops.
  55.  *  - 30 July 1997. Added APM support.
  56.  *  - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX).
  57.  *    Improved sync check logic.
  58.  *    Vendor specific support routines.
  59.  */
  60.  
  61. #include <sys/cdefs.h>
  62. __FBSDID("$FreeBSD: releng/11.2/sys/dev/atkbdc/psm.c 331172 2018-03-19 03:49:54Z eadler $");
  63.  
  64. #include "opt_isa.h"
  65. #include "opt_psm.h"
  66. #include "opt_evdev.h"
  67.  
  68. #include <sys/param.h>
  69. #include <sys/systm.h>
  70. #include <sys/kernel.h>
  71. #include <sys/module.h>
  72. #include <sys/bus.h>
  73. #include <sys/conf.h>
  74. #include <sys/filio.h>
  75. #include <sys/poll.h>
  76. #include <sys/sigio.h>
  77. #include <sys/signalvar.h>
  78. #include <sys/syslog.h>
  79. #include <machine/bus.h>
  80. #include <sys/rman.h>
  81. #include <sys/selinfo.h>
  82. #include <sys/sysctl.h>
  83. #include <sys/time.h>
  84. #include <sys/uio.h>
  85.  
  86. #include <sys/limits.h>
  87. #include <sys/mouse.h>
  88. #include <machine/resource.h>
  89.  
  90. #ifdef DEV_ISA
  91. #include <isa/isavar.h>
  92. #endif
  93.  
  94. #ifdef EVDEV_SUPPORT
  95. #include <dev/evdev/evdev.h>
  96. #include <dev/evdev/input.h>
  97. #endif
  98.  
  99. #include <dev/atkbdc/atkbdcreg.h>
  100. #include <dev/atkbdc/psm.h>
  101.  
  102. /*
  103.  * Driver specific options: the following options may be set by
  104.  * `options' statements in the kernel configuration file.
  105.  */
  106.  
  107. /* debugging */
  108. #ifndef PSM_DEBUG
  109. #define PSM_DEBUG   4   /*
  110.                  * logging: 0: none, 1: brief, 2: verbose
  111.                  *          3: sync errors, 4: all packets
  112.                  */
  113. #endif
  114. #define VLOG(level, args)   do {    \
  115.     if (verbose >= level)       \
  116.         log args;       \
  117. } while (0)
  118.  
  119. #ifndef PSM_INPUT_TIMEOUT
  120. #define PSM_INPUT_TIMEOUT   2000000 /* 2 sec */
  121. #endif
  122.  
  123. #ifndef PSM_TAP_TIMEOUT
  124. #define PSM_TAP_TIMEOUT     125000
  125. #endif
  126.  
  127. #ifndef PSM_TAP_THRESHOLD
  128. #define PSM_TAP_THRESHOLD   25
  129. #endif
  130.  
  131. /* end of driver specific options */
  132.  
  133. #define PSMCPNP_DRIVER_NAME "psmcpnp"
  134.  
  135. struct psmcpnp_softc {
  136.     enum {
  137.         PSMCPNP_GENERIC,
  138.         PSMCPNP_FORCEPAD,
  139.         PSMCPNP_HPSYN81,
  140.     } type;     /* Based on PnP ID */
  141. };
  142.  
  143. /* input queue */
  144. #define PSM_BUFSIZE     960
  145. #define PSM_SMALLBUFSIZE    240
  146.  
  147. /* operation levels */
  148. #define PSM_LEVEL_BASE      0
  149. #define PSM_LEVEL_STANDARD  1
  150. #define PSM_LEVEL_NATIVE    2
  151. #define PSM_LEVEL_MIN       PSM_LEVEL_BASE
  152. #define PSM_LEVEL_MAX       PSM_LEVEL_NATIVE
  153.  
  154. /* Logitech PS2++ protocol */
  155. #define MOUSE_PS2PLUS_CHECKBITS(b)  \
  156.     ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
  157. #define MOUSE_PS2PLUS_PACKET_TYPE(b)    \
  158.     (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
  159.  
  160. /* ring buffer */
  161. typedef struct ringbuf {
  162.     int     count;  /* # of valid elements in the buffer */
  163.     int     head;   /* head pointer */
  164.     int     tail;   /* tail poiner */
  165.     u_char buf[PSM_BUFSIZE];
  166. } ringbuf_t;
  167.  
  168. /* data buffer */
  169. typedef struct packetbuf {
  170.     u_char  ipacket[16];    /* interim input buffer */
  171.     int inputbytes; /* # of bytes in the input buffer */
  172. } packetbuf_t;
  173.  
  174. #ifndef PSM_PACKETQUEUE
  175. #define PSM_PACKETQUEUE 128
  176. #endif
  177.  
  178. /*
  179.  * Typical bezel limits. Taken from 'Synaptics
  180.  * PS/2 TouchPad Interfacing Guide' p.3.2.3.
  181.  */
  182. #define SYNAPTICS_DEFAULT_MAX_X 5472
  183. #define SYNAPTICS_DEFAULT_MAX_Y 4448
  184. #define SYNAPTICS_DEFAULT_MIN_X 1472
  185. #define SYNAPTICS_DEFAULT_MIN_Y 1408
  186.  
  187. typedef struct synapticsinfo {
  188.     struct sysctl_ctx_list   sysctl_ctx;
  189.     struct sysctl_oid   *sysctl_tree;
  190.     int          directional_scrolls;
  191.     int          two_finger_scroll;
  192.     int          min_pressure;
  193.     int          max_pressure;
  194.     int          max_width;
  195.     int          margin_top;
  196.     int          margin_right;
  197.     int          margin_bottom;
  198.     int          margin_left;
  199.     int          na_top;
  200.     int          na_right;
  201.     int          na_bottom;
  202.     int          na_left;
  203.     int          window_min;
  204.     int          window_max;
  205.     int          multiplicator;
  206.     int          weight_current;
  207.     int          weight_previous;
  208.     int          weight_previous_na;
  209.     int          weight_len_squared;
  210.     int          div_min;
  211.     int          div_max;
  212.     int          div_max_na;
  213.     int          div_len;
  214.     int          tap_max_delta;
  215.     int          tap_min_queue;
  216.     int          taphold_timeout;
  217.     int          vscroll_ver_area;
  218.     int          vscroll_hor_area;
  219.     int          vscroll_min_delta;
  220.     int          vscroll_div_min;
  221.     int          vscroll_div_max;
  222.     int          touchpad_off;
  223.     int          softbuttons_y;
  224.     int          softbutton2_x;
  225.     int          softbutton3_x;
  226.     int          max_x;
  227.     int          max_y;
  228. } synapticsinfo_t;
  229.  
  230. typedef struct synapticspacket {
  231.     int         x;
  232.     int         y;
  233. } synapticspacket_t;
  234.  
  235. #define SYNAPTICS_PACKETQUEUE 10
  236. #define SYNAPTICS_QUEUE_CURSOR(x)                   \
  237.     (x + SYNAPTICS_PACKETQUEUE) % SYNAPTICS_PACKETQUEUE
  238.  
  239. #define SYNAPTICS_VERSION_GE(synhw, major, minor)           \
  240.     ((synhw).infoMajor > (major) ||                 \
  241.      ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
  242.  
  243. typedef struct smoother {
  244.     synapticspacket_t   queue[SYNAPTICS_PACKETQUEUE];
  245.     int         queue_len;
  246.     int         queue_cursor;
  247.     int         start_x;
  248.     int         start_y;
  249.     int         avg_dx;
  250.     int         avg_dy;
  251.     int         squelch_x;
  252.     int         squelch_y;
  253.     int         is_fuzzy;
  254.     int         active;
  255. } smoother_t;
  256.  
  257. typedef struct gesture {
  258.     int         window_min;
  259.     int         fingers_nb;
  260.     int         tap_button;
  261.     int         in_taphold;
  262.     int         in_vscroll;
  263.     int         zmax;       /* maximum pressure value */
  264.     struct timeval      taptimeout; /* tap timeout for touchpads */
  265. } gesture_t;
  266.  
  267. enum {
  268.     TRACKPOINT_SYSCTL_SENSITIVITY,
  269.     TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
  270.     TRACKPOINT_SYSCTL_UPPER_PLATEAU,
  271.     TRACKPOINT_SYSCTL_BACKUP_RANGE,
  272.     TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
  273.     TRACKPOINT_SYSCTL_MINIMUM_DRAG,
  274.     TRACKPOINT_SYSCTL_UP_THRESHOLD,
  275.     TRACKPOINT_SYSCTL_THRESHOLD,
  276.     TRACKPOINT_SYSCTL_JENKS_CURVATURE,
  277.     TRACKPOINT_SYSCTL_Z_TIME,
  278.     TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
  279.     TRACKPOINT_SYSCTL_SKIP_BACKUPS
  280. };
  281.  
  282. typedef struct trackpointinfo {
  283.     struct sysctl_ctx_list sysctl_ctx;
  284.     struct sysctl_oid *sysctl_tree;
  285.     int sensitivity;
  286.     int inertia;
  287.     int uplateau;
  288.     int reach;
  289.     int draghys;
  290.     int mindrag;
  291.     int upthresh;
  292.     int threshold;
  293.     int jenks;
  294.     int ztime;
  295.     int pts;
  296.     int skipback;
  297. } trackpointinfo_t;
  298.  
  299. typedef struct finger {
  300.     int         x;
  301.     int         y;
  302.     int         p;
  303.     int         w;
  304.     int         flags;
  305. } finger_t;
  306. #define PSM_FINGERS     2   /* # of processed fingers */
  307. #define PSM_FINGER_IS_PEN   (1<<0)
  308. #define PSM_FINGER_FUZZY    (1<<1)
  309. #define PSM_FINGER_DEFAULT_P    tap_threshold
  310. #define PSM_FINGER_DEFAULT_W    1
  311. #define PSM_FINGER_IS_SET(f) ((f).x != -1 && (f).y != -1 && (f).p != 0)
  312. #define PSM_FINGER_RESET(f) do { \
  313.     (f) = (finger_t) { .x = -1, .y = -1, .p = 0, .w = 0, .flags = 0 }; \
  314. } while (0)
  315.  
  316. typedef struct elantechhw {
  317.     int         hwversion;
  318.     int         fwversion;
  319.     int         sizex;
  320.     int         sizey;
  321.     int         dpmmx;
  322.     int         dpmmy;
  323.     int         ntracesx;
  324.     int         ntracesy;
  325.     int         dptracex;
  326.     int         dptracey;
  327.     int         issemimt;
  328.     int         isclickpad;
  329.     int         hascrc;
  330.     int         hastrackpoint;
  331.     int         haspressure;
  332. } elantechhw_t;
  333.  
  334. /* minimum versions supported by this driver */
  335. #define ELANTECH_HW_IS_V1(fwver) ((fwver) < 0x020030 || (fwver) == 0x020600)
  336.  
  337. #define ELANTECH_MAGIC(magic)               \
  338.     ((magic)[0] == 0x3c && (magic)[1] == 0x03 &&    \
  339.     ((magic)[2] == 0xc8 || (magic)[2] == 0x00))
  340.  
  341. #define ELANTECH_FW_ID      0x00
  342. #define ELANTECH_FW_VERSION 0x01
  343. #define ELANTECH_CAPABILITIES   0x02
  344. #define ELANTECH_SAMPLE     0x03
  345. #define ELANTECH_RESOLUTION 0x04
  346. #define ELANTECH_REG_READ   0x10
  347. #define ELANTECH_REG_WRITE  0x11
  348. #define ELANTECH_REG_RDWR   0x00
  349. #define ELANTECH_CUSTOM_CMD 0xf8
  350.  
  351. #ifdef EVDEV_SUPPORT
  352. #define ELANTECH_MAX_FINGERS    5
  353. #else
  354. #define ELANTECH_MAX_FINGERS    PSM_FINGERS
  355. #endif
  356.  
  357. #define ELANTECH_FINGER_MAX_P   255
  358. #define ELANTECH_FINGER_MAX_W   15
  359. #define ELANTECH_FINGER_SET_XYP(pb) (finger_t) {            \
  360.     .x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2],       \
  361.     .y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5],       \
  362.     .p = ((pb)->ipacket[1] & 0xf0) | (((pb)->ipacket[4] >> 4) & 0x0f),  \
  363.     .w = PSM_FINGER_DEFAULT_W,                      \
  364.     .flags = 0                              \
  365. }
  366.  
  367. enum {
  368.     ELANTECH_PKT_NOP,
  369.     ELANTECH_PKT_TRACKPOINT,
  370.     ELANTECH_PKT_V2_COMMON,
  371.     ELANTECH_PKT_V2_2FINGER,
  372.     ELANTECH_PKT_V3,
  373.     ELANTECH_PKT_V4_STATUS,
  374.     ELANTECH_PKT_V4_HEAD,
  375.     ELANTECH_PKT_V4_MOTION
  376. };
  377.  
  378. #define ELANTECH_PKT_IS_TRACKPOINT(pb) (((pb)->ipacket[3] & 0x0f) == 0x06)
  379. #define ELANTECH_PKT_IS_DEBOUNCE(pb, hwversion) ((hwversion) == 4 ? 0 : \
  380.     (pb)->ipacket[0] == ((hwversion) == 2 ? 0x84 : 0xc4) &&     \
  381.     (pb)->ipacket[1] == 0xff && (pb)->ipacket[2] == 0xff &&     \
  382.     (pb)->ipacket[3] == 0x02 && (pb)->ipacket[4] == 0xff &&     \
  383.     (pb)->ipacket[5] == 0xff)
  384. #define ELANTECH_PKT_IS_V2(pb)                      \
  385.     (((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x0f) == 0x02)
  386. #define ELANTECH_PKT_IS_V3_HEAD(pb, hascrc) ((hascrc) ?         \
  387.     ((pb)->ipacket[3] & 0x09) == 0x08 :                 \
  388.     ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0xcf) == 0x02)
  389. #define ELANTECH_PKT_IS_V3_TAIL(pb, hascrc) ((hascrc) ?         \
  390.     ((pb)->ipacket[3] & 0x09) == 0x09 :                 \
  391.     ((pb)->ipacket[0] & 0x0c) == 0x0c && ((pb)->ipacket[3] & 0xce) == 0x0c)
  392. #define ELANTECH_PKT_IS_V4(pb, hascrc) ((hascrc) ?          \
  393.     ((pb)->ipacket[3] & 0x08) == 0x00 :                 \
  394.     ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x1c) == 0x10)
  395.  
  396. typedef struct elantechaction {
  397.     finger_t        fingers[ELANTECH_MAX_FINGERS];
  398.     int         mask;
  399.     int         mask_v4wait;
  400. } elantechaction_t;
  401.  
  402. enum {
  403.       FOCALTECH_PKT_TOUCH = 0x3,
  404.       FOCALTECH_PKT_ABS = 0x6,
  405.       FOCALTECH_PKT_REL = 0x9,
  406. };
  407.  
  408. #define FOCALTECH_MAX_X 2431
  409. #define FOCALTECH_MAX_Y 1663
  410.  
  411. #define FOCALTECH_MAX_FINGERS PSM_FINGERS
  412.  
  413. typedef struct focalfinger {
  414.   int x;
  415.   int y;
  416.  
  417.   bool active;
  418.   bool valid;
  419. } focalfinger_t;
  420.  
  421. typedef struct focaltechhw {
  422.   int pressed;
  423.   int width;
  424.  
  425.   focalfinger_t fingers[FOCALTECH_MAX_FINGERS];
  426.  
  427. } focaltechhw_t;
  428.  
  429. /* driver control block */
  430. struct psm_softc {      /* Driver status information */
  431.     int     unit;
  432.     struct selinfo  rsel;       /* Process selecting for Input */
  433.     u_char      state;      /* Mouse driver state */
  434.     int     config;     /* driver configuration flags */
  435.     int     flags;      /* other flags */
  436.     KBDC        kbdc;       /* handle to access kbd controller */
  437.     struct resource *intr;      /* IRQ resource */
  438.     void        *ih;        /* interrupt handle */
  439.     mousehw_t   hw;     /* hardware information */
  440.     synapticshw_t   synhw;      /* Synaptics hardware information */
  441.     synapticsinfo_t syninfo;    /* Synaptics configuration */
  442.     smoother_t  smoother[PSM_FINGERS];  /* Motion smoothing */
  443.     gesture_t   gesture;    /* Gesture context */
  444.     elantechhw_t    elanhw;     /* Elantech hardware information */
  445.     elantechaction_t elanaction;    /* Elantech action context */
  446.         focaltechhw_t   focalhw;
  447.         int     tphw;       /* TrackPoint hardware information */
  448.     trackpointinfo_t tpinfo;    /* TrackPoint configuration */
  449.     mousemode_t mode;       /* operation mode */
  450.     mousemode_t dflt_mode;  /* default operation mode */
  451.     mousestatus_t   status;     /* accumulated mouse movement */
  452.     ringbuf_t   queue;      /* mouse status queue */
  453.     packetbuf_t pqueue[PSM_PACKETQUEUE]; /* mouse data queue */
  454.     int     pqueue_start;   /* start of data in queue */
  455.     int     pqueue_end; /* end of data in queue */
  456.     int     button;     /* the latest button state */
  457.     int     xold;       /* previous absolute X position */
  458.     int     yold;       /* previous absolute Y position */
  459.     int     xaverage;   /* average X position */
  460.     int     yaverage;   /* average Y position */
  461.     int     squelch; /* level to filter movement at low speed */
  462.     int     syncerrors; /* # of bytes discarded to synchronize */
  463.     int     pkterrors;  /* # of packets failed during quaranteen. */
  464.     int     fpcount;    /* forcePad valid packet counter */
  465.     struct timeval  inputtimeout;
  466.     struct timeval  lastsoftintr;   /* time of last soft interrupt */
  467.     struct timeval  lastinputerr;   /* time last sync error happened */
  468.     struct timeval  idletimeout;
  469.     packetbuf_t idlepacket; /* packet to send after idle timeout */
  470.     int     watchdog;   /* watchdog timer flag */
  471.     struct callout  callout;    /* watchdog timer call out */
  472.     struct callout  softcallout; /* buffer timer call out */
  473.     struct cdev *dev;
  474.     struct cdev *bdev;
  475.     int     lasterr;
  476.     int     cmdcount;
  477.     struct sigio    *async;     /* Processes waiting for SIGIO */
  478.     int     extended_buttons;
  479. #ifdef EVDEV_SUPPORT
  480.     struct evdev_dev *evdev_a;  /* Absolute reporting device */
  481.     struct evdev_dev *evdev_r;  /* Relative reporting device */
  482. #endif
  483. };
  484. static devclass_t psm_devclass;
  485.  
  486. /* driver state flags (state) */
  487. #define PSM_VALID       0x80
  488. #define PSM_OPEN        1   /* Device is open */
  489. #define PSM_ASLP        2   /* Waiting for mouse data */
  490. #define PSM_SOFTARMED       4   /* Software interrupt armed */
  491. #define PSM_NEED_SYNCBITS   8   /* Set syncbits using next data pkt */
  492. #define PSM_EV_OPEN_R       0x10    /* Relative evdev device is open */
  493. #define PSM_EV_OPEN_A       0x20    /* Absolute evdev device is open */
  494.  
  495. /* driver configuration flags (config) */
  496. #define PSM_CONFIG_RESOLUTION   0x000f  /* resolution */
  497. #define PSM_CONFIG_ACCEL    0x00f0  /* acceleration factor */
  498. #define PSM_CONFIG_NOCHECKSYNC  0x0100  /* disable sync. test */
  499. #define PSM_CONFIG_NOIDPROBE    0x0200  /* disable mouse model probe */
  500. #define PSM_CONFIG_NORESET  0x0400  /* don't reset the mouse */
  501. #define PSM_CONFIG_FORCETAP 0x0800  /* assume `tap' action exists */
  502. #define PSM_CONFIG_IGNPORTERROR 0x1000  /* ignore error in aux port test */
  503. #define PSM_CONFIG_HOOKRESUME   0x2000  /* hook the system resume event */
  504. #define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
  505.  
  506. #define PSM_CONFIG_FLAGS    \
  507.     (PSM_CONFIG_RESOLUTION |    \
  508.     PSM_CONFIG_ACCEL |      \
  509.     PSM_CONFIG_NOCHECKSYNC |    \
  510.     PSM_CONFIG_NOIDPROBE |  \
  511.     PSM_CONFIG_NORESET |    \
  512.     PSM_CONFIG_FORCETAP |   \
  513.     PSM_CONFIG_IGNPORTERROR |   \
  514.     PSM_CONFIG_HOOKRESUME | \
  515.     PSM_CONFIG_INITAFTERSUSPEND)
  516.  
  517. /* other flags (flags) */
  518. #define PSM_FLAGS_FINGERDOWN    0x0001  /* VersaPad finger down */
  519.  
  520. #define kbdcp(p)            ((atkbdc_softc_t *)(p))
  521. #define ALWAYS_RESTORE_CONTROLLER(kbdc) !(kbdcp(kbdc)->quirks \
  522.     & KBDC_QUIRK_KEEP_ACTIVATED)
  523.  
  524. /* Tunables */
  525. static int tap_enabled = -1;
  526. static int verbose = PSM_DEBUG;
  527. static int synaptics_support = 0;
  528. static int trackpoint_support = 0;
  529. static int elantech_support = 0;
  530.  
  531. /* for backward compatibility */
  532. #define OLD_MOUSE_GETHWINFO _IOR('M', 1, old_mousehw_t)
  533. #define OLD_MOUSE_GETMODE   _IOR('M', 2, old_mousemode_t)
  534. #define OLD_MOUSE_SETMODE   _IOW('M', 3, old_mousemode_t)
  535.  
  536. typedef struct old_mousehw {
  537.     int buttons;
  538.     int iftype;
  539.     int type;
  540.     int hwid;
  541. } old_mousehw_t;
  542.  
  543. typedef struct old_mousemode {
  544.     int protocol;
  545.     int rate;
  546.     int resolution;
  547.     int accelfactor;
  548. } old_mousemode_t;
  549.  
  550. #define SYN_OFFSET(field) offsetof(struct psm_softc, syninfo.field)
  551. enum {
  552.     SYNAPTICS_SYSCTL_MIN_PRESSURE =     SYN_OFFSET(min_pressure),
  553.     SYNAPTICS_SYSCTL_MAX_PRESSURE =     SYN_OFFSET(max_pressure),
  554.     SYNAPTICS_SYSCTL_MAX_WIDTH =        SYN_OFFSET(max_width),
  555.     SYNAPTICS_SYSCTL_MARGIN_TOP =       SYN_OFFSET(margin_top),
  556.     SYNAPTICS_SYSCTL_MARGIN_RIGHT =     SYN_OFFSET(margin_right),
  557.     SYNAPTICS_SYSCTL_MARGIN_BOTTOM =    SYN_OFFSET(margin_bottom),
  558.     SYNAPTICS_SYSCTL_MARGIN_LEFT =      SYN_OFFSET(margin_left),
  559.     SYNAPTICS_SYSCTL_NA_TOP =       SYN_OFFSET(na_top),
  560.     SYNAPTICS_SYSCTL_NA_RIGHT =     SYN_OFFSET(na_right),
  561.     SYNAPTICS_SYSCTL_NA_BOTTOM =        SYN_OFFSET(na_bottom),
  562.     SYNAPTICS_SYSCTL_NA_LEFT =      SYN_OFFSET(na_left),
  563.     SYNAPTICS_SYSCTL_WINDOW_MIN =       SYN_OFFSET(window_min),
  564.     SYNAPTICS_SYSCTL_WINDOW_MAX =       SYN_OFFSET(window_max),
  565.     SYNAPTICS_SYSCTL_MULTIPLICATOR =    SYN_OFFSET(multiplicator),
  566.     SYNAPTICS_SYSCTL_WEIGHT_CURRENT =   SYN_OFFSET(weight_current),
  567.     SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS =  SYN_OFFSET(weight_previous),
  568.     SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA =   SYN_OFFSET(weight_previous_na),
  569.     SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED =   SYN_OFFSET(weight_len_squared),
  570.     SYNAPTICS_SYSCTL_DIV_MIN =      SYN_OFFSET(div_min),
  571.     SYNAPTICS_SYSCTL_DIV_MAX =      SYN_OFFSET(div_max),
  572.     SYNAPTICS_SYSCTL_DIV_MAX_NA =       SYN_OFFSET(div_max_na),
  573.     SYNAPTICS_SYSCTL_DIV_LEN =      SYN_OFFSET(div_len),
  574.     SYNAPTICS_SYSCTL_TAP_MAX_DELTA =    SYN_OFFSET(tap_max_delta),
  575.     SYNAPTICS_SYSCTL_TAP_MIN_QUEUE =    SYN_OFFSET(tap_min_queue),
  576.     SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT =  SYN_OFFSET(taphold_timeout),
  577.     SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA = SYN_OFFSET(vscroll_hor_area),
  578.     SYNAPTICS_SYSCTL_VSCROLL_VER_AREA = SYN_OFFSET(vscroll_ver_area),
  579.     SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA =    SYN_OFFSET(vscroll_min_delta),
  580.     SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN =  SYN_OFFSET(vscroll_div_min),
  581.     SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX =  SYN_OFFSET(vscroll_div_max),
  582.     SYNAPTICS_SYSCTL_TOUCHPAD_OFF =     SYN_OFFSET(touchpad_off),
  583.     SYNAPTICS_SYSCTL_SOFTBUTTONS_Y =    SYN_OFFSET(softbuttons_y),
  584.     SYNAPTICS_SYSCTL_SOFTBUTTON2_X =    SYN_OFFSET(softbutton2_x),
  585.     SYNAPTICS_SYSCTL_SOFTBUTTON3_X =    SYN_OFFSET(softbutton3_x),
  586. };
  587.  
  588. /* packet formatting function */
  589. typedef int packetfunc_t(struct psm_softc *, u_char *, int *, int,
  590.     mousestatus_t *);
  591.  
  592. /* function prototypes */
  593. static void psmidentify(driver_t *, device_t);
  594. static int  psmprobe(device_t);
  595. static int  psmattach(device_t);
  596. static int  psmdetach(device_t);
  597. static int  psmresume(device_t);
  598.  
  599. static d_open_t     psm_cdev_open;
  600. static d_close_t    psm_cdev_close;
  601. static d_read_t     psmread;
  602. static d_write_t    psmwrite;
  603. static d_ioctl_t    psmioctl;
  604. static d_poll_t     psmpoll;
  605.  
  606. static int  psmopen(struct psm_softc *);
  607. static int  psmclose(struct psm_softc *);
  608.  
  609. #ifdef EVDEV_SUPPORT
  610. static evdev_open_t psm_ev_open_r;
  611. static evdev_close_t    psm_ev_close_r;
  612. static evdev_open_t psm_ev_open_a;
  613. static evdev_close_t    psm_ev_close_a;
  614. #endif
  615.  
  616. static int  enable_aux_dev(KBDC);
  617. static int  disable_aux_dev(KBDC);
  618. static int  get_mouse_status(KBDC, int *, int, int);
  619. static int  get_aux_id(KBDC);
  620. static int  set_mouse_sampling_rate(KBDC, int);
  621. static int  set_mouse_scaling(KBDC, int);
  622. static int  set_mouse_resolution(KBDC, int);
  623. static int  set_mouse_mode(KBDC);
  624. static int  get_mouse_buttons(KBDC);
  625. static int  is_a_mouse(int);
  626. static void recover_from_error(KBDC);
  627. static int  restore_controller(KBDC, int);
  628. static int  doinitialize(struct psm_softc *, mousemode_t *);
  629. static int  doopen(struct psm_softc *, int);
  630. static int  reinitialize(struct psm_softc *, int);
  631. static char *model_name(int);
  632. static void psmsoftintr(void *);
  633. static void psmsoftintridle(void *);
  634. static void psmintr(void *);
  635. static void psmtimeout(void *);
  636. static int  timeelapsed(const struct timeval *, int, int,
  637.             const struct timeval *);
  638. static void dropqueue(struct psm_softc *);
  639. static void flushpackets(struct psm_softc *);
  640. static void proc_mmanplus(struct psm_softc *, packetbuf_t *,
  641.             mousestatus_t *, int *, int *, int *);
  642. static int  proc_synaptics(struct psm_softc *, packetbuf_t *,
  643.             mousestatus_t *, int *, int *, int *);
  644. static void proc_versapad(struct psm_softc *, packetbuf_t *,
  645.             mousestatus_t *, int *, int *, int *);
  646. static int  proc_elantech(struct psm_softc *, packetbuf_t *,
  647.             mousestatus_t *, int *, int *, int *);
  648. static int proc_focaltech(struct psm_softc *, packetbuf_t *,
  649.               mousestatus_t *, int *, int *, int *);
  650. static int  psmpalmdetect(struct psm_softc *, finger_t *, int);
  651. static void psmgestures(struct psm_softc *, finger_t *, int,
  652.             mousestatus_t *);
  653. static void psmsmoother(struct psm_softc *, finger_t *, int,
  654.             mousestatus_t *, int *, int *);
  655. static int  tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
  656.             u_char *);
  657.  
  658. /* vendor specific features */
  659. enum probearg { PROBE, REINIT };
  660. typedef int probefunc_t(struct psm_softc *, enum probearg);
  661.  
  662. static int  mouse_id_proc1(KBDC, int, int, int *);
  663. static int  mouse_ext_command(KBDC, int);
  664.  
  665. static probefunc_t  enable_groller;
  666. static probefunc_t  enable_gmouse;
  667. static probefunc_t  enable_aglide;
  668. static probefunc_t  enable_kmouse;
  669. static probefunc_t  enable_msexplorer;
  670. static probefunc_t  enable_msintelli;
  671. static probefunc_t  enable_4dmouse;
  672. static probefunc_t  enable_4dplus;
  673. static probefunc_t  enable_mmanplus;
  674. static probefunc_t  enable_synaptics;
  675. static probefunc_t  enable_trackpoint;
  676. static probefunc_t  enable_versapad;
  677. static probefunc_t  enable_elantech;
  678. static probefunc_t      enable_focaltech;
  679.  
  680.  
  681. static void set_trackpoint_parameters(struct psm_softc *sc);
  682. static void synaptics_passthrough_on(struct psm_softc *sc);
  683. static void synaptics_passthrough_off(struct psm_softc *sc);
  684. static int synaptics_preferred_mode(struct psm_softc *sc);
  685. static void synaptics_set_mode(struct psm_softc *sc, int mode_byte);
  686.  
  687. static struct {
  688.     int     model;
  689.     u_char      syncmask;
  690.     int     packetsize;
  691.     probefunc_t *probefunc;
  692. } vendortype[] = {
  693.     /*
  694.      * WARNING: the order of probe is very important.  Don't mess it
  695.      * unless you know what you are doing.
  696.      */
  697.           /* Focaltech Touchpad */
  698.           { MOUSE_MODEL_FOCALTECH,
  699.             0x0, 6, enable_focaltech },
  700.     { MOUSE_MODEL_NET,      /* Genius NetMouse */
  701.       0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse },
  702.     { MOUSE_MODEL_NETSCROLL,    /* Genius NetScroll */
  703.       0xc8, 6, enable_groller },
  704.     { MOUSE_MODEL_MOUSEMANPLUS, /* Logitech MouseMan+ */
  705.       0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus },
  706.     { MOUSE_MODEL_EXPLORER,     /* Microsoft IntelliMouse Explorer */
  707.       0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer },
  708.     { MOUSE_MODEL_4D,       /* A4 Tech 4D Mouse */
  709.       0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse },
  710.     { MOUSE_MODEL_4DPLUS,       /* A4 Tech 4D+ Mouse */
  711.       0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
  712.     { MOUSE_MODEL_SYNAPTICS,    /* Synaptics Touchpad */
  713.       0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
  714.     { MOUSE_MODEL_ELANTECH,     /* Elantech Touchpad */
  715.       0x04, MOUSE_ELANTECH_PACKETSIZE, enable_elantech },
  716.     { MOUSE_MODEL_INTELLI,      /* Microsoft IntelliMouse */
  717.       0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
  718.     { MOUSE_MODEL_GLIDEPOINT,   /* ALPS GlidePoint */
  719.       0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide },
  720.     { MOUSE_MODEL_THINK,        /* Kensington ThinkingMouse */
  721.       0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
  722.     { MOUSE_MODEL_VERSAPAD,     /* Interlink electronics VersaPad */
  723.       0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
  724.     { MOUSE_MODEL_TRACKPOINT,   /* IBM/Lenovo TrackPoint */
  725.       0xc0, MOUSE_PS2_PACKETSIZE, enable_trackpoint },
  726.     { MOUSE_MODEL_GENERIC,
  727.       0xc0, MOUSE_PS2_PACKETSIZE, NULL },
  728. };
  729. #define GENERIC_MOUSE_ENTRY (nitems(vendortype) - 1)
  730.  
  731. /* device driver declarateion */
  732. static device_method_t psm_methods[] = {
  733.     /* Device interface */
  734.     DEVMETHOD(device_identify,  psmidentify),
  735.     DEVMETHOD(device_probe,     psmprobe),
  736.     DEVMETHOD(device_attach,    psmattach),
  737.     DEVMETHOD(device_detach,    psmdetach),
  738.     DEVMETHOD(device_resume,    psmresume),
  739.  
  740.     { 0, 0 }
  741. };
  742.  
  743. static driver_t psm_driver = {
  744.     PSM_DRIVER_NAME,
  745.     psm_methods,
  746.     sizeof(struct psm_softc),
  747. };
  748.  
  749. static struct cdevsw psm_cdevsw = {
  750.     .d_version =    D_VERSION,
  751.     .d_flags =  D_NEEDGIANT,
  752.     .d_open =   psm_cdev_open,
  753.     .d_close =  psm_cdev_close,
  754.     .d_read =   psmread,
  755.     .d_write =  psmwrite,
  756.     .d_ioctl =  psmioctl,
  757.     .d_poll =   psmpoll,
  758.     .d_name =   PSM_DRIVER_NAME,
  759. };
  760.  
  761. #ifdef EVDEV_SUPPORT
  762. static const struct evdev_methods psm_ev_methods_r = {
  763.     .ev_open = psm_ev_open_r,
  764.     .ev_close = psm_ev_close_r,
  765. };
  766. static const struct evdev_methods psm_ev_methods_a = {
  767.     .ev_open = psm_ev_open_a,
  768.     .ev_close = psm_ev_close_a,
  769. };
  770. #endif
  771.  
  772. /* device I/O routines */
  773. static int
  774. enable_aux_dev(KBDC kbdc)
  775. {
  776.     int res;
  777.  
  778.     res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
  779.     VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res));
  780.  
  781.     return (res == PSM_ACK);
  782. }
  783.  
  784. static int
  785. disable_aux_dev(KBDC kbdc)
  786. {
  787.     int res;
  788.  
  789.     res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
  790.     VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res));
  791.  
  792.     return (res == PSM_ACK);
  793. }
  794.  
  795. static int
  796. get_mouse_status(KBDC kbdc, int *status, int flag, int len)
  797. {
  798.     int cmd;
  799.     int res;
  800.     int i;
  801.  
  802.     switch (flag) {
  803.     case 0:
  804.     default:
  805.         cmd = PSMC_SEND_DEV_STATUS;
  806.         break;
  807.     case 1:
  808.         cmd = PSMC_SEND_DEV_DATA;
  809.         break;
  810.     }
  811.     empty_aux_buffer(kbdc, 5);
  812.     res = send_aux_command(kbdc, cmd);
  813.     VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
  814.         (flag == 1) ? "DATA" : "STATUS", res));
  815.     if (res != PSM_ACK)
  816.         return (0);
  817.  
  818.     for (i = 0; i < len; ++i) {
  819.         status[i] = read_aux_data(kbdc);
  820.         if (status[i] < 0)
  821.             break;
  822.     }
  823.  
  824.     VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n",
  825.         (flag == 1) ? "data" : "status", status[0], status[1], status[2]));
  826.  
  827.     return (i);
  828. }
  829.  
  830. static int
  831. get_aux_id(KBDC kbdc)
  832. {
  833.     int res;
  834.     int id;
  835.  
  836.     empty_aux_buffer(kbdc, 5);
  837.     res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
  838.     VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res));
  839.     if (res != PSM_ACK)
  840.         return (-1);
  841.  
  842.     /* 10ms delay */
  843.     DELAY(10000);
  844.  
  845.     id = read_aux_data(kbdc);
  846.     VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id));
  847.  
  848.     return (id);
  849. }
  850.  
  851. static int
  852. set_mouse_sampling_rate(KBDC kbdc, int rate)
  853. {
  854.     int res;
  855.  
  856.     res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
  857.     VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res));
  858.  
  859.     return ((res == PSM_ACK) ? rate : -1);
  860. }
  861.  
  862. static int
  863. set_mouse_scaling(KBDC kbdc, int scale)
  864. {
  865.     int res;
  866.  
  867.     switch (scale) {
  868.     case 1:
  869.     default:
  870.         scale = PSMC_SET_SCALING11;
  871.         break;
  872.     case 2:
  873.         scale = PSMC_SET_SCALING21;
  874.         break;
  875.     }
  876.     res = send_aux_command(kbdc, scale);
  877.     VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
  878.         (scale == PSMC_SET_SCALING21) ? "21" : "11", res));
  879.  
  880.     return (res == PSM_ACK);
  881. }
  882.  
  883. /* `val' must be 0 through PSMD_MAX_RESOLUTION */
  884. static int
  885. set_mouse_resolution(KBDC kbdc, int val)
  886. {
  887.     int res;
  888.  
  889.     res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
  890.     VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res));
  891.  
  892.     return ((res == PSM_ACK) ? val : -1);
  893. }
  894.  
  895. /*
  896.  * NOTE: once `set_mouse_mode()' is called, the mouse device must be
  897.  * re-enabled by calling `enable_aux_dev()'
  898.  */
  899. static int
  900. set_mouse_mode(KBDC kbdc)
  901. {
  902.     int res;
  903.  
  904.     res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
  905.     VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res));
  906.  
  907.     return (res == PSM_ACK);
  908. }
  909.  
  910. static int
  911. get_mouse_buttons(KBDC kbdc)
  912. {
  913.     int c = 2;      /* assume two buttons by default */
  914.     int status[3];
  915.  
  916.     /*
  917.      * NOTE: a special sequence to obtain Logitech Mouse specific
  918.      * information: set resolution to 25 ppi, set scaling to 1:1, set
  919.      * scaling to 1:1, set scaling to 1:1. Then the second byte of the
  920.      * mouse status bytes is the number of available buttons.
  921.      * Some manufactures also support this sequence.
  922.      */
  923.     if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
  924.         return (c);
  925.     if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) &&
  926.         set_mouse_scaling(kbdc, 1) &&
  927.         get_mouse_status(kbdc, status, 0, 3) >= 3 && status[1] != 0)
  928.         return (status[1]);
  929.     return (c);
  930. }
  931.  
  932. /* misc subroutines */
  933. /*
  934.  * Someday, I will get the complete list of valid pointing devices and
  935.  * their IDs... XXX
  936.  */
  937. static int
  938. is_a_mouse(int id)
  939. {
  940. #if 0
  941.     static int valid_ids[] = {
  942.         PSM_MOUSE_ID,       /* mouse */
  943.         PSM_BALLPOINT_ID,   /* ballpoint device */
  944.         PSM_INTELLI_ID,     /* Intellimouse */
  945.         PSM_EXPLORER_ID,    /* Intellimouse Explorer */
  946.         -1          /* end of table */
  947.     };
  948.     int i;
  949.  
  950.     for (i = 0; valid_ids[i] >= 0; ++i)
  951.     if (valid_ids[i] == id)
  952.         return (TRUE);
  953.     return (FALSE);
  954. #else
  955.     return (TRUE);
  956. #endif
  957. }
  958.  
  959. static char *
  960. model_name(int model)
  961. {
  962.     static struct {
  963.         int model_code;
  964.         char    *model_name;
  965.     } models[] = {
  966.         { MOUSE_MODEL_NETSCROLL,    "NetScroll" },
  967.         { MOUSE_MODEL_NET,      "NetMouse/NetScroll Optical" },
  968.         { MOUSE_MODEL_GLIDEPOINT,   "GlidePoint" },
  969.         { MOUSE_MODEL_THINK,        "ThinkingMouse" },
  970.         { MOUSE_MODEL_INTELLI,      "IntelliMouse" },
  971.         { MOUSE_MODEL_MOUSEMANPLUS, "MouseMan+" },
  972.         { MOUSE_MODEL_VERSAPAD,     "VersaPad" },
  973.         { MOUSE_MODEL_EXPLORER,     "IntelliMouse Explorer" },
  974.         { MOUSE_MODEL_4D,       "4D Mouse" },
  975.         { MOUSE_MODEL_4DPLUS,       "4D+ Mouse" },
  976.         { MOUSE_MODEL_SYNAPTICS,    "Synaptics Touchpad" },
  977.         { MOUSE_MODEL_TRACKPOINT,   "IBM/Lenovo TrackPoint" },
  978.         { MOUSE_MODEL_ELANTECH,     "Elantech Touchpad" },
  979.         { MOUSE_MODEL_FOCALTECH,        "Focaltech Touchpad" },
  980.         { MOUSE_MODEL_GENERIC,      "Generic PS/2 mouse" },
  981.         { MOUSE_MODEL_UNKNOWN,      "Unknown" },
  982.     };
  983.     int i;
  984.  
  985.     for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i)
  986.         if (models[i].model_code == model)
  987.             break;
  988.     return (models[i].model_name);
  989. }
  990.  
  991. static void
  992. recover_from_error(KBDC kbdc)
  993. {
  994.     /* discard anything left in the output buffer */
  995.     empty_both_buffers(kbdc, 10);
  996.  
  997. #if 0
  998.     /*
  999.      * NOTE: KBDC_RESET_KBD may not restore the communication between the
  1000.      * keyboard and the controller.
  1001.      */
  1002.     reset_kbd(kbdc);
  1003. #else
  1004.     /*
  1005.      * NOTE: somehow diagnostic and keyboard port test commands bring the
  1006.      * keyboard back.
  1007.      */
  1008.     if (!test_controller(kbdc))
  1009.         log(LOG_ERR, "psm: keyboard controller failed.\n");
  1010.     /* if there isn't a keyboard in the system, the following error is OK */
  1011.     if (test_kbd_port(kbdc) != 0)
  1012.         VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n"));
  1013. #endif
  1014. }
  1015.  
  1016. static int
  1017. restore_controller(KBDC kbdc, int command_byte)
  1018. {
  1019.     empty_both_buffers(kbdc, 10);
  1020.  
  1021.     if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
  1022.         log(LOG_ERR, "psm: failed to restore the keyboard controller "
  1023.             "command byte.\n");
  1024.         empty_both_buffers(kbdc, 10);
  1025.         return (FALSE);
  1026.     } else {
  1027.         empty_both_buffers(kbdc, 10);
  1028.         return (TRUE);
  1029.     }
  1030. }
  1031.  
  1032. /*
  1033.  * Re-initialize the aux port and device. The aux port must be enabled
  1034.  * and its interrupt must be disabled before calling this routine.
  1035.  * The aux device will be disabled before returning.
  1036.  * The keyboard controller must be locked via `kbdc_lock()' before
  1037.  * calling this routine.
  1038.  */
  1039. static int
  1040. doinitialize(struct psm_softc *sc, mousemode_t *mode)
  1041. {
  1042.     KBDC kbdc = sc->kbdc;
  1043.     int stat[3];
  1044.     int i;
  1045.  
  1046.     switch((i = test_aux_port(kbdc))) {
  1047.     case 1: /* ignore these errors */
  1048.     case 2:
  1049.     case 3:
  1050.     case PSM_ACK:
  1051.         if (verbose)
  1052.             log(LOG_DEBUG,
  1053.                 "psm%d: strange result for test aux port (%d).\n",
  1054.                 sc->unit, i);
  1055.         /* FALLTHROUGH */
  1056.     case 0:     /* no error */
  1057.         break;
  1058.     case -1:    /* time out */
  1059.     default:    /* error */
  1060.         recover_from_error(kbdc);
  1061.         if (sc->config & PSM_CONFIG_IGNPORTERROR)
  1062.             break;
  1063.         log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
  1064.             sc->unit, i);
  1065.         return (FALSE);
  1066.     }
  1067.  
  1068.     if (sc->config & PSM_CONFIG_NORESET) {
  1069.         /*
  1070.          * Don't try to reset the pointing device.  It may possibly
  1071.          * be left in the unknown state, though...
  1072.          */
  1073.     } else {
  1074.         /*
  1075.          * NOTE: some controllers appears to hang the `keyboard' when
  1076.          * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
  1077.          */
  1078.         if (!reset_aux_dev(kbdc)) {
  1079.             recover_from_error(kbdc);
  1080.             log(LOG_ERR, "psm%d: failed to reset the aux device.\n",
  1081.                 sc->unit);
  1082.             return (FALSE);
  1083.         }
  1084.     }
  1085.  
  1086.     /*
  1087.      * both the aux port and the aux device is functioning, see
  1088.      * if the device can be enabled.
  1089.      */
  1090.     if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
  1091.         log(LOG_ERR, "psm%d: failed to enable the aux device.\n",
  1092.             sc->unit);
  1093.         return (FALSE);
  1094.     }
  1095.     empty_both_buffers(kbdc, 10);   /* remove stray data if any */
  1096.  
  1097.     /* Re-enable the mouse. */
  1098.     for (i = 0; vendortype[i].probefunc != NULL; ++i)
  1099.         if (vendortype[i].model == sc->hw.model)
  1100.             (*vendortype[i].probefunc)(sc, REINIT);
  1101.  
  1102.     /* set mouse parameters */
  1103.     if (mode != (mousemode_t *)NULL) {
  1104.         if (mode->rate > 0)
  1105.             mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
  1106.         if (mode->resolution >= 0)
  1107.             mode->resolution =
  1108.                 set_mouse_resolution(kbdc, mode->resolution);
  1109.         set_mouse_scaling(kbdc, 1);
  1110.         set_mouse_mode(kbdc);
  1111.     }
  1112.  
  1113.     /* Record sync on the next data packet we see. */
  1114.     sc->flags |= PSM_NEED_SYNCBITS;
  1115.  
  1116.     /* just check the status of the mouse */
  1117.     if (get_mouse_status(kbdc, stat, 0, 3) < 3)
  1118.         log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n",
  1119.             sc->unit);
  1120.  
  1121.     return (TRUE);
  1122. }
  1123.  
  1124. static int
  1125. doopen(struct psm_softc *sc, int command_byte)
  1126. {
  1127.     int stat[3];
  1128.  
  1129.     /*
  1130.      * FIXME: Synaptics TouchPad seems to go back to Relative Mode with
  1131.      * no obvious reason. Thus we check the current mode and restore the
  1132.      * Absolute Mode if it was cleared.
  1133.      *
  1134.      * The previous hack at the end of psmprobe() wasn't efficient when
  1135.      * moused(8) was restarted.
  1136.      *
  1137.      * A Reset (FF) or Set Defaults (F6) command would clear the
  1138.      * Absolute Mode bit. But a verbose boot or debug.psm.loglevel=5
  1139.      * doesn't show any evidence of such a command.
  1140.      */
  1141.     if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
  1142.         mouse_ext_command(sc->kbdc, 1);
  1143.         get_mouse_status(sc->kbdc, stat, 0, 3);
  1144.         if ((SYNAPTICS_VERSION_GE(sc->synhw, 7, 5) ||
  1145.              stat[1] == 0x46 || stat[1] == 0x47) &&
  1146.              stat[2] == 0x40) {
  1147.             synaptics_set_mode(sc, synaptics_preferred_mode(sc));
  1148.             VLOG(5, (LOG_DEBUG, "psm%d: Synaptis Absolute Mode "
  1149.                 "hopefully restored\n",
  1150.                 sc->unit));
  1151.         }
  1152.     }
  1153.  
  1154.     /*
  1155.      * A user may want to disable tap and drag gestures on a Synaptics
  1156.      * TouchPad when it operates in Relative Mode.
  1157.      */
  1158.     if (sc->hw.model == MOUSE_MODEL_GENERIC) {
  1159.         if (tap_enabled > 0) {
  1160.             VLOG(2, (LOG_DEBUG,
  1161.                 "psm%d: enable tap and drag gestures\n",
  1162.                 sc->unit));
  1163.             synaptics_set_mode(sc, synaptics_preferred_mode(sc));
  1164.         } else if (tap_enabled == 0) {
  1165.             VLOG(2, (LOG_DEBUG,
  1166.                 "psm%d: disable tap and drag gestures\n",
  1167.                 sc->unit));
  1168.             synaptics_set_mode(sc, synaptics_preferred_mode(sc));
  1169.         }
  1170.     }
  1171.  
  1172.     /* enable the mouse device */
  1173.     if (!enable_aux_dev(sc->kbdc)) {
  1174.         /* MOUSE ERROR: failed to enable the mouse because:
  1175.          * 1) the mouse is faulty,
  1176.          * 2) the mouse has been removed(!?)
  1177.          * In the latter case, the keyboard may have hung, and need
  1178.          * recovery procedure...
  1179.          */
  1180.         recover_from_error(sc->kbdc);
  1181. #if 0
  1182.         /* FIXME: we could reset the mouse here and try to enable
  1183.          * it again. But it will take long time and it's not a good
  1184.          * idea to disable the keyboard that long...
  1185.          */
  1186.         if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
  1187.             recover_from_error(sc->kbdc);
  1188. #else
  1189.         {
  1190. #endif
  1191.             restore_controller(sc->kbdc, command_byte);
  1192.             /* mark this device is no longer available */
  1193.             sc->state &= ~PSM_VALID;
  1194.             log(LOG_ERR,
  1195.                 "psm%d: failed to enable the device (doopen).\n",
  1196.             sc->unit);
  1197.             return (EIO);
  1198.         }
  1199.     }
  1200.  
  1201.     if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
  1202.         log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n",
  1203.             sc->unit);
  1204.  
  1205.     /* enable the aux port and interrupt */
  1206.     if (!set_controller_command_byte(sc->kbdc,
  1207.         kbdc_get_device_mask(sc->kbdc),
  1208.         (command_byte & KBD_KBD_CONTROL_BITS) |
  1209.         KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
  1210.         /* CONTROLLER ERROR */
  1211.         disable_aux_dev(sc->kbdc);
  1212.         restore_controller(sc->kbdc, command_byte);
  1213.         log(LOG_ERR,
  1214.             "psm%d: failed to enable the aux interrupt (doopen).\n",
  1215.             sc->unit);
  1216.         return (EIO);
  1217.     }
  1218.  
  1219.     /* start the watchdog timer */
  1220.     sc->watchdog = FALSE;
  1221.     callout_reset(&sc->callout, hz * 2, psmtimeout, sc);
  1222.  
  1223.     return (0);
  1224. }
  1225.  
  1226. static int
  1227. reinitialize(struct psm_softc *sc, int doinit)
  1228. {
  1229.     int err;
  1230.     int c;
  1231.     int s;
  1232.  
  1233.     /* don't let anybody mess with the aux device */
  1234.     if (!kbdc_lock(sc->kbdc, TRUE))
  1235.         return (EIO);
  1236.     s = spltty();
  1237.  
  1238.     /* block our watchdog timer */
  1239.     sc->watchdog = FALSE;
  1240.     callout_stop(&sc->callout);
  1241.  
  1242.     /* save the current controller command byte */
  1243.     empty_both_buffers(sc->kbdc, 10);
  1244.     c = get_controller_command_byte(sc->kbdc);
  1245.     VLOG(2, (LOG_DEBUG,
  1246.         "psm%d: current command byte: %04x (reinitialize).\n",
  1247.         sc->unit, c));
  1248.  
  1249.     /* enable the aux port but disable the aux interrupt and the keyboard */
  1250.     if ((c == -1) || !set_controller_command_byte(sc->kbdc,
  1251.         kbdc_get_device_mask(sc->kbdc),
  1252.         KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
  1253.         KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  1254.         /* CONTROLLER ERROR */
  1255.         splx(s);
  1256.         kbdc_lock(sc->kbdc, FALSE);
  1257.         log(LOG_ERR,
  1258.             "psm%d: unable to set the command byte (reinitialize).\n",
  1259.             sc->unit);
  1260.         return (EIO);
  1261.     }
  1262.  
  1263.     /* flush any data */
  1264.     if (sc->state & PSM_VALID) {
  1265.         /* this may fail; but never mind... */
  1266.         disable_aux_dev(sc->kbdc);
  1267.         empty_aux_buffer(sc->kbdc, 10);
  1268.     }
  1269.     flushpackets(sc);
  1270.     sc->syncerrors = 0;
  1271.     sc->pkterrors = 0;
  1272.     memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr));
  1273.  
  1274.     /* try to detect the aux device; are you still there? */
  1275.     err = 0;
  1276.     if (doinit) {
  1277.         if (doinitialize(sc, &sc->mode)) {
  1278.             /* yes */
  1279.             sc->state |= PSM_VALID;
  1280.         } else {
  1281.             /* the device has gone! */
  1282.             restore_controller(sc->kbdc, c);
  1283.             sc->state &= ~PSM_VALID;
  1284.             log(LOG_ERR,
  1285.                 "psm%d: the aux device has gone! (reinitialize).\n",
  1286.                 sc->unit);
  1287.             err = ENXIO;
  1288.         }
  1289.     }
  1290.     splx(s);
  1291.  
  1292.     /* restore the driver state */
  1293.     if ((sc->state & (PSM_OPEN | PSM_EV_OPEN_R | PSM_EV_OPEN_A)) &&
  1294.         (err == 0)) {
  1295.         /* enable the aux device and the port again */
  1296.         err = doopen(sc, c);
  1297.         if (err != 0)
  1298.             log(LOG_ERR, "psm%d: failed to enable the device "
  1299.                 "(reinitialize).\n", sc->unit);
  1300.     } else {
  1301.         /* restore the keyboard port and disable the aux port */
  1302.         if (!set_controller_command_byte(sc->kbdc,
  1303.             kbdc_get_device_mask(sc->kbdc),
  1304.             (c & KBD_KBD_CONTROL_BITS) |
  1305.             KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  1306.             /* CONTROLLER ERROR */
  1307.             log(LOG_ERR, "psm%d: failed to disable the aux port "
  1308.                 "(reinitialize).\n", sc->unit);
  1309.             err = EIO;
  1310.         }
  1311.     }
  1312.  
  1313.     kbdc_lock(sc->kbdc, FALSE);
  1314.     return (err);
  1315. }
  1316.  
  1317. /* psm driver entry points */
  1318.  
  1319. static void
  1320. psmidentify(driver_t *driver, device_t parent)
  1321. {
  1322.     device_t psmc;
  1323.     device_t psm;
  1324.     u_long irq;
  1325.     int unit;
  1326.  
  1327.     unit = device_get_unit(parent);
  1328.  
  1329.     /* always add at least one child */
  1330.     psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit);
  1331.     if (psm == NULL)
  1332.         return;
  1333.  
  1334.     irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX);
  1335.     if (irq > 0)
  1336.         return;
  1337.  
  1338.     /*
  1339.      * If the PS/2 mouse device has already been reported by ACPI or
  1340.      * PnP BIOS, obtain the IRQ resource from it.
  1341.      * (See psmcpnp_attach() below.)
  1342.      */
  1343.     psmc = device_find_child(device_get_parent(parent),
  1344.         PSMCPNP_DRIVER_NAME, unit);
  1345.     if (psmc == NULL)
  1346.         return;
  1347.     irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0);
  1348.     if (irq <= 0)
  1349.         return;
  1350.     bus_delete_resource(psmc, SYS_RES_IRQ, 0);
  1351.     bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
  1352. }
  1353.  
  1354. #define endprobe(v) do {            \
  1355.     if (bootverbose)            \
  1356.         --verbose;          \
  1357.     kbdc_set_device_mask(sc->kbdc, mask);   \
  1358.     kbdc_lock(sc->kbdc, FALSE);     \
  1359.     return (v);             \
  1360. } while (0)
  1361.  
  1362. static int
  1363. psmprobe(device_t dev)
  1364. {
  1365.     int unit = device_get_unit(dev);
  1366.     struct psm_softc *sc = device_get_softc(dev);
  1367.     int stat[3];
  1368.     int command_byte;
  1369.     int mask;
  1370.     int rid;
  1371.     int i;
  1372.  
  1373. #if 0
  1374.     kbdc_debug(TRUE);
  1375. #endif
  1376.  
  1377.     /* see if IRQ is available */
  1378.     rid = KBDC_RID_AUX;
  1379.     sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
  1380.     if (sc->intr == NULL) {
  1381.         if (bootverbose)
  1382.             device_printf(dev, "unable to allocate IRQ\n");
  1383.         return (ENXIO);
  1384.     }
  1385.     bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
  1386.  
  1387.     sc->unit = unit;
  1388.     sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
  1389.     sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS;
  1390.     /* XXX: for backward compatibility */
  1391. #if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM)
  1392.     sc->config |=
  1393. #ifdef PSM_RESETAFTERSUSPEND
  1394.     PSM_CONFIG_INITAFTERSUSPEND;
  1395. #else
  1396.     PSM_CONFIG_HOOKRESUME;
  1397. #endif
  1398. #endif /* PSM_HOOKRESUME | PSM_HOOKAPM */
  1399.     sc->flags = 0;
  1400.     if (bootverbose)
  1401.         ++verbose;
  1402.  
  1403.     device_set_desc(dev, "PS/2 Mouse");
  1404.  
  1405.     if (!kbdc_lock(sc->kbdc, TRUE)) {
  1406.         printf("psm%d: unable to lock the controller.\n", unit);
  1407.         if (bootverbose)
  1408.             --verbose;
  1409.         return (ENXIO);
  1410.     }
  1411.  
  1412.     /*
  1413.      * NOTE: two bits in the command byte controls the operation of the
  1414.      * aux port (mouse port): the aux port disable bit (bit 5) and the aux
  1415.      * port interrupt (IRQ 12) enable bit (bit 2).
  1416.      */
  1417.  
  1418.     /* discard anything left after the keyboard initialization */
  1419.     empty_both_buffers(sc->kbdc, 10);
  1420.  
  1421.     /* save the current command byte; it will be used later */
  1422.     mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
  1423.     command_byte = get_controller_command_byte(sc->kbdc);
  1424.     if (verbose)
  1425.         printf("psm%d: current command byte:%04x\n", unit,
  1426.             command_byte);
  1427.     if (command_byte == -1) {
  1428.         /* CONTROLLER ERROR */
  1429.         printf("psm%d: unable to get the current command byte value.\n",
  1430.             unit);
  1431.         endprobe(ENXIO);
  1432.     }
  1433.  
  1434.     /*
  1435.      * disable the keyboard port while probing the aux port, which must be
  1436.      * enabled during this routine
  1437.      */
  1438.     if (!set_controller_command_byte(sc->kbdc,
  1439.         KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
  1440.         KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
  1441.         KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  1442.         /*
  1443.          * this is CONTROLLER ERROR; I don't know how to recover
  1444.          * from this error...
  1445.          */
  1446.         if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
  1447.             restore_controller(sc->kbdc, command_byte);
  1448.         printf("psm%d: unable to set the command byte.\n", unit);
  1449.         endprobe(ENXIO);
  1450.     }
  1451.     write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
  1452.  
  1453.     /*
  1454.      * NOTE: `test_aux_port()' is designed to return with zero if the aux
  1455.      * port exists and is functioning. However, some controllers appears
  1456.      * to respond with zero even when the aux port doesn't exist. (It may
  1457.      * be that this is only the case when the controller DOES have the aux
  1458.      * port but the port is not wired on the motherboard.) The keyboard
  1459.      * controllers without the port, such as the original AT, are
  1460.      * supposed to return with an error code or simply time out. In any
  1461.      * case, we have to continue probing the port even when the controller
  1462.      * passes this test.
  1463.      *
  1464.      * XXX: some controllers erroneously return the error code 1, 2 or 3
  1465.      * when it has a perfectly functional aux port. We have to ignore
  1466.      * this error code. Even if the controller HAS error with the aux
  1467.      * port, it will be detected later...
  1468.      * XXX: another incompatible controller returns PSM_ACK (0xfa)...
  1469.      */
  1470.     switch ((i = test_aux_port(sc->kbdc))) {
  1471.     case 1:     /* ignore these errors */
  1472.     case 2:
  1473.     case 3:
  1474.     case PSM_ACK:
  1475.         if (verbose)
  1476.             printf("psm%d: strange result for test aux port "
  1477.                 "(%d).\n", unit, i);
  1478.         /* FALLTHROUGH */
  1479.     case 0:     /* no error */
  1480.         break;
  1481.     case -1:    /* time out */
  1482.     default:    /* error */
  1483.         recover_from_error(sc->kbdc);
  1484.         if (sc->config & PSM_CONFIG_IGNPORTERROR)
  1485.             break;
  1486.         if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
  1487.             restore_controller(sc->kbdc, command_byte);
  1488.         if (verbose)
  1489.             printf("psm%d: the aux port is not functioning (%d).\n",
  1490.                 unit, i);
  1491.         endprobe(ENXIO);
  1492.     }
  1493.  
  1494.     if (sc->config & PSM_CONFIG_NORESET) {
  1495.         /*
  1496.          * Don't try to reset the pointing device.  It may possibly be
  1497.          * left in an unknown state, though...
  1498.          */
  1499.     } else {
  1500.         /*
  1501.          * NOTE: some controllers appears to hang the `keyboard' when
  1502.          * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
  1503.          *
  1504.          * Attempt to reset the controller twice -- this helps
  1505.          * pierce through some KVM switches. The second reset
  1506.          * is non-fatal.
  1507.          */
  1508.         if (!reset_aux_dev(sc->kbdc)) {
  1509.             recover_from_error(sc->kbdc);
  1510.             if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
  1511.                 restore_controller(sc->kbdc, command_byte);
  1512.             if (verbose)
  1513.                 printf("psm%d: failed to reset the aux "
  1514.                     "device.\n", unit);
  1515.             endprobe(ENXIO);
  1516.         } else if (!reset_aux_dev(sc->kbdc)) {
  1517.             recover_from_error(sc->kbdc);
  1518.             if (verbose >= 2)
  1519.                 printf("psm%d: failed to reset the aux device "
  1520.                     "(2).\n", unit);
  1521.         }
  1522.     }
  1523.  
  1524.     /*
  1525.      * both the aux port and the aux device are functioning, see if the
  1526.      * device can be enabled. NOTE: when enabled, the device will start
  1527.      * sending data; we shall immediately disable the device once we know
  1528.      * the device can be enabled.
  1529.      */
  1530.     if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
  1531.         /* MOUSE ERROR */
  1532.         recover_from_error(sc->kbdc);
  1533.         if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
  1534.             restore_controller(sc->kbdc, command_byte);
  1535.         if (verbose)
  1536.             printf("psm%d: failed to enable the aux device.\n",
  1537.                 unit);
  1538.         endprobe(ENXIO);
  1539.     }
  1540.  
  1541.     /* save the default values after reset */
  1542.     if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
  1543.         sc->dflt_mode.rate = sc->mode.rate = stat[2];
  1544.         sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
  1545.     } else {
  1546.         sc->dflt_mode.rate = sc->mode.rate = -1;
  1547.         sc->dflt_mode.resolution = sc->mode.resolution = -1;
  1548.     }
  1549.  
  1550.     /* hardware information */
  1551.     sc->hw.iftype = MOUSE_IF_PS2;
  1552.  
  1553.     /* verify the device is a mouse */
  1554.     sc->hw.hwid = get_aux_id(sc->kbdc);
  1555.     if (!is_a_mouse(sc->hw.hwid)) {
  1556.         if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
  1557.             restore_controller(sc->kbdc, command_byte);
  1558.         if (verbose)
  1559.             printf("psm%d: unknown device type (%d).\n", unit,
  1560.                 sc->hw.hwid);
  1561.         endprobe(ENXIO);
  1562.     }
  1563.     switch (sc->hw.hwid) {
  1564.     case PSM_BALLPOINT_ID:
  1565.         sc->hw.type = MOUSE_TRACKBALL;
  1566.         break;
  1567.     case PSM_MOUSE_ID:
  1568.     case PSM_INTELLI_ID:
  1569.     case PSM_EXPLORER_ID:
  1570.     case PSM_4DMOUSE_ID:
  1571.     case PSM_4DPLUS_ID:
  1572.         sc->hw.type = MOUSE_MOUSE;
  1573.         break;
  1574.     default:
  1575.         sc->hw.type = MOUSE_UNKNOWN;
  1576.         break;
  1577.     }
  1578.  
  1579.     if (sc->config & PSM_CONFIG_NOIDPROBE) {
  1580.         sc->hw.buttons = 2;
  1581.         i = GENERIC_MOUSE_ENTRY;
  1582.     } else {
  1583.         /* # of buttons */
  1584.         sc->hw.buttons = get_mouse_buttons(sc->kbdc);
  1585.  
  1586.         /* other parameters */
  1587.         for (i = 0; vendortype[i].probefunc != NULL; ++i)
  1588.             if ((*vendortype[i].probefunc)(sc, PROBE)) {
  1589.                 if (verbose >= 2)
  1590.                     printf("psm%d: found %s\n", unit,
  1591.                         model_name(vendortype[i].model));
  1592.                 break;
  1593.             }
  1594.     }
  1595.  
  1596.     sc->hw.model = vendortype[i].model;
  1597.  
  1598.     sc->dflt_mode.level = PSM_LEVEL_BASE;
  1599.     sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
  1600.     sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
  1601.     if (sc->config & PSM_CONFIG_NOCHECKSYNC)
  1602.         sc->dflt_mode.syncmask[0] = 0;
  1603.     else
  1604.         sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
  1605.     if (sc->config & PSM_CONFIG_FORCETAP)
  1606.         sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP;
  1607.     sc->dflt_mode.syncmask[1] = 0;  /* syncbits */
  1608.     sc->mode = sc->dflt_mode;
  1609.     sc->mode.packetsize = vendortype[i].packetsize;
  1610.  
  1611.     /* set mouse parameters */
  1612. #if 0
  1613.     /*
  1614.      * A version of Logitech FirstMouse+ won't report wheel movement,
  1615.      * if SET_DEFAULTS is sent...  Don't use this command.
  1616.      * This fix was found by Takashi Nishida.
  1617.      */
  1618.     i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
  1619.     if (verbose >= 2)
  1620.         printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
  1621. #endif
  1622.     if (sc->config & PSM_CONFIG_RESOLUTION)
  1623.         sc->mode.resolution =
  1624.             set_mouse_resolution(sc->kbdc,
  1625.             (sc->config & PSM_CONFIG_RESOLUTION) - 1);
  1626.     else if (sc->mode.resolution >= 0)
  1627.         sc->mode.resolution =
  1628.             set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
  1629.     if (sc->mode.rate > 0)
  1630.         sc->mode.rate =
  1631.             set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
  1632.     set_mouse_scaling(sc->kbdc, 1);
  1633.  
  1634.     /* Record sync on the next data packet we see. */
  1635.     sc->flags |= PSM_NEED_SYNCBITS;
  1636.  
  1637.     /* just check the status of the mouse */
  1638.     /*
  1639.      * NOTE: XXX there are some arcane controller/mouse combinations out
  1640.      * there, which hung the controller unless there is data transmission
  1641.      * after ACK from the mouse.
  1642.      */
  1643.     if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
  1644.         printf("psm%d: failed to get status.\n", unit);
  1645.     else {
  1646.         /*
  1647.          * When in its native mode, some mice operate with different
  1648.          * default parameters than in the PS/2 compatible mode.
  1649.          */
  1650.         sc->dflt_mode.rate = sc->mode.rate = stat[2];
  1651.         sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
  1652.     }
  1653.  
  1654.     /* disable the aux port for now... */
  1655.     if (!set_controller_command_byte(sc->kbdc,
  1656.         KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
  1657.         (command_byte & KBD_KBD_CONTROL_BITS) |
  1658.         KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  1659.         /*
  1660.          * this is CONTROLLER ERROR; I don't know the proper way to
  1661.          * recover from this error...
  1662.          */
  1663.         if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
  1664.             restore_controller(sc->kbdc, command_byte);
  1665.         printf("psm%d: unable to set the command byte.\n", unit);
  1666.         endprobe(ENXIO);
  1667.     }
  1668.  
  1669.     /* done */
  1670.     kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
  1671.     kbdc_lock(sc->kbdc, FALSE);
  1672.     return (0);
  1673. }
  1674.  
  1675. #ifdef EVDEV_SUPPORT
  1676. /* Values are taken from Linux drivers for userland software compatibility */
  1677. #define PS2_MOUSE_VENDOR        0x0002
  1678. #define PS2_MOUSE_GENERIC_PRODUCT   0x0001
  1679. #define PS2_MOUSE_SYNAPTICS_NAME    "SynPS/2 Synaptics TouchPad"
  1680. #define PS2_MOUSE_SYNAPTICS_PRODUCT 0x0007
  1681. #define PS2_MOUSE_TRACKPOINT_NAME   "TPPS/2 IBM TrackPoint"
  1682. #define PS2_MOUSE_TRACKPOINT_PRODUCT    0x000A
  1683. #define PS2_MOUSE_ELANTECH_NAME     "ETPS/2 Elantech Touchpad"
  1684. #define PS2_MOUSE_ELANTECH_ST_NAME  "ETPS/2 Elantech TrackPoint"
  1685. #define PS2_MOUSE_ELANTECH_PRODUCT  0x000E
  1686. #define PS2_MOUSE_FOCALTECH_NAME        "FocalTechPS/2 Focaltech Touchpad"
  1687. #define PS2_MOUSE_FOCALTECH_PRODUCT     0x0012
  1688.  
  1689.  
  1690. #define ABSINFO_END { ABS_CNT, 0, 0, 0 }
  1691.  
  1692. static void
  1693. psm_support_abs_bulk(struct evdev_dev *evdev, const uint16_t info[][4])
  1694. {
  1695.     size_t i;
  1696.  
  1697.     for (i = 0; info[i][0] != ABS_CNT; i++)
  1698.         evdev_support_abs(evdev, info[i][0], 0, info[i][1], info[i][2],
  1699.             0, 0, info[i][3]);
  1700. }
  1701.  
  1702. static void
  1703. psm_push_mt_finger(struct psm_softc *sc, int id, const finger_t *f)
  1704. {
  1705.     int y = sc->synhw.minimumYCoord + sc->synhw.maximumYCoord - f->y;
  1706.  
  1707.     evdev_push_abs(sc->evdev_a, ABS_MT_SLOT, id);
  1708.     evdev_push_abs(sc->evdev_a, ABS_MT_TRACKING_ID, id);
  1709.     evdev_push_abs(sc->evdev_a, ABS_MT_POSITION_X, f->x);
  1710.     evdev_push_abs(sc->evdev_a, ABS_MT_POSITION_Y, y);
  1711.     evdev_push_abs(sc->evdev_a, ABS_MT_PRESSURE, f->p);
  1712. }
  1713.  
  1714. static void
  1715. psm_push_st_finger(struct psm_softc *sc, const finger_t *f)
  1716. {
  1717.     int y = sc->synhw.minimumYCoord + sc->synhw.maximumYCoord - f->y;
  1718.  
  1719.     evdev_push_abs(sc->evdev_a, ABS_X, f->x);
  1720.     evdev_push_abs(sc->evdev_a, ABS_Y, y);
  1721.     evdev_push_abs(sc->evdev_a, ABS_PRESSURE, f->p);
  1722.     if (sc->synhw.capPalmDetect)
  1723.         evdev_push_abs(sc->evdev_a, ABS_TOOL_WIDTH, f->w);
  1724. }
  1725.  
  1726. static void
  1727. psm_release_mt_slot(struct evdev_dev *evdev, int32_t slot)
  1728. {
  1729.  
  1730.     evdev_push_abs(evdev, ABS_MT_SLOT, slot);
  1731.     evdev_push_abs(evdev, ABS_MT_TRACKING_ID, -1);
  1732. }
  1733.  
  1734. static int
  1735. psm_register(device_t dev, int model_code)
  1736. {
  1737.     struct psm_softc *sc = device_get_softc(dev);
  1738.     struct evdev_dev *evdev_r;
  1739.     int error, i, nbuttons, nwheels, product;
  1740.     bool is_pointing_stick;
  1741.     const char *name;
  1742.  
  1743.     name = model_name(model_code);
  1744.     nbuttons = sc->hw.buttons;
  1745.     product = PS2_MOUSE_GENERIC_PRODUCT;
  1746.     nwheels = 0;
  1747.     is_pointing_stick = false;
  1748.  
  1749.     switch (model_code) {
  1750.     case MOUSE_MODEL_TRACKPOINT:
  1751.         name = PS2_MOUSE_TRACKPOINT_NAME;
  1752.         product = PS2_MOUSE_TRACKPOINT_PRODUCT;
  1753.         nbuttons = 3;
  1754.         is_pointing_stick = true;
  1755.         break;
  1756.  
  1757.     case MOUSE_MODEL_ELANTECH:
  1758.         name = PS2_MOUSE_ELANTECH_ST_NAME;
  1759.         product = PS2_MOUSE_ELANTECH_PRODUCT;
  1760.         nbuttons = 3;
  1761.         is_pointing_stick = true;
  1762.         break;
  1763.  
  1764.     case MOUSE_MODEL_MOUSEMANPLUS:
  1765.     case MOUSE_MODEL_4D:
  1766.         nwheels = 2;
  1767.         break;
  1768.  
  1769.     case MOUSE_MODEL_EXPLORER:
  1770.     case MOUSE_MODEL_INTELLI:
  1771.     case MOUSE_MODEL_NET:
  1772.     case MOUSE_MODEL_NETSCROLL:
  1773.     case MOUSE_MODEL_4DPLUS:
  1774.         nwheels = 1;
  1775.         break;
  1776.     }
  1777.  
  1778.     evdev_r = evdev_alloc();
  1779.     evdev_set_name(evdev_r, name);
  1780.     evdev_set_phys(evdev_r, device_get_nameunit(dev));
  1781.     evdev_set_id(evdev_r, BUS_I8042, PS2_MOUSE_VENDOR, product, 0);
  1782.     evdev_set_methods(evdev_r, sc, &psm_ev_methods_r);
  1783.  
  1784.     evdev_support_prop(evdev_r, INPUT_PROP_POINTER);
  1785.     if (is_pointing_stick)
  1786.         evdev_support_prop(evdev_r, INPUT_PROP_POINTING_STICK);
  1787.     evdev_support_event(evdev_r, EV_SYN);
  1788.     evdev_support_event(evdev_r, EV_KEY);
  1789.     evdev_support_event(evdev_r, EV_REL);
  1790.     evdev_support_rel(evdev_r, REL_X);
  1791.     evdev_support_rel(evdev_r, REL_Y);
  1792.     switch (nwheels) {
  1793.     case 2:
  1794.         evdev_support_rel(evdev_r, REL_HWHEEL);
  1795.         /* FALLTHROUGH */
  1796.     case 1:
  1797.         evdev_support_rel(evdev_r, REL_WHEEL);
  1798.     }
  1799.     for (i = 0; i < nbuttons; i++)
  1800.         evdev_support_key(evdev_r, BTN_MOUSE + i);
  1801.  
  1802.     error = evdev_register_mtx(evdev_r, &Giant);
  1803.     if (error)
  1804.         evdev_free(evdev_r);
  1805.     else
  1806.         sc->evdev_r = evdev_r;
  1807.     return (error);
  1808. }
  1809.  
  1810. static int
  1811. psm_register_synaptics(device_t dev)
  1812. {
  1813.     struct psm_softc *sc = device_get_softc(dev);
  1814.     const uint16_t synaptics_absinfo_st[][4] = {
  1815.         { ABS_X,        sc->synhw.minimumXCoord,
  1816.             sc->synhw.maximumXCoord, sc->synhw.infoXupmm },
  1817.         { ABS_Y,        sc->synhw.minimumYCoord,
  1818.             sc->synhw.maximumYCoord, sc->synhw.infoYupmm },
  1819.         { ABS_PRESSURE,     0, ELANTECH_FINGER_MAX_P, 0 },
  1820.         ABSINFO_END,
  1821.     };
  1822.     const uint16_t synaptics_absinfo_mt[][4] = {
  1823.         { ABS_MT_SLOT,      0, PSM_FINGERS-1, 0},
  1824.         { ABS_MT_TRACKING_ID,   -1, PSM_FINGERS-1, 0},
  1825.         { ABS_MT_POSITION_X,    sc->synhw.minimumXCoord,
  1826.             sc->synhw.maximumXCoord, sc->synhw.infoXupmm },
  1827.         { ABS_MT_POSITION_Y,    sc->synhw.minimumYCoord,
  1828.             sc->synhw.maximumYCoord, sc->synhw.infoYupmm },
  1829.         { ABS_MT_PRESSURE,  0, ELANTECH_FINGER_MAX_P, 0 },
  1830.         ABSINFO_END,
  1831.     };
  1832.     struct evdev_dev *evdev_a;
  1833.     int error, i, guest_model;
  1834.  
  1835.     evdev_a = evdev_alloc();
  1836.     evdev_set_name(evdev_a, PS2_MOUSE_SYNAPTICS_NAME);
  1837.     evdev_set_phys(evdev_a, device_get_nameunit(dev));
  1838.     evdev_set_id(evdev_a, BUS_I8042, PS2_MOUSE_VENDOR,
  1839.         PS2_MOUSE_SYNAPTICS_PRODUCT, 0);
  1840.     evdev_set_methods(evdev_a, sc, &psm_ev_methods_a);
  1841.  
  1842.     evdev_support_event(evdev_a, EV_SYN);
  1843.     evdev_support_event(evdev_a, EV_KEY);
  1844.     evdev_support_event(evdev_a, EV_ABS);
  1845.     evdev_support_prop(evdev_a, INPUT_PROP_POINTER);
  1846.     if (sc->synhw.capAdvancedGestures)
  1847.         evdev_support_prop(evdev_a, INPUT_PROP_SEMI_MT);
  1848.     if (sc->synhw.capClickPad)
  1849.         evdev_support_prop(evdev_a, INPUT_PROP_BUTTONPAD);
  1850.     evdev_support_key(evdev_a, BTN_TOUCH);
  1851.     evdev_support_nfingers(evdev_a, 3);
  1852.     psm_support_abs_bulk(evdev_a, synaptics_absinfo_st);
  1853.     if (sc->synhw.capAdvancedGestures || sc->synhw.capReportsV)
  1854.         psm_support_abs_bulk(evdev_a, synaptics_absinfo_mt);
  1855.     if (sc->synhw.capPalmDetect)
  1856.         evdev_support_abs(evdev_a, ABS_TOOL_WIDTH, 0, 0, 15, 0, 0, 0);
  1857.     evdev_support_key(evdev_a, BTN_LEFT);
  1858.     if (!sc->synhw.capClickPad) {
  1859.         evdev_support_key(evdev_a, BTN_RIGHT);
  1860.         if (sc->synhw.capExtended && sc->synhw.capMiddle)
  1861.             evdev_support_key(evdev_a, BTN_MIDDLE);
  1862.     }
  1863.     if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
  1864.         evdev_support_key(evdev_a, BTN_BACK);
  1865.         evdev_support_key(evdev_a, BTN_FORWARD);
  1866.     }
  1867.     if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0))
  1868.         for (i = 0; i < sc->synhw.nExtendedButtons; i++)
  1869.             evdev_support_key(evdev_a, BTN_0 + i);
  1870.  
  1871.     error = evdev_register_mtx(evdev_a, &Giant);
  1872.     if (!error && sc->synhw.capPassthrough) {
  1873.         guest_model = sc->tpinfo.sysctl_tree != NULL ?
  1874.             MOUSE_MODEL_TRACKPOINT : MOUSE_MODEL_GENERIC;
  1875.         error = psm_register(dev, guest_model);
  1876.     }
  1877.     if (error)
  1878.         evdev_free(evdev_a);
  1879.     else
  1880.         sc->evdev_a = evdev_a;
  1881.     return (error);
  1882. }
  1883.  
  1884. static int
  1885. psm_register_elantech(device_t dev)
  1886. {
  1887.     struct psm_softc *sc = device_get_softc(dev);
  1888.     const uint16_t elantech_absinfo[][4] = {
  1889.         { ABS_X,        0, sc->elanhw.sizex,
  1890.                        sc->elanhw.dpmmx },
  1891.         { ABS_Y,        0, sc->elanhw.sizey,
  1892.                        sc->elanhw.dpmmy },
  1893.         { ABS_PRESSURE,     0, ELANTECH_FINGER_MAX_P, 0 },
  1894.         { ABS_TOOL_WIDTH,   0, ELANTECH_FINGER_MAX_W, 0 },
  1895.         { ABS_MT_SLOT,      0, ELANTECH_MAX_FINGERS - 1, 0 },
  1896.         { ABS_MT_TRACKING_ID,   -1, ELANTECH_MAX_FINGERS - 1, 0 },
  1897.         { ABS_MT_POSITION_X,    0, sc->elanhw.sizex,
  1898.                        sc->elanhw.dpmmx },
  1899.         { ABS_MT_POSITION_Y,    0, sc->elanhw.sizey,
  1900.                        sc->elanhw.dpmmy },
  1901.         { ABS_MT_PRESSURE,  0, ELANTECH_FINGER_MAX_P, 0 },
  1902.         { ABS_MT_TOUCH_MAJOR,   0, ELANTECH_FINGER_MAX_W *
  1903.                        sc->elanhw.dptracex, 0 },
  1904.         ABSINFO_END,
  1905.     };
  1906.     struct evdev_dev *evdev_a;
  1907.     int error;
  1908.  
  1909.     evdev_a = evdev_alloc();
  1910.     evdev_set_name(evdev_a, PS2_MOUSE_ELANTECH_NAME);
  1911.     evdev_set_phys(evdev_a, device_get_nameunit(dev));
  1912.     evdev_set_id(evdev_a, BUS_I8042, PS2_MOUSE_VENDOR,
  1913.         PS2_MOUSE_ELANTECH_PRODUCT, 0);
  1914.     evdev_set_methods(evdev_a, sc, &psm_ev_methods_a);
  1915.  
  1916.     evdev_support_event(evdev_a, EV_SYN);
  1917.     evdev_support_event(evdev_a, EV_KEY);
  1918.     evdev_support_event(evdev_a, EV_ABS);
  1919.     evdev_support_prop(evdev_a, INPUT_PROP_POINTER);
  1920.     if (sc->elanhw.issemimt)
  1921.         evdev_support_prop(evdev_a, INPUT_PROP_SEMI_MT);
  1922.     if (sc->elanhw.isclickpad)
  1923.         evdev_support_prop(evdev_a, INPUT_PROP_BUTTONPAD);
  1924.     evdev_support_key(evdev_a, BTN_TOUCH);
  1925.     evdev_support_nfingers(evdev_a, ELANTECH_MAX_FINGERS);
  1926.     evdev_support_key(evdev_a, BTN_LEFT);
  1927.     if (!sc->elanhw.isclickpad)
  1928.         evdev_support_key(evdev_a, BTN_RIGHT);
  1929.     psm_support_abs_bulk(evdev_a, elantech_absinfo);
  1930.  
  1931.     error = evdev_register_mtx(evdev_a, &Giant);
  1932.     if (!error && sc->elanhw.hastrackpoint)
  1933.         error = psm_register(dev, MOUSE_MODEL_ELANTECH);
  1934.     if (error)
  1935.         evdev_free(evdev_a);
  1936.     else
  1937.         sc->evdev_a = evdev_a;
  1938.     return (error);
  1939. }
  1940.  
  1941. static int psm_register_focaltech(device_t dev)
  1942. {
  1943.     struct psm_softc *sc = device_get_softc(dev);
  1944.     const uint16_t focaltech_absinfo[][4] = {
  1945.         { ABS_TOOL_WIDTH,   0, 15, 0 },
  1946.         { ABS_MT_SLOT,      0, 4, 0 },
  1947.         { ABS_MT_POSITION_X,    0, FOCALTECH_MAX_X,
  1948.                        32 },
  1949.         { ABS_MT_POSITION_Y,    0, FOCALTECH_MAX_Y,
  1950.                        32 },
  1951.         ABSINFO_END,
  1952.     };
  1953.     struct evdev_dev *evdev_a;
  1954.     int error;
  1955.  
  1956.    
  1957.     evdev_a = evdev_alloc();
  1958.     evdev_set_name(evdev_a, PS2_MOUSE_FOCALTECH_NAME);
  1959.     evdev_set_phys(evdev_a, device_get_nameunit(dev));
  1960.     evdev_set_id(evdev_a, BUS_I8042, PS2_MOUSE_VENDOR,
  1961.         PS2_MOUSE_FOCALTECH_PRODUCT, 0);
  1962.     evdev_set_methods(evdev_a, sc, &psm_ev_methods_a);
  1963.  
  1964.     evdev_support_event(evdev_a, EV_SYN);
  1965.     evdev_support_event(evdev_a, EV_KEY);
  1966.     evdev_support_event(evdev_a, EV_ABS);
  1967.     evdev_support_prop(evdev_a, INPUT_PROP_POINTER);
  1968.     if (sc->elanhw.issemimt)
  1969.         evdev_support_prop(evdev_a, INPUT_PROP_SEMI_MT);
  1970.     if (sc->elanhw.isclickpad)
  1971.         evdev_support_prop(evdev_a, INPUT_PROP_BUTTONPAD);
  1972.     evdev_support_key(evdev_a, BTN_TOUCH);
  1973.     evdev_support_nfingers(evdev_a, 5);
  1974.     evdev_support_key(evdev_a, BTN_LEFT);
  1975.     if (!sc->elanhw.isclickpad)
  1976.         evdev_support_key(evdev_a, BTN_RIGHT);
  1977.     psm_support_abs_bulk(evdev_a, focaltech_absinfo);
  1978.  
  1979.     error = evdev_register_mtx(evdev_a, &Giant);
  1980.     if (!error && sc->elanhw.hastrackpoint)
  1981.         error = psm_register(dev, MOUSE_MODEL_FOCALTECH);
  1982.     if (error)
  1983.         evdev_free(evdev_a);
  1984.     else
  1985.         sc->evdev_a = evdev_a;
  1986.     return (error);
  1987.  
  1988.  
  1989. }
  1990.  
  1991. #endif
  1992.  
  1993. static int
  1994. psmattach(device_t dev)
  1995. {
  1996.     int unit = device_get_unit(dev);
  1997.     struct psm_softc *sc = device_get_softc(dev);
  1998.     int error;
  1999.     int rid;
  2000.  
  2001.     /* Setup initial state */
  2002.     sc->state = PSM_VALID;
  2003.     callout_init(&sc->callout, 0);
  2004.     callout_init(&sc->softcallout, 0);
  2005.  
  2006.     /* Setup our interrupt handler */
  2007.     rid = KBDC_RID_AUX;
  2008.     sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
  2009.     if (sc->intr == NULL)
  2010.         return (ENXIO);
  2011.     error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc,
  2012.         &sc->ih);
  2013.     if (error) {
  2014.         bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
  2015.         return (error);
  2016.     }
  2017.  
  2018.     /* Done */
  2019.     sc->dev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "psm%d", unit);
  2020.     sc->dev->si_drv1 = sc;
  2021.     sc->bdev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "bpsm%d", unit);
  2022.     sc->bdev->si_drv1 = sc;
  2023.  
  2024. #ifdef EVDEV_SUPPORT
  2025.     switch (sc->hw.model) {
  2026.     case MOUSE_MODEL_SYNAPTICS:
  2027.         error = psm_register_synaptics(dev);
  2028.         break;
  2029.  
  2030.     case MOUSE_MODEL_ELANTECH:
  2031.         error = psm_register_elantech(dev);
  2032.         break;
  2033.  
  2034.     case MOUSE_MODEL_FOCALTECH:
  2035.       error = psm_register_focaltech(dev);
  2036.       break;
  2037.  
  2038.     default:
  2039.         error = psm_register(dev, sc->hw.model);
  2040.     }
  2041.  
  2042.     if (error)
  2043.         return (error);
  2044. #endif
  2045.  
  2046.     /* Some touchpad devices need full reinitialization after suspend. */
  2047.     switch (sc->hw.model) {
  2048.     case MOUSE_MODEL_SYNAPTICS:
  2049.     case MOUSE_MODEL_GLIDEPOINT:
  2050.     case MOUSE_MODEL_VERSAPAD:
  2051.     case MOUSE_MODEL_ELANTECH:
  2052.     case MOUSE_MODEL_FOCALTECH:
  2053.         sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
  2054.         break;
  2055.     default:
  2056.         if (sc->synhw.infoMajor >= 4 || sc->tphw > 0)
  2057.             sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
  2058.         break;
  2059.     }
  2060.  
  2061.     /* Elantech trackpad`s sync bit differs from touchpad`s one */
  2062.     if (sc->hw.model == MOUSE_MODEL_ELANTECH &&
  2063.         (sc->elanhw.hascrc || sc->elanhw.hastrackpoint)) {
  2064.         sc->config |= PSM_CONFIG_NOCHECKSYNC;
  2065.         sc->flags &= ~PSM_NEED_SYNCBITS;
  2066.     }
  2067.  
  2068.     if (!verbose)
  2069.         printf("psm%d: model %s, device ID %d\n",
  2070.             unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
  2071.     else {
  2072.         printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
  2073.             unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff,
  2074.             sc->hw.hwid >> 8, sc->hw.buttons);
  2075.         printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
  2076.             unit, sc->config, sc->flags, sc->mode.packetsize);
  2077.         printf("psm%d: syncmask:%02x, syncbits:%02x%s\n",
  2078.             unit, sc->mode.syncmask[0], sc->mode.syncmask[1],
  2079.             sc->config & PSM_CONFIG_NOCHECKSYNC ? " (sync not checked)" : "");
  2080.     }
  2081.  
  2082.     if (bootverbose)
  2083.         --verbose;
  2084.  
  2085.     return (0);
  2086. }
  2087.  
  2088. static int
  2089. psmdetach(device_t dev)
  2090. {
  2091.     struct psm_softc *sc;
  2092.     int rid;
  2093.  
  2094.     sc = device_get_softc(dev);
  2095.     if (sc->state & PSM_OPEN)
  2096.         return (EBUSY);
  2097.  
  2098. #ifdef EVDEV_SUPPORT
  2099.     evdev_free(sc->evdev_r);
  2100.     evdev_free(sc->evdev_a);
  2101. #endif
  2102.  
  2103.     rid = KBDC_RID_AUX;
  2104.     bus_teardown_intr(dev, sc->intr, sc->ih);
  2105.     bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
  2106.  
  2107.     destroy_dev(sc->dev);
  2108.     destroy_dev(sc->bdev);
  2109.  
  2110.     callout_drain(&sc->callout);
  2111.     callout_drain(&sc->softcallout);
  2112.  
  2113.     return (0);
  2114. }
  2115.  
  2116. #ifdef EVDEV_SUPPORT
  2117. static int
  2118. psm_ev_open_r(struct evdev_dev *evdev, void *ev_softc)
  2119. {
  2120.     struct psm_softc *sc = (struct psm_softc *)ev_softc;
  2121.     int err = 0;
  2122.  
  2123.     /* Get device data */
  2124.     if ((sc->state & PSM_VALID) == 0) {
  2125.         /* the device is no longer valid/functioning */
  2126.         return (ENXIO);
  2127.     }
  2128.  
  2129.     if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_A)))
  2130.         err = psmopen(sc);
  2131.  
  2132.     if (err == 0)
  2133.         sc->state |= PSM_EV_OPEN_R;
  2134.  
  2135.     return (err);
  2136. }
  2137.  
  2138. static void
  2139. psm_ev_close_r(struct evdev_dev *evdev, void *ev_softc)
  2140. {
  2141.     struct psm_softc *sc = (struct psm_softc *)ev_softc;
  2142.  
  2143.     sc->state &= ~PSM_EV_OPEN_R;
  2144.  
  2145.     if (sc->state & (PSM_OPEN | PSM_EV_OPEN_A))
  2146.         return;
  2147.  
  2148.     if (sc->state & PSM_VALID)
  2149.         psmclose(sc);
  2150. }
  2151.  
  2152. static int
  2153. psm_ev_open_a(struct evdev_dev *evdev, void *ev_softc)
  2154. {
  2155.     struct psm_softc *sc = (struct psm_softc *)ev_softc;
  2156.     int err = 0;
  2157.  
  2158.     /* Get device data */
  2159.     if ((sc->state & PSM_VALID) == 0) {
  2160.         /* the device is no longer valid/functioning */
  2161.         return (ENXIO);
  2162.     }
  2163.  
  2164.     if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_R)))
  2165.         err = psmopen(sc);
  2166.  
  2167.     if (err == 0)
  2168.         sc->state |= PSM_EV_OPEN_A;
  2169.  
  2170.     return (err);
  2171. }
  2172.  
  2173. static void
  2174. psm_ev_close_a(struct evdev_dev *evdev, void *ev_softc)
  2175. {
  2176.     struct psm_softc *sc = (struct psm_softc *)ev_softc;
  2177.  
  2178.     sc->state &= ~PSM_EV_OPEN_A;
  2179.  
  2180.     if (sc->state & (PSM_OPEN | PSM_EV_OPEN_R))
  2181.         return;
  2182.  
  2183.     if (sc->state & PSM_VALID)
  2184.         psmclose(sc);
  2185. }
  2186. #endif
  2187.  
  2188. static int
  2189. psm_cdev_open(struct cdev *dev, int flag, int fmt, struct thread *td)
  2190. {
  2191.     struct psm_softc *sc;
  2192.     int err = 0;
  2193.  
  2194.     /* Get device data */
  2195.     sc = dev->si_drv1;
  2196.     if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
  2197.         /* the device is no longer valid/functioning */
  2198.         return (ENXIO);
  2199.     }
  2200.  
  2201.     /* Disallow multiple opens */
  2202.     if (sc->state & PSM_OPEN)
  2203.         return (EBUSY);
  2204.  
  2205.     device_busy(devclass_get_device(psm_devclass, sc->unit));
  2206.  
  2207. #ifdef EVDEV_SUPPORT
  2208.     /* Already opened by evdev */
  2209.     if (!(sc->state & (PSM_EV_OPEN_R | PSM_EV_OPEN_A)))
  2210. #endif
  2211.         err = psmopen(sc);
  2212.  
  2213.     if (err == 0)
  2214.         sc->state |= PSM_OPEN;
  2215.     else
  2216.         device_unbusy(devclass_get_device(psm_devclass, sc->unit));
  2217.  
  2218.     return (err);
  2219. }
  2220.  
  2221. static int
  2222. psm_cdev_close(struct cdev *dev, int flag, int fmt, struct thread *td)
  2223. {
  2224.     struct psm_softc *sc;
  2225.     int err = 0;
  2226.  
  2227.     /* Get device data */
  2228.     sc = dev->si_drv1;
  2229.     if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
  2230.         /* the device is no longer valid/functioning */
  2231.         return (ENXIO);
  2232.     }
  2233.  
  2234. #ifdef EVDEV_SUPPORT
  2235.     /* Still opened by evdev */
  2236.     if (!(sc->state & (PSM_EV_OPEN_R | PSM_EV_OPEN_A)))
  2237. #endif
  2238.         err = psmclose(sc);
  2239.  
  2240.     if (err == 0) {
  2241.         sc->state &= ~PSM_OPEN;
  2242.         /* clean up and sigio requests */
  2243.         if (sc->async != NULL) {
  2244.             funsetown(&sc->async);
  2245.             sc->async = NULL;
  2246.         }
  2247.         device_unbusy(devclass_get_device(psm_devclass, sc->unit));
  2248.     }
  2249.  
  2250.     return (err);
  2251. }
  2252.  
  2253. static int
  2254. psmopen(struct psm_softc *sc)
  2255. {
  2256.     int command_byte;
  2257.     int err;
  2258.     int s;
  2259.  
  2260.     /* Initialize state */
  2261.     sc->mode.level = sc->dflt_mode.level;
  2262.     sc->mode.protocol = sc->dflt_mode.protocol;
  2263.     sc->watchdog = FALSE;
  2264.     sc->async = NULL;
  2265.  
  2266.     /* flush the event queue */
  2267.     sc->queue.count = 0;
  2268.     sc->queue.head = 0;
  2269.     sc->queue.tail = 0;
  2270.     sc->status.flags = 0;
  2271.     sc->status.button = 0;
  2272.     sc->status.obutton = 0;
  2273.     sc->status.dx = 0;
  2274.     sc->status.dy = 0;
  2275.     sc->status.dz = 0;
  2276.     sc->button = 0;
  2277.     sc->pqueue_start = 0;
  2278.     sc->pqueue_end = 0;
  2279.  
  2280.     /* empty input buffer */
  2281.     flushpackets(sc);
  2282.     sc->syncerrors = 0;
  2283.     sc->pkterrors = 0;
  2284.  
  2285.     /* don't let timeout routines in the keyboard driver to poll the kbdc */
  2286.     if (!kbdc_lock(sc->kbdc, TRUE))
  2287.         return (EIO);
  2288.  
  2289.     /* save the current controller command byte */
  2290.     s = spltty();
  2291.     command_byte = get_controller_command_byte(sc->kbdc);
  2292.  
  2293.     /* enable the aux port and temporalily disable the keyboard */
  2294.     if (command_byte == -1 || !set_controller_command_byte(sc->kbdc,
  2295.         kbdc_get_device_mask(sc->kbdc),
  2296.         KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
  2297.         KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  2298.         /* CONTROLLER ERROR; do you know how to get out of this? */
  2299.         kbdc_lock(sc->kbdc, FALSE);
  2300.         splx(s);
  2301.         log(LOG_ERR,
  2302.             "psm%d: unable to set the command byte (psmopen).\n",
  2303.             sc->unit);
  2304.         return (EIO);
  2305.     }
  2306.     /*
  2307.      * Now that the keyboard controller is told not to generate
  2308.      * the keyboard and mouse interrupts, call `splx()' to allow
  2309.      * the other tty interrupts. The clock interrupt may also occur,
  2310.      * but timeout routines will be blocked by the poll flag set
  2311.      * via `kbdc_lock()'
  2312.      */
  2313.     splx(s);
  2314.  
  2315.     /* enable the mouse device */
  2316.     err = doopen(sc, command_byte);
  2317.  
  2318.     /* done */
  2319.     kbdc_lock(sc->kbdc, FALSE);
  2320.     return (err);
  2321. }
  2322.  
  2323. static int
  2324. psmclose(struct psm_softc *sc)
  2325. {
  2326.     int stat[3];
  2327.     int command_byte;
  2328.     int s;
  2329.  
  2330.     /* don't let timeout routines in the keyboard driver to poll the kbdc */
  2331.     if (!kbdc_lock(sc->kbdc, TRUE))
  2332.         return (EIO);
  2333.  
  2334.     /* save the current controller command byte */
  2335.     s = spltty();
  2336.     command_byte = get_controller_command_byte(sc->kbdc);
  2337.     if (command_byte == -1) {
  2338.         kbdc_lock(sc->kbdc, FALSE);
  2339.         splx(s);
  2340.         return (EIO);
  2341.     }
  2342.  
  2343.     /* disable the aux interrupt and temporalily disable the keyboard */
  2344.     if (!set_controller_command_byte(sc->kbdc,
  2345.         kbdc_get_device_mask(sc->kbdc),
  2346.         KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
  2347.         KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  2348.         log(LOG_ERR,
  2349.             "psm%d: failed to disable the aux int (psmclose).\n",
  2350.             sc->unit);
  2351.         /* CONTROLLER ERROR;
  2352.          * NOTE: we shall force our way through. Because the only
  2353.          * ill effect we shall see is that we may not be able
  2354.          * to read ACK from the mouse, and it doesn't matter much
  2355.          * so long as the mouse will accept the DISABLE command.
  2356.          */
  2357.     }
  2358.     splx(s);
  2359.  
  2360.     /* stop the watchdog timer */
  2361.     callout_stop(&sc->callout);
  2362.  
  2363.     /* remove anything left in the output buffer */
  2364.     empty_aux_buffer(sc->kbdc, 10);
  2365.  
  2366.     /* disable the aux device, port and interrupt */
  2367.     if (sc->state & PSM_VALID) {
  2368.         if (!disable_aux_dev(sc->kbdc)) {
  2369.             /* MOUSE ERROR;
  2370.              * NOTE: we don't return (error) and continue,
  2371.              * pretending we have successfully disabled the device.
  2372.              * It's OK because the interrupt routine will discard
  2373.              * any data from the mouse hereafter.
  2374.              */
  2375.             log(LOG_ERR,
  2376.                 "psm%d: failed to disable the device (psmclose).\n",
  2377.                 sc->unit);
  2378.         }
  2379.  
  2380.         if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
  2381.             log(LOG_DEBUG,
  2382.                 "psm%d: failed to get status (psmclose).\n",
  2383.                 sc->unit);
  2384.     }
  2385.  
  2386.     if (!set_controller_command_byte(sc->kbdc,
  2387.         kbdc_get_device_mask(sc->kbdc),
  2388.         (command_byte & KBD_KBD_CONTROL_BITS) |
  2389.         KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  2390.         /*
  2391.          * CONTROLLER ERROR;
  2392.          * we shall ignore this error; see the above comment.
  2393.          */
  2394.         log(LOG_ERR,
  2395.             "psm%d: failed to disable the aux port (psmclose).\n",
  2396.             sc->unit);
  2397.     }
  2398.  
  2399.     /* remove anything left in the output buffer */
  2400.     empty_aux_buffer(sc->kbdc, 10);
  2401.  
  2402.     /* close is almost always successful */
  2403.     kbdc_lock(sc->kbdc, FALSE);
  2404.     return (0);
  2405. }
  2406.  
  2407. static int
  2408. tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status,
  2409.     u_char *buf)
  2410. {
  2411.     static u_char butmapps2[8] = {
  2412.         0,
  2413.         MOUSE_PS2_BUTTON1DOWN,
  2414.         MOUSE_PS2_BUTTON2DOWN,
  2415.         MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
  2416.         MOUSE_PS2_BUTTON3DOWN,
  2417.         MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
  2418.         MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
  2419.         MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN |
  2420.             MOUSE_PS2_BUTTON3DOWN,
  2421.     };
  2422.     static u_char butmapmsc[8] = {
  2423.         MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP |
  2424.             MOUSE_MSC_BUTTON3UP,
  2425.         MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
  2426.         MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
  2427.         MOUSE_MSC_BUTTON3UP,
  2428.         MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
  2429.         MOUSE_MSC_BUTTON2UP,
  2430.         MOUSE_MSC_BUTTON1UP,
  2431.         0,
  2432.     };
  2433.     int mapped;
  2434.     int i;
  2435.  
  2436.     if (sc->mode.level == PSM_LEVEL_BASE) {
  2437.         mapped = status->button & ~MOUSE_BUTTON4DOWN;
  2438.         if (status->button & MOUSE_BUTTON4DOWN)
  2439.             mapped |= MOUSE_BUTTON1DOWN;
  2440.         status->button = mapped;
  2441.         buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
  2442.         i = imax(imin(status->dx, 255), -256);
  2443.         if (i < 0)
  2444.             buf[0] |= MOUSE_PS2_XNEG;
  2445.         buf[1] = i;
  2446.         i = imax(imin(status->dy, 255), -256);
  2447.         if (i < 0)
  2448.             buf[0] |= MOUSE_PS2_YNEG;
  2449.         buf[2] = i;
  2450.         return (MOUSE_PS2_PACKETSIZE);
  2451.     } else if (sc->mode.level == PSM_LEVEL_STANDARD) {
  2452.         buf[0] = MOUSE_MSC_SYNC |
  2453.             butmapmsc[status->button & MOUSE_STDBUTTONS];
  2454.         i = imax(imin(status->dx, 255), -256);
  2455.         buf[1] = i >> 1;
  2456.         buf[3] = i - buf[1];
  2457.         i = imax(imin(status->dy, 255), -256);
  2458.         buf[2] = i >> 1;
  2459.         buf[4] = i - buf[2];
  2460.         i = imax(imin(status->dz, 127), -128);
  2461.         buf[5] = (i >> 1) & 0x7f;
  2462.         buf[6] = (i - (i >> 1)) & 0x7f;
  2463.         buf[7] = (~status->button >> 3) & 0x7f;
  2464.         return (MOUSE_SYS_PACKETSIZE);
  2465.     }
  2466.     return (pb->inputbytes);
  2467. }
  2468.  
  2469. static int
  2470. psmread(struct cdev *dev, struct uio *uio, int flag)
  2471. {
  2472.     struct psm_softc *sc = dev->si_drv1;
  2473.     u_char buf[PSM_SMALLBUFSIZE];
  2474.     int error = 0;
  2475.     int s;
  2476.     int l;
  2477.  
  2478.     if ((sc->state & PSM_VALID) == 0)
  2479.         return (EIO);
  2480.  
  2481.     /* block until mouse activity occurred */
  2482.     s = spltty();
  2483.     while (sc->queue.count <= 0) {
  2484.         if (dev != sc->bdev) {
  2485.             splx(s);
  2486.             return (EWOULDBLOCK);
  2487.         }
  2488.         sc->state |= PSM_ASLP;
  2489.         error = tsleep(sc, PZERO | PCATCH, "psmrea", 0);
  2490.         sc->state &= ~PSM_ASLP;
  2491.         if (error) {
  2492.             splx(s);
  2493.             return (error);
  2494.         } else if ((sc->state & PSM_VALID) == 0) {
  2495.             /* the device disappeared! */
  2496.             splx(s);
  2497.             return (EIO);
  2498.         }
  2499.     }
  2500.     splx(s);
  2501.  
  2502.     /* copy data to the user land */
  2503.     while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
  2504.         s = spltty();
  2505.         l = imin(sc->queue.count, uio->uio_resid);
  2506.         if (l > sizeof(buf))
  2507.             l = sizeof(buf);
  2508.         if (l > sizeof(sc->queue.buf) - sc->queue.head) {
  2509.             bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
  2510.                 sizeof(sc->queue.buf) - sc->queue.head);
  2511.             bcopy(&sc->queue.buf[0],
  2512.                 &buf[sizeof(sc->queue.buf) - sc->queue.head],
  2513.                 l - (sizeof(sc->queue.buf) - sc->queue.head));
  2514.         } else
  2515.             bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
  2516.         sc->queue.count -= l;
  2517.         sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
  2518.         splx(s);
  2519.         error = uiomove(buf, l, uio);
  2520.         if (error)
  2521.             break;
  2522.     }
  2523.  
  2524.     return (error);
  2525. }
  2526.  
  2527. static int
  2528. block_mouse_data(struct psm_softc *sc, int *c)
  2529. {
  2530.     int s;
  2531.  
  2532.     if (!kbdc_lock(sc->kbdc, TRUE))
  2533.         return (EIO);
  2534.  
  2535.     s = spltty();
  2536.     *c = get_controller_command_byte(sc->kbdc);
  2537.     if ((*c == -1) || !set_controller_command_byte(sc->kbdc,
  2538.         kbdc_get_device_mask(sc->kbdc),
  2539.         KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
  2540.         KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  2541.         /* this is CONTROLLER ERROR */
  2542.         splx(s);
  2543.         kbdc_lock(sc->kbdc, FALSE);
  2544.         return (EIO);
  2545.     }
  2546.  
  2547.     /*
  2548.      * The device may be in the middle of status data transmission.
  2549.      * The transmission will be interrupted, thus, incomplete status
  2550.      * data must be discarded. Although the aux interrupt is disabled
  2551.      * at the keyboard controller level, at most one aux interrupt
  2552.      * may have already been pending and a data byte is in the
  2553.      * output buffer; throw it away. Note that the second argument
  2554.      * to `empty_aux_buffer()' is zero, so that the call will just
  2555.      * flush the internal queue.
  2556.      * `psmintr()' will be invoked after `splx()' if an interrupt is
  2557.      * pending; it will see no data and returns immediately.
  2558.      */
  2559.     empty_aux_buffer(sc->kbdc, 0);      /* flush the queue */
  2560.     read_aux_data_no_wait(sc->kbdc);    /* throw away data if any */
  2561.     flushpackets(sc);
  2562.     splx(s);
  2563.  
  2564.     return (0);
  2565. }
  2566.  
  2567. static void
  2568. dropqueue(struct psm_softc *sc)
  2569. {
  2570.  
  2571.     sc->queue.count = 0;
  2572.     sc->queue.head = 0;
  2573.     sc->queue.tail = 0;
  2574.     if ((sc->state & PSM_SOFTARMED) != 0) {
  2575.         sc->state &= ~PSM_SOFTARMED;
  2576.         callout_stop(&sc->softcallout);
  2577.     }
  2578.     sc->pqueue_start = sc->pqueue_end;
  2579. }
  2580.  
  2581. static void
  2582. flushpackets(struct psm_softc *sc)
  2583. {
  2584.  
  2585.     dropqueue(sc);
  2586.     bzero(&sc->pqueue, sizeof(sc->pqueue));
  2587. }
  2588.  
  2589. static int
  2590. unblock_mouse_data(struct psm_softc *sc, int c)
  2591. {
  2592.     int error = 0;
  2593.  
  2594.     /*
  2595.      * We may have seen a part of status data during `set_mouse_XXX()'.
  2596.      * they have been queued; flush it.
  2597.      */
  2598.     empty_aux_buffer(sc->kbdc, 0);
  2599.  
  2600.     /* restore ports and interrupt */
  2601.     if (!set_controller_command_byte(sc->kbdc,
  2602.         kbdc_get_device_mask(sc->kbdc),
  2603.         c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
  2604.         /*
  2605.          * CONTROLLER ERROR; this is serious, we may have
  2606.          * been left with the inaccessible keyboard and
  2607.          * the disabled mouse interrupt.
  2608.          */
  2609.         error = EIO;
  2610.     }
  2611.  
  2612.     kbdc_lock(sc->kbdc, FALSE);
  2613.     return (error);
  2614. }
  2615.  
  2616. static int
  2617. psmwrite(struct cdev *dev, struct uio *uio, int flag)
  2618. {
  2619.     struct psm_softc *sc = dev->si_drv1;
  2620.     u_char buf[PSM_SMALLBUFSIZE];
  2621.     int error = 0, i, l;
  2622.  
  2623.     if ((sc->state & PSM_VALID) == 0)
  2624.         return (EIO);
  2625.  
  2626.     if (sc->mode.level < PSM_LEVEL_NATIVE)
  2627.         return (ENODEV);
  2628.  
  2629.     /* copy data from the user land */
  2630.     while (uio->uio_resid > 0) {
  2631.         l = imin(PSM_SMALLBUFSIZE, uio->uio_resid);
  2632.         error = uiomove(buf, l, uio);
  2633.         if (error)
  2634.             break;
  2635.         for (i = 0; i < l; i++) {
  2636.             VLOG(4, (LOG_DEBUG, "psm: cmd 0x%x\n", buf[i]));
  2637.             if (!write_aux_command(sc->kbdc, buf[i])) {
  2638.                 VLOG(2, (LOG_DEBUG,
  2639.                     "psm: cmd 0x%x failed.\n", buf[i]));
  2640.                 return (reinitialize(sc, FALSE));
  2641.             }
  2642.         }
  2643.     }
  2644.  
  2645.     return (error);
  2646. }
  2647.  
  2648. static int
  2649. psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
  2650.     struct thread *td)
  2651. {
  2652.     struct psm_softc *sc = dev->si_drv1;
  2653.     mousemode_t mode;
  2654.     mousestatus_t status;
  2655. #if (defined(MOUSE_GETVARS))
  2656.     mousevar_t *var;
  2657. #endif
  2658.     mousedata_t *data;
  2659.     int stat[3];
  2660.     int command_byte;
  2661.     int error = 0;
  2662.     int s;
  2663.  
  2664.     /* Perform IOCTL command */
  2665.     switch (cmd) {
  2666.  
  2667.     case OLD_MOUSE_GETHWINFO:
  2668.         s = spltty();
  2669.         ((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
  2670.         ((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
  2671.         ((old_mousehw_t *)addr)->type = sc->hw.type;
  2672.         ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
  2673.         splx(s);
  2674.         break;
  2675.  
  2676.     case MOUSE_GETHWINFO:
  2677.         s = spltty();
  2678.         *(mousehw_t *)addr = sc->hw;
  2679.         if (sc->mode.level == PSM_LEVEL_BASE)
  2680.             ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
  2681.         splx(s);
  2682.         break;
  2683.  
  2684.     case MOUSE_SYN_GETHWINFO:
  2685.         s = spltty();
  2686.         if (sc->synhw.infoMajor >= 4)
  2687.             *(synapticshw_t *)addr = sc->synhw;
  2688.         else
  2689.             error = EINVAL;
  2690.         splx(s);
  2691.         break;
  2692.  
  2693.     case OLD_MOUSE_GETMODE:
  2694.         s = spltty();
  2695.         switch (sc->mode.level) {
  2696.         case PSM_LEVEL_BASE:
  2697.             ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
  2698.             break;
  2699.         case PSM_LEVEL_STANDARD:
  2700.             ((old_mousemode_t *)addr)->protocol =
  2701.                 MOUSE_PROTO_SYSMOUSE;
  2702.             break;
  2703.         case PSM_LEVEL_NATIVE:
  2704.             ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
  2705.             break;
  2706.         }
  2707.         ((old_mousemode_t *)addr)->rate = sc->mode.rate;
  2708.         ((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
  2709.         ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
  2710.         splx(s);
  2711.         break;
  2712.  
  2713.     case MOUSE_GETMODE:
  2714.         s = spltty();
  2715.         *(mousemode_t *)addr = sc->mode;
  2716.         if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
  2717.             ((mousemode_t *)addr)->syncmask[0] = 0;
  2718.             ((mousemode_t *)addr)->syncmask[1] = 0;
  2719.         }
  2720.         ((mousemode_t *)addr)->resolution =
  2721.             MOUSE_RES_LOW - sc->mode.resolution;
  2722.         switch (sc->mode.level) {
  2723.         case PSM_LEVEL_BASE:
  2724.             ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
  2725.             ((mousemode_t *)addr)->packetsize =
  2726.                 MOUSE_PS2_PACKETSIZE;
  2727.             break;
  2728.         case PSM_LEVEL_STANDARD:
  2729.             ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
  2730.             ((mousemode_t *)addr)->packetsize =
  2731.                 MOUSE_SYS_PACKETSIZE;
  2732.             ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
  2733.             ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
  2734.             break;
  2735.         case PSM_LEVEL_NATIVE:
  2736.             /* FIXME: this isn't quite correct... XXX */
  2737.             ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
  2738.             break;
  2739.         }
  2740.         splx(s);
  2741.         break;
  2742.  
  2743.     case OLD_MOUSE_SETMODE:
  2744.     case MOUSE_SETMODE:
  2745.         if (cmd == OLD_MOUSE_SETMODE) {
  2746.             mode.rate = ((old_mousemode_t *)addr)->rate;
  2747.             /*
  2748.              * resolution  old I/F   new I/F
  2749.              * default        0         0
  2750.              * low            1        -2
  2751.              * medium low     2        -3
  2752.              * medium high    3        -4
  2753.              * high           4        -5
  2754.              */
  2755.             if (((old_mousemode_t *)addr)->resolution > 0)
  2756.                 mode.resolution =
  2757.                     -((old_mousemode_t *)addr)->resolution - 1;
  2758.             else
  2759.                 mode.resolution = 0;
  2760.             mode.accelfactor =
  2761.                 ((old_mousemode_t *)addr)->accelfactor;
  2762.             mode.level = -1;
  2763.         } else
  2764.             mode = *(mousemode_t *)addr;
  2765.  
  2766.         /* adjust and validate parameters. */
  2767.         if (mode.rate > UCHAR_MAX)
  2768.             return (EINVAL);
  2769.         if (mode.rate == 0)
  2770.             mode.rate = sc->dflt_mode.rate;
  2771.         else if (mode.rate == -1)
  2772.             /* don't change the current setting */
  2773.             ;
  2774.         else if (mode.rate < 0)
  2775.             return (EINVAL);
  2776.         if (mode.resolution >= UCHAR_MAX)
  2777.             return (EINVAL);
  2778.         if (mode.resolution >= 200)
  2779.             mode.resolution = MOUSE_RES_HIGH;
  2780.         else if (mode.resolution >= 100)
  2781.             mode.resolution = MOUSE_RES_MEDIUMHIGH;
  2782.         else if (mode.resolution >= 50)
  2783.             mode.resolution = MOUSE_RES_MEDIUMLOW;
  2784.         else if (mode.resolution > 0)
  2785.             mode.resolution = MOUSE_RES_LOW;
  2786.         if (mode.resolution == MOUSE_RES_DEFAULT)
  2787.             mode.resolution = sc->dflt_mode.resolution;
  2788.         else if (mode.resolution == -1)
  2789.             /* don't change the current setting */
  2790.             ;
  2791.         else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
  2792.             mode.resolution = MOUSE_RES_LOW - mode.resolution;
  2793.         if (mode.level == -1)
  2794.             /* don't change the current setting */
  2795.             mode.level = sc->mode.level;
  2796.         else if ((mode.level < PSM_LEVEL_MIN) ||
  2797.             (mode.level > PSM_LEVEL_MAX))
  2798.             return (EINVAL);
  2799.         if (mode.accelfactor == -1)
  2800.             /* don't change the current setting */
  2801.             mode.accelfactor = sc->mode.accelfactor;
  2802.         else if (mode.accelfactor < 0)
  2803.             return (EINVAL);
  2804.  
  2805.         /* don't allow anybody to poll the keyboard controller */
  2806.         error = block_mouse_data(sc, &command_byte);
  2807.         if (error)
  2808.             return (error);
  2809.  
  2810.         /* set mouse parameters */
  2811.         if (mode.rate > 0)
  2812.             mode.rate = set_mouse_sampling_rate(sc->kbdc,
  2813.                 mode.rate);
  2814.         if (mode.resolution >= 0)
  2815.             mode.resolution =
  2816.                 set_mouse_resolution(sc->kbdc, mode.resolution);
  2817.         set_mouse_scaling(sc->kbdc, 1);
  2818.         get_mouse_status(sc->kbdc, stat, 0, 3);
  2819.  
  2820.         s = spltty();
  2821.         sc->mode.rate = mode.rate;
  2822.         sc->mode.resolution = mode.resolution;
  2823.         sc->mode.accelfactor = mode.accelfactor;
  2824.         sc->mode.level = mode.level;
  2825.         splx(s);
  2826.  
  2827.         unblock_mouse_data(sc, command_byte);
  2828.         break;
  2829.  
  2830.     case MOUSE_GETLEVEL:
  2831.         *(int *)addr = sc->mode.level;
  2832.         break;
  2833.  
  2834.     case MOUSE_SETLEVEL:
  2835.         if ((*(int *)addr < PSM_LEVEL_MIN) ||
  2836.             (*(int *)addr > PSM_LEVEL_MAX))
  2837.             return (EINVAL);
  2838.         sc->mode.level = *(int *)addr;
  2839.         break;
  2840.  
  2841.     case MOUSE_GETSTATUS:
  2842.         s = spltty();
  2843.         status = sc->status;
  2844.         sc->status.flags = 0;
  2845.         sc->status.obutton = sc->status.button;
  2846.         sc->status.button = 0;
  2847.         sc->status.dx = 0;
  2848.         sc->status.dy = 0;
  2849.         sc->status.dz = 0;
  2850.         splx(s);
  2851.         *(mousestatus_t *)addr = status;
  2852.         break;
  2853.  
  2854. #if (defined(MOUSE_GETVARS))
  2855.     case MOUSE_GETVARS:
  2856.         var = (mousevar_t *)addr;
  2857.         bzero(var, sizeof(*var));
  2858.         s = spltty();
  2859.         var->var[0] = MOUSE_VARS_PS2_SIG;
  2860.         var->var[1] = sc->config;
  2861.         var->var[2] = sc->flags;
  2862.         splx(s);
  2863.         break;
  2864.  
  2865.     case MOUSE_SETVARS:
  2866.         return (ENODEV);
  2867. #endif /* MOUSE_GETVARS */
  2868.  
  2869.     case MOUSE_READSTATE:
  2870.     case MOUSE_READDATA:
  2871.         data = (mousedata_t *)addr;
  2872.         if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
  2873.             return (EINVAL);
  2874.  
  2875.         error = block_mouse_data(sc, &command_byte);
  2876.         if (error)
  2877.             return (error);
  2878.         if ((data->len = get_mouse_status(sc->kbdc, data->buf,
  2879.             (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
  2880.             error = EIO;
  2881.         unblock_mouse_data(sc, command_byte);
  2882.         break;
  2883.  
  2884. #if (defined(MOUSE_SETRESOLUTION))
  2885.     case MOUSE_SETRESOLUTION:
  2886.         mode.resolution = *(int *)addr;
  2887.         if (mode.resolution >= UCHAR_MAX)
  2888.             return (EINVAL);
  2889.         else if (mode.resolution >= 200)
  2890.             mode.resolution = MOUSE_RES_HIGH;
  2891.         else if (mode.resolution >= 100)
  2892.             mode.resolution = MOUSE_RES_MEDIUMHIGH;
  2893.         else if (mode.resolution >= 50)
  2894.             mode.resolution = MOUSE_RES_MEDIUMLOW;
  2895.         else if (mode.resolution > 0)
  2896.             mode.resolution = MOUSE_RES_LOW;
  2897.         if (mode.resolution == MOUSE_RES_DEFAULT)
  2898.             mode.resolution = sc->dflt_mode.resolution;
  2899.         else if (mode.resolution == -1)
  2900.             mode.resolution = sc->mode.resolution;
  2901.         else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
  2902.             mode.resolution = MOUSE_RES_LOW - mode.resolution;
  2903.  
  2904.         error = block_mouse_data(sc, &command_byte);
  2905.         if (error)
  2906.             return (error);
  2907.         sc->mode.resolution =
  2908.             set_mouse_resolution(sc->kbdc, mode.resolution);
  2909.         if (sc->mode.resolution != mode.resolution)
  2910.             error = EIO;
  2911.         unblock_mouse_data(sc, command_byte);
  2912.         break;
  2913. #endif /* MOUSE_SETRESOLUTION */
  2914.  
  2915. #if (defined(MOUSE_SETRATE))
  2916.     case MOUSE_SETRATE:
  2917.         mode.rate = *(int *)addr;
  2918.         if (mode.rate > UCHAR_MAX)
  2919.             return (EINVAL);
  2920.         if (mode.rate == 0)
  2921.             mode.rate = sc->dflt_mode.rate;
  2922.         else if (mode.rate < 0)
  2923.             mode.rate = sc->mode.rate;
  2924.  
  2925.         error = block_mouse_data(sc, &command_byte);
  2926.         if (error)
  2927.             return (error);
  2928.         sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
  2929.         if (sc->mode.rate != mode.rate)
  2930.             error = EIO;
  2931.         unblock_mouse_data(sc, command_byte);
  2932.         break;
  2933. #endif /* MOUSE_SETRATE */
  2934.  
  2935. #if (defined(MOUSE_SETSCALING))
  2936.     case MOUSE_SETSCALING:
  2937.         if ((*(int *)addr <= 0) || (*(int *)addr > 2))
  2938.             return (EINVAL);
  2939.  
  2940.         error = block_mouse_data(sc, &command_byte);
  2941.         if (error)
  2942.             return (error);
  2943.         if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
  2944.             error = EIO;
  2945.         unblock_mouse_data(sc, command_byte);
  2946.         break;
  2947. #endif /* MOUSE_SETSCALING */
  2948.  
  2949. #if (defined(MOUSE_GETHWID))
  2950.     case MOUSE_GETHWID:
  2951.         error = block_mouse_data(sc, &command_byte);
  2952.         if (error)
  2953.             return (error);
  2954.         sc->hw.hwid &= ~0x00ff;
  2955.         sc->hw.hwid |= get_aux_id(sc->kbdc);
  2956.         *(int *)addr = sc->hw.hwid & 0x00ff;
  2957.         unblock_mouse_data(sc, command_byte);
  2958.         break;
  2959. #endif /* MOUSE_GETHWID */
  2960.  
  2961.     case FIONBIO:
  2962.     case FIOASYNC:
  2963.         break;
  2964.     case FIOSETOWN:
  2965.         error = fsetown(*(int *)addr, &sc->async);
  2966.         break;
  2967.     case FIOGETOWN:
  2968.         *(int *) addr = fgetown(&sc->async);
  2969.         break;
  2970.     default:
  2971.         return (ENOTTY);
  2972.     }
  2973.  
  2974.     return (error);
  2975. }
  2976.  
  2977. static void
  2978. psmtimeout(void *arg)
  2979. {
  2980.     struct psm_softc *sc;
  2981.     int s;
  2982.  
  2983.     sc = (struct psm_softc *)arg;
  2984.     s = spltty();
  2985.     if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
  2986.         VLOG(6, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit));
  2987.         psmintr(sc);
  2988.         kbdc_lock(sc->kbdc, FALSE);
  2989.     }
  2990.     sc->watchdog = TRUE;
  2991.     splx(s);
  2992.     callout_reset(&sc->callout, hz, psmtimeout, sc);
  2993. }
  2994.  
  2995. /* Add all sysctls under the debug.psm and hw.psm nodes */
  2996. static SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
  2997. static SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
  2998.  
  2999. SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RWTUN, &verbose, 0,
  3000.     "Verbosity level");
  3001.  
  3002. static int psmhz = 20;
  3003. SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0,
  3004.     "Frequency of the softcallout (in hz)");
  3005. static int psmerrsecs = 2;
  3006. SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0,
  3007.     "Number of seconds during which packets will dropped after a sync error");
  3008. static int psmerrusecs = 0;
  3009. SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0,
  3010.     "Microseconds to add to psmerrsecs");
  3011. static int psmsecs = 0;
  3012. SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0,
  3013.     "Max number of seconds between soft interrupts");
  3014. static int psmusecs = 500000;
  3015. SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0,
  3016.     "Microseconds to add to psmsecs");
  3017. static int pkterrthresh = 2;
  3018. SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0,
  3019.     "Number of error packets allowed before reinitializing the mouse");
  3020.  
  3021. SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RWTUN, &tap_enabled, 0,
  3022.     "Enable tap and drag gestures");
  3023. static int tap_threshold = PSM_TAP_THRESHOLD;
  3024. SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0,
  3025.     "Button tap threshold");
  3026. static int tap_timeout = PSM_TAP_TIMEOUT;
  3027. SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0,
  3028.     "Tap timeout for touchpads");
  3029.  
  3030. /* Tunables */
  3031. SYSCTL_INT(_hw_psm, OID_AUTO, synaptics_support, CTLFLAG_RDTUN,
  3032.     &synaptics_support, 0, "Enable support for Synaptics touchpads");
  3033.  
  3034. SYSCTL_INT(_hw_psm, OID_AUTO, trackpoint_support, CTLFLAG_RDTUN,
  3035.     &trackpoint_support, 0, "Enable support for IBM/Lenovo TrackPoint");
  3036.  
  3037. SYSCTL_INT(_hw_psm, OID_AUTO, elantech_support, CTLFLAG_RDTUN,
  3038.     &elantech_support, 0, "Enable support for Elantech touchpads");
  3039.  
  3040. static void
  3041. psmintr(void *arg)
  3042. {
  3043.     struct psm_softc *sc = arg;
  3044.     struct timeval now;
  3045.     int c;
  3046.     packetbuf_t *pb;
  3047.  
  3048.  
  3049.     /* read until there is nothing to read */
  3050.     while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
  3051.         pb = &sc->pqueue[sc->pqueue_end];
  3052.  
  3053.         /* discard the byte if the device is not open */
  3054.         if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_R | PSM_EV_OPEN_A)))
  3055.             continue;
  3056.  
  3057.         getmicrouptime(&now);
  3058.         if ((pb->inputbytes > 0) &&
  3059.             timevalcmp(&now, &sc->inputtimeout, >)) {
  3060.             VLOG(3, (LOG_DEBUG, "psmintr: delay too long; "
  3061.                 "resetting byte count\n"));
  3062.             pb->inputbytes = 0;
  3063.             sc->syncerrors = 0;
  3064.             sc->pkterrors = 0;
  3065.         }
  3066.         sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT / 1000000;
  3067.         sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT % 1000000;
  3068.         timevaladd(&sc->inputtimeout, &now);
  3069.  
  3070.         pb->ipacket[pb->inputbytes++] = c;
  3071.  
  3072.         if (sc->mode.level == PSM_LEVEL_NATIVE) {
  3073.             VLOG(4, (LOG_DEBUG, "psmintr: %02x\n", pb->ipacket[0]));
  3074.             sc->syncerrors = 0;
  3075.             sc->pkterrors = 0;
  3076.             goto next;
  3077.         } else {
  3078.             if (pb->inputbytes < sc->mode.packetsize)
  3079.                 continue;
  3080.  
  3081.             VLOG(4, (LOG_DEBUG,
  3082.                 "psmintr: %02x %02x %02x %02x %02x %02x\n",
  3083.                 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
  3084.                 pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
  3085.         }
  3086.  
  3087.         c = pb->ipacket[0];
  3088.  
  3089.         if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
  3090.             sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]);
  3091.             sc->flags &= ~PSM_NEED_SYNCBITS;
  3092.             VLOG(2, (LOG_DEBUG,
  3093.                 "psmintr: Sync bytes now %04x,%04x\n",
  3094.                 sc->mode.syncmask[0], sc->mode.syncmask[1]));
  3095.         } else if ((sc->config & PSM_CONFIG_NOCHECKSYNC) == 0 &&
  3096.             (c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
  3097.             VLOG(3, (LOG_DEBUG, "psmintr: out of sync "
  3098.                 "(%04x != %04x) %d cmds since last error.\n",
  3099.                 c & sc->mode.syncmask[0], sc->mode.syncmask[1],
  3100.                 sc->cmdcount - sc->lasterr));
  3101.             sc->lasterr = sc->cmdcount;
  3102.             /*
  3103.              * The sync byte test is a weak measure of packet
  3104.              * validity.  Conservatively discard any input yet
  3105.              * to be seen by userland when we detect a sync
  3106.              * error since there is a good chance some of
  3107.              * the queued packets have undetected errors.
  3108.              */
  3109.             dropqueue(sc);
  3110.             if (sc->syncerrors == 0)
  3111.                 sc->pkterrors++;
  3112.             ++sc->syncerrors;
  3113.             sc->lastinputerr = now;
  3114.             if (sc->syncerrors >= sc->mode.packetsize * 2 ||
  3115.                 sc->pkterrors >= pkterrthresh) {
  3116.                 /*
  3117.                  * If we've failed to find a single sync byte
  3118.                  * in 2 packets worth of data, or we've seen
  3119.                  * persistent packet errors during the
  3120.                  * validation period, reinitialize the mouse
  3121.                  * in hopes of returning it to the expected
  3122.                  * mode.
  3123.                  */
  3124.                 VLOG(3, (LOG_DEBUG,
  3125.                     "psmintr: reset the mouse.\n"));
  3126.                 reinitialize(sc, TRUE);
  3127.             } else if (sc->syncerrors == sc->mode.packetsize) {
  3128.                 /*
  3129.                  * Try a soft reset after searching for a sync
  3130.                  * byte through a packet length of bytes.
  3131.                  */
  3132.                 VLOG(3, (LOG_DEBUG,
  3133.                     "psmintr: re-enable the mouse.\n"));
  3134.                 pb->inputbytes = 0;
  3135.                 disable_aux_dev(sc->kbdc);
  3136.                 enable_aux_dev(sc->kbdc);
  3137.             } else {
  3138.                 VLOG(3, (LOG_DEBUG,
  3139.                     "psmintr: discard a byte (%d)\n",
  3140.                     sc->syncerrors));
  3141.                 pb->inputbytes--;
  3142.                 bcopy(&pb->ipacket[1], &pb->ipacket[0],
  3143.                     pb->inputbytes);
  3144.             }
  3145.             continue;
  3146.         }
  3147.  
  3148.         /*
  3149.          * We have what appears to be a valid packet.
  3150.          * Reset the error counters.
  3151.          */
  3152.         sc->syncerrors = 0;
  3153.  
  3154.         /*
  3155.          * Drop even good packets if they occur within a timeout
  3156.          * period of a sync error.  This allows the detection of
  3157.          * a change in the mouse's packet mode without exposing
  3158.          * erratic mouse behavior to the user.  Some KVMs forget
  3159.          * enhanced mouse modes during switch events.
  3160.          */
  3161.         if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs,
  3162.             &now)) {
  3163.             pb->inputbytes = 0;
  3164.             continue;
  3165.         }
  3166.  
  3167.         /*
  3168.          * Now that we're out of the validation period, reset
  3169.          * the packet error count.
  3170.          */
  3171.         sc->pkterrors = 0;
  3172.  
  3173.         sc->cmdcount++;
  3174. next:
  3175.         if (++sc->pqueue_end >= PSM_PACKETQUEUE)
  3176.             sc->pqueue_end = 0;
  3177.         /*
  3178.          * If we've filled the queue then call the softintr ourselves,
  3179.          * otherwise schedule the interrupt for later.
  3180.          */
  3181.         if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) ||
  3182.             (sc->pqueue_end == sc->pqueue_start)) {
  3183.             if ((sc->state & PSM_SOFTARMED) != 0) {
  3184.                 sc->state &= ~PSM_SOFTARMED;
  3185.                 callout_stop(&sc->softcallout);
  3186.             }
  3187.             psmsoftintr(arg);
  3188.         } else if ((sc->state & PSM_SOFTARMED) == 0) {
  3189.             sc->state |= PSM_SOFTARMED;
  3190.             callout_reset(&sc->softcallout,
  3191.                 psmhz < 1 ? 1 : (hz/psmhz), psmsoftintr, arg);
  3192.         }
  3193.     }
  3194. }
  3195.  
  3196. static void
  3197. proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
  3198.     int *x, int *y, int *z)
  3199. {
  3200.  
  3201.     /*
  3202.      * PS2++ protocol packet
  3203.      *
  3204.      *          b7 b6 b5 b4 b3 b2 b1 b0
  3205.      * byte 1:  *  1  p3 p2 1  *  *  *
  3206.      * byte 2:  c1 c2 p1 p0 d1 d0 1  0
  3207.      *
  3208.      * p3-p0: packet type
  3209.      * c1, c2: c1 & c2 == 1, if p2 == 0
  3210.      *         c1 & c2 == 0, if p2 == 1
  3211.      *
  3212.      * packet type: 0 (device type)
  3213.      * See comments in enable_mmanplus() below.
  3214.      *
  3215.      * packet type: 1 (wheel data)
  3216.      *
  3217.      *          b7 b6 b5 b4 b3 b2 b1 b0
  3218.      * byte 3:  h  *  B5 B4 s  d2 d1 d0
  3219.      *
  3220.      * h: 1, if horizontal roller data
  3221.      *    0, if vertical roller data
  3222.      * B4, B5: button 4 and 5
  3223.      * s: sign bit
  3224.      * d2-d0: roller data
  3225.      *
  3226.      * packet type: 2 (reserved)
  3227.      */
  3228.     if (((pb->ipacket[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) &&
  3229.         (abs(*x) > 191) && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) {
  3230.         /*
  3231.          * the extended data packet encodes button
  3232.          * and wheel events
  3233.          */
  3234.         switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) {
  3235.         case 1:
  3236.             /* wheel data packet */
  3237.             *x = *y = 0;
  3238.             if (pb->ipacket[2] & 0x80) {
  3239.                 /* XXX horizontal roller count - ignore it */
  3240.                 ;
  3241.             } else {
  3242.                 /* vertical roller count */
  3243.                 *z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) ?
  3244.                     (pb->ipacket[2] & 0x0f) - 16 :
  3245.                     (pb->ipacket[2] & 0x0f);
  3246.             }
  3247.             ms->button |= (pb->ipacket[2] &
  3248.                 MOUSE_PS2PLUS_BUTTON4DOWN) ?
  3249.                 MOUSE_BUTTON4DOWN : 0;
  3250.             ms->button |= (pb->ipacket[2] &
  3251.                 MOUSE_PS2PLUS_BUTTON5DOWN) ?
  3252.                 MOUSE_BUTTON5DOWN : 0;
  3253.             break;
  3254.         case 2:
  3255.             /*
  3256.              * this packet type is reserved by
  3257.              * Logitech...
  3258.              */
  3259.             /*
  3260.              * IBM ScrollPoint Mouse uses this
  3261.              * packet type to encode both vertical
  3262.              * and horizontal scroll movement.
  3263.              */
  3264.             *x = *y = 0;
  3265.             /* horizontal count */
  3266.             if (pb->ipacket[2] & 0x0f)
  3267.                 *z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ?
  3268.                     -2 : 2;
  3269.             /* vertical count */
  3270.             if (pb->ipacket[2] & 0xf0)
  3271.                 *z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ?
  3272.                     -1 : 1;
  3273.             break;
  3274.         case 0:
  3275.             /* device type packet - shouldn't happen */
  3276.             /* FALLTHROUGH */
  3277.         default:
  3278.             *x = *y = 0;
  3279.             ms->button = ms->obutton;
  3280.             VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet "
  3281.                 "type %d: 0x%02x 0x%02x 0x%02x\n",
  3282.                 MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket),
  3283.                 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]));
  3284.             break;
  3285.         }
  3286.     } else {
  3287.         /* preserve button states */
  3288.         ms->button |= ms->obutton & MOUSE_EXTBUTTONS;
  3289.     }
  3290. }
  3291.  
  3292. static int
  3293. proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
  3294.     int *x, int *y, int *z)
  3295. {
  3296.     static int touchpad_buttons;
  3297.     static int guest_buttons;
  3298.     static finger_t f[PSM_FINGERS];
  3299.     int w, id, nfingers, ewcode, extended_buttons, clickpad_pressed;
  3300.  
  3301.     extended_buttons = 0;
  3302.  
  3303.     /* TouchPad PS/2 absolute mode message format with capFourButtons:
  3304.      *
  3305.      *  Bits:        7   6   5   4   3   2   1   0 (LSB)
  3306.      *  ------------------------------------------------
  3307.      *  ipacket[0]:  1   0  W3  W2   0  W1   R   L
  3308.      *  ipacket[1]: Yb  Ya  Y9  Y8  Xb  Xa  X9  X8
  3309.      *  ipacket[2]: Z7  Z6  Z5  Z4  Z3  Z2  Z1  Z0
  3310.      *  ipacket[3]:  1   1  Yc  Xc   0  W0 D^R U^L
  3311.      *  ipacket[4]: X7  X6  X5  X4  X3  X2  X1  X0
  3312.      *  ipacket[5]: Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
  3313.      *
  3314.      * Legend:
  3315.      *  L: left physical mouse button
  3316.      *  R: right physical mouse button
  3317.      *  D: down button
  3318.      *  U: up button
  3319.      *  W: "wrist" value
  3320.      *  X: x position
  3321.      *  Y: y position
  3322.      *  Z: pressure
  3323.      *
  3324.      * Without capFourButtons but with nExtendeButtons and/or capMiddle
  3325.      *
  3326.      *  Bits:        7   6   5   4      3      2      1      0 (LSB)
  3327.      *  ------------------------------------------------------
  3328.      *  ipacket[3]:  1   1  Yc  Xc      0     W0    E^R    M^L
  3329.      *  ipacket[4]: X7  X6  X5  X4  X3|b7  X2|b5  X1|b3  X0|b1
  3330.      *  ipacket[5]: Y7  Y6  Y5  Y4  Y3|b8  Y2|b6  Y1|b4  Y0|b2
  3331.      *
  3332.      * Legend:
  3333.      *  M: Middle physical mouse button
  3334.      *  E: Extended mouse buttons reported instead of low bits of X and Y
  3335.      *  b1-b8: Extended mouse buttons
  3336.      *    Only ((nExtendedButtons + 1) >> 1) bits are used in packet
  3337.      *    4 and 5, for reading X and Y value they should be zeroed.
  3338.      *
  3339.      * Absolute reportable limits:    0 - 6143.
  3340.      * Typical bezel limits:       1472 - 5472.
  3341.      * Typical edge marings:       1632 - 5312.
  3342.      *
  3343.      * w = 3 Passthrough Packet
  3344.      *
  3345.      * Byte 2,5,6 == Byte 1,2,3 of "Guest"
  3346.      */
  3347.  
  3348.     if (!synaptics_support)
  3349.         return (0);
  3350.  
  3351.     /* Sanity check for out of sync packets. */
  3352.     if ((pb->ipacket[0] & 0xc8) != 0x80 ||
  3353.         (pb->ipacket[3] & 0xc8) != 0xc0)
  3354.         return (-1);
  3355.  
  3356.     *x = *y = 0;
  3357.     ms->button = ms->obutton;
  3358.  
  3359.     /*
  3360.      * Pressure value.
  3361.      * Interpretation:
  3362.      *   z = 0      No finger contact
  3363.      *   z = 10     Finger hovering near the pad
  3364.      *   z = 30     Very light finger contact
  3365.      *   z = 80     Normal finger contact
  3366.      *   z = 110    Very heavy finger contact
  3367.      *   z = 200    Finger lying flat on pad surface
  3368.      *   z = 255    Maximum reportable Z
  3369.      */
  3370.     *z = pb->ipacket[2];
  3371.  
  3372.     /*
  3373.      * Finger width value
  3374.      * Interpretation:
  3375.      *   w = 0      Two finger on the pad (capMultiFinger needed)
  3376.      *   w = 1      Three or more fingers (capMultiFinger needed)
  3377.      *   w = 2      Pen (instead of finger) (capPen needed)
  3378.      *   w = 3      Reserved (passthrough?)
  3379.      *   w = 4-7    Finger of normal width (capPalmDetect needed)
  3380.      *   w = 8-14   Very wide finger or palm (capPalmDetect needed)
  3381.      *   w = 15     Maximum reportable width (capPalmDetect needed)
  3382.      */
  3383.     /* XXX Is checking capExtended enough? */
  3384.     if (sc->synhw.capExtended)
  3385.         w = ((pb->ipacket[0] & 0x30) >> 2) |
  3386.             ((pb->ipacket[0] & 0x04) >> 1) |
  3387.             ((pb->ipacket[3] & 0x04) >> 2);
  3388.     else {
  3389.         /* Assume a finger of regular width. */
  3390.         w = 4;
  3391.     }
  3392.  
  3393.     switch (w) {
  3394.     case 3:
  3395.         /*
  3396.          * Handle packets from the guest device. See:
  3397.          * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
  3398.          */
  3399.         if (sc->synhw.capPassthrough) {
  3400.             *x = ((pb->ipacket[1] & 0x10) ?
  3401.                 pb->ipacket[4] - 256 : pb->ipacket[4]);
  3402.             *y = ((pb->ipacket[1] & 0x20) ?
  3403.                 pb->ipacket[5] - 256 : pb->ipacket[5]);
  3404.             *z = 0;
  3405.  
  3406.             guest_buttons = 0;
  3407.             if (pb->ipacket[1] & 0x01)
  3408.                 guest_buttons |= MOUSE_BUTTON1DOWN;
  3409.             if (pb->ipacket[1] & 0x04)
  3410.                 guest_buttons |= MOUSE_BUTTON2DOWN;
  3411.                 if (pb->ipacket[1] & 0x02)
  3412.                 guest_buttons |= MOUSE_BUTTON3DOWN;
  3413. #ifdef EVDEV_SUPPORT
  3414.             if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
  3415.                 evdev_push_rel(sc->evdev_r, REL_X, *x);
  3416.                 evdev_push_rel(sc->evdev_r, REL_Y, -*y);
  3417.                 evdev_push_mouse_btn(sc->evdev_r,
  3418.                     guest_buttons);
  3419.                 evdev_sync(sc->evdev_r);
  3420.             }
  3421. #endif
  3422.             ms->button = touchpad_buttons | guest_buttons |
  3423.                 sc->extended_buttons;
  3424.         }
  3425.         goto SYNAPTICS_END;
  3426.  
  3427.     case 2:
  3428.         /* Handle Extended W mode packets */
  3429.         ewcode = (pb->ipacket[5] & 0xf0) >> 4;
  3430. #if PSM_FINGERS > 1
  3431.         switch (ewcode) {
  3432.         case 1:
  3433.             /* Secondary finger */
  3434.             if (sc->synhw.capAdvancedGestures)
  3435.                 f[1] = (finger_t) {
  3436.                     .x = (((pb->ipacket[4] & 0x0f) << 8) |
  3437.                         pb->ipacket[1]) << 1,
  3438.                     .y = (((pb->ipacket[4] & 0xf0) << 4) |
  3439.                         pb->ipacket[2]) << 1,
  3440.                     .p = ((pb->ipacket[3] & 0x30) |
  3441.                         (pb->ipacket[5] & 0x0f)) << 1,
  3442.                     .w = PSM_FINGER_DEFAULT_W,
  3443.                     .flags = PSM_FINGER_FUZZY,
  3444.                 };
  3445.             else if (sc->synhw.capReportsV)
  3446.                 f[1] = (finger_t) {
  3447.                     .x = (((pb->ipacket[4] & 0x0f) << 8) |
  3448.                         (pb->ipacket[1] & 0xfe)) << 1,
  3449.                     .y = (((pb->ipacket[4] & 0xf0) << 4) |
  3450.                         (pb->ipacket[2] & 0xfe)) << 1,
  3451.                     .p = ((pb->ipacket[3] & 0x30) |
  3452.                         (pb->ipacket[5] & 0x0e)) << 1,
  3453.                     .w = (((pb->ipacket[5] & 0x01) << 2) |
  3454.                         ((pb->ipacket[2] & 0x01) << 1) |
  3455.                         (pb->ipacket[1] & 0x01)) + 8,
  3456.                     .flags = PSM_FINGER_FUZZY,
  3457.                 };
  3458.         default:
  3459.             break;
  3460.         }
  3461. #endif
  3462.         goto SYNAPTICS_END;
  3463.  
  3464.     case 1:
  3465.     case 0:
  3466.         nfingers = w + 2;
  3467.         break;
  3468.  
  3469.     default:
  3470.         nfingers = 1;
  3471.     }
  3472.  
  3473.     if (sc->syninfo.touchpad_off)
  3474.         goto SYNAPTICS_END;
  3475.  
  3476.     /* Button presses */
  3477.     touchpad_buttons = 0;
  3478.     if (pb->ipacket[0] & 0x01)
  3479.         touchpad_buttons |= MOUSE_BUTTON1DOWN;
  3480.     if (pb->ipacket[0] & 0x02)
  3481.         touchpad_buttons |= MOUSE_BUTTON3DOWN;
  3482.  
  3483.     if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
  3484.         if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x01)
  3485.             touchpad_buttons |= MOUSE_BUTTON4DOWN;
  3486.         if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x02)
  3487.             touchpad_buttons |= MOUSE_BUTTON5DOWN;
  3488.     } else if (sc->synhw.capExtended && sc->synhw.capMiddle &&
  3489.         !sc->synhw.capClickPad) {
  3490.         /* Middle Button */
  3491.         if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
  3492.             touchpad_buttons |= MOUSE_BUTTON2DOWN;
  3493.     } else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) {
  3494.         /* Extended Buttons */
  3495.         if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
  3496.             if (sc->syninfo.directional_scrolls) {
  3497.                 if (pb->ipacket[4] & 0x01)
  3498.                     extended_buttons |= MOUSE_BUTTON4DOWN;
  3499.                 if (pb->ipacket[5] & 0x01)
  3500.                     extended_buttons |= MOUSE_BUTTON5DOWN;
  3501.                 if (pb->ipacket[4] & 0x02)
  3502.                     extended_buttons |= MOUSE_BUTTON6DOWN;
  3503.                 if (pb->ipacket[5] & 0x02)
  3504.                     extended_buttons |= MOUSE_BUTTON7DOWN;
  3505.             } else {
  3506.                 if (pb->ipacket[4] & 0x01)
  3507.                     extended_buttons |= MOUSE_BUTTON1DOWN;
  3508.                 if (pb->ipacket[5] & 0x01)
  3509.                     extended_buttons |= MOUSE_BUTTON3DOWN;
  3510.                 if (pb->ipacket[4] & 0x02)
  3511.                     extended_buttons |= MOUSE_BUTTON2DOWN;
  3512.                 sc->extended_buttons = extended_buttons;
  3513.             }
  3514.  
  3515.             /*
  3516.              * Zero out bits used by extended buttons to avoid
  3517.              * misinterpretation of the data absolute position.
  3518.              *
  3519.              * The bits represented by
  3520.              *
  3521.              *     (nExtendedButtons + 1) >> 1
  3522.              *
  3523.              * will be masked out in both bytes.
  3524.              * The mask for n bits is computed with the formula
  3525.              *
  3526.              *     (1 << n) - 1
  3527.              */
  3528.             int maskedbits = 0;
  3529.             int mask = 0;
  3530.             maskedbits = (sc->synhw.nExtendedButtons + 1) >> 1;
  3531.             mask = (1 << maskedbits) - 1;
  3532. #ifdef EVDEV_SUPPORT
  3533.             int i;
  3534.             if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
  3535.                 if (sc->synhw.capPassthrough) {
  3536.                     evdev_push_mouse_btn(sc->evdev_r,
  3537.                         extended_buttons);
  3538.                     evdev_sync(sc->evdev_r);
  3539.                 }
  3540.                 for (i = 0; i < maskedbits; i++) {
  3541.                     evdev_push_key(sc->evdev_a,
  3542.                         BTN_0 + i * 2,
  3543.                         pb->ipacket[4] & (1 << i));
  3544.                     evdev_push_key(sc->evdev_a,
  3545.                         BTN_0 + i * 2 + 1,
  3546.                         pb->ipacket[5] & (1 << i));
  3547.                 }
  3548.             }
  3549. #endif
  3550.             pb->ipacket[4] &= ~(mask);
  3551.             pb->ipacket[5] &= ~(mask);
  3552.         } else  if (!sc->syninfo.directional_scrolls &&
  3553.             !sc->gesture.in_vscroll) {
  3554.             /*
  3555.              * Keep reporting MOUSE DOWN until we get a new packet
  3556.              * indicating otherwise.
  3557.              */
  3558.             extended_buttons |= sc->extended_buttons;
  3559.         }
  3560.     }
  3561.  
  3562.     if (sc->synhw.capReportsV && nfingers > 1)
  3563.         f[0] = (finger_t) {
  3564.             .x = ((pb->ipacket[3] & 0x10) << 8) |
  3565.                 ((pb->ipacket[1] & 0x0f) << 8) |
  3566.                 (pb->ipacket[4] & 0xfd),
  3567.             .y = ((pb->ipacket[3] & 0x20) << 7) |
  3568.                 ((pb->ipacket[1] & 0xf0) << 4) |
  3569.                 (pb->ipacket[5] & 0xfd),
  3570.             .p = *z & 0xfe,
  3571.             .w = (((pb->ipacket[2] & 0x01) << 2) |
  3572.                 (pb->ipacket[5] & 0x02) |
  3573.                 ((pb->ipacket[4] & 0x02) >> 1)) + 8,
  3574.             .flags = PSM_FINGER_FUZZY,
  3575.         };
  3576.     else
  3577.         f[0] = (finger_t) {
  3578.             .x = ((pb->ipacket[3] & 0x10) << 8) |
  3579.                 ((pb->ipacket[1] & 0x0f) << 8) |
  3580.                 pb->ipacket[4],
  3581.             .y = ((pb->ipacket[3] & 0x20) << 7) |
  3582.                 ((pb->ipacket[1] & 0xf0) << 4) |
  3583.                 pb->ipacket[5],
  3584.             .p = *z,
  3585.             .w = w,
  3586.             .flags = nfingers > 1 ? PSM_FINGER_FUZZY : 0,
  3587.         };
  3588.  
  3589.     /* Ignore hovering and unmeasurable touches */
  3590.     if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2)
  3591.         nfingers = 0;
  3592.  
  3593.     /* Handle ClickPad */
  3594.     if (sc->synhw.capClickPad) {
  3595.         clickpad_pressed = (pb->ipacket[0] ^ pb->ipacket[3]) & 0x01;
  3596.         if (sc->synhw.forcePad) {
  3597.             /*
  3598.              * Forcepads erroneously report button click if there
  3599.              * are 2 or more fingers on the touchpad breaking
  3600.              * multifinger gestures. To workaround this start
  3601.              * reporting a click only after 4 consecutive single
  3602.              * touch packets has been received.
  3603.              * Skip these packets in case more contacts appear.
  3604.              */
  3605.             switch (nfingers) {
  3606.             case 0:
  3607.                 sc->fpcount = 0;
  3608.                 break;
  3609.             case 1:
  3610.                 if (clickpad_pressed && sc->fpcount < INT_MAX)
  3611.                     ++sc->fpcount;
  3612.                 /* FALLTHROUGH */
  3613.             default:
  3614.                 if (!clickpad_pressed)
  3615.                     sc->fpcount = 0;
  3616.                 if (sc->fpcount >= sc->syninfo.window_min)
  3617.                     touchpad_buttons |= MOUSE_BUTTON1DOWN;
  3618.             }
  3619.         } else if (clickpad_pressed)
  3620.             touchpad_buttons |= MOUSE_BUTTON1DOWN;
  3621.     }
  3622.  
  3623.     for (id = 0; id < PSM_FINGERS; id++)
  3624.         if (id >= nfingers)
  3625.             PSM_FINGER_RESET(f[id]);
  3626.  
  3627. #ifdef EVDEV_SUPPORT
  3628.     if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
  3629.         for (id = 0; id < PSM_FINGERS; id++) {
  3630.             if (PSM_FINGER_IS_SET(f[id]))
  3631.                 psm_push_mt_finger(sc, id, &f[id]);
  3632.             else
  3633.                 psm_release_mt_slot(sc->evdev_a, id);
  3634.         }
  3635.         evdev_push_key(sc->evdev_a, BTN_TOUCH, nfingers > 0);
  3636.         evdev_push_nfingers(sc->evdev_a, nfingers);
  3637.         if (nfingers > 0)
  3638.             psm_push_st_finger(sc, &f[0]);
  3639.         else
  3640.             evdev_push_abs(sc->evdev_a, ABS_PRESSURE, 0);
  3641.         evdev_push_mouse_btn(sc->evdev_a, touchpad_buttons);
  3642.         if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
  3643.             evdev_push_key(sc->evdev_a, BTN_FORWARD,
  3644.                 touchpad_buttons & MOUSE_BUTTON4DOWN);
  3645.             evdev_push_key(sc->evdev_a, BTN_BACK,
  3646.                 touchpad_buttons & MOUSE_BUTTON5DOWN);
  3647.         }
  3648.         evdev_sync(sc->evdev_a);
  3649.     }
  3650. #endif
  3651.  
  3652.     ms->button = touchpad_buttons;
  3653.  
  3654.     psmgestures(sc, &f[0], nfingers, ms);
  3655.     for (id = 0; id < PSM_FINGERS; id++)
  3656.         psmsmoother(sc, &f[id], id, ms, x, y);
  3657.  
  3658.     /* Palm detection doesn't terminate the current action. */
  3659.     if (psmpalmdetect(sc, &f[0], nfingers)) {
  3660.         *x = *y = *z = 0;
  3661.         ms->button = ms->obutton;
  3662.         return (0);
  3663.     }
  3664.  
  3665.     ms->button |= extended_buttons | guest_buttons;
  3666.  
  3667. SYNAPTICS_END:
  3668.     /*
  3669.      * Use the extra buttons as a scrollwheel
  3670.      *
  3671.      * XXX X.Org uses the Z axis for vertical wheel only,
  3672.      * whereas moused(8) understands special values to differ
  3673.      * vertical and horizontal wheels.
  3674.      *
  3675.      * xf86-input-mouse needs therefore a small patch to
  3676.      * understand these special values. Without it, the
  3677.      * horizontal wheel acts as a vertical wheel in X.Org.
  3678.      *
  3679.      * That's why the horizontal wheel is disabled by
  3680.      * default for now.
  3681.      */
  3682.     if (ms->button & MOUSE_BUTTON4DOWN)
  3683.         *z = -1;
  3684.     else if (ms->button & MOUSE_BUTTON5DOWN)
  3685.         *z = 1;
  3686.     else if (ms->button & MOUSE_BUTTON6DOWN)
  3687.         *z = -2;
  3688.     else if (ms->button & MOUSE_BUTTON7DOWN)
  3689.         *z = 2;
  3690.     else
  3691.         *z = 0;
  3692.     ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
  3693.         MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
  3694.  
  3695.     return (0);
  3696. }
  3697.  
  3698. static int
  3699. psmpalmdetect(struct psm_softc *sc, finger_t *f, int nfingers)
  3700. {
  3701.     if (!(
  3702.         ((sc->synhw.capMultiFinger || sc->synhw.capAdvancedGestures) &&
  3703.           !sc->synhw.capReportsV && nfingers > 1) ||
  3704.         (sc->synhw.capReportsV && nfingers > 2) ||
  3705.         (sc->synhw.capPalmDetect && f->w <= sc->syninfo.max_width) ||
  3706.         (!sc->synhw.capPalmDetect && f->p <= sc->syninfo.max_pressure) ||
  3707.         (sc->synhw.capPen && f->flags & PSM_FINGER_IS_PEN))) {
  3708.         /*
  3709.          * We consider the packet irrelevant for the current
  3710.          * action when:
  3711.          *  - the width isn't comprised in:
  3712.          *    [1; max_width]
  3713.          *  - the pressure isn't comprised in:
  3714.          *    [min_pressure; max_pressure]
  3715.          *  - pen aren't supported but PSM_FINGER_IS_PEN is set
  3716.          */
  3717.         VLOG(2, (LOG_DEBUG, "synaptics: palm detected! (%d)\n", f->w));
  3718.         return (1);
  3719.     }
  3720.     return (0);
  3721. }
  3722.  
  3723. static void
  3724. psmgestures(struct psm_softc *sc, finger_t *fingers, int nfingers,
  3725.     mousestatus_t *ms)
  3726. {
  3727.     smoother_t *smoother;
  3728.     gesture_t *gest;
  3729.     finger_t *f;
  3730.     int y_ok, center_button, center_x, right_button, right_x, i;
  3731.  
  3732.     f = &fingers[0];
  3733.     smoother = &sc->smoother[0];
  3734.     gest = &sc->gesture;
  3735.  
  3736.     /* Find first active finger. */
  3737.     if (nfingers > 0) {
  3738.         for (i = 0; i < PSM_FINGERS; i++) {
  3739.             if (PSM_FINGER_IS_SET(fingers[i])) {
  3740.                 f = &fingers[i];
  3741.                 smoother = &sc->smoother[i];
  3742.                 break;
  3743.             }
  3744.         }
  3745.     }
  3746.  
  3747.     /*
  3748.      * Check pressure to detect a real wanted action on the
  3749.      * touchpad.
  3750.      */
  3751.     if (f->p >= sc->syninfo.min_pressure) {
  3752.         int x0, y0;
  3753.         int dxp, dyp;
  3754.         int start_x, start_y;
  3755.         int queue_len;
  3756.         int margin_top, margin_right, margin_bottom, margin_left;
  3757.         int window_min, window_max;
  3758.         int vscroll_hor_area, vscroll_ver_area;
  3759.         int two_finger_scroll;
  3760.         int max_x, max_y;
  3761.  
  3762.         /* Read sysctl. */
  3763.         /* XXX Verify values? */
  3764.         margin_top = sc->syninfo.margin_top;
  3765.         margin_right = sc->syninfo.margin_right;
  3766.         margin_bottom = sc->syninfo.margin_bottom;
  3767.         margin_left = sc->syninfo.margin_left;
  3768.         window_min = sc->syninfo.window_min;
  3769.         window_max = sc->syninfo.window_max;
  3770.         vscroll_hor_area = sc->syninfo.vscroll_hor_area;
  3771.         vscroll_ver_area = sc->syninfo.vscroll_ver_area;
  3772.         two_finger_scroll = sc->syninfo.two_finger_scroll;
  3773.         max_x = sc->syninfo.max_x;
  3774.         max_y = sc->syninfo.max_y;
  3775.  
  3776.         /* Read current absolute position. */
  3777.         x0 = f->x;
  3778.         y0 = f->y;
  3779.  
  3780.         /*
  3781.          * Limit the coordinates to the specified margins because
  3782.          * this area isn't very reliable.
  3783.          */
  3784.         if (x0 <= margin_left)
  3785.             x0 = margin_left;
  3786.         else if (x0 >= max_x - margin_right)
  3787.             x0 = max_x - margin_right;
  3788.         if (y0 <= margin_bottom)
  3789.             y0 = margin_bottom;
  3790.         else if (y0 >= max_y - margin_top)
  3791.             y0 = max_y - margin_top;
  3792.  
  3793.         VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
  3794.             x0, y0, f->p, f->w));
  3795.  
  3796.         /*
  3797.          * If the action is just beginning, init the structure and
  3798.          * compute tap timeout.
  3799.          */
  3800.         if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
  3801.             VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
  3802.  
  3803.             /* Initialize queue. */
  3804.             gest->window_min = window_min;
  3805.  
  3806.             /* Reset pressure peak. */
  3807.             gest->zmax = 0;
  3808.  
  3809.             /* Reset fingers count. */
  3810.             gest->fingers_nb = 0;
  3811.  
  3812.             /* Reset virtual scrolling state. */
  3813.             gest->in_vscroll = 0;
  3814.  
  3815.             /* Compute tap timeout. */
  3816.             gest->taptimeout.tv_sec  = tap_timeout / 1000000;
  3817.             gest->taptimeout.tv_usec = tap_timeout % 1000000;
  3818.             timevaladd(&gest->taptimeout, &sc->lastsoftintr);
  3819.  
  3820.             sc->flags |= PSM_FLAGS_FINGERDOWN;
  3821.  
  3822.             /* Smoother has not been reset yet */
  3823.             queue_len = 1;
  3824.             start_x = x0;
  3825.             start_y = y0;
  3826.         } else {
  3827.             queue_len = smoother->queue_len + 1;
  3828.             start_x = smoother->start_x;
  3829.             start_y = smoother->start_y;
  3830.         }
  3831.  
  3832.         /* Process ClickPad softbuttons */
  3833.         if (sc->synhw.capClickPad && ms->button & MOUSE_BUTTON1DOWN) {
  3834.             y_ok = sc->syninfo.softbuttons_y >= 0 ?
  3835.                 start_y < sc->syninfo.softbuttons_y :
  3836.                 start_y > max_y + sc->syninfo.softbuttons_y;
  3837.  
  3838.             center_button = MOUSE_BUTTON2DOWN;
  3839.             center_x = sc->syninfo.softbutton2_x;
  3840.             right_button = MOUSE_BUTTON3DOWN;
  3841.             right_x = sc->syninfo.softbutton3_x;
  3842.  
  3843.             if (center_x > 0 && right_x > 0 && center_x > right_x) {
  3844.                 center_button = MOUSE_BUTTON3DOWN;
  3845.                 center_x = sc->syninfo.softbutton3_x;
  3846.                 right_button = MOUSE_BUTTON2DOWN;
  3847.                 right_x = sc->syninfo.softbutton2_x;
  3848.             }
  3849.  
  3850.             if (right_x > 0 && start_x > right_x && y_ok)
  3851.                 ms->button = (ms->button &
  3852.                     ~MOUSE_BUTTON1DOWN) | right_button;
  3853.             else if (center_x > 0 && start_x > center_x && y_ok)
  3854.                 ms->button = (ms->button &
  3855.                     ~MOUSE_BUTTON1DOWN) | center_button;
  3856.         }
  3857.  
  3858.         /* If in tap-hold, add the recorded button. */
  3859.         if (gest->in_taphold)
  3860.             ms->button |= gest->tap_button;
  3861.  
  3862.         /*
  3863.          * For tap, we keep the maximum number of fingers and the
  3864.          * pressure peak. Also with multiple fingers, we increase
  3865.          * the minimum window.
  3866.          */
  3867.         if (nfingers > 1)
  3868.             gest->window_min = window_max;
  3869.         gest->fingers_nb = imax(nfingers, gest->fingers_nb);
  3870.         gest->zmax = imax(f->p, gest->zmax);
  3871.  
  3872.         /* Do we have enough packets to consider this a gesture? */
  3873.         if (queue_len < gest->window_min)
  3874.             return;
  3875.  
  3876.         /* Is a scrolling action occurring? */
  3877.         if (!gest->in_taphold && !ms->button &&
  3878.             (!gest->in_vscroll || two_finger_scroll)) {
  3879.             /*
  3880.              * A scrolling action must not conflict with a tap
  3881.              * action. Here are the conditions to consider a
  3882.              * scrolling action:
  3883.              *  - the action in a configurable area
  3884.              *  - one of the following:
  3885.              *     . the distance between the last packet and the
  3886.              *       first should be above a configurable minimum
  3887.              *     . tap timed out
  3888.              */
  3889.             dxp = abs(x0 - start_x);
  3890.             dyp = abs(y0 - start_y);
  3891.  
  3892.             if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, >) ||
  3893.                 dxp >= sc->syninfo.vscroll_min_delta ||
  3894.                 dyp >= sc->syninfo.vscroll_min_delta) {
  3895.                 /*
  3896.                  * Handle two finger scrolling.
  3897.                  * Note that we don't rely on fingers_nb
  3898.                  * as that keeps the maximum number of fingers.
  3899.                  */
  3900.                 if (two_finger_scroll) {
  3901.                     if (nfingers == 2) {
  3902.                         gest->in_vscroll +=
  3903.                             dyp ? 2 : 0;
  3904.                         gest->in_vscroll +=
  3905.                             dxp ? 1 : 0;
  3906.                     }
  3907.                 } else {
  3908.                     /* Check for horizontal scrolling. */
  3909.                     if ((vscroll_hor_area > 0 &&
  3910.                         start_y <= vscroll_hor_area) ||
  3911.                         (vscroll_hor_area < 0 &&
  3912.                          start_y >=
  3913.                          max_y + vscroll_hor_area))
  3914.                         gest->in_vscroll += 2;
  3915.  
  3916.                     /* Check for vertical scrolling. */
  3917.                     if ((vscroll_ver_area > 0 &&
  3918.                         start_x <= vscroll_ver_area) ||
  3919.                         (vscroll_ver_area < 0 &&
  3920.                          start_x >=
  3921.                          max_x + vscroll_ver_area))
  3922.                         gest->in_vscroll += 1;
  3923.                 }
  3924.  
  3925.                 /* Avoid conflicts if area overlaps. */
  3926.                 if (gest->in_vscroll >= 3)
  3927.                     gest->in_vscroll =
  3928.                         (dxp > dyp) ? 2 : 1;
  3929.             }
  3930.         }
  3931.         /*
  3932.          * Reset two finger scrolling when the number of fingers
  3933.          * is different from two or any button is pressed.
  3934.          */
  3935.         if (two_finger_scroll && gest->in_vscroll != 0 &&
  3936.             (nfingers != 2 || ms->button))
  3937.             gest->in_vscroll = 0;
  3938.  
  3939.         VLOG(5, (LOG_DEBUG,
  3940.             "synaptics: virtual scrolling: %s "
  3941.             "(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
  3942.             gest->in_vscroll ? "YES" : "NO",
  3943.             gest->in_vscroll, dxp, dyp,
  3944.             gest->fingers_nb));
  3945.  
  3946.     } else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
  3947.         /*
  3948.          * An action is currently taking place but the pressure
  3949.          * dropped under the minimum, putting an end to it.
  3950.          */
  3951.         int taphold_timeout, dx, dy, tap_max_delta;
  3952.  
  3953.         dx = abs(smoother->queue[smoother->queue_cursor].x -
  3954.             smoother->start_x);
  3955.         dy = abs(smoother->queue[smoother->queue_cursor].y -
  3956.             smoother->start_y);
  3957.  
  3958.         /* Max delta is disabled for multi-fingers tap. */
  3959.         if (gest->fingers_nb > 1)
  3960.             tap_max_delta = imax(dx, dy);
  3961.         else
  3962.             tap_max_delta = sc->syninfo.tap_max_delta;
  3963.  
  3964.         sc->flags &= ~PSM_FLAGS_FINGERDOWN;
  3965.  
  3966.         /* Check for tap. */
  3967.         VLOG(3, (LOG_DEBUG,
  3968.             "synaptics: zmax=%d, dx=%d, dy=%d, "
  3969.             "delta=%d, fingers=%d, queue=%d\n",
  3970.             gest->zmax, dx, dy, tap_max_delta, gest->fingers_nb,
  3971.             smoother->queue_len));
  3972.         if (!gest->in_vscroll && gest->zmax >= tap_threshold &&
  3973.             timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=) &&
  3974.             dx <= tap_max_delta && dy <= tap_max_delta &&
  3975.             smoother->queue_len >= sc->syninfo.tap_min_queue) {
  3976.             /*
  3977.              * We have a tap if:
  3978.              *   - the maximum pressure went over tap_threshold
  3979.              *   - the action ended before tap_timeout
  3980.              *
  3981.              * To handle tap-hold, we must delay any button push to
  3982.              * the next action.
  3983.              */
  3984.             if (gest->in_taphold) {
  3985.                 /*
  3986.                  * This is the second and last tap of a
  3987.                  * double tap action, not a tap-hold.
  3988.                  */
  3989.                 gest->in_taphold = 0;
  3990.  
  3991.                 /*
  3992.                  * For double-tap to work:
  3993.                  *   - no button press is emitted (to
  3994.                  *     simulate a button release)
  3995.                  *   - PSM_FLAGS_FINGERDOWN is set to
  3996.                  *     force the next packet to emit a
  3997.                  *     button press)
  3998.                  */
  3999.                 VLOG(2, (LOG_DEBUG,
  4000.                     "synaptics: button RELEASE: %d\n",
  4001.                     gest->tap_button));
  4002.                 sc->flags |= PSM_FLAGS_FINGERDOWN;
  4003.  
  4004.                 /* Schedule button press on next interrupt */
  4005.                 sc->idletimeout.tv_sec  = psmhz > 1 ?
  4006.                     0 : 1;
  4007.                 sc->idletimeout.tv_usec = psmhz > 1 ?
  4008.                     1000000 / psmhz : 0;
  4009.             } else {
  4010.                 /*
  4011.                  * This is the first tap: we set the
  4012.                  * tap-hold state and notify the button
  4013.                  * down event.
  4014.                  */
  4015.                 gest->in_taphold = 1;
  4016.                 taphold_timeout = sc->syninfo.taphold_timeout;
  4017.                 gest->taptimeout.tv_sec  = taphold_timeout /
  4018.                     1000000;
  4019.                 gest->taptimeout.tv_usec = taphold_timeout %
  4020.                     1000000;
  4021.                 sc->idletimeout = gest->taptimeout;
  4022.                 timevaladd(&gest->taptimeout,
  4023.                     &sc->lastsoftintr);
  4024.  
  4025.                 switch (gest->fingers_nb) {
  4026.                 case 3:
  4027.                     gest->tap_button =
  4028.                         MOUSE_BUTTON2DOWN;
  4029.                     break;
  4030.                 case 2:
  4031.                     gest->tap_button =
  4032.                         MOUSE_BUTTON3DOWN;
  4033.                     break;
  4034.                 default:
  4035.                     gest->tap_button =
  4036.                         MOUSE_BUTTON1DOWN;
  4037.                 }
  4038.                 VLOG(2, (LOG_DEBUG,
  4039.                     "synaptics: button PRESS: %d\n",
  4040.                     gest->tap_button));
  4041.                 ms->button |= gest->tap_button;
  4042.             }
  4043.         } else {
  4044.             /*
  4045.              * Not enough pressure or timeout: reset
  4046.              * tap-hold state.
  4047.              */
  4048.             if (gest->in_taphold) {
  4049.                 VLOG(2, (LOG_DEBUG,
  4050.                     "synaptics: button RELEASE: %d\n",
  4051.                     gest->tap_button));
  4052.                 gest->in_taphold = 0;
  4053.             } else {
  4054.                 VLOG(2, (LOG_DEBUG,
  4055.                     "synaptics: not a tap-hold\n"));
  4056.             }
  4057.         }
  4058.     } else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && gest->in_taphold) {
  4059.         /*
  4060.          * For a tap-hold to work, the button must remain down at
  4061.          * least until timeout (where the in_taphold flags will be
  4062.          * cleared) or during the next action.
  4063.          */
  4064.         if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=)) {
  4065.             ms->button |= gest->tap_button;
  4066.         } else {
  4067.             VLOG(2, (LOG_DEBUG, "synaptics: button RELEASE: %d\n",
  4068.                 gest->tap_button));
  4069.             gest->in_taphold = 0;
  4070.         }
  4071.     }
  4072.  
  4073.     return;
  4074. }
  4075.  
  4076. static void
  4077. psmsmoother(struct psm_softc *sc, finger_t *f, int smoother_id,
  4078.     mousestatus_t *ms, int *x, int *y)
  4079. {
  4080.     smoother_t *smoother = &sc->smoother[smoother_id];
  4081.     gesture_t *gest = &(sc->gesture);
  4082.  
  4083.     /*
  4084.      * Check pressure to detect a real wanted action on the
  4085.      * touchpad.
  4086.      */
  4087.     if (f->p >= sc->syninfo.min_pressure) {
  4088.         int x0, y0;
  4089.         int cursor, peer, window;
  4090.         int dx, dy, dxp, dyp;
  4091.         int max_width, max_pressure;
  4092.         int margin_top, margin_right, margin_bottom, margin_left;
  4093.         int na_top, na_right, na_bottom, na_left;
  4094.         int window_min, window_max;
  4095.         int multiplicator;
  4096.         int weight_current, weight_previous, weight_len_squared;
  4097.         int div_min, div_max, div_len;
  4098.         int vscroll_hor_area, vscroll_ver_area;
  4099.         int two_finger_scroll;
  4100.         int max_x, max_y;
  4101.         int len, weight_prev_x, weight_prev_y;
  4102.         int div_max_x, div_max_y, div_x, div_y;
  4103.         int is_fuzzy;
  4104.  
  4105.         /* Read sysctl. */
  4106.         /* XXX Verify values? */
  4107.         max_width = sc->syninfo.max_width;
  4108.         max_pressure = sc->syninfo.max_pressure;
  4109.         margin_top = sc->syninfo.margin_top;
  4110.         margin_right = sc->syninfo.margin_right;
  4111.         margin_bottom = sc->syninfo.margin_bottom;
  4112.         margin_left = sc->syninfo.margin_left;
  4113.         na_top = sc->syninfo.na_top;
  4114.         na_right = sc->syninfo.na_right;
  4115.         na_bottom = sc->syninfo.na_bottom;
  4116.         na_left = sc->syninfo.na_left;
  4117.         window_min = sc->syninfo.window_min;
  4118.         window_max = sc->syninfo.window_max;
  4119.         multiplicator = sc->syninfo.multiplicator;
  4120.         weight_current = sc->syninfo.weight_current;
  4121.         weight_previous = sc->syninfo.weight_previous;
  4122.         weight_len_squared = sc->syninfo.weight_len_squared;
  4123.         div_min = sc->syninfo.div_min;
  4124.         div_max = sc->syninfo.div_max;
  4125.         div_len = sc->syninfo.div_len;
  4126.         vscroll_hor_area = sc->syninfo.vscroll_hor_area;
  4127.         vscroll_ver_area = sc->syninfo.vscroll_ver_area;
  4128.         two_finger_scroll = sc->syninfo.two_finger_scroll;
  4129.         max_x = sc->syninfo.max_x;
  4130.         max_y = sc->syninfo.max_y;
  4131.  
  4132.         is_fuzzy = (f->flags & PSM_FINGER_FUZZY) != 0;
  4133.  
  4134.         /* Read current absolute position. */
  4135.         x0 = f->x;
  4136.         y0 = f->y;
  4137.  
  4138.         /*
  4139.          * Limit the coordinates to the specified margins because
  4140.          * this area isn't very reliable.
  4141.          */
  4142.         if (x0 <= margin_left)
  4143.             x0 = margin_left;
  4144.         else if (x0 >= max_x - margin_right)
  4145.             x0 = max_x - margin_right;
  4146.         if (y0 <= margin_bottom)
  4147.             y0 = margin_bottom;
  4148.         else if (y0 >= max_y - margin_top)
  4149.             y0 = max_y - margin_top;
  4150.  
  4151.         /* If the action is just beginning, init the structure. */
  4152.         if (smoother->active == 0) {
  4153.             VLOG(3, (LOG_DEBUG, "smoother%d: ---\n", smoother_id));
  4154.  
  4155.             /* Store the first point of this action. */
  4156.             smoother->start_x = x0;
  4157.             smoother->start_y = y0;
  4158.             dx = dy = 0;
  4159.  
  4160.             /* Initialize queue. */
  4161.             smoother->queue_cursor = SYNAPTICS_PACKETQUEUE;
  4162.             smoother->queue_len = 0;
  4163.  
  4164.             /* Reset average. */
  4165.             smoother->avg_dx = 0;
  4166.             smoother->avg_dy = 0;
  4167.  
  4168.             /* Reset squelch. */
  4169.             smoother->squelch_x = 0;
  4170.             smoother->squelch_y = 0;
  4171.  
  4172.             /* Activate queue */
  4173.             smoother->active = 1;
  4174.         } else {
  4175.             /* Calculate the current delta. */
  4176.             cursor = smoother->queue_cursor;
  4177.             dx = x0 - smoother->queue[cursor].x;
  4178.             dy = y0 - smoother->queue[cursor].y;
  4179.         }
  4180.  
  4181.         VLOG(3, (LOG_DEBUG, "smoother%d: ipacket: [%d, %d], %d, %d\n",
  4182.             smoother_id, x0, y0, f->p, f->w));
  4183.  
  4184.         /* Queue this new packet. */
  4185.         cursor = SYNAPTICS_QUEUE_CURSOR(smoother->queue_cursor - 1);
  4186.         smoother->queue[cursor].x = x0;
  4187.         smoother->queue[cursor].y = y0;
  4188.         smoother->queue_cursor = cursor;
  4189.         if (smoother->queue_len < SYNAPTICS_PACKETQUEUE)
  4190.             smoother->queue_len++;
  4191.         VLOG(5, (LOG_DEBUG,
  4192.             "smoother%d: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
  4193.             smoother_id, cursor, x0, y0, dx, dy));
  4194.  
  4195.         /* Do we have enough packets to consider this a movement? */
  4196.         if (smoother->queue_len < gest->window_min)
  4197.             return;
  4198.  
  4199.         weight_prev_x = weight_prev_y = weight_previous;
  4200.         div_max_x = div_max_y = div_max;
  4201.  
  4202.         if (gest->in_vscroll) {
  4203.             /* Dividers are different with virtual scrolling. */
  4204.             div_min = sc->syninfo.vscroll_div_min;
  4205.             div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
  4206.         } else {
  4207.             /*
  4208.              * There's a lot of noise in coordinates when
  4209.              * the finger is on the touchpad's borders. When
  4210.              * using this area, we apply a special weight and
  4211.              * div.
  4212.              */
  4213.             if (x0 <= na_left || x0 >= max_x - na_right) {
  4214.                 weight_prev_x = sc->syninfo.weight_previous_na;
  4215.                 div_max_x = sc->syninfo.div_max_na;
  4216.             }
  4217.  
  4218.             if (y0 <= na_bottom || y0 >= max_y - na_top) {
  4219.                 weight_prev_y = sc->syninfo.weight_previous_na;
  4220.                 div_max_y = sc->syninfo.div_max_na;
  4221.             }
  4222.         }
  4223.  
  4224.         /*
  4225.          * Calculate weights for the average operands and
  4226.          * the divisor. Both depend on the distance between
  4227.          * the current packet and a previous one (based on the
  4228.          * window width).
  4229.          */
  4230.         window = imin(smoother->queue_len, window_max);
  4231.         peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
  4232.         dxp = abs(x0 - smoother->queue[peer].x) + 1;
  4233.         dyp = abs(y0 - smoother->queue[peer].y) + 1;
  4234.         len = (dxp * dxp) + (dyp * dyp);
  4235.         weight_prev_x = imin(weight_prev_x,
  4236.             weight_len_squared * weight_prev_x / len);
  4237.         weight_prev_y = imin(weight_prev_y,
  4238.             weight_len_squared * weight_prev_y / len);
  4239.  
  4240.         len = (dxp + dyp) / 2;
  4241.         div_x = div_len * div_max_x / len;
  4242.         div_x = imin(div_max_x, div_x);
  4243.         div_x = imax(div_min, div_x);
  4244.         div_y = div_len * div_max_y / len;
  4245.         div_y = imin(div_max_y, div_y);
  4246.         div_y = imax(div_min, div_y);
  4247.  
  4248.         VLOG(3, (LOG_DEBUG,
  4249.             "smoother%d: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
  4250.             smoother_id, peer, len, weight_prev_x, weight_prev_y,
  4251.             div_x, div_y));
  4252.  
  4253.         /* Compute averages. */
  4254.         smoother->avg_dx =
  4255.             (weight_current * dx * multiplicator +
  4256.              weight_prev_x * smoother->avg_dx) /
  4257.             (weight_current + weight_prev_x);
  4258.  
  4259.         smoother->avg_dy =
  4260.             (weight_current * dy * multiplicator +
  4261.              weight_prev_y * smoother->avg_dy) /
  4262.             (weight_current + weight_prev_y);
  4263.  
  4264.         VLOG(5, (LOG_DEBUG,
  4265.             "smoother%d: avg_dx~=%d, avg_dy~=%d\n", smoother_id,
  4266.             smoother->avg_dx / multiplicator,
  4267.             smoother->avg_dy / multiplicator));
  4268.  
  4269.         /* Use these averages to calculate x & y. */
  4270.         smoother->squelch_x += smoother->avg_dx;
  4271.         dxp = smoother->squelch_x / (div_x * multiplicator);
  4272.         smoother->squelch_x = smoother->squelch_x %
  4273.             (div_x * multiplicator);
  4274.  
  4275.         smoother->squelch_y += smoother->avg_dy;
  4276.         dyp = smoother->squelch_y / (div_y * multiplicator);
  4277.         smoother->squelch_y = smoother->squelch_y %
  4278.             (div_y * multiplicator);
  4279.  
  4280.         switch(gest->in_vscroll) {
  4281.         case 0: /* Pointer movement. */
  4282.             /* On real<->fuzzy finger switch the x/y pos jumps */
  4283.             if (is_fuzzy == smoother->is_fuzzy) {
  4284.                 *x += dxp;
  4285.                 *y += dyp;
  4286.             }
  4287.  
  4288.             VLOG(3, (LOG_DEBUG, "smoother%d: [%d, %d] -> [%d, %d]\n",
  4289.                 smoother_id, dx, dy, dxp, dyp));
  4290.             break;
  4291.         case 1: /* Vertical scrolling. */
  4292.             if (dyp != 0)
  4293.                 ms->button |= (dyp > 0) ?
  4294.                     MOUSE_BUTTON4DOWN : MOUSE_BUTTON5DOWN;
  4295.             break;
  4296.         case 2: /* Horizontal scrolling. */
  4297.             if (dxp != 0)
  4298.                 ms->button |= (dxp > 0) ?
  4299.                     MOUSE_BUTTON7DOWN : MOUSE_BUTTON6DOWN;
  4300.             break;
  4301.         }
  4302.  
  4303.         smoother->is_fuzzy = is_fuzzy;
  4304.  
  4305.     } else {
  4306.         /*
  4307.          * Deactivate queue. Note: We can not just reset queue here
  4308.          * as these values are still used by gesture processor.
  4309.          * So postpone reset till next touch.
  4310.          */
  4311.         smoother->active = 0;
  4312.     }
  4313. }
  4314.  
  4315. static int
  4316. proc_elantech(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
  4317.     int *x, int *y, int *z)
  4318. {
  4319.     static int touchpad_button, trackpoint_button;
  4320.     finger_t fn, f[ELANTECH_MAX_FINGERS];
  4321.     int pkt, id, scale, i, nfingers, mask;
  4322.  
  4323.     if (!elantech_support)
  4324.         return (0);
  4325.  
  4326.     /* Determine packet format and do a sanity check for out of sync packets. */
  4327.     if (ELANTECH_PKT_IS_DEBOUNCE(pb, sc->elanhw.hwversion))
  4328.         pkt = ELANTECH_PKT_NOP;
  4329.     else if (sc->elanhw.hastrackpoint && ELANTECH_PKT_IS_TRACKPOINT(pb))
  4330.         pkt = ELANTECH_PKT_TRACKPOINT;
  4331.     else
  4332.     switch (sc->elanhw.hwversion) {
  4333.     case 2:
  4334.         if (!ELANTECH_PKT_IS_V2(pb))
  4335.             return (-1);
  4336.  
  4337.         pkt = (pb->ipacket[0] & 0xc0) == 0x80 ?
  4338.             ELANTECH_PKT_V2_2FINGER : ELANTECH_PKT_V2_COMMON;
  4339.         break;
  4340.     case 3:
  4341.         if (!ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc) &&
  4342.             !ELANTECH_PKT_IS_V3_TAIL(pb, sc->elanhw.hascrc))
  4343.             return (-1);
  4344.  
  4345.         pkt = ELANTECH_PKT_V3;
  4346.         break;
  4347.     case 4:
  4348.         if (!ELANTECH_PKT_IS_V4(pb, sc->elanhw.hascrc))
  4349.             return (-1);
  4350.  
  4351.         switch (pb->ipacket[3] & 0x03) {
  4352.         case 0x00:
  4353.             pkt = ELANTECH_PKT_V4_STATUS;
  4354.             break;
  4355.         case 0x01:
  4356.             pkt = ELANTECH_PKT_V4_HEAD;
  4357.             break;
  4358.         case 0x02:
  4359.             pkt = ELANTECH_PKT_V4_MOTION;
  4360.             break;
  4361.         default:
  4362.             return (-1);
  4363.         }
  4364.         break;
  4365.     default:
  4366.         return (-1);
  4367.     }
  4368.  
  4369.     VLOG(5, (LOG_DEBUG, "elantech: ipacket format: %d\n", pkt));
  4370.  
  4371.     for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
  4372.         PSM_FINGER_RESET(f[id]);
  4373.  
  4374.     *x = *y = *z = 0;
  4375.     ms->button = ms->obutton;
  4376.  
  4377.     if (sc->syninfo.touchpad_off)
  4378.         return (0);
  4379.  
  4380.     /* Common legend
  4381.      * L: Left mouse button pressed
  4382.      * R: Right mouse button pressed
  4383.      * N: number of fingers on touchpad
  4384.      * X: absolute x value (horizontal)
  4385.      * Y: absolute y value (vertical)
  4386.      * W; width of the finger touch
  4387.      * P: pressure
  4388.      */
  4389.     switch (pkt) {
  4390.     case ELANTECH_PKT_V2_COMMON:    /* HW V2. One/Three finger touch */
  4391.         /*               7   6   5   4   3   2   1   0 (LSB)
  4392.          * -------------------------------------------
  4393.          * ipacket[0]:  N1  N0  W3  W2   .   .   R   L
  4394.          * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
  4395.          * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
  4396.          * ipacket[3]:  N4  VF  W1  W0   .   .   .  B2
  4397.          * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
  4398.          * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
  4399.          * -------------------------------------------
  4400.          * N4: set if more than 3 fingers (only in 3 fingers mode)
  4401.          * VF: a kind of flag? (only on EF123, 0 when finger
  4402.          *     is over one of the buttons, 1 otherwise)
  4403.          * B2: (on EF113 only, 0 otherwise), one button pressed
  4404.          * P & W is not reported on EF113 touchpads
  4405.          */
  4406.         nfingers = (pb->ipacket[0] & 0xc0) >> 6;
  4407.         if (nfingers == 3 && (pb->ipacket[3] & 0x80))
  4408.             nfingers = 4;
  4409.  
  4410.         if (nfingers == 0) {
  4411.             mask = (1 << nfingers) - 1; /* = 0x00 */
  4412.             break;
  4413.         }
  4414.  
  4415.         /* Map 3-rd and 4-th fingers to first finger */
  4416.         mask = (1 << 1) - 1;    /* = 0x01 */
  4417.         f[0] = ELANTECH_FINGER_SET_XYP(pb);
  4418.         if (sc->elanhw.haspressure) {
  4419.             f[0].w = ((pb->ipacket[0] & 0x30) >> 2) |
  4420.                 ((pb->ipacket[3] & 0x30) >> 4);
  4421.         } else {
  4422.             f[0].p = PSM_FINGER_DEFAULT_P;
  4423.             f[0].w = PSM_FINGER_DEFAULT_W;
  4424.         }
  4425.  
  4426.         /*
  4427.          * HW v2 dont report exact finger positions when 3 or more
  4428.          * fingers are on touchpad.
  4429.          */
  4430.         if (nfingers > 2)
  4431.             f[0].flags = PSM_FINGER_FUZZY;
  4432.  
  4433.         break;
  4434.  
  4435.     case ELANTECH_PKT_V2_2FINGER:   /*HW V2. Two finger touch */
  4436.         /*               7   6   5   4   3   2   1   0 (LSB)
  4437.          * -------------------------------------------
  4438.          * ipacket[0]:  N1  N0 AY8 AX8   .   .   R   L
  4439.          * ipacket[1]: AX7 AX6 AX5 AX4 AX3 AX2 AX1 AX0
  4440.          * ipacket[2]: AY7 AY6 AY5 AY4 AY3 AY2 AY1 AY0
  4441.          * ipacket[3]:   .   . BY8 BX8   .   .   .   .
  4442.          * ipacket[4]: BX7 BX6 BX5 BX4 BX3 BX2 BX1 BX0
  4443.          * ipacket[5]: BY7 BY6 BY5 BY4 BY3 BY2 BY1 BY0
  4444.          * -------------------------------------------
  4445.          * AX: lower-left finger absolute x value
  4446.          * AY: lower-left finger absolute y value
  4447.          * BX: upper-right finger absolute x value
  4448.          * BY: upper-right finger absolute y value
  4449.          */
  4450.         nfingers = 2;
  4451.         mask = (1 << nfingers) - 1;
  4452.  
  4453.         for (id = 0; id < imin(2, ELANTECH_MAX_FINGERS); id ++)
  4454.             f[id] = (finger_t) {
  4455.                 .x = (((pb->ipacket[id * 3] & 0x10) << 4) |
  4456.                     pb->ipacket[id * 3 + 1]) << 2,
  4457.                 .y = (((pb->ipacket[id * 3] & 0x20) << 3) |
  4458.                     pb->ipacket[id * 3 + 2]) << 2,
  4459.                 .p = PSM_FINGER_DEFAULT_P,
  4460.                 .w = PSM_FINGER_DEFAULT_W,
  4461.                 /* HW ver.2 sends bounding box */
  4462.                 .flags = PSM_FINGER_FUZZY
  4463.             };
  4464.         break;
  4465.  
  4466.     case ELANTECH_PKT_V3:   /* HW Version 3 */
  4467.         /*               7   6   5   4   3   2   1   0 (LSB)
  4468.          * -------------------------------------------
  4469.          * ipacket[0]:  N1  N0  W3  W2   0   1   R   L
  4470.          * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
  4471.          * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
  4472.          * ipacket[3]:   0   0  W1  W0   0   0   1   0
  4473.          * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
  4474.          * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
  4475.          * -------------------------------------------
  4476.          */
  4477.         nfingers = (pb->ipacket[0] & 0xc0) >> 6;
  4478.         /* Map 3-rd finger to first finger */
  4479.         id = nfingers > 2 ? 0 : nfingers - 1;
  4480.         mask = (1 << (id + 1)) - 1;
  4481.  
  4482.         if (nfingers == 0)
  4483.             break;
  4484.  
  4485.         fn = ELANTECH_FINGER_SET_XYP(pb);
  4486.         fn.w = ((pb->ipacket[0] & 0x30) >> 2) |
  4487.             ((pb->ipacket[3] & 0x30) >> 4);
  4488.  
  4489.         /*
  4490.          * HW v3 dont report exact finger positions when 3 or more
  4491.          * fingers are on touchpad.
  4492.          */
  4493.         if (nfingers > 1)
  4494.             fn.flags = PSM_FINGER_FUZZY;
  4495.  
  4496.         if (nfingers == 2) {
  4497.             if (ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc)) {
  4498.                 sc->elanaction.fingers[0] = fn;
  4499.                 return (0);
  4500.             } else
  4501.                 f[0] = sc->elanaction.fingers[0];
  4502.         }
  4503.         f[id] = fn;
  4504.         break;
  4505.  
  4506.     case ELANTECH_PKT_V4_STATUS:    /* HW Version 4. Status packet */
  4507.         /*               7   6   5   4   3   2   1   0 (LSB)
  4508.          * -------------------------------------------
  4509.          * ipacket[0]:   .   .   .   .   0   1   R   L
  4510.          * ipacket[1]:   .   .   .  F4  F3  F2  F1  F0
  4511.          * ipacket[2]:   .   .   .   .   .   .   .   .
  4512.          * ipacket[3]:   .   .   .   1   0   0   0   0
  4513.          * ipacket[4]:  PL   .   .   .   .   .   .   .
  4514.          * ipacket[5]:   .   .   .   .   .   .   .   .
  4515.          * -------------------------------------------
  4516.          * Fn: finger n is on touchpad
  4517.          * PL: palm
  4518.          * HV ver4 sends a status packet to indicate that the numbers
  4519.          * or identities of the fingers has been changed
  4520.          */
  4521.  
  4522.         mask = pb->ipacket[1] & 0x1f;
  4523.         nfingers = bitcount(mask);
  4524.  
  4525.         if (sc->elanaction.mask_v4wait != 0)
  4526.             VLOG(3, (LOG_DEBUG, "elantech: HW v4 status packet"
  4527.                 " when not all previous head packets received\n"));
  4528.  
  4529.         /* Bitmap of fingers to receive before gesture processing */
  4530.         sc->elanaction.mask_v4wait = mask & ~sc->elanaction.mask;
  4531.  
  4532.         /* Skip "new finger is on touchpad" packets */
  4533.         if (sc->elanaction.mask_v4wait) {
  4534.             sc->elanaction.mask = mask;
  4535.             return (0);
  4536.         }
  4537.  
  4538.         break;
  4539.  
  4540.     case ELANTECH_PKT_V4_HEAD:  /* HW Version 4. Head packet */
  4541.         /*               7   6   5   4   3   2   1   0 (LSB)
  4542.          * -------------------------------------------
  4543.          * ipacket[0]:  W3  W2  W1  W0   0   1   R   L
  4544.          * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
  4545.          * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
  4546.          * ipacket[3]: ID2 ID1 ID0   1   0   0   0   1
  4547.          * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
  4548.          * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
  4549.          * -------------------------------------------
  4550.          * ID: finger id
  4551.          * HW ver 4 sends head packets in two cases:
  4552.          * 1. One finger touch and movement.
  4553.          * 2. Next after status packet to tell new finger positions.
  4554.          */
  4555.         mask = sc->elanaction.mask;
  4556.         nfingers = bitcount(mask);
  4557.         id = ((pb->ipacket[3] & 0xe0) >> 5) - 1;
  4558.         fn = ELANTECH_FINGER_SET_XYP(pb);
  4559.         fn.w =(pb->ipacket[0] & 0xf0) >> 4;
  4560.  
  4561.         if (id < 0)
  4562.             return (0);
  4563.  
  4564.         /* Packet is finger position update. Report it */
  4565.         if (sc->elanaction.mask_v4wait == 0) {
  4566.             if (id < ELANTECH_MAX_FINGERS)
  4567.                 f[id] = fn;
  4568.             break;
  4569.         }
  4570.  
  4571.         /* Remove finger from waiting bitmap and store into context */
  4572.         sc->elanaction.mask_v4wait &= ~(1 << id);
  4573.         if (id < ELANTECH_MAX_FINGERS)
  4574.             sc->elanaction.fingers[id] = fn;
  4575.  
  4576.         /* Wait for other fingers if needed */
  4577.         if (sc->elanaction.mask_v4wait != 0)
  4578.             return (0);
  4579.  
  4580.         /* All new fingers are received. Report them from context */
  4581.         for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
  4582.             if (sc->elanaction.mask & (1 << id))
  4583.                 f[id] =  sc->elanaction.fingers[id];
  4584.  
  4585.         break;
  4586.  
  4587.     case ELANTECH_PKT_V4_MOTION:    /* HW Version 4. Motion packet */
  4588.         /*               7   6   5   4   3   2   1   0 (LSB)
  4589.          * -------------------------------------------
  4590.          * ipacket[0]: ID2 ID1 ID0  OF   0   1   R   L
  4591.          * ipacket[1]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0
  4592.          * ipacket[2]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0
  4593.          * ipacket[3]: ID2 ID1 ID0   1   0   0   1   0
  4594.          * ipacket[4]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0
  4595.          * ipacket[5]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0
  4596.          * -------------------------------------------
  4597.          * OF: delta overflows (> 127 or < -128), in this case
  4598.          *     firmware sends us (delta x / 5) and (delta y / 5)
  4599.          * ID: finger id
  4600.          * DX: delta x (two's complement)
  4601.          * XY: delta y (two's complement)
  4602.          * byte 0 ~ 2 for one finger
  4603.          * byte 3 ~ 5 for another finger
  4604.          */
  4605.         mask = sc->elanaction.mask;
  4606.         nfingers = bitcount(mask);
  4607.  
  4608.         scale = (pb->ipacket[0] & 0x10) ? 5 : 1;
  4609.         for (i = 0; i <= 3; i += 3) {
  4610.             id = ((pb->ipacket[i] & 0xe0) >> 5) - 1;
  4611.             if (id < 0 || id >= ELANTECH_MAX_FINGERS)
  4612.                 continue;
  4613.  
  4614.             if (PSM_FINGER_IS_SET(sc->elanaction.fingers[id])) {
  4615.                 f[id] = sc->elanaction.fingers[id];
  4616.                 f[id].x += imax(-f[id].x,
  4617.                     (signed char)pb->ipacket[i+1] * scale);
  4618.                 f[id].y += imax(-f[id].y,
  4619.                     (signed char)pb->ipacket[i+2] * scale);
  4620.             } else {
  4621.                 VLOG(3, (LOG_DEBUG, "elantech: "
  4622.                     "HW v4 motion packet skipped\n"));
  4623.             }
  4624.         }
  4625.  
  4626.         break;
  4627.  
  4628.     case ELANTECH_PKT_TRACKPOINT:
  4629.         /*               7   6   5   4   3   2   1   0 (LSB)
  4630.          * -------------------------------------------
  4631.          * ipacket[0]:   0   0  SX  SY   0   M   R   L
  4632.          * ipacket[1]: ~SX   0   0   0   0   0   0   0
  4633.          * ipacket[2]: ~SY   0   0   0   0   0   0   0
  4634.          * ipacket[3]:   0   0 ~SY ~SX   0   1   1   0
  4635.          * ipacket[4]:  X7  X6  X5  X4  X3  X2  X1  X0
  4636.          * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
  4637.          * -------------------------------------------
  4638.          * X and Y are written in two's complement spread
  4639.          * over 9 bits with SX/SY the relative top bit and
  4640.          * X7..X0 and Y7..Y0 the lower bits.
  4641.          */
  4642.         *x = (pb->ipacket[0] & 0x20) ?
  4643.             pb->ipacket[4] - 256 : pb->ipacket[4];
  4644.         *y = (pb->ipacket[0] & 0x10) ?
  4645.             pb->ipacket[5] - 256 : pb->ipacket[5];
  4646.  
  4647.         trackpoint_button =
  4648.             ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
  4649.             ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0) |
  4650.             ((pb->ipacket[0] & 0x04) ? MOUSE_BUTTON2DOWN : 0);
  4651. #ifdef EVDEV_SUPPORT
  4652.         evdev_push_rel(sc->evdev_r, REL_X, *x);
  4653.         evdev_push_rel(sc->evdev_r, REL_Y, -*y);
  4654.         evdev_push_mouse_btn(sc->evdev_r, trackpoint_button);
  4655.         evdev_sync(sc->evdev_r);
  4656. #endif
  4657.         ms->button = touchpad_button | trackpoint_button;
  4658.         return (0);
  4659.  
  4660.     case ELANTECH_PKT_NOP:
  4661.         return (0);
  4662.  
  4663.     default:
  4664.         return (-1);
  4665.     }
  4666.  
  4667.     for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
  4668.         if (PSM_FINGER_IS_SET(f[id]))
  4669.             VLOG(2, (LOG_DEBUG, "elantech: "
  4670.                 "finger %d: down [%d, %d], %d, %d, %d\n", id + 1,
  4671.                 f[id].x, f[id].y, f[id].p, f[id].w, f[id].flags));
  4672.  
  4673.     /* Touchpad button presses */
  4674.     if (sc->elanhw.isclickpad) {
  4675.         touchpad_button =
  4676.             ((pb->ipacket[0] & 0x03) ? MOUSE_BUTTON1DOWN : 0);
  4677.     } else {
  4678.         touchpad_button =
  4679.             ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
  4680.             ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0);
  4681.     }
  4682.  
  4683. #ifdef EVDEV_SUPPORT
  4684.     if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
  4685.         for (id = 0; id < ELANTECH_MAX_FINGERS; id++) {
  4686.             if (PSM_FINGER_IS_SET(f[id])) {
  4687.                 psm_push_mt_finger(sc, id, &f[id]);
  4688.                 /* Convert touch width to surface units */
  4689.                 evdev_push_abs(sc->evdev_a, ABS_MT_TOUCH_MAJOR,
  4690.                     f[id].w * sc->elanhw.dptracex);
  4691.             }
  4692.             if (sc->elanaction.mask & (1 << id) &&
  4693.                 !(mask & (1 << id)))
  4694.                 psm_release_mt_slot(sc->evdev_a, id);
  4695.         }
  4696.         evdev_push_key(sc->evdev_a, BTN_TOUCH, nfingers > 0);
  4697.         evdev_push_nfingers(sc->evdev_a, nfingers);
  4698.         if (nfingers > 0) {
  4699.             if (PSM_FINGER_IS_SET(f[0]))
  4700.                 psm_push_st_finger(sc, &f[0]);
  4701.         } else
  4702.             evdev_push_abs(sc->evdev_a, ABS_PRESSURE, 0);
  4703.         evdev_push_mouse_btn(sc->evdev_a, touchpad_button);
  4704.         evdev_sync(sc->evdev_a);
  4705.     }
  4706. #endif
  4707.  
  4708.     ms->button = touchpad_button | trackpoint_button;
  4709.  
  4710.     /* Send finger 1 position to gesture processor */
  4711.     if (PSM_FINGER_IS_SET(f[0]) || PSM_FINGER_IS_SET(f[1]) ||
  4712.         nfingers == 0)
  4713.         psmgestures(sc, &f[0], imin(nfingers, 3), ms);
  4714.     /* Send fingers positions to movement smoothers */
  4715.     for (id = 0; id < PSM_FINGERS; id++)
  4716.         if (PSM_FINGER_IS_SET(f[id]) || !(mask & (1 << id)))
  4717.             psmsmoother(sc, &f[id], id, ms, x, y);
  4718.  
  4719.     /* Store current finger positions in action context */
  4720.     for (id = 0; id < ELANTECH_MAX_FINGERS; id++) {
  4721.         if (PSM_FINGER_IS_SET(f[id]))
  4722.             sc->elanaction.fingers[id] = f[id];
  4723.         if ((sc->elanaction.mask & (1 << id)) && !(mask & (1 << id)))
  4724.             PSM_FINGER_RESET(sc->elanaction.fingers[id]);
  4725.     }
  4726.     sc->elanaction.mask = mask;
  4727.  
  4728.     /* Palm detection doesn't terminate the current action. */
  4729.     if (psmpalmdetect(sc, &f[0], nfingers)) {
  4730.         *x = *y = *z = 0;
  4731.         ms->button = ms->obutton;
  4732.         return (0);
  4733.     }
  4734.  
  4735.     /* Use the extra buttons as a scrollwheel */
  4736.     if (ms->button & MOUSE_BUTTON4DOWN)
  4737.         *z = -1;
  4738.     else if (ms->button & MOUSE_BUTTON5DOWN)
  4739.         *z = 1;
  4740.     else if (ms->button & MOUSE_BUTTON6DOWN)
  4741.         *z = -2;
  4742.     else if (ms->button & MOUSE_BUTTON7DOWN)
  4743.         *z = 2;
  4744.     else
  4745.         *z = 0;
  4746.     ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
  4747.         MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
  4748.  
  4749.     return (0);
  4750. }
  4751.  
  4752. static void
  4753. proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
  4754.     int *x, int *y, int *z)
  4755. {
  4756.     static int butmap_versapad[8] = {
  4757.         0,
  4758.         MOUSE_BUTTON3DOWN,
  4759.         0,
  4760.         MOUSE_BUTTON3DOWN,
  4761.         MOUSE_BUTTON1DOWN,
  4762.         MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
  4763.         MOUSE_BUTTON1DOWN,
  4764.         MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
  4765.     };
  4766.     int c, x0, y0;
  4767.  
  4768.     /* VersaPad PS/2 absolute mode message format
  4769.      *
  4770.      * [packet1]     7   6   5   4   3   2   1   0(LSB)
  4771.      *  ipacket[0]:  1   1   0   A   1   L   T   R
  4772.      *  ipacket[1]: H7  H6  H5  H4  H3  H2  H1  H0
  4773.      *  ipacket[2]: V7  V6  V5  V4  V3  V2  V1  V0
  4774.      *  ipacket[3]:  1   1   1   A   1   L   T   R
  4775.      *  ipacket[4]:V11 V10  V9  V8 H11 H10  H9  H8
  4776.      *  ipacket[5]:  0  P6  P5  P4  P3  P2  P1  P0
  4777.      *
  4778.      * [note]
  4779.      *  R: right physical mouse button (1=on)
  4780.      *  T: touch pad virtual button (1=tapping)
  4781.      *  L: left physical mouse button (1=on)
  4782.      *  A: position data is valid (1=valid)
  4783.      *  H: horizontal data (12bit signed integer. H11 is sign bit.)
  4784.      *  V: vertical data (12bit signed integer. V11 is sign bit.)
  4785.      *  P: pressure data
  4786.      *
  4787.      * Tapping is mapped to MOUSE_BUTTON4.
  4788.      */
  4789.     c = pb->ipacket[0];
  4790.     *x = *y = 0;
  4791.     ms->button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
  4792.     ms->button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
  4793.     if (c & MOUSE_PS2VERSA_IN_USE) {
  4794.         x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8);
  4795.         y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4);
  4796.         if (x0 & 0x800)
  4797.             x0 -= 0x1000;
  4798.         if (y0 & 0x800)
  4799.             y0 -= 0x1000;
  4800.         if (sc->flags & PSM_FLAGS_FINGERDOWN) {
  4801.             *x = sc->xold - x0;
  4802.             *y = y0 - sc->yold;
  4803.             if (*x < 0) /* XXX */
  4804.                 ++*x;
  4805.             else if (*x)
  4806.                 --*x;
  4807.             if (*y < 0)
  4808.                 ++*y;
  4809.             else if (*y)
  4810.                 --*y;
  4811.         } else
  4812.             sc->flags |= PSM_FLAGS_FINGERDOWN;
  4813.         sc->xold = x0;
  4814.         sc->yold = y0;
  4815.     } else
  4816.         sc->flags &= ~PSM_FLAGS_FINGERDOWN;
  4817. }
  4818.  
  4819. static int
  4820. proc_focaltech(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
  4821.            int *x, int *y, int *z) {
  4822.   focaltechhw_t *state = &sc->focalhw;
  4823.   unsigned char *packet = pb->ipacket;
  4824.   int i;
  4825.  
  4826.   // TODO: we should store ALL 5 fingers and then send them
  4827.   // off to the gesture processor
  4828.  
  4829.   // Process the new packet
  4830.   switch(pb->ipacket[0] & 0xf) {
  4831.   case FOCALTECH_PKT_TOUCH: {
  4832.     state->pressed = (packet[0] >> 4) & 1;
  4833.  
  4834.     // Fingers bitmap
  4835.     unsigned char fingers = packet[1];
  4836.    
  4837.     for (i = 0; i < FOCALTECH_MAX_FINGERS; i++) {
  4838.       focalfinger_t *f = &state->fingers[i];
  4839.  
  4840.       f->active = fingers & 1;
  4841.  
  4842.       if (!f->active) {
  4843.     f->valid = false;
  4844.       }
  4845.      
  4846.       fingers >>= 1;
  4847.     }
  4848.   } break;
  4849.   case FOCALTECH_PKT_ABS: {
  4850.     unsigned int finger = (packet[1] >> 4) - 1;
  4851.     if (finger >= FOCALTECH_MAX_FINGERS) {
  4852.       // unsupported finger...
  4853.       VLOG(2, (LOG_DEBUG, "Unsupported finger reported"));
  4854.       break;
  4855.     }
  4856.  
  4857.     state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
  4858.     state->fingers[finger].y = (packet[3] << 8) | packet[4];
  4859.     state->width = packet[5] >> 4;
  4860.     state->fingers[finger].valid = true;
  4861.   } break;
  4862.   case FOCALTECH_PKT_REL: {
  4863.     state->pressed = packet[0] >> 7;
  4864.  
  4865.     int finger1 = ((packet[0] >> 4) & 0x7) - 1;
  4866.     if (finger1 < FOCALTECH_MAX_FINGERS) {
  4867.       state->fingers[finger1].x += (char)packet[1];
  4868.       state->fingers[finger1].y += (char)packet[2];
  4869.     } else {
  4870.       VLOG(2, (LOG_DEBUG, "Unsupported finger reported"));
  4871.       // unsupported finger
  4872.       break;
  4873.     }
  4874.  
  4875.     int finger2 = ((packet[3] >> 4) & 0x7) - 1;
  4876.     if (finger2 < FOCALTECH_MAX_FINGERS) {
  4877.       state->fingers[finger2].x += (char)packet[4];
  4878.       state->fingers[finger2].y += (char)packet[5];
  4879.     }
  4880.   } break;
  4881.   default:
  4882.     // invalid packet
  4883.     VLOG(2, (LOG_DEBUG, "Unsupported packet type %d", pb->ipacket[0] & 0xf));
  4884.   }
  4885.  
  4886.   *x = *y = *z = 0;
  4887.   ms->button = ms->obutton;
  4888.  
  4889.   ms->button = state->pressed;
  4890.  
  4891.   focalfinger_t *fingers = state->fingers;
  4892.  
  4893.   // convert to finger_t
  4894.   finger_t psmfingers[FOCALTECH_MAX_FINGERS];
  4895.   for (i = 0; i < FOCALTECH_MAX_FINGERS; i++) {
  4896.     if (fingers[i].active && fingers[i].valid) {
  4897.       psmfingers[i] = (finger_t) {
  4898.                   .x = fingers[i].x,
  4899.                   .y = fingers[i].y,
  4900.                   .p = PSM_FINGER_DEFAULT_P,
  4901.                   .w = PSM_FINGER_DEFAULT_W,
  4902.       };
  4903.     } else {
  4904.       PSM_FINGER_RESET(psmfingers[i]);
  4905.     }
  4906.   }
  4907.  
  4908.   #ifdef EVDEV_SUPPORT
  4909.   int active_fingers = 0;
  4910.   for(int id = 0; id < 5; id++) {
  4911.     focalfinger_t *finger = &state->fingers[id];
  4912.     bool active = finger->active && finger->valid;
  4913.  
  4914.     evdev_push_abs(sc->evdev_a, ABS_MT_SLOT, id);
  4915.  
  4916.     if (!active)
  4917.       evdev_push_abs(sc->evdev_a, ABS_MT_TRACKING_ID, -1);
  4918.     else
  4919.       evdev_push_abs(sc->evdev_a, ABS_MT_TRACKING_ID, id);
  4920.  
  4921.     if (active) {
  4922.       evdev_push_abs(sc->evdev_a, ABS_MT_POSITION_X, finger->x);
  4923.       evdev_push_abs(sc->evdev_a, ABS_MT_POSITION_Y, FOCALTECH_MAX_Y - finger->y);
  4924.       evdev_push_abs(sc->evdev_a, ABS_TOOL_WIDTH, state->width);
  4925.  
  4926.       active_fingers += 1;
  4927.     }
  4928.   }
  4929.  
  4930.   evdev_push_mt_compat(sc->evdev_a);
  4931.  
  4932.   if (state->pressed)
  4933.     evdev_push_mouse_btn(sc->evdev_a, BTN_LEFT);
  4934.  
  4935.   evdev_sync(sc->evdev_a);
  4936. #endif
  4937.  
  4938.  
  4939.   *x = fingers[0].x;
  4940.   *y = fingers[0].y;
  4941.    
  4942.   // Process gestures on fingers
  4943.   if ((fingers[0].active && fingers[0].valid) ||
  4944.       (fingers[1].active && fingers[1].valid)) {
  4945.     psmgestures(sc, &psmfingers[0], FOCALTECH_MAX_FINGERS, ms);
  4946.   }
  4947.  
  4948.   // Do position smoothing
  4949.   for (i = 0; i < FOCALTECH_MAX_FINGERS; i++)
  4950.     if (PSM_FINGER_IS_SET(psmfingers[i])) {
  4951.       psmsmoother(sc, &psmfingers[i], i, ms, x, y);
  4952.     }
  4953.  
  4954.   if (psmpalmdetect(sc, &psmfingers[0], FOCALTECH_MAX_FINGERS)) {
  4955.     *x = *y = *z = 0;
  4956.     ms->button = ms->obutton;
  4957.     return (0);
  4958.   }
  4959.  
  4960.   /* Use the extra buttons as a scrollwheel */
  4961.   if (ms->button & MOUSE_BUTTON4DOWN)
  4962.     *z = -1;
  4963.   else if (ms->button & MOUSE_BUTTON5DOWN)
  4964.     *z = 1;
  4965.   else if (ms->button & MOUSE_BUTTON6DOWN)
  4966.     *z = -2;
  4967.   else if (ms->button & MOUSE_BUTTON7DOWN)
  4968.     *z = 2;
  4969.   else
  4970.     *z = 0;
  4971.   ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
  4972.           MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
  4973.  
  4974.   return (0);
  4975. }
  4976.  
  4977. static void
  4978. psmsoftintridle(void *arg)
  4979. {
  4980.     struct psm_softc *sc = arg;
  4981.     packetbuf_t *pb;
  4982.  
  4983.     /* Invoke soft handler only when pqueue is empty. Otherwise it will be
  4984.      * invoked from psmintr soon with pqueue filled with real data */
  4985.     if (sc->pqueue_start == sc->pqueue_end &&
  4986.         sc->idlepacket.inputbytes > 0) {
  4987.         /* Grow circular queue backwards to avoid race with psmintr */
  4988.         if (--sc->pqueue_start < 0)
  4989.             sc->pqueue_start = PSM_PACKETQUEUE - 1;
  4990.  
  4991.         pb = &sc->pqueue[sc->pqueue_start];
  4992.         memcpy(pb, &sc->idlepacket, sizeof(packetbuf_t));
  4993.         VLOG(4, (LOG_DEBUG,
  4994.             "psmsoftintridle: %02x %02x %02x %02x %02x %02x\n",
  4995.             pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
  4996.             pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
  4997.  
  4998.         psmsoftintr(arg);
  4999.     }
  5000. }
  5001.  
  5002. static void
  5003. psmsoftintr(void *arg)
  5004. {
  5005.     /*
  5006.      * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
  5007.      * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
  5008.      */
  5009.     static int butmap[8] = {
  5010.         0,
  5011.         MOUSE_BUTTON1DOWN,
  5012.         MOUSE_BUTTON3DOWN,
  5013.         MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
  5014.         MOUSE_BUTTON2DOWN,
  5015.         MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
  5016.         MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
  5017.         MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
  5018.     };
  5019.     struct psm_softc *sc = arg;
  5020.     mousestatus_t ms;
  5021.     packetbuf_t *pb;
  5022.     int x, y, z, c, l, s;
  5023.  
  5024.     VLOG(3, (LOG_DEBUG, "psm%d: model is %d level is %d\n", sc->unit, sc->hw.model, sc->mode.level));
  5025.    
  5026.     getmicrouptime(&sc->lastsoftintr);
  5027.  
  5028.     s = spltty();
  5029.  
  5030.     do {
  5031.         pb = &sc->pqueue[sc->pqueue_start];
  5032.  
  5033.         if (sc->mode.level == PSM_LEVEL_NATIVE)
  5034.             goto next_native;
  5035.  
  5036.         c = pb->ipacket[0];
  5037.         /*
  5038.          * A kludge for Kensington device!
  5039.          * The MSB of the horizontal count appears to be stored in
  5040.          * a strange place.
  5041.          */
  5042.         if (sc->hw.model == MOUSE_MODEL_THINK)
  5043.             pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
  5044.  
  5045.         /* ignore the overflow bits... */
  5046.         x = (c & MOUSE_PS2_XNEG) ?
  5047.             pb->ipacket[1] - 256 : pb->ipacket[1];
  5048.         y = (c & MOUSE_PS2_YNEG) ?
  5049.             pb->ipacket[2] - 256 : pb->ipacket[2];
  5050.         z = 0;
  5051.         ms.obutton = sc->button;      /* previous button state */
  5052.         ms.button = butmap[c & MOUSE_PS2_BUTTONS];
  5053.         /* `tapping' action */
  5054.         if (sc->config & PSM_CONFIG_FORCETAP)
  5055.             ms.button |= ((c & MOUSE_PS2_TAP)) ?
  5056.                 0 : MOUSE_BUTTON4DOWN;
  5057.         timevalclear(&sc->idletimeout);
  5058.         sc->idlepacket.inputbytes = 0;
  5059.  
  5060.         VLOG(3, (LOG_DEBUG, "psm%d: model is %d\n", sc->unit, sc->hw.model));
  5061.        
  5062.         switch (sc->hw.model) {
  5063.         case MOUSE_MODEL_EXPLORER:
  5064.             /*
  5065.              *          b7 b6 b5 b4 b3 b2 b1 b0
  5066.              * byte 1:  oy ox sy sx 1  M  R  L
  5067.              * byte 2:  x  x  x  x  x  x  x  x
  5068.              * byte 3:  y  y  y  y  y  y  y  y
  5069.              * byte 4:  *  *  S2 S1 s  d2 d1 d0
  5070.              *
  5071.              * L, M, R, S1, S2: left, middle, right and side buttons
  5072.              * s: wheel data sign bit
  5073.              * d2-d0: wheel data
  5074.              */
  5075.             z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) ?
  5076.                 (pb->ipacket[3] & 0x0f) - 16 :
  5077.                 (pb->ipacket[3] & 0x0f);
  5078.             ms.button |=
  5079.                 (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) ?
  5080.                 MOUSE_BUTTON4DOWN : 0;
  5081.             ms.button |=
  5082.                 (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) ?
  5083.                 MOUSE_BUTTON5DOWN : 0;
  5084.             break;
  5085.  
  5086.         case MOUSE_MODEL_INTELLI:
  5087.         case MOUSE_MODEL_NET:
  5088.             /* wheel data is in the fourth byte */
  5089.             z = (char)pb->ipacket[3];
  5090.             /*
  5091.              * XXX some mice may send 7 when there is no Z movement?             */
  5092.             if ((z >= 7) || (z <= -7))
  5093.                 z = 0;
  5094.             /* some compatible mice have additional buttons */
  5095.             ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) ?
  5096.                 MOUSE_BUTTON4DOWN : 0;
  5097.             ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) ?
  5098.                 MOUSE_BUTTON5DOWN : 0;
  5099.             break;
  5100.  
  5101.         case MOUSE_MODEL_MOUSEMANPLUS:
  5102.             proc_mmanplus(sc, pb, &ms, &x, &y, &z);
  5103.             break;
  5104.  
  5105.         case MOUSE_MODEL_GLIDEPOINT:
  5106.             /* `tapping' action */
  5107.             ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 :
  5108.                 MOUSE_BUTTON4DOWN;
  5109.             break;
  5110.  
  5111.         case MOUSE_MODEL_NETSCROLL:
  5112.             /*
  5113.              * three additional bytes encode buttons and
  5114.              * wheel events
  5115.              */
  5116.             ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) ?
  5117.                 MOUSE_BUTTON4DOWN : 0;
  5118.             ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) ?
  5119.                 MOUSE_BUTTON5DOWN : 0;
  5120.             z = (pb->ipacket[3] & MOUSE_PS2_XNEG) ?
  5121.                 pb->ipacket[4] - 256 : pb->ipacket[4];
  5122.             break;
  5123.  
  5124.         case MOUSE_MODEL_THINK:
  5125.             /* the fourth button state in the first byte */
  5126.             ms.button |= (c & MOUSE_PS2_TAP) ?
  5127.                 MOUSE_BUTTON4DOWN : 0;
  5128.             break;
  5129.  
  5130.         case MOUSE_MODEL_VERSAPAD:
  5131.             proc_versapad(sc, pb, &ms, &x, &y, &z);
  5132.             c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
  5133.                 ((y < 0) ? MOUSE_PS2_YNEG : 0);
  5134.             break;
  5135.  
  5136.         case MOUSE_MODEL_4D:
  5137.             /*
  5138.              *          b7 b6 b5 b4 b3 b2 b1 b0
  5139.              * byte 1:  s2 d2 s1 d1 1  M  R  L
  5140.              * byte 2:  sx x  x  x  x  x  x  x
  5141.              * byte 3:  sy y  y  y  y  y  y  y
  5142.              *
  5143.              * s1: wheel 1 direction
  5144.              * d1: wheel 1 data
  5145.              * s2: wheel 2 direction
  5146.              * d2: wheel 2 data
  5147.              */
  5148.             x = (pb->ipacket[1] & 0x80) ?
  5149.                 pb->ipacket[1] - 256 : pb->ipacket[1];
  5150.             y = (pb->ipacket[2] & 0x80) ?
  5151.                 pb->ipacket[2] - 256 : pb->ipacket[2];
  5152.             switch (c & MOUSE_4D_WHEELBITS) {
  5153.             case 0x10:
  5154.                 z = 1;
  5155.                 break;
  5156.             case 0x30:
  5157.                 z = -1;
  5158.                 break;
  5159.             case 0x40:  /* XXX 2nd wheel turning right */
  5160.                 z = 2;
  5161.                 break;
  5162.             case 0xc0:  /* XXX 2nd wheel turning left */
  5163.                 z = -2;
  5164.                 break;
  5165.             }
  5166.             break;
  5167.  
  5168.         case MOUSE_MODEL_4DPLUS:
  5169.             if ((x < 16 - 256) && (y < 16 - 256)) {
  5170.                 /*
  5171.                  *          b7 b6 b5 b4 b3 b2 b1 b0
  5172.                  * byte 1:  0  0  1  1  1  M  R  L
  5173.                  * byte 2:  0  0  0  0  1  0  0  0
  5174.                  * byte 3:  0  0  0  0  S  s  d1 d0
  5175.                  *
  5176.                  * L, M, R, S: left, middle, right,
  5177.                  *             and side buttons
  5178.                  * s: wheel data sign bit
  5179.                  * d1-d0: wheel data
  5180.                  */
  5181.                 x = y = 0;
  5182.                 if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
  5183.                     ms.button |= MOUSE_BUTTON4DOWN;
  5184.                 z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) ?
  5185.                     ((pb->ipacket[2] & 0x07) - 8) :
  5186.                     (pb->ipacket[2] & 0x07) ;
  5187.             } else {
  5188.                 /* preserve previous button states */
  5189.                 ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
  5190.             }
  5191.             break;
  5192.  
  5193.         case MOUSE_MODEL_SYNAPTICS:
  5194.             if (proc_synaptics(sc, pb, &ms, &x, &y, &z) != 0) {
  5195.                 VLOG(3, (LOG_DEBUG, "synaptics: "
  5196.                     "packet rejected\n"));
  5197.                 goto next;
  5198.             }
  5199.             break;
  5200.  
  5201.         case MOUSE_MODEL_ELANTECH:
  5202.             if (proc_elantech(sc, pb, &ms, &x, &y, &z) != 0) {
  5203.                 VLOG(3, (LOG_DEBUG, "elantech: "
  5204.                     "packet rejected\n"));
  5205.                 goto next;
  5206.             }
  5207.             break;
  5208.         case MOUSE_MODEL_FOCALTECH:
  5209.           // VLOG(3, (LOG_DEBUG, "psm%d: CALLING FOCALTECH PROC\n", sc->unit));
  5210.           if (proc_focaltech(sc, pb, &ms, &x, &y, &z) != 0) {
  5211.             VLOG(3, (LOG_DEBUG, "psm%d: focaltech: packet rejected\n", sc->unit));
  5212.             goto next;
  5213.           }
  5214.             break;
  5215.  
  5216.         case MOUSE_MODEL_TRACKPOINT:
  5217.         case MOUSE_MODEL_GENERIC:
  5218.           VLOG(3, (LOG_DEBUG, "psm%d: generic packet\n", sc->unit));
  5219.         default:
  5220.             break;
  5221.         }
  5222.  
  5223. #ifdef EVDEV_SUPPORT
  5224.     if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE &&
  5225.         sc->hw.model != MOUSE_MODEL_ELANTECH &&
  5226.         sc->hw.model != MOUSE_MODEL_SYNAPTICS) {
  5227.         evdev_push_rel(sc->evdev_r, EV_REL, x);
  5228.         evdev_push_rel(sc->evdev_r, EV_REL, -y);
  5229.  
  5230.         switch (sc->hw.model) {
  5231.         case MOUSE_MODEL_EXPLORER:
  5232.         case MOUSE_MODEL_INTELLI:
  5233.         case MOUSE_MODEL_NET:
  5234.         case MOUSE_MODEL_NETSCROLL:
  5235.         case MOUSE_MODEL_4DPLUS:
  5236.             evdev_push_rel(sc->evdev_r, REL_WHEEL, -z);
  5237.             break;
  5238.         case MOUSE_MODEL_MOUSEMANPLUS:
  5239.         case MOUSE_MODEL_4D:
  5240.             switch (z) {
  5241.             case 1:
  5242.             case -1:
  5243.                 evdev_push_rel(sc->evdev_r, REL_WHEEL, -z);
  5244.                 break;
  5245.             case 2:
  5246.             case -2:
  5247.                 evdev_push_rel(sc->evdev_r, REL_HWHEEL, z / 2);
  5248.                 break;
  5249.             }
  5250.             break;
  5251.         }
  5252.  
  5253.         evdev_push_mouse_btn(sc->evdev_r, ms.button);
  5254.         evdev_sync(sc->evdev_r);
  5255.     }
  5256. #endif
  5257.  
  5258.     /* scale values */
  5259.     if (sc->mode.accelfactor >= 1) {
  5260.         if (x != 0) {
  5261.             x = x * x / sc->mode.accelfactor;
  5262.             if (x == 0)
  5263.                 x = 1;
  5264.             if (c & MOUSE_PS2_XNEG)
  5265.                 x = -x;
  5266.         }
  5267.         if (y != 0) {
  5268.             y = y * y / sc->mode.accelfactor;
  5269.             if (y == 0)
  5270.                 y = 1;
  5271.             if (c & MOUSE_PS2_YNEG)
  5272.                 y = -y;
  5273.         }
  5274.     }
  5275.  
  5276.     /* Store last packet for reinjection if it has not been set already */
  5277.     if (timevalisset(&sc->idletimeout) && sc->idlepacket.inputbytes == 0)
  5278.         sc->idlepacket = *pb;
  5279.  
  5280.     ms.dx = x;
  5281.     ms.dy = y;
  5282.     ms.dz = z;
  5283.     ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) |
  5284.         (ms.obutton ^ ms.button);
  5285.  
  5286.     pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket);
  5287.  
  5288.     sc->status.flags |= ms.flags;
  5289.     sc->status.dx += ms.dx;
  5290.     sc->status.dy += ms.dy;
  5291.     sc->status.dz += ms.dz;
  5292.     sc->status.button = ms.button;
  5293.     sc->button = ms.button;
  5294.  
  5295. next_native:
  5296.     sc->watchdog = FALSE;
  5297.  
  5298.     /* queue data */
  5299.     if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) {
  5300.         l = imin(pb->inputbytes,
  5301.             sizeof(sc->queue.buf) - sc->queue.tail);
  5302.         bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
  5303.         if (pb->inputbytes > l)
  5304.             bcopy(&pb->ipacket[l], &sc->queue.buf[0],
  5305.                 pb->inputbytes - l);
  5306.         sc->queue.tail = (sc->queue.tail + pb->inputbytes) %
  5307.             sizeof(sc->queue.buf);
  5308.         sc->queue.count += pb->inputbytes;
  5309.     }
  5310.  
  5311. next:
  5312.     pb->inputbytes = 0;
  5313.     if (++sc->pqueue_start >= PSM_PACKETQUEUE)
  5314.         sc->pqueue_start = 0;
  5315.     } while (sc->pqueue_start != sc->pqueue_end);
  5316.  
  5317.     if (sc->state & PSM_ASLP) {
  5318.         sc->state &= ~PSM_ASLP;
  5319.         wakeup(sc);
  5320.     }
  5321.     selwakeuppri(&sc->rsel, PZERO);
  5322.     if (sc->async != NULL) {
  5323.         pgsigio(&sc->async, SIGIO, 0);
  5324.     }
  5325.     sc->state &= ~PSM_SOFTARMED;
  5326.  
  5327.     /* schedule injection of predefined packet after idletimeout
  5328.      * if no data packets have been received from psmintr */
  5329.     if (timevalisset(&sc->idletimeout)) {
  5330.         sc->state |= PSM_SOFTARMED;
  5331.         callout_reset(&sc->softcallout, tvtohz(&sc->idletimeout),
  5332.             psmsoftintridle, sc);
  5333.         VLOG(2, (LOG_DEBUG, "softintr: callout set: %d ticks\n",
  5334.             tvtohz(&sc->idletimeout)));
  5335.     }
  5336.     splx(s);
  5337. }
  5338.  
  5339. static int
  5340. psmpoll(struct cdev *dev, int events, struct thread *td)
  5341. {
  5342.     struct psm_softc *sc = dev->si_drv1;
  5343.     int s;
  5344.     int revents = 0;
  5345.  
  5346.     /* Return true if a mouse event available */
  5347.     s = spltty();
  5348.     if (events & (POLLIN | POLLRDNORM)) {
  5349.         if (sc->queue.count > 0)
  5350.             revents |= events & (POLLIN | POLLRDNORM);
  5351.         else
  5352.             selrecord(td, &sc->rsel);
  5353.     }
  5354.     splx(s);
  5355.  
  5356.     return (revents);
  5357. }
  5358.  
  5359. /* vendor/model specific routines */
  5360.  
  5361. static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
  5362. {
  5363.     if (set_mouse_resolution(kbdc, res) != res)
  5364.         return (FALSE);
  5365.     if (set_mouse_scaling(kbdc, scale) &&
  5366.         set_mouse_scaling(kbdc, scale) &&
  5367.         set_mouse_scaling(kbdc, scale) &&
  5368.         (get_mouse_status(kbdc, status, 0, 3) >= 3))
  5369.         return (TRUE);
  5370.     return (FALSE);
  5371. }
  5372.  
  5373. static int
  5374. mouse_ext_command(KBDC kbdc, int command)
  5375. {
  5376.     int c;
  5377.  
  5378.     c = (command >> 6) & 0x03;
  5379.     if (set_mouse_resolution(kbdc, c) != c)
  5380.         return (FALSE);
  5381.     c = (command >> 4) & 0x03;
  5382.     if (set_mouse_resolution(kbdc, c) != c)
  5383.         return (FALSE);
  5384.     c = (command >> 2) & 0x03;
  5385.     if (set_mouse_resolution(kbdc, c) != c)
  5386.         return (FALSE);
  5387.     c = (command >> 0) & 0x03;
  5388.     if (set_mouse_resolution(kbdc, c) != c)
  5389.         return (FALSE);
  5390.     return (TRUE);
  5391. }
  5392.  
  5393. #ifdef notyet
  5394. /* Logitech MouseMan Cordless II */
  5395. static int
  5396. enable_lcordless(struct psm_softc *sc, enum probearg arg)
  5397. {
  5398.     KBDC kbdc = sc->kbdc;
  5399.     int status[3];
  5400.     int ch;
  5401.  
  5402.     if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 2, status))
  5403.         return (FALSE);
  5404.     if (status[1] == PSMD_RES_HIGH)
  5405.         return (FALSE);
  5406.     ch = (status[0] & 0x07) - 1;    /* channel # */
  5407.     if ((ch <= 0) || (ch > 4))
  5408.         return (FALSE);
  5409.     /*
  5410.      * status[1]: always one?
  5411.      * status[2]: battery status? (0-100)
  5412.      */
  5413.     return (TRUE);
  5414. }
  5415. #endif /* notyet */
  5416.  
  5417. /* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
  5418. static int
  5419. enable_groller(struct psm_softc *sc, enum probearg arg)
  5420. {
  5421.     KBDC kbdc = sc->kbdc;
  5422.     int status[3];
  5423.  
  5424.     /*
  5425.      * The special sequence to enable the fourth button and the
  5426.      * roller. Immediately after this sequence check status bytes.
  5427.      * if the mouse is NetScroll, the second and the third bytes are
  5428.      * '3' and 'D'.
  5429.      */
  5430.  
  5431.     /*
  5432.      * If the mouse is an ordinary PS/2 mouse, the status bytes should
  5433.      * look like the following.
  5434.      *
  5435.      * byte 1 bit 7 always 0
  5436.      *        bit 6 stream mode (0)
  5437.      *        bit 5 disabled (0)
  5438.      *        bit 4 1:1 scaling (0)
  5439.      *        bit 3 always 0
  5440.      *        bit 0-2 button status
  5441.      * byte 2 resolution (PSMD_RES_HIGH)
  5442.      * byte 3 report rate (?)
  5443.      */
  5444.  
  5445.     if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
  5446.         return (FALSE);
  5447.     if ((status[1] != '3') || (status[2] != 'D'))
  5448.         return (FALSE);
  5449.     /* FIXME: SmartScroll Mouse has 5 buttons! XXX */
  5450.     if (arg == PROBE)
  5451.         sc->hw.buttons = 4;
  5452.     return (TRUE);
  5453. }
  5454.  
  5455. /* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
  5456. static int
  5457. enable_gmouse(struct psm_softc *sc, enum probearg arg)
  5458. {
  5459.     KBDC kbdc = sc->kbdc;
  5460.     int status[3];
  5461.  
  5462.     /*
  5463.      * The special sequence to enable the middle, "rubber" button.
  5464.      * Immediately after this sequence check status bytes.
  5465.      * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
  5466.      * the second and the third bytes are '3' and 'U'.
  5467.      * NOTE: NetMouse reports that it has three buttons although it has
  5468.      * two buttons and a rubber button. NetMouse Pro and MIE Mouse
  5469.      * say they have three buttons too and they do have a button on the
  5470.      * side...
  5471.      */
  5472.     if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
  5473.         return (FALSE);
  5474.     if ((status[1] != '3') || (status[2] != 'U'))
  5475.         return (FALSE);
  5476.     return (TRUE);
  5477. }
  5478.  
  5479. /* ALPS GlidePoint */
  5480. static int
  5481. enable_aglide(struct psm_softc *sc, enum probearg arg)
  5482. {
  5483.     KBDC kbdc = sc->kbdc;
  5484.     int status[3];
  5485.  
  5486.     /*
  5487.      * The special sequence to obtain ALPS GlidePoint specific
  5488.      * information. Immediately after this sequence, status bytes will
  5489.      * contain something interesting.
  5490.      * NOTE: ALPS produces several models of GlidePoint. Some of those
  5491.      * do not respond to this sequence, thus, cannot be detected this way.
  5492.      */
  5493.     if (set_mouse_sampling_rate(kbdc, 100) != 100)
  5494.         return (FALSE);
  5495.     if (!mouse_id_proc1(kbdc, PSMD_RES_LOW, 2, status))
  5496.         return (FALSE);
  5497.     if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
  5498.         return (FALSE);
  5499.     return (TRUE);
  5500. }
  5501.  
  5502. /* Kensington ThinkingMouse/Trackball */
  5503. static int
  5504. enable_kmouse(struct psm_softc *sc, enum probearg arg)
  5505. {
  5506.     static u_char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
  5507.     KBDC kbdc = sc->kbdc;
  5508.     int status[3];
  5509.     int id1;
  5510.     int id2;
  5511.     int i;
  5512.  
  5513.     id1 = get_aux_id(kbdc);
  5514.     if (set_mouse_sampling_rate(kbdc, 10) != 10)
  5515.         return (FALSE);
  5516.     /*
  5517.      * The device is now in the native mode? It returns a different
  5518.      * ID value...
  5519.      */
  5520.     id2 = get_aux_id(kbdc);
  5521.     if ((id1 == id2) || (id2 != 2))
  5522.         return (FALSE);
  5523.  
  5524.     if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
  5525.         return (FALSE);
  5526. #if PSM_DEBUG >= 2
  5527.     /* at this point, resolution is LOW, sampling rate is 10/sec */
  5528.     if (get_mouse_status(kbdc, status, 0, 3) < 3)
  5529.         return (FALSE);
  5530. #endif
  5531.  
  5532.     /*
  5533.      * The special sequence to enable the third and fourth buttons.
  5534.      * Otherwise they behave like the first and second buttons.
  5535.      */
  5536.     for (i = 0; i < nitems(rate); ++i)
  5537.         if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
  5538.             return (FALSE);
  5539.  
  5540.     /*
  5541.      * At this point, the device is using default resolution and
  5542.      * sampling rate for the native mode.
  5543.      */
  5544.     if (get_mouse_status(kbdc, status, 0, 3) < 3)
  5545.         return (FALSE);
  5546.     if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
  5547.         return (FALSE);
  5548.  
  5549.     /* the device appears be enabled by this sequence, diable it for now */
  5550.     disable_aux_dev(kbdc);
  5551.     empty_aux_buffer(kbdc, 5);
  5552.  
  5553.     return (TRUE);
  5554. }
  5555.  
  5556. /* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
  5557. static int
  5558. enable_mmanplus(struct psm_softc *sc, enum probearg arg)
  5559. {
  5560.     KBDC kbdc = sc->kbdc;
  5561.     int data[3];
  5562.  
  5563.     /* the special sequence to enable the fourth button and the roller. */
  5564.     /*
  5565.      * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
  5566.      * must be called exactly three times since the last RESET command
  5567.      * before this sequence. XXX
  5568.      */
  5569.     if (!set_mouse_scaling(kbdc, 1))
  5570.         return (FALSE);
  5571.     if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
  5572.         return (FALSE);
  5573.     if (get_mouse_status(kbdc, data, 1, 3) < 3)
  5574.         return (FALSE);
  5575.  
  5576.     /*
  5577.      * PS2++ protocol, packet type 0
  5578.      *
  5579.      *          b7 b6 b5 b4 b3 b2 b1 b0
  5580.      * byte 1:  *  1  p3 p2 1  *  *  *
  5581.      * byte 2:  1  1  p1 p0 m1 m0 1  0
  5582.      * byte 3:  m7 m6 m5 m4 m3 m2 m1 m0
  5583.      *
  5584.      * p3-p0: packet type: 0
  5585.      * m7-m0: model ID: MouseMan+:0x50,
  5586.      *          FirstMouse+:0x51,
  5587.      *          ScrollPoint:0x58...
  5588.      */
  5589.     /* check constant bits */
  5590.     if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
  5591.         return (FALSE);
  5592.     if ((data[1] & 0xc3) != 0xc2)
  5593.         return (FALSE);
  5594.     /* check d3-d0 in byte 2 */
  5595.     if (!MOUSE_PS2PLUS_CHECKBITS(data))
  5596.         return (FALSE);
  5597.     /* check p3-p0 */
  5598.     if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
  5599.         return (FALSE);
  5600.  
  5601.     if (arg == PROBE) {
  5602.         sc->hw.hwid &= 0x00ff;
  5603.         sc->hw.hwid |= data[2] << 8;    /* save model ID */
  5604.     }
  5605.  
  5606.     /*
  5607.      * MouseMan+ (or FirstMouse+) is now in its native mode, in which
  5608.      * the wheel and the fourth button events are encoded in the
  5609.      * special data packet. The mouse may be put in the IntelliMouse mode
  5610.      * if it is initialized by the IntelliMouse's method.
  5611.      */
  5612.     return (TRUE);
  5613. }
  5614.  
  5615. /* MS IntelliMouse Explorer */
  5616. static int
  5617. enable_msexplorer(struct psm_softc *sc, enum probearg arg)
  5618. {
  5619.     KBDC kbdc = sc->kbdc;
  5620.     static u_char rate0[] = { 200, 100, 80, };
  5621.     static u_char rate1[] = { 200, 200, 80, };
  5622.     int id;
  5623.     int i;
  5624.  
  5625.     /*
  5626.      * This is needed for at least A4Tech X-7xx mice - they do not go
  5627.      * straight to Explorer mode, but need to be set to Intelli mode
  5628.      * first.
  5629.      */
  5630.     enable_msintelli(sc, arg);
  5631.  
  5632.     /* the special sequence to enable the extra buttons and the roller. */
  5633.     for (i = 0; i < nitems(rate1); ++i)
  5634.         if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
  5635.             return (FALSE);
  5636.     /* the device will give the genuine ID only after the above sequence */
  5637.     id = get_aux_id(kbdc);
  5638.     if (id != PSM_EXPLORER_ID)
  5639.         return (FALSE);
  5640.  
  5641.     if (arg == PROBE) {
  5642.         sc->hw.buttons = 5; /* IntelliMouse Explorer XXX */
  5643.         sc->hw.hwid = id;
  5644.     }
  5645.  
  5646.     /*
  5647.      * XXX: this is a kludge to fool some KVM switch products
  5648.      * which think they are clever enough to know the 4-byte IntelliMouse
  5649.      * protocol, and assume any other protocols use 3-byte packets.
  5650.      * They don't convey 4-byte data packets from the IntelliMouse Explorer
  5651.      * correctly to the host computer because of this!
  5652.      * The following sequence is actually IntelliMouse's "wake up"
  5653.      * sequence; it will make the KVM think the mouse is IntelliMouse
  5654.      * when it is in fact IntelliMouse Explorer.
  5655.      */
  5656.     for (i = 0; i < nitems(rate0); ++i)
  5657.         if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
  5658.             break;
  5659.     get_aux_id(kbdc);
  5660.  
  5661.     return (TRUE);
  5662. }
  5663.  
  5664. /*
  5665.  * MS IntelliMouse
  5666.  * Logitech MouseMan+ and FirstMouse+ will also respond to this
  5667.  * probe routine and act like IntelliMouse.
  5668.  */
  5669. static int
  5670. enable_msintelli(struct psm_softc *sc, enum probearg arg)
  5671. {
  5672.     KBDC kbdc = sc->kbdc;
  5673.     static u_char rate[] = { 200, 100, 80, };
  5674.     int id;
  5675.     int i;
  5676.  
  5677.     /* the special sequence to enable the third button and the roller. */
  5678.     for (i = 0; i < nitems(rate); ++i)
  5679.         if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
  5680.             return (FALSE);
  5681.     /* the device will give the genuine ID only after the above sequence */
  5682.     id = get_aux_id(kbdc);
  5683.     if (id != PSM_INTELLI_ID)
  5684.         return (FALSE);
  5685.  
  5686.     if (arg == PROBE) {
  5687.         sc->hw.buttons = 3;
  5688.         sc->hw.hwid = id;
  5689.     }
  5690.  
  5691.     return (TRUE);
  5692. }
  5693.  
  5694. /*
  5695.  * A4 Tech 4D Mouse
  5696.  * Newer wheel mice from A4 Tech may use the 4D+ protocol.
  5697.  */
  5698. static int
  5699. enable_4dmouse(struct psm_softc *sc, enum probearg arg)
  5700. {
  5701.     static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
  5702.     KBDC kbdc = sc->kbdc;
  5703.     int id;
  5704.     int i;
  5705.  
  5706.     for (i = 0; i < nitems(rate); ++i)
  5707.         if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
  5708.             return (FALSE);
  5709.     id = get_aux_id(kbdc);
  5710.     /*
  5711.      * WinEasy 4D, 4 Way Scroll 4D: 6
  5712.      * Cable-Free 4D: 8 (4DPLUS)
  5713.      * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
  5714.      */
  5715.     if (id != PSM_4DMOUSE_ID)
  5716.         return (FALSE);
  5717.  
  5718.     if (arg == PROBE) {
  5719.         sc->hw.buttons = 3; /* XXX some 4D mice have 4? */
  5720.         sc->hw.hwid = id;
  5721.     }
  5722.  
  5723.     return (TRUE);
  5724. }
  5725.  
  5726. /*
  5727.  * A4 Tech 4D+ Mouse
  5728.  * Newer wheel mice from A4 Tech seem to use this protocol.
  5729.  * Older models are recognized as either 4D Mouse or IntelliMouse.
  5730.  */
  5731. static int
  5732. enable_4dplus(struct psm_softc *sc, enum probearg arg)
  5733. {
  5734.     KBDC kbdc = sc->kbdc;
  5735.     int id;
  5736.  
  5737.     /*
  5738.      * enable_4dmouse() already issued the following ID sequence...
  5739.     static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
  5740.     int i;
  5741.  
  5742.     for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
  5743.         if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
  5744.             return (FALSE);
  5745.     */
  5746.  
  5747.     id = get_aux_id(kbdc);
  5748.     switch (id) {
  5749.     case PSM_4DPLUS_ID:
  5750.         break;
  5751.     case PSM_4DPLUS_RFSW35_ID:
  5752.         break;
  5753.     default:
  5754.         return (FALSE);
  5755.     }
  5756.  
  5757.     if (arg == PROBE) {
  5758.         sc->hw.buttons = (id == PSM_4DPLUS_ID) ? 4 : 3;
  5759.         sc->hw.hwid = id;
  5760.     }
  5761.  
  5762.     return (TRUE);
  5763. }
  5764.  
  5765. /* Synaptics Touchpad */
  5766. static int
  5767. synaptics_sysctl(SYSCTL_HANDLER_ARGS)
  5768. {
  5769.     struct psm_softc *sc;
  5770.     int error, arg;
  5771.  
  5772.     if (oidp->oid_arg1 == NULL || oidp->oid_arg2 < 0 ||
  5773.         oidp->oid_arg2 > SYNAPTICS_SYSCTL_SOFTBUTTON3_X)
  5774.         return (EINVAL);
  5775.  
  5776.     sc = oidp->oid_arg1;
  5777.  
  5778.     /* Read the current value. */
  5779.     arg = *(int *)((char *)sc + oidp->oid_arg2);
  5780.     error = sysctl_handle_int(oidp, &arg, 0, req);
  5781.  
  5782.     /* Sanity check. */
  5783.     if (error || !req->newptr)
  5784.         return (error);
  5785.  
  5786.     /*
  5787.      * Check that the new value is in the concerned node's range
  5788.      * of values.
  5789.      */
  5790.     switch (oidp->oid_arg2) {
  5791.     case SYNAPTICS_SYSCTL_MIN_PRESSURE:
  5792.     case SYNAPTICS_SYSCTL_MAX_PRESSURE:
  5793.         if (arg < 0 || arg > 255)
  5794.             return (EINVAL);
  5795.         break;
  5796.     case SYNAPTICS_SYSCTL_MAX_WIDTH:
  5797.         if (arg < 4 || arg > 15)
  5798.             return (EINVAL);
  5799.         break;
  5800.     case SYNAPTICS_SYSCTL_MARGIN_TOP:
  5801.     case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
  5802.     case SYNAPTICS_SYSCTL_NA_TOP:
  5803.     case SYNAPTICS_SYSCTL_NA_BOTTOM:
  5804.         if (arg < 0 || arg > sc->synhw.maximumYCoord)
  5805.             return (EINVAL);
  5806.         break;
  5807.     case SYNAPTICS_SYSCTL_SOFTBUTTON2_X:
  5808.     case SYNAPTICS_SYSCTL_SOFTBUTTON3_X:
  5809.         /* Softbuttons is clickpad only feature */
  5810.         if (!sc->synhw.capClickPad && arg != 0)
  5811.             return (EINVAL);
  5812.         /* FALLTHROUGH */
  5813.     case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
  5814.     case SYNAPTICS_SYSCTL_MARGIN_LEFT:
  5815.     case SYNAPTICS_SYSCTL_NA_RIGHT:
  5816.     case SYNAPTICS_SYSCTL_NA_LEFT:
  5817.         if (arg < 0 || arg > sc->synhw.maximumXCoord)
  5818.             return (EINVAL);
  5819.         break;
  5820.     case SYNAPTICS_SYSCTL_WINDOW_MIN:
  5821.     case SYNAPTICS_SYSCTL_WINDOW_MAX:
  5822.     case SYNAPTICS_SYSCTL_TAP_MIN_QUEUE:
  5823.         if (arg < 1 || arg > SYNAPTICS_PACKETQUEUE)
  5824.             return (EINVAL);
  5825.         break;
  5826.     case SYNAPTICS_SYSCTL_MULTIPLICATOR:
  5827.     case SYNAPTICS_SYSCTL_WEIGHT_CURRENT:
  5828.     case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS:
  5829.     case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA:
  5830.     case SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED:
  5831.     case SYNAPTICS_SYSCTL_DIV_MIN:
  5832.     case SYNAPTICS_SYSCTL_DIV_MAX:
  5833.     case SYNAPTICS_SYSCTL_DIV_MAX_NA:
  5834.     case SYNAPTICS_SYSCTL_DIV_LEN:
  5835.     case SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN:
  5836.     case SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX:
  5837.         if (arg < 1)
  5838.             return (EINVAL);
  5839.         break;
  5840.     case SYNAPTICS_SYSCTL_TAP_MAX_DELTA:
  5841.     case SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT:
  5842.     case SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA:
  5843.         if (arg < 0)
  5844.             return (EINVAL);
  5845.         break;
  5846.     case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
  5847.         if (arg < -sc->synhw.maximumXCoord ||
  5848.             arg > sc->synhw.maximumXCoord)
  5849.             return (EINVAL);
  5850.         break;
  5851.     case SYNAPTICS_SYSCTL_SOFTBUTTONS_Y:
  5852.         /* Softbuttons is clickpad only feature */
  5853.         if (!sc->synhw.capClickPad && arg != 0)
  5854.             return (EINVAL);
  5855.         /* FALLTHROUGH */
  5856.     case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
  5857.         if (arg < -sc->synhw.maximumYCoord ||
  5858.             arg > sc->synhw.maximumYCoord)
  5859.             return (EINVAL);
  5860.         break;
  5861.         case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
  5862.         if (arg < 0 || arg > 1)
  5863.             return (EINVAL);
  5864.         break;
  5865.     default:
  5866.         return (EINVAL);
  5867.     }
  5868.  
  5869.     /* Update. */
  5870.     *(int *)((char *)sc + oidp->oid_arg2) = arg;
  5871.  
  5872.     return (error);
  5873. }
  5874.  
  5875. static void
  5876. synaptics_sysctl_create_softbuttons_tree(struct psm_softc *sc)
  5877. {
  5878.     /*
  5879.      * Set predefined sizes for softbuttons.
  5880.      * Values are taken to match HP Pavilion dv6 clickpad drawings
  5881.      * with thin middle softbutton placed on separator
  5882.      */
  5883.  
  5884.     /* hw.psm.synaptics.softbuttons_y */
  5885.     sc->syninfo.softbuttons_y = 1700;
  5886.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  5887.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5888.         "softbuttons_y", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  5889.         sc, SYNAPTICS_SYSCTL_SOFTBUTTONS_Y,
  5890.         synaptics_sysctl, "I",
  5891.         "Vertical size of softbuttons area");
  5892.  
  5893.     /* hw.psm.synaptics.softbutton2_x */
  5894.     sc->syninfo.softbutton2_x = 3100;
  5895.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  5896.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5897.         "softbutton2_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  5898.         sc, SYNAPTICS_SYSCTL_SOFTBUTTON2_X,
  5899.         synaptics_sysctl, "I",
  5900.         "Horisontal position of 2-nd softbutton left edge (0-disable)");
  5901.  
  5902.     /* hw.psm.synaptics.softbutton3_x */
  5903.     sc->syninfo.softbutton3_x = 3900;
  5904.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  5905.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5906.         "softbutton3_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  5907.         sc, SYNAPTICS_SYSCTL_SOFTBUTTON3_X,
  5908.         synaptics_sysctl, "I",
  5909.         "Horisontal position of 3-rd softbutton left edge (0-disable)");
  5910. }
  5911.  
  5912. static void
  5913. synaptics_sysctl_create_tree(struct psm_softc *sc, const char *name,
  5914.     const char *descr)
  5915. {
  5916.  
  5917.     if (sc->syninfo.sysctl_tree != NULL)
  5918.         return;
  5919.  
  5920.     /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
  5921.     sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
  5922.     sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
  5923.         SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, name, CTLFLAG_RD,
  5924.         0, descr);
  5925.  
  5926.     /* hw.psm.synaptics.directional_scrolls. */
  5927.     sc->syninfo.directional_scrolls = 0;
  5928.     SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
  5929.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5930.         "directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY,
  5931.         &sc->syninfo.directional_scrolls, 0,
  5932.         "Enable hardware scrolling pad (if non-zero) or register it as "
  5933.         "extended buttons (if 0)");
  5934.  
  5935.     /* hw.psm.synaptics.max_x. */
  5936.     sc->syninfo.max_x = 6143;
  5937.     SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
  5938.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5939.         "max_x", CTLFLAG_RD|CTLFLAG_ANYBODY,
  5940.         &sc->syninfo.max_x, 0,
  5941.         "Horizontal reporting range");
  5942.  
  5943.     /* hw.psm.synaptics.max_y. */
  5944.     sc->syninfo.max_y = 6143;
  5945.     SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
  5946.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5947.         "max_y", CTLFLAG_RD|CTLFLAG_ANYBODY,
  5948.         &sc->syninfo.max_y, 0,
  5949.         "Vertical reporting range");
  5950.  
  5951.     /*
  5952.      * Turn off two finger scroll if we have a
  5953.      * physical area reserved for scrolling or when
  5954.      * there's no multi finger support.
  5955.      */
  5956.     if (sc->synhw.verticalScroll || (sc->synhw.capMultiFinger == 0 &&
  5957.                      sc->synhw.capAdvancedGestures == 0))
  5958.         sc->syninfo.two_finger_scroll = 0;
  5959.     else
  5960.         sc->syninfo.two_finger_scroll = 1;
  5961.     /* hw.psm.synaptics.two_finger_scroll. */
  5962.     SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
  5963.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5964.         "two_finger_scroll", CTLFLAG_RW|CTLFLAG_ANYBODY,
  5965.         &sc->syninfo.two_finger_scroll, 0,
  5966.         "Enable two finger scrolling");
  5967.  
  5968.     /* hw.psm.synaptics.min_pressure. */
  5969.     sc->syninfo.min_pressure = 32;
  5970.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  5971.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5972.         "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  5973.         sc, SYNAPTICS_SYSCTL_MIN_PRESSURE,
  5974.         synaptics_sysctl, "I",
  5975.         "Minimum pressure required to start an action");
  5976.  
  5977.     /* hw.psm.synaptics.max_pressure. */
  5978.     sc->syninfo.max_pressure = 220;
  5979.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  5980.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5981.         "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  5982.         sc, SYNAPTICS_SYSCTL_MAX_PRESSURE,
  5983.         synaptics_sysctl, "I",
  5984.         "Maximum pressure to detect palm");
  5985.  
  5986.     /* hw.psm.synaptics.max_width. */
  5987.     sc->syninfo.max_width = 10;
  5988.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  5989.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5990.         "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  5991.         sc, SYNAPTICS_SYSCTL_MAX_WIDTH,
  5992.         synaptics_sysctl, "I",
  5993.         "Maximum finger width to detect palm");
  5994.  
  5995.     /* hw.psm.synaptics.top_margin. */
  5996.     sc->syninfo.margin_top = 200;
  5997.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  5998.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  5999.         "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6000.         sc, SYNAPTICS_SYSCTL_MARGIN_TOP,
  6001.         synaptics_sysctl, "I",
  6002.         "Top margin");
  6003.  
  6004.     /* hw.psm.synaptics.right_margin. */
  6005.     sc->syninfo.margin_right = 200;
  6006.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6007.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6008.         "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6009.         sc, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
  6010.         synaptics_sysctl, "I",
  6011.         "Right margin");
  6012.  
  6013.     /* hw.psm.synaptics.bottom_margin. */
  6014.     sc->syninfo.margin_bottom = 200;
  6015.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6016.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6017.         "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6018.         sc, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
  6019.         synaptics_sysctl, "I",
  6020.         "Bottom margin");
  6021.  
  6022.     /* hw.psm.synaptics.left_margin. */
  6023.     sc->syninfo.margin_left = 200;
  6024.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6025.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6026.         "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6027.         sc, SYNAPTICS_SYSCTL_MARGIN_LEFT,
  6028.         synaptics_sysctl, "I",
  6029.         "Left margin");
  6030.  
  6031.     /* hw.psm.synaptics.na_top. */
  6032.     sc->syninfo.na_top = 1783;
  6033.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6034.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6035.         "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6036.         sc, SYNAPTICS_SYSCTL_NA_TOP,
  6037.         synaptics_sysctl, "I",
  6038.         "Top noisy area, where weight_previous_na is used instead "
  6039.         "of weight_previous");
  6040.  
  6041.     /* hw.psm.synaptics.na_right. */
  6042.     sc->syninfo.na_right = 563;
  6043.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6044.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6045.         "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6046.         sc, SYNAPTICS_SYSCTL_NA_RIGHT,
  6047.         synaptics_sysctl, "I",
  6048.         "Right noisy area, where weight_previous_na is used instead "
  6049.         "of weight_previous");
  6050.  
  6051.     /* hw.psm.synaptics.na_bottom. */
  6052.     sc->syninfo.na_bottom = 1408;
  6053.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6054.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6055.         "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6056.         sc, SYNAPTICS_SYSCTL_NA_BOTTOM,
  6057.         synaptics_sysctl, "I",
  6058.         "Bottom noisy area, where weight_previous_na is used instead "
  6059.         "of weight_previous");
  6060.  
  6061.     /* hw.psm.synaptics.na_left. */
  6062.     sc->syninfo.na_left = 1600;
  6063.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6064.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6065.         "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6066.         sc, SYNAPTICS_SYSCTL_NA_LEFT,
  6067.         synaptics_sysctl, "I",
  6068.         "Left noisy area, where weight_previous_na is used instead "
  6069.         "of weight_previous");
  6070.  
  6071.     /* hw.psm.synaptics.window_min. */
  6072.     sc->syninfo.window_min = 4;
  6073.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6074.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6075.         "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6076.         sc, SYNAPTICS_SYSCTL_WINDOW_MIN,
  6077.         synaptics_sysctl, "I",
  6078.         "Minimum window size to start an action");
  6079.  
  6080.     /* hw.psm.synaptics.window_max. */
  6081.     sc->syninfo.window_max = 10;
  6082.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6083.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6084.         "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6085.         sc, SYNAPTICS_SYSCTL_WINDOW_MAX,
  6086.         synaptics_sysctl, "I",
  6087.         "Maximum window size");
  6088.  
  6089.     /* hw.psm.synaptics.multiplicator. */
  6090.     sc->syninfo.multiplicator = 10000;
  6091.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6092.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6093.         "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6094.         sc, SYNAPTICS_SYSCTL_MULTIPLICATOR,
  6095.         synaptics_sysctl, "I",
  6096.         "Multiplicator to increase precision in averages and divisions");
  6097.  
  6098.     /* hw.psm.synaptics.weight_current. */
  6099.     sc->syninfo.weight_current = 3;
  6100.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6101.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6102.         "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6103.         sc, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
  6104.         synaptics_sysctl, "I",
  6105.         "Weight of the current movement in the new average");
  6106.  
  6107.     /* hw.psm.synaptics.weight_previous. */
  6108.     sc->syninfo.weight_previous = 6;
  6109.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6110.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6111.         "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6112.         sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
  6113.         synaptics_sysctl, "I",
  6114.         "Weight of the previous average");
  6115.  
  6116.     /* hw.psm.synaptics.weight_previous_na. */
  6117.     sc->syninfo.weight_previous_na = 20;
  6118.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6119.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6120.         "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6121.         sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
  6122.         synaptics_sysctl, "I",
  6123.         "Weight of the previous average (inside the noisy area)");
  6124.  
  6125.     /* hw.psm.synaptics.weight_len_squared. */
  6126.     sc->syninfo.weight_len_squared = 2000;
  6127.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6128.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6129.         "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6130.         sc, SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
  6131.         synaptics_sysctl, "I",
  6132.         "Length (squared) of segments where weight_previous "
  6133.         "starts to decrease");
  6134.  
  6135.     /* hw.psm.synaptics.div_min. */
  6136.     sc->syninfo.div_min = 9;
  6137.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6138.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6139.         "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6140.         sc, SYNAPTICS_SYSCTL_DIV_MIN,
  6141.         synaptics_sysctl, "I",
  6142.         "Divisor for fast movements");
  6143.  
  6144.     /* hw.psm.synaptics.div_max. */
  6145.     sc->syninfo.div_max = 17;
  6146.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6147.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6148.         "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6149.         sc, SYNAPTICS_SYSCTL_DIV_MAX,
  6150.         synaptics_sysctl, "I",
  6151.         "Divisor for slow movements");
  6152.  
  6153.     /* hw.psm.synaptics.div_max_na. */
  6154.     sc->syninfo.div_max_na = 30;
  6155.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6156.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6157.         "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6158.         sc, SYNAPTICS_SYSCTL_DIV_MAX_NA,
  6159.         synaptics_sysctl, "I",
  6160.         "Divisor with slow movements (inside the noisy area)");
  6161.  
  6162.     /* hw.psm.synaptics.div_len. */
  6163.     sc->syninfo.div_len = 100;
  6164.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6165.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6166.         "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6167.         sc, SYNAPTICS_SYSCTL_DIV_LEN,
  6168.         synaptics_sysctl, "I",
  6169.         "Length of segments where div_max starts to decrease");
  6170.  
  6171.     /* hw.psm.synaptics.tap_max_delta. */
  6172.     sc->syninfo.tap_max_delta = 80;
  6173.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6174.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6175.         "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6176.         sc, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
  6177.         synaptics_sysctl, "I",
  6178.         "Length of segments above which a tap is ignored");
  6179.  
  6180.     /* hw.psm.synaptics.tap_min_queue. */
  6181.     sc->syninfo.tap_min_queue = 2;
  6182.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6183.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6184.         "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6185.         sc, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
  6186.         synaptics_sysctl, "I",
  6187.         "Number of packets required to consider a tap");
  6188.  
  6189.     /* hw.psm.synaptics.taphold_timeout. */
  6190.     sc->gesture.in_taphold = 0;
  6191.     sc->syninfo.taphold_timeout = tap_timeout;
  6192.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6193.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6194.         "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6195.         sc, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
  6196.         synaptics_sysctl, "I",
  6197.         "Maximum elapsed time between two taps to consider a tap-hold "
  6198.         "action");
  6199.  
  6200.     /* hw.psm.synaptics.vscroll_hor_area. */
  6201.     sc->syninfo.vscroll_hor_area = 0; /* 1300 */
  6202.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6203.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6204.         "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6205.         sc, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
  6206.         synaptics_sysctl, "I",
  6207.         "Area reserved for horizontal virtual scrolling");
  6208.  
  6209.     /* hw.psm.synaptics.vscroll_ver_area. */
  6210.     sc->syninfo.vscroll_ver_area = -400 - sc->syninfo.margin_right;
  6211.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6212.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6213.         "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6214.         sc, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
  6215.         synaptics_sysctl, "I",
  6216.         "Area reserved for vertical virtual scrolling");
  6217.  
  6218.     /* hw.psm.synaptics.vscroll_min_delta. */
  6219.     sc->syninfo.vscroll_min_delta = 50;
  6220.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6221.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6222.         "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6223.         sc, SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
  6224.         synaptics_sysctl, "I",
  6225.         "Minimum movement to consider virtual scrolling");
  6226.  
  6227.     /* hw.psm.synaptics.vscroll_div_min. */
  6228.     sc->syninfo.vscroll_div_min = 100;
  6229.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6230.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6231.         "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6232.         sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
  6233.         synaptics_sysctl, "I",
  6234.         "Divisor for fast scrolling");
  6235.  
  6236.     /* hw.psm.synaptics.vscroll_div_min. */
  6237.     sc->syninfo.vscroll_div_max = 150;
  6238.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6239.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6240.         "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6241.         sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
  6242.         synaptics_sysctl, "I",
  6243.         "Divisor for slow scrolling");
  6244.  
  6245.     /* hw.psm.synaptics.touchpad_off. */
  6246.     sc->syninfo.touchpad_off = 0;
  6247.     SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
  6248.         SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
  6249.         "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6250.         sc, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
  6251.         synaptics_sysctl, "I",
  6252.         "Turn off touchpad");
  6253.  
  6254.     sc->syninfo.softbuttons_y = 0;
  6255.     sc->syninfo.softbutton2_x = 0;
  6256.     sc->syninfo.softbutton3_x = 0;
  6257.  
  6258.     /* skip softbuttons sysctl on not clickpads */
  6259.     if (sc->synhw.capClickPad)
  6260.         synaptics_sysctl_create_softbuttons_tree(sc);
  6261. }
  6262.  
  6263. static int
  6264. synaptics_preferred_mode(struct psm_softc *sc) {
  6265.     int mode_byte;
  6266.  
  6267.     /* Check if we are in relative mode */
  6268.     if (sc->hw.model != MOUSE_MODEL_SYNAPTICS) {
  6269.         if (tap_enabled == 0)
  6270.             /*
  6271.              * Disable tap & drag gestures. We use a Mode Byte
  6272.              * and set the DisGest bit (see �2.5 of Synaptics
  6273.              * TouchPad Interfacing Guide).
  6274.              */
  6275.             return (0x04);
  6276.         else
  6277.             /*
  6278.              * Enable tap & drag gestures. We use a Mode Byte
  6279.              * and clear the DisGest bit (see �2.5 of Synaptics
  6280.              * TouchPad Interfacing Guide).
  6281.              */
  6282.             return (0x00);
  6283.     }
  6284.  
  6285.     mode_byte = 0xc4;
  6286.  
  6287.     /* request wmode where available */
  6288.     if (sc->synhw.capExtended)
  6289.         mode_byte |= 1;
  6290.  
  6291.     return mode_byte;
  6292. }
  6293.  
  6294. static void
  6295. synaptics_set_mode(struct psm_softc *sc, int mode_byte) {
  6296.     mouse_ext_command(sc->kbdc, mode_byte);
  6297.  
  6298.     /* "Commit" the Set Mode Byte command sent above. */
  6299.     set_mouse_sampling_rate(sc->kbdc, 20);
  6300.  
  6301.     /*
  6302.      * Enable advanced gestures mode if supported and we are not entering
  6303.      * passthrough or relative mode.
  6304.      */
  6305.     if ((sc->synhw.capAdvancedGestures || sc->synhw.capReportsV) &&
  6306.         sc->hw.model == MOUSE_MODEL_SYNAPTICS && !(mode_byte & (1 << 5))) {
  6307.         mouse_ext_command(sc->kbdc, 3);
  6308.         set_mouse_sampling_rate(sc->kbdc, 0xc8);
  6309.     }
  6310. }
  6311.  
  6312. static int
  6313. enable_synaptics(struct psm_softc *sc, enum probearg arg)
  6314. {
  6315.     device_t psmcpnp;
  6316.     struct psmcpnp_softc *psmcpnp_sc;
  6317.     KBDC kbdc = sc->kbdc;
  6318.     synapticshw_t synhw;
  6319.     int status[3];
  6320.     int buttons, middle_byte;
  6321.  
  6322.     VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n"));
  6323.  
  6324.     /*
  6325.      * Just to be on the safe side: this avoids troubles with
  6326.      * following mouse_ext_command() when the previous command
  6327.      * was PSMC_SET_RESOLUTION. Set Scaling has no effect on
  6328.      * Synaptics Touchpad behaviour.
  6329.      */
  6330.     set_mouse_scaling(kbdc, 1);
  6331.  
  6332.     /* Identify the Touchpad version. */
  6333.     if (mouse_ext_command(kbdc, 0) == 0)
  6334.         return (FALSE);
  6335.     if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6336.         return (FALSE);
  6337.     middle_byte = status[1];
  6338.     if (middle_byte != 0x46 && middle_byte != 0x47)
  6339.         return (FALSE);
  6340.  
  6341.     bzero(&synhw, sizeof(synhw));
  6342.     synhw.infoMinor = status[0];
  6343.     synhw.infoMajor = status[2] & 0x0f;
  6344.  
  6345.     if (verbose >= 2)
  6346.         printf("Synaptics Touchpad v%d.%d\n", synhw.infoMajor,
  6347.             synhw.infoMinor);
  6348.  
  6349.     /*
  6350.      * Most synaptics touchpads return 0x47 in middle byte in responce to
  6351.      * identify command as stated in p.4.4 of "Synaptics PS/2 TouchPad
  6352.      * Interfacing Guide" and we only support v4.0 or better. But some
  6353.      * devices return 0x46 here and have a different numbering scheme.
  6354.      * In the case of 0x46, we allow versions as low as v2.0
  6355.      */
  6356.     if ((middle_byte == 0x47 && synhw.infoMajor < 4) ||
  6357.         (middle_byte == 0x46 && synhw.infoMajor < 2)) {
  6358.         printf("  Unsupported (pre-v4) Touchpad detected\n");
  6359.         return (FALSE);
  6360.     }
  6361.  
  6362.     /* Get the Touchpad model information. */
  6363.     if (mouse_ext_command(kbdc, 3) == 0)
  6364.         return (FALSE);
  6365.     if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6366.         return (FALSE);
  6367.     if ((status[1] & 0x01) != 0) {
  6368.         printf("  Failed to read model information\n");
  6369.         return (FALSE);
  6370.     }
  6371.  
  6372.     synhw.infoRot180   = (status[0] & 0x80) != 0;
  6373.     synhw.infoPortrait = (status[0] & 0x40) != 0;
  6374.     synhw.infoSensor   =  status[0] & 0x3f;
  6375.     synhw.infoHardware = (status[1] & 0xfe) >> 1;
  6376.     synhw.infoNewAbs   = (status[2] & 0x80) != 0;
  6377.     synhw.capPen       = (status[2] & 0x40) != 0;
  6378.     synhw.infoSimplC   = (status[2] & 0x20) != 0;
  6379.     synhw.infoGeometry =  status[2] & 0x0f;
  6380.  
  6381.     if (verbose >= 2) {
  6382.         printf("  Model information:\n");
  6383.         printf("   infoRot180: %d\n", synhw.infoRot180);
  6384.         printf("   infoPortrait: %d\n", synhw.infoPortrait);
  6385.         printf("   infoSensor: %d\n", synhw.infoSensor);
  6386.         printf("   infoHardware: %d\n", synhw.infoHardware);
  6387.         printf("   infoNewAbs: %d\n", synhw.infoNewAbs);
  6388.         printf("   capPen: %d\n", synhw.capPen);
  6389.         printf("   infoSimplC: %d\n", synhw.infoSimplC);
  6390.         printf("   infoGeometry: %d\n", synhw.infoGeometry);
  6391.     }
  6392.  
  6393.     /* Read the extended capability bits. */
  6394.     if (mouse_ext_command(kbdc, 2) == 0)
  6395.         return (FALSE);
  6396.     if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6397.         return (FALSE);
  6398.     if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != middle_byte) {
  6399.         printf("  Failed to read extended capability bits\n");
  6400.         return (FALSE);
  6401.     }
  6402.  
  6403.     psmcpnp = devclass_get_device(devclass_find(PSMCPNP_DRIVER_NAME),
  6404.         sc->unit);
  6405.     psmcpnp_sc = (psmcpnp != NULL) ? device_get_softc(psmcpnp) : NULL;
  6406.  
  6407.     /*
  6408.      * Set conservative defaults for 0x46 middle byte touchpads
  6409.      * as ExtendedQueries return bogus data.
  6410.      */
  6411.     if (middle_byte == 0x46) {
  6412.         synhw.capExtended = 1;
  6413.         synhw.capPalmDetect = 1;
  6414.         synhw.capPassthrough = 1;
  6415.         synhw.capMultiFinger = 1;
  6416.         synhw.maximumXCoord = SYNAPTICS_DEFAULT_MAX_X;
  6417.         synhw.maximumYCoord = SYNAPTICS_DEFAULT_MAX_Y;
  6418.         synhw.minimumXCoord = SYNAPTICS_DEFAULT_MIN_X;
  6419.         synhw.minimumYCoord = SYNAPTICS_DEFAULT_MIN_Y;
  6420.         /* Enable multitouch mode for HW v8.1 devices */
  6421.         if (psmcpnp_sc != NULL &&
  6422.             psmcpnp_sc->type == PSMCPNP_HPSYN81)
  6423.             synhw.capReportsV = 1;
  6424.     } else
  6425.         synhw.capExtended = (status[0] & 0x80) != 0;
  6426.  
  6427.     /* Set the different capabilities when they exist. */
  6428.     buttons = 0;
  6429.     if (synhw.capExtended && middle_byte == 0x47) {
  6430.         synhw.nExtendedQueries = (status[0] & 0x70) >> 4;
  6431.         synhw.capMiddle        = (status[0] & 0x04) != 0;
  6432.         synhw.capPassthrough   = (status[2] & 0x80) != 0;
  6433.         synhw.capLowPower      = (status[2] & 0x40) != 0;
  6434.         synhw.capMultiFingerReport =
  6435.                      (status[2] & 0x20) != 0;
  6436.         synhw.capSleep         = (status[2] & 0x10) != 0;
  6437.         synhw.capFourButtons   = (status[2] & 0x08) != 0;
  6438.         synhw.capBallistics    = (status[2] & 0x04) != 0;
  6439.         synhw.capMultiFinger   = (status[2] & 0x02) != 0;
  6440.         synhw.capPalmDetect    = (status[2] & 0x01) != 0;
  6441.  
  6442.         if (!set_mouse_scaling(kbdc, 1))
  6443.             return (FALSE);
  6444.         if (mouse_ext_command(kbdc, 0x08) == 0)
  6445.             return (FALSE);
  6446.         if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6447.             return (FALSE);
  6448.  
  6449.         if (status[0] != 0 && (status[1] & 0x80) && status[2] != 0) {
  6450.             synhw.infoXupmm = status[0];
  6451.             synhw.infoYupmm = status[2];
  6452.         }
  6453.  
  6454.         if (verbose >= 2) {
  6455.             printf("  Extended capabilities:\n");
  6456.             printf("   capExtended: %d\n", synhw.capExtended);
  6457.             printf("   capMiddle: %d\n", synhw.capMiddle);
  6458.             printf("   nExtendedQueries: %d\n",
  6459.                 synhw.nExtendedQueries);
  6460.             printf("   capPassthrough: %d\n", synhw.capPassthrough);
  6461.             printf("   capLowPower: %d\n", synhw.capLowPower);
  6462.             printf("   capMultiFingerReport: %d\n",
  6463.                 synhw.capMultiFingerReport);
  6464.             printf("   capSleep: %d\n", synhw.capSleep);
  6465.             printf("   capFourButtons: %d\n", synhw.capFourButtons);
  6466.             printf("   capBallistics: %d\n", synhw.capBallistics);
  6467.             printf("   capMultiFinger: %d\n", synhw.capMultiFinger);
  6468.             printf("   capPalmDetect: %d\n", synhw.capPalmDetect);
  6469.             printf("   infoXupmm: %d\n", synhw.infoXupmm);
  6470.             printf("   infoYupmm: %d\n", synhw.infoYupmm);
  6471.         }
  6472.  
  6473.         /*
  6474.          * If nExtendedQueries is 1 or greater, then the TouchPad
  6475.          * supports this number of extended queries. We can load
  6476.          * more information about buttons using query 0x09.
  6477.          */
  6478.         if (synhw.nExtendedQueries >= 1) {
  6479.             if (!set_mouse_scaling(kbdc, 1))
  6480.                 return (FALSE);
  6481.             if (mouse_ext_command(kbdc, 0x09) == 0)
  6482.                 return (FALSE);
  6483.             if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6484.                 return (FALSE);
  6485.             synhw.verticalScroll   = (status[0] & 0x01) != 0;
  6486.             synhw.horizontalScroll = (status[0] & 0x02) != 0;
  6487.             synhw.verticalWheel    = (status[0] & 0x08) != 0;
  6488.             synhw.nExtendedButtons = (status[1] & 0xf0) >> 4;
  6489.             synhw.capEWmode        = (status[0] & 0x04) != 0;
  6490.             if (verbose >= 2) {
  6491.                 printf("  Extended model ID:\n");
  6492.                 printf("   verticalScroll: %d\n",
  6493.                     synhw.verticalScroll);
  6494.                 printf("   horizontalScroll: %d\n",
  6495.                     synhw.horizontalScroll);
  6496.                 printf("   verticalWheel: %d\n",
  6497.                     synhw.verticalWheel);
  6498.                 printf("   nExtendedButtons: %d\n",
  6499.                     synhw.nExtendedButtons);
  6500.                 printf("   capEWmode: %d\n",
  6501.                     synhw.capEWmode);
  6502.             }
  6503.             /*
  6504.              * Add the number of extended buttons to the total
  6505.              * button support count, including the middle button
  6506.              * if capMiddle support bit is set.
  6507.              */
  6508.             buttons = synhw.nExtendedButtons + synhw.capMiddle;
  6509.         } else
  6510.             /*
  6511.              * If the capFourButtons support bit is set,
  6512.              * add a fourth button to the total button count.
  6513.              */
  6514.             buttons = synhw.capFourButtons ? 1 : 0;
  6515.  
  6516.         /* Read the continued capabilities bits. */
  6517.         if (synhw.nExtendedQueries >= 4) {
  6518.             if (!set_mouse_scaling(kbdc, 1))
  6519.                 return (FALSE);
  6520.             if (mouse_ext_command(kbdc, 0x0c) == 0)
  6521.                 return (FALSE);
  6522.             if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6523.                 return (FALSE);
  6524.  
  6525.             synhw.capClickPad         = (status[1] & 0x01) << 1;
  6526.             synhw.capClickPad        |= (status[0] & 0x10) != 0;
  6527.             synhw.capDeluxeLEDs       = (status[1] & 0x02) != 0;
  6528.             synhw.noAbsoluteFilter    = (status[1] & 0x04) != 0;
  6529.             synhw.capReportsV         = (status[1] & 0x08) != 0;
  6530.             synhw.capUniformClickPad  = (status[1] & 0x10) != 0;
  6531.             synhw.capReportsMin       = (status[1] & 0x20) != 0;
  6532.             synhw.capInterTouch       = (status[1] & 0x40) != 0;
  6533.             synhw.capReportsMax       = (status[0] & 0x02) != 0;
  6534.             synhw.capClearPad         = (status[0] & 0x04) != 0;
  6535.             synhw.capAdvancedGestures = (status[0] & 0x08) != 0;
  6536.             synhw.capCoveredPad       = (status[0] & 0x80) != 0;
  6537.  
  6538.             if (synhw.capReportsMax) {
  6539.                 if (!set_mouse_scaling(kbdc, 1))
  6540.                     return (FALSE);
  6541.                 if (mouse_ext_command(kbdc, 0x0d) == 0)
  6542.                     return (FALSE);
  6543.                 if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6544.                     return (FALSE);
  6545.  
  6546.                 synhw.maximumXCoord = (status[0] << 5) |
  6547.                              ((status[1] & 0x0f) << 1);
  6548.                 synhw.maximumYCoord = (status[2] << 5) |
  6549.                              ((status[1] & 0xf0) >> 3);
  6550.             } else {
  6551.                 synhw.maximumXCoord = SYNAPTICS_DEFAULT_MAX_X;
  6552.                 synhw.maximumYCoord = SYNAPTICS_DEFAULT_MAX_Y;
  6553.             }
  6554.  
  6555.             if (synhw.capReportsMin) {
  6556.                 if (!set_mouse_scaling(kbdc, 1))
  6557.                     return (FALSE);
  6558.                 if (mouse_ext_command(kbdc, 0x0f) == 0)
  6559.                     return (FALSE);
  6560.                 if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6561.                     return (FALSE);
  6562.  
  6563.                 synhw.minimumXCoord = (status[0] << 5) |
  6564.                              ((status[1] & 0x0f) << 1);
  6565.                 synhw.minimumYCoord = (status[2] << 5) |
  6566.                              ((status[1] & 0xf0) >> 3);
  6567.             } else {
  6568.                 synhw.minimumXCoord = SYNAPTICS_DEFAULT_MIN_X;
  6569.                 synhw.minimumYCoord = SYNAPTICS_DEFAULT_MIN_Y;
  6570.             }
  6571.  
  6572.             /*
  6573.              * ClickPad properties are not exported through PS/2
  6574.              * protocol. Detection is based on controller's PnP ID.
  6575.              */
  6576.             if (synhw.capClickPad && psmcpnp_sc != NULL) {
  6577.                 switch (psmcpnp_sc->type) {
  6578.                 case PSMCPNP_FORCEPAD:
  6579.                     synhw.forcePad = 1;
  6580.                     break;
  6581.                 default:
  6582.                     break;
  6583.                 }
  6584.             }
  6585.  
  6586.             if (verbose >= 2) {
  6587.                 printf("  Continued capabilities:\n");
  6588.                 printf("   capClickPad: %d\n",
  6589.                        synhw.capClickPad);
  6590.                 printf("   capDeluxeLEDs: %d\n",
  6591.                        synhw.capDeluxeLEDs);
  6592.                 printf("   noAbsoluteFilter: %d\n",
  6593.                        synhw.noAbsoluteFilter);
  6594.                 printf("   capReportsV: %d\n",
  6595.                        synhw.capReportsV);
  6596.                 printf("   capUniformClickPad: %d\n",
  6597.                        synhw.capUniformClickPad);
  6598.                 printf("   capReportsMin: %d\n",
  6599.                        synhw.capReportsMin);
  6600.                 printf("   capInterTouch: %d\n",
  6601.                        synhw.capInterTouch);
  6602.                 printf("   capReportsMax: %d\n",
  6603.                        synhw.capReportsMax);
  6604.                 printf("   capClearPad: %d\n",
  6605.                        synhw.capClearPad);
  6606.                 printf("   capAdvancedGestures: %d\n",
  6607.                        synhw.capAdvancedGestures);
  6608.                 printf("   capCoveredPad: %d\n",
  6609.                        synhw.capCoveredPad);
  6610.                 if (synhw.capReportsMax) {
  6611.                     printf("   maximumXCoord: %d\n",
  6612.                            synhw.maximumXCoord);
  6613.                     printf("   maximumYCoord: %d\n",
  6614.                            synhw.maximumYCoord);
  6615.                 }
  6616.                 if (synhw.capReportsMin) {
  6617.                     printf("   minimumXCoord: %d\n",
  6618.                            synhw.minimumXCoord);
  6619.                     printf("   minimumYCoord: %d\n",
  6620.                            synhw.minimumYCoord);
  6621.                 }
  6622.                 if (synhw.capClickPad) {
  6623.                     printf("   forcePad: %d\n",
  6624.                            synhw.forcePad);
  6625.                 }
  6626.             }
  6627.             buttons += synhw.capClickPad;
  6628.         }
  6629.     }
  6630.  
  6631.     if (verbose >= 2) {
  6632.         if (synhw.capExtended)
  6633.             printf("  Additional Buttons: %d\n", buttons);
  6634.         else
  6635.             printf("  No extended capabilities\n");
  6636.     }
  6637.  
  6638.     /*
  6639.      * Add the default number of 3 buttons to the total
  6640.      * count of supported buttons reported above.
  6641.      */
  6642.     buttons += 3;
  6643.  
  6644.     /*
  6645.      * Read the mode byte.
  6646.      *
  6647.      * XXX: Note the Synaptics documentation also defines the first
  6648.      * byte of the response to this query to be a constant 0x3b, this
  6649.      * does not appear to be true for Touchpads with guest devices.
  6650.      */
  6651.     if (mouse_ext_command(kbdc, 1) == 0)
  6652.         return (FALSE);
  6653.     if (get_mouse_status(kbdc, status, 0, 3) != 3)
  6654.         return (FALSE);
  6655.     if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != middle_byte) {
  6656.         printf("  Failed to read mode byte\n");
  6657.         return (FALSE);
  6658.     }
  6659.  
  6660.     if (arg == PROBE)
  6661.         sc->synhw = synhw;
  6662.     if (!synaptics_support)
  6663.         return (FALSE);
  6664.  
  6665.     /* Set mouse type just now for synaptics_set_mode() */
  6666.     sc->hw.model = MOUSE_MODEL_SYNAPTICS;
  6667.  
  6668.     synaptics_set_mode(sc, synaptics_preferred_mode(sc));
  6669.  
  6670.     if (trackpoint_support && synhw.capPassthrough) {
  6671.         enable_trackpoint(sc, arg);
  6672.     }
  6673.  
  6674.     VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n", buttons));
  6675.  
  6676.     if (arg == PROBE) {
  6677.         /* Create sysctl tree. */
  6678.         synaptics_sysctl_create_tree(sc, "synaptics",
  6679.             "Synaptics TouchPad");
  6680.         sc->hw.buttons = buttons;
  6681.     }
  6682.  
  6683.     return (TRUE);
  6684. }
  6685.  
  6686. static void
  6687. synaptics_passthrough_on(struct psm_softc *sc)
  6688. {
  6689.     VLOG(2, (LOG_NOTICE, "psm: setting pass-through mode.\n"));
  6690.     synaptics_set_mode(sc, synaptics_preferred_mode(sc) | (1 << 5));
  6691. }
  6692.  
  6693. static void
  6694. synaptics_passthrough_off(struct psm_softc *sc)
  6695. {
  6696.     VLOG(2, (LOG_NOTICE, "psm: turning pass-through mode off.\n"));
  6697.     set_mouse_scaling(sc->kbdc, 2);
  6698.     set_mouse_scaling(sc->kbdc, 1);
  6699.     synaptics_set_mode(sc, synaptics_preferred_mode(sc));
  6700. }
  6701.  
  6702. /* IBM/Lenovo TrackPoint */
  6703. static int
  6704. trackpoint_command(struct psm_softc *sc, int cmd, int loc, int val)
  6705. {
  6706.     const int seq[] = { 0xe2, cmd, loc, val };
  6707.     int i;
  6708.  
  6709.     if (sc->synhw.capPassthrough)
  6710.         synaptics_passthrough_on(sc);
  6711.  
  6712.     for (i = 0; i < nitems(seq); i++) {
  6713.         if (sc->synhw.capPassthrough &&
  6714.             (seq[i] == 0xff || seq[i] == 0xe7))
  6715.             if (send_aux_command(sc->kbdc, 0xe7) != PSM_ACK) {
  6716.                 synaptics_passthrough_off(sc);
  6717.                 return (EIO);
  6718.             }
  6719.         if (send_aux_command(sc->kbdc, seq[i]) != PSM_ACK) {
  6720.             if (sc->synhw.capPassthrough)
  6721.                 synaptics_passthrough_off(sc);
  6722.             return (EIO);
  6723.         }
  6724.     }
  6725.  
  6726.     if (sc->synhw.capPassthrough)
  6727.         synaptics_passthrough_off(sc);
  6728.  
  6729.     return (0);
  6730. }
  6731.  
  6732. #define PSM_TPINFO(x)   offsetof(struct psm_softc, tpinfo.x)
  6733. #define TPMASK      0
  6734. #define TPLOC       1
  6735. #define TPINFO      2
  6736.  
  6737. static int
  6738. trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
  6739. {
  6740.     static const int data[][3] = {
  6741.         { 0x00, 0x4a, PSM_TPINFO(sensitivity) },
  6742.         { 0x00, 0x4d, PSM_TPINFO(inertia) },
  6743.         { 0x00, 0x60, PSM_TPINFO(uplateau) },
  6744.         { 0x00, 0x57, PSM_TPINFO(reach) },
  6745.         { 0x00, 0x58, PSM_TPINFO(draghys) },
  6746.         { 0x00, 0x59, PSM_TPINFO(mindrag) },
  6747.         { 0x00, 0x5a, PSM_TPINFO(upthresh) },
  6748.         { 0x00, 0x5c, PSM_TPINFO(threshold) },
  6749.         { 0x00, 0x5d, PSM_TPINFO(jenks) },
  6750.         { 0x00, 0x5e, PSM_TPINFO(ztime) },
  6751.         { 0x01, 0x2c, PSM_TPINFO(pts) },
  6752.         { 0x08, 0x2d, PSM_TPINFO(skipback) }
  6753.     };
  6754.     struct psm_softc *sc;
  6755.     int error, newval, *oldvalp;
  6756.     const int *tp;
  6757.  
  6758.     if (arg1 == NULL || arg2 < 0 || arg2 >= nitems(data))
  6759.         return (EINVAL);
  6760.     sc = arg1;
  6761.     tp = data[arg2];
  6762.     oldvalp = (int *)((intptr_t)sc + tp[TPINFO]);
  6763.     newval = *oldvalp;
  6764.     error = sysctl_handle_int(oidp, &newval, 0, req);
  6765.     if (error != 0)
  6766.         return (error);
  6767.     if (newval == *oldvalp)
  6768.         return (0);
  6769.     if (newval < 0 || newval > (tp[TPMASK] == 0 ? 255 : 1))
  6770.         return (EINVAL);
  6771.     error = trackpoint_command(sc, tp[TPMASK] == 0 ? 0x81 : 0x47,
  6772.         tp[TPLOC], tp[TPMASK] == 0 ? newval : tp[TPMASK]);
  6773.     if (error != 0)
  6774.         return (error);
  6775.     *oldvalp = newval;
  6776.  
  6777.     return (0);
  6778. }
  6779.  
  6780. static void
  6781. trackpoint_sysctl_create_tree(struct psm_softc *sc)
  6782. {
  6783.  
  6784.     if (sc->tpinfo.sysctl_tree != NULL)
  6785.         return;
  6786.  
  6787.     /* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */
  6788.     sysctl_ctx_init(&sc->tpinfo.sysctl_ctx);
  6789.     sc->tpinfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx,
  6790.         SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD,
  6791.         0, "IBM/Lenovo TrackPoint");
  6792.  
  6793.     /* hw.psm.trackpoint.sensitivity */
  6794.     sc->tpinfo.sensitivity = 0x80;
  6795.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6796.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6797.         "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6798.         sc, TRACKPOINT_SYSCTL_SENSITIVITY,
  6799.         trackpoint_sysctl, "I",
  6800.         "Sensitivity");
  6801.  
  6802.     /* hw.psm.trackpoint.negative_inertia */
  6803.     sc->tpinfo.inertia = 0x06;
  6804.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6805.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6806.         "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6807.         sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
  6808.         trackpoint_sysctl, "I",
  6809.         "Negative inertia factor");
  6810.  
  6811.     /* hw.psm.trackpoint.upper_plateau */
  6812.     sc->tpinfo.uplateau = 0x61;
  6813.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6814.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6815.         "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6816.         sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU,
  6817.         trackpoint_sysctl, "I",
  6818.         "Transfer function upper plateau speed");
  6819.  
  6820.     /* hw.psm.trackpoint.backup_range */
  6821.     sc->tpinfo.reach = 0x0a;
  6822.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6823.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6824.         "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6825.         sc, TRACKPOINT_SYSCTL_BACKUP_RANGE,
  6826.         trackpoint_sysctl, "I",
  6827.         "Backup range");
  6828.  
  6829.     /* hw.psm.trackpoint.drag_hysteresis */
  6830.     sc->tpinfo.draghys = 0xff;
  6831.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6832.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6833.         "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6834.         sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
  6835.         trackpoint_sysctl, "I",
  6836.         "Drag hysteresis");
  6837.  
  6838.     /* hw.psm.trackpoint.minimum_drag */
  6839.     sc->tpinfo.mindrag = 0x14;
  6840.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6841.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6842.         "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6843.         sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG,
  6844.         trackpoint_sysctl, "I",
  6845.         "Minimum drag");
  6846.  
  6847.     /* hw.psm.trackpoint.up_threshold */
  6848.     sc->tpinfo.upthresh = 0xff;
  6849.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6850.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6851.         "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6852.         sc, TRACKPOINT_SYSCTL_UP_THRESHOLD,
  6853.         trackpoint_sysctl, "I",
  6854.         "Up threshold for release");
  6855.  
  6856.     /* hw.psm.trackpoint.threshold */
  6857.     sc->tpinfo.threshold = 0x08;
  6858.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6859.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6860.         "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6861.         sc, TRACKPOINT_SYSCTL_THRESHOLD,
  6862.         trackpoint_sysctl, "I",
  6863.         "Threshold");
  6864.  
  6865.     /* hw.psm.trackpoint.jenks_curvature */
  6866.     sc->tpinfo.jenks = 0x87;
  6867.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6868.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6869.         "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6870.         sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE,
  6871.         trackpoint_sysctl, "I",
  6872.         "Jenks curvature");
  6873.  
  6874.     /* hw.psm.trackpoint.z_time */
  6875.     sc->tpinfo.ztime = 0x26;
  6876.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6877.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6878.         "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6879.         sc, TRACKPOINT_SYSCTL_Z_TIME,
  6880.         trackpoint_sysctl, "I",
  6881.         "Z time constant");
  6882.  
  6883.     /* hw.psm.trackpoint.press_to_select */
  6884.     sc->tpinfo.pts = 0x00;
  6885.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6886.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6887.         "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6888.         sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
  6889.         trackpoint_sysctl, "I",
  6890.         "Press to Select");
  6891.  
  6892.     /* hw.psm.trackpoint.skip_backups */
  6893.     sc->tpinfo.skipback = 0x00;
  6894.     SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
  6895.         SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
  6896.         "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
  6897.         sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS,
  6898.         trackpoint_sysctl, "I",
  6899.         "Skip backups from drags");
  6900. }
  6901.  
  6902. static void
  6903. set_trackpoint_parameters(struct psm_softc *sc)
  6904. {
  6905.     trackpoint_command(sc, 0x81, 0x4a, sc->tpinfo.sensitivity);
  6906.     trackpoint_command(sc, 0x81, 0x60, sc->tpinfo.uplateau);
  6907.     trackpoint_command(sc, 0x81, 0x4d, sc->tpinfo.inertia);
  6908.     trackpoint_command(sc, 0x81, 0x57, sc->tpinfo.reach);
  6909.     trackpoint_command(sc, 0x81, 0x58, sc->tpinfo.draghys);
  6910.     trackpoint_command(sc, 0x81, 0x59, sc->tpinfo.mindrag);
  6911.     trackpoint_command(sc, 0x81, 0x5a, sc->tpinfo.upthresh);
  6912.     trackpoint_command(sc, 0x81, 0x5c, sc->tpinfo.threshold);
  6913.     trackpoint_command(sc, 0x81, 0x5d, sc->tpinfo.jenks);
  6914.     trackpoint_command(sc, 0x81, 0x5e, sc->tpinfo.ztime);
  6915.     if (sc->tpinfo.pts == 0x01)
  6916.         trackpoint_command(sc, 0x47, 0x2c, 0x01);
  6917.     if (sc->tpinfo.skipback == 0x01)
  6918.         trackpoint_command(sc, 0x47, 0x2d, 0x08);
  6919. }
  6920.  
  6921. static int
  6922. enable_trackpoint(struct psm_softc *sc, enum probearg arg)
  6923. {
  6924.     KBDC kbdc = sc->kbdc;
  6925.     int id;
  6926.  
  6927.     /*
  6928.      * If called from enable_synaptics(), make sure that passthrough
  6929.      * mode is enabled so we can reach the trackpoint.
  6930.      * However, passthrough mode must be disabled before setting the
  6931.      * trackpoint parameters, as rackpoint_command() enables and disables
  6932.      * passthrough mode on its own.
  6933.      */
  6934.     if (sc->synhw.capPassthrough)
  6935.         synaptics_passthrough_on(sc);
  6936.  
  6937.     if (send_aux_command(kbdc, 0xe1) != PSM_ACK ||
  6938.         read_aux_data(kbdc) != 0x01)
  6939.         goto no_trackpoint;
  6940.     id = read_aux_data(kbdc);
  6941.     if (id < 0x01)
  6942.         goto no_trackpoint;
  6943.     if (arg == PROBE)
  6944.         sc->tphw = id;
  6945.     if (!trackpoint_support)
  6946.         goto no_trackpoint;
  6947.  
  6948.     if (sc->synhw.capPassthrough)
  6949.         synaptics_passthrough_off(sc);
  6950.  
  6951.     if (arg == PROBE) {
  6952.         trackpoint_sysctl_create_tree(sc);
  6953.         /*
  6954.          * Don't overwrite hwid and buttons when we are
  6955.          * a guest device.
  6956.          */
  6957.         if (!sc->synhw.capPassthrough) {
  6958.             sc->hw.hwid = id;
  6959.             sc->hw.buttons = 3;
  6960.         }
  6961.     }
  6962.  
  6963.     set_trackpoint_parameters(sc);
  6964.  
  6965.     return (TRUE);
  6966.  
  6967. no_trackpoint:
  6968.     if (sc->synhw.capPassthrough)
  6969.         synaptics_passthrough_off(sc);
  6970.  
  6971.     return (FALSE);
  6972. }
  6973.  
  6974. /* Interlink electronics VersaPad */
  6975. static int
  6976. enable_versapad(struct psm_softc *sc, enum probearg arg)
  6977. {
  6978.     KBDC kbdc = sc->kbdc;
  6979.     int data[3];
  6980.  
  6981.     set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
  6982.     set_mouse_sampling_rate(kbdc, 100);     /* set rate 100 */
  6983.     set_mouse_scaling(kbdc, 1);         /* set scale 1:1 */
  6984.     set_mouse_scaling(kbdc, 1);         /* set scale 1:1 */
  6985.     set_mouse_scaling(kbdc, 1);         /* set scale 1:1 */
  6986.     set_mouse_scaling(kbdc, 1);         /* set scale 1:1 */
  6987.     if (get_mouse_status(kbdc, data, 0, 3) < 3) /* get status */
  6988.         return (FALSE);
  6989.     if (data[2] != 0xa || data[1] != 0 )    /* rate == 0xa && res. == 0 */
  6990.         return (FALSE);
  6991.     set_mouse_scaling(kbdc, 1);         /* set scale 1:1 */
  6992.  
  6993.     return (TRUE);              /* PS/2 absolute mode */
  6994. }
  6995.  
  6996. /* Elantech Touchpad */
  6997. static int
  6998. elantech_read_1(KBDC kbdc, int hwversion, int reg, int *val)
  6999. {
  7000.     int res, readcmd, retidx;
  7001.     int resp[3];
  7002.  
  7003.     readcmd = hwversion == 2 ? ELANTECH_REG_READ : ELANTECH_REG_RDWR;
  7004.     retidx = hwversion == 4 ? 1 : 0;
  7005.  
  7006.     res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
  7007.     res |= send_aux_command(kbdc, readcmd) != PSM_ACK;
  7008.     res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
  7009.     res |= send_aux_command(kbdc, reg) != PSM_ACK;
  7010.     res |= get_mouse_status(kbdc, resp, 0, 3) != 3;
  7011.  
  7012.     if (res == 0)
  7013.         *val = resp[retidx];
  7014.  
  7015.     return (res);
  7016. }
  7017.  
  7018. static int
  7019. elantech_write_1(KBDC kbdc, int hwversion, int reg, int val)
  7020. {
  7021.     int res, writecmd;
  7022.  
  7023.     writecmd = hwversion == 2 ? ELANTECH_REG_WRITE : ELANTECH_REG_RDWR;
  7024.  
  7025.     res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
  7026.     res |= send_aux_command(kbdc, writecmd) != PSM_ACK;
  7027.     res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
  7028.     res |= send_aux_command(kbdc, reg) != PSM_ACK;
  7029.     if (hwversion == 4) {
  7030.         res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
  7031.         res |= send_aux_command(kbdc, writecmd) != PSM_ACK;
  7032.     }
  7033.     res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
  7034.     res |= send_aux_command(kbdc, val) != PSM_ACK;
  7035.     res |= set_mouse_scaling(kbdc, 1) == 0;
  7036.  
  7037.     return (res);
  7038. }
  7039.  
  7040. static int
  7041. elantech_cmd(KBDC kbdc, int hwversion, int cmd, int *resp)
  7042. {
  7043.     int res;
  7044.  
  7045.     if (hwversion == 2) {
  7046.         res = set_mouse_scaling(kbdc, 1) == 0;
  7047.         res |= mouse_ext_command(kbdc, cmd) == 0;
  7048.     } else {
  7049.         res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
  7050.         res |= send_aux_command(kbdc, cmd) != PSM_ACK;
  7051.     }
  7052.     res |= get_mouse_status(kbdc, resp, 0, 3) != 3;
  7053.  
  7054.     return (res);
  7055. }
  7056.  
  7057. static int
  7058. elantech_init(KBDC kbdc, elantechhw_t *elanhw)
  7059. {
  7060.     int i, val, res, hwversion, reg10;
  7061.  
  7062.     /* set absolute mode */
  7063.     hwversion = elanhw->hwversion;
  7064.     reg10 = -1;
  7065.     switch (hwversion) {
  7066.     case 2:
  7067.         reg10 = elanhw->fwversion == 0x020030 ? 0x54 : 0xc4;
  7068.         res = elantech_write_1(kbdc, hwversion, 0x10, reg10);
  7069.         if (res)
  7070.             break;
  7071.         res = elantech_write_1(kbdc, hwversion, 0x11, 0x8A);
  7072.         break;
  7073.     case 3:
  7074.         reg10 = 0x0b;
  7075.         res = elantech_write_1(kbdc, hwversion, 0x10, reg10);
  7076.         break;
  7077.     case 4:
  7078.         res = elantech_write_1(kbdc, hwversion, 0x07, 0x01);
  7079.         break;
  7080.     default:
  7081.         res = 1;
  7082.     }
  7083.  
  7084.     /* Read back reg 0x10 to ensure hardware is ready. */
  7085.     if (res == 0 && reg10 >= 0) {
  7086.         for (i = 0; i < 5; i++) {
  7087.             if (elantech_read_1(kbdc, hwversion, 0x10, &val) == 0)
  7088.                 break;
  7089.             DELAY(2000);
  7090.         }
  7091.         if (i == 5)
  7092.             res = 1;
  7093.     }
  7094.  
  7095.     if (res)
  7096.         printf("couldn't set absolute mode\n");
  7097.  
  7098.     return (res);
  7099. }
  7100.  
  7101. static void
  7102. elantech_init_synaptics(struct psm_softc *sc)
  7103. {
  7104.  
  7105.     /* Set capabilites required by movement smother */
  7106.     sc->synhw.infoMajor = sc->elanhw.hwversion;
  7107.     sc->synhw.infoMinor = sc->elanhw.fwversion;
  7108.     sc->synhw.infoXupmm = sc->elanhw.dpmmx;
  7109.     sc->synhw.infoYupmm = sc->elanhw.dpmmy;
  7110.     sc->synhw.verticalScroll = 0;
  7111.     sc->synhw.nExtendedQueries = 4;
  7112.     sc->synhw.capExtended = 1;
  7113.     sc->synhw.capPassthrough = sc->elanhw.hastrackpoint;
  7114.     sc->synhw.capClickPad = sc->elanhw.isclickpad;
  7115.     sc->synhw.capMultiFinger = 1;
  7116.     if (sc->elanhw.issemimt)
  7117.         sc->synhw.capAdvancedGestures = 1;
  7118.     else
  7119.         sc->synhw.capReportsV = 1;
  7120.     sc->synhw.capPalmDetect = 1;
  7121.     sc->synhw.capPen = 0;
  7122.     sc->synhw.capReportsMax = 1;
  7123.     sc->synhw.maximumXCoord = sc->elanhw.sizex;
  7124.     sc->synhw.maximumYCoord = sc->elanhw.sizey;
  7125.     sc->synhw.capReportsMin = 1;
  7126.     sc->synhw.minimumXCoord = 0;
  7127.     sc->synhw.minimumYCoord = 0;
  7128.  
  7129.     if (sc->syninfo.sysctl_tree == NULL) {
  7130.         synaptics_sysctl_create_tree(sc, "elantech",
  7131.             "Elantech Touchpad");
  7132.  
  7133.         /*
  7134.          * Adjust synaptic smoother tunables
  7135.          * 1. Disable finger detection pressure threshold. Unlike
  7136.          *    synaptics we assume the finger is acting when packet with
  7137.          *    its X&Y arrives not when pressure exceedes some threshold
  7138.          * 2. Disable unrelated features like margins and noisy areas
  7139.          * 3. Disable virtual scroll areas as 2nd finger is preferable
  7140.          * 4. For clickpads set bottom quarter as 42% - 16% - 42% sized
  7141.          *    softbuttons
  7142.          * 5. Scale down divisors and movement lengths by a factor of 3
  7143.          *    where 3 is Synaptics to Elantech (~2200/800) dpi ratio
  7144.          */
  7145.  
  7146.         /* Set reporting range to be equal touchpad size */
  7147.         sc->syninfo.max_x = sc->elanhw.sizex;
  7148.         sc->syninfo.max_y = sc->elanhw.sizey;
  7149.  
  7150.         /* Disable finger detection pressure threshold */
  7151.         sc->syninfo.min_pressure = 1;
  7152.  
  7153.         /* Adjust palm width to nearly match synaptics w=10 */
  7154.         sc->syninfo.max_width = 7;
  7155.  
  7156.         /* Elans often report double & triple taps as single event */
  7157.         sc->syninfo.tap_min_queue = 1;
  7158.  
  7159.         /* Use full area of touchpad */
  7160.         sc->syninfo.margin_top = 0;
  7161.         sc->syninfo.margin_right = 0;
  7162.         sc->syninfo.margin_bottom = 0;
  7163.         sc->syninfo.margin_left = 0;
  7164.  
  7165.         /* Disable noisy area */
  7166.         sc->syninfo.na_top = 0;
  7167.         sc->syninfo.na_right = 0;
  7168.         sc->syninfo.na_bottom = 0;
  7169.         sc->syninfo.na_left = 0;
  7170.  
  7171.         /* Tune divisors and movement lengths */
  7172.         sc->syninfo.weight_len_squared = 200;
  7173.         sc->syninfo.div_min = 3;
  7174.         sc->syninfo.div_max = 6;
  7175.         sc->syninfo.div_max_na = 10;
  7176.         sc->syninfo.div_len = 30;
  7177.         sc->syninfo.tap_max_delta = 25;
  7178.  
  7179.         /* Disable virtual scrolling areas and tune its divisors */
  7180.         sc->syninfo.vscroll_hor_area = 0;
  7181.         sc->syninfo.vscroll_ver_area = 0;
  7182.         sc->syninfo.vscroll_min_delta = 15;
  7183.         sc->syninfo.vscroll_div_min = 30;
  7184.         sc->syninfo.vscroll_div_max = 50;
  7185.  
  7186.         /* Set bottom quarter as 42% - 16% - 42% sized softbuttons */
  7187.         if (sc->elanhw.isclickpad) {
  7188.             sc->syninfo.softbuttons_y = sc->elanhw.sizey / 4;
  7189.             sc->syninfo.softbutton2_x = sc->elanhw.sizex * 11 / 25;
  7190.             sc->syninfo.softbutton3_x = sc->elanhw.sizex * 14 / 25;
  7191.         }
  7192.     }
  7193.  
  7194.     return;
  7195. }
  7196.  
  7197. static int
  7198. enable_elantech(struct psm_softc *sc, enum probearg arg)
  7199. {
  7200.     static const int ic2hw[] =
  7201.     /*IC: 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
  7202.         { 0, 0, 2, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0 };
  7203.     static const int fw_sizes[][3] = {
  7204.         /* FW.vers  MaxX  MaxY */
  7205.         { 0x020030, 1152,  768 },
  7206.         { 0x020800, 1152,  768 },
  7207.         { 0x020b00, 1152,  768 },
  7208.         { 0x040215,  900,  500 },
  7209.         { 0x040216,  819,  405 },
  7210.         { 0x040219,  900,  500 },
  7211.     };
  7212.     elantechhw_t elanhw;
  7213.     int icversion, hwversion, xtr, i, id, resp[3], dpix, dpiy;
  7214.     KBDC kbdc = sc->kbdc;
  7215.  
  7216.     VLOG(3, (LOG_DEBUG, "elantech: BEGIN init\n"));
  7217.  
  7218.     set_mouse_scaling(kbdc, 1);
  7219.     set_mouse_scaling(kbdc, 1);
  7220.     set_mouse_scaling(kbdc, 1);
  7221.     if (get_mouse_status(kbdc, resp, 0, 3) != 3)
  7222.         return (FALSE);
  7223.  
  7224.     if (!ELANTECH_MAGIC(resp))
  7225.         return (FALSE);
  7226.  
  7227.     /* Identify the Touchpad version. */
  7228.     if (elantech_cmd(kbdc, 2, ELANTECH_FW_VERSION, resp))
  7229.         return (FALSE);
  7230.  
  7231.     bzero(&elanhw, sizeof(elanhw));
  7232.  
  7233.     elanhw.fwversion = (resp[0] << 16) | (resp[1] << 8) | resp[2];
  7234.     icversion = resp[0] & 0x0f;
  7235.     hwversion = ic2hw[icversion];
  7236.  
  7237.     if (verbose >= 2)
  7238.         printf("Elantech touchpad hardware v.%d firmware v.0x%06x\n",
  7239.             hwversion, elanhw.fwversion);
  7240.  
  7241.     if (ELANTECH_HW_IS_V1(elanhw.fwversion)) {
  7242.         printf ("  Unsupported touchpad hardware (v1)\n");
  7243.         return (FALSE);
  7244.     }
  7245.     if (hwversion == 0) {
  7246.         printf ("  Unknown touchpad hardware (firmware v.0x%06x)\n",
  7247.             elanhw.fwversion);
  7248.         return (FALSE);
  7249.     }
  7250.  
  7251.     /* Get the Touchpad model information. */
  7252.     elanhw.hwversion = hwversion;
  7253.     elanhw.issemimt = hwversion == 2;
  7254.     elanhw.isclickpad = (resp[1] & 0x10) != 0;
  7255.     elanhw.hascrc = (resp[1] & 0x40) != 0;
  7256.     elanhw.haspressure = elanhw.fwversion >= 0x020800;
  7257.  
  7258.     /* Read the capability bits. */
  7259.     if (elantech_cmd(kbdc, hwversion, ELANTECH_CAPABILITIES, resp) != 0) {
  7260.         printf("  Failed to read capability bits\n");
  7261.         return (FALSE);
  7262.     }
  7263.  
  7264.     elanhw.ntracesx = imax(resp[1], 3);
  7265.     elanhw.ntracesy = imax(resp[2], 3);
  7266.     elanhw.hastrackpoint = (resp[0] & 0x80) != 0;
  7267.  
  7268.     /* Get the touchpad resolution */
  7269.     switch (hwversion) {
  7270.     case 4:
  7271.         if (elantech_cmd(kbdc, hwversion, ELANTECH_RESOLUTION, resp)
  7272.             == 0) {
  7273.             dpix = (resp[1] & 0x0f) * 10 + 790;
  7274.             dpiy = ((resp[1] & 0xf0) >> 4) * 10 + 790;
  7275.             elanhw.dpmmx = (dpix * 10 + 5) / 254;
  7276.             elanhw.dpmmy = (dpiy * 10 + 5) / 254;
  7277.             break;
  7278.         }
  7279.         /* FALLTHROUGH */
  7280.     case 2:
  7281.     case 3:
  7282.         elanhw.dpmmx = elanhw.dpmmy = 32; /* 800 dpi */
  7283.         break;
  7284.     }
  7285.  
  7286.     if (!elantech_support)
  7287.         return (FALSE);
  7288.  
  7289.     if (elantech_init(kbdc, &elanhw)) {
  7290.         printf("couldn't initialize elantech touchpad\n");
  7291.         return (FALSE);
  7292.     }
  7293.  
  7294.     /*
  7295.      * Get the touchpad reporting range.
  7296.      * On HW v.3 touchpads it should be done after switching hardware
  7297.      * to real resolution mode (by setting bit 3 of reg10)
  7298.      */
  7299.     elanhw.dptracex = elanhw.dptracey = 64;
  7300.     for (i = 0; i < nitems(fw_sizes); i++) {
  7301.         if (elanhw.fwversion == fw_sizes[i][0]) {
  7302.             elanhw.sizex = fw_sizes[i][1];
  7303.             elanhw.sizey = fw_sizes[i][2];
  7304.             goto found;
  7305.         }
  7306.     }
  7307.     if (elantech_cmd(kbdc, hwversion, ELANTECH_FW_ID, resp) != 0) {
  7308.         printf("  Failed to read touchpad size\n");
  7309.         elanhw.sizex = 10000; /* Arbitrary high values to     */
  7310.         elanhw.sizey = 10000; /* prevent clipping in smoother */
  7311.     } else if (hwversion == 2) {
  7312.         if ((elanhw.fwversion >> 16) == 0x14 && (resp[1] & 0x10) &&
  7313.             !elantech_cmd(kbdc, hwversion, ELANTECH_SAMPLE, resp)) {
  7314.             elanhw.dptracex = resp[1] / 2;
  7315.             elanhw.dptracey = resp[2] / 2;
  7316.         }
  7317.         xtr = ((elanhw.fwversion >> 8) == 0x0208) ? 1 : 2;
  7318.         elanhw.sizex = (elanhw.ntracesx - xtr) * elanhw.dptracex;
  7319.         elanhw.sizey = (elanhw.ntracesy - xtr) * elanhw.dptracey;
  7320.     } else {
  7321.         elanhw.sizex = (resp[0] & 0x0f) << 8 | resp[1];
  7322.         elanhw.sizey = (resp[0] & 0xf0) << 4 | resp[2];
  7323.         xtr = (elanhw.sizex % (elanhw.ntracesx - 2) == 0) ? 2 : 1;
  7324.         elanhw.dptracex = elanhw.sizex / (elanhw.ntracesx - xtr);
  7325.         elanhw.dptracey = elanhw.sizey / (elanhw.ntracesy - xtr);
  7326.     }
  7327. found:
  7328.     if (verbose >= 2) {
  7329.         printf("  Model information:\n");
  7330.         printf("   MaxX:       %d\n", elanhw.sizex);
  7331.         printf("   MaxY:       %d\n", elanhw.sizey);
  7332.         printf("   DpmmX:      %d\n", elanhw.dpmmx);
  7333.         printf("   DpmmY:      %d\n", elanhw.dpmmy);
  7334.         printf("   TracesX:    %d\n", elanhw.ntracesx);
  7335.         printf("   TracesY:    %d\n", elanhw.ntracesy);
  7336.         printf("   DptraceX:   %d\n", elanhw.dptracex);
  7337.         printf("   DptraceY:   %d\n", elanhw.dptracey);
  7338.         printf("   SemiMT:     %d\n", elanhw.issemimt);
  7339.         printf("   Clickpad:   %d\n", elanhw.isclickpad);
  7340.         printf("   Trackpoint: %d\n", elanhw.hastrackpoint);
  7341.         printf("   CRC:        %d\n", elanhw.hascrc);
  7342.         printf("   Pressure:   %d\n", elanhw.haspressure);
  7343.     }
  7344.  
  7345.     VLOG(3, (LOG_DEBUG, "elantech: END init\n"));
  7346.  
  7347.     if (arg == PROBE) {
  7348.         sc->elanhw = elanhw;
  7349.         sc->hw.buttons = 3;
  7350.  
  7351.         /* Initialize synaptics movement smoother */
  7352.         elantech_init_synaptics(sc);
  7353.  
  7354.         for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
  7355.             PSM_FINGER_RESET(sc->elanaction.fingers[id]);
  7356.     }
  7357.  
  7358.     return (TRUE);
  7359. }
  7360.  
  7361. static void
  7362. focaltech_init_synaptics(struct psm_softc *sc)
  7363. {
  7364.  
  7365.   /* Set capabilites required by movement smother */
  7366.   sc->synhw.infoMajor = 0;
  7367.   sc->synhw.infoMinor = 0;
  7368.   sc->synhw.infoXupmm = 32;
  7369.   sc->synhw.infoYupmm = 32;
  7370.   sc->synhw.verticalScroll = 0;
  7371.   sc->synhw.nExtendedQueries = 4;
  7372.   sc->synhw.capExtended = 1;
  7373.   sc->synhw.capPassthrough = false;
  7374.   sc->synhw.capClickPad = true;
  7375.   sc->synhw.capMultiFinger = 1;
  7376.   sc->synhw.capAdvancedGestures = 1;
  7377.   sc->synhw.capPalmDetect = 1;
  7378.   sc->synhw.capPen = 0;
  7379.   sc->synhw.capReportsMax = 1;
  7380.   sc->synhw.maximumXCoord = FOCALTECH_MAX_X;
  7381.   sc->synhw.maximumYCoord = FOCALTECH_MAX_Y;
  7382.   sc->synhw.capReportsMin = 1;
  7383.   sc->synhw.minimumXCoord = 0;
  7384.   sc->synhw.minimumYCoord = 0;
  7385.  
  7386.   if (sc->syninfo.sysctl_tree == NULL) {
  7387.     synaptics_sysctl_create_tree(sc, "focaltech",
  7388.                  "FocalTech Touchpad");
  7389.  
  7390.     /*
  7391.      * Adjust synaptic smoother tunables
  7392.      * 1. Disable finger detection pressure threshold. Unlike
  7393.      *    synaptics we assume the finger is acting when packet with
  7394.      *    its X&Y arrives not when pressure exceedes some threshold
  7395.      * 2. Disable unrelated features like margins and noisy areas
  7396.      * 3. Disable virtual scroll areas as 2nd finger is preferable
  7397.      * 4. For clickpads set bottom quarter as 42% - 16% - 42% sized
  7398.      *    softbuttons
  7399.      * 5. Scale down divisors and movement lengths by a factor of 3
  7400.      *    where 3 is Synaptics to Elantech (~2200/800) dpi ratio
  7401.      */
  7402.  
  7403.     /* Set reporting range to be equal touchpad size */
  7404.     sc->syninfo.max_x = FOCALTECH_MAX_X;
  7405.     sc->syninfo.max_y = FOCALTECH_MAX_Y;
  7406.  
  7407.     /* Disable finger detection pressure threshold */
  7408.     sc->syninfo.min_pressure = 1;
  7409.  
  7410.     /* Adjust palm width to nearly match synaptics w=10 */
  7411.     sc->syninfo.max_width = 7;
  7412.  
  7413.     /* Elans often report double & triple taps as single event */
  7414.     sc->syninfo.tap_min_queue = 1;
  7415.  
  7416.     /* Use full area of touchpad */
  7417.     sc->syninfo.margin_top = 0;
  7418.     sc->syninfo.margin_right = 0;
  7419.     sc->syninfo.margin_bottom = 0;
  7420.     sc->syninfo.margin_left = 0;
  7421.  
  7422.     /* Disable noisy area */
  7423.     sc->syninfo.na_top = 0;
  7424.     sc->syninfo.na_right = 0;
  7425.     sc->syninfo.na_bottom = 0;
  7426.     sc->syninfo.na_left = 0;
  7427.  
  7428.     /* Tune divisors and movement lengths */
  7429.     sc->syninfo.weight_len_squared = 200;
  7430.     sc->syninfo.div_min = 3;
  7431.     sc->syninfo.div_max = 6;
  7432.     sc->syninfo.div_max_na = 10;
  7433.     sc->syninfo.div_len = 30;
  7434.     sc->syninfo.tap_max_delta = 25;
  7435.  
  7436.     /* Disable virtual scrolling areas and tune its divisors */
  7437.     sc->syninfo.vscroll_hor_area = 0;
  7438.     sc->syninfo.vscroll_ver_area = 0;
  7439.     sc->syninfo.vscroll_min_delta = 15;
  7440.     sc->syninfo.vscroll_div_min = 30;
  7441.     sc->syninfo.vscroll_div_max = 50;
  7442.  
  7443.     /* Set bottom quarter as 42% - 16% - 42% sized softbuttons */
  7444.     if (sc->elanhw.isclickpad) {
  7445.       sc->syninfo.softbuttons_y = sc->elanhw.sizey / 4;
  7446.       sc->syninfo.softbutton2_x = sc->elanhw.sizex * 11 / 25;
  7447.       sc->syninfo.softbutton3_x = sc->elanhw.sizex * 14 / 25;
  7448.     }
  7449.   }
  7450.  
  7451.   return;
  7452.  
  7453. }
  7454.  
  7455.  
  7456. static int
  7457. focaltech_init(KBDC kbdc, focaltechhw_t *focalhw, int unit)
  7458. {
  7459.   VLOG(3, (LOG_DEBUG, "psm%d: switching to focaltech protocol!\n", unit));
  7460.  
  7461.   // Send the switch protocol messages
  7462.   recover_from_error(kbdc);
  7463.  
  7464.   send_aux_command_and_data(kbdc, 0xF8, 0);
  7465.   send_aux_command_and_data(kbdc, 0xF8, 0);
  7466.   send_aux_command_and_data(kbdc, 0xF8, 0);
  7467.  
  7468.   send_aux_command_and_data(kbdc, 0xF8, 1);
  7469.   set_mouse_scaling(kbdc, 1);
  7470.   enable_aux_dev(kbdc);
  7471.  
  7472.   VLOG(3, (LOG_DEBUG, "psm%d: switching finished!\n", unit));
  7473.  
  7474.   return (0);
  7475. }
  7476.  
  7477.  
  7478. static int
  7479. enable_focaltech(struct psm_softc *sc, enum probearg arg)
  7480. {
  7481.   device_t psmcpnp;
  7482.   devclass_t devclass;
  7483.  
  7484.   VLOG(3, (LOG_DEBUG, "psm%d: focaltech: BEGIN init\n", sc->unit));
  7485.  
  7486.   /* Here we just do what the linux kernel does to find this device and
  7487.    * scan for its pnpinfo */
  7488.  
  7489.   psmcpnp = devclass_get_device(devclass_find(PSMCPNP_DRIVER_NAME), sc->unit);
  7490.   devclass = device_get_devclass(psmcpnp);
  7491.  
  7492.   char pnpinfo[128];
  7493.   bus_child_pnpinfo_str(psmcpnp, pnpinfo, sizeof(pnpinfo));
  7494.   log(LOG_ERR, "psm%d: pnpinfo: %s\n", sc->unit, pnpinfo);
  7495.  
  7496.   /* TODO: Dont just strstr for this!
  7497.    * Surely there is a way to get this... */
  7498.   if(!strstr(pnpinfo, "_HID=FLT010")) {
  7499.     return (FALSE);
  7500.   }
  7501.  
  7502.   sc->config |= PSM_CONFIG_NOCHECKSYNC;
  7503.   sc->hw.buttons = 3;
  7504.   sc->dflt_mode.level = PSM_LEVEL_STANDARD;
  7505.  
  7506.   focaltech_init(sc->kbdc, &sc->focalhw, sc->unit);
  7507.  
  7508.   focaltech_init_synaptics(sc);
  7509.  
  7510.   VLOG(3, (LOG_DEBUG, "psm%d: focaltech: END init\n", sc->unit));
  7511.  
  7512.   return (TRUE);
  7513. }
  7514.  
  7515. /*
  7516.  * Return true if 'now' is earlier than (start + (secs.usecs)).
  7517.  * Now may be NULL and the function will fetch the current time from
  7518.  * getmicrouptime(), or a cached 'now' can be passed in.
  7519.  * All values should be numbers derived from getmicrouptime().
  7520.  */
  7521. static int
  7522. timeelapsed(start, secs, usecs, now)
  7523.     const struct timeval *start, *now;
  7524.     int secs, usecs;
  7525. {
  7526.     struct timeval snow, tv;
  7527.  
  7528.     /* if there is no 'now' passed in, the get it as a convience. */
  7529.     if (now == NULL) {
  7530.         getmicrouptime(&snow);
  7531.         now = &snow;
  7532.     }
  7533.  
  7534.     tv.tv_sec = secs;
  7535.     tv.tv_usec = usecs;
  7536.     timevaladd(&tv, start);
  7537.     return (timevalcmp(&tv, now, <));
  7538. }
  7539.  
  7540. static int
  7541. psmresume(device_t dev)
  7542. {
  7543.     struct psm_softc *sc = device_get_softc(dev);
  7544.     int unit = device_get_unit(dev);
  7545.     int err;
  7546.  
  7547.     VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit));
  7548.  
  7549.     if ((sc->config &
  7550.         (PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND)) == 0)
  7551.         return (0);
  7552.  
  7553.     err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND);
  7554.  
  7555.     if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
  7556.         /*
  7557.          * Release the blocked process; it must be notified that
  7558.          * the device cannot be accessed anymore.
  7559.          */
  7560.         sc->state &= ~PSM_ASLP;
  7561.         wakeup(sc);
  7562.     }
  7563.  
  7564.     VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit));
  7565.  
  7566.     return (err);
  7567. }
  7568.  
  7569. DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
  7570. #ifdef EVDEV_SUPPORT
  7571. MODULE_DEPEND(psm, evdev, 1, 1, 1);
  7572. #endif
  7573.  
  7574. #ifdef DEV_ISA
  7575.  
  7576. /*
  7577.  * This sucks up assignments from PNPBIOS and ACPI.
  7578.  */
  7579.  
  7580. /*
  7581.  * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may
  7582.  * appear BEFORE the AT keyboard controller.  As the PS/2 mouse device
  7583.  * can be probed and attached only after the AT keyboard controller is
  7584.  * attached, we shall quietly reserve the IRQ resource for later use.
  7585.  * If the PS/2 mouse device is reported to us AFTER the keyboard controller,
  7586.  * copy the IRQ resource to the PS/2 mouse device instance hanging
  7587.  * under the keyboard controller, then probe and attach it.
  7588.  */
  7589.  
  7590. static  devclass_t          psmcpnp_devclass;
  7591.  
  7592. static  device_probe_t          psmcpnp_probe;
  7593. static  device_attach_t         psmcpnp_attach;
  7594.  
  7595. static device_method_t psmcpnp_methods[] = {
  7596.     DEVMETHOD(device_probe,     psmcpnp_probe),
  7597.     DEVMETHOD(device_attach,    psmcpnp_attach),
  7598.  
  7599.     { 0, 0 }
  7600. };
  7601.  
  7602. static driver_t psmcpnp_driver = {
  7603.     PSMCPNP_DRIVER_NAME,
  7604.     psmcpnp_methods,
  7605.     sizeof(struct psmcpnp_softc),
  7606. };
  7607.  
  7608. static struct isa_pnp_id psmcpnp_ids[] = {
  7609.     { 0x030fd041, "PS/2 mouse port" },      /* PNP0F03 */
  7610.     { 0x0e0fd041, "PS/2 mouse port" },      /* PNP0F0E */
  7611.     { 0x120fd041, "PS/2 mouse port" },      /* PNP0F12 */
  7612.     { 0x130fd041, "PS/2 mouse port" },      /* PNP0F13 */
  7613.     { 0x1303d041, "PS/2 port" },            /* PNP0313, XXX */
  7614.     { 0x02002e4f, "Dell PS/2 mouse port" },     /* Lat. X200, Dell */
  7615.     { 0x0002a906, "ALPS Glide Point" },     /* ALPS Glide Point */
  7616.     { 0x80374d24, "IBM PS/2 mouse port" },      /* IBM3780, ThinkPad */
  7617.     { 0x81374d24, "IBM PS/2 mouse port" },      /* IBM3781, ThinkPad */
  7618.     { 0x0190d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9001, Vaio */
  7619.     { 0x0290d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9002, Vaio */
  7620.     { 0x0390d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9003, Vaio */
  7621.     { 0x0490d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9004, Vaio */
  7622.     { 0 }
  7623. };
  7624.  
  7625. /* _HID list for quirk detection. Any device below has _CID from psmcpnp_ids */
  7626. static struct isa_pnp_id forcepad_ids[] = {
  7627.     { 0x0d302e4f, "HP PS/2 forcepad port" },    /* SYN300D, EB 1040 */
  7628.     { 0x14302e4f, "HP PS/2 forcepad port" },    /* SYN3014, EB 1040 */
  7629.     { 0 }
  7630. };
  7631.  
  7632. /* List of HW v8.1 synaptics touchpads erroneously detected as HW v2.0 */
  7633. static struct isa_pnp_id hpsyn81_ids[] = {
  7634.     { 0x9e012e4f, "HP PS/2 trackpad port" },    /* SYN019E, EB 9470 */
  7635.     { 0 }
  7636. };
  7637.  
  7638. static int
  7639. create_a_copy(device_t atkbdc, device_t me)
  7640. {
  7641.     device_t psm;
  7642.     u_long irq;
  7643.  
  7644.     /* find the PS/2 mouse device instance under the keyboard controller */
  7645.     psm = device_find_child(atkbdc, PSM_DRIVER_NAME,
  7646.         device_get_unit(atkbdc));
  7647.     if (psm == NULL)
  7648.         return (ENXIO);
  7649.     if (device_get_state(psm) != DS_NOTPRESENT)
  7650.         return (0);
  7651.  
  7652.     /* move our resource to the found device */
  7653.     irq = bus_get_resource_start(me, SYS_RES_IRQ, 0);
  7654.     bus_delete_resource(me, SYS_RES_IRQ, 0);
  7655.     bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
  7656.  
  7657.     /* ...then probe and attach it */
  7658.     return (device_probe_and_attach(psm));
  7659. }
  7660.  
  7661. static int
  7662. psmcpnp_probe(device_t dev)
  7663. {
  7664.     struct psmcpnp_softc *sc = device_get_softc(dev);
  7665.     struct resource *res;
  7666.     u_long irq;
  7667.     int rid;
  7668.  
  7669.     if (ISA_PNP_PROBE(device_get_parent(dev), dev, forcepad_ids) == 0)
  7670.         sc->type = PSMCPNP_FORCEPAD;
  7671.     else if(ISA_PNP_PROBE(device_get_parent(dev), dev, hpsyn81_ids) == 0)
  7672.         sc->type = PSMCPNP_HPSYN81;
  7673.     else if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids) == 0)
  7674.         sc->type = PSMCPNP_GENERIC;
  7675.     else
  7676.         return (ENXIO);
  7677.  
  7678.     /*
  7679.      * The PnP BIOS and ACPI are supposed to assign an IRQ (12)
  7680.      * to the PS/2 mouse device node. But, some buggy PnP BIOS
  7681.      * declares the PS/2 mouse device node without an IRQ resource!
  7682.      * If this happens, we shall refer to device hints.
  7683.      * If we still don't find it there, use a hardcoded value... XXX
  7684.      */
  7685.     rid = 0;
  7686.     irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid);
  7687.     if (irq <= 0) {
  7688.         if (resource_long_value(PSM_DRIVER_NAME,
  7689.             device_get_unit(dev),"irq", &irq) != 0)
  7690.             irq = 12;   /* XXX */
  7691.         device_printf(dev, "irq resource info is missing; "
  7692.             "assuming irq %ld\n", irq);
  7693.         bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1);
  7694.     }
  7695.     res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
  7696.     bus_release_resource(dev, SYS_RES_IRQ, rid, res);
  7697.  
  7698.     /* keep quiet */
  7699.     if (!bootverbose)
  7700.         device_quiet(dev);
  7701.  
  7702.     return ((res == NULL) ? ENXIO : 0);
  7703. }
  7704.  
  7705. static int
  7706. psmcpnp_attach(device_t dev)
  7707. {
  7708.     device_t atkbdc;
  7709.  
  7710.     /* find the keyboard controller, which may be on acpi* or isa* bus */
  7711.     atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME),
  7712.         device_get_unit(dev));
  7713.     if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED))
  7714.         create_a_copy(atkbdc, dev);
  7715.  
  7716.     return (0);
  7717. }
  7718.  
  7719. DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0);
  7720. DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0);
  7721.  
  7722. #endif /* DEV_ISA */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement