]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/atkbdc/psm.c
Merge sync of head
[FreeBSD/FreeBSD.git] / sys / dev / atkbdc / psm.c
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  *
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$");
63
64 #include "opt_isa.h"
65 #include "opt_psm.h"
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/module.h>
71 #include <sys/bus.h>
72 #include <sys/conf.h>
73 #include <sys/filio.h>
74 #include <sys/poll.h>
75 #include <sys/sigio.h>
76 #include <sys/signalvar.h>
77 #include <sys/syslog.h>
78 #include <machine/bus.h>
79 #include <sys/rman.h>
80 #include <sys/selinfo.h>
81 #include <sys/sysctl.h>
82 #include <sys/time.h>
83 #include <sys/uio.h>
84
85 #include <sys/limits.h>
86 #include <sys/mouse.h>
87 #include <machine/resource.h>
88
89 #ifdef DEV_ISA
90 #include <isa/isavar.h>
91 #endif
92
93 #include <dev/atkbdc/atkbdcreg.h>
94 #include <dev/atkbdc/psm.h>
95
96 /*
97  * Driver specific options: the following options may be set by
98  * `options' statements in the kernel configuration file.
99  */
100
101 /* debugging */
102 #ifndef PSM_DEBUG
103 #define PSM_DEBUG       0       /*
104                                  * logging: 0: none, 1: brief, 2: verbose
105                                  *          3: sync errors, 4: all packets
106                                  */
107 #endif
108 #define VLOG(level, args)       do {    \
109         if (verbose >= level)           \
110                 log args;               \
111 } while (0)
112
113 #ifndef PSM_INPUT_TIMEOUT
114 #define PSM_INPUT_TIMEOUT       2000000 /* 2 sec */
115 #endif
116
117 #ifndef PSM_TAP_TIMEOUT
118 #define PSM_TAP_TIMEOUT         125000
119 #endif
120
121 #ifndef PSM_TAP_THRESHOLD
122 #define PSM_TAP_THRESHOLD       25
123 #endif
124
125 /* end of driver specific options */
126
127 #define PSMCPNP_DRIVER_NAME     "psmcpnp"
128
129 /* input queue */
130 #define PSM_BUFSIZE             960
131 #define PSM_SMALLBUFSIZE        240
132
133 /* operation levels */
134 #define PSM_LEVEL_BASE          0
135 #define PSM_LEVEL_STANDARD      1
136 #define PSM_LEVEL_NATIVE        2
137 #define PSM_LEVEL_MIN           PSM_LEVEL_BASE
138 #define PSM_LEVEL_MAX           PSM_LEVEL_NATIVE
139
140 /* Logitech PS2++ protocol */
141 #define MOUSE_PS2PLUS_CHECKBITS(b)      \
142     ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
143 #define MOUSE_PS2PLUS_PACKET_TYPE(b)    \
144     (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
145
146 /* ring buffer */
147 typedef struct ringbuf {
148         int             count;  /* # of valid elements in the buffer */
149         int             head;   /* head pointer */
150         int             tail;   /* tail poiner */
151         u_char buf[PSM_BUFSIZE];
152 } ringbuf_t;
153
154 /* data buffer */
155 typedef struct packetbuf {
156         u_char  ipacket[16];    /* interim input buffer */
157         int     inputbytes;     /* # of bytes in the input buffer */
158 } packetbuf_t;
159
160 #ifndef PSM_PACKETQUEUE
161 #define PSM_PACKETQUEUE 128
162 #endif
163
164 enum {
165         SYNAPTICS_SYSCTL_MIN_PRESSURE,
166         SYNAPTICS_SYSCTL_MAX_PRESSURE,
167         SYNAPTICS_SYSCTL_MAX_WIDTH,
168         SYNAPTICS_SYSCTL_MARGIN_TOP,
169         SYNAPTICS_SYSCTL_MARGIN_RIGHT,
170         SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
171         SYNAPTICS_SYSCTL_MARGIN_LEFT,
172         SYNAPTICS_SYSCTL_NA_TOP,
173         SYNAPTICS_SYSCTL_NA_RIGHT,
174         SYNAPTICS_SYSCTL_NA_BOTTOM,
175         SYNAPTICS_SYSCTL_NA_LEFT,
176         SYNAPTICS_SYSCTL_WINDOW_MIN,
177         SYNAPTICS_SYSCTL_WINDOW_MAX,
178         SYNAPTICS_SYSCTL_MULTIPLICATOR,
179         SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
180         SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
181         SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
182         SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
183         SYNAPTICS_SYSCTL_DIV_MIN,
184         SYNAPTICS_SYSCTL_DIV_MAX,
185         SYNAPTICS_SYSCTL_DIV_MAX_NA,
186         SYNAPTICS_SYSCTL_DIV_LEN,
187         SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
188         SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
189         SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
190         SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
191         SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
192         SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
193         SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
194         SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
195         SYNAPTICS_SYSCTL_TOUCHPAD_OFF
196 };
197
198 typedef struct synapticsinfo {
199         struct sysctl_ctx_list   sysctl_ctx;
200         struct sysctl_oid       *sysctl_tree;
201         int                      directional_scrolls;
202         int                      two_finger_scroll;
203         int                      min_pressure;
204         int                      max_pressure;
205         int                      max_width;
206         int                      margin_top;
207         int                      margin_right;
208         int                      margin_bottom;
209         int                      margin_left;
210         int                      na_top;
211         int                      na_right;
212         int                      na_bottom;
213         int                      na_left;
214         int                      window_min;
215         int                      window_max;
216         int                      multiplicator;
217         int                      weight_current;
218         int                      weight_previous;
219         int                      weight_previous_na;
220         int                      weight_len_squared;
221         int                      div_min;
222         int                      div_max;
223         int                      div_max_na;
224         int                      div_len;
225         int                      tap_max_delta;
226         int                      tap_min_queue;
227         int                      taphold_timeout;
228         int                      vscroll_ver_area;
229         int                      vscroll_hor_area;
230         int                      vscroll_min_delta;
231         int                      vscroll_div_min;
232         int                      vscroll_div_max;
233         int                      touchpad_off;
234 } synapticsinfo_t;
235
236 typedef struct synapticspacket {
237         int                     x;
238         int                     y;
239 } synapticspacket_t;
240
241 #define SYNAPTICS_PACKETQUEUE 10
242 #define SYNAPTICS_QUEUE_CURSOR(x)                                       \
243         (x + SYNAPTICS_PACKETQUEUE) % SYNAPTICS_PACKETQUEUE
244
245 #define SYNAPTICS_VERSION_GE(synhw, major, minor)                       \
246     ((synhw).infoMajor > (major) ||                                     \
247      ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
248
249 typedef struct synapticsaction {
250         synapticspacket_t       queue[SYNAPTICS_PACKETQUEUE];
251         int                     queue_len;
252         int                     queue_cursor;
253         int                     window_min;
254         int                     start_x;
255         int                     start_y;
256         int                     avg_dx;
257         int                     avg_dy;
258         int                     squelch_x;
259         int                     squelch_y;
260         int                     fingers_nb;
261         int                     tap_button;
262         int                     in_taphold;
263         int                     in_vscroll;
264 } synapticsaction_t;
265
266 enum {
267         TRACKPOINT_SYSCTL_SENSITIVITY,
268         TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
269         TRACKPOINT_SYSCTL_UPPER_PLATEAU,
270         TRACKPOINT_SYSCTL_BACKUP_RANGE,
271         TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
272         TRACKPOINT_SYSCTL_MINIMUM_DRAG,
273         TRACKPOINT_SYSCTL_UP_THRESHOLD,
274         TRACKPOINT_SYSCTL_THRESHOLD,
275         TRACKPOINT_SYSCTL_JENKS_CURVATURE,
276         TRACKPOINT_SYSCTL_Z_TIME,
277         TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
278         TRACKPOINT_SYSCTL_SKIP_BACKUPS
279 };
280
281 typedef struct trackpointinfo {
282         struct sysctl_ctx_list sysctl_ctx;
283         struct sysctl_oid *sysctl_tree;
284         int     sensitivity;
285         int     inertia;
286         int     uplateau;
287         int     reach;
288         int     draghys;
289         int     mindrag;
290         int     upthresh;
291         int     threshold;
292         int     jenks;
293         int     ztime;
294         int     pts;
295         int     skipback;
296 } trackpointinfo_t;
297
298 /* driver control block */
299 struct psm_softc {              /* Driver status information */
300         int             unit;
301         struct selinfo  rsel;           /* Process selecting for Input */
302         u_char          state;          /* Mouse driver state */
303         int             config;         /* driver configuration flags */
304         int             flags;          /* other flags */
305         KBDC            kbdc;           /* handle to access kbd controller */
306         struct resource *intr;          /* IRQ resource */
307         void            *ih;            /* interrupt handle */
308         mousehw_t       hw;             /* hardware information */
309         synapticshw_t   synhw;          /* Synaptics hardware information */
310         synapticsinfo_t syninfo;        /* Synaptics configuration */
311         synapticsaction_t synaction;    /* Synaptics action context */
312         int             tphw;           /* TrackPoint hardware information */
313         trackpointinfo_t tpinfo;        /* TrackPoint configuration */
314         mousemode_t     mode;           /* operation mode */
315         mousemode_t     dflt_mode;      /* default operation mode */
316         mousestatus_t   status;         /* accumulated mouse movement */
317         ringbuf_t       queue;          /* mouse status queue */
318         packetbuf_t     pqueue[PSM_PACKETQUEUE]; /* mouse data queue */
319         int             pqueue_start;   /* start of data in queue */
320         int             pqueue_end;     /* end of data in queue */
321         int             button;         /* the latest button state */
322         int             xold;           /* previous absolute X position */
323         int             yold;           /* previous absolute Y position */
324         int             xaverage;       /* average X position */
325         int             yaverage;       /* average Y position */
326         int             squelch; /* level to filter movement at low speed */
327         int             zmax;   /* maximum pressure value for touchpads */
328         int             syncerrors; /* # of bytes discarded to synchronize */
329         int             pkterrors;  /* # of packets failed during quaranteen. */
330         struct timeval  inputtimeout;
331         struct timeval  lastsoftintr;   /* time of last soft interrupt */
332         struct timeval  lastinputerr;   /* time last sync error happened */
333         struct timeval  taptimeout;     /* tap timeout for touchpads */
334         int             watchdog;       /* watchdog timer flag */
335         struct callout  callout;        /* watchdog timer call out */
336         struct callout  softcallout; /* buffer timer call out */
337         struct cdev     *dev;
338         struct cdev     *bdev;
339         int             lasterr;
340         int             cmdcount;
341         struct sigio    *async;         /* Processes waiting for SIGIO */
342         int             extended_buttons;
343 };
344 static devclass_t psm_devclass;
345
346 /* driver state flags (state) */
347 #define PSM_VALID               0x80
348 #define PSM_OPEN                1       /* Device is open */
349 #define PSM_ASLP                2       /* Waiting for mouse data */
350 #define PSM_SOFTARMED           4       /* Software interrupt armed */
351 #define PSM_NEED_SYNCBITS       8       /* Set syncbits using next data pkt */
352
353 /* driver configuration flags (config) */
354 #define PSM_CONFIG_RESOLUTION   0x000f  /* resolution */
355 #define PSM_CONFIG_ACCEL        0x00f0  /* acceleration factor */
356 #define PSM_CONFIG_NOCHECKSYNC  0x0100  /* disable sync. test */
357 #define PSM_CONFIG_NOIDPROBE    0x0200  /* disable mouse model probe */
358 #define PSM_CONFIG_NORESET      0x0400  /* don't reset the mouse */
359 #define PSM_CONFIG_FORCETAP     0x0800  /* assume `tap' action exists */
360 #define PSM_CONFIG_IGNPORTERROR 0x1000  /* ignore error in aux port test */
361 #define PSM_CONFIG_HOOKRESUME   0x2000  /* hook the system resume event */
362 #define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
363
364 #define PSM_CONFIG_FLAGS        \
365     (PSM_CONFIG_RESOLUTION |    \
366     PSM_CONFIG_ACCEL |          \
367     PSM_CONFIG_NOCHECKSYNC |    \
368     PSM_CONFIG_NOIDPROBE |      \
369     PSM_CONFIG_NORESET |        \
370     PSM_CONFIG_FORCETAP |       \
371     PSM_CONFIG_IGNPORTERROR |   \
372     PSM_CONFIG_HOOKRESUME |     \
373     PSM_CONFIG_INITAFTERSUSPEND)
374
375 /* other flags (flags) */
376 #define PSM_FLAGS_FINGERDOWN    0x0001  /* VersaPad finger down */
377
378 #define kbdcp(p)                        ((atkbdc_softc_t *)(p))
379 #define ALWAYS_RESTORE_CONTROLLER(kbdc) !(kbdcp(kbdc)->quirks \
380     & KBDC_QUIRK_KEEP_ACTIVATED)
381
382 /* Tunables */
383 static int tap_enabled = -1;
384 TUNABLE_INT("hw.psm.tap_enabled", &tap_enabled);
385
386 static int synaptics_support = 0;
387 TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
388
389 static int trackpoint_support = 0;
390 TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
391
392 static int verbose = PSM_DEBUG;
393 TUNABLE_INT("debug.psm.loglevel", &verbose);
394
395 /* for backward compatibility */
396 #define OLD_MOUSE_GETHWINFO     _IOR('M', 1, old_mousehw_t)
397 #define OLD_MOUSE_GETMODE       _IOR('M', 2, old_mousemode_t)
398 #define OLD_MOUSE_SETMODE       _IOW('M', 3, old_mousemode_t)
399
400 typedef struct old_mousehw {
401         int     buttons;
402         int     iftype;
403         int     type;
404         int     hwid;
405 } old_mousehw_t;
406
407 typedef struct old_mousemode {
408         int     protocol;
409         int     rate;
410         int     resolution;
411         int     accelfactor;
412 } old_mousemode_t;
413
414 /* packet formatting function */
415 typedef int     packetfunc_t(struct psm_softc *, u_char *, int *, int,
416     mousestatus_t *);
417
418 /* function prototypes */
419 static void     psmidentify(driver_t *, device_t);
420 static int      psmprobe(device_t);
421 static int      psmattach(device_t);
422 static int      psmdetach(device_t);
423 static int      psmresume(device_t);
424
425 static d_open_t         psmopen;
426 static d_close_t        psmclose;
427 static d_read_t         psmread;
428 static d_write_t        psmwrite;
429 static d_ioctl_t        psmioctl;
430 static d_poll_t         psmpoll;
431
432 static int      enable_aux_dev(KBDC);
433 static int      disable_aux_dev(KBDC);
434 static int      get_mouse_status(KBDC, int *, int, int);
435 static int      get_aux_id(KBDC);
436 static int      set_mouse_sampling_rate(KBDC, int);
437 static int      set_mouse_scaling(KBDC, int);
438 static int      set_mouse_resolution(KBDC, int);
439 static int      set_mouse_mode(KBDC);
440 static int      get_mouse_buttons(KBDC);
441 static int      is_a_mouse(int);
442 static void     recover_from_error(KBDC);
443 static int      restore_controller(KBDC, int);
444 static int      doinitialize(struct psm_softc *, mousemode_t *);
445 static int      doopen(struct psm_softc *, int);
446 static int      reinitialize(struct psm_softc *, int);
447 static char     *model_name(int);
448 static void     psmsoftintr(void *);
449 static void     psmintr(void *);
450 static void     psmtimeout(void *);
451 static int      timeelapsed(const struct timeval *, int, int,
452                     const struct timeval *);
453 static void     dropqueue(struct psm_softc *);
454 static void     flushpackets(struct psm_softc *);
455 static void     proc_mmanplus(struct psm_softc *, packetbuf_t *,
456                     mousestatus_t *, int *, int *, int *);
457 static int      proc_synaptics(struct psm_softc *, packetbuf_t *,
458                     mousestatus_t *, int *, int *, int *);
459 static void     proc_versapad(struct psm_softc *, packetbuf_t *,
460                     mousestatus_t *, int *, int *, int *);
461 static int      tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
462                     u_char *);
463
464 /* vendor specific features */
465 typedef int     probefunc_t(KBDC, struct psm_softc *);
466
467 static int      mouse_id_proc1(KBDC, int, int, int *);
468 static int      mouse_ext_command(KBDC, int);
469
470 static probefunc_t      enable_groller;
471 static probefunc_t      enable_gmouse;
472 static probefunc_t      enable_aglide;
473 static probefunc_t      enable_kmouse;
474 static probefunc_t      enable_msexplorer;
475 static probefunc_t      enable_msintelli;
476 static probefunc_t      enable_4dmouse;
477 static probefunc_t      enable_4dplus;
478 static probefunc_t      enable_mmanplus;
479 static probefunc_t      enable_synaptics;
480 static probefunc_t      enable_trackpoint;
481 static probefunc_t      enable_versapad;
482
483 static void set_trackpoint_parameters(struct psm_softc *sc);
484 static void synaptics_passthrough_on(struct psm_softc *sc);
485 static void synaptics_passthrough_off(struct psm_softc *sc);
486 static int synaptics_preferred_mode(struct psm_softc *sc);
487 static void synaptics_set_mode(struct psm_softc *sc, int mode_byte);
488
489 static struct {
490         int             model;
491         u_char          syncmask;
492         int             packetsize;
493         probefunc_t     *probefunc;
494 } vendortype[] = {
495         /*
496          * WARNING: the order of probe is very important.  Don't mess it
497          * unless you know what you are doing.
498          */
499         { MOUSE_MODEL_NET,              /* Genius NetMouse */
500           0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse },
501         { MOUSE_MODEL_NETSCROLL,        /* Genius NetScroll */
502           0xc8, 6, enable_groller },
503         { MOUSE_MODEL_MOUSEMANPLUS,     /* Logitech MouseMan+ */
504           0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus },
505         { MOUSE_MODEL_EXPLORER,         /* Microsoft IntelliMouse Explorer */
506           0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer },
507         { MOUSE_MODEL_4D,               /* A4 Tech 4D Mouse */
508           0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse },
509         { MOUSE_MODEL_4DPLUS,           /* A4 Tech 4D+ Mouse */
510           0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
511         { MOUSE_MODEL_SYNAPTICS,        /* Synaptics Touchpad */
512           0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
513         { MOUSE_MODEL_INTELLI,          /* Microsoft IntelliMouse */
514           0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
515         { MOUSE_MODEL_GLIDEPOINT,       /* ALPS GlidePoint */
516           0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide },
517         { MOUSE_MODEL_THINK,            /* Kensington ThinkingMouse */
518           0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
519         { MOUSE_MODEL_VERSAPAD,         /* Interlink electronics VersaPad */
520           0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
521         { MOUSE_MODEL_TRACKPOINT,       /* IBM/Lenovo TrackPoint */
522           0xc0, MOUSE_PS2_PACKETSIZE, enable_trackpoint },
523         { MOUSE_MODEL_GENERIC,
524           0xc0, MOUSE_PS2_PACKETSIZE, NULL },
525 };
526 #define GENERIC_MOUSE_ENTRY     \
527     ((sizeof(vendortype) / sizeof(*vendortype)) - 1)
528
529 /* device driver declarateion */
530 static device_method_t psm_methods[] = {
531         /* Device interface */
532         DEVMETHOD(device_identify,      psmidentify),
533         DEVMETHOD(device_probe,         psmprobe),
534         DEVMETHOD(device_attach,        psmattach),
535         DEVMETHOD(device_detach,        psmdetach),
536         DEVMETHOD(device_resume,        psmresume),
537
538         { 0, 0 }
539 };
540
541 static driver_t psm_driver = {
542         PSM_DRIVER_NAME,
543         psm_methods,
544         sizeof(struct psm_softc),
545 };
546
547 static struct cdevsw psm_cdevsw = {
548         .d_version =    D_VERSION,
549         .d_flags =      D_NEEDGIANT,
550         .d_open =       psmopen,
551         .d_close =      psmclose,
552         .d_read =       psmread,
553         .d_write =      psmwrite,
554         .d_ioctl =      psmioctl,
555         .d_poll =       psmpoll,
556         .d_name =       PSM_DRIVER_NAME,
557 };
558
559 /* device I/O routines */
560 static int
561 enable_aux_dev(KBDC kbdc)
562 {
563         int res;
564
565         res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
566         VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res));
567
568         return (res == PSM_ACK);
569 }
570
571 static int
572 disable_aux_dev(KBDC kbdc)
573 {
574         int res;
575
576         res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
577         VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res));
578
579         return (res == PSM_ACK);
580 }
581
582 static int
583 get_mouse_status(KBDC kbdc, int *status, int flag, int len)
584 {
585         int cmd;
586         int res;
587         int i;
588
589         switch (flag) {
590         case 0:
591         default:
592                 cmd = PSMC_SEND_DEV_STATUS;
593                 break;
594         case 1:
595                 cmd = PSMC_SEND_DEV_DATA;
596                 break;
597         }
598         empty_aux_buffer(kbdc, 5);
599         res = send_aux_command(kbdc, cmd);
600         VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
601             (flag == 1) ? "DATA" : "STATUS", res));
602         if (res != PSM_ACK)
603                 return (0);
604
605         for (i = 0; i < len; ++i) {
606                 status[i] = read_aux_data(kbdc);
607                 if (status[i] < 0)
608                         break;
609         }
610
611         VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n",
612             (flag == 1) ? "data" : "status", status[0], status[1], status[2]));
613
614         return (i);
615 }
616
617 static int
618 get_aux_id(KBDC kbdc)
619 {
620         int res;
621         int id;
622
623         empty_aux_buffer(kbdc, 5);
624         res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
625         VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res));
626         if (res != PSM_ACK)
627                 return (-1);
628
629         /* 10ms delay */
630         DELAY(10000);
631
632         id = read_aux_data(kbdc);
633         VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id));
634
635         return (id);
636 }
637
638 static int
639 set_mouse_sampling_rate(KBDC kbdc, int rate)
640 {
641         int res;
642
643         res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
644         VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res));
645
646         return ((res == PSM_ACK) ? rate : -1);
647 }
648
649 static int
650 set_mouse_scaling(KBDC kbdc, int scale)
651 {
652         int res;
653
654         switch (scale) {
655         case 1:
656         default:
657                 scale = PSMC_SET_SCALING11;
658                 break;
659         case 2:
660                 scale = PSMC_SET_SCALING21;
661                 break;
662         }
663         res = send_aux_command(kbdc, scale);
664         VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
665             (scale == PSMC_SET_SCALING21) ? "21" : "11", res));
666
667         return (res == PSM_ACK);
668 }
669
670 /* `val' must be 0 through PSMD_MAX_RESOLUTION */
671 static int
672 set_mouse_resolution(KBDC kbdc, int val)
673 {
674         int res;
675
676         res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
677         VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res));
678
679         return ((res == PSM_ACK) ? val : -1);
680 }
681
682 /*
683  * NOTE: once `set_mouse_mode()' is called, the mouse device must be
684  * re-enabled by calling `enable_aux_dev()'
685  */
686 static int
687 set_mouse_mode(KBDC kbdc)
688 {
689         int res;
690
691         res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
692         VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res));
693
694         return (res == PSM_ACK);
695 }
696
697 static int
698 get_mouse_buttons(KBDC kbdc)
699 {
700         int c = 2;              /* assume two buttons by default */
701         int status[3];
702
703         /*
704          * NOTE: a special sequence to obtain Logitech Mouse specific
705          * information: set resolution to 25 ppi, set scaling to 1:1, set
706          * scaling to 1:1, set scaling to 1:1. Then the second byte of the
707          * mouse status bytes is the number of available buttons.
708          * Some manufactures also support this sequence.
709          */
710         if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
711                 return (c);
712         if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) &&
713             set_mouse_scaling(kbdc, 1) &&
714             get_mouse_status(kbdc, status, 0, 3) >= 3 && status[1] != 0)
715                 return (status[1]);
716         return (c);
717 }
718
719 /* misc subroutines */
720 /*
721  * Someday, I will get the complete list of valid pointing devices and
722  * their IDs... XXX
723  */
724 static int
725 is_a_mouse(int id)
726 {
727 #if 0
728         static int valid_ids[] = {
729                 PSM_MOUSE_ID,           /* mouse */
730                 PSM_BALLPOINT_ID,       /* ballpoint device */
731                 PSM_INTELLI_ID,         /* Intellimouse */
732                 PSM_EXPLORER_ID,        /* Intellimouse Explorer */
733                 -1                      /* end of table */
734         };
735         int i;
736
737         for (i = 0; valid_ids[i] >= 0; ++i)
738         if (valid_ids[i] == id)
739                 return (TRUE);
740         return (FALSE);
741 #else
742         return (TRUE);
743 #endif
744 }
745
746 static char *
747 model_name(int model)
748 {
749         static struct {
750                 int     model_code;
751                 char    *model_name;
752         } models[] = {
753                 { MOUSE_MODEL_NETSCROLL,        "NetScroll" },
754                 { MOUSE_MODEL_NET,              "NetMouse/NetScroll Optical" },
755                 { MOUSE_MODEL_GLIDEPOINT,       "GlidePoint" },
756                 { MOUSE_MODEL_THINK,            "ThinkingMouse" },
757                 { MOUSE_MODEL_INTELLI,          "IntelliMouse" },
758                 { MOUSE_MODEL_MOUSEMANPLUS,     "MouseMan+" },
759                 { MOUSE_MODEL_VERSAPAD,         "VersaPad" },
760                 { MOUSE_MODEL_EXPLORER,         "IntelliMouse Explorer" },
761                 { MOUSE_MODEL_4D,               "4D Mouse" },
762                 { MOUSE_MODEL_4DPLUS,           "4D+ Mouse" },
763                 { MOUSE_MODEL_SYNAPTICS,        "Synaptics Touchpad" },
764                 { MOUSE_MODEL_TRACKPOINT,       "IBM/Lenovo TrackPoint" },
765                 { MOUSE_MODEL_GENERIC,          "Generic PS/2 mouse" },
766                 { MOUSE_MODEL_UNKNOWN,          "Unknown" },
767         };
768         int i;
769
770         for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i)
771                 if (models[i].model_code == model)
772                         break;
773         return (models[i].model_name);
774 }
775
776 static void
777 recover_from_error(KBDC kbdc)
778 {
779         /* discard anything left in the output buffer */
780         empty_both_buffers(kbdc, 10);
781
782 #if 0
783         /*
784          * NOTE: KBDC_RESET_KBD may not restore the communication between the
785          * keyboard and the controller.
786          */
787         reset_kbd(kbdc);
788 #else
789         /*
790          * NOTE: somehow diagnostic and keyboard port test commands bring the
791          * keyboard back.
792          */
793         if (!test_controller(kbdc))
794                 log(LOG_ERR, "psm: keyboard controller failed.\n");
795         /* if there isn't a keyboard in the system, the following error is OK */
796         if (test_kbd_port(kbdc) != 0)
797                 VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n"));
798 #endif
799 }
800
801 static int
802 restore_controller(KBDC kbdc, int command_byte)
803 {
804         empty_both_buffers(kbdc, 10);
805
806         if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
807                 log(LOG_ERR, "psm: failed to restore the keyboard controller "
808                     "command byte.\n");
809                 empty_both_buffers(kbdc, 10);
810                 return (FALSE);
811         } else {
812                 empty_both_buffers(kbdc, 10);
813                 return (TRUE);
814         }
815 }
816
817 /*
818  * Re-initialize the aux port and device. The aux port must be enabled
819  * and its interrupt must be disabled before calling this routine.
820  * The aux device will be disabled before returning.
821  * The keyboard controller must be locked via `kbdc_lock()' before
822  * calling this routine.
823  */
824 static int
825 doinitialize(struct psm_softc *sc, mousemode_t *mode)
826 {
827         KBDC kbdc = sc->kbdc;
828         int stat[3];
829         int i;
830
831         switch((i = test_aux_port(kbdc))) {
832         case 1: /* ignore these errors */
833         case 2:
834         case 3:
835         case PSM_ACK:
836                 if (verbose)
837                         log(LOG_DEBUG,
838                             "psm%d: strange result for test aux port (%d).\n",
839                             sc->unit, i);
840                 /* FALLTHROUGH */
841         case 0:         /* no error */
842                 break;
843         case -1:        /* time out */
844         default:        /* error */
845                 recover_from_error(kbdc);
846                 if (sc->config & PSM_CONFIG_IGNPORTERROR)
847                         break;
848                 log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
849                     sc->unit, i);
850                 return (FALSE);
851         }
852
853         if (sc->config & PSM_CONFIG_NORESET) {
854                 /*
855                  * Don't try to reset the pointing device.  It may possibly
856                  * be left in the unknown state, though...
857                  */
858         } else {
859                 /*
860                  * NOTE: some controllers appears to hang the `keyboard' when
861                  * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
862                  */
863                 if (!reset_aux_dev(kbdc)) {
864                         recover_from_error(kbdc);
865                         log(LOG_ERR, "psm%d: failed to reset the aux device.\n",
866                             sc->unit);
867                         return (FALSE);
868                 }
869         }
870
871         /*
872          * both the aux port and the aux device is functioning, see
873          * if the device can be enabled.
874          */
875         if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
876                 log(LOG_ERR, "psm%d: failed to enable the aux device.\n",
877                     sc->unit);
878                 return (FALSE);
879         }
880         empty_both_buffers(kbdc, 10);   /* remove stray data if any */
881
882         /* Re-enable the mouse. */
883         for (i = 0; vendortype[i].probefunc != NULL; ++i)
884                 if (vendortype[i].model == sc->hw.model)
885                         (*vendortype[i].probefunc)(sc->kbdc, NULL);
886
887         /* set mouse parameters */
888         if (mode != (mousemode_t *)NULL) {
889                 if (mode->rate > 0)
890                         mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
891                 if (mode->resolution >= 0)
892                         mode->resolution =
893                             set_mouse_resolution(kbdc, mode->resolution);
894                 set_mouse_scaling(kbdc, 1);
895                 set_mouse_mode(kbdc);
896
897                 /*
898                  * Trackpoint settings are lost on resume.
899                  * Restore them here.
900                  */
901                 if (sc->tphw > 0)
902                         set_trackpoint_parameters(sc);
903         }
904
905         /* Record sync on the next data packet we see. */
906         sc->flags |= PSM_NEED_SYNCBITS;
907
908         /* just check the status of the mouse */
909         if (get_mouse_status(kbdc, stat, 0, 3) < 3)
910                 log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n",
911                     sc->unit);
912
913         return (TRUE);
914 }
915
916 static int
917 doopen(struct psm_softc *sc, int command_byte)
918 {
919         int stat[3];
920
921         /*
922          * FIXME: Synaptics TouchPad seems to go back to Relative Mode with
923          * no obvious reason. Thus we check the current mode and restore the
924          * Absolute Mode if it was cleared.
925          *
926          * The previous hack at the end of psmprobe() wasn't efficient when
927          * moused(8) was restarted.
928          *
929          * A Reset (FF) or Set Defaults (F6) command would clear the
930          * Absolute Mode bit. But a verbose boot or debug.psm.loglevel=5
931          * doesn't show any evidence of such a command.
932          */
933         if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
934                 mouse_ext_command(sc->kbdc, 1);
935                 get_mouse_status(sc->kbdc, stat, 0, 3);
936                 if ((SYNAPTICS_VERSION_GE(sc->synhw, 7, 5) ||
937                      stat[1] == 0x47) &&
938                      stat[2] == 0x40) {
939                         synaptics_set_mode(sc, synaptics_preferred_mode(sc));
940                         VLOG(5, (LOG_DEBUG, "psm%d: Synaptis Absolute Mode "
941                             "hopefully restored\n",
942                             sc->unit));
943                 }
944         }
945
946         /*
947          * A user may want to disable tap and drag gestures on a Synaptics
948          * TouchPad when it operates in Relative Mode.
949          */
950         if (sc->hw.model == MOUSE_MODEL_GENERIC) {
951                 if (tap_enabled > 0) {
952                         /*
953                          * Enable tap & drag gestures. We use a Mode Byte
954                          * and clear the DisGest bit (see Â§2.5 of Synaptics
955                          * TouchPad Interfacing Guide).
956                          */
957                         VLOG(2, (LOG_DEBUG,
958                             "psm%d: enable tap and drag gestures\n",
959                             sc->unit));
960                         mouse_ext_command(sc->kbdc, 0x00);
961                         set_mouse_sampling_rate(sc->kbdc, 20);
962                 } else if (tap_enabled == 0) {
963                         /*
964                          * Disable tap & drag gestures. We use a Mode Byte
965                          * and set the DisGest bit (see Â§2.5 of Synaptics
966                          * TouchPad Interfacing Guide).
967                          */
968                         VLOG(2, (LOG_DEBUG,
969                             "psm%d: disable tap and drag gestures\n",
970                             sc->unit));
971                         mouse_ext_command(sc->kbdc, 0x04);
972                         set_mouse_sampling_rate(sc->kbdc, 20);
973                 }
974         }
975
976         /* enable the mouse device */
977         if (!enable_aux_dev(sc->kbdc)) {
978                 /* MOUSE ERROR: failed to enable the mouse because:
979                  * 1) the mouse is faulty,
980                  * 2) the mouse has been removed(!?)
981                  * In the latter case, the keyboard may have hung, and need
982                  * recovery procedure...
983                  */
984                 recover_from_error(sc->kbdc);
985 #if 0
986                 /* FIXME: we could reset the mouse here and try to enable
987                  * it again. But it will take long time and it's not a good
988                  * idea to disable the keyboard that long...
989                  */
990                 if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
991                         recover_from_error(sc->kbdc);
992 #else
993                 {
994 #endif
995                         restore_controller(sc->kbdc, command_byte);
996                         /* mark this device is no longer available */
997                         sc->state &= ~PSM_VALID;
998                         log(LOG_ERR,
999                             "psm%d: failed to enable the device (doopen).\n",
1000                         sc->unit);
1001                         return (EIO);
1002                 }
1003         }
1004
1005         if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1006                 log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n",
1007                     sc->unit);
1008
1009         /* enable the aux port and interrupt */
1010         if (!set_controller_command_byte(sc->kbdc,
1011             kbdc_get_device_mask(sc->kbdc),
1012             (command_byte & KBD_KBD_CONTROL_BITS) |
1013             KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
1014                 /* CONTROLLER ERROR */
1015                 disable_aux_dev(sc->kbdc);
1016                 restore_controller(sc->kbdc, command_byte);
1017                 log(LOG_ERR,
1018                     "psm%d: failed to enable the aux interrupt (doopen).\n",
1019                     sc->unit);
1020                 return (EIO);
1021         }
1022
1023         /* start the watchdog timer */
1024         sc->watchdog = FALSE;
1025         callout_reset(&sc->callout, hz * 2, psmtimeout, sc);
1026
1027         return (0);
1028 }
1029
1030 static int
1031 reinitialize(struct psm_softc *sc, int doinit)
1032 {
1033         int err;
1034         int c;
1035         int s;
1036
1037         /* don't let anybody mess with the aux device */
1038         if (!kbdc_lock(sc->kbdc, TRUE))
1039                 return (EIO);
1040         s = spltty();
1041
1042         /* block our watchdog timer */
1043         sc->watchdog = FALSE;
1044         callout_stop(&sc->callout);
1045
1046         /* save the current controller command byte */
1047         empty_both_buffers(sc->kbdc, 10);
1048         c = get_controller_command_byte(sc->kbdc);
1049         VLOG(2, (LOG_DEBUG,
1050             "psm%d: current command byte: %04x (reinitialize).\n",
1051             sc->unit, c));
1052
1053         /* enable the aux port but disable the aux interrupt and the keyboard */
1054         if ((c == -1) || !set_controller_command_byte(sc->kbdc,
1055             kbdc_get_device_mask(sc->kbdc),
1056             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1057             KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1058                 /* CONTROLLER ERROR */
1059                 splx(s);
1060                 kbdc_lock(sc->kbdc, FALSE);
1061                 log(LOG_ERR,
1062                     "psm%d: unable to set the command byte (reinitialize).\n",
1063                     sc->unit);
1064                 return (EIO);
1065         }
1066
1067         /* flush any data */
1068         if (sc->state & PSM_VALID) {
1069                 /* this may fail; but never mind... */
1070                 disable_aux_dev(sc->kbdc);
1071                 empty_aux_buffer(sc->kbdc, 10);
1072         }
1073         flushpackets(sc);
1074         sc->syncerrors = 0;
1075         sc->pkterrors = 0;
1076         memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr));
1077
1078         /* try to detect the aux device; are you still there? */
1079         err = 0;
1080         if (doinit) {
1081                 if (doinitialize(sc, &sc->mode)) {
1082                         /* yes */
1083                         sc->state |= PSM_VALID;
1084                 } else {
1085                         /* the device has gone! */
1086                         restore_controller(sc->kbdc, c);
1087                         sc->state &= ~PSM_VALID;
1088                         log(LOG_ERR,
1089                             "psm%d: the aux device has gone! (reinitialize).\n",
1090                             sc->unit);
1091                         err = ENXIO;
1092                 }
1093         }
1094         splx(s);
1095
1096         /* restore the driver state */
1097         if ((sc->state & PSM_OPEN) && (err == 0)) {
1098                 /* enable the aux device and the port again */
1099                 err = doopen(sc, c);
1100                 if (err != 0)
1101                         log(LOG_ERR, "psm%d: failed to enable the device "
1102                             "(reinitialize).\n", sc->unit);
1103         } else {
1104                 /* restore the keyboard port and disable the aux port */
1105                 if (!set_controller_command_byte(sc->kbdc,
1106                     kbdc_get_device_mask(sc->kbdc),
1107                     (c & KBD_KBD_CONTROL_BITS) |
1108                     KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1109                         /* CONTROLLER ERROR */
1110                         log(LOG_ERR, "psm%d: failed to disable the aux port "
1111                             "(reinitialize).\n", sc->unit);
1112                         err = EIO;
1113                 }
1114         }
1115
1116         kbdc_lock(sc->kbdc, FALSE);
1117         return (err);
1118 }
1119
1120 /* psm driver entry points */
1121
1122 static void
1123 psmidentify(driver_t *driver, device_t parent)
1124 {
1125         device_t psmc;
1126         device_t psm;
1127         u_long irq;
1128         int unit;
1129
1130         unit = device_get_unit(parent);
1131
1132         /* always add at least one child */
1133         psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit);
1134         if (psm == NULL)
1135                 return;
1136
1137         irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX);
1138         if (irq > 0)
1139                 return;
1140
1141         /*
1142          * If the PS/2 mouse device has already been reported by ACPI or
1143          * PnP BIOS, obtain the IRQ resource from it.
1144          * (See psmcpnp_attach() below.)
1145          */
1146         psmc = device_find_child(device_get_parent(parent),
1147             PSMCPNP_DRIVER_NAME, unit);
1148         if (psmc == NULL)
1149                 return;
1150         irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0);
1151         if (irq <= 0)
1152                 return;
1153         bus_delete_resource(psmc, SYS_RES_IRQ, 0);
1154         bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
1155 }
1156
1157 #define endprobe(v)     do {                    \
1158         if (bootverbose)                        \
1159                 --verbose;                      \
1160         kbdc_set_device_mask(sc->kbdc, mask);   \
1161         kbdc_lock(sc->kbdc, FALSE);             \
1162         return (v);                             \
1163 } while (0)
1164
1165 static int
1166 psmprobe(device_t dev)
1167 {
1168         int unit = device_get_unit(dev);
1169         struct psm_softc *sc = device_get_softc(dev);
1170         int stat[3];
1171         int command_byte;
1172         int mask;
1173         int rid;
1174         int i;
1175
1176 #if 0
1177         kbdc_debug(TRUE);
1178 #endif
1179
1180         /* see if IRQ is available */
1181         rid = KBDC_RID_AUX;
1182         sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1183         if (sc->intr == NULL) {
1184                 if (bootverbose)
1185                         device_printf(dev, "unable to allocate IRQ\n");
1186                 return (ENXIO);
1187         }
1188         bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1189
1190         sc->unit = unit;
1191         sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
1192         sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS;
1193         /* XXX: for backward compatibility */
1194 #if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM)
1195         sc->config |=
1196 #ifdef PSM_RESETAFTERSUSPEND
1197         PSM_CONFIG_INITAFTERSUSPEND;
1198 #else
1199         PSM_CONFIG_HOOKRESUME;
1200 #endif
1201 #endif /* PSM_HOOKRESUME | PSM_HOOKAPM */
1202         sc->flags = 0;
1203         if (bootverbose)
1204                 ++verbose;
1205
1206         device_set_desc(dev, "PS/2 Mouse");
1207
1208         if (!kbdc_lock(sc->kbdc, TRUE)) {
1209                 printf("psm%d: unable to lock the controller.\n", unit);
1210                 if (bootverbose)
1211                         --verbose;
1212                 return (ENXIO);
1213         }
1214
1215         /*
1216          * NOTE: two bits in the command byte controls the operation of the
1217          * aux port (mouse port): the aux port disable bit (bit 5) and the aux
1218          * port interrupt (IRQ 12) enable bit (bit 2).
1219          */
1220
1221         /* discard anything left after the keyboard initialization */
1222         empty_both_buffers(sc->kbdc, 10);
1223
1224         /* save the current command byte; it will be used later */
1225         mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
1226         command_byte = get_controller_command_byte(sc->kbdc);
1227         if (verbose)
1228                 printf("psm%d: current command byte:%04x\n", unit,
1229                     command_byte);
1230         if (command_byte == -1) {
1231                 /* CONTROLLER ERROR */
1232                 printf("psm%d: unable to get the current command byte value.\n",
1233                         unit);
1234                 endprobe(ENXIO);
1235         }
1236
1237         /*
1238          * disable the keyboard port while probing the aux port, which must be
1239          * enabled during this routine
1240          */
1241         if (!set_controller_command_byte(sc->kbdc,
1242             KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1243             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1244             KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1245                 /*
1246                  * this is CONTROLLER ERROR; I don't know how to recover
1247                  * from this error...
1248                  */
1249                 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1250                         restore_controller(sc->kbdc, command_byte);
1251                 printf("psm%d: unable to set the command byte.\n", unit);
1252                 endprobe(ENXIO);
1253         }
1254         write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
1255
1256         /*
1257          * NOTE: `test_aux_port()' is designed to return with zero if the aux
1258          * port exists and is functioning. However, some controllers appears
1259          * to respond with zero even when the aux port doesn't exist. (It may
1260          * be that this is only the case when the controller DOES have the aux
1261          * port but the port is not wired on the motherboard.) The keyboard
1262          * controllers without the port, such as the original AT, are
1263          * supposed to return with an error code or simply time out. In any
1264          * case, we have to continue probing the port even when the controller
1265          * passes this test.
1266          *
1267          * XXX: some controllers erroneously return the error code 1, 2 or 3
1268          * when it has a perfectly functional aux port. We have to ignore
1269          * this error code. Even if the controller HAS error with the aux
1270          * port, it will be detected later...
1271          * XXX: another incompatible controller returns PSM_ACK (0xfa)...
1272          */
1273         switch ((i = test_aux_port(sc->kbdc))) {
1274         case 1:         /* ignore these errors */
1275         case 2:
1276         case 3:
1277         case PSM_ACK:
1278                 if (verbose)
1279                         printf("psm%d: strange result for test aux port "
1280                             "(%d).\n", unit, i);
1281                 /* FALLTHROUGH */
1282         case 0:         /* no error */
1283                 break;
1284         case -1:        /* time out */
1285         default:        /* error */
1286                 recover_from_error(sc->kbdc);
1287                 if (sc->config & PSM_CONFIG_IGNPORTERROR)
1288                         break;
1289                 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1290                         restore_controller(sc->kbdc, command_byte);
1291                 if (verbose)
1292                         printf("psm%d: the aux port is not functioning (%d).\n",
1293                             unit, i);
1294                 endprobe(ENXIO);
1295         }
1296
1297         if (sc->config & PSM_CONFIG_NORESET) {
1298                 /*
1299                  * Don't try to reset the pointing device.  It may possibly be
1300                  * left in an unknown state, though...
1301                  */
1302         } else {
1303                 /*
1304                  * NOTE: some controllers appears to hang the `keyboard' when
1305                  * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
1306                  *
1307                  * Attempt to reset the controller twice -- this helps
1308                  * pierce through some KVM switches. The second reset
1309                  * is non-fatal.
1310                  */
1311                 if (!reset_aux_dev(sc->kbdc)) {
1312                         recover_from_error(sc->kbdc);
1313                         if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1314                                 restore_controller(sc->kbdc, command_byte);
1315                         if (verbose)
1316                                 printf("psm%d: failed to reset the aux "
1317                                     "device.\n", unit);
1318                         endprobe(ENXIO);
1319                 } else if (!reset_aux_dev(sc->kbdc)) {
1320                         recover_from_error(sc->kbdc);
1321                         if (verbose >= 2)
1322                                 printf("psm%d: failed to reset the aux device "
1323                                     "(2).\n", unit);
1324                 }
1325         }
1326
1327         /*
1328          * both the aux port and the aux device are functioning, see if the
1329          * device can be enabled. NOTE: when enabled, the device will start
1330          * sending data; we shall immediately disable the device once we know
1331          * the device can be enabled.
1332          */
1333         if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
1334                 /* MOUSE ERROR */
1335                 recover_from_error(sc->kbdc);
1336                 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1337                         restore_controller(sc->kbdc, command_byte);
1338                 if (verbose)
1339                         printf("psm%d: failed to enable the aux device.\n",
1340                             unit);
1341                 endprobe(ENXIO);
1342         }
1343
1344         /* save the default values after reset */
1345         if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
1346                 sc->dflt_mode.rate = sc->mode.rate = stat[2];
1347                 sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1348         } else {
1349                 sc->dflt_mode.rate = sc->mode.rate = -1;
1350                 sc->dflt_mode.resolution = sc->mode.resolution = -1;
1351         }
1352
1353         /* hardware information */
1354         sc->hw.iftype = MOUSE_IF_PS2;
1355
1356         /* verify the device is a mouse */
1357         sc->hw.hwid = get_aux_id(sc->kbdc);
1358         if (!is_a_mouse(sc->hw.hwid)) {
1359                 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1360                         restore_controller(sc->kbdc, command_byte);
1361                 if (verbose)
1362                         printf("psm%d: unknown device type (%d).\n", unit,
1363                             sc->hw.hwid);
1364                 endprobe(ENXIO);
1365         }
1366         switch (sc->hw.hwid) {
1367         case PSM_BALLPOINT_ID:
1368                 sc->hw.type = MOUSE_TRACKBALL;
1369                 break;
1370         case PSM_MOUSE_ID:
1371         case PSM_INTELLI_ID:
1372         case PSM_EXPLORER_ID:
1373         case PSM_4DMOUSE_ID:
1374         case PSM_4DPLUS_ID:
1375                 sc->hw.type = MOUSE_MOUSE;
1376                 break;
1377         default:
1378                 sc->hw.type = MOUSE_UNKNOWN;
1379                 break;
1380         }
1381
1382         if (sc->config & PSM_CONFIG_NOIDPROBE) {
1383                 sc->hw.buttons = 2;
1384                 i = GENERIC_MOUSE_ENTRY;
1385         } else {
1386                 /* # of buttons */
1387                 sc->hw.buttons = get_mouse_buttons(sc->kbdc);
1388
1389                 /* other parameters */
1390                 for (i = 0; vendortype[i].probefunc != NULL; ++i)
1391                         if ((*vendortype[i].probefunc)(sc->kbdc, sc)) {
1392                                 if (verbose >= 2)
1393                                         printf("psm%d: found %s\n", unit,
1394                                             model_name(vendortype[i].model));
1395                                 break;
1396                         }
1397         }
1398
1399         sc->hw.model = vendortype[i].model;
1400
1401         sc->dflt_mode.level = PSM_LEVEL_BASE;
1402         sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
1403         sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
1404         if (sc->config & PSM_CONFIG_NOCHECKSYNC)
1405                 sc->dflt_mode.syncmask[0] = 0;
1406         else
1407                 sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
1408         if (sc->config & PSM_CONFIG_FORCETAP)
1409                 sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP;
1410         sc->dflt_mode.syncmask[1] = 0;  /* syncbits */
1411         sc->mode = sc->dflt_mode;
1412         sc->mode.packetsize = vendortype[i].packetsize;
1413
1414         /* set mouse parameters */
1415 #if 0
1416         /*
1417          * A version of Logitech FirstMouse+ won't report wheel movement,
1418          * if SET_DEFAULTS is sent...  Don't use this command.
1419          * This fix was found by Takashi Nishida.
1420          */
1421         i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
1422         if (verbose >= 2)
1423                 printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
1424 #endif
1425         if (sc->config & PSM_CONFIG_RESOLUTION)
1426                 sc->mode.resolution =
1427                     set_mouse_resolution(sc->kbdc,
1428                     (sc->config & PSM_CONFIG_RESOLUTION) - 1);
1429         else if (sc->mode.resolution >= 0)
1430                 sc->mode.resolution =
1431                     set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
1432         if (sc->mode.rate > 0)
1433                 sc->mode.rate =
1434                     set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
1435         set_mouse_scaling(sc->kbdc, 1);
1436
1437         /* Record sync on the next data packet we see. */
1438         sc->flags |= PSM_NEED_SYNCBITS;
1439
1440         /* just check the status of the mouse */
1441         /*
1442          * NOTE: XXX there are some arcane controller/mouse combinations out
1443          * there, which hung the controller unless there is data transmission
1444          * after ACK from the mouse.
1445          */
1446         if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1447                 printf("psm%d: failed to get status.\n", unit);
1448         else {
1449                 /*
1450                  * When in its native mode, some mice operate with different
1451                  * default parameters than in the PS/2 compatible mode.
1452                  */
1453                 sc->dflt_mode.rate = sc->mode.rate = stat[2];
1454                 sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1455         }
1456
1457         /* disable the aux port for now... */
1458         if (!set_controller_command_byte(sc->kbdc,
1459             KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1460             (command_byte & KBD_KBD_CONTROL_BITS) |
1461             KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1462                 /*
1463                  * this is CONTROLLER ERROR; I don't know the proper way to
1464                  * recover from this error...
1465                  */
1466                 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1467                         restore_controller(sc->kbdc, command_byte);
1468                 printf("psm%d: unable to set the command byte.\n", unit);
1469                 endprobe(ENXIO);
1470         }
1471
1472         /* done */
1473         kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
1474         kbdc_lock(sc->kbdc, FALSE);
1475         return (0);
1476 }
1477
1478 static int
1479 psmattach(device_t dev)
1480 {
1481         int unit = device_get_unit(dev);
1482         struct psm_softc *sc = device_get_softc(dev);
1483         int error;
1484         int rid;
1485
1486         /* Setup initial state */
1487         sc->state = PSM_VALID;
1488         callout_init(&sc->callout, 0);
1489         callout_init(&sc->softcallout, 0);
1490
1491         /* Setup our interrupt handler */
1492         rid = KBDC_RID_AUX;
1493         sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1494         if (sc->intr == NULL)
1495                 return (ENXIO);
1496         error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc,
1497             &sc->ih);
1498         if (error) {
1499                 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1500                 return (error);
1501         }
1502
1503         /* Done */
1504         sc->dev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "psm%d", unit);
1505         sc->dev->si_drv1 = sc;
1506         sc->bdev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "bpsm%d", unit);
1507         sc->bdev->si_drv1 = sc;
1508
1509         /* Some touchpad devices need full reinitialization after suspend. */
1510         switch (sc->hw.model) {
1511         case MOUSE_MODEL_SYNAPTICS:
1512         case MOUSE_MODEL_GLIDEPOINT:
1513         case MOUSE_MODEL_VERSAPAD:
1514                 sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1515                 break;
1516         default:
1517                 if (sc->synhw.infoMajor >= 4 || sc->tphw > 0)
1518                         sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1519                 break;
1520         }
1521
1522         if (!verbose)
1523                 printf("psm%d: model %s, device ID %d\n",
1524                     unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
1525         else {
1526                 printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
1527                     unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff,
1528                     sc->hw.hwid >> 8, sc->hw.buttons);
1529                 printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
1530                     unit, sc->config, sc->flags, sc->mode.packetsize);
1531                 printf("psm%d: syncmask:%02x, syncbits:%02x\n",
1532                     unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
1533         }
1534
1535         if (bootverbose)
1536                 --verbose;
1537
1538         return (0);
1539 }
1540
1541 static int
1542 psmdetach(device_t dev)
1543 {
1544         struct psm_softc *sc;
1545         int rid;
1546
1547         sc = device_get_softc(dev);
1548         if (sc->state & PSM_OPEN)
1549                 return (EBUSY);
1550
1551         rid = KBDC_RID_AUX;
1552         bus_teardown_intr(dev, sc->intr, sc->ih);
1553         bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1554
1555         destroy_dev(sc->dev);
1556         destroy_dev(sc->bdev);
1557
1558         callout_drain(&sc->callout);
1559         callout_drain(&sc->softcallout);
1560
1561         return (0);
1562 }
1563
1564 static int
1565 psmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
1566 {
1567         struct psm_softc *sc;
1568         int command_byte;
1569         int err;
1570         int s;
1571
1572         /* Get device data */
1573         sc = dev->si_drv1;
1574         if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
1575                 /* the device is no longer valid/functioning */
1576                 return (ENXIO);
1577         }
1578
1579         /* Disallow multiple opens */
1580         if (sc->state & PSM_OPEN)
1581                 return (EBUSY);
1582
1583         device_busy(devclass_get_device(psm_devclass, sc->unit));
1584
1585         /* Initialize state */
1586         sc->mode.level = sc->dflt_mode.level;
1587         sc->mode.protocol = sc->dflt_mode.protocol;
1588         sc->watchdog = FALSE;
1589         sc->async = NULL;
1590
1591         /* flush the event queue */
1592         sc->queue.count = 0;
1593         sc->queue.head = 0;
1594         sc->queue.tail = 0;
1595         sc->status.flags = 0;
1596         sc->status.button = 0;
1597         sc->status.obutton = 0;
1598         sc->status.dx = 0;
1599         sc->status.dy = 0;
1600         sc->status.dz = 0;
1601         sc->button = 0;
1602         sc->pqueue_start = 0;
1603         sc->pqueue_end = 0;
1604
1605         /* empty input buffer */
1606         flushpackets(sc);
1607         sc->syncerrors = 0;
1608         sc->pkterrors = 0;
1609
1610         /* don't let timeout routines in the keyboard driver to poll the kbdc */
1611         if (!kbdc_lock(sc->kbdc, TRUE))
1612                 return (EIO);
1613
1614         /* save the current controller command byte */
1615         s = spltty();
1616         command_byte = get_controller_command_byte(sc->kbdc);
1617
1618         /* enable the aux port and temporalily disable the keyboard */
1619         if (command_byte == -1 || !set_controller_command_byte(sc->kbdc,
1620             kbdc_get_device_mask(sc->kbdc),
1621             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1622             KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1623                 /* CONTROLLER ERROR; do you know how to get out of this? */
1624                 kbdc_lock(sc->kbdc, FALSE);
1625                 splx(s);
1626                 log(LOG_ERR,
1627                     "psm%d: unable to set the command byte (psmopen).\n",
1628                     sc->unit);
1629                 return (EIO);
1630         }
1631         /*
1632          * Now that the keyboard controller is told not to generate
1633          * the keyboard and mouse interrupts, call `splx()' to allow
1634          * the other tty interrupts. The clock interrupt may also occur,
1635          * but timeout routines will be blocked by the poll flag set
1636          * via `kbdc_lock()'
1637          */
1638         splx(s);
1639
1640         /* enable the mouse device */
1641         err = doopen(sc, command_byte);
1642
1643         /* done */
1644         if (err == 0)
1645                 sc->state |= PSM_OPEN;
1646         kbdc_lock(sc->kbdc, FALSE);
1647         return (err);
1648 }
1649
1650 static int
1651 psmclose(struct cdev *dev, int flag, int fmt, struct thread *td)
1652 {
1653         struct psm_softc *sc = dev->si_drv1;
1654         int stat[3];
1655         int command_byte;
1656         int s;
1657
1658         /* don't let timeout routines in the keyboard driver to poll the kbdc */
1659         if (!kbdc_lock(sc->kbdc, TRUE))
1660                 return (EIO);
1661
1662         /* save the current controller command byte */
1663         s = spltty();
1664         command_byte = get_controller_command_byte(sc->kbdc);
1665         if (command_byte == -1) {
1666                 kbdc_lock(sc->kbdc, FALSE);
1667                 splx(s);
1668                 return (EIO);
1669         }
1670
1671         /* disable the aux interrupt and temporalily disable the keyboard */
1672         if (!set_controller_command_byte(sc->kbdc,
1673             kbdc_get_device_mask(sc->kbdc),
1674             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1675             KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1676                 log(LOG_ERR,
1677                     "psm%d: failed to disable the aux int (psmclose).\n",
1678                     sc->unit);
1679                 /* CONTROLLER ERROR;
1680                  * NOTE: we shall force our way through. Because the only
1681                  * ill effect we shall see is that we may not be able
1682                  * to read ACK from the mouse, and it doesn't matter much
1683                  * so long as the mouse will accept the DISABLE command.
1684                  */
1685         }
1686         splx(s);
1687
1688         /* stop the watchdog timer */
1689         callout_stop(&sc->callout);
1690
1691         /* remove anything left in the output buffer */
1692         empty_aux_buffer(sc->kbdc, 10);
1693
1694         /* disable the aux device, port and interrupt */
1695         if (sc->state & PSM_VALID) {
1696                 if (!disable_aux_dev(sc->kbdc)) {
1697                         /* MOUSE ERROR;
1698                          * NOTE: we don't return (error) and continue,
1699                          * pretending we have successfully disabled the device.
1700                          * It's OK because the interrupt routine will discard
1701                          * any data from the mouse hereafter.
1702                          */
1703                         log(LOG_ERR,
1704                             "psm%d: failed to disable the device (psmclose).\n",
1705                             sc->unit);
1706                 }
1707
1708                 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1709                         log(LOG_DEBUG,
1710                             "psm%d: failed to get status (psmclose).\n",
1711                             sc->unit);
1712         }
1713
1714         if (!set_controller_command_byte(sc->kbdc,
1715             kbdc_get_device_mask(sc->kbdc),
1716             (command_byte & KBD_KBD_CONTROL_BITS) |
1717             KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1718                 /*
1719                  * CONTROLLER ERROR;
1720                  * we shall ignore this error; see the above comment.
1721                  */
1722                 log(LOG_ERR,
1723                     "psm%d: failed to disable the aux port (psmclose).\n",
1724                     sc->unit);
1725         }
1726
1727         /* remove anything left in the output buffer */
1728         empty_aux_buffer(sc->kbdc, 10);
1729
1730         /* clean up and sigio requests */
1731         if (sc->async != NULL) {
1732                 funsetown(&sc->async);
1733                 sc->async = NULL;
1734         }
1735
1736         /* close is almost always successful */
1737         sc->state &= ~PSM_OPEN;
1738         kbdc_lock(sc->kbdc, FALSE);
1739         device_unbusy(devclass_get_device(psm_devclass, sc->unit));
1740         return (0);
1741 }
1742
1743 static int
1744 tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status,
1745     u_char *buf)
1746 {
1747         static u_char butmapps2[8] = {
1748                 0,
1749                 MOUSE_PS2_BUTTON1DOWN,
1750                 MOUSE_PS2_BUTTON2DOWN,
1751                 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
1752                 MOUSE_PS2_BUTTON3DOWN,
1753                 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
1754                 MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1755                 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN |
1756                     MOUSE_PS2_BUTTON3DOWN,
1757         };
1758         static u_char butmapmsc[8] = {
1759                 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP |
1760                     MOUSE_MSC_BUTTON3UP,
1761                 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1762                 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1763                 MOUSE_MSC_BUTTON3UP,
1764                 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1765                 MOUSE_MSC_BUTTON2UP,
1766                 MOUSE_MSC_BUTTON1UP,
1767                 0,
1768         };
1769         int mapped;
1770         int i;
1771
1772         if (sc->mode.level == PSM_LEVEL_BASE) {
1773                 mapped = status->button & ~MOUSE_BUTTON4DOWN;
1774                 if (status->button & MOUSE_BUTTON4DOWN)
1775                         mapped |= MOUSE_BUTTON1DOWN;
1776                 status->button = mapped;
1777                 buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
1778                 i = imax(imin(status->dx, 255), -256);
1779                 if (i < 0)
1780                         buf[0] |= MOUSE_PS2_XNEG;
1781                 buf[1] = i;
1782                 i = imax(imin(status->dy, 255), -256);
1783                 if (i < 0)
1784                         buf[0] |= MOUSE_PS2_YNEG;
1785                 buf[2] = i;
1786                 return (MOUSE_PS2_PACKETSIZE);
1787         } else if (sc->mode.level == PSM_LEVEL_STANDARD) {
1788                 buf[0] = MOUSE_MSC_SYNC |
1789                     butmapmsc[status->button & MOUSE_STDBUTTONS];
1790                 i = imax(imin(status->dx, 255), -256);
1791                 buf[1] = i >> 1;
1792                 buf[3] = i - buf[1];
1793                 i = imax(imin(status->dy, 255), -256);
1794                 buf[2] = i >> 1;
1795                 buf[4] = i - buf[2];
1796                 i = imax(imin(status->dz, 127), -128);
1797                 buf[5] = (i >> 1) & 0x7f;
1798                 buf[6] = (i - (i >> 1)) & 0x7f;
1799                 buf[7] = (~status->button >> 3) & 0x7f;
1800                 return (MOUSE_SYS_PACKETSIZE);
1801         }
1802         return (pb->inputbytes);
1803 }
1804
1805 static int
1806 psmread(struct cdev *dev, struct uio *uio, int flag)
1807 {
1808         struct psm_softc *sc = dev->si_drv1;
1809         u_char buf[PSM_SMALLBUFSIZE];
1810         int error = 0;
1811         int s;
1812         int l;
1813
1814         if ((sc->state & PSM_VALID) == 0)
1815                 return (EIO);
1816
1817         /* block until mouse activity occured */
1818         s = spltty();
1819         while (sc->queue.count <= 0) {
1820                 if (dev != sc->bdev) {
1821                         splx(s);
1822                         return (EWOULDBLOCK);
1823                 }
1824                 sc->state |= PSM_ASLP;
1825                 error = tsleep(sc, PZERO | PCATCH, "psmrea", 0);
1826                 sc->state &= ~PSM_ASLP;
1827                 if (error) {
1828                         splx(s);
1829                         return (error);
1830                 } else if ((sc->state & PSM_VALID) == 0) {
1831                         /* the device disappeared! */
1832                         splx(s);
1833                         return (EIO);
1834                 }
1835         }
1836         splx(s);
1837
1838         /* copy data to the user land */
1839         while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
1840                 s = spltty();
1841                 l = imin(sc->queue.count, uio->uio_resid);
1842                 if (l > sizeof(buf))
1843                         l = sizeof(buf);
1844                 if (l > sizeof(sc->queue.buf) - sc->queue.head) {
1845                         bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
1846                             sizeof(sc->queue.buf) - sc->queue.head);
1847                         bcopy(&sc->queue.buf[0],
1848                             &buf[sizeof(sc->queue.buf) - sc->queue.head],
1849                             l - (sizeof(sc->queue.buf) - sc->queue.head));
1850                 } else
1851                         bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
1852                 sc->queue.count -= l;
1853                 sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
1854                 splx(s);
1855                 error = uiomove(buf, l, uio);
1856                 if (error)
1857                         break;
1858         }
1859
1860         return (error);
1861 }
1862
1863 static int
1864 block_mouse_data(struct psm_softc *sc, int *c)
1865 {
1866         int s;
1867
1868         if (!kbdc_lock(sc->kbdc, TRUE))
1869                 return (EIO);
1870
1871         s = spltty();
1872         *c = get_controller_command_byte(sc->kbdc);
1873         if ((*c == -1) || !set_controller_command_byte(sc->kbdc,
1874             kbdc_get_device_mask(sc->kbdc),
1875             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1876             KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1877                 /* this is CONTROLLER ERROR */
1878                 splx(s);
1879                 kbdc_lock(sc->kbdc, FALSE);
1880                 return (EIO);
1881         }
1882
1883         /*
1884          * The device may be in the middle of status data transmission.
1885          * The transmission will be interrupted, thus, incomplete status
1886          * data must be discarded. Although the aux interrupt is disabled
1887          * at the keyboard controller level, at most one aux interrupt
1888          * may have already been pending and a data byte is in the
1889          * output buffer; throw it away. Note that the second argument
1890          * to `empty_aux_buffer()' is zero, so that the call will just
1891          * flush the internal queue.
1892          * `psmintr()' will be invoked after `splx()' if an interrupt is
1893          * pending; it will see no data and returns immediately.
1894          */
1895         empty_aux_buffer(sc->kbdc, 0);          /* flush the queue */
1896         read_aux_data_no_wait(sc->kbdc);        /* throw away data if any */
1897         flushpackets(sc);
1898         splx(s);
1899
1900         return (0);
1901 }
1902
1903 static void
1904 dropqueue(struct psm_softc *sc)
1905 {
1906
1907         sc->queue.count = 0;
1908         sc->queue.head = 0;
1909         sc->queue.tail = 0;
1910         if ((sc->state & PSM_SOFTARMED) != 0) {
1911                 sc->state &= ~PSM_SOFTARMED;
1912                 callout_stop(&sc->softcallout);
1913         }
1914         sc->pqueue_start = sc->pqueue_end;
1915 }
1916
1917 static void
1918 flushpackets(struct psm_softc *sc)
1919 {
1920
1921         dropqueue(sc);
1922         bzero(&sc->pqueue, sizeof(sc->pqueue));
1923 }
1924
1925 static int
1926 unblock_mouse_data(struct psm_softc *sc, int c)
1927 {
1928         int error = 0;
1929
1930         /*
1931          * We may have seen a part of status data during `set_mouse_XXX()'.
1932          * they have been queued; flush it.
1933          */
1934         empty_aux_buffer(sc->kbdc, 0);
1935
1936         /* restore ports and interrupt */
1937         if (!set_controller_command_byte(sc->kbdc,
1938             kbdc_get_device_mask(sc->kbdc),
1939             c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
1940                 /*
1941                  * CONTROLLER ERROR; this is serious, we may have
1942                  * been left with the inaccessible keyboard and
1943                  * the disabled mouse interrupt.
1944                  */
1945                 error = EIO;
1946         }
1947
1948         kbdc_lock(sc->kbdc, FALSE);
1949         return (error);
1950 }
1951
1952 static int
1953 psmwrite(struct cdev *dev, struct uio *uio, int flag)
1954 {
1955         struct psm_softc *sc = dev->si_drv1;
1956         u_char buf[PSM_SMALLBUFSIZE];
1957         int error = 0, i, l;
1958
1959         if ((sc->state & PSM_VALID) == 0)
1960                 return (EIO);
1961
1962         if (sc->mode.level < PSM_LEVEL_NATIVE)
1963                 return (ENODEV);
1964
1965         /* copy data from the user land */
1966         while (uio->uio_resid > 0) {
1967                 l = imin(PSM_SMALLBUFSIZE, uio->uio_resid);
1968                 error = uiomove(buf, l, uio);
1969                 if (error)
1970                         break;
1971                 for (i = 0; i < l; i++) {
1972                         VLOG(4, (LOG_DEBUG, "psm: cmd 0x%x\n", buf[i]));
1973                         if (!write_aux_command(sc->kbdc, buf[i])) {
1974                                 VLOG(2, (LOG_DEBUG,
1975                                     "psm: cmd 0x%x failed.\n", buf[i]));
1976                                 return (reinitialize(sc, FALSE));
1977                         }
1978                 }
1979         }
1980
1981         return (error);
1982 }
1983
1984 static int
1985 psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
1986     struct thread *td)
1987 {
1988         struct psm_softc *sc = dev->si_drv1;
1989         mousemode_t mode;
1990         mousestatus_t status;
1991 #if (defined(MOUSE_GETVARS))
1992         mousevar_t *var;
1993 #endif
1994         mousedata_t *data;
1995         int stat[3];
1996         int command_byte;
1997         int error = 0;
1998         int s;
1999
2000         /* Perform IOCTL command */
2001         switch (cmd) {
2002
2003         case OLD_MOUSE_GETHWINFO:
2004                 s = spltty();
2005                 ((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
2006                 ((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
2007                 ((old_mousehw_t *)addr)->type = sc->hw.type;
2008                 ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
2009                 splx(s);
2010                 break;
2011
2012         case MOUSE_GETHWINFO:
2013                 s = spltty();
2014                 *(mousehw_t *)addr = sc->hw;
2015                 if (sc->mode.level == PSM_LEVEL_BASE)
2016                         ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
2017                 splx(s);
2018                 break;
2019
2020         case MOUSE_SYN_GETHWINFO:
2021                 s = spltty();
2022                 if (sc->synhw.infoMajor >= 4)
2023                         *(synapticshw_t *)addr = sc->synhw;
2024                 else
2025                         error = EINVAL;
2026                 splx(s);
2027                 break;
2028
2029         case OLD_MOUSE_GETMODE:
2030                 s = spltty();
2031                 switch (sc->mode.level) {
2032                 case PSM_LEVEL_BASE:
2033                         ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2034                         break;
2035                 case PSM_LEVEL_STANDARD:
2036                         ((old_mousemode_t *)addr)->protocol =
2037                             MOUSE_PROTO_SYSMOUSE;
2038                         break;
2039                 case PSM_LEVEL_NATIVE:
2040                         ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2041                         break;
2042                 }
2043                 ((old_mousemode_t *)addr)->rate = sc->mode.rate;
2044                 ((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
2045                 ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
2046                 splx(s);
2047                 break;
2048
2049         case MOUSE_GETMODE:
2050                 s = spltty();
2051                 *(mousemode_t *)addr = sc->mode;
2052                 if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2053                         ((mousemode_t *)addr)->syncmask[0] = 0;
2054                         ((mousemode_t *)addr)->syncmask[1] = 0;
2055                 }
2056                 ((mousemode_t *)addr)->resolution =
2057                         MOUSE_RES_LOW - sc->mode.resolution;
2058                 switch (sc->mode.level) {
2059                 case PSM_LEVEL_BASE:
2060                         ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2061                         ((mousemode_t *)addr)->packetsize =
2062                             MOUSE_PS2_PACKETSIZE;
2063                         break;
2064                 case PSM_LEVEL_STANDARD:
2065                         ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
2066                         ((mousemode_t *)addr)->packetsize =
2067                             MOUSE_SYS_PACKETSIZE;
2068                         ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
2069                         ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
2070                         break;
2071                 case PSM_LEVEL_NATIVE:
2072                         /* FIXME: this isn't quite correct... XXX */
2073                         ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2074                         break;
2075                 }
2076                 splx(s);
2077                 break;
2078
2079         case OLD_MOUSE_SETMODE:
2080         case MOUSE_SETMODE:
2081                 if (cmd == OLD_MOUSE_SETMODE) {
2082                         mode.rate = ((old_mousemode_t *)addr)->rate;
2083                         /*
2084                          * resolution  old I/F   new I/F
2085                          * default        0         0
2086                          * low            1        -2
2087                          * medium low     2        -3
2088                          * medium high    3        -4
2089                          * high           4        -5
2090                          */
2091                         if (((old_mousemode_t *)addr)->resolution > 0)
2092                                 mode.resolution =
2093                                     -((old_mousemode_t *)addr)->resolution - 1;
2094                         else
2095                                 mode.resolution = 0;
2096                         mode.accelfactor =
2097                             ((old_mousemode_t *)addr)->accelfactor;
2098                         mode.level = -1;
2099                 } else
2100                         mode = *(mousemode_t *)addr;
2101
2102                 /* adjust and validate parameters. */
2103                 if (mode.rate > UCHAR_MAX)
2104                         return (EINVAL);
2105                 if (mode.rate == 0)
2106                         mode.rate = sc->dflt_mode.rate;
2107                 else if (mode.rate == -1)
2108                         /* don't change the current setting */
2109                         ;
2110                 else if (mode.rate < 0)
2111                         return (EINVAL);
2112                 if (mode.resolution >= UCHAR_MAX)
2113                         return (EINVAL);
2114                 if (mode.resolution >= 200)
2115                         mode.resolution = MOUSE_RES_HIGH;
2116                 else if (mode.resolution >= 100)
2117                         mode.resolution = MOUSE_RES_MEDIUMHIGH;
2118                 else if (mode.resolution >= 50)
2119                         mode.resolution = MOUSE_RES_MEDIUMLOW;
2120                 else if (mode.resolution > 0)
2121                         mode.resolution = MOUSE_RES_LOW;
2122                 if (mode.resolution == MOUSE_RES_DEFAULT)
2123                         mode.resolution = sc->dflt_mode.resolution;
2124                 else if (mode.resolution == -1)
2125                         /* don't change the current setting */
2126                         ;
2127                 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2128                         mode.resolution = MOUSE_RES_LOW - mode.resolution;
2129                 if (mode.level == -1)
2130                         /* don't change the current setting */
2131                         mode.level = sc->mode.level;
2132                 else if ((mode.level < PSM_LEVEL_MIN) ||
2133                     (mode.level > PSM_LEVEL_MAX))
2134                         return (EINVAL);
2135                 if (mode.accelfactor == -1)
2136                         /* don't change the current setting */
2137                         mode.accelfactor = sc->mode.accelfactor;
2138                 else if (mode.accelfactor < 0)
2139                         return (EINVAL);
2140
2141                 /* don't allow anybody to poll the keyboard controller */
2142                 error = block_mouse_data(sc, &command_byte);
2143                 if (error)
2144                         return (error);
2145
2146                 /* set mouse parameters */
2147                 if (mode.rate > 0)
2148                         mode.rate = set_mouse_sampling_rate(sc->kbdc,
2149                             mode.rate);
2150                 if (mode.resolution >= 0)
2151                         mode.resolution =
2152                             set_mouse_resolution(sc->kbdc, mode.resolution);
2153                 set_mouse_scaling(sc->kbdc, 1);
2154                 get_mouse_status(sc->kbdc, stat, 0, 3);
2155
2156                 s = spltty();
2157                 sc->mode.rate = mode.rate;
2158                 sc->mode.resolution = mode.resolution;
2159                 sc->mode.accelfactor = mode.accelfactor;
2160                 sc->mode.level = mode.level;
2161                 splx(s);
2162
2163                 unblock_mouse_data(sc, command_byte);
2164                 break;
2165
2166         case MOUSE_GETLEVEL:
2167                 *(int *)addr = sc->mode.level;
2168                 break;
2169
2170         case MOUSE_SETLEVEL:
2171                 if ((*(int *)addr < PSM_LEVEL_MIN) ||
2172                     (*(int *)addr > PSM_LEVEL_MAX))
2173                         return (EINVAL);
2174                 sc->mode.level = *(int *)addr;
2175
2176                 if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
2177                         /*
2178                          * If we are entering PSM_LEVEL_NATIVE, we want to
2179                          * enable sending of "extended W mode" packets to
2180                          * userland. Reset the mode of the touchpad so that the
2181                          * change in the level is picked up.
2182                          */
2183                         error = block_mouse_data(sc, &command_byte);
2184                         if (error)
2185                                 return (error);
2186                         synaptics_set_mode(sc, synaptics_preferred_mode(sc));
2187                         unblock_mouse_data(sc, command_byte);
2188                 }
2189                 break;
2190
2191         case MOUSE_GETSTATUS:
2192                 s = spltty();
2193                 status = sc->status;
2194                 sc->status.flags = 0;
2195                 sc->status.obutton = sc->status.button;
2196                 sc->status.button = 0;
2197                 sc->status.dx = 0;
2198                 sc->status.dy = 0;
2199                 sc->status.dz = 0;
2200                 splx(s);
2201                 *(mousestatus_t *)addr = status;
2202                 break;
2203
2204 #if (defined(MOUSE_GETVARS))
2205         case MOUSE_GETVARS:
2206                 var = (mousevar_t *)addr;
2207                 bzero(var, sizeof(*var));
2208                 s = spltty();
2209                 var->var[0] = MOUSE_VARS_PS2_SIG;
2210                 var->var[1] = sc->config;
2211                 var->var[2] = sc->flags;
2212                 splx(s);
2213                 break;
2214
2215         case MOUSE_SETVARS:
2216                 return (ENODEV);
2217 #endif /* MOUSE_GETVARS */
2218
2219         case MOUSE_READSTATE:
2220         case MOUSE_READDATA:
2221                 data = (mousedata_t *)addr;
2222                 if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
2223                         return (EINVAL);
2224
2225                 error = block_mouse_data(sc, &command_byte);
2226                 if (error)
2227                         return (error);
2228                 if ((data->len = get_mouse_status(sc->kbdc, data->buf,
2229                     (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
2230                         error = EIO;
2231                 unblock_mouse_data(sc, command_byte);
2232                 break;
2233
2234 #if (defined(MOUSE_SETRESOLUTION))
2235         case MOUSE_SETRESOLUTION:
2236                 mode.resolution = *(int *)addr;
2237                 if (mode.resolution >= UCHAR_MAX)
2238                         return (EINVAL);
2239                 else if (mode.resolution >= 200)
2240                         mode.resolution = MOUSE_RES_HIGH;
2241                 else if (mode.resolution >= 100)
2242                         mode.resolution = MOUSE_RES_MEDIUMHIGH;
2243                 else if (mode.resolution >= 50)
2244                         mode.resolution = MOUSE_RES_MEDIUMLOW;
2245                 else if (mode.resolution > 0)
2246                         mode.resolution = MOUSE_RES_LOW;
2247                 if (mode.resolution == MOUSE_RES_DEFAULT)
2248                         mode.resolution = sc->dflt_mode.resolution;
2249                 else if (mode.resolution == -1)
2250                         mode.resolution = sc->mode.resolution;
2251                 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2252                         mode.resolution = MOUSE_RES_LOW - mode.resolution;
2253
2254                 error = block_mouse_data(sc, &command_byte);
2255                 if (error)
2256                         return (error);
2257                 sc->mode.resolution =
2258                     set_mouse_resolution(sc->kbdc, mode.resolution);
2259                 if (sc->mode.resolution != mode.resolution)
2260                         error = EIO;
2261                 unblock_mouse_data(sc, command_byte);
2262                 break;
2263 #endif /* MOUSE_SETRESOLUTION */
2264
2265 #if (defined(MOUSE_SETRATE))
2266         case MOUSE_SETRATE:
2267                 mode.rate = *(int *)addr;
2268                 if (mode.rate > UCHAR_MAX)
2269                         return (EINVAL);
2270                 if (mode.rate == 0)
2271                         mode.rate = sc->dflt_mode.rate;
2272                 else if (mode.rate < 0)
2273                         mode.rate = sc->mode.rate;
2274
2275                 error = block_mouse_data(sc, &command_byte);
2276                 if (error)
2277                         return (error);
2278                 sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
2279                 if (sc->mode.rate != mode.rate)
2280                         error = EIO;
2281                 unblock_mouse_data(sc, command_byte);
2282                 break;
2283 #endif /* MOUSE_SETRATE */
2284
2285 #if (defined(MOUSE_SETSCALING))
2286         case MOUSE_SETSCALING:
2287                 if ((*(int *)addr <= 0) || (*(int *)addr > 2))
2288                         return (EINVAL);
2289
2290                 error = block_mouse_data(sc, &command_byte);
2291                 if (error)
2292                         return (error);
2293                 if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
2294                         error = EIO;
2295                 unblock_mouse_data(sc, command_byte);
2296                 break;
2297 #endif /* MOUSE_SETSCALING */
2298
2299 #if (defined(MOUSE_GETHWID))
2300         case MOUSE_GETHWID:
2301                 error = block_mouse_data(sc, &command_byte);
2302                 if (error)
2303                         return (error);
2304                 sc->hw.hwid &= ~0x00ff;
2305                 sc->hw.hwid |= get_aux_id(sc->kbdc);
2306                 *(int *)addr = sc->hw.hwid & 0x00ff;
2307                 unblock_mouse_data(sc, command_byte);
2308                 break;
2309 #endif /* MOUSE_GETHWID */
2310
2311         case FIONBIO:
2312         case FIOASYNC:
2313                 break;
2314         case FIOSETOWN:
2315                 error = fsetown(*(int *)addr, &sc->async);
2316                 break;
2317         case FIOGETOWN:
2318                 *(int *) addr = fgetown(&sc->async);
2319                 break;
2320         default:
2321                 return (ENOTTY);
2322         }
2323
2324         return (error);
2325 }
2326
2327 static void
2328 psmtimeout(void *arg)
2329 {
2330         struct psm_softc *sc;
2331         int s;
2332
2333         sc = (struct psm_softc *)arg;
2334         s = spltty();
2335         if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
2336                 VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit));
2337                 psmintr(sc);
2338                 kbdc_lock(sc->kbdc, FALSE);
2339         }
2340         sc->watchdog = TRUE;
2341         splx(s);
2342         callout_reset(&sc->callout, hz, psmtimeout, sc);
2343 }
2344
2345 /* Add all sysctls under the debug.psm and hw.psm nodes */
2346 static SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2347 static SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2348
2349 SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0,
2350     "Verbosity level");
2351
2352 static int psmhz = 20;
2353 SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0,
2354     "Frequency of the softcallout (in hz)");
2355 static int psmerrsecs = 2;
2356 SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0,
2357     "Number of seconds during which packets will dropped after a sync error");
2358 static int psmerrusecs = 0;
2359 SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0,
2360     "Microseconds to add to psmerrsecs");
2361 static int psmsecs = 0;
2362 SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0,
2363     "Max number of seconds between soft interrupts");
2364 static int psmusecs = 500000;
2365 SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0,
2366     "Microseconds to add to psmsecs");
2367 static int pkterrthresh = 2;
2368 SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0,
2369     "Number of error packets allowed before reinitializing the mouse");
2370
2371 SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RW, &tap_enabled, 0,
2372     "Enable tap and drag gestures");
2373 static int tap_threshold = PSM_TAP_THRESHOLD;
2374 SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0,
2375     "Button tap threshold");
2376 static int tap_timeout = PSM_TAP_TIMEOUT;
2377 SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0,
2378     "Tap timeout for touchpads");
2379
2380 static void
2381 psmintr(void *arg)
2382 {
2383         struct psm_softc *sc = arg;
2384         struct timeval now;
2385         int c;
2386         packetbuf_t *pb;
2387
2388
2389         /* read until there is nothing to read */
2390         while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
2391                 pb = &sc->pqueue[sc->pqueue_end];
2392
2393                 /* discard the byte if the device is not open */
2394                 if ((sc->state & PSM_OPEN) == 0)
2395                         continue;
2396
2397                 getmicrouptime(&now);
2398                 if ((pb->inputbytes > 0) &&
2399                     timevalcmp(&now, &sc->inputtimeout, >)) {
2400                         VLOG(3, (LOG_DEBUG, "psmintr: delay too long; "
2401                             "resetting byte count\n"));
2402                         pb->inputbytes = 0;
2403                         sc->syncerrors = 0;
2404                         sc->pkterrors = 0;
2405                 }
2406                 sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT / 1000000;
2407                 sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT % 1000000;
2408                 timevaladd(&sc->inputtimeout, &now);
2409
2410                 pb->ipacket[pb->inputbytes++] = c;
2411
2412                 if (sc->mode.level == PSM_LEVEL_NATIVE) {
2413                         VLOG(4, (LOG_DEBUG, "psmintr: %02x\n", pb->ipacket[0]));
2414                         sc->syncerrors = 0;
2415                         sc->pkterrors = 0;
2416                         goto next;
2417                 } else {
2418                         if (pb->inputbytes < sc->mode.packetsize)
2419                                 continue;
2420
2421                         VLOG(4, (LOG_DEBUG,
2422                             "psmintr: %02x %02x %02x %02x %02x %02x\n",
2423                             pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
2424                             pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
2425                 }
2426
2427                 c = pb->ipacket[0];
2428
2429                 if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2430                         sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]);
2431                         sc->flags &= ~PSM_NEED_SYNCBITS;
2432                         VLOG(2, (LOG_DEBUG,
2433                             "psmintr: Sync bytes now %04x,%04x\n",
2434                             sc->mode.syncmask[0], sc->mode.syncmask[0]));
2435                 } else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
2436                         VLOG(3, (LOG_DEBUG, "psmintr: out of sync "
2437                             "(%04x != %04x) %d cmds since last error.\n",
2438                             c & sc->mode.syncmask[0], sc->mode.syncmask[1],
2439                             sc->cmdcount - sc->lasterr));
2440                         sc->lasterr = sc->cmdcount;
2441                         /*
2442                          * The sync byte test is a weak measure of packet
2443                          * validity.  Conservatively discard any input yet
2444                          * to be seen by userland when we detect a sync
2445                          * error since there is a good chance some of
2446                          * the queued packets have undetected errors.
2447                          */
2448                         dropqueue(sc);
2449                         if (sc->syncerrors == 0)
2450                                 sc->pkterrors++;
2451                         ++sc->syncerrors;
2452                         sc->lastinputerr = now;
2453                         if (sc->syncerrors >= sc->mode.packetsize * 2 ||
2454                             sc->pkterrors >= pkterrthresh) {
2455                                 /*
2456                                  * If we've failed to find a single sync byte
2457                                  * in 2 packets worth of data, or we've seen
2458                                  * persistent packet errors during the
2459                                  * validation period, reinitialize the mouse
2460                                  * in hopes of returning it to the expected
2461                                  * mode.
2462                                  */
2463                                 VLOG(3, (LOG_DEBUG,
2464                                     "psmintr: reset the mouse.\n"));
2465                                 reinitialize(sc, TRUE);
2466                         } else if (sc->syncerrors == sc->mode.packetsize) {
2467                                 /*
2468                                  * Try a soft reset after searching for a sync
2469                                  * byte through a packet length of bytes.
2470                                  */
2471                                 VLOG(3, (LOG_DEBUG,
2472                                     "psmintr: re-enable the mouse.\n"));
2473                                 pb->inputbytes = 0;
2474                                 disable_aux_dev(sc->kbdc);
2475                                 enable_aux_dev(sc->kbdc);
2476                         } else {
2477                                 VLOG(3, (LOG_DEBUG,
2478                                     "psmintr: discard a byte (%d)\n",
2479                                     sc->syncerrors));
2480                                 pb->inputbytes--;
2481                                 bcopy(&pb->ipacket[1], &pb->ipacket[0],
2482                                     pb->inputbytes);
2483                         }
2484                         continue;
2485                 }
2486
2487                 /*
2488                  * We have what appears to be a valid packet.
2489                  * Reset the error counters.
2490                  */
2491                 sc->syncerrors = 0;
2492
2493                 /*
2494                  * Drop even good packets if they occur within a timeout
2495                  * period of a sync error.  This allows the detection of
2496                  * a change in the mouse's packet mode without exposing
2497                  * erratic mouse behavior to the user.  Some KVMs forget
2498                  * enhanced mouse modes during switch events.
2499                  */
2500                 if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs,
2501                     &now)) {
2502                         pb->inputbytes = 0;
2503                         continue;
2504                 }
2505
2506                 /*
2507                  * Now that we're out of the validation period, reset
2508                  * the packet error count.
2509                  */
2510                 sc->pkterrors = 0;
2511
2512                 sc->cmdcount++;
2513 next:
2514                 if (++sc->pqueue_end >= PSM_PACKETQUEUE)
2515                         sc->pqueue_end = 0;
2516                 /*
2517                  * If we've filled the queue then call the softintr ourselves,
2518                  * otherwise schedule the interrupt for later.
2519                  */
2520                 if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) ||
2521                     (sc->pqueue_end == sc->pqueue_start)) {
2522                         if ((sc->state & PSM_SOFTARMED) != 0) {
2523                                 sc->state &= ~PSM_SOFTARMED;
2524                                 callout_stop(&sc->softcallout);
2525                         }
2526                         psmsoftintr(arg);
2527                 } else if ((sc->state & PSM_SOFTARMED) == 0) {
2528                         sc->state |= PSM_SOFTARMED;
2529                         callout_reset(&sc->softcallout,
2530                             psmhz < 1 ? 1 : (hz/psmhz), psmsoftintr, arg);
2531                 }
2532         }
2533 }
2534
2535 static void
2536 proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2537     int *x, int *y, int *z)
2538 {
2539
2540         /*
2541          * PS2++ protocol packet
2542          *
2543          *          b7 b6 b5 b4 b3 b2 b1 b0
2544          * byte 1:  *  1  p3 p2 1  *  *  *
2545          * byte 2:  c1 c2 p1 p0 d1 d0 1  0
2546          *
2547          * p3-p0: packet type
2548          * c1, c2: c1 & c2 == 1, if p2 == 0
2549          *         c1 & c2 == 0, if p2 == 1
2550          *
2551          * packet type: 0 (device type)
2552          * See comments in enable_mmanplus() below.
2553          *
2554          * packet type: 1 (wheel data)
2555          *
2556          *          b7 b6 b5 b4 b3 b2 b1 b0
2557          * byte 3:  h  *  B5 B4 s  d2 d1 d0
2558          *
2559          * h: 1, if horizontal roller data
2560          *    0, if vertical roller data
2561          * B4, B5: button 4 and 5
2562          * s: sign bit
2563          * d2-d0: roller data
2564          *
2565          * packet type: 2 (reserved)
2566          */
2567         if (((pb->ipacket[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) &&
2568             (abs(*x) > 191) && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) {
2569                 /*
2570                  * the extended data packet encodes button
2571                  * and wheel events
2572                  */
2573                 switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) {
2574                 case 1:
2575                         /* wheel data packet */
2576                         *x = *y = 0;
2577                         if (pb->ipacket[2] & 0x80) {
2578                                 /* XXX horizontal roller count - ignore it */
2579                                 ;
2580                         } else {
2581                                 /* vertical roller count */
2582                                 *z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) ?
2583                                     (pb->ipacket[2] & 0x0f) - 16 :
2584                                     (pb->ipacket[2] & 0x0f);
2585                         }
2586                         ms->button |= (pb->ipacket[2] &
2587                             MOUSE_PS2PLUS_BUTTON4DOWN) ?
2588                             MOUSE_BUTTON4DOWN : 0;
2589                         ms->button |= (pb->ipacket[2] &
2590                             MOUSE_PS2PLUS_BUTTON5DOWN) ?
2591                             MOUSE_BUTTON5DOWN : 0;
2592                         break;
2593                 case 2:
2594                         /*
2595                          * this packet type is reserved by
2596                          * Logitech...
2597                          */
2598                         /*
2599                          * IBM ScrollPoint Mouse uses this
2600                          * packet type to encode both vertical
2601                          * and horizontal scroll movement.
2602                          */
2603                         *x = *y = 0;
2604                         /* horizontal count */
2605                         if (pb->ipacket[2] & 0x0f)
2606                                 *z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ?
2607                                     -2 : 2;
2608                         /* vertical count */
2609                         if (pb->ipacket[2] & 0xf0)
2610                                 *z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ?
2611                                     -1 : 1;
2612                         break;
2613                 case 0:
2614                         /* device type packet - shouldn't happen */
2615                         /* FALLTHROUGH */
2616                 default:
2617                         *x = *y = 0;
2618                         ms->button = ms->obutton;
2619                         VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet "
2620                             "type %d: 0x%02x 0x%02x 0x%02x\n",
2621                             MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket),
2622                             pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]));
2623                         break;
2624                 }
2625         } else {
2626                 /* preserve button states */
2627                 ms->button |= ms->obutton & MOUSE_EXTBUTTONS;
2628         }
2629 }
2630
2631 static int
2632 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2633     int *x, int *y, int *z)
2634 {
2635         static int touchpad_buttons;
2636         static int guest_buttons;
2637         int w, x0, y0;
2638
2639         /* TouchPad PS/2 absolute mode message format with capFourButtons:
2640          *
2641          *  Bits:        7   6   5   4   3   2   1   0 (LSB)
2642          *  ------------------------------------------------
2643          *  ipacket[0]:  1   0  W3  W2   0  W1   R   L
2644          *  ipacket[1]: Yb  Ya  Y9  Y8  Xb  Xa  X9  X8
2645          *  ipacket[2]: Z7  Z6  Z5  Z4  Z3  Z2  Z1  Z0
2646          *  ipacket[3]:  1   1  Yc  Xc   0  W0 D^R U^L
2647          *  ipacket[4]: X7  X6  X5  X4  X3  X2  X1  X0
2648          *  ipacket[5]: Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
2649          *
2650          * Legend:
2651          *  L: left physical mouse button
2652          *  R: right physical mouse button
2653          *  D: down button
2654          *  U: up button
2655          *  W: "wrist" value
2656          *  X: x position
2657          *  Y: y position
2658          *  Z: pressure
2659          *
2660          * Without capFourButtons but with nExtendeButtons and/or capMiddle
2661          *
2662          *  Bits:        7   6   5   4      3      2      1      0 (LSB)
2663          *  ------------------------------------------------------
2664          *  ipacket[3]:  1   1  Yc  Xc      0     W0    E^R    M^L
2665          *  ipacket[4]: X7  X6  X5  X4  X3|b7  X2|b5  X1|b3  X0|b1
2666          *  ipacket[5]: Y7  Y6  Y5  Y4  Y3|b8  Y2|b6  Y1|b4  Y0|b2
2667          *
2668          * Legend:
2669          *  M: Middle physical mouse button
2670          *  E: Extended mouse buttons reported instead of low bits of X and Y
2671          *  b1-b8: Extended mouse buttons
2672          *    Only ((nExtendedButtons + 1) >> 1) bits are used in packet
2673          *    4 and 5, for reading X and Y value they should be zeroed.
2674          *
2675          * Absolute reportable limits:    0 - 6143.
2676          * Typical bezel limits:       1472 - 5472.
2677          * Typical edge marings:       1632 - 5312.
2678          *
2679          * w = 3 Passthrough Packet
2680          *
2681          * Byte 2,5,6 == Byte 1,2,3 of "Guest"
2682          */
2683
2684         if (!synaptics_support)
2685                 return (0);
2686
2687         /* Sanity check for out of sync packets. */
2688         if ((pb->ipacket[0] & 0xc8) != 0x80 ||
2689             (pb->ipacket[3] & 0xc8) != 0xc0)
2690                 return (-1);
2691
2692         *x = *y = 0;
2693
2694         /*
2695          * Pressure value.
2696          * Interpretation:
2697          *   z = 0      No finger contact
2698          *   z = 10     Finger hovering near the pad
2699          *   z = 30     Very light finger contact
2700          *   z = 80     Normal finger contact
2701          *   z = 110    Very heavy finger contact
2702          *   z = 200    Finger lying flat on pad surface
2703          *   z = 255    Maximum reportable Z
2704          */
2705         *z = pb->ipacket[2];
2706
2707         /*
2708          * Finger width value
2709          * Interpretation:
2710          *   w = 0      Two finger on the pad (capMultiFinger needed)
2711          *   w = 1      Three or more fingers (capMultiFinger needed)
2712          *   w = 2      Pen (instead of finger) (capPen needed)
2713          *   w = 3      Reserved (passthrough?)
2714          *   w = 4-7    Finger of normal width (capPalmDetect needed)
2715          *   w = 8-14   Very wide finger or palm (capPalmDetect needed)
2716          *   w = 15     Maximum reportable width (capPalmDetect needed)
2717          */
2718         /* XXX Is checking capExtended enough? */
2719         if (sc->synhw.capExtended)
2720                 w = ((pb->ipacket[0] & 0x30) >> 2) |
2721                     ((pb->ipacket[0] & 0x04) >> 1) |
2722                     ((pb->ipacket[3] & 0x04) >> 2);
2723         else {
2724                 /* Assume a finger of regular width. */
2725                 w = 4;
2726         }
2727
2728         /*
2729          * Handle packets from the guest device. See:
2730          * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
2731          */
2732         if (w == 3 && sc->synhw.capPassthrough) {
2733                 *x = ((pb->ipacket[1] & 0x10) ?
2734                     pb->ipacket[4] - 256 : pb->ipacket[4]);
2735                 *y = ((pb->ipacket[1] & 0x20) ?
2736                     pb->ipacket[5] - 256 : pb->ipacket[5]);
2737                 *z = 0;
2738
2739                 guest_buttons = 0;
2740                 if (pb->ipacket[1] & 0x01)
2741                         guest_buttons |= MOUSE_BUTTON1DOWN;
2742                 if (pb->ipacket[1] & 0x04)
2743                         guest_buttons |= MOUSE_BUTTON2DOWN;
2744                 if (pb->ipacket[1] & 0x02)
2745                         guest_buttons |= MOUSE_BUTTON3DOWN;
2746
2747                 ms->button = touchpad_buttons | guest_buttons;
2748                 goto SYNAPTICS_END;
2749         }
2750
2751         if (sc->syninfo.touchpad_off) {
2752                 *x = *y = *z = 0;
2753                 ms->button = ms->obutton;
2754                 goto SYNAPTICS_END;
2755         }
2756
2757         /* Button presses */
2758         touchpad_buttons = 0;
2759         if (pb->ipacket[0] & 0x01)
2760                 touchpad_buttons |= MOUSE_BUTTON1DOWN;
2761         if (pb->ipacket[0] & 0x02)
2762                 touchpad_buttons |= MOUSE_BUTTON3DOWN;
2763
2764         if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
2765                 if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x01)
2766                         touchpad_buttons |= MOUSE_BUTTON4DOWN;
2767                 if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x02)
2768                         touchpad_buttons |= MOUSE_BUTTON5DOWN;
2769         } else if (sc->synhw.capExtended && sc->synhw.capMiddle &&
2770             !sc->synhw.capClickPad) {
2771                 /* Middle Button */
2772                 if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
2773                         touchpad_buttons |= MOUSE_BUTTON2DOWN;
2774         } else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) {
2775                 /* Extended Buttons */
2776                 if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
2777                         if (sc->syninfo.directional_scrolls) {
2778                                 if (pb->ipacket[4] & 0x01)
2779                                         touchpad_buttons |= MOUSE_BUTTON4DOWN;
2780                                 if (pb->ipacket[5] & 0x01)
2781                                         touchpad_buttons |= MOUSE_BUTTON5DOWN;
2782                                 if (pb->ipacket[4] & 0x02)
2783                                         touchpad_buttons |= MOUSE_BUTTON6DOWN;
2784                                 if (pb->ipacket[5] & 0x02)
2785                                         touchpad_buttons |= MOUSE_BUTTON7DOWN;
2786                         } else {
2787                                 if (pb->ipacket[4] & 0x01)
2788                                         touchpad_buttons |= MOUSE_BUTTON1DOWN;
2789                                 if (pb->ipacket[5] & 0x01)
2790                                         touchpad_buttons |= MOUSE_BUTTON3DOWN;
2791                                 if (pb->ipacket[4] & 0x02)
2792                                         touchpad_buttons |= MOUSE_BUTTON2DOWN;
2793                                 sc->extended_buttons = touchpad_buttons;
2794                         }
2795
2796                         /*
2797                          * Zero out bits used by extended buttons to avoid
2798                          * misinterpretation of the data absolute position.
2799                          *
2800                          * The bits represented by
2801                          *
2802                          *     (nExtendedButtons + 1) >> 1
2803                          *
2804                          * will be masked out in both bytes.
2805                          * The mask for n bits is computed with the formula
2806                          *
2807                          *     (1 << n) - 1
2808                          */
2809                         int maskedbits = 0;
2810                         int mask = 0;
2811                         maskedbits = (sc->synhw.nExtendedButtons + 1) >> 1;
2812                         mask = (1 << maskedbits) - 1;
2813                         pb->ipacket[4] &= ~(mask);
2814                         pb->ipacket[5] &= ~(mask);
2815                 } else  if (!sc->syninfo.directional_scrolls &&
2816                     !sc->synaction.in_vscroll) {
2817                         /*
2818                          * Keep reporting MOUSE DOWN until we get a new packet
2819                          * indicating otherwise.
2820                          */
2821                         touchpad_buttons |= sc->extended_buttons;
2822                 }
2823         }
2824         /* Handle ClickPad. */
2825         if (sc->synhw.capClickPad &&
2826             ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
2827                 touchpad_buttons |= MOUSE_BUTTON1DOWN;
2828
2829         ms->button = touchpad_buttons | guest_buttons;
2830
2831         /*
2832          * Check pressure to detect a real wanted action on the
2833          * touchpad.
2834          */
2835         if (*z >= sc->syninfo.min_pressure) {
2836                 synapticsaction_t *synaction;
2837                 int cursor, peer, window;
2838                 int dx, dy, dxp, dyp;
2839                 int max_width, max_pressure;
2840                 int margin_top, margin_right, margin_bottom, margin_left;
2841                 int na_top, na_right, na_bottom, na_left;
2842                 int window_min, window_max;
2843                 int multiplicator;
2844                 int weight_current, weight_previous, weight_len_squared;
2845                 int div_min, div_max, div_len;
2846                 int vscroll_hor_area, vscroll_ver_area;
2847                 int two_finger_scroll;
2848                 int len, weight_prev_x, weight_prev_y;
2849                 int div_max_x, div_max_y, div_x, div_y;
2850
2851                 /* Read sysctl. */
2852                 /* XXX Verify values? */
2853                 max_width = sc->syninfo.max_width;
2854                 max_pressure = sc->syninfo.max_pressure;
2855                 margin_top = sc->syninfo.margin_top;
2856                 margin_right = sc->syninfo.margin_right;
2857                 margin_bottom = sc->syninfo.margin_bottom;
2858                 margin_left = sc->syninfo.margin_left;
2859                 na_top = sc->syninfo.na_top;
2860                 na_right = sc->syninfo.na_right;
2861                 na_bottom = sc->syninfo.na_bottom;
2862                 na_left = sc->syninfo.na_left;
2863                 window_min = sc->syninfo.window_min;
2864                 window_max = sc->syninfo.window_max;
2865                 multiplicator = sc->syninfo.multiplicator;
2866                 weight_current = sc->syninfo.weight_current;
2867                 weight_previous = sc->syninfo.weight_previous;
2868                 weight_len_squared = sc->syninfo.weight_len_squared;
2869                 div_min = sc->syninfo.div_min;
2870                 div_max = sc->syninfo.div_max;
2871                 div_len = sc->syninfo.div_len;
2872                 vscroll_hor_area = sc->syninfo.vscroll_hor_area;
2873                 vscroll_ver_area = sc->syninfo.vscroll_ver_area;
2874                 two_finger_scroll = sc->syninfo.two_finger_scroll;
2875
2876                 /* Palm detection. */
2877                 if (!(
2878                     ((sc->synhw.capMultiFinger ||
2879                       sc->synhw.capAdvancedGestures) && (w == 0 || w == 1)) ||
2880                     (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
2881                     (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
2882                     (sc->synhw.capPen && w == 2))) {
2883                         /*
2884                          * We consider the packet irrelevant for the current
2885                          * action when:
2886                          *  - the width isn't comprised in:
2887                          *    [4; max_width]
2888                          *  - the pressure isn't comprised in:
2889                          *    [min_pressure; max_pressure]
2890                          *  - pen aren't supported but w is 2
2891                          *
2892                          *  Note that this doesn't terminate the current action.
2893                          */
2894                         VLOG(2, (LOG_DEBUG,
2895                             "synaptics: palm detected! (%d)\n", w));
2896                         goto SYNAPTICS_END;
2897                 }
2898
2899                 /* Read current absolute position. */
2900                 x0 = ((pb->ipacket[3] & 0x10) << 8) |
2901                     ((pb->ipacket[1] & 0x0f) << 8) |
2902                     pb->ipacket[4];
2903                 y0 = ((pb->ipacket[3] & 0x20) << 7) |
2904                     ((pb->ipacket[1] & 0xf0) << 4) |
2905                     pb->ipacket[5];
2906
2907                 synaction = &(sc->synaction);
2908
2909                 /*
2910                  * If the action is just beginning, init the structure and
2911                  * compute tap timeout.
2912                  */
2913                 if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
2914                         VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
2915
2916                         /* Store the first point of this action. */
2917                         synaction->start_x = x0;
2918                         synaction->start_y = y0;
2919                         dx = dy = 0;
2920
2921                         /* Initialize queue. */
2922                         synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
2923                         synaction->queue_len = 0;
2924                         synaction->window_min = window_min;
2925
2926                         /* Reset average. */
2927                         synaction->avg_dx = 0;
2928                         synaction->avg_dy = 0;
2929
2930                         /* Reset squelch. */
2931                         synaction->squelch_x = 0;
2932                         synaction->squelch_y = 0;
2933
2934                         /* Reset pressure peak. */
2935                         sc->zmax = 0;
2936
2937                         /* Reset fingers count. */
2938                         synaction->fingers_nb = 0;
2939
2940                         /* Reset virtual scrolling state. */
2941                         synaction->in_vscroll = 0;
2942
2943                         /* Compute tap timeout. */
2944                         sc->taptimeout.tv_sec  = tap_timeout / 1000000;
2945                         sc->taptimeout.tv_usec = tap_timeout % 1000000;
2946                         timevaladd(&sc->taptimeout, &sc->lastsoftintr);
2947
2948                         sc->flags |= PSM_FLAGS_FINGERDOWN;
2949                 } else {
2950                         /* Calculate the current delta. */
2951                         cursor = synaction->queue_cursor;
2952                         dx = x0 - synaction->queue[cursor].x;
2953                         dy = y0 - synaction->queue[cursor].y;
2954                 }
2955
2956                 /* If in tap-hold, add the recorded button. */
2957                 if (synaction->in_taphold)
2958                         ms->button |= synaction->tap_button;
2959
2960                 /*
2961                  * From now on, we can use the SYNAPTICS_END label to skip
2962                  * the current packet.
2963                  */
2964
2965                 /*
2966                  * Limit the coordinates to the specified margins because
2967                  * this area isn't very reliable.
2968                  */
2969                 if (x0 <= margin_left)
2970                         x0 = margin_left;
2971                 else if (x0 >= 6143 - margin_right)
2972                         x0 = 6143 - margin_right;
2973                 if (y0 <= margin_bottom)
2974                         y0 = margin_bottom;
2975                 else if (y0 >= 6143 - margin_top)
2976                         y0 = 6143 - margin_top;
2977
2978                 VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
2979                     x0, y0, *z, w));
2980
2981                 /* Queue this new packet. */
2982                 cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
2983                 synaction->queue[cursor].x = x0;
2984                 synaction->queue[cursor].y = y0;
2985                 synaction->queue_cursor = cursor;
2986                 if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
2987                         synaction->queue_len++;
2988                 VLOG(5, (LOG_DEBUG,
2989                     "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
2990                     cursor, x0, y0, dx, dy));
2991
2992                 /*
2993                  * For tap, we keep the maximum number of fingers and the
2994                  * pressure peak. Also with multiple fingers, we increase
2995                  * the minimum window.
2996                  */
2997                 switch (w) {
2998                 case 1: /* Three or more fingers. */
2999                         synaction->fingers_nb = imax(3, synaction->fingers_nb);
3000                         synaction->window_min = window_max;
3001                         break;
3002                 case 0: /* Two fingers. */
3003                         synaction->fingers_nb = imax(2, synaction->fingers_nb);
3004                         synaction->window_min = window_max;
3005                         break;
3006                 default: /* One finger or undetectable. */
3007                         synaction->fingers_nb = imax(1, synaction->fingers_nb);
3008                 }
3009                 sc->zmax = imax(*z, sc->zmax);
3010
3011                 /* Do we have enough packets to consider this a movement? */
3012                 if (synaction->queue_len < synaction->window_min)
3013                         goto SYNAPTICS_END;
3014
3015                 /* Is a scrolling action occuring? */
3016                 if (!synaction->in_taphold && !synaction->in_vscroll) {
3017                         /*
3018                          * A scrolling action must not conflict with a tap
3019                          * action. Here are the conditions to consider a
3020                          * scrolling action:
3021                          *  - the action in a configurable area
3022                          *  - one of the following:
3023                          *     . the distance between the last packet and the
3024                          *       first should be above a configurable minimum
3025                          *     . tap timed out
3026                          */
3027                         dxp = abs(synaction->queue[synaction->queue_cursor].x -
3028                             synaction->start_x);
3029                         dyp = abs(synaction->queue[synaction->queue_cursor].y -
3030                             synaction->start_y);
3031
3032                         if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
3033                             dxp >= sc->syninfo.vscroll_min_delta ||
3034                             dyp >= sc->syninfo.vscroll_min_delta) {
3035                                 /*
3036                                  * Handle two finger scrolling.
3037                                  * Note that we don't rely on fingers_nb
3038                                  * as that keeps the maximum number of fingers.
3039                                  */
3040                                 if (two_finger_scroll) {
3041                                         if (w == 0) {
3042                                                 synaction->in_vscroll +=
3043                                                     dyp ? 2 : 0;
3044                                                 synaction->in_vscroll +=
3045                                                     dxp ? 1 : 0;
3046                                         }
3047                                 } else {
3048                                         /* Check for horizontal scrolling. */
3049                                         if ((vscroll_hor_area > 0 &&
3050                                             synaction->start_y <=
3051                                                 vscroll_hor_area) ||
3052                                             (vscroll_hor_area < 0 &&
3053                                              synaction->start_y >=
3054                                              6143 + vscroll_hor_area))
3055                                                 synaction->in_vscroll += 2;
3056
3057                                         /* Check for vertical scrolling. */
3058                                         if ((vscroll_ver_area > 0 &&
3059                                             synaction->start_x <=
3060                                                 vscroll_ver_area) ||
3061                                             (vscroll_ver_area < 0 &&
3062                                              synaction->start_x >=
3063                                              6143 + vscroll_ver_area))
3064                                                 synaction->in_vscroll += 1;
3065                                 }
3066
3067                                 /* Avoid conflicts if area overlaps. */
3068                                 if (synaction->in_vscroll >= 3)
3069                                         synaction->in_vscroll =
3070                                             (dxp > dyp) ? 2 : 1;
3071                         }
3072                 }
3073                 /*
3074                  * Reset two finger scrolling when the number of fingers
3075                  * is different from two.
3076                  */
3077                 if (two_finger_scroll && w != 0)
3078                         synaction->in_vscroll = 0;
3079
3080                 VLOG(5, (LOG_DEBUG,
3081                         "synaptics: virtual scrolling: %s "
3082                         "(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
3083                         synaction->in_vscroll ? "YES" : "NO",
3084                         synaction->in_vscroll, dxp, dyp,
3085                         synaction->fingers_nb));
3086
3087                 weight_prev_x = weight_prev_y = weight_previous;
3088                 div_max_x = div_max_y = div_max;
3089
3090                 if (synaction->in_vscroll) {
3091                         /* Dividers are different with virtual scrolling. */
3092                         div_min = sc->syninfo.vscroll_div_min;
3093                         div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
3094                 } else {
3095                         /*
3096                          * There's a lot of noise in coordinates when
3097                          * the finger is on the touchpad's borders. When
3098                          * using this area, we apply a special weight and
3099                          * div.
3100                          */
3101                         if (x0 <= na_left || x0 >= 6143 - na_right) {
3102                                 weight_prev_x = sc->syninfo.weight_previous_na;
3103                                 div_max_x = sc->syninfo.div_max_na;
3104                         }
3105
3106                         if (y0 <= na_bottom || y0 >= 6143 - na_top) {
3107                                 weight_prev_y = sc->syninfo.weight_previous_na;
3108                                 div_max_y = sc->syninfo.div_max_na;
3109                         }
3110                 }
3111
3112                 /*
3113                  * Calculate weights for the average operands and
3114                  * the divisor. Both depend on the distance between
3115                  * the current packet and a previous one (based on the
3116                  * window width).
3117                  */
3118                 window = imin(synaction->queue_len, window_max);
3119                 peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
3120                 dxp = abs(x0 - synaction->queue[peer].x) + 1;
3121                 dyp = abs(y0 - synaction->queue[peer].y) + 1;
3122                 len = (dxp * dxp) + (dyp * dyp);
3123                 weight_prev_x = imin(weight_prev_x,
3124                     weight_len_squared * weight_prev_x / len);
3125                 weight_prev_y = imin(weight_prev_y,
3126                     weight_len_squared * weight_prev_y / len);
3127
3128                 len = (dxp + dyp) / 2;
3129                 div_x = div_len * div_max_x / len;
3130                 div_x = imin(div_max_x, div_x);
3131                 div_x = imax(div_min, div_x);
3132                 div_y = div_len * div_max_y / len;
3133                 div_y = imin(div_max_y, div_y);
3134                 div_y = imax(div_min, div_y);
3135
3136                 VLOG(3, (LOG_DEBUG,
3137                     "synaptics: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
3138                     peer, len, weight_prev_x, weight_prev_y, div_x, div_y));
3139
3140                 /* Compute averages. */
3141                 synaction->avg_dx =
3142                     (weight_current * dx * multiplicator +
3143                      weight_prev_x * synaction->avg_dx) /
3144                     (weight_current + weight_prev_x);
3145
3146                 synaction->avg_dy =
3147                     (weight_current * dy * multiplicator +
3148                      weight_prev_y * synaction->avg_dy) /
3149                     (weight_current + weight_prev_y);
3150
3151                 VLOG(5, (LOG_DEBUG,
3152                     "synaptics: avg_dx~=%d, avg_dy~=%d\n",
3153                     synaction->avg_dx / multiplicator,
3154                     synaction->avg_dy / multiplicator));
3155
3156                 /* Use these averages to calculate x & y. */
3157                 synaction->squelch_x += synaction->avg_dx;
3158                 *x = synaction->squelch_x / (div_x * multiplicator);
3159                 synaction->squelch_x = synaction->squelch_x %
3160                     (div_x * multiplicator);
3161
3162                 synaction->squelch_y += synaction->avg_dy;
3163                 *y = synaction->squelch_y / (div_y * multiplicator);
3164                 synaction->squelch_y = synaction->squelch_y %
3165                     (div_y * multiplicator);
3166
3167                 if (synaction->in_vscroll) {
3168                         switch(synaction->in_vscroll) {
3169                         case 1: /* Vertical scrolling. */
3170                                 if (*y != 0)
3171                                         ms->button |= (*y > 0) ?
3172                                             MOUSE_BUTTON4DOWN :
3173                                             MOUSE_BUTTON5DOWN;
3174                                 break;
3175                         case 2: /* Horizontal scrolling. */
3176                                 if (*x != 0)
3177                                         ms->button |= (*x > 0) ?
3178                                             MOUSE_BUTTON7DOWN :
3179                                             MOUSE_BUTTON6DOWN;
3180                                 break;
3181                         }
3182
3183                         /* The pointer is not moved. */
3184                         *x = *y = 0;
3185                 } else {
3186                         VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n",
3187                             dx, dy, *x, *y));
3188                 }
3189         } else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3190                 /*
3191                  * An action is currently taking place but the pressure
3192                  * dropped under the minimum, putting an end to it.
3193                  */
3194                 synapticsaction_t *synaction;
3195                 int taphold_timeout, dx, dy, tap_max_delta;
3196
3197                 synaction = &(sc->synaction);
3198                 dx = abs(synaction->queue[synaction->queue_cursor].x -
3199                     synaction->start_x);
3200                 dy = abs(synaction->queue[synaction->queue_cursor].y -
3201                     synaction->start_y);
3202
3203                 /* Max delta is disabled for multi-fingers tap. */
3204                 if (synaction->fingers_nb > 1)
3205                         tap_max_delta = imax(dx, dy);
3206                 else
3207                         tap_max_delta = sc->syninfo.tap_max_delta;
3208
3209                 sc->flags &= ~PSM_FLAGS_FINGERDOWN;
3210
3211                 /* Check for tap. */
3212                 VLOG(3, (LOG_DEBUG,
3213                     "synaptics: zmax=%d, dx=%d, dy=%d, "
3214                     "delta=%d, fingers=%d, queue=%d\n",
3215                     sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb,
3216                     synaction->queue_len));
3217                 if (!synaction->in_vscroll && sc->zmax >= tap_threshold &&
3218                     timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) &&
3219                     dx <= tap_max_delta && dy <= tap_max_delta &&
3220                     synaction->queue_len >= sc->syninfo.tap_min_queue) {
3221                         /*
3222                          * We have a tap if:
3223                          *   - the maximum pressure went over tap_threshold
3224                          *   - the action ended before tap_timeout
3225                          *
3226                          * To handle tap-hold, we must delay any button push to
3227                          * the next action.
3228                          */
3229                         if (synaction->in_taphold) {
3230                                 /*
3231                                  * This is the second and last tap of a
3232                                  * double tap action, not a tap-hold.
3233                                  */
3234                                 synaction->in_taphold = 0;
3235
3236                                 /*
3237                                  * For double-tap to work:
3238                                  *   - no button press is emitted (to
3239                                  *     simulate a button release)
3240                                  *   - PSM_FLAGS_FINGERDOWN is set to
3241                                  *     force the next packet to emit a
3242                                  *     button press)
3243                                  */
3244                                 VLOG(2, (LOG_DEBUG,
3245                                     "synaptics: button RELEASE: %d\n",
3246                                     synaction->tap_button));
3247                                 sc->flags |= PSM_FLAGS_FINGERDOWN;
3248                         } else {
3249                                 /*
3250                                  * This is the first tap: we set the
3251                                  * tap-hold state and notify the button
3252                                  * down event.
3253                                  */
3254                                 synaction->in_taphold = 1;
3255                                 taphold_timeout = sc->syninfo.taphold_timeout;
3256                                 sc->taptimeout.tv_sec  = taphold_timeout /
3257                                     1000000;
3258                                 sc->taptimeout.tv_usec = taphold_timeout %
3259                                     1000000;
3260                                 timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3261
3262                                 switch (synaction->fingers_nb) {
3263                                 case 3:
3264                                         synaction->tap_button =
3265                                             MOUSE_BUTTON2DOWN;
3266                                         break;
3267                                 case 2:
3268                                         synaction->tap_button =
3269                                             MOUSE_BUTTON3DOWN;
3270                                         break;
3271                                 default:
3272                                         synaction->tap_button =
3273                                             MOUSE_BUTTON1DOWN;
3274                                 }
3275                                 VLOG(2, (LOG_DEBUG,
3276                                     "synaptics: button PRESS: %d\n",
3277                                     synaction->tap_button));
3278                                 ms->button |= synaction->tap_button;
3279                         }
3280                 } else {
3281                         /*
3282                          * Not enough pressure or timeout: reset
3283                          * tap-hold state.
3284                          */
3285                         if (synaction->in_taphold) {
3286                                 VLOG(2, (LOG_DEBUG,
3287                                     "synaptics: button RELEASE: %d\n",
3288                                     synaction->tap_button));
3289                                 synaction->in_taphold = 0;
3290                         } else {
3291                                 VLOG(2, (LOG_DEBUG,
3292                                     "synaptics: not a tap-hold\n"));
3293                         }
3294                 }
3295         } else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
3296             sc->synaction.in_taphold) {
3297                 /*
3298                  * For a tap-hold to work, the button must remain down at
3299                  * least until timeout (where the in_taphold flags will be
3300                  * cleared) or during the next action.
3301                  */
3302                 if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
3303                         ms->button |= sc->synaction.tap_button;
3304                 } else {
3305                         VLOG(2, (LOG_DEBUG,
3306                             "synaptics: button RELEASE: %d\n",
3307                             sc->synaction.tap_button));
3308                         sc->synaction.in_taphold = 0;
3309                 }
3310         }
3311
3312 SYNAPTICS_END:
3313         /*
3314          * Use the extra buttons as a scrollwheel
3315          *
3316          * XXX X.Org uses the Z axis for vertical wheel only,
3317          * whereas moused(8) understands special values to differ
3318          * vertical and horizontal wheels.
3319          *
3320          * xf86-input-mouse needs therefore a small patch to
3321          * understand these special values. Without it, the
3322          * horizontal wheel acts as a vertical wheel in X.Org.
3323          *
3324          * That's why the horizontal wheel is disabled by
3325          * default for now.
3326          */
3327
3328         if (ms->button & MOUSE_BUTTON4DOWN) {
3329                 *z = -1;
3330                 ms->button &= ~MOUSE_BUTTON4DOWN;
3331         } else if (ms->button & MOUSE_BUTTON5DOWN) {
3332                 *z = 1;
3333                 ms->button &= ~MOUSE_BUTTON5DOWN;
3334         } else if (ms->button & MOUSE_BUTTON6DOWN) {
3335                 *z = -2;
3336                 ms->button &= ~MOUSE_BUTTON6DOWN;
3337         } else if (ms->button & MOUSE_BUTTON7DOWN) {
3338                 *z = 2;
3339                 ms->button &= ~MOUSE_BUTTON7DOWN;
3340         } else
3341                 *z = 0;
3342
3343         return (0);
3344 }
3345
3346 static void
3347 proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
3348     int *x, int *y, int *z)
3349 {
3350         static int butmap_versapad[8] = {
3351                 0,
3352                 MOUSE_BUTTON3DOWN,
3353                 0,
3354                 MOUSE_BUTTON3DOWN,
3355                 MOUSE_BUTTON1DOWN,
3356                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
3357                 MOUSE_BUTTON1DOWN,
3358                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
3359         };
3360         int c, x0, y0;
3361
3362         /* VersaPad PS/2 absolute mode message format
3363          *
3364          * [packet1]     7   6   5   4   3   2   1   0(LSB)
3365          *  ipacket[0]:  1   1   0   A   1   L   T   R
3366          *  ipacket[1]: H7  H6  H5  H4  H3  H2  H1  H0
3367          *  ipacket[2]: V7  V6  V5  V4  V3  V2  V1  V0
3368          *  ipacket[3]:  1   1   1   A   1   L   T   R
3369          *  ipacket[4]:V11 V10  V9  V8 H11 H10  H9  H8
3370          *  ipacket[5]:  0  P6  P5  P4  P3  P2  P1  P0
3371          *
3372          * [note]
3373          *  R: right physical mouse button (1=on)
3374          *  T: touch pad virtual button (1=tapping)
3375          *  L: left physical mouse button (1=on)
3376          *  A: position data is valid (1=valid)
3377          *  H: horizontal data (12bit signed integer. H11 is sign bit.)
3378          *  V: vertical data (12bit signed integer. V11 is sign bit.)
3379          *  P: pressure data
3380          *
3381          * Tapping is mapped to MOUSE_BUTTON4.
3382          */
3383         c = pb->ipacket[0];
3384         *x = *y = 0;
3385         ms->button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
3386         ms->button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
3387         if (c & MOUSE_PS2VERSA_IN_USE) {
3388                 x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8);
3389                 y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4);
3390                 if (x0 & 0x800)
3391                         x0 -= 0x1000;
3392                 if (y0 & 0x800)
3393                         y0 -= 0x1000;
3394                 if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3395                         *x = sc->xold - x0;
3396                         *y = y0 - sc->yold;
3397                         if (*x < 0)     /* XXX */
3398                                 ++*x;
3399                         else if (*x)
3400                                 --*x;
3401                         if (*y < 0)
3402                                 ++*y;
3403                         else if (*y)
3404                                 --*y;
3405                 } else
3406                         sc->flags |= PSM_FLAGS_FINGERDOWN;
3407                 sc->xold = x0;
3408                 sc->yold = y0;
3409         } else
3410                 sc->flags &= ~PSM_FLAGS_FINGERDOWN;
3411 }
3412
3413 static void
3414 psmsoftintr(void *arg)
3415 {
3416         /*
3417          * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
3418          * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
3419          */
3420         static int butmap[8] = {
3421                 0,
3422                 MOUSE_BUTTON1DOWN,
3423                 MOUSE_BUTTON3DOWN,
3424                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
3425                 MOUSE_BUTTON2DOWN,
3426                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
3427                 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
3428                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
3429         };
3430         struct psm_softc *sc = arg;
3431         mousestatus_t ms;
3432         packetbuf_t *pb;
3433         int x, y, z, c, l, s;
3434
3435         getmicrouptime(&sc->lastsoftintr);
3436
3437         s = spltty();
3438
3439         do {
3440                 pb = &sc->pqueue[sc->pqueue_start];
3441
3442                 if (sc->mode.level == PSM_LEVEL_NATIVE)
3443                         goto next_native;
3444
3445                 c = pb->ipacket[0];
3446                 /*
3447                  * A kludge for Kensington device!
3448                  * The MSB of the horizontal count appears to be stored in
3449                  * a strange place.
3450                  */
3451                 if (sc->hw.model == MOUSE_MODEL_THINK)
3452                         pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
3453
3454                 /* ignore the overflow bits... */
3455                 x = (c & MOUSE_PS2_XNEG) ?
3456                     pb->ipacket[1] - 256 : pb->ipacket[1];
3457                 y = (c & MOUSE_PS2_YNEG) ?
3458                     pb->ipacket[2] - 256 : pb->ipacket[2];
3459                 z = 0;
3460                 ms.obutton = sc->button;          /* previous button state */
3461                 ms.button = butmap[c & MOUSE_PS2_BUTTONS];
3462                 /* `tapping' action */
3463                 if (sc->config & PSM_CONFIG_FORCETAP)
3464                         ms.button |= ((c & MOUSE_PS2_TAP)) ?
3465                             0 : MOUSE_BUTTON4DOWN;
3466
3467                 switch (sc->hw.model) {
3468
3469                 case MOUSE_MODEL_EXPLORER:
3470                         /*
3471                          *          b7 b6 b5 b4 b3 b2 b1 b0
3472                          * byte 1:  oy ox sy sx 1  M  R  L
3473                          * byte 2:  x  x  x  x  x  x  x  x
3474                          * byte 3:  y  y  y  y  y  y  y  y
3475                          * byte 4:  *  *  S2 S1 s  d2 d1 d0
3476                          *
3477                          * L, M, R, S1, S2: left, middle, right and side buttons
3478                          * s: wheel data sign bit
3479                          * d2-d0: wheel data
3480                          */
3481                         z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) ?
3482                             (pb->ipacket[3] & 0x0f) - 16 :
3483                             (pb->ipacket[3] & 0x0f);
3484                         ms.button |=
3485                             (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) ?
3486                             MOUSE_BUTTON4DOWN : 0;
3487                         ms.button |=
3488                             (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) ?
3489                             MOUSE_BUTTON5DOWN : 0;
3490                         break;
3491
3492                 case MOUSE_MODEL_INTELLI:
3493                 case MOUSE_MODEL_NET:
3494                         /* wheel data is in the fourth byte */
3495                         z = (char)pb->ipacket[3];
3496                         /*
3497                          * XXX some mice may send 7 when there is no Z movement?                         */
3498                         if ((z >= 7) || (z <= -7))
3499                                 z = 0;
3500                         /* some compatible mice have additional buttons */
3501                         ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) ?
3502                             MOUSE_BUTTON4DOWN : 0;
3503                         ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) ?
3504                             MOUSE_BUTTON5DOWN : 0;
3505                         break;
3506
3507                 case MOUSE_MODEL_MOUSEMANPLUS:
3508                         proc_mmanplus(sc, pb, &ms, &x, &y, &z);
3509                         break;
3510
3511                 case MOUSE_MODEL_GLIDEPOINT:
3512                         /* `tapping' action */
3513                         ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 :
3514                             MOUSE_BUTTON4DOWN;
3515                         break;
3516
3517                 case MOUSE_MODEL_NETSCROLL:
3518                         /*
3519                          * three addtional bytes encode buttons and
3520                          * wheel events
3521                          */
3522                         ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) ?
3523                             MOUSE_BUTTON4DOWN : 0;
3524                         ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) ?
3525                             MOUSE_BUTTON5DOWN : 0;
3526                         z = (pb->ipacket[3] & MOUSE_PS2_XNEG) ?
3527                             pb->ipacket[4] - 256 : pb->ipacket[4];
3528                         break;
3529
3530                 case MOUSE_MODEL_THINK:
3531                         /* the fourth button state in the first byte */
3532                         ms.button |= (c & MOUSE_PS2_TAP) ?
3533                             MOUSE_BUTTON4DOWN : 0;
3534                         break;
3535
3536                 case MOUSE_MODEL_VERSAPAD:
3537                         proc_versapad(sc, pb, &ms, &x, &y, &z);
3538                         c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
3539                             ((y < 0) ? MOUSE_PS2_YNEG : 0);
3540                         break;
3541
3542                 case MOUSE_MODEL_4D:
3543                         /*
3544                          *          b7 b6 b5 b4 b3 b2 b1 b0
3545                          * byte 1:  s2 d2 s1 d1 1  M  R  L
3546                          * byte 2:  sx x  x  x  x  x  x  x
3547                          * byte 3:  sy y  y  y  y  y  y  y
3548                          *
3549                          * s1: wheel 1 direction
3550                          * d1: wheel 1 data
3551                          * s2: wheel 2 direction
3552                          * d2: wheel 2 data
3553                          */
3554                         x = (pb->ipacket[1] & 0x80) ?
3555                             pb->ipacket[1] - 256 : pb->ipacket[1];
3556                         y = (pb->ipacket[2] & 0x80) ?
3557                             pb->ipacket[2] - 256 : pb->ipacket[2];
3558                         switch (c & MOUSE_4D_WHEELBITS) {
3559                         case 0x10:
3560                                 z = 1;
3561                                 break;
3562                         case 0x30:
3563                                 z = -1;
3564                                 break;
3565                         case 0x40:      /* XXX 2nd wheel turning right */
3566                                 z = 2;
3567                                 break;
3568                         case 0xc0:      /* XXX 2nd wheel turning left */
3569                                 z = -2;
3570                                 break;
3571                         }
3572                         break;
3573
3574                 case MOUSE_MODEL_4DPLUS:
3575                         if ((x < 16 - 256) && (y < 16 - 256)) {
3576                                 /*
3577                                  *          b7 b6 b5 b4 b3 b2 b1 b0
3578                                  * byte 1:  0  0  1  1  1  M  R  L
3579                                  * byte 2:  0  0  0  0  1  0  0  0
3580                                  * byte 3:  0  0  0  0  S  s  d1 d0
3581                                  *
3582                                  * L, M, R, S: left, middle, right,
3583                                  *             and side buttons
3584                                  * s: wheel data sign bit
3585                                  * d1-d0: wheel data
3586                                  */
3587                                 x = y = 0;
3588                                 if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
3589                                         ms.button |= MOUSE_BUTTON4DOWN;
3590                                 z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) ?
3591                                     ((pb->ipacket[2] & 0x07) - 8) :
3592                                     (pb->ipacket[2] & 0x07) ;
3593                         } else {
3594                                 /* preserve previous button states */
3595                                 ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
3596                         }
3597                         break;
3598
3599                 case MOUSE_MODEL_SYNAPTICS:
3600                         if (proc_synaptics(sc, pb, &ms, &x, &y, &z) != 0)
3601                                 goto next;
3602                         break;
3603
3604                 case MOUSE_MODEL_TRACKPOINT:
3605                 case MOUSE_MODEL_GENERIC:
3606                 default:
3607                         break;
3608                 }
3609
3610         /* scale values */
3611         if (sc->mode.accelfactor >= 1) {
3612                 if (x != 0) {
3613                         x = x * x / sc->mode.accelfactor;
3614                         if (x == 0)
3615                                 x = 1;
3616                         if (c & MOUSE_PS2_XNEG)
3617                                 x = -x;
3618                 }
3619                 if (y != 0) {
3620                         y = y * y / sc->mode.accelfactor;
3621                         if (y == 0)
3622                                 y = 1;
3623                         if (c & MOUSE_PS2_YNEG)
3624                                 y = -y;
3625                 }
3626         }
3627
3628         ms.dx = x;
3629         ms.dy = y;
3630         ms.dz = z;
3631         ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) |
3632             (ms.obutton ^ ms.button);
3633
3634         pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket);
3635
3636         sc->status.flags |= ms.flags;
3637         sc->status.dx += ms.dx;
3638         sc->status.dy += ms.dy;
3639         sc->status.dz += ms.dz;
3640         sc->status.button = ms.button;
3641         sc->button = ms.button;
3642
3643 next_native:
3644         sc->watchdog = FALSE;
3645
3646         /* queue data */
3647         if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) {
3648                 l = imin(pb->inputbytes,
3649                     sizeof(sc->queue.buf) - sc->queue.tail);
3650                 bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
3651                 if (pb->inputbytes > l)
3652                         bcopy(&pb->ipacket[l], &sc->queue.buf[0],
3653                             pb->inputbytes - l);
3654                 sc->queue.tail = (sc->queue.tail + pb->inputbytes) %
3655                     sizeof(sc->queue.buf);
3656                 sc->queue.count += pb->inputbytes;
3657         }
3658         pb->inputbytes = 0;
3659
3660 next:
3661         if (++sc->pqueue_start >= PSM_PACKETQUEUE)
3662                 sc->pqueue_start = 0;
3663         } while (sc->pqueue_start != sc->pqueue_end);
3664
3665         if (sc->state & PSM_ASLP) {
3666                 sc->state &= ~PSM_ASLP;
3667                 wakeup(sc);
3668         }
3669         selwakeuppri(&sc->rsel, PZERO);
3670         if (sc->async != NULL) {
3671                 pgsigio(&sc->async, SIGIO, 0);
3672         }
3673         sc->state &= ~PSM_SOFTARMED;
3674         splx(s);
3675 }
3676
3677 static int
3678 psmpoll(struct cdev *dev, int events, struct thread *td)
3679 {
3680         struct psm_softc *sc = dev->si_drv1;
3681         int s;
3682         int revents = 0;
3683
3684         /* Return true if a mouse event available */
3685         s = spltty();
3686         if (events & (POLLIN | POLLRDNORM)) {
3687                 if (sc->queue.count > 0)
3688                         revents |= events & (POLLIN | POLLRDNORM);
3689                 else
3690                         selrecord(td, &sc->rsel);
3691         }
3692         splx(s);
3693
3694         return (revents);
3695 }
3696
3697 /* vendor/model specific routines */
3698
3699 static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
3700 {
3701         if (set_mouse_resolution(kbdc, res) != res)
3702                 return (FALSE);
3703         if (set_mouse_scaling(kbdc, scale) &&
3704             set_mouse_scaling(kbdc, scale) &&
3705             set_mouse_scaling(kbdc, scale) &&
3706             (get_mouse_status(kbdc, status, 0, 3) >= 3))
3707                 return (TRUE);
3708         return (FALSE);
3709 }
3710
3711 static int
3712 mouse_ext_command(KBDC kbdc, int command)
3713 {
3714         int c;
3715
3716         c = (command >> 6) & 0x03;
3717         if (set_mouse_resolution(kbdc, c) != c)
3718                 return (FALSE);
3719         c = (command >> 4) & 0x03;
3720         if (set_mouse_resolution(kbdc, c) != c)
3721                 return (FALSE);
3722         c = (command >> 2) & 0x03;
3723         if (set_mouse_resolution(kbdc, c) != c)
3724                 return (FALSE);
3725         c = (command >> 0) & 0x03;
3726         if (set_mouse_resolution(kbdc, c) != c)
3727                 return (FALSE);
3728         return (TRUE);
3729 }
3730
3731 #ifdef notyet
3732 /* Logitech MouseMan Cordless II */
3733 static int
3734 enable_lcordless(KDBC kbdc, struct psm_softc *sc)
3735 {
3736         int status[3];
3737         int ch;
3738
3739         if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 2, status))
3740                 return (FALSE);
3741         if (status[1] == PSMD_RES_HIGH)
3742                 return (FALSE);
3743         ch = (status[0] & 0x07) - 1;    /* channel # */
3744         if ((ch <= 0) || (ch > 4))
3745                 return (FALSE);
3746         /*
3747          * status[1]: always one?
3748          * status[2]: battery status? (0-100)
3749          */
3750         return (TRUE);
3751 }
3752 #endif /* notyet */
3753
3754 /* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
3755 static int
3756 enable_groller(KBDC kbdc, struct psm_softc *sc)
3757 {
3758         int status[3];
3759
3760         /*
3761          * The special sequence to enable the fourth button and the
3762          * roller. Immediately after this sequence check status bytes.
3763          * if the mouse is NetScroll, the second and the third bytes are
3764          * '3' and 'D'.
3765          */
3766
3767         /*
3768          * If the mouse is an ordinary PS/2 mouse, the status bytes should
3769          * look like the following.
3770          *
3771          * byte 1 bit 7 always 0
3772          *        bit 6 stream mode (0)
3773          *        bit 5 disabled (0)
3774          *        bit 4 1:1 scaling (0)
3775          *        bit 3 always 0
3776          *        bit 0-2 button status
3777          * byte 2 resolution (PSMD_RES_HIGH)
3778          * byte 3 report rate (?)
3779          */
3780
3781         if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
3782                 return (FALSE);
3783         if ((status[1] != '3') || (status[2] != 'D'))
3784                 return (FALSE);
3785         /* FIXME: SmartScroll Mouse has 5 buttons! XXX */
3786         if (sc != NULL)
3787                 sc->hw.buttons = 4;
3788         return (TRUE);
3789 }
3790
3791 /* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
3792 static int
3793 enable_gmouse(KBDC kbdc, struct psm_softc *sc)
3794 {
3795         int status[3];
3796
3797         /*
3798          * The special sequence to enable the middle, "rubber" button.
3799          * Immediately after this sequence check status bytes.
3800          * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
3801          * the second and the third bytes are '3' and 'U'.
3802          * NOTE: NetMouse reports that it has three buttons although it has
3803          * two buttons and a rubber button. NetMouse Pro and MIE Mouse
3804          * say they have three buttons too and they do have a button on the
3805          * side...
3806          */
3807         if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
3808                 return (FALSE);
3809         if ((status[1] != '3') || (status[2] != 'U'))
3810                 return (FALSE);
3811         return (TRUE);
3812 }
3813
3814 /* ALPS GlidePoint */
3815 static int
3816 enable_aglide(KBDC kbdc, struct psm_softc *sc)
3817 {
3818         int status[3];
3819
3820         /*
3821          * The special sequence to obtain ALPS GlidePoint specific
3822          * information. Immediately after this sequence, status bytes will
3823          * contain something interesting.
3824          * NOTE: ALPS produces several models of GlidePoint. Some of those
3825          * do not respond to this sequence, thus, cannot be detected this way.
3826          */
3827         if (set_mouse_sampling_rate(kbdc, 100) != 100)
3828                 return (FALSE);
3829         if (!mouse_id_proc1(kbdc, PSMD_RES_LOW, 2, status))
3830                 return (FALSE);
3831         if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
3832                 return (FALSE);
3833         return (TRUE);
3834 }
3835
3836 /* Kensington ThinkingMouse/Trackball */
3837 static int
3838 enable_kmouse(KBDC kbdc, struct psm_softc *sc)
3839 {
3840         static u_char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
3841         int status[3];
3842         int id1;
3843         int id2;
3844         int i;
3845
3846         id1 = get_aux_id(kbdc);
3847         if (set_mouse_sampling_rate(kbdc, 10) != 10)
3848                 return (FALSE);
3849         /*
3850          * The device is now in the native mode? It returns a different
3851          * ID value...
3852          */
3853         id2 = get_aux_id(kbdc);
3854         if ((id1 == id2) || (id2 != 2))
3855                 return (FALSE);
3856
3857         if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
3858                 return (FALSE);
3859 #if PSM_DEBUG >= 2
3860         /* at this point, resolution is LOW, sampling rate is 10/sec */
3861         if (get_mouse_status(kbdc, status, 0, 3) < 3)
3862                 return (FALSE);
3863 #endif
3864
3865         /*
3866          * The special sequence to enable the third and fourth buttons.
3867          * Otherwise they behave like the first and second buttons.
3868          */
3869         for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3870                 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3871                         return (FALSE);
3872
3873         /*
3874          * At this point, the device is using default resolution and
3875          * sampling rate for the native mode.
3876          */
3877         if (get_mouse_status(kbdc, status, 0, 3) < 3)
3878                 return (FALSE);
3879         if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
3880                 return (FALSE);
3881
3882         /* the device appears be enabled by this sequence, diable it for now */
3883         disable_aux_dev(kbdc);
3884         empty_aux_buffer(kbdc, 5);
3885
3886         return (TRUE);
3887 }
3888
3889 /* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
3890 static int
3891 enable_mmanplus(KBDC kbdc, struct psm_softc *sc)
3892 {
3893         int data[3];
3894
3895         /* the special sequence to enable the fourth button and the roller. */
3896         /*
3897          * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
3898          * must be called exactly three times since the last RESET command
3899          * before this sequence. XXX
3900          */
3901         if (!set_mouse_scaling(kbdc, 1))
3902                 return (FALSE);
3903         if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
3904                 return (FALSE);
3905         if (get_mouse_status(kbdc, data, 1, 3) < 3)
3906                 return (FALSE);
3907
3908         /*
3909          * PS2++ protocol, packet type 0
3910          *
3911          *          b7 b6 b5 b4 b3 b2 b1 b0
3912          * byte 1:  *  1  p3 p2 1  *  *  *
3913          * byte 2:  1  1  p1 p0 m1 m0 1  0
3914          * byte 3:  m7 m6 m5 m4 m3 m2 m1 m0
3915          *
3916          * p3-p0: packet type: 0
3917          * m7-m0: model ID: MouseMan+:0x50,
3918          *                  FirstMouse+:0x51,
3919          *                  ScrollPoint:0x58...
3920          */
3921         /* check constant bits */
3922         if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
3923                 return (FALSE);
3924         if ((data[1] & 0xc3) != 0xc2)
3925                 return (FALSE);
3926         /* check d3-d0 in byte 2 */
3927         if (!MOUSE_PS2PLUS_CHECKBITS(data))
3928                 return (FALSE);
3929         /* check p3-p0 */
3930         if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
3931                 return (FALSE);
3932
3933         if (sc != NULL) {
3934                 sc->hw.hwid &= 0x00ff;
3935                 sc->hw.hwid |= data[2] << 8;    /* save model ID */
3936         }
3937
3938         /*
3939          * MouseMan+ (or FirstMouse+) is now in its native mode, in which
3940          * the wheel and the fourth button events are encoded in the
3941          * special data packet. The mouse may be put in the IntelliMouse mode
3942          * if it is initialized by the IntelliMouse's method.
3943          */
3944         return (TRUE);
3945 }
3946
3947 /* MS IntelliMouse Explorer */
3948 static int
3949 enable_msexplorer(KBDC kbdc, struct psm_softc *sc)
3950 {
3951         static u_char rate0[] = { 200, 100, 80, };
3952         static u_char rate1[] = { 200, 200, 80, };
3953         int id;
3954         int i;
3955
3956         /*
3957          * This is needed for at least A4Tech X-7xx mice - they do not go
3958          * straight to Explorer mode, but need to be set to Intelli mode
3959          * first.
3960          */
3961         enable_msintelli(kbdc, sc);
3962
3963         /* the special sequence to enable the extra buttons and the roller. */
3964         for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i)
3965                 if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
3966                         return (FALSE);
3967         /* the device will give the genuine ID only after the above sequence */
3968         id = get_aux_id(kbdc);
3969         if (id != PSM_EXPLORER_ID)
3970                 return (FALSE);
3971
3972         if (sc != NULL) {
3973                 sc->hw.buttons = 5;     /* IntelliMouse Explorer XXX */
3974                 sc->hw.hwid = id;
3975         }
3976
3977         /*
3978          * XXX: this is a kludge to fool some KVM switch products
3979          * which think they are clever enough to know the 4-byte IntelliMouse
3980          * protocol, and assume any other protocols use 3-byte packets.
3981          * They don't convey 4-byte data packets from the IntelliMouse Explorer
3982          * correctly to the host computer because of this!
3983          * The following sequence is actually IntelliMouse's "wake up"
3984          * sequence; it will make the KVM think the mouse is IntelliMouse
3985          * when it is in fact IntelliMouse Explorer.
3986          */
3987         for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i)
3988                 if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
3989                         break;
3990         get_aux_id(kbdc);
3991
3992         return (TRUE);
3993 }
3994
3995 /* MS IntelliMouse */
3996 static int
3997 enable_msintelli(KBDC kbdc, struct psm_softc *sc)
3998 {
3999         /*
4000          * Logitech MouseMan+ and FirstMouse+ will also respond to this
4001          * probe routine and act like IntelliMouse.
4002          */
4003
4004         static u_char rate[] = { 200, 100, 80, };
4005         int id;
4006         int i;
4007
4008         /* the special sequence to enable the third button and the roller. */
4009         for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
4010                 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
4011                         return (FALSE);
4012         /* the device will give the genuine ID only after the above sequence */
4013         id = get_aux_id(kbdc);
4014         if (id != PSM_INTELLI_ID)
4015                 return (FALSE);
4016
4017         if (sc != NULL) {
4018                 sc->hw.buttons = 3;
4019                 sc->hw.hwid = id;
4020         }
4021
4022         return (TRUE);
4023 }
4024
4025 /* A4 Tech 4D Mouse */
4026 static int
4027 enable_4dmouse(KBDC kbdc, struct psm_softc *sc)
4028 {
4029         /*
4030          * Newer wheel mice from A4 Tech may use the 4D+ protocol.
4031          */
4032
4033         static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
4034         int id;
4035         int i;
4036
4037         for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
4038                 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
4039                         return (FALSE);
4040         id = get_aux_id(kbdc);
4041         /*
4042          * WinEasy 4D, 4 Way Scroll 4D: 6
4043          * Cable-Free 4D: 8 (4DPLUS)
4044          * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
4045          */
4046         if (id != PSM_4DMOUSE_ID)
4047                 return (FALSE);
4048
4049         if (sc != NULL) {
4050                 sc->hw.buttons = 3;     /* XXX some 4D mice have 4? */
4051                 sc->hw.hwid = id;
4052         }
4053
4054         return (TRUE);
4055 }
4056
4057 /* A4 Tech 4D+ Mouse */
4058 static int
4059 enable_4dplus(KBDC kbdc, struct psm_softc *sc)
4060 {
4061         /*
4062          * Newer wheel mice from A4 Tech seem to use this protocol.
4063          * Older models are recognized as either 4D Mouse or IntelliMouse.
4064          */
4065         int id;
4066
4067         /*
4068          * enable_4dmouse() already issued the following ID sequence...
4069         static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
4070         int i;
4071
4072         for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
4073                 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
4074                         return (FALSE);
4075         */
4076
4077         id = get_aux_id(kbdc);
4078         switch (id) {
4079         case PSM_4DPLUS_ID:
4080                 break;
4081         case PSM_4DPLUS_RFSW35_ID:
4082                 break;
4083         default:
4084                 return (FALSE);
4085         }
4086
4087         if (sc != NULL) {
4088                 sc->hw.buttons = (id == PSM_4DPLUS_ID) ? 4 : 3;
4089                 sc->hw.hwid = id;
4090         }
4091
4092         return (TRUE);
4093 }
4094
4095 /* Synaptics Touchpad */
4096 static int
4097 synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4098 {
4099         int error, arg;
4100
4101         /* Read the current value. */
4102         arg = *(int *)oidp->oid_arg1;
4103         error = sysctl_handle_int(oidp, &arg, 0, req);
4104
4105         /* Sanity check. */
4106         if (error || !req->newptr)
4107                 return (error);
4108
4109         /*
4110          * Check that the new value is in the concerned node's range
4111          * of values.
4112          */
4113         switch (oidp->oid_arg2) {
4114         case SYNAPTICS_SYSCTL_MIN_PRESSURE:
4115         case SYNAPTICS_SYSCTL_MAX_PRESSURE:
4116                 if (arg < 0 || arg > 255)
4117                         return (EINVAL);
4118                 break;
4119         case SYNAPTICS_SYSCTL_MAX_WIDTH:
4120                 if (arg < 4 || arg > 15)
4121                         return (EINVAL);
4122                 break;
4123         case SYNAPTICS_SYSCTL_MARGIN_TOP:
4124         case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4125         case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4126         case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4127         case SYNAPTICS_SYSCTL_NA_TOP:
4128         case SYNAPTICS_SYSCTL_NA_RIGHT:
4129         case SYNAPTICS_SYSCTL_NA_BOTTOM:
4130         case SYNAPTICS_SYSCTL_NA_LEFT:
4131                 if (arg < 0 || arg > 6143)
4132                         return (EINVAL);
4133                 break;
4134         case SYNAPTICS_SYSCTL_WINDOW_MIN:
4135         case SYNAPTICS_SYSCTL_WINDOW_MAX:
4136         case SYNAPTICS_SYSCTL_TAP_MIN_QUEUE:
4137                 if (arg < 1 || arg > SYNAPTICS_PACKETQUEUE)
4138                         return (EINVAL);
4139                 break;
4140         case SYNAPTICS_SYSCTL_MULTIPLICATOR:
4141         case SYNAPTICS_SYSCTL_WEIGHT_CURRENT:
4142         case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS:
4143         case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA:
4144         case SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED:
4145         case SYNAPTICS_SYSCTL_DIV_MIN:
4146         case SYNAPTICS_SYSCTL_DIV_MAX:
4147         case SYNAPTICS_SYSCTL_DIV_MAX_NA:
4148         case SYNAPTICS_SYSCTL_DIV_LEN:
4149         case SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN:
4150         case SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX:
4151                 if (arg < 1)
4152                         return (EINVAL);
4153                 break;
4154         case SYNAPTICS_SYSCTL_TAP_MAX_DELTA:
4155         case SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT:
4156         case SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA:
4157                 if (arg < 0)
4158                         return (EINVAL);
4159                 break;
4160         case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4161         case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4162                 if (arg < -6143 || arg > 6143)
4163                         return (EINVAL);
4164                 break;
4165         case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
4166                 if (arg < 0 || arg > 1)
4167                         return (EINVAL);
4168                 break;
4169         default:
4170                 return (EINVAL);
4171         }
4172
4173         /* Update. */
4174         *(int *)oidp->oid_arg1 = arg;
4175
4176         return (error);
4177 }
4178
4179 static void
4180 synaptics_sysctl_create_tree(struct psm_softc *sc)
4181 {
4182
4183         if (sc->syninfo.sysctl_tree != NULL)
4184                 return;
4185
4186         /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
4187         sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
4188         sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
4189             SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
4190             0, "Synaptics TouchPad");
4191
4192         /* hw.psm.synaptics.directional_scrolls. */
4193         sc->syninfo.directional_scrolls = 0;
4194         SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
4195             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4196             "directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY,
4197             &sc->syninfo.directional_scrolls, 0,
4198             "Enable hardware scrolling pad (if non-zero) or register it as "
4199             "extended buttons (if 0)");
4200
4201         /*
4202          * Turn off two finger scroll if we have a
4203          * physical area reserved for scrolling or when
4204          * there's no multi finger support.
4205          */
4206         if (sc->synhw.verticalScroll || (sc->synhw.capMultiFinger == 0 &&
4207                                          sc->synhw.capAdvancedGestures == 0))
4208                 sc->syninfo.two_finger_scroll = 0;
4209         else
4210                 sc->syninfo.two_finger_scroll = 1;
4211         /* hw.psm.synaptics.two_finger_scroll. */
4212         SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
4213             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4214             "two_finger_scroll", CTLFLAG_RW|CTLFLAG_ANYBODY,
4215             &sc->syninfo.two_finger_scroll, 0,
4216             "Enable two finger scrolling");
4217
4218         /* hw.psm.synaptics.min_pressure. */
4219         sc->syninfo.min_pressure = 16;
4220         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4221             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4222             "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4223             &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE,
4224             synaptics_sysctl, "I",
4225             "Minimum pressure required to start an action");
4226
4227         /* hw.psm.synaptics.max_pressure. */
4228         sc->syninfo.max_pressure = 220;
4229         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4230             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4231             "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4232             &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE,
4233             synaptics_sysctl, "I",
4234             "Maximum pressure to detect palm");
4235
4236         /* hw.psm.synaptics.max_width. */
4237         sc->syninfo.max_width = 10;
4238         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4239             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4240             "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4241             &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH,
4242             synaptics_sysctl, "I",
4243             "Maximum finger width to detect palm");
4244
4245         /* hw.psm.synaptics.top_margin. */
4246         sc->syninfo.margin_top = 200;
4247         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4248             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4249             "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4250             &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP,
4251             synaptics_sysctl, "I",
4252             "Top margin");
4253
4254         /* hw.psm.synaptics.right_margin. */
4255         sc->syninfo.margin_right = 200;
4256         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4257             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4258             "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4259             &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
4260             synaptics_sysctl, "I",
4261             "Right margin");
4262
4263         /* hw.psm.synaptics.bottom_margin. */
4264         sc->syninfo.margin_bottom = 200;
4265         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4266             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4267             "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4268             &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
4269             synaptics_sysctl, "I",
4270             "Bottom margin");
4271
4272         /* hw.psm.synaptics.left_margin. */
4273         sc->syninfo.margin_left = 200;
4274         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4275             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4276             "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4277             &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT,
4278             synaptics_sysctl, "I",
4279             "Left margin");
4280
4281         /* hw.psm.synaptics.na_top. */
4282         sc->syninfo.na_top = 1783;
4283         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4284             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4285             "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4286             &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP,
4287             synaptics_sysctl, "I",
4288             "Top noisy area, where weight_previous_na is used instead "
4289             "of weight_previous");
4290
4291         /* hw.psm.synaptics.na_right. */
4292         sc->syninfo.na_right = 563;
4293         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4294             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4295             "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4296             &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT,
4297             synaptics_sysctl, "I",
4298             "Right noisy area, where weight_previous_na is used instead "
4299             "of weight_previous");
4300
4301         /* hw.psm.synaptics.na_bottom. */
4302         sc->syninfo.na_bottom = 1408;
4303         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4304             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4305             "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4306             &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM,
4307             synaptics_sysctl, "I",
4308             "Bottom noisy area, where weight_previous_na is used instead "
4309             "of weight_previous");
4310
4311         /* hw.psm.synaptics.na_left. */
4312         sc->syninfo.na_left = 1600;
4313         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4314             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4315             "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4316             &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT,
4317             synaptics_sysctl, "I",
4318             "Left noisy area, where weight_previous_na is used instead "
4319             "of weight_previous");
4320
4321         /* hw.psm.synaptics.window_min. */
4322         sc->syninfo.window_min = 4;
4323         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4324             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4325             "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4326             &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN,
4327             synaptics_sysctl, "I",
4328             "Minimum window size to start an action");
4329
4330         /* hw.psm.synaptics.window_max. */
4331         sc->syninfo.window_max = 10;
4332         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4333             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4334             "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4335             &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX,
4336             synaptics_sysctl, "I",
4337             "Maximum window size");
4338
4339         /* hw.psm.synaptics.multiplicator. */
4340         sc->syninfo.multiplicator = 10000;
4341         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4342             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4343             "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4344             &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR,
4345             synaptics_sysctl, "I",
4346             "Multiplicator to increase precision in averages and divisions");
4347
4348         /* hw.psm.synaptics.weight_current. */
4349         sc->syninfo.weight_current = 3;
4350         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4351             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4352             "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4353             &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
4354             synaptics_sysctl, "I",
4355             "Weight of the current movement in the new average");
4356
4357         /* hw.psm.synaptics.weight_previous. */
4358         sc->syninfo.weight_previous = 6;
4359         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4360             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4361             "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4362             &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
4363             synaptics_sysctl, "I",
4364             "Weight of the previous average");
4365
4366         /* hw.psm.synaptics.weight_previous_na. */
4367         sc->syninfo.weight_previous_na = 20;
4368         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4369             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4370             "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4371             &sc->syninfo.weight_previous_na,
4372             SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4373             synaptics_sysctl, "I",
4374             "Weight of the previous average (inside the noisy area)");
4375
4376         /* hw.psm.synaptics.weight_len_squared. */
4377         sc->syninfo.weight_len_squared = 2000;
4378         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4379             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4380             "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4381             &sc->syninfo.weight_len_squared,
4382             SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4383             synaptics_sysctl, "I",
4384             "Length (squared) of segments where weight_previous "
4385             "starts to decrease");
4386
4387         /* hw.psm.synaptics.div_min. */
4388         sc->syninfo.div_min = 9;
4389         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4390             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4391             "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4392             &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN,
4393             synaptics_sysctl, "I",
4394             "Divisor for fast movements");
4395
4396         /* hw.psm.synaptics.div_max. */
4397         sc->syninfo.div_max = 17;
4398         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4399             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4400             "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4401             &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX,
4402             synaptics_sysctl, "I",
4403             "Divisor for slow movements");
4404
4405         /* hw.psm.synaptics.div_max_na. */
4406         sc->syninfo.div_max_na = 30;
4407         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4408             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4409             "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4410             &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA,
4411             synaptics_sysctl, "I",
4412             "Divisor with slow movements (inside the noisy area)");
4413
4414         /* hw.psm.synaptics.div_len. */
4415         sc->syninfo.div_len = 100;
4416         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4417             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4418             "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4419             &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN,
4420             synaptics_sysctl, "I",
4421             "Length of segments where div_max starts to decrease");
4422
4423         /* hw.psm.synaptics.tap_max_delta. */
4424         sc->syninfo.tap_max_delta = 80;
4425         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4426             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4427             "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4428             &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
4429             synaptics_sysctl, "I",
4430             "Length of segments above which a tap is ignored");
4431
4432         /* hw.psm.synaptics.tap_min_queue. */
4433         sc->syninfo.tap_min_queue = 2;
4434         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4435             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4436             "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4437             &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
4438             synaptics_sysctl, "I",
4439             "Number of packets required to consider a tap");
4440
4441         /* hw.psm.synaptics.taphold_timeout. */
4442         sc->synaction.in_taphold = 0;
4443         sc->syninfo.taphold_timeout = tap_timeout;
4444         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4445             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4446             "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4447             &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
4448             synaptics_sysctl, "I",
4449             "Maximum elapsed time between two taps to consider a tap-hold "
4450             "action");
4451
4452         /* hw.psm.synaptics.vscroll_hor_area. */
4453         sc->syninfo.vscroll_hor_area = 0; /* 1300 */
4454         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4455             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4456             "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4457             &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
4458             synaptics_sysctl, "I",
4459             "Area reserved for horizontal virtual scrolling");
4460
4461         /* hw.psm.synaptics.vscroll_ver_area. */
4462         sc->syninfo.vscroll_ver_area = -600;
4463         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4464             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4465             "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4466             &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
4467             synaptics_sysctl, "I",
4468             "Area reserved for vertical virtual scrolling");
4469
4470         /* hw.psm.synaptics.vscroll_min_delta. */
4471         sc->syninfo.vscroll_min_delta = 50;
4472         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4473             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4474             "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4475             &sc->syninfo.vscroll_min_delta,
4476             SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4477             synaptics_sysctl, "I",
4478             "Minimum movement to consider virtual scrolling");
4479
4480         /* hw.psm.synaptics.vscroll_div_min. */
4481         sc->syninfo.vscroll_div_min = 100;
4482         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4483             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4484             "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4485             &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
4486             synaptics_sysctl, "I",
4487             "Divisor for fast scrolling");
4488
4489         /* hw.psm.synaptics.vscroll_div_min. */
4490         sc->syninfo.vscroll_div_max = 150;
4491         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4492             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4493             "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4494             &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
4495             synaptics_sysctl, "I",
4496             "Divisor for slow scrolling");
4497
4498         /* hw.psm.synaptics.touchpad_off. */
4499         sc->syninfo.touchpad_off = 0;
4500         SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4501             SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4502             "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4503             &sc->syninfo.touchpad_off, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
4504             synaptics_sysctl, "I",
4505             "Turn off touchpad");
4506 }
4507
4508 static int
4509 synaptics_preferred_mode(struct psm_softc *sc) {
4510         int mode_byte;
4511
4512         mode_byte = 0xc0;
4513
4514         /* request wmode where available */
4515         if (sc->synhw.capExtended)
4516                 mode_byte |= 1;
4517
4518         /*
4519          * Disable gesture processing when native packets are requested. This
4520          * enables sending of encapsulated "extended W mode" packets.
4521          */
4522         if (sc->mode.level == PSM_LEVEL_NATIVE)
4523                 mode_byte |= (1 << 2);
4524
4525         return mode_byte;
4526 }
4527
4528 static void
4529 synaptics_set_mode(struct psm_softc *sc, int mode_byte) {
4530         mouse_ext_command(sc->kbdc, mode_byte);
4531
4532         /* "Commit" the Set Mode Byte command sent above. */
4533         set_mouse_sampling_rate(sc->kbdc, 20);
4534
4535         /*
4536          * Enable advanced gestures mode if supported and we are not entering
4537          * passthrough mode.
4538          */
4539         if (sc->synhw.capAdvancedGestures && !(mode_byte & (1 << 5))) {
4540                 mouse_ext_command(sc->kbdc, 3);
4541                 set_mouse_sampling_rate(sc->kbdc, 0xc8);
4542         }
4543 }
4544
4545 static int
4546 enable_synaptics(KBDC kbdc, struct psm_softc *sc)
4547 {
4548         synapticshw_t synhw;
4549         int status[3];
4550         int buttons;
4551
4552         VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n"));
4553
4554         /*
4555          * Just to be on the safe side: this avoids troubles with
4556          * following mouse_ext_command() when the previous command
4557          * was PSMC_SET_RESOLUTION. Set Scaling has no effect on
4558          * Synaptics Touchpad behaviour.
4559          */
4560         set_mouse_scaling(kbdc, 1);
4561
4562         /* Identify the Touchpad version. */
4563         if (mouse_ext_command(kbdc, 0) == 0)
4564                 return (FALSE);
4565         if (get_mouse_status(kbdc, status, 0, 3) != 3)
4566                 return (FALSE);
4567         if (status[1] != 0x47)
4568                 return (FALSE);
4569
4570         bzero(&synhw, sizeof(synhw));
4571         synhw.infoMinor = status[0];
4572         synhw.infoMajor = status[2] & 0x0f;
4573
4574         if (verbose >= 2)
4575                 printf("Synaptics Touchpad v%d.%d\n", synhw.infoMajor,
4576                     synhw.infoMinor);
4577
4578         if (synhw.infoMajor < 4) {
4579                 printf("  Unsupported (pre-v4) Touchpad detected\n");
4580                 return (FALSE);
4581         }
4582
4583         /* Get the Touchpad model information. */
4584         if (mouse_ext_command(kbdc, 3) == 0)
4585                 return (FALSE);
4586         if (get_mouse_status(kbdc, status, 0, 3) != 3)
4587                 return (FALSE);
4588         if ((status[1] & 0x01) != 0) {
4589                 printf("  Failed to read model information\n");
4590                 return (FALSE);
4591         }
4592
4593         synhw.infoRot180   = (status[0] & 0x80) != 0;
4594         synhw.infoPortrait = (status[0] & 0x40) != 0;
4595         synhw.infoSensor   =  status[0] & 0x3f;
4596         synhw.infoHardware = (status[1] & 0xfe) >> 1;
4597         synhw.infoNewAbs   = (status[2] & 0x80) != 0;
4598         synhw.capPen       = (status[2] & 0x40) != 0;
4599         synhw.infoSimplC   = (status[2] & 0x20) != 0;
4600         synhw.infoGeometry =  status[2] & 0x0f;
4601
4602         if (verbose >= 2) {
4603                 printf("  Model information:\n");
4604                 printf("   infoRot180: %d\n", synhw.infoRot180);
4605                 printf("   infoPortrait: %d\n", synhw.infoPortrait);
4606                 printf("   infoSensor: %d\n", synhw.infoSensor);
4607                 printf("   infoHardware: %d\n", synhw.infoHardware);
4608                 printf("   infoNewAbs: %d\n", synhw.infoNewAbs);
4609                 printf("   capPen: %d\n", synhw.capPen);
4610                 printf("   infoSimplC: %d\n", synhw.infoSimplC);
4611                 printf("   infoGeometry: %d\n", synhw.infoGeometry);
4612         }
4613
4614         /* Read the extended capability bits. */
4615         if (mouse_ext_command(kbdc, 2) == 0)
4616                 return (FALSE);
4617         if (get_mouse_status(kbdc, status, 0, 3) != 3)
4618                 return (FALSE);
4619         if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) {
4620                 printf("  Failed to read extended capability bits\n");
4621                 return (FALSE);
4622         }
4623
4624         /* Set the different capabilities when they exist. */
4625         buttons = 0;
4626         synhw.capExtended = (status[0] & 0x80) != 0;
4627         if (synhw.capExtended) {
4628                 synhw.nExtendedQueries = (status[0] & 0x70) >> 4;
4629                 synhw.capMiddle        = (status[0] & 0x04) != 0;
4630                 synhw.capPassthrough   = (status[2] & 0x80) != 0;
4631                 synhw.capLowPower      = (status[2] & 0x40) != 0;
4632                 synhw.capMultiFingerReport =
4633                                          (status[2] & 0x20) != 0;
4634                 synhw.capSleep         = (status[2] & 0x10) != 0;
4635                 synhw.capFourButtons   = (status[2] & 0x08) != 0;
4636                 synhw.capBallistics    = (status[2] & 0x04) != 0;
4637                 synhw.capMultiFinger   = (status[2] & 0x02) != 0;
4638                 synhw.capPalmDetect    = (status[2] & 0x01) != 0;
4639
4640                 if (!set_mouse_scaling(kbdc, 1))
4641                         return (FALSE);
4642                 if (mouse_ext_command(kbdc, 0x08) == 0)
4643                         return (FALSE);
4644                 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4645                         return (FALSE);
4646
4647                 synhw.infoXupmm = status[0];
4648                 synhw.infoYupmm = status[2];
4649
4650                 if (verbose >= 2) {
4651                         printf("  Extended capabilities:\n");
4652                         printf("   capExtended: %d\n", synhw.capExtended);
4653                         printf("   capMiddle: %d\n", synhw.capMiddle);
4654                         printf("   nExtendedQueries: %d\n",
4655                             synhw.nExtendedQueries);
4656                         printf("   capPassthrough: %d\n", synhw.capPassthrough);
4657                         printf("   capLowPower: %d\n", synhw.capLowPower);
4658                         printf("   capMultiFingerReport: %d\n",
4659                             synhw.capMultiFingerReport);
4660                         printf("   capSleep: %d\n", synhw.capSleep);
4661                         printf("   capFourButtons: %d\n", synhw.capFourButtons);
4662                         printf("   capBallistics: %d\n", synhw.capBallistics);
4663                         printf("   capMultiFinger: %d\n", synhw.capMultiFinger);
4664                         printf("   capPalmDetect: %d\n", synhw.capPalmDetect);
4665                         printf("   infoXupmm: %d\n", synhw.infoXupmm);
4666                         printf("   infoYupmm: %d\n", synhw.infoYupmm);
4667                 }
4668
4669                 /*
4670                  * If nExtendedQueries is 1 or greater, then the TouchPad
4671                  * supports this number of extended queries. We can load
4672                  * more information about buttons using query 0x09.
4673                  */
4674                 if (synhw.nExtendedQueries >= 1) {
4675                         if (!set_mouse_scaling(kbdc, 1))
4676                                 return (FALSE);
4677                         if (mouse_ext_command(kbdc, 0x09) == 0)
4678                                 return (FALSE);
4679                         if (get_mouse_status(kbdc, status, 0, 3) != 3)
4680                                 return (FALSE);
4681                         synhw.verticalScroll   = (status[0] & 0x01) != 0;
4682                         synhw.horizontalScroll = (status[0] & 0x02) != 0;
4683                         synhw.verticalWheel    = (status[0] & 0x08) != 0;
4684                         synhw.nExtendedButtons = (status[1] & 0xf0) >> 4;
4685                         synhw.capEWmode        = (status[0] & 0x04) != 0;
4686                         if (verbose >= 2) {
4687                                 printf("  Extended model ID:\n");
4688                                 printf("   verticalScroll: %d\n",
4689                                     synhw.verticalScroll);
4690                                 printf("   horizontalScroll: %d\n",
4691                                     synhw.horizontalScroll);
4692                                 printf("   verticalWheel: %d\n",
4693                                     synhw.verticalWheel);
4694                                 printf("   nExtendedButtons: %d\n",
4695                                     synhw.nExtendedButtons);
4696                                 printf("   capEWmode: %d\n",
4697                                     synhw.capEWmode);
4698                         }
4699                         /*
4700                          * Add the number of extended buttons to the total
4701                          * button support count, including the middle button
4702                          * if capMiddle support bit is set.
4703                          */
4704                         buttons = synhw.nExtendedButtons + synhw.capMiddle;
4705                 } else
4706                         /*
4707                          * If the capFourButtons support bit is set,
4708                          * add a fourth button to the total button count.
4709                          */
4710                         buttons = synhw.capFourButtons ? 1 : 0;
4711
4712                 /* Read the continued capabilities bits. */
4713                 if (synhw.nExtendedQueries >= 4) {
4714                         if (!set_mouse_scaling(kbdc, 1))
4715                                 return (FALSE);
4716                         if (mouse_ext_command(kbdc, 0x0c) == 0)
4717                                 return (FALSE);
4718                         if (get_mouse_status(kbdc, status, 0, 3) != 3)
4719                                 return (FALSE);
4720
4721                         synhw.capClickPad         = (status[1] & 0x01) << 1;
4722                         synhw.capClickPad        |= (status[0] & 0x10) != 0;
4723                         synhw.capDeluxeLEDs       = (status[1] & 0x02) != 0;
4724                         synhw.noAbsoluteFilter    = (status[1] & 0x04) != 0;
4725                         synhw.capReportsV         = (status[1] & 0x08) != 0;
4726                         synhw.capUniformClickPad  = (status[1] & 0x10) != 0;
4727                         synhw.capReportsMin       = (status[1] & 0x20) != 0;
4728                         synhw.capInterTouch       = (status[1] & 0x40) != 0;
4729                         synhw.capReportsMax       = (status[0] & 0x02) != 0;
4730                         synhw.capClearPad         = (status[0] & 0x04) != 0;
4731                         synhw.capAdvancedGestures = (status[0] & 0x08) != 0;
4732                         synhw.capCoveredPad       = (status[0] & 0x80) != 0;
4733
4734                         if (synhw.capReportsMax) {
4735                                 if (!set_mouse_scaling(kbdc, 1))
4736                                         return (FALSE);
4737                                 if (mouse_ext_command(kbdc, 0x0d) == 0)
4738                                         return (FALSE);
4739                                 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4740                                         return (FALSE);
4741
4742                                 synhw.maximumXCoord = (status[0] << 5) |
4743                                                      ((status[1] & 0x0f) << 1);
4744                                 synhw.maximumYCoord = (status[2] << 5) |
4745                                                      ((status[1] & 0xf0) >> 3);
4746                         }
4747                         if (synhw.capReportsMin) {
4748                                 if (!set_mouse_scaling(kbdc, 1))
4749                                         return (FALSE);
4750                                 if (mouse_ext_command(kbdc, 0x0f) == 0)
4751                                         return (FALSE);
4752                                 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4753                                         return (FALSE);
4754
4755                                 synhw.minimumXCoord = (status[0] << 5) |
4756                                                      ((status[1] & 0x0f) << 1);
4757                                 synhw.minimumYCoord = (status[2] << 5) |
4758                                                      ((status[1] & 0xf0) >> 3);
4759                         }
4760
4761                         if (verbose >= 2) {
4762                                 printf("  Continued capabilities:\n");
4763                                 printf("   capClickPad: %d\n",
4764                                        synhw.capClickPad);
4765                                 printf("   capDeluxeLEDs: %d\n",
4766                                        synhw.capDeluxeLEDs);
4767                                 printf("   noAbsoluteFilter: %d\n",
4768                                        synhw.noAbsoluteFilter);
4769                                 printf("   capReportsV: %d\n",
4770                                        synhw.capReportsV);
4771                                 printf("   capUniformClickPad: %d\n",
4772                                        synhw.capUniformClickPad);
4773                                 printf("   capReportsMin: %d\n",
4774                                        synhw.capReportsMin);
4775                                 printf("   capInterTouch: %d\n",
4776                                        synhw.capInterTouch);
4777                                 printf("   capReportsMax: %d\n",
4778                                        synhw.capReportsMax);
4779                                 printf("   capClearPad: %d\n",
4780                                        synhw.capClearPad);
4781                                 printf("   capAdvancedGestures: %d\n",
4782                                        synhw.capAdvancedGestures);
4783                                 printf("   capCoveredPad: %d\n",
4784                                        synhw.capCoveredPad);
4785                                 if (synhw.capReportsMax) {
4786                                         printf("   maximumXCoord: %d\n",
4787                                                synhw.maximumXCoord);
4788                                         printf("   maximumYCoord: %d\n",
4789                                                synhw.maximumYCoord);
4790                                 }
4791                                 if (synhw.capReportsMin) {
4792                                         printf("   minimumXCoord: %d\n",
4793                                                synhw.minimumXCoord);
4794                                         printf("   minimumYCoord: %d\n",
4795                                                synhw.minimumYCoord);
4796                                 }
4797                         }
4798                         buttons += synhw.capClickPad;
4799                 }
4800         }
4801
4802         if (verbose >= 2) {
4803                 if (synhw.capExtended)
4804                         printf("  Additional Buttons: %d\n", buttons);
4805                 else
4806                         printf("  No extended capabilities\n");
4807         }
4808
4809         /*
4810          * Add the default number of 3 buttons to the total
4811          * count of supported buttons reported above.
4812          */
4813         buttons += 3;
4814
4815         /*
4816          * Read the mode byte.
4817          *
4818          * XXX: Note the Synaptics documentation also defines the first
4819          * byte of the response to this query to be a constant 0x3b, this
4820          * does not appear to be true for Touchpads with guest devices.
4821          */
4822         if (mouse_ext_command(kbdc, 1) == 0)
4823                 return (FALSE);
4824         if (get_mouse_status(kbdc, status, 0, 3) != 3)
4825                 return (FALSE);
4826         if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) {
4827                 printf("  Failed to read mode byte\n");
4828                 return (FALSE);
4829         }
4830
4831         if (sc != NULL)
4832                 sc->synhw = synhw;
4833         if (!synaptics_support)
4834                 return (FALSE);
4835
4836         VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n", buttons));
4837
4838         if (sc != NULL) {
4839                 synaptics_set_mode(sc, synaptics_preferred_mode(sc));
4840                 if (trackpoint_support && synhw.capPassthrough) {
4841                         synaptics_passthrough_on(sc);
4842                         enable_trackpoint(kbdc, sc);
4843                         synaptics_passthrough_off(sc);
4844                 }
4845                 /* Create sysctl tree. */
4846                 synaptics_sysctl_create_tree(sc);
4847                 sc->hw.buttons = buttons;
4848         }
4849
4850         return (TRUE);
4851 }
4852
4853 static void
4854 synaptics_passthrough_on(struct psm_softc *sc)
4855 {
4856         VLOG(2, (LOG_NOTICE, "psm: setting pass-through mode.\n"));
4857         synaptics_set_mode(sc, synaptics_preferred_mode(sc) | (1 << 5));
4858 }
4859
4860 static void
4861 synaptics_passthrough_off(struct psm_softc *sc)
4862 {
4863         VLOG(2, (LOG_NOTICE, "psm: turning pass-through mode off.\n"));
4864         set_mouse_scaling(sc->kbdc, 2);
4865         set_mouse_scaling(sc->kbdc, 1);
4866         synaptics_set_mode(sc, synaptics_preferred_mode(sc));
4867 }
4868
4869 /* IBM/Lenovo TrackPoint */
4870 static int
4871 trackpoint_command(struct psm_softc *sc, int cmd, int loc, int val)
4872 {
4873         const int seq[] = { 0xe2, cmd, loc, val };
4874         int i;
4875
4876         if (sc->synhw.capPassthrough)
4877                 synaptics_passthrough_on(sc);
4878
4879         for (i = 0; i < nitems(seq); i++) {
4880                 if (sc->synhw.capPassthrough &&
4881                     (seq[i] == 0xff || seq[i] == 0xe7))
4882                         if (send_aux_command(sc->kbdc, 0xe7) != PSM_ACK) {
4883                                 synaptics_passthrough_off(sc);
4884                                 return (EIO);
4885                         }
4886                 if (send_aux_command(sc->kbdc, seq[i]) != PSM_ACK) {
4887                         if (sc->synhw.capPassthrough)
4888                                 synaptics_passthrough_off(sc);
4889                         return (EIO);
4890                 }
4891         }
4892
4893         if (sc->synhw.capPassthrough)
4894                 synaptics_passthrough_off(sc);
4895
4896         return (0);
4897 }
4898
4899 #define PSM_TPINFO(x)   offsetof(struct psm_softc, tpinfo.x)
4900 #define TPMASK          0
4901 #define TPLOC           1
4902 #define TPINFO          2
4903
4904 static int
4905 trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
4906 {
4907         static const int data[][3] = {
4908                 { 0x00, 0x4a, PSM_TPINFO(sensitivity) },
4909                 { 0x00, 0x4d, PSM_TPINFO(inertia) },
4910                 { 0x00, 0x60, PSM_TPINFO(uplateau) },
4911                 { 0x00, 0x57, PSM_TPINFO(reach) },
4912                 { 0x00, 0x58, PSM_TPINFO(draghys) },
4913                 { 0x00, 0x59, PSM_TPINFO(mindrag) },
4914                 { 0x00, 0x5a, PSM_TPINFO(upthresh) },
4915                 { 0x00, 0x5c, PSM_TPINFO(threshold) },
4916                 { 0x00, 0x5d, PSM_TPINFO(jenks) },
4917                 { 0x00, 0x5e, PSM_TPINFO(ztime) },
4918                 { 0x01, 0x2c, PSM_TPINFO(pts) },
4919                 { 0x08, 0x2d, PSM_TPINFO(skipback) }
4920         };
4921         struct psm_softc *sc;
4922         int error, newval, *oldvalp;
4923         const int *tp;
4924
4925         if (arg1 == NULL || arg2 < 0 || arg2 >= nitems(data))
4926                 return (EINVAL);
4927         sc = arg1;
4928         tp = data[arg2];
4929         oldvalp = (int *)((intptr_t)sc + tp[TPINFO]);
4930         newval = *oldvalp;
4931         error = sysctl_handle_int(oidp, &newval, 0, req);
4932         if (error != 0)
4933                 return (error);
4934         if (newval == *oldvalp)
4935                 return (0);
4936         if (newval < 0 || newval > (tp[TPMASK] == 0 ? 255 : 1))
4937                 return (EINVAL);
4938         error = trackpoint_command(sc, tp[TPMASK] == 0 ? 0x81 : 0x47,
4939             tp[TPLOC], tp[TPMASK] == 0 ? newval : tp[TPMASK]);
4940         if (error != 0)
4941                 return (error);
4942         *oldvalp = newval;
4943
4944         return (0);
4945 }
4946
4947 static void
4948 trackpoint_sysctl_create_tree(struct psm_softc *sc)
4949 {
4950
4951         if (sc->tpinfo.sysctl_tree != NULL)
4952                 return;
4953
4954         /* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */
4955         sysctl_ctx_init(&sc->tpinfo.sysctl_ctx);
4956         sc->tpinfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx,
4957             SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD,
4958             0, "IBM/Lenovo TrackPoint");
4959
4960         /* hw.psm.trackpoint.sensitivity */
4961         sc->tpinfo.sensitivity = 0x80;
4962         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4963             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4964             "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4965             sc, TRACKPOINT_SYSCTL_SENSITIVITY,
4966             trackpoint_sysctl, "I",
4967             "Sensitivity");
4968
4969         /* hw.psm.trackpoint.negative_inertia */
4970         sc->tpinfo.inertia = 0x06;
4971         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4972             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4973             "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4974             sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
4975             trackpoint_sysctl, "I",
4976             "Negative inertia factor");
4977
4978         /* hw.psm.trackpoint.upper_plateau */
4979         sc->tpinfo.uplateau = 0x61;
4980         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4981             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4982             "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4983             sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU,
4984             trackpoint_sysctl, "I",
4985             "Transfer function upper plateau speed");
4986
4987         /* hw.psm.trackpoint.backup_range */
4988         sc->tpinfo.reach = 0x0a;
4989         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4990             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4991             "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4992             sc, TRACKPOINT_SYSCTL_BACKUP_RANGE,
4993             trackpoint_sysctl, "I",
4994             "Backup range");
4995
4996         /* hw.psm.trackpoint.drag_hysteresis */
4997         sc->tpinfo.draghys = 0xff;
4998         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4999             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
5000             "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5001             sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
5002             trackpoint_sysctl, "I",
5003             "Drag hysteresis");
5004
5005         /* hw.psm.trackpoint.minimum_drag */
5006         sc->tpinfo.mindrag = 0x14;
5007         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
5008             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
5009             "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5010             sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG,
5011             trackpoint_sysctl, "I",
5012             "Minimum drag");
5013
5014         /* hw.psm.trackpoint.up_threshold */
5015         sc->tpinfo.upthresh = 0xff;
5016         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
5017             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
5018             "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5019             sc, TRACKPOINT_SYSCTL_UP_THRESHOLD,
5020             trackpoint_sysctl, "I",
5021             "Up threshold for release");
5022
5023         /* hw.psm.trackpoint.threshold */
5024         sc->tpinfo.threshold = 0x08;
5025         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
5026             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
5027             "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5028             sc, TRACKPOINT_SYSCTL_THRESHOLD,
5029             trackpoint_sysctl, "I",
5030             "Threshold");
5031
5032         /* hw.psm.trackpoint.jenks_curvature */
5033         sc->tpinfo.jenks = 0x87;
5034         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
5035             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
5036             "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5037             sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE,
5038             trackpoint_sysctl, "I",
5039             "Jenks curvature");
5040
5041         /* hw.psm.trackpoint.z_time */
5042         sc->tpinfo.ztime = 0x26;
5043         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
5044             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
5045             "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5046             sc, TRACKPOINT_SYSCTL_Z_TIME,
5047             trackpoint_sysctl, "I",
5048             "Z time constant");
5049
5050         /* hw.psm.trackpoint.press_to_select */
5051         sc->tpinfo.pts = 0x00;
5052         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
5053             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
5054             "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5055             sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
5056             trackpoint_sysctl, "I",
5057             "Press to Select");
5058
5059         /* hw.psm.trackpoint.skip_backups */
5060         sc->tpinfo.skipback = 0x00;
5061         SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
5062             SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
5063             "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5064             sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS,
5065             trackpoint_sysctl, "I",
5066             "Skip backups from drags");
5067 }
5068
5069 static void
5070 set_trackpoint_parameters(struct psm_softc *sc)
5071 {
5072         trackpoint_command(sc, 0x81, 0x4a, sc->tpinfo.sensitivity);
5073         trackpoint_command(sc, 0x81, 0x60, sc->tpinfo.uplateau);
5074         trackpoint_command(sc, 0x81, 0x4d, sc->tpinfo.inertia);
5075         trackpoint_command(sc, 0x81, 0x57, sc->tpinfo.reach);
5076         trackpoint_command(sc, 0x81, 0x58, sc->tpinfo.draghys);
5077         trackpoint_command(sc, 0x81, 0x59, sc->tpinfo.mindrag);
5078         trackpoint_command(sc, 0x81, 0x5a, sc->tpinfo.upthresh);
5079         trackpoint_command(sc, 0x81, 0x5c, sc->tpinfo.threshold);
5080         trackpoint_command(sc, 0x81, 0x5d, sc->tpinfo.jenks);
5081         trackpoint_command(sc, 0x81, 0x5e, sc->tpinfo.ztime);
5082         if (sc->tpinfo.pts == 0x01)
5083                 trackpoint_command(sc, 0x47, 0x2c, 0x01);
5084         if (sc->tpinfo.skipback == 0x01)
5085                 trackpoint_command(sc, 0x47, 0x2d, 0x08);
5086 }
5087
5088 static int
5089 enable_trackpoint(KBDC kbdc, struct psm_softc *sc)
5090 {
5091         int id;
5092
5093         if (send_aux_command(kbdc, 0xe1) != PSM_ACK ||
5094             read_aux_data(kbdc) != 0x01)
5095                 return (FALSE);
5096         id = read_aux_data(kbdc);
5097         if (id < 0x01)
5098                 return (FALSE);
5099         if (sc != NULL)
5100                 sc->tphw = id;
5101         if (!trackpoint_support)
5102                 return (FALSE);
5103
5104         if (sc != NULL) {
5105                 /* Create sysctl tree. */
5106                 trackpoint_sysctl_create_tree(sc);
5107
5108                 /*
5109                  * Don't overwrite hwid and buttons when we are
5110                  * a guest device.
5111                  */
5112                 if (!sc->synhw.capPassthrough) {
5113                         sc->hw.hwid = id;
5114                         sc->hw.buttons = 3;
5115                 }
5116         }
5117
5118         return (TRUE);
5119 }
5120
5121 /* Interlink electronics VersaPad */
5122 static int
5123 enable_versapad(KBDC kbdc, struct psm_softc *sc)
5124 {
5125         int data[3];
5126
5127         set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
5128         set_mouse_sampling_rate(kbdc, 100);             /* set rate 100 */
5129         set_mouse_scaling(kbdc, 1);                     /* set scale 1:1 */
5130         set_mouse_scaling(kbdc, 1);                     /* set scale 1:1 */
5131         set_mouse_scaling(kbdc, 1);                     /* set scale 1:1 */
5132         set_mouse_scaling(kbdc, 1);                     /* set scale 1:1 */
5133         if (get_mouse_status(kbdc, data, 0, 3) < 3)     /* get status */
5134                 return (FALSE);
5135         if (data[2] != 0xa || data[1] != 0 )    /* rate == 0xa && res. == 0 */
5136                 return (FALSE);
5137         set_mouse_scaling(kbdc, 1);                     /* set scale 1:1 */
5138
5139         return (TRUE);                          /* PS/2 absolute mode */
5140 }
5141
5142 /*
5143  * Return true if 'now' is earlier than (start + (secs.usecs)).
5144  * Now may be NULL and the function will fetch the current time from
5145  * getmicrouptime(), or a cached 'now' can be passed in.
5146  * All values should be numbers derived from getmicrouptime().
5147  */
5148 static int
5149 timeelapsed(start, secs, usecs, now)
5150         const struct timeval *start, *now;
5151         int secs, usecs;
5152 {
5153         struct timeval snow, tv;
5154
5155         /* if there is no 'now' passed in, the get it as a convience. */
5156         if (now == NULL) {
5157                 getmicrouptime(&snow);
5158                 now = &snow;
5159         }
5160
5161         tv.tv_sec = secs;
5162         tv.tv_usec = usecs;
5163         timevaladd(&tv, start);
5164         return (timevalcmp(&tv, now, <));
5165 }
5166
5167 static int
5168 psmresume(device_t dev)
5169 {
5170         struct psm_softc *sc = device_get_softc(dev);
5171         int unit = device_get_unit(dev);
5172         int err;
5173
5174         VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit));
5175
5176         if ((sc->config &
5177             (PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND)) == 0)
5178                 return (0);
5179
5180         err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND);
5181
5182         if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
5183                 /*
5184                  * Release the blocked process; it must be notified that
5185                  * the device cannot be accessed anymore.
5186                  */
5187                 sc->state &= ~PSM_ASLP;
5188                 wakeup(sc);
5189         }
5190
5191         VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit));
5192
5193         return (err);
5194 }
5195
5196 DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
5197
5198 #ifdef DEV_ISA
5199
5200 /*
5201  * This sucks up assignments from PNPBIOS and ACPI.
5202  */
5203
5204 /*
5205  * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may
5206  * appear BEFORE the AT keyboard controller.  As the PS/2 mouse device
5207  * can be probed and attached only after the AT keyboard controller is
5208  * attached, we shall quietly reserve the IRQ resource for later use.
5209  * If the PS/2 mouse device is reported to us AFTER the keyboard controller,
5210  * copy the IRQ resource to the PS/2 mouse device instance hanging
5211  * under the keyboard controller, then probe and attach it.
5212  */
5213
5214 static  devclass_t                      psmcpnp_devclass;
5215
5216 static  device_probe_t                  psmcpnp_probe;
5217 static  device_attach_t                 psmcpnp_attach;
5218
5219 static device_method_t psmcpnp_methods[] = {
5220         DEVMETHOD(device_probe,         psmcpnp_probe),
5221         DEVMETHOD(device_attach,        psmcpnp_attach),
5222
5223         { 0, 0 }
5224 };
5225
5226 static driver_t psmcpnp_driver = {
5227         PSMCPNP_DRIVER_NAME,
5228         psmcpnp_methods,
5229         1,                      /* no softc */
5230 };
5231
5232 static struct isa_pnp_id psmcpnp_ids[] = {
5233         { 0x030fd041, "PS/2 mouse port" },              /* PNP0F03 */
5234         { 0x0e0fd041, "PS/2 mouse port" },              /* PNP0F0E */
5235         { 0x120fd041, "PS/2 mouse port" },              /* PNP0F12 */
5236         { 0x130fd041, "PS/2 mouse port" },              /* PNP0F13 */
5237         { 0x1303d041, "PS/2 port" },                    /* PNP0313, XXX */
5238         { 0x02002e4f, "Dell PS/2 mouse port" },         /* Lat. X200, Dell */
5239         { 0x0002a906, "ALPS Glide Point" },             /* ALPS Glide Point */
5240         { 0x80374d24, "IBM PS/2 mouse port" },          /* IBM3780, ThinkPad */
5241         { 0x81374d24, "IBM PS/2 mouse port" },          /* IBM3781, ThinkPad */
5242         { 0x0190d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9001, Vaio */
5243         { 0x0290d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9002, Vaio */
5244         { 0x0390d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9003, Vaio */
5245         { 0x0490d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9004, Vaio */
5246         { 0 }
5247 };
5248
5249 static int
5250 create_a_copy(device_t atkbdc, device_t me)
5251 {
5252         device_t psm;
5253         u_long irq;
5254
5255         /* find the PS/2 mouse device instance under the keyboard controller */
5256         psm = device_find_child(atkbdc, PSM_DRIVER_NAME,
5257             device_get_unit(atkbdc));
5258         if (psm == NULL)
5259                 return (ENXIO);
5260         if (device_get_state(psm) != DS_NOTPRESENT)
5261                 return (0);
5262
5263         /* move our resource to the found device */
5264         irq = bus_get_resource_start(me, SYS_RES_IRQ, 0);
5265         bus_delete_resource(me, SYS_RES_IRQ, 0);
5266         bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
5267
5268         /* ...then probe and attach it */
5269         return (device_probe_and_attach(psm));
5270 }
5271
5272 static int
5273 psmcpnp_probe(device_t dev)
5274 {
5275         struct resource *res;
5276         u_long irq;
5277         int rid;
5278
5279         if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
5280                 return (ENXIO);
5281
5282         /*
5283          * The PnP BIOS and ACPI are supposed to assign an IRQ (12)
5284          * to the PS/2 mouse device node. But, some buggy PnP BIOS
5285          * declares the PS/2 mouse device node without an IRQ resource!
5286          * If this happens, we shall refer to device hints.
5287          * If we still don't find it there, use a hardcoded value... XXX
5288          */
5289         rid = 0;
5290         irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid);
5291         if (irq <= 0) {
5292                 if (resource_long_value(PSM_DRIVER_NAME,
5293                     device_get_unit(dev),"irq", &irq) != 0)
5294                         irq = 12;       /* XXX */
5295                 device_printf(dev, "irq resource info is missing; "
5296                     "assuming irq %ld\n", irq);
5297                 bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1);
5298         }
5299         res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
5300         bus_release_resource(dev, SYS_RES_IRQ, rid, res);
5301
5302         /* keep quiet */
5303         if (!bootverbose)
5304                 device_quiet(dev);
5305
5306         return ((res == NULL) ? ENXIO : 0);
5307 }
5308
5309 static int
5310 psmcpnp_attach(device_t dev)
5311 {
5312         device_t atkbdc;
5313
5314         /* find the keyboard controller, which may be on acpi* or isa* bus */
5315         atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME),
5316             device_get_unit(dev));
5317         if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED))
5318                 create_a_copy(atkbdc, dev);
5319
5320         return (0);
5321 }
5322
5323 DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0);
5324 DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0);
5325
5326 #endif /* DEV_ISA */