The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/isa/psm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * $FreeBSD$
   24  */
   25 
   26 /*
   27  *  Ported to 386bsd Oct 17, 1992
   28  *  Sandi Donno, Computer Science, University of Cape Town, South Africa
   29  *  Please send bug reports to sandi@cs.uct.ac.za
   30  *
   31  *  Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
   32  *  although I was only partially successful in getting the alpha release
   33  *  of his "driver for the Logitech and ATI Inport Bus mice for use with
   34  *  386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
   35  *  found his code to be an invaluable reference when porting this driver
   36  *  to 386bsd.
   37  *
   38  *  Further modifications for latest 386BSD+patchkit and port to NetBSD,
   39  *  Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
   40  *
   41  *  Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
   42  *  Andrew Herbert - 12 June 1993
   43  *
   44  *  Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
   45  *  - 13 June 1993
   46  *
   47  *  Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
   48  *  - 24 October 1993
   49  *
   50  *  Hardware access routines and probe logic rewritten by
   51  *  Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
   52  *  - 3, 14, 22 October 1996.
   53  *  - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
   54  *  - 14, 30 November 1996. Uses `kbdio.c'.
   55  *  - 13 December 1996. Uses queuing version of `kbdio.c'.
   56  *  - January/February 1997. Tweaked probe logic for 
   57  *    HiNote UltraII/Latitude/Armada laptops.
   58  *  - 30 July 1997. Added APM support.
   59  *  - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX). 
   60  *    Improved sync check logic.
   61  *    Vendor specific support routines.
   62  */
   63 
   64 #include "psm.h"
   65 /* #include "apm.h" */
   66 #include "opt_devfs.h"
   67 #include "opt_psm.h"
   68 
   69 #if NPSM > 0
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 #include <sys/kernel.h>
   74 #include <sys/module.h>
   75 #include <sys/bus.h>
   76 #include <sys/conf.h>
   77 #include <sys/poll.h>
   78 #include <sys/syslog.h>
   79 #include <sys/malloc.h>
   80 #include <sys/rman.h>
   81 #ifdef DEVFS
   82 #include <sys/devfsext.h>
   83 #endif
   84 #include <sys/select.h>
   85 #include <sys/uio.h>
   86 
   87 #include <machine/clock.h>
   88 #include <machine/limits.h>
   89 #include <machine/mouse.h>
   90 #include <machine/resource.h>
   91 
   92 #include <isa/isareg.h>
   93 #include <isa/isavar.h>
   94 #include <dev/kbd/atkbdcreg.h>
   95 
   96 /*
   97  * Driver specific options: the following options may be set by
   98  * `options' statements in the kernel configuration file.
   99  */
  100 
  101 /* debugging */
  102 #ifndef PSM_DEBUG
  103 #define PSM_DEBUG       0       /* logging: 0: none, 1: brief, 2: verbose */
  104 #endif
  105 
  106 /* features */
  107 
  108 /* #define PSM_HOOKAPM             hook the APM resume event */
  109 /* #define PSM_RESETAFTERSUSPEND   reset the device at the resume event */
  110 
  111 #if NAPM <= 0
  112 #undef PSM_HOOKAPM
  113 #endif /* NAPM */
  114 
  115 #ifndef PSM_HOOKAPM
  116 #undef PSM_RESETAFTERSUSPEND
  117 #endif /* PSM_HOOKAPM */
  118 
  119 /* end of driver specific options */
  120 
  121 /* input queue */
  122 #define PSM_BUFSIZE             960
  123 #define PSM_SMALLBUFSIZE        240
  124 
  125 /* operation levels */
  126 #define PSM_LEVEL_BASE          0
  127 #define PSM_LEVEL_STANDARD      1
  128 #define PSM_LEVEL_NATIVE        2
  129 #define PSM_LEVEL_MIN           PSM_LEVEL_BASE
  130 #define PSM_LEVEL_MAX           PSM_LEVEL_NATIVE
  131 
  132 /* Logitech PS2++ protocol */
  133 #define MOUSE_PS2PLUS_CHECKBITS(b)      \
  134                                 ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
  135 #define MOUSE_PS2PLUS_PACKET_TYPE(b)    \
  136                                 (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
  137 
  138 /* some macros */
  139 #define PSM_UNIT(dev)           (minor(dev) >> 1)
  140 #define PSM_NBLOCKIO(dev)       (minor(dev) & 1)
  141 #define PSM_MKMINOR(unit,block) (((unit) << 1) | ((block) ? 0:1))
  142 
  143 #ifndef max
  144 #define max(x,y)                ((x) > (y) ? (x) : (y))
  145 #endif
  146 #ifndef min
  147 #define min(x,y)                ((x) < (y) ? (x) : (y))
  148 #endif
  149 
  150 #define abs(x)                  (((x) < 0) ? -(x) : (x))
  151 
  152 /* ring buffer */
  153 typedef struct ringbuf {
  154     int           count;        /* # of valid elements in the buffer */
  155     int           head;         /* head pointer */
  156     int           tail;         /* tail poiner */
  157     unsigned char buf[PSM_BUFSIZE];
  158 } ringbuf_t;
  159 
  160 /* driver control block */
  161 struct psm_softc {              /* Driver status information */
  162     struct selinfo rsel;        /* Process selecting for Input */
  163     unsigned char state;        /* Mouse driver state */
  164     int           config;       /* driver configuration flags */
  165     int           flags;        /* other flags */
  166     KBDC          kbdc;         /* handle to access the keyboard controller */
  167     int           addr;         /* I/O port address */
  168     mousehw_t     hw;           /* hardware information */
  169     mousemode_t   mode;         /* operation mode */
  170     mousemode_t   dflt_mode;    /* default operation mode */
  171     mousestatus_t status;       /* accumulated mouse movement */
  172     ringbuf_t     queue;        /* mouse status queue */
  173     unsigned char ipacket[16];  /* interim input buffer */
  174     int           inputbytes;   /* # of bytes in the input buffer */
  175     int           button;       /* the latest button state */
  176     int           xold; /* previous absolute X position */
  177     int           yold; /* previous absolute Y position */
  178 #ifdef DEVFS
  179     void          *devfs_token;
  180     void          *b_devfs_token;
  181 #endif
  182 #ifdef PSM_HOOKAPM
  183     struct apmhook resumehook;
  184 #endif
  185 };
  186 devclass_t psm_devclass;
  187 #define PSM_SOFTC(unit) ((struct psm_softc*)devclass_get_softc(psm_devclass, unit))
  188 
  189 /* driver state flags (state) */
  190 #define PSM_VALID               0x80
  191 #define PSM_OPEN                1       /* Device is open */
  192 #define PSM_ASLP                2       /* Waiting for mouse data */
  193 
  194 /* driver configuration flags (config) */
  195 #define PSM_CONFIG_RESOLUTION   0x000f  /* resolution */
  196 #define PSM_CONFIG_ACCEL        0x00f0  /* acceleration factor */
  197 #define PSM_CONFIG_NOCHECKSYNC  0x0100  /* disable sync. test */
  198 #define PSM_CONFIG_NOIDPROBE    0x0200  /* disable mouse model probe */
  199 #define PSM_CONFIG_NORESET      0x0400  /* don't reset the mouse */
  200 #define PSM_CONFIG_FORCETAP     0x0800  /* assume `tap' action exists */
  201 #define PSM_CONFIG_IGNPORTERROR 0x1000  /* ignore error in aux port test */
  202 
  203 #define PSM_CONFIG_FLAGS        (PSM_CONFIG_RESOLUTION          \
  204                                     | PSM_CONFIG_ACCEL          \
  205                                     | PSM_CONFIG_NOCHECKSYNC    \
  206                                     | PSM_CONFIG_NOIDPROBE      \
  207                                     | PSM_CONFIG_NORESET        \
  208                                     | PSM_CONFIG_FORCETAP       \
  209                                     | PSM_CONFIG_IGNPORTERROR)
  210 
  211 /* other flags (flags) */
  212 #define PSM_FLAGS_FINGERDOWN    0x0001 /* VersaPad finger down */
  213 
  214 /* for backward compatibility */
  215 #define OLD_MOUSE_GETHWINFO     _IOR('M', 1, old_mousehw_t)
  216 #define OLD_MOUSE_GETMODE       _IOR('M', 2, old_mousemode_t)
  217 #define OLD_MOUSE_SETMODE       _IOW('M', 3, old_mousemode_t)
  218 
  219 typedef struct old_mousehw {
  220     int buttons;
  221     int iftype;
  222     int type;
  223     int hwid;
  224 } old_mousehw_t;
  225 
  226 typedef struct old_mousemode {
  227     int protocol;
  228     int rate;
  229     int resolution;
  230     int accelfactor;
  231 } old_mousemode_t;
  232 
  233 /* packet formatting function */
  234 typedef int packetfunc_t __P((struct psm_softc *, unsigned char *,
  235                               int *, int, mousestatus_t *));
  236 
  237 /* function prototypes */
  238 static int psmprobe __P((device_t));
  239 static int psmattach __P((device_t));
  240 #ifdef PSM_HOOKAPM
  241 static int psmresume __P((void *));
  242 #endif
  243 
  244 static d_open_t psmopen;
  245 static d_close_t psmclose;
  246 static d_read_t psmread;
  247 static d_ioctl_t psmioctl;
  248 static d_poll_t psmpoll;
  249 
  250 static int enable_aux_dev __P((KBDC));
  251 static int disable_aux_dev __P((KBDC));
  252 static int get_mouse_status __P((KBDC, int *, int, int));
  253 static int get_aux_id __P((KBDC));
  254 static int set_mouse_sampling_rate __P((KBDC, int));
  255 static int set_mouse_scaling __P((KBDC, int));
  256 static int set_mouse_resolution __P((KBDC, int));
  257 #ifdef PSM_RESETAFTERSUSPEND
  258 static int set_mouse_mode __P((KBDC));
  259 #endif /* PSM_RESETAFTERSUSPEND */
  260 static int get_mouse_buttons __P((KBDC));
  261 static int is_a_mouse __P((int));
  262 static void recover_from_error __P((KBDC));
  263 static int restore_controller __P((KBDC, int));
  264 #ifdef PSM_RESETAFTERSUSPEND
  265 static int reinitialize __P((int, mousemode_t *));
  266 #endif
  267 static int doopen __P((int, int));
  268 static char *model_name(int);
  269 static void psmintr(void*);
  270 
  271 /* vendor specific features */
  272 typedef int probefunc_t __P((struct psm_softc *));
  273 
  274 static int mouse_id_proc1 __P((KBDC, int, int, int *));
  275 static probefunc_t enable_groller;
  276 static probefunc_t enable_gmouse;
  277 static probefunc_t enable_aglide; 
  278 static probefunc_t enable_kmouse;
  279 static probefunc_t enable_msintelli;
  280 static probefunc_t enable_mmanplus;
  281 static probefunc_t enable_versapad;
  282 static int tame_mouse __P((struct psm_softc *, mousestatus_t *, unsigned char *));
  283 
  284 static struct {
  285     int                 model;
  286     unsigned char       syncmask;
  287     int                 packetsize;
  288     probefunc_t         *probefunc;
  289 } vendortype[] = {
  290     { MOUSE_MODEL_NET,                  /* Genius NetMouse */
  291       0xc8, MOUSE_INTELLI_PACKETSIZE, enable_gmouse, },
  292     { MOUSE_MODEL_NETSCROLL,            /* Genius NetScroll */
  293       0xc8, 6, enable_groller, },
  294     { MOUSE_MODEL_GLIDEPOINT,           /* ALPS GlidePoint */
  295       0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, },
  296     { MOUSE_MODEL_MOUSEMANPLUS,         /* Logitech MouseMan+ */
  297       0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus, },
  298     { MOUSE_MODEL_THINK,                /* Kensignton ThinkingMouse */
  299       0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse, },
  300     { MOUSE_MODEL_INTELLI,              /* Microsoft IntelliMouse */
  301       0xc8, MOUSE_INTELLI_PACKETSIZE, enable_msintelli, },
  302     { MOUSE_MODEL_VERSAPAD,             /* Interlink electronics VersaPad */
  303       0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad, },
  304     { MOUSE_MODEL_GENERIC,
  305       0xc0, MOUSE_PS2_PACKETSIZE, NULL, },
  306 };
  307 #define GENERIC_MOUSE_ENTRY     7
  308 
  309 /* device driver declarateion */
  310 static device_method_t psm_methods[] = {
  311         /* Device interface */
  312         DEVMETHOD(device_probe,         psmprobe),
  313         DEVMETHOD(device_attach,        psmattach),
  314 
  315         { 0, 0 }
  316 };
  317 
  318 static driver_t psm_driver = {
  319     "psm",
  320     psm_methods,
  321     DRIVER_TYPE_TTY,
  322     sizeof(struct psm_softc),
  323 };
  324 
  325 #define CDEV_MAJOR        21
  326 
  327 static struct  cdevsw psm_cdevsw = {
  328         psmopen,        psmclose,       psmread,        nowrite,        /* 21 */
  329         psmioctl,       nostop,         nullreset,      nodevtotty,
  330         psmpoll,        nommap,         NULL,           "psm",  NULL,   -1
  331 };
  332 
  333 /* debug message level */
  334 static int verbose = PSM_DEBUG;
  335 
  336 /* device I/O routines */
  337 static int
  338 enable_aux_dev(KBDC kbdc)
  339 {
  340     int res;
  341 
  342     res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
  343     if (verbose >= 2)
  344         log(LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res);
  345 
  346     return (res == PSM_ACK);
  347 }
  348 
  349 static int
  350 disable_aux_dev(KBDC kbdc)
  351 {
  352     int res;
  353 
  354     res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
  355     if (verbose >= 2)
  356         log(LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res);
  357 
  358     return (res == PSM_ACK);
  359 }
  360 
  361 static int
  362 get_mouse_status(KBDC kbdc, int *status, int flag, int len)
  363 {
  364     int cmd;
  365     int res;
  366     int i;
  367 
  368     switch (flag) {
  369     case 0:
  370     default:
  371         cmd = PSMC_SEND_DEV_STATUS;
  372         break;
  373     case 1:
  374         cmd = PSMC_SEND_DEV_DATA;
  375         break;
  376     }
  377     empty_aux_buffer(kbdc, 5);
  378     res = send_aux_command(kbdc, cmd);
  379     if (verbose >= 2)
  380         log(LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", 
  381             (flag == 1) ? "DATA" : "STATUS", res);
  382     if (res != PSM_ACK)
  383         return 0;
  384 
  385     for (i = 0; i < len; ++i) {
  386         status[i] = read_aux_data(kbdc);
  387         if (status[i] < 0)
  388             break;
  389     }
  390 
  391     if (verbose) {
  392         log(LOG_DEBUG, "psm: %s %02x %02x %02x\n",
  393             (flag == 1) ? "data" : "status", status[0], status[1], status[2]);
  394     }
  395 
  396     return i;
  397 }
  398 
  399 static int
  400 get_aux_id(KBDC kbdc)
  401 {
  402     int res;
  403     int id;
  404 
  405     empty_aux_buffer(kbdc, 5);
  406     res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
  407     if (verbose >= 2)
  408         log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res);
  409     if (res != PSM_ACK)
  410         return (-1);
  411 
  412     /* 10ms delay */
  413     DELAY(10000);
  414 
  415     id = read_aux_data(kbdc);
  416     if (verbose >= 2)
  417         log(LOG_DEBUG, "psm: device ID: %04x\n", id);
  418 
  419     return id;
  420 }
  421 
  422 static int
  423 set_mouse_sampling_rate(KBDC kbdc, int rate)
  424 {
  425     int res;
  426 
  427     res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
  428     if (verbose >= 2)
  429         log(LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res);
  430 
  431     return ((res == PSM_ACK) ? rate : -1);
  432 }
  433 
  434 static int
  435 set_mouse_scaling(KBDC kbdc, int scale)
  436 {
  437     int res;
  438 
  439     switch (scale) {
  440     case 1:
  441     default:
  442         scale = PSMC_SET_SCALING11;
  443         break;
  444     case 2:
  445         scale = PSMC_SET_SCALING21;
  446         break;
  447     }
  448     res = send_aux_command(kbdc, scale);
  449     if (verbose >= 2)
  450         log(LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n", 
  451             (scale == PSMC_SET_SCALING21) ? "21" : "11", res);
  452 
  453     return (res == PSM_ACK);
  454 }
  455 
  456 /* `val' must be 0 through PSMD_MAX_RESOLUTION */
  457 static int
  458 set_mouse_resolution(KBDC kbdc, int val)
  459 {
  460     int res;
  461 
  462     res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
  463     if (verbose >= 2)
  464         log(LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res);
  465 
  466     return ((res == PSM_ACK) ? val : -1);
  467 }
  468 
  469 #ifdef PSM_RESETAFTERSUSPEND
  470 /*
  471  * NOTE: once `set_mouse_mode()' is called, the mouse device must be
  472  * re-enabled by calling `enable_aux_dev()'
  473  */
  474 static int
  475 set_mouse_mode(KBDC kbdc)
  476 {
  477     int res;
  478 
  479     res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
  480     if (verbose >= 2)
  481         log(LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res);
  482 
  483     return (res == PSM_ACK);
  484 }
  485 #endif /* PSM_RESETAFTERSUSPEND */
  486 
  487 
  488 static int
  489 get_mouse_buttons(KBDC kbdc)
  490 {
  491     int c = 2;          /* assume two buttons by default */
  492     int status[3];
  493 
  494     /*
  495      * NOTE: a special sequence to obtain Logitech Mouse specific
  496      * information: set resolution to 25 ppi, set scaling to 1:1, set
  497      * scaling to 1:1, set scaling to 1:1. Then the second byte of the
  498      * mouse status bytes is the number of available buttons.
  499      * Some manufactures also support this sequence.
  500      */
  501     if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
  502         return c;
  503     if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1)
  504         && set_mouse_scaling(kbdc, 1) 
  505         && (get_mouse_status(kbdc, status, 0, 3) >= 3)) {
  506         if (status[1] != 0)
  507             return status[1];
  508     }
  509     return c;
  510 }
  511 
  512 /* misc subroutines */
  513 /*
  514  * Someday, I will get the complete list of valid pointing devices and
  515  * their IDs... XXX
  516  */
  517 static int
  518 is_a_mouse(int id)
  519 {
  520 #if 0
  521     static int valid_ids[] = {
  522         PSM_MOUSE_ID,           /* mouse */
  523         PSM_BALLPOINT_ID,       /* ballpoint device */
  524         PSM_INTELLI_ID,         /* Intellimouse */
  525         -1                      /* end of table */
  526     };
  527     int i;
  528 
  529     for (i = 0; valid_ids[i] >= 0; ++i)
  530         if (valid_ids[i] == id)
  531             return TRUE;
  532     return FALSE;
  533 #else
  534     return TRUE;
  535 #endif
  536 }
  537 
  538 static char *
  539 model_name(int model)
  540 {
  541     static struct {
  542         int model_code;
  543         char *model_name;
  544     } models[] = {
  545         { MOUSE_MODEL_NETSCROLL,        "NetScroll Mouse" },
  546         { MOUSE_MODEL_NET,              "NetMouse" },
  547         { MOUSE_MODEL_GLIDEPOINT,       "GlidePoint" },
  548         { MOUSE_MODEL_THINK,            "ThinkingMouse" },
  549         { MOUSE_MODEL_INTELLI,          "IntelliMouse" },
  550         { MOUSE_MODEL_MOUSEMANPLUS,     "MouseMan+" },
  551         { MOUSE_MODEL_VERSAPAD,         "VersaPad" },
  552         { MOUSE_MODEL_GENERIC,          "Generic PS/2 mouse" },
  553         { MOUSE_MODEL_UNKNOWN,          NULL },
  554     };
  555     int i;
  556 
  557     for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i) {
  558         if (models[i].model_code == model)
  559             return models[i].model_name;
  560     }
  561     return "Unknown";
  562 }
  563 
  564 static void
  565 recover_from_error(KBDC kbdc)
  566 {
  567     /* discard anything left in the output buffer */
  568     empty_both_buffers(kbdc, 10);
  569 
  570 #if 0
  571     /*
  572      * NOTE: KBDC_RESET_KBD may not restore the communication between the
  573      * keyboard and the controller.
  574      */
  575     reset_kbd(kbdc);
  576 #else
  577     /*
  578      * NOTE: somehow diagnostic and keyboard port test commands bring the
  579      * keyboard back.
  580      */
  581     if (!test_controller(kbdc)) 
  582         log(LOG_ERR, "psm: keyboard controller failed.\n");
  583     /* if there isn't a keyboard in the system, the following error is OK */
  584     if (test_kbd_port(kbdc) != 0) {
  585         if (verbose)
  586             log(LOG_ERR, "psm: keyboard port failed.\n");
  587     }
  588 #endif
  589 }
  590 
  591 static int
  592 restore_controller(KBDC kbdc, int command_byte)
  593 {
  594     empty_both_buffers(kbdc, 10);
  595 
  596     if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
  597         log(LOG_ERR, "psm: failed to restore the keyboard controller "
  598                      "command byte.\n");
  599         return FALSE;
  600     } else {
  601         return TRUE;
  602     }
  603 }
  604 
  605 #ifdef PSM_RESETAFTERSUSPEND
  606 /* 
  607  * Re-initialize the aux port and device. The aux port must be enabled
  608  * and its interrupt must be disabled before calling this routine. 
  609  * The aux device will be disabled before returning.
  610  * The keyboard controller must be locked via `kbdc_lock()' before
  611  * calling this routine.
  612  */
  613 static int
  614 reinitialize(int unit, mousemode_t *mode)
  615 {
  616     struct psm_softc *sc = PSM_SOFTC(unit);
  617     KBDC kbdc = sc->kbdc;
  618     int stat[3];
  619     int i;
  620 
  621     switch((i = test_aux_port(kbdc))) {
  622     case 1:     /* ignore this error */
  623     case PSM_ACK:
  624         if (verbose)
  625             log(LOG_DEBUG, "psm%d: strange result for test aux port (%d).\n",
  626                 unit, i);
  627         /* fall though */
  628     case 0:     /* no error */
  629         break;
  630     case -1:    /* time out */
  631     default:    /* error */
  632         recover_from_error(kbdc);
  633         if (sc->config & PSM_CONFIG_IGNPORTERROR)
  634             break;
  635         log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
  636             unit, i);
  637         return FALSE;
  638     }
  639 
  640     if (sc->config & PSM_CONFIG_NORESET) {
  641         /* 
  642          * Don't try to reset the pointing device.  It may possibly be
  643          * left in the unknown state, though...
  644          */
  645     } else {
  646         /* 
  647          * NOTE: some controllers appears to hang the `keyboard' when
  648          * the aux port doesn't exist and `PSMC_RESET_DEV' is issued. 
  649          */
  650         if (!reset_aux_dev(kbdc)) {
  651             recover_from_error(kbdc);
  652             log(LOG_ERR, "psm%d: failed to reset the aux device.\n", unit);
  653             return FALSE;
  654         }
  655     }
  656 
  657     /* 
  658      * both the aux port and the aux device is functioning, see
  659      * if the device can be enabled. 
  660      */
  661     if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
  662         log(LOG_ERR, "psm%d: failed to enable the aux device.\n", unit);
  663         return FALSE;
  664     }
  665     empty_both_buffers(kbdc, 10);       /* remove stray data if any */
  666 
  667     if (sc->config & PSM_CONFIG_NOIDPROBE) {
  668         i = GENERIC_MOUSE_ENTRY;
  669     } else {
  670         /* FIXME: hardware ID, mouse buttons? */
  671 
  672         /* other parameters */
  673         for (i = 0; vendortype[i].probefunc != NULL; ++i) {
  674             if ((*vendortype[i].probefunc)(sc)) {
  675                 if (verbose >= 2)
  676                     log(LOG_ERR, "psm%d: found %s\n", 
  677                         unit, model_name(vendortype[i].model));
  678                 break;
  679             }
  680         }
  681     }
  682 
  683     sc->hw.model = vendortype[i].model;
  684     sc->mode.packetsize = vendortype[i].packetsize;
  685 
  686     /* set mouse parameters */
  687     if (mode != (mousemode_t *)NULL) {
  688         if (mode->rate > 0)
  689             mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
  690         if (mode->resolution >= 0)
  691             mode->resolution = set_mouse_resolution(kbdc, mode->resolution);
  692         set_mouse_scaling(kbdc, 1);
  693         set_mouse_mode(kbdc);   
  694     }
  695 
  696     /* request a data packet and extract sync. bits */
  697     if (get_mouse_status(kbdc, stat, 1, 3) < 3) {
  698         log(LOG_DEBUG, "psm%d: failed to get data (reinitialize).\n", unit);
  699         sc->mode.syncmask[0] = 0;
  700     } else {
  701         sc->mode.syncmask[1] = stat[0] & sc->mode.syncmask[0];  /* syncbits */
  702         /* the NetScroll Mouse will send three more bytes... Ignore them */
  703         empty_aux_buffer(kbdc, 5);
  704     }
  705 
  706     /* just check the status of the mouse */
  707     if (get_mouse_status(kbdc, stat, 0, 3) < 3)
  708         log(LOG_DEBUG, "psm%d: failed to get status (reinitialize).\n", unit);
  709 
  710     return TRUE;
  711 }
  712 #endif /* PSM_RESETAFTERSUSPEND */
  713 
  714 static int
  715 doopen(int unit, int command_byte)
  716 {
  717     struct psm_softc *sc = PSM_SOFTC(unit);
  718     int stat[3];
  719 
  720     /* enable the mouse device */
  721     if (!enable_aux_dev(sc->kbdc)) {
  722         /* MOUSE ERROR: failed to enable the mouse because:
  723          * 1) the mouse is faulty,
  724          * 2) the mouse has been removed(!?)
  725          * In the latter case, the keyboard may have hung, and need 
  726          * recovery procedure...
  727          */
  728         recover_from_error(sc->kbdc);
  729 #if 0
  730         /* FIXME: we could reset the mouse here and try to enable
  731          * it again. But it will take long time and it's not a good
  732          * idea to disable the keyboard that long...
  733          */
  734         if (!reinitialize(unit, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
  735             recover_from_error(sc->kbdc);
  736 #else
  737         {
  738 #endif
  739             restore_controller(sc->kbdc, command_byte);
  740             /* mark this device is no longer available */
  741             sc->state &= ~PSM_VALID;    
  742             log(LOG_ERR, "psm%d: failed to enable the device (doopen).\n",
  743                 unit);
  744             return (EIO);
  745         }
  746     }
  747 
  748     if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) 
  749         log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n", unit);
  750 
  751     /* enable the aux port and interrupt */
  752     if (!set_controller_command_byte(sc->kbdc, 
  753             kbdc_get_device_mask(sc->kbdc),
  754             (command_byte & KBD_KBD_CONTROL_BITS)
  755                 | KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
  756         /* CONTROLLER ERROR */
  757         disable_aux_dev(sc->kbdc);
  758         restore_controller(sc->kbdc, command_byte);
  759         log(LOG_ERR, "psm%d: failed to enable the aux interrupt (doopen).\n",
  760             unit);
  761         return (EIO);
  762     }
  763 
  764     return (0);
  765 }
  766 
  767 /* psm driver entry points */
  768 
  769 #define endprobe(v)     {   if (bootverbose)                            \
  770                                 --verbose;                              \
  771                             kbdc_set_device_mask(sc->kbdc, mask);       \
  772                             kbdc_lock(sc->kbdc, FALSE);                 \
  773                             free(sc, M_DEVBUF);                         \
  774                             return (v);                                 \
  775                         }
  776 
  777 static int
  778 psmprobe(device_t dev)
  779 {
  780     int unit = device_get_unit(dev);
  781     struct psm_softc *sc = device_get_softc(dev);
  782     u_long port;
  783     u_long flags;
  784     int stat[3];
  785     int command_byte;
  786     int mask;
  787     int i;
  788 
  789 #if 0
  790     kbdc_debug(TRUE);
  791 #endif
  792     BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_PORT, &port);
  793     BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
  794 
  795     sc->addr = port;
  796     sc->kbdc = kbdc_open(sc->addr);
  797     sc->config = flags & PSM_CONFIG_FLAGS;
  798     sc->flags = 0;
  799     if (bootverbose)
  800         ++verbose;
  801 
  802     device_set_desc(dev, "PS/2 Mouse");
  803 
  804     if (!kbdc_lock(sc->kbdc, TRUE)) {
  805         printf("psm%d: unable to lock the controller.\n", unit);
  806         if (bootverbose)
  807             --verbose;
  808         return (ENXIO);
  809     }
  810 
  811     /*
  812      * NOTE: two bits in the command byte controls the operation of the
  813      * aux port (mouse port): the aux port disable bit (bit 5) and the aux
  814      * port interrupt (IRQ 12) enable bit (bit 2).
  815      */
  816 
  817     /* discard anything left after the keyboard initialization */
  818     empty_both_buffers(sc->kbdc, 10);
  819 
  820     /* save the current command byte; it will be used later */
  821     mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
  822     command_byte = get_controller_command_byte(sc->kbdc);
  823     if (verbose) 
  824         printf("psm%d: current command byte:%04x\n", unit, command_byte);
  825     if (command_byte == -1) {
  826         /* CONTROLLER ERROR */
  827         printf("psm%d: unable to get the current command byte value.\n",
  828             unit);
  829         endprobe(ENXIO);
  830     }
  831 
  832     /*
  833      * disable the keyboard port while probing the aux port, which must be
  834      * enabled during this routine
  835      */
  836     if (!set_controller_command_byte(sc->kbdc,
  837             KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
  838             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
  839                 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
  840         /* 
  841          * this is CONTROLLER ERROR; I don't know how to recover 
  842          * from this error... 
  843          */
  844         restore_controller(sc->kbdc, command_byte);
  845         printf("psm%d: unable to set the command byte.\n", unit);
  846         endprobe(ENXIO);
  847     }
  848     write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
  849 
  850     /*
  851      * NOTE: `test_aux_port()' is designed to return with zero if the aux
  852      * port exists and is functioning. However, some controllers appears
  853      * to respond with zero even when the aux port doesn't exist. (It may
  854      * be that this is only the case when the controller DOES have the aux
  855      * port but the port is not wired on the motherboard.) The keyboard
  856      * controllers without the port, such as the original AT, are
  857      * supporsed to return with an error code or simply time out. In any
  858      * case, we have to continue probing the port even when the controller
  859      * passes this test.
  860      *
  861      * XXX: some controllers erroneously return the error code 1 when
  862      * it has the perfectly functional aux port. We have to ignore this
  863      * error code. Even if the controller HAS error with the aux port,
  864      * it will be detected later...
  865      * XXX: another incompatible controller returns PSM_ACK (0xfa)...
  866      */
  867     switch ((i = test_aux_port(sc->kbdc))) {
  868     case 1:        /* ignore this error */
  869     case PSM_ACK:
  870         if (verbose)
  871             printf("psm%d: strange result for test aux port (%d).\n",
  872                 unit, i);
  873         /* fall though */
  874     case 0:        /* no error */
  875         break;
  876     case -1:        /* time out */
  877     default:        /* error */
  878         recover_from_error(sc->kbdc);
  879         if (sc->config & PSM_CONFIG_IGNPORTERROR)
  880             break;
  881         restore_controller(sc->kbdc, command_byte);
  882         if (verbose)
  883             printf("psm%d: the aux port is not functioning (%d).\n",
  884                 unit, i);
  885         endprobe(ENXIO);
  886     }
  887 
  888     if (sc->config & PSM_CONFIG_NORESET) {
  889         /* 
  890          * Don't try to reset the pointing device.  It may possibly be
  891          * left in the unknown state, though...
  892          */
  893     } else {
  894         /*
  895          * NOTE: some controllers appears to hang the `keyboard' when the aux
  896          * port doesn't exist and `PSMC_RESET_DEV' is issued.
  897          */
  898         if (!reset_aux_dev(sc->kbdc)) {
  899             recover_from_error(sc->kbdc);
  900             restore_controller(sc->kbdc, command_byte);
  901             if (verbose)
  902                 printf("psm%d: failed to reset the aux device.\n", unit);
  903             endprobe(ENXIO);
  904         }
  905     }
  906 
  907     /*
  908      * both the aux port and the aux device is functioning, see if the
  909      * device can be enabled. NOTE: when enabled, the device will start
  910      * sending data; we shall immediately disable the device once we know
  911      * the device can be enabled.
  912      */
  913     if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
  914         /* MOUSE ERROR */
  915         recover_from_error(sc->kbdc);
  916         restore_controller(sc->kbdc, command_byte);
  917         if (verbose)
  918             printf("psm%d: failed to enable the aux device.\n", unit);
  919         endprobe(ENXIO);
  920     }
  921 
  922     /* save the default values after reset */
  923     if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
  924         sc->dflt_mode.rate = sc->mode.rate = stat[2];
  925         sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
  926     } else {
  927         sc->dflt_mode.rate = sc->mode.rate = -1;
  928         sc->dflt_mode.resolution = sc->mode.resolution = -1;
  929     }
  930 
  931     /* hardware information */
  932     sc->hw.iftype = MOUSE_IF_PS2;
  933 
  934     /* verify the device is a mouse */
  935     sc->hw.hwid = get_aux_id(sc->kbdc);
  936     if (!is_a_mouse(sc->hw.hwid)) {
  937         restore_controller(sc->kbdc, command_byte);
  938         if (verbose)
  939             printf("psm%d: unknown device type (%d).\n", unit, sc->hw.hwid);
  940         endprobe(ENXIO);
  941     }
  942     switch (sc->hw.hwid) {
  943     case PSM_BALLPOINT_ID:
  944         sc->hw.type = MOUSE_TRACKBALL;
  945         break;
  946     case PSM_MOUSE_ID:
  947     case PSM_INTELLI_ID:
  948         sc->hw.type = MOUSE_MOUSE;
  949         break;
  950     default:
  951         sc->hw.type = MOUSE_UNKNOWN;
  952         break;
  953     }
  954 
  955     if (sc->config & PSM_CONFIG_NOIDPROBE) {
  956         sc->hw.buttons = 2;
  957         i = GENERIC_MOUSE_ENTRY;
  958     } else {
  959         /* # of buttons */
  960         sc->hw.buttons = get_mouse_buttons(sc->kbdc);
  961 
  962         /* other parameters */
  963         for (i = 0; vendortype[i].probefunc != NULL; ++i) {
  964             if ((*vendortype[i].probefunc)(sc)) {
  965                 if (verbose >= 2)
  966                     printf("psm%d: found %s\n",
  967                            unit, model_name(vendortype[i].model));
  968                 break;
  969             }
  970         }
  971     }
  972 
  973     sc->hw.model = vendortype[i].model;
  974 
  975     sc->dflt_mode.level = PSM_LEVEL_BASE;
  976     sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
  977     sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
  978     if (sc->config & PSM_CONFIG_NOCHECKSYNC)
  979         sc->dflt_mode.syncmask[0] = 0;
  980     else
  981         sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
  982     if (sc->config & PSM_CONFIG_FORCETAP)
  983         sc->mode.syncmask[0] &= ~MOUSE_PS2_TAP;
  984     sc->dflt_mode.syncmask[1] = 0;      /* syncbits */
  985     sc->mode = sc->dflt_mode;
  986     sc->mode.packetsize = vendortype[i].packetsize;
  987 
  988     /* set mouse parameters */
  989 #if 0
  990     /* 
  991      * A version of Logitech FirstMouse+ won't report wheel movement,
  992      * if SET_DEFAULTS is sent...  Don't use this command.
  993      * This fix was found by Takashi Nishida.
  994      */
  995     i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
  996     if (verbose >= 2)
  997         printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
  998 #endif
  999     if (sc->config & PSM_CONFIG_RESOLUTION) {
 1000         sc->mode.resolution
 1001             = set_mouse_resolution(sc->kbdc, 
 1002                                    (sc->config & PSM_CONFIG_RESOLUTION) - 1);
 1003     } else if (sc->mode.resolution >= 0) {
 1004         sc->mode.resolution
 1005             = set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
 1006     }
 1007     if (sc->mode.rate > 0) {
 1008         sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
 1009     }
 1010     set_mouse_scaling(sc->kbdc, 1);
 1011 
 1012     /* request a data packet and extract sync. bits */
 1013     if (get_mouse_status(sc->kbdc, stat, 1, 3) < 3) {
 1014         printf("psm%d: failed to get data.\n", unit);
 1015         sc->mode.syncmask[0] = 0;
 1016     } else {
 1017         sc->mode.syncmask[1] = stat[0] & sc->mode.syncmask[0];  /* syncbits */
 1018         /* the NetScroll Mouse will send three more bytes... Ignore them */
 1019         empty_aux_buffer(sc->kbdc, 5);
 1020     }
 1021 
 1022     /* just check the status of the mouse */
 1023     /* 
 1024      * NOTE: XXX there are some arcane controller/mouse combinations out 
 1025      * there, which hung the controller unless there is data transmission 
 1026      * after ACK from the mouse.
 1027      */
 1028     if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) {
 1029         printf("psm%d: failed to get status.\n", unit);
 1030     } else {
 1031         /* 
 1032          * When in its native mode, some mice operate with different 
 1033          * default parameters than in the PS/2 compatible mode.
 1034          */
 1035         sc->dflt_mode.rate = sc->mode.rate = stat[2];
 1036         sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
 1037      }
 1038 
 1039     /* disable the aux port for now... */
 1040     if (!set_controller_command_byte(sc->kbdc, 
 1041             KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
 1042             (command_byte & KBD_KBD_CONTROL_BITS)
 1043                 | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
 1044         /* 
 1045          * this is CONTROLLER ERROR; I don't know the proper way to 
 1046          * recover from this error... 
 1047          */
 1048         restore_controller(sc->kbdc, command_byte);
 1049         printf("psm%d: unable to set the command byte.\n", unit);
 1050         endprobe(ENXIO);
 1051     }
 1052 
 1053     /* done */
 1054     kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
 1055     kbdc_lock(sc->kbdc, FALSE);
 1056     return (0);
 1057 }
 1058 
 1059 static int
 1060 psmattach(device_t dev)
 1061 {
 1062     int unit = device_get_unit(dev);
 1063     struct psm_softc *sc = device_get_softc(dev);
 1064     void *ih;
 1065     struct resource *res;
 1066     u_long irq;
 1067     int zero = 0;
 1068 
 1069     if (sc == NULL)    /* shouldn't happen */
 1070         return (ENXIO);
 1071 
 1072     /* Setup initial state */
 1073     sc->state = PSM_VALID;
 1074 
 1075     /* Done */
 1076 #ifdef    DEVFS
 1077     sc->devfs_token =
 1078         devfs_add_devswf(&psm_cdevsw, PSM_MKMINOR(unit, FALSE),
 1079         DV_CHR, 0, 0, 0666, "psm%d", unit);
 1080     sc->b_devfs_token =
 1081         devfs_add_devswf(&psm_cdevsw, PSM_MKMINOR(unit, TRUE),
 1082         DV_CHR, 0, 0, 0666, "bpsm%d", unit);
 1083 #endif /* DEVFS */
 1084 
 1085 #ifdef PSM_HOOKAPM
 1086     sc->resumehook.ah_name = "PS/2 mouse";
 1087     sc->resumehook.ah_fun = psmresume;
 1088     sc->resumehook.ah_arg = (void *)unit;
 1089     sc->resumehook.ah_order = APM_MID_ORDER;
 1090     apm_hook_establish(APM_HOOK_RESUME , &sc->resumehook);
 1091     if (verbose)
 1092         printf("psm%d: APM hooks installed.\n", unit);
 1093 #endif /* PSM_HOOKAPM */
 1094 
 1095     if (!verbose) {
 1096         printf("psm%d: model %s, device ID %d\n", 
 1097             unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
 1098     } else {
 1099         printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
 1100             unit, model_name(sc->hw.model),
 1101             sc->hw.hwid & 0x00ff, sc->hw.hwid >> 8, sc->hw.buttons);
 1102         printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
 1103             unit, sc->config, sc->flags, sc->mode.packetsize);
 1104         printf("psm%d: syncmask:%02x, syncbits:%02x\n",
 1105             unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
 1106     }
 1107 
 1108     if (bootverbose)
 1109         --verbose;
 1110 
 1111     BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
 1112     res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1,
 1113                              RF_SHAREABLE | RF_ACTIVE);
 1114     BUS_SETUP_INTR(device_get_parent(dev), dev, res, psmintr, sc,
 1115                    &ih);
 1116 
 1117     return (0);
 1118 }
 1119 
 1120 static int
 1121 psmopen(dev_t dev, int flag, int fmt, struct proc *p)
 1122 {
 1123     int unit = PSM_UNIT(dev);
 1124     struct psm_softc *sc;
 1125     int command_byte;
 1126     int err;
 1127     int s;
 1128 
 1129     /* Validate unit number */
 1130     if (unit >= NPSM)
 1131         return (ENXIO);
 1132 
 1133     /* Get device data */
 1134     sc = PSM_SOFTC(unit);
 1135     if ((sc == NULL) || (sc->state & PSM_VALID) == 0)
 1136         /* the device is no longer valid/functioning */
 1137         return (ENXIO);
 1138 
 1139     /* Disallow multiple opens */
 1140     if (sc->state & PSM_OPEN)
 1141         return (EBUSY);
 1142 
 1143     device_busy(devclass_get_device(psm_devclass, unit));
 1144 
 1145     /* Initialize state */
 1146     sc->rsel.si_flags = 0;
 1147     sc->rsel.si_pid = 0;
 1148     sc->mode.level = sc->dflt_mode.level;
 1149     sc->mode.protocol = sc->dflt_mode.protocol;
 1150 
 1151     /* flush the event queue */
 1152     sc->queue.count = 0;
 1153     sc->queue.head = 0;
 1154     sc->queue.tail = 0;
 1155     sc->status.flags = 0;
 1156     sc->status.button = 0;
 1157     sc->status.obutton = 0;
 1158     sc->status.dx = 0;
 1159     sc->status.dy = 0;
 1160     sc->status.dz = 0;
 1161     sc->button = 0;
 1162 
 1163     /* empty input buffer */
 1164     bzero(sc->ipacket, sizeof(sc->ipacket));
 1165     sc->inputbytes = 0;
 1166 
 1167     /* don't let timeout routines in the keyboard driver to poll the kbdc */
 1168     if (!kbdc_lock(sc->kbdc, TRUE))
 1169         return (EIO);
 1170 
 1171     /* save the current controller command byte */
 1172     s = spltty();
 1173     command_byte = get_controller_command_byte(sc->kbdc);
 1174 
 1175     /* enable the aux port and temporalily disable the keyboard */
 1176     if ((command_byte == -1) 
 1177         || !set_controller_command_byte(sc->kbdc,
 1178             kbdc_get_device_mask(sc->kbdc),
 1179             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
 1180                 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
 1181         /* CONTROLLER ERROR; do you know how to get out of this? */
 1182         kbdc_lock(sc->kbdc, FALSE);
 1183         splx(s);
 1184         log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n",
 1185             unit);
 1186         return (EIO);
 1187     }
 1188     /* 
 1189      * Now that the keyboard controller is told not to generate 
 1190      * the keyboard and mouse interrupts, call `splx()' to allow 
 1191      * the other tty interrupts. The clock interrupt may also occur, 
 1192      * but timeout routines will be blocked by the poll flag set 
 1193      * via `kbdc_lock()'
 1194      */
 1195     splx(s);
 1196   
 1197     /* enable the mouse device */
 1198     err = doopen(unit, command_byte);
 1199 
 1200     /* done */
 1201     if (err == 0) 
 1202         sc->state |= PSM_OPEN;
 1203     kbdc_lock(sc->kbdc, FALSE);
 1204     return (err);
 1205 }
 1206 
 1207 static int
 1208 psmclose(dev_t dev, int flag, int fmt, struct proc *p)
 1209 {
 1210     int unit = PSM_UNIT(dev);
 1211     struct psm_softc *sc = PSM_SOFTC(unit);
 1212     int stat[3];
 1213     int command_byte;
 1214     int s;
 1215 
 1216     /* don't let timeout routines in the keyboard driver to poll the kbdc */
 1217     if (!kbdc_lock(sc->kbdc, TRUE))
 1218         return (EIO);
 1219 
 1220     /* save the current controller command byte */
 1221     s = spltty();
 1222     command_byte = get_controller_command_byte(sc->kbdc);
 1223     if (command_byte == -1) {
 1224         kbdc_lock(sc->kbdc, FALSE);
 1225         splx(s);
 1226         return (EIO);
 1227     }
 1228 
 1229     /* disable the aux interrupt and temporalily disable the keyboard */
 1230     if (!set_controller_command_byte(sc->kbdc, 
 1231             kbdc_get_device_mask(sc->kbdc),
 1232             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
 1233                 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
 1234         log(LOG_ERR, "psm%d: failed to disable the aux int (psmclose).\n",
 1235             PSM_UNIT(dev));
 1236         /* CONTROLLER ERROR;
 1237          * NOTE: we shall force our way through. Because the only
 1238          * ill effect we shall see is that we may not be able
 1239          * to read ACK from the mouse, and it doesn't matter much 
 1240          * so long as the mouse will accept the DISABLE command.
 1241          */
 1242     }
 1243     splx(s);
 1244 
 1245     /* remove anything left in the output buffer */
 1246     empty_aux_buffer(sc->kbdc, 10);
 1247 
 1248     /* disable the aux device, port and interrupt */
 1249     if (sc->state & PSM_VALID) {
 1250         if (!disable_aux_dev(sc->kbdc)) {
 1251             /* MOUSE ERROR; 
 1252              * NOTE: we don't return error and continue, pretending 
 1253              * we have successfully disabled the device. It's OK because 
 1254              * the interrupt routine will discard any data from the mouse
 1255              * hereafter. 
 1256              */
 1257             log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n",
 1258                 PSM_UNIT(dev));
 1259         }
 1260 
 1261         if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
 1262             log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", 
 1263                 PSM_UNIT(dev));
 1264     }
 1265 
 1266     if (!set_controller_command_byte(sc->kbdc, 
 1267             kbdc_get_device_mask(sc->kbdc),
 1268             (command_byte & KBD_KBD_CONTROL_BITS)
 1269                 | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
 1270         /* CONTROLLER ERROR; 
 1271          * we shall ignore this error; see the above comment.
 1272          */
 1273         log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n",
 1274             PSM_UNIT(dev));
 1275     }
 1276 
 1277     /* remove anything left in the output buffer */
 1278     empty_aux_buffer(sc->kbdc, 10);
 1279 
 1280     /* close is almost always successful */
 1281     sc->state &= ~PSM_OPEN;
 1282     kbdc_lock(sc->kbdc, FALSE);
 1283     device_unbusy(devclass_get_device(psm_devclass, unit));
 1284     return (0);
 1285 }
 1286 
 1287 static int
 1288 tame_mouse(struct psm_softc *sc, mousestatus_t *status, unsigned char *buf)
 1289 {
 1290     static unsigned char butmapps2[8] = {
 1291         0,
 1292         MOUSE_PS2_BUTTON1DOWN, 
 1293         MOUSE_PS2_BUTTON2DOWN,
 1294         MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
 1295         MOUSE_PS2_BUTTON3DOWN,
 1296         MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
 1297         MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
 1298         MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
 1299     };
 1300     static unsigned char butmapmsc[8] = {
 1301         MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
 1302         MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
 1303         MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
 1304         MOUSE_MSC_BUTTON3UP,
 1305         MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
 1306         MOUSE_MSC_BUTTON2UP,
 1307         MOUSE_MSC_BUTTON1UP, 
 1308         0,
 1309     };
 1310     int mapped;
 1311     int i;
 1312 
 1313     if (sc->mode.level == PSM_LEVEL_BASE) {
 1314         mapped = status->button & ~MOUSE_BUTTON4DOWN;
 1315         if (status->button & MOUSE_BUTTON4DOWN) 
 1316             mapped |= MOUSE_BUTTON1DOWN;
 1317         status->button = mapped;
 1318         buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
 1319         i = max(min(status->dx, 255), -256);
 1320         if (i < 0)
 1321             buf[0] |= MOUSE_PS2_XNEG;
 1322         buf[1] = i;
 1323         i = max(min(status->dy, 255), -256);
 1324         if (i < 0)
 1325             buf[0] |= MOUSE_PS2_YNEG;
 1326         buf[2] = i;
 1327         return MOUSE_PS2_PACKETSIZE;
 1328     } else if (sc->mode.level == PSM_LEVEL_STANDARD) {
 1329         buf[0] = MOUSE_MSC_SYNC | butmapmsc[status->button & MOUSE_STDBUTTONS];
 1330         i = max(min(status->dx, 255), -256);
 1331         buf[1] = i >> 1;
 1332         buf[3] = i - buf[1];
 1333         i = max(min(status->dy, 255), -256);
 1334         buf[2] = i >> 1;
 1335         buf[4] = i - buf[2];
 1336         i = max(min(status->dz, 127), -128);
 1337         buf[5] = (i >> 1) & 0x7f;
 1338         buf[6] = (i - (i >> 1)) & 0x7f;
 1339         buf[7] = (~status->button >> 3) & 0x7f;
 1340         return MOUSE_SYS_PACKETSIZE;
 1341     }
 1342     return sc->inputbytes;;
 1343 }
 1344 
 1345 static int
 1346 psmread(dev_t dev, struct uio *uio, int flag)
 1347 {
 1348     register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
 1349     unsigned char buf[PSM_SMALLBUFSIZE];
 1350     int error = 0;
 1351     int s;
 1352     int l;
 1353 
 1354     if ((sc->state & PSM_VALID) == 0)
 1355         return EIO;
 1356 
 1357     /* block until mouse activity occured */
 1358     s = spltty();
 1359     while (sc->queue.count <= 0) {
 1360         if (PSM_NBLOCKIO(dev)) {
 1361             splx(s);
 1362             return EWOULDBLOCK;
 1363         }
 1364         sc->state |= PSM_ASLP;
 1365         error = tsleep((caddr_t) sc, PZERO | PCATCH, "psmrea", 0);
 1366         sc->state &= ~PSM_ASLP;
 1367         if (error) {
 1368             splx(s);
 1369             return error;
 1370         } else if ((sc->state & PSM_VALID) == 0) {
 1371             /* the device disappeared! */
 1372             splx(s);
 1373             return EIO;
 1374         }
 1375     }
 1376     splx(s);
 1377 
 1378     /* copy data to the user land */
 1379     while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
 1380         s = spltty();
 1381         l = min(sc->queue.count, uio->uio_resid);
 1382         if (l > sizeof(buf))
 1383             l = sizeof(buf);
 1384         if (l > sizeof(sc->queue.buf) - sc->queue.head) {
 1385             bcopy(&sc->queue.buf[sc->queue.head], &buf[0], 
 1386                 sizeof(sc->queue.buf) - sc->queue.head);
 1387             bcopy(&sc->queue.buf[0], 
 1388                 &buf[sizeof(sc->queue.buf) - sc->queue.head],
 1389                 l - (sizeof(sc->queue.buf) - sc->queue.head));
 1390         } else {
 1391             bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
 1392         }
 1393         sc->queue.count -= l;
 1394         sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
 1395         splx(s);
 1396         error = uiomove(buf, l, uio);
 1397         if (error)
 1398             break;
 1399     }
 1400 
 1401     return error;
 1402 }
 1403 
 1404 static int
 1405 block_mouse_data(struct psm_softc *sc, int *c)
 1406 {
 1407     int s;
 1408 
 1409     if (!kbdc_lock(sc->kbdc, TRUE)) 
 1410         return EIO;
 1411 
 1412     s = spltty();
 1413     *c = get_controller_command_byte(sc->kbdc);
 1414     if ((*c == -1) 
 1415         || !set_controller_command_byte(sc->kbdc, 
 1416             kbdc_get_device_mask(sc->kbdc),
 1417             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
 1418                 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
 1419         /* this is CONTROLLER ERROR */
 1420         splx(s);
 1421         kbdc_lock(sc->kbdc, FALSE);
 1422         return EIO;
 1423     }
 1424 
 1425     /* 
 1426      * The device may be in the middle of status data transmission.
 1427      * The transmission will be interrupted, thus, incomplete status 
 1428      * data must be discarded. Although the aux interrupt is disabled 
 1429      * at the keyboard controller level, at most one aux interrupt 
 1430      * may have already been pending and a data byte is in the 
 1431      * output buffer; throw it away. Note that the second argument 
 1432      * to `empty_aux_buffer()' is zero, so that the call will just 
 1433      * flush the internal queue.
 1434      * `psmintr()' will be invoked after `splx()' if an interrupt is
 1435      * pending; it will see no data and returns immediately.
 1436      */
 1437     empty_aux_buffer(sc->kbdc, 0);      /* flush the queue */
 1438     read_aux_data_no_wait(sc->kbdc);    /* throw away data if any */
 1439     sc->inputbytes = 0;
 1440     splx(s);
 1441 
 1442     return 0;
 1443 }
 1444 
 1445 static int
 1446 unblock_mouse_data(struct psm_softc *sc, int c)
 1447 {
 1448     int error = 0;
 1449 
 1450     /* 
 1451      * We may have seen a part of status data during `set_mouse_XXX()'.
 1452      * they have been queued; flush it.
 1453      */
 1454     empty_aux_buffer(sc->kbdc, 0);
 1455 
 1456     /* restore ports and interrupt */
 1457     if (!set_controller_command_byte(sc->kbdc, 
 1458             kbdc_get_device_mask(sc->kbdc),
 1459             c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
 1460         /* CONTROLLER ERROR; this is serious, we may have
 1461          * been left with the inaccessible keyboard and
 1462          * the disabled mouse interrupt. 
 1463          */
 1464         error = EIO;
 1465     }
 1466 
 1467     kbdc_lock(sc->kbdc, FALSE);
 1468     return error;
 1469 }
 1470 
 1471 static int
 1472 psmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
 1473 {
 1474     struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
 1475     mousemode_t mode;
 1476     mousestatus_t status;
 1477 #if (defined(MOUSE_GETVARS))
 1478     mousevar_t *var;
 1479 #endif
 1480     mousedata_t *data;
 1481     int stat[3];
 1482     int command_byte;
 1483     int error = 0;
 1484     int s;
 1485 
 1486     /* Perform IOCTL command */
 1487     switch (cmd) {
 1488 
 1489     case OLD_MOUSE_GETHWINFO:
 1490         s = spltty();
 1491         ((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
 1492         ((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
 1493         ((old_mousehw_t *)addr)->type = sc->hw.type;
 1494         ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
 1495         splx(s);
 1496         break;
 1497 
 1498     case MOUSE_GETHWINFO:
 1499         s = spltty();
 1500         *(mousehw_t *)addr = sc->hw;
 1501         if (sc->mode.level == PSM_LEVEL_BASE)
 1502             ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
 1503         splx(s);
 1504         break;
 1505 
 1506     case OLD_MOUSE_GETMODE:
 1507         s = spltty();
 1508         switch (sc->mode.level) {
 1509         case PSM_LEVEL_BASE:
 1510             ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
 1511             break;
 1512         case PSM_LEVEL_STANDARD:
 1513             ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
 1514             break;
 1515         case PSM_LEVEL_NATIVE:
 1516             ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
 1517             break;
 1518         }
 1519         ((old_mousemode_t *)addr)->rate = sc->mode.rate;
 1520         ((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
 1521         ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
 1522         splx(s);
 1523         break;
 1524 
 1525     case MOUSE_GETMODE:
 1526         s = spltty();
 1527         *(mousemode_t *)addr = sc->mode;
 1528         ((mousemode_t *)addr)->resolution = 
 1529             MOUSE_RES_LOW - sc->mode.resolution;
 1530         switch (sc->mode.level) {
 1531         case PSM_LEVEL_BASE:
 1532             ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
 1533             ((mousemode_t *)addr)->packetsize = MOUSE_PS2_PACKETSIZE;
 1534             break;
 1535         case PSM_LEVEL_STANDARD:
 1536             ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
 1537             ((mousemode_t *)addr)->packetsize = MOUSE_SYS_PACKETSIZE;
 1538             ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
 1539             ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
 1540             break;
 1541         case PSM_LEVEL_NATIVE:
 1542             /* FIXME: this isn't quite correct... XXX */
 1543             ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
 1544             break;
 1545         }
 1546         splx(s);
 1547         break;
 1548 
 1549     case OLD_MOUSE_SETMODE:
 1550     case MOUSE_SETMODE:
 1551         if (cmd == OLD_MOUSE_SETMODE) {
 1552             mode.rate = ((old_mousemode_t *)addr)->rate;
 1553             /*
 1554              * resolution  old I/F   new I/F
 1555              * default        0         0
 1556              * low            1        -2
 1557              * medium low     2        -3
 1558              * medium high    3        -4
 1559              * high           4        -5
 1560              */
 1561             if (((old_mousemode_t *)addr)->resolution > 0)
 1562                 mode.resolution = -((old_mousemode_t *)addr)->resolution - 1;
 1563             mode.accelfactor = ((old_mousemode_t *)addr)->accelfactor;
 1564             mode.level = -1;
 1565         } else {
 1566             mode = *(mousemode_t *)addr;
 1567         }
 1568 
 1569         /* adjust and validate parameters. */
 1570         if (mode.rate > UCHAR_MAX)
 1571             return EINVAL;
 1572         if (mode.rate == 0)
 1573             mode.rate = sc->dflt_mode.rate;
 1574         else if (mode.rate == -1)
 1575             /* don't change the current setting */
 1576             ;
 1577         else if (mode.rate < 0)
 1578             return EINVAL;
 1579         if (mode.resolution >= UCHAR_MAX)
 1580             return EINVAL;
 1581         if (mode.resolution >= 200)
 1582             mode.resolution = MOUSE_RES_HIGH;
 1583         else if (mode.resolution >= 100)
 1584             mode.resolution = MOUSE_RES_MEDIUMHIGH;
 1585         else if (mode.resolution >= 50)
 1586             mode.resolution = MOUSE_RES_MEDIUMLOW;
 1587         else if (mode.resolution > 0)
 1588             mode.resolution = MOUSE_RES_LOW;
 1589         if (mode.resolution == MOUSE_RES_DEFAULT)
 1590             mode.resolution = sc->dflt_mode.resolution;
 1591         else if (mode.resolution == -1)
 1592             /* don't change the current setting */
 1593             ;
 1594         else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
 1595             mode.resolution = MOUSE_RES_LOW - mode.resolution;
 1596         if (mode.level == -1)
 1597             /* don't change the current setting */
 1598             mode.level = sc->mode.level;
 1599         else if ((mode.level < PSM_LEVEL_MIN) || (mode.level > PSM_LEVEL_MAX))
 1600             return EINVAL;
 1601         if (mode.accelfactor == -1)
 1602             /* don't change the current setting */
 1603             mode.accelfactor = sc->mode.accelfactor;
 1604         else if (mode.accelfactor < 0)
 1605             return EINVAL;
 1606 
 1607         /* don't allow anybody to poll the keyboard controller */
 1608         error = block_mouse_data(sc, &command_byte);
 1609         if (error)
 1610             return error;
 1611 
 1612         /* set mouse parameters */
 1613         if (mode.rate > 0)
 1614             mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
 1615         if (mode.resolution >= 0)
 1616             mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution);
 1617         set_mouse_scaling(sc->kbdc, 1);
 1618         get_mouse_status(sc->kbdc, stat, 0, 3);
 1619 
 1620         s = spltty();
 1621         sc->mode.rate = mode.rate;
 1622         sc->mode.resolution = mode.resolution;
 1623         sc->mode.accelfactor = mode.accelfactor;
 1624         sc->mode.level = mode.level;
 1625         splx(s);
 1626 
 1627         unblock_mouse_data(sc, command_byte);
 1628         break;
 1629 
 1630     case MOUSE_GETLEVEL:
 1631         *(int *)addr = sc->mode.level;
 1632         break;
 1633 
 1634     case MOUSE_SETLEVEL:
 1635         if ((*(int *)addr < PSM_LEVEL_MIN) || (*(int *)addr > PSM_LEVEL_MAX))
 1636             return EINVAL;
 1637         sc->mode.level = *(int *)addr;
 1638         break;
 1639 
 1640     case MOUSE_GETSTATUS:
 1641         s = spltty();
 1642         status = sc->status;
 1643         sc->status.flags = 0;
 1644         sc->status.obutton = sc->status.button;
 1645         sc->status.button = 0;
 1646         sc->status.dx = 0;
 1647         sc->status.dy = 0;
 1648         sc->status.dz = 0;
 1649         splx(s);
 1650         *(mousestatus_t *)addr = status;
 1651         break;
 1652 
 1653 #if (defined(MOUSE_GETVARS))
 1654     case MOUSE_GETVARS:
 1655         var = (mousevar_t *)addr;
 1656         bzero(var, sizeof(*var));
 1657         s = spltty();
 1658         var->var[0] = MOUSE_VARS_PS2_SIG;
 1659         var->var[1] = sc->config;
 1660         var->var[2] = sc->flags;
 1661         splx(s);
 1662         break;
 1663 
 1664     case MOUSE_SETVARS:
 1665         return ENODEV;
 1666 #endif /* MOUSE_GETVARS */
 1667 
 1668     case MOUSE_READSTATE:
 1669     case MOUSE_READDATA:
 1670         data = (mousedata_t *)addr;
 1671         if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
 1672             return EINVAL;
 1673 
 1674         error = block_mouse_data(sc, &command_byte);
 1675         if (error)
 1676             return error;
 1677         if ((data->len = get_mouse_status(sc->kbdc, data->buf, 
 1678                 (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
 1679             error = EIO;
 1680         unblock_mouse_data(sc, command_byte);
 1681         break;
 1682 
 1683 #if (defined(MOUSE_SETRESOLUTION))
 1684     case MOUSE_SETRESOLUTION:
 1685         mode.resolution = *(int *)addr;
 1686         if (mode.resolution >= UCHAR_MAX)
 1687             return EINVAL;
 1688         else if (mode.resolution >= 200)
 1689             mode.resolution = MOUSE_RES_HIGH;
 1690         else if (mode.resolution >= 100)
 1691             mode.resolution = MOUSE_RES_MEDIUMHIGH;
 1692         else if (mode.resolution >= 50)
 1693             mode.resolution = MOUSE_RES_MEDIUMLOW;
 1694         else if (mode.resolution > 0)
 1695             mode.resolution = MOUSE_RES_LOW;
 1696         if (mode.resolution == MOUSE_RES_DEFAULT)
 1697             mode.resolution = sc->dflt_mode.resolution;
 1698         else if (mode.resolution == -1)
 1699             mode.resolution = sc->mode.resolution;
 1700         else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
 1701             mode.resolution = MOUSE_RES_LOW - mode.resolution;
 1702 
 1703         error = block_mouse_data(sc, &command_byte);
 1704         if (error)
 1705             return error;
 1706         sc->mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution);
 1707         if (sc->mode.resolution != mode.resolution)
 1708             error = EIO;
 1709         unblock_mouse_data(sc, command_byte);
 1710         break;
 1711 #endif /* MOUSE_SETRESOLUTION */
 1712 
 1713 #if (defined(MOUSE_SETRATE))
 1714     case MOUSE_SETRATE:
 1715         mode.rate = *(int *)addr;
 1716         if (mode.rate > UCHAR_MAX)
 1717             return EINVAL;
 1718         if (mode.rate == 0)
 1719             mode.rate = sc->dflt_mode.rate;
 1720         else if (mode.rate < 0)
 1721             mode.rate = sc->mode.rate;
 1722 
 1723         error = block_mouse_data(sc, &command_byte);
 1724         if (error)
 1725             return error;
 1726         sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
 1727         if (sc->mode.rate != mode.rate)
 1728             error = EIO;
 1729         unblock_mouse_data(sc, command_byte);
 1730         break;
 1731 #endif /* MOUSE_SETRATE */
 1732 
 1733 #if (defined(MOUSE_SETSCALING))
 1734     case MOUSE_SETSCALING:
 1735         if ((*(int *)addr <= 0) || (*(int *)addr > 2))
 1736             return EINVAL;
 1737 
 1738         error = block_mouse_data(sc, &command_byte);
 1739         if (error)
 1740             return error;
 1741         if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
 1742             error = EIO;
 1743         unblock_mouse_data(sc, command_byte);
 1744         break;
 1745 #endif /* MOUSE_SETSCALING */
 1746 
 1747 #if (defined(MOUSE_GETHWID))
 1748     case MOUSE_GETHWID:
 1749         error = block_mouse_data(sc, &command_byte);
 1750         if (error)
 1751             return error;
 1752         sc->hw.hwid &= ~0x00ff;
 1753         sc->hw.hwid |= get_aux_id(sc->kbdc);
 1754         *(int *)addr = sc->hw.hwid & 0x00ff;
 1755         unblock_mouse_data(sc, command_byte);
 1756         break;
 1757 #endif /* MOUSE_GETHWID */
 1758 
 1759     default:
 1760         return ENOTTY;
 1761     }
 1762 
 1763     return error;
 1764 }
 1765 
 1766 static void
 1767 psmintr(void *arg)
 1768 {
 1769     /*
 1770      * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
 1771      * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
 1772      */
 1773     static int butmap[8] = {
 1774         0, 
 1775         MOUSE_BUTTON1DOWN, 
 1776         MOUSE_BUTTON3DOWN, 
 1777         MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 
 1778         MOUSE_BUTTON2DOWN, 
 1779         MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 
 1780         MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
 1781         MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
 1782     };
 1783     static int butmap_versapad[8] = {
 1784         0, 
 1785         MOUSE_BUTTON3DOWN, 
 1786         0, 
 1787         MOUSE_BUTTON3DOWN, 
 1788         MOUSE_BUTTON1DOWN, 
 1789         MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 
 1790         MOUSE_BUTTON1DOWN,
 1791         MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
 1792     };
 1793     register struct psm_softc *sc = arg;
 1794     mousestatus_t ms;
 1795     int x, y, z;
 1796     int c;
 1797     int l;
 1798     int x0, y0;
 1799 
 1800     /* read until there is nothing to read */
 1801     while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
 1802     
 1803         /* discard the byte if the device is not open */
 1804         if ((sc->state & PSM_OPEN) == 0)
 1805             continue;
 1806     
 1807         /* 
 1808          * Check sync bits. We check for overflow bits and the bit 3
 1809          * for most mice. True, the code doesn't work if overflow 
 1810          * condition occurs. But we expect it rarely happens...
 1811          */
 1812         if ((sc->inputbytes == 0) 
 1813                 && ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1])) {
 1814             log(LOG_DEBUG, "psmintr: out of sync (%04x != %04x).\n", 
 1815                 c & sc->mode.syncmask[0], sc->mode.syncmask[1]);
 1816             continue;
 1817         }
 1818 
 1819         sc->ipacket[sc->inputbytes++] = c;
 1820         if (sc->inputbytes < sc->mode.packetsize) 
 1821             continue;
 1822 
 1823 #if 0
 1824         log(LOG_DEBUG, "psmintr: %02x %02x %02x %02x %02x %02x\n",
 1825             sc->ipacket[0], sc->ipacket[1], sc->ipacket[2],
 1826             sc->ipacket[3], sc->ipacket[4], sc->ipacket[5]);
 1827 #endif
 1828 
 1829         c = sc->ipacket[0];
 1830 
 1831         /* 
 1832          * A kludge for Kensington device! 
 1833          * The MSB of the horizontal count appears to be stored in 
 1834          * a strange place. This kludge doesn't affect other mice 
 1835          * because the bit is the overflow bit which is, in most cases, 
 1836          * expected to be zero when we reach here. XXX 
 1837          */
 1838         if (sc->hw.model != MOUSE_MODEL_VERSAPAD)
 1839             sc->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
 1840 
 1841         /* ignore the overflow bits... */
 1842         x = (c & MOUSE_PS2_XNEG) ?  sc->ipacket[1] - 256 : sc->ipacket[1];
 1843         y = (c & MOUSE_PS2_YNEG) ?  sc->ipacket[2] - 256 : sc->ipacket[2];
 1844         z = 0;
 1845         ms.obutton = sc->button;                  /* previous button state */
 1846         ms.button = butmap[c & MOUSE_PS2_BUTTONS];
 1847         /* `tapping' action */
 1848         if (sc->config & PSM_CONFIG_FORCETAP)
 1849             ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
 1850 
 1851         switch (sc->hw.model) {
 1852 
 1853         case MOUSE_MODEL_INTELLI:
 1854         case MOUSE_MODEL_NET:
 1855             /* wheel data is in the fourth byte */
 1856             z = (char)sc->ipacket[3];
 1857             break;
 1858 
 1859         case MOUSE_MODEL_MOUSEMANPLUS:
 1860             /*
 1861              * PS2++ protocl packet
 1862              *
 1863              *          b7 b6 b5 b4 b3 b2 b1 b0
 1864              * byte 1:  *  1  p3 p2 1  *  *  *
 1865              * byte 2:  c1 c2 p1 p0 d1 d0 1  0
 1866              *
 1867              * p3-p0: packet type
 1868              * c1, c2: c1 & c2 == 1, if p2 == 0
 1869              *         c1 & c2 == 0, if p2 == 1
 1870              *
 1871              * packet type: 0 (device type)
 1872              * See comments in enable_mmanplus() below.
 1873              * 
 1874              * packet type: 1 (wheel data)
 1875              *
 1876              *          b7 b6 b5 b4 b3 b2 b1 b0
 1877              * byte 3:  h  *  B5 B4 s  d2 d1 d0
 1878              *
 1879              * h: 1, if horizontal roller data
 1880              *    0, if vertical roller data
 1881              * B4, B5: button 4 and 5
 1882              * s: sign bit
 1883              * d2-d0: roller data
 1884              *
 1885              * packet type: 2 (reserved)
 1886              */
 1887             if (((c & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
 1888                     && (abs(x) > 191)
 1889                     && MOUSE_PS2PLUS_CHECKBITS(sc->ipacket)) {
 1890                 /* the extended data packet encodes button and wheel events */
 1891                 switch (MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket)) {
 1892                 case 1:
 1893                     /* wheel data packet */
 1894                     x = y = 0;
 1895                     if (sc->ipacket[2] & 0x80) {
 1896                         /* horizontal roller count - ignore it XXX*/
 1897                     } else {
 1898                         /* vertical roller count */
 1899                         z = (sc->ipacket[2] & MOUSE_PS2PLUS_ZNEG)
 1900                             ? (sc->ipacket[2] & 0x0f) - 16
 1901                             : (sc->ipacket[2] & 0x0f);
 1902                     }
 1903                     ms.button |= (sc->ipacket[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
 1904                         ? MOUSE_BUTTON4DOWN : 0;
 1905                     ms.button |= (sc->ipacket[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
 1906                         ? MOUSE_BUTTON5DOWN : 0;
 1907                     break;
 1908                 case 2:
 1909                     /* this packet type is reserved, and currently ignored */
 1910                     /* FALL THROUGH */
 1911                 case 0:
 1912                     /* device type packet - shouldn't happen */
 1913                     /* FALL THROUGH */
 1914                 default:
 1915                     x = y = 0;
 1916                     ms.button = ms.obutton;
 1917                     log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: "
 1918                                    "0x%02x 0x%02x 0x%02x\n",
 1919                         MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket),
 1920                         sc->ipacket[0], sc->ipacket[1], sc->ipacket[2]);
 1921                     break;
 1922                 }
 1923             } else {
 1924                 /* preserve button states */
 1925                 ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
 1926             }
 1927             break;
 1928 
 1929         case MOUSE_MODEL_GLIDEPOINT:
 1930             /* `tapping' action */
 1931             ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
 1932             break;
 1933 
 1934         case MOUSE_MODEL_NETSCROLL:
 1935             /* three addtional bytes encode button and wheel events */
 1936             ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) 
 1937                 ? MOUSE_BUTTON4DOWN : 0;
 1938             z = (sc->ipacket[3] & MOUSE_PS2_XNEG) 
 1939                 ? sc->ipacket[4] - 256 : sc->ipacket[4];
 1940             break;
 1941 
 1942         case MOUSE_MODEL_THINK:
 1943             /* the fourth button state in the first byte */
 1944             ms.button |= (c & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
 1945             break;
 1946 
 1947         case MOUSE_MODEL_VERSAPAD:
 1948             /* VersaPad PS/2 absolute mode message format
 1949              *
 1950              * [packet1]     7   6   5   4   3   2   1   0(LSB)
 1951              *  ipacket[0]:  1   1   0   A   1   L   T   R
 1952              *  ipacket[1]: H7  H6  H5  H4  H3  H2  H1  H0
 1953              *  ipacket[2]: V7  V6  V5  V4  V3  V2  V1  V0
 1954              *  ipacket[3]:  1   1   1   A   1   L   T   R
 1955              *  ipacket[4]:V11 V10  V9  V8 H11 H10  H9  H8
 1956              *  ipacket[5]:  0  P6  P5  P4  P3  P2  P1  P0
 1957              *
 1958              * [note]
 1959              *  R: right physical mouse button (1=on)
 1960              *  T: touch pad virtual button (1=tapping)
 1961              *  L: left physical mouse button (1=on)
 1962              *  A: position data is valid (1=valid)
 1963              *  H: horizontal data (12bit signed integer. H11 is sign bit.)
 1964              *  V: vertical data (12bit signed integer. V11 is sign bit.)
 1965              *  P: pressure data
 1966              *
 1967              * Tapping is mapped to MOUSE_BUTTON4.
 1968              */
 1969             ms.button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
 1970             ms.button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
 1971             x = y = 0;
 1972             if (c & MOUSE_PS2VERSA_IN_USE) {
 1973                 x0 = sc->ipacket[1] | (((sc->ipacket[4]) & 0x0f) << 8);
 1974                 y0 = sc->ipacket[2] | (((sc->ipacket[4]) & 0xf0) << 4);
 1975                 if (x0 & 0x800)
 1976                     x0 -= 0x1000;
 1977                 if (y0 & 0x800)
 1978                     y0 -= 0x1000;
 1979                 if (sc->flags & PSM_FLAGS_FINGERDOWN) {
 1980                     x = sc->xold - x0;
 1981                     y = y0 - sc->yold;
 1982                     if (x < 0)  /* XXX */
 1983                         x++;
 1984                     else if (x)
 1985                         x--;
 1986                     if (y < 0)
 1987                         y++;
 1988                     else if (y)
 1989                         y--;
 1990                 } else {
 1991                     sc->flags |= PSM_FLAGS_FINGERDOWN;
 1992                 }
 1993                 sc->xold = x0;
 1994                 sc->yold = y0;
 1995             } else {
 1996                 sc->flags &= ~PSM_FLAGS_FINGERDOWN;
 1997             }
 1998             c = ((x < 0) ? MOUSE_PS2_XNEG : 0)
 1999                 | ((y < 0) ? MOUSE_PS2_YNEG : 0);
 2000             break;
 2001 
 2002         case MOUSE_MODEL_GENERIC:
 2003         default:
 2004             break;
 2005         }
 2006 
 2007         /* scale values */
 2008         if (sc->mode.accelfactor >= 1) {
 2009             if (x != 0) {
 2010                 x = x * x / sc->mode.accelfactor;
 2011                 if (x == 0)
 2012                     x = 1;
 2013                 if (c & MOUSE_PS2_XNEG)
 2014                     x = -x;
 2015             }
 2016             if (y != 0) {
 2017                 y = y * y / sc->mode.accelfactor;
 2018                 if (y == 0)
 2019                     y = 1;
 2020                 if (c & MOUSE_PS2_YNEG)
 2021                     y = -y;
 2022             }
 2023         }
 2024 
 2025         ms.dx = x;
 2026         ms.dy = y;
 2027         ms.dz = z;
 2028         ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) 
 2029             | (ms.obutton ^ ms.button);
 2030 
 2031         if (sc->mode.level < PSM_LEVEL_NATIVE)
 2032             sc->inputbytes = tame_mouse(sc, &ms, sc->ipacket);
 2033 
 2034         sc->status.flags |= ms.flags;
 2035         sc->status.dx += ms.dx;
 2036         sc->status.dy += ms.dy;
 2037         sc->status.dz += ms.dz;
 2038         sc->status.button = ms.button;
 2039         sc->button = ms.button;
 2040 
 2041         /* queue data */
 2042         if (sc->queue.count + sc->inputbytes < sizeof(sc->queue.buf)) {
 2043             l = min(sc->inputbytes, sizeof(sc->queue.buf) - sc->queue.tail);
 2044             bcopy(&sc->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
 2045             if (sc->inputbytes > l)
 2046                 bcopy(&sc->ipacket[l], &sc->queue.buf[0], sc->inputbytes - l);
 2047             sc->queue.tail = 
 2048                 (sc->queue.tail + sc->inputbytes) % sizeof(sc->queue.buf);
 2049             sc->queue.count += sc->inputbytes;
 2050         }
 2051         sc->inputbytes = 0;
 2052 
 2053         if (sc->state & PSM_ASLP) {
 2054             sc->state &= ~PSM_ASLP;
 2055             wakeup((caddr_t) sc);
 2056         }
 2057         selwakeup(&sc->rsel);
 2058     }
 2059 }
 2060 
 2061 static int
 2062 psmpoll(dev_t dev, int events, struct proc *p)
 2063 {
 2064     struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
 2065     int s;
 2066     int revents = 0;
 2067 
 2068     /* Return true if a mouse event available */
 2069     s = spltty();
 2070     if (events & (POLLIN | POLLRDNORM)) {
 2071         if (sc->queue.count > 0)
 2072             revents |= events & (POLLIN | POLLRDNORM);
 2073         else
 2074             selrecord(p, &sc->rsel);
 2075     }
 2076     splx(s);
 2077 
 2078     return (revents);
 2079 }
 2080 
 2081 /* vendor/model specific routines */
 2082 
 2083 static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
 2084 {
 2085     if (set_mouse_resolution(kbdc, res) != res)
 2086         return FALSE;
 2087     if (set_mouse_scaling(kbdc, scale)
 2088         && set_mouse_scaling(kbdc, scale)
 2089         && set_mouse_scaling(kbdc, scale) 
 2090         && (get_mouse_status(kbdc, status, 0, 3) >= 3)) 
 2091         return TRUE;
 2092     return FALSE;
 2093 }
 2094 
 2095 #if notyet
 2096 /* Logitech MouseMan Cordless II */
 2097 static int
 2098 enable_lcordless(struct psm_softc *sc)
 2099 {
 2100     int status[3];
 2101     int ch;
 2102 
 2103     if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 2, status))
 2104         return FALSE;
 2105     if (status[1] == PSMD_RES_HIGH)
 2106         return FALSE;
 2107     ch = (status[0] & 0x07) - 1;        /* channel # */
 2108     if ((ch <= 0) || (ch > 4))
 2109         return FALSE;
 2110     /* 
 2111      * status[1]: always one?
 2112      * status[2]: battery status? (0-100)
 2113      */
 2114     return TRUE;
 2115 }
 2116 #endif /* notyet */
 2117 
 2118 /* Genius NetScroll Mouse */
 2119 static int
 2120 enable_groller(struct psm_softc *sc)
 2121 {
 2122     int status[3];
 2123 
 2124     /*
 2125      * The special sequence to enable the fourth button and the
 2126      * roller. Immediately after this sequence check status bytes.
 2127      * if the mouse is NetScroll, the second and the third bytes are 
 2128      * '3' and 'D'.
 2129      */
 2130 
 2131     /*
 2132      * If the mouse is an ordinary PS/2 mouse, the status bytes should
 2133      * look like the following.
 2134      * 
 2135      * byte 1 bit 7 always 0
 2136      *        bit 6 stream mode (0)
 2137      *        bit 5 disabled (0)
 2138      *        bit 4 1:1 scaling (0)
 2139      *        bit 3 always 0
 2140      *        bit 0-2 button status
 2141      * byte 2 resolution (PSMD_RES_HIGH)
 2142      * byte 3 report rate (?)
 2143      */
 2144 
 2145     if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
 2146         return FALSE;
 2147     if ((status[1] != '3') || (status[2] != 'D'))
 2148         return FALSE;
 2149     /* FIXME!! */
 2150     sc->hw.buttons = get_mouse_buttons(sc->kbdc);
 2151     sc->hw.buttons = 4;
 2152     return TRUE;
 2153 }
 2154 
 2155 /* Genius NetMouse/NetMouse Pro */
 2156 static int
 2157 enable_gmouse(struct psm_softc *sc)
 2158 {
 2159     int status[3];
 2160 
 2161     /*
 2162      * The special sequence to enable the middle, "rubber" button. 
 2163      * Immediately after this sequence check status bytes.
 2164      * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse, 
 2165      * the second and the third bytes are '3' and 'U'.
 2166      * NOTE: NetMouse reports that it has three buttons although it has
 2167      * two buttons and a rubber button. NetMouse Pro and MIE Mouse
 2168      * say they have three buttons too and they do have a button on the
 2169      * side...
 2170      */
 2171     if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
 2172         return FALSE;
 2173     if ((status[1] != '3') || (status[2] != 'U'))
 2174         return FALSE;
 2175     return TRUE;
 2176 }
 2177 
 2178 /* ALPS GlidePoint */
 2179 static int
 2180 enable_aglide(struct psm_softc *sc)
 2181 {
 2182     int status[3];
 2183 
 2184     /*
 2185      * The special sequence to obtain ALPS GlidePoint specific
 2186      * information. Immediately after this sequence, status bytes will 
 2187      * contain something interesting.
 2188      * NOTE: ALPS produces several models of GlidePoint. Some of those
 2189      * do not respond to this sequence, thus, cannot be detected this way.
 2190      */
 2191     if (set_mouse_sampling_rate(sc->kbdc, 100) != 100)
 2192         return FALSE;
 2193     if (!mouse_id_proc1(sc->kbdc, PSMD_RES_LOW, 2, status))
 2194         return FALSE;
 2195     if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
 2196         return FALSE;
 2197     return TRUE;
 2198 }
 2199 
 2200 /* Kensington ThinkingMouse/Trackball */
 2201 static int
 2202 enable_kmouse(struct psm_softc *sc)
 2203 {
 2204     static unsigned char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
 2205     KBDC kbdc = sc->kbdc;
 2206     int status[3];
 2207     int id1;
 2208     int id2;
 2209     int i;
 2210 
 2211     id1 = get_aux_id(kbdc);
 2212     if (set_mouse_sampling_rate(kbdc, 10) != 10)
 2213         return FALSE;
 2214     /* 
 2215      * The device is now in the native mode? It returns a different
 2216      * ID value...
 2217      */
 2218     id2 = get_aux_id(kbdc);
 2219     if ((id1 == id2) || (id2 != 2))
 2220         return FALSE;
 2221 
 2222     if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
 2223         return FALSE;
 2224 #if PSM_DEBUG >= 2
 2225     /* at this point, resolution is LOW, sampling rate is 10/sec */
 2226     if (get_mouse_status(kbdc, status, 0, 3) < 3)
 2227         return FALSE;
 2228 #endif
 2229 
 2230     /*
 2231      * The special sequence to enable the third and fourth buttons.
 2232      * Otherwise they behave like the first and second buttons.
 2233      */
 2234     for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
 2235         if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
 2236             return FALSE;
 2237     }
 2238 
 2239     /* 
 2240      * At this point, the device is using default resolution and
 2241      * sampling rate for the native mode. 
 2242      */
 2243     if (get_mouse_status(kbdc, status, 0, 3) < 3)
 2244         return FALSE;
 2245     if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
 2246         return FALSE;
 2247 
 2248     /* the device appears be enabled by this sequence, diable it for now */
 2249     disable_aux_dev(kbdc);
 2250     empty_aux_buffer(kbdc, 5);
 2251 
 2252     return TRUE;
 2253 }
 2254 
 2255 /* Logitech MouseMan+/FirstMouse+ */
 2256 static int
 2257 enable_mmanplus(struct psm_softc *sc)
 2258 {
 2259     static char res[] = {
 2260         -1, PSMD_RES_LOW, PSMD_RES_HIGH, PSMD_RES_MEDIUM_HIGH,
 2261         PSMD_RES_MEDIUM_LOW, -1, PSMD_RES_HIGH, PSMD_RES_MEDIUM_LOW,
 2262         PSMD_RES_MEDIUM_HIGH, PSMD_RES_HIGH, 
 2263     };
 2264     KBDC kbdc = sc->kbdc;
 2265     int data[3];
 2266     int i;
 2267 
 2268     /* the special sequence to enable the fourth button and the roller. */
 2269     for (i = 0; i < sizeof(res)/sizeof(res[0]); ++i) {
 2270         if (res[i] < 0) {
 2271             if (!set_mouse_scaling(kbdc, 1))
 2272                 return FALSE;
 2273         } else {
 2274             if (set_mouse_resolution(kbdc, res[i]) != res[i])
 2275                 return FALSE;
 2276         }
 2277     }
 2278 
 2279     if (get_mouse_status(kbdc, data, 1, 3) < 3)
 2280         return FALSE;
 2281 
 2282     /*
 2283      * PS2++ protocl, packet type 0
 2284      *
 2285      *          b7 b6 b5 b4 b3 b2 b1 b0
 2286      * byte 1:  *  1  p3 p2 1  *  *  *
 2287      * byte 2:  1  1  p1 p0 m1 m0 1  0
 2288      * byte 3:  m7 m6 m5 m4 m3 m2 m1 m0
 2289      *
 2290      * p3-p0: packet type: 0
 2291      * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51,...
 2292      */
 2293     /* check constant bits */
 2294     if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
 2295         return FALSE;
 2296     if ((data[1] & 0xc3) != 0xc2)
 2297         return FALSE;
 2298     /* check d3-d0 in byte 2 */
 2299     if (!MOUSE_PS2PLUS_CHECKBITS(data))
 2300         return FALSE;
 2301     /* check p3-p0 */
 2302     if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
 2303         return FALSE;
 2304 
 2305     sc->hw.hwid &= 0x00ff;
 2306     sc->hw.hwid |= data[2] << 8;        /* save model ID */
 2307 
 2308     /*
 2309      * MouseMan+ (or FirstMouse+) is now in its native mode, in which
 2310      * the wheel and the fourth button events are encoded in the
 2311      * special data packet. The mouse may be put in the IntelliMouse mode
 2312      * if it is initialized by the IntelliMouse's method.
 2313      */
 2314     return TRUE;
 2315 }
 2316 
 2317 /* MS IntelliMouse */
 2318 static int
 2319 enable_msintelli(struct psm_softc *sc)
 2320 {
 2321     /*
 2322      * Logitech MouseMan+ and FirstMouse+ will also respond to this
 2323      * probe routine and act like IntelliMouse.
 2324      */
 2325 
 2326     static unsigned char rate[] = { 200, 100, 80, };
 2327     KBDC kbdc = sc->kbdc;
 2328     int id;
 2329     int i;
 2330 
 2331     /* the special sequence to enable the third button and the roller. */
 2332     for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
 2333         if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
 2334             return FALSE;
 2335     }
 2336     /* the device will give the genuine ID only after the above sequence */
 2337     id = get_aux_id(kbdc);
 2338     if (id != PSM_INTELLI_ID)
 2339         return FALSE;
 2340 
 2341     sc->hw.hwid = id;
 2342     sc->hw.buttons = 3;
 2343 
 2344     return TRUE;
 2345 }
 2346 
 2347 /* Interlink electronics VersaPad */
 2348 static int
 2349 enable_versapad(struct psm_softc *sc)
 2350 {
 2351     KBDC kbdc = sc->kbdc;
 2352     int data[3];
 2353 
 2354     set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
 2355     set_mouse_sampling_rate(kbdc, 100);         /* set rate 100 */
 2356     set_mouse_scaling(kbdc, 1);                 /* set scale 1:1 */
 2357     set_mouse_scaling(kbdc, 1);                 /* set scale 1:1 */
 2358     set_mouse_scaling(kbdc, 1);                 /* set scale 1:1 */
 2359     set_mouse_scaling(kbdc, 1);                 /* set scale 1:1 */
 2360     if (get_mouse_status(kbdc, data, 0, 3) < 3) /* get status */
 2361         return FALSE;
 2362     if (data[2] != 0xa || data[1] != 0 )        /* rate == 0xa && res. == 0 */
 2363         return FALSE;
 2364     set_mouse_scaling(kbdc, 1);                 /* set scale 1:1 */
 2365 
 2366     return TRUE;                                /* PS/2 absolute mode */
 2367 }
 2368 
 2369 #ifdef PSM_HOOKAPM
 2370 static int
 2371 psmresume(void *dummy)
 2372 {
 2373     struct psm_softc *sc = psm_softc[(int)dummy];
 2374     int unit = (int)dummy;
 2375     int err = 0;
 2376     int s;
 2377     int c;
 2378 
 2379     if (verbose >= 2)
 2380         log(LOG_NOTICE, "psm%d: APM resume hook called.\n", unit);
 2381 
 2382     /* don't let anybody mess with the aux device */
 2383     if (!kbdc_lock(sc->kbdc, TRUE))
 2384         return (EIO);
 2385     s = spltty();
 2386 
 2387     /* save the current controller command byte */
 2388     empty_both_buffers(sc->kbdc, 10);
 2389     c = get_controller_command_byte(sc->kbdc);
 2390     if (verbose >= 2)
 2391         log(LOG_DEBUG, "psm%d: current command byte: %04x (psmresume).\n", 
 2392             unit, c);
 2393 
 2394     /* enable the aux port but disable the aux interrupt and the keyboard */
 2395     if ((c == -1) || !set_controller_command_byte(sc->kbdc,
 2396             kbdc_get_device_mask(sc->kbdc),
 2397             KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
 2398                 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
 2399         /* CONTROLLER ERROR */
 2400         splx(s);
 2401         kbdc_lock(sc->kbdc, FALSE);
 2402         log(LOG_ERR, "psm%d: unable to set the command byte (psmresume).\n",
 2403             unit);
 2404         return (EIO);
 2405     }
 2406 
 2407     /* flush any data */
 2408     if (sc->state & PSM_VALID) {
 2409         disable_aux_dev(sc->kbdc);      /* this may fail; but never mind... */
 2410         empty_aux_buffer(sc->kbdc, 10);
 2411     }
 2412     sc->inputbytes = 0;
 2413 
 2414 #ifdef PSM_RESETAFTERSUSPEND
 2415     /* try to detect the aux device; are you still there? */
 2416     if (reinitialize(unit, &sc->mode)) {
 2417         /* yes */
 2418         sc->state |= PSM_VALID;
 2419     } else {
 2420         /* the device has gone! */
 2421         restore_controller(sc->kbdc, c);
 2422         sc->state &= ~PSM_VALID;
 2423         log(LOG_ERR, "psm%d: the aux device has gone! (psmresume).\n",
 2424             unit);
 2425         err = ENXIO;
 2426     }
 2427 #endif /* PSM_RESETAFTERSUSPEND */
 2428     splx(s);
 2429 
 2430     /* restore the driver state */
 2431     if ((sc->state & PSM_OPEN) && (err == 0)) {
 2432         /* enable the aux device and the port again */
 2433         err = doopen(unit, c);
 2434         if (err != 0) 
 2435             log(LOG_ERR, "psm%d: failed to enable the device (psmresume).\n",
 2436                 unit);
 2437     } else {
 2438         /* restore the keyboard port and disable the aux port */
 2439         if (!set_controller_command_byte(sc->kbdc, 
 2440                 kbdc_get_device_mask(sc->kbdc),
 2441                 (c & KBD_KBD_CONTROL_BITS)
 2442                     | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
 2443             /* CONTROLLER ERROR */
 2444             log(LOG_ERR, "psm%d: failed to disable the aux port (psmresume).\n",
 2445                 unit);
 2446             err = EIO;
 2447         }
 2448     }
 2449 
 2450     /* done */
 2451     kbdc_lock(sc->kbdc, FALSE);
 2452     if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
 2453         /* 
 2454          * Release the blocked process; it must be notified that the device
 2455          * cannot be accessed anymore.
 2456          */
 2457         sc->state &= ~PSM_ASLP;
 2458         wakeup((caddr_t)sc);
 2459     }
 2460 
 2461     if (verbose >= 2)
 2462         log(LOG_DEBUG, "psm%d: APM resume hook exiting.\n", unit);
 2463 
 2464     return (err);
 2465 }
 2466 #endif /* PSM_HOOKAPM */
 2467 
 2468 CDEV_DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass,
 2469                    CDEV_MAJOR, psm_cdevsw, 0, 0);
 2470 
 2471 #endif /* NPSM > 0 */

Cache object: 23bc87e73f8a8eed9f5fc72a04d6d471


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.