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