1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*      Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
  22 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T       */
  23 /*        All Rights Reserved   */
  24 
  25 /*
  26  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 
  31 /*
  32  * PS/2 type Mouse Module - Streams
  33  */
  34 
  35 #include <sys/param.h>
  36 #include <sys/types.h>
  37 #include <sys/kmem.h>
  38 #include <sys/signal.h>
  39 #include <sys/errno.h>
  40 #include <sys/file.h>
  41 #include <sys/termio.h>
  42 #include <sys/stream.h>
  43 #include <sys/stropts.h>
  44 #include <sys/strtty.h>
  45 #include <sys/strsun.h>
  46 #include <sys/debug.h>
  47 #include <sys/ddi.h>
  48 #include <sys/stat.h>
  49 #include <sys/cmn_err.h>
  50 #include <sys/sunddi.h>
  51 
  52 #include <sys/promif.h>
  53 #include <sys/cred.h>
  54 
  55 #include <sys/i8042.h>
  56 #include <sys/note.h>
  57 #include <sys/mouse.h>
  58 
  59 #define DRIVER_NAME(dip)        ddi_driver_name(dip)
  60 
  61 #define MOUSE8042_INTERNAL_OPEN(minor)  (((minor) & 0x1) == 1)
  62 #define MOUSE8042_MINOR_TO_INSTANCE(minor)      ((minor) / 2)
  63 #define MOUSE8042_INTERNAL_MINOR(minor)         ((minor) + 1)
  64 
  65 #define MOUSE8042_RESET_TIMEOUT_USECS   500000  /* 500 ms */
  66 
  67 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
  68 extern void consconfig_link(major_t major, minor_t minor);
  69 extern int consconfig_unlink(major_t major, minor_t minor);
  70 
  71 
  72 /*
  73  *
  74  * Local Static Data
  75  *
  76  */
  77 
  78 /*
  79  * We only support one instance.  Yes, it's theoretically possible to
  80  * plug in more than one, but it's not worth the implementation cost.
  81  *
  82  * The introduction of USB keyboards might make it worth reassessing
  83  * this decision, as they might free up the keyboard port for a second
  84  * PS/2 style mouse.
  85  */
  86 static dev_info_t *mouse8042_dip;
  87 
  88 /*
  89  * RESET states
  90  */
  91 typedef enum {
  92         MSE_RESET_IDLE, /* No reset in progress */
  93         MSE_RESET_PRE,  /* Send reset, waiting for ACK */
  94         MSE_RESET_ACK,  /* Got ACK, waiting for 0xAA */
  95         MSE_RESET_AA,   /* Got 0xAA, waiting for 0x00 */
  96         MSE_RESET_FAILED
  97 } mouse8042_reset_state_e;
  98 
  99 struct mouse_state {
 100         queue_t *ms_rqp;
 101         queue_t *ms_wqp;
 102         ddi_iblock_cookie_t     ms_iblock_cookie;
 103         ddi_acc_handle_t        ms_handle;
 104         uint8_t                 *ms_addr;
 105         kmutex_t                ms_mutex;
 106 
 107         minor_t                 ms_minor;
 108         boolean_t               ms_opened;
 109         kmutex_t                reset_mutex;
 110         kcondvar_t              reset_cv;
 111         mouse8042_reset_state_e reset_state;
 112         timeout_id_t            reset_tid;
 113         int                     ready;
 114         mblk_t                  *reply_mp;
 115         mblk_t                  *reset_ack_mp;
 116         bufcall_id_t            bc_id;
 117 };
 118 
 119 static uint_t mouse8042_intr(caddr_t arg);
 120 static int mouse8042_open(queue_t *q, dev_t *devp, int flag, int sflag,
 121                 cred_t *cred_p);
 122 static int mouse8042_close(queue_t *q, int flag, cred_t *cred_p);
 123 static int mouse8042_wsrv(queue_t *qp);
 124 static int mouse8042_wput(queue_t *q, mblk_t *mp);
 125 
 126 static int mouse8042_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
 127                 void *arg, void **result);
 128 static int mouse8042_attach(dev_info_t *dev, ddi_attach_cmd_t cmd);
 129 static int mouse8042_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
 130 
 131 
 132 /*
 133  * Streams module info.
 134  */
 135 #define MODULE_NAME     "mouse8042"
 136 
 137 static struct module_info       mouse8042_minfo = {
 138         23,             /* Module ID number */
 139         MODULE_NAME,
 140         0, INFPSZ,      /* minimum & maximum packet sizes */
 141         256, 128        /* hi and low water marks */
 142 };
 143 
 144 static struct qinit mouse8042_rinit = {
 145         NULL,           /* put */
 146         NULL,           /* service */
 147         mouse8042_open,
 148         mouse8042_close,
 149         NULL,           /* admin */
 150         &mouse8042_minfo,
 151         NULL            /* statistics */
 152 };
 153 
 154 static struct qinit mouse8042_winit = {
 155         mouse8042_wput, /* put */
 156         mouse8042_wsrv, /* service */
 157         NULL,           /* open */
 158         NULL,           /* close */
 159         NULL,           /* admin */
 160         &mouse8042_minfo,
 161         NULL            /* statistics */
 162 };
 163 
 164 static struct streamtab mouse8042_strinfo = {
 165         &mouse8042_rinit,
 166         &mouse8042_winit,
 167         NULL,           /* muxrinit */
 168         NULL,           /* muxwinit */
 169 };
 170 
 171 /*
 172  * Local Function Declarations
 173  */
 174 
 175 static struct cb_ops    mouse8042_cb_ops = {
 176         nodev,                  /* open */
 177         nodev,                  /* close */
 178         nodev,                  /* strategy */
 179         nodev,                  /* print */
 180         nodev,                  /* dump */
 181         nodev,                  /* read */
 182         nodev,                  /* write */
 183         nodev,                  /* ioctl */
 184         nodev,                  /* devmap */
 185         nodev,                  /* mmap */
 186         nodev,                  /* segmap */
 187         nochpoll,               /* poll */
 188         ddi_prop_op,            /* cb_prop_op */
 189         &mouse8042_strinfo, /* streamtab  */
 190         D_MP | D_NEW
 191 };
 192 
 193 
 194 static struct dev_ops   mouse8042_ops = {
 195         DEVO_REV,               /* devo_rev, */
 196         0,                      /* refcnt  */
 197         mouse8042_getinfo,      /* getinfo */
 198         nulldev,                /* identify */
 199         nulldev,                /* probe */
 200         mouse8042_attach,       /* attach */
 201         mouse8042_detach,       /* detach */
 202         nodev,                  /* reset */
 203         &mouse8042_cb_ops,  /* driver operations */
 204         (struct bus_ops *)0,    /* bus operations */
 205         NULL,                   /* power */
 206         ddi_quiesce_not_needed,         /* quiesce */
 207 };
 208 
 209 /*
 210  * This is the loadable module wrapper.
 211  */
 212 #include <sys/modctl.h>
 213 
 214 extern struct mod_ops mod_driverops;
 215 
 216 /*
 217  * Module linkage information for the kernel.
 218  */
 219 
 220 static struct modldrv modldrv = {
 221         &mod_driverops, /* Type of module.  This one is a driver */
 222         "PS/2 Mouse",
 223         &mouse8042_ops,     /* driver ops */
 224 };
 225 
 226 static struct modlinkage modlinkage = {
 227         MODREV_1,
 228         { (void *)&modldrv, NULL }
 229 };
 230 
 231 /*
 232  * This is the driver initialization routine.
 233  */
 234 int
 235 _init()
 236 {
 237         int     rv;
 238 
 239         rv = mod_install(&modlinkage);
 240         return (rv);
 241 }
 242 
 243 
 244 int
 245 _fini(void)
 246 {
 247         return (mod_remove(&modlinkage));
 248 }
 249 
 250 
 251 int
 252 _info(struct modinfo *modinfop)
 253 {
 254         return (mod_info(&modlinkage, modinfop));
 255 }
 256 
 257 static int
 258 mouse8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 259 {
 260         struct mouse_state *state;
 261         mblk_t *mp;
 262         int instance = ddi_get_instance(dip);
 263         static ddi_device_acc_attr_t attr = {
 264                 DDI_DEVICE_ATTR_V0,
 265                 DDI_NEVERSWAP_ACC,
 266                 DDI_STRICTORDER_ACC,
 267         };
 268         int rc;
 269 
 270 
 271         if (cmd == DDI_RESUME) {
 272                 state = (struct mouse_state *)ddi_get_driver_private(dip);
 273 
 274                 /* Ready to handle inbound data from mouse8042_intr */
 275                 state->ready = 1;
 276 
 277                 /*
 278                  * Send a 0xaa 0x00 upstream.
 279                  * This causes the vuid module to reset the mouse.
 280                  */
 281                 if (state->ms_rqp != NULL) {
 282                         if (mp = allocb(1, BPRI_MED)) {
 283                                 *mp->b_wptr++ = 0xaa;
 284                                 putnext(state->ms_rqp, mp);
 285                         }
 286                         if (mp = allocb(1, BPRI_MED)) {
 287                                 *mp->b_wptr++ = 0x0;
 288                                 putnext(state->ms_rqp, mp);
 289                         }
 290                 }
 291                 return (DDI_SUCCESS);
 292         }
 293 
 294         if (cmd != DDI_ATTACH)
 295                 return (DDI_FAILURE);
 296 
 297         if (mouse8042_dip != NULL)
 298                 return (DDI_FAILURE);
 299 
 300         /* allocate and initialize state structure */
 301         state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP);
 302         state->ms_opened = B_FALSE;
 303         state->reset_state = MSE_RESET_IDLE;
 304         state->reset_tid = 0;
 305         state->bc_id = 0;
 306         ddi_set_driver_private(dip, state);
 307 
 308         /*
 309          * In order to support virtual keyboard/mouse, we should distinguish
 310          * between internal virtual open and external physical open.
 311          *
 312          * When the physical devices are opened by application, they will
 313          * be unlinked from the virtual device and their data stream will
 314          * not be sent to the virtual device. When the opened physical
 315          * devices are closed, they will be relinked to the virtual devices.
 316          *
 317          * All these automatic switch between virtual and physical are
 318          * transparent.
 319          *
 320          * So we change minor node numbering scheme to be:
 321          *      external node minor num == instance * 2
 322          *      internal node minor num == instance * 2 + 1
 323          */
 324         rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2,
 325             DDI_NT_MOUSE, NULL);
 326         if (rc != DDI_SUCCESS) {
 327                 goto fail_1;
 328         }
 329 
 330         if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR,
 331             instance * 2 + 1) != DDI_SUCCESS) {
 332                 goto fail_2;
 333         }
 334 
 335         rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr,
 336             (offset_t)0, (offset_t)0, &attr, &state->ms_handle);
 337         if (rc != DDI_SUCCESS) {
 338                 goto fail_2;
 339         }
 340 
 341         rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie);
 342         if (rc != DDI_SUCCESS) {
 343                 goto fail_3;
 344         }
 345 
 346         mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER,
 347             state->ms_iblock_cookie);
 348         mutex_init(&state->reset_mutex, NULL, MUTEX_DRIVER,
 349             state->ms_iblock_cookie);
 350         cv_init(&state->reset_cv, NULL, CV_DRIVER, NULL);
 351 
 352         rc = ddi_add_intr(dip, 0,
 353             (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL,
 354             mouse8042_intr, (caddr_t)state);
 355         if (rc != DDI_SUCCESS) {
 356                 goto fail_3;
 357         }
 358 
 359         mouse8042_dip = dip;
 360 
 361         /* Ready to handle inbound data from mouse8042_intr */
 362         state->ready = 1;
 363 
 364         /* Now that we're attached, announce our presence to the world. */
 365         ddi_report_dev(dip);
 366         return (DDI_SUCCESS);
 367 
 368 fail_3:
 369         ddi_regs_map_free(&state->ms_handle);
 370 
 371 fail_2:
 372         ddi_remove_minor_node(dip, NULL);
 373 
 374 fail_1:
 375         kmem_free(state, sizeof (struct mouse_state));
 376         return (rc);
 377 }
 378 
 379 /*ARGSUSED*/
 380 static int
 381 mouse8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 382 {
 383         struct mouse_state *state;
 384 
 385         state = ddi_get_driver_private(dip);
 386 
 387         switch (cmd) {
 388         case DDI_SUSPEND:
 389                 /* Ignore all data from mouse8042_intr until we fully resume */
 390                 state->ready = 0;
 391                 return (DDI_SUCCESS);
 392 
 393         case DDI_DETACH:
 394                 ddi_remove_intr(dip, 0, state->ms_iblock_cookie);
 395                 mouse8042_dip = NULL;
 396                 cv_destroy(&state->reset_cv);
 397                 mutex_destroy(&state->reset_mutex);
 398                 mutex_destroy(&state->ms_mutex);
 399                 ddi_prop_remove_all(dip);
 400                 ddi_regs_map_free(&state->ms_handle);
 401                 ddi_remove_minor_node(dip, NULL);
 402                 kmem_free(state, sizeof (struct mouse_state));
 403                 return (DDI_SUCCESS);
 404 
 405         default:
 406                 return (DDI_FAILURE);
 407         }
 408 }
 409 
 410 
 411 /* ARGSUSED */
 412 static int
 413 mouse8042_getinfo(
 414     dev_info_t *dip,
 415     ddi_info_cmd_t infocmd,
 416     void *arg,
 417     void **result)
 418 {
 419         dev_t dev = (dev_t)arg;
 420         minor_t minor = getminor(dev);
 421         int     instance = MOUSE8042_MINOR_TO_INSTANCE(minor);
 422 
 423         switch (infocmd) {
 424         case DDI_INFO_DEVT2DEVINFO:
 425                 if (mouse8042_dip == NULL)
 426                         return (DDI_FAILURE);
 427 
 428                 *result = (void *)mouse8042_dip;
 429                 break;
 430         case DDI_INFO_DEVT2INSTANCE:
 431                 *result = (void *)(uintptr_t)instance;
 432                 break;
 433         default:
 434                 return (DDI_FAILURE);
 435         }
 436         return (DDI_SUCCESS);
 437 }
 438 
 439 /*ARGSUSED*/
 440 static int
 441 mouse8042_open(
 442         queue_t *q,
 443         dev_t   *devp,
 444         int     flag,
 445         int     sflag,
 446         cred_t  *cred_p)
 447 {
 448         struct mouse_state *state;
 449         minor_t minor = getminor(*devp);
 450         int rval;
 451 
 452         if (mouse8042_dip == NULL)
 453                 return (ENXIO);
 454 
 455         state = ddi_get_driver_private(mouse8042_dip);
 456 
 457         mutex_enter(&state->ms_mutex);
 458 
 459         if (state->ms_opened) {
 460                 /*
 461                  * Exit if the same minor node is already open
 462                  */
 463                 if (state->ms_minor == minor) {
 464                         mutex_exit(&state->ms_mutex);
 465                         return (0);
 466                 }
 467 
 468                 /*
 469                  * Check whether it is switch between physical and virtual
 470                  *
 471                  * Opening from virtual while the device is being physically
 472                  * opened by an application should not happen. So we ASSERT
 473                  * this in DEBUG version, and return error in the non-DEBUG
 474                  * case.
 475                  */
 476                 ASSERT(!MOUSE8042_INTERNAL_OPEN(minor));
 477 
 478                 if (MOUSE8042_INTERNAL_OPEN(minor)) {
 479                         mutex_exit(&state->ms_mutex);
 480                         return (EINVAL);
 481                 }
 482 
 483                 /*
 484                  * Opening the physical one while it is being underneath
 485                  * the virtual one.
 486                  *
 487                  * consconfig_unlink is called to unlink this device from
 488                  * the virtual one, thus the old stream serving for this
 489                  * device under the virtual one is closed, and then the
 490                  * lower driver's close routine (here is mouse8042_close)
 491                  * is also called to accomplish the whole stream close.
 492                  * Here we have to drop the lock because mouse8042_close
 493                  * also needs the lock.
 494                  *
 495                  * For mouse, the old stream is:
 496                  *      consms->["pushmod"->]"mouse_vp driver"
 497                  *
 498                  * After the consconfig_unlink returns, the old stream is closed
 499                  * and we grab the lock again to reopen this device as normal.
 500                  */
 501                 mutex_exit(&state->ms_mutex);
 502 
 503                 /*
 504                  * If unlink fails, fail the physical open.
 505                  */
 506                 if ((rval = consconfig_unlink(ddi_driver_major(mouse8042_dip),
 507                     MOUSE8042_INTERNAL_MINOR(minor))) != 0) {
 508                         return (rval);
 509                 }
 510 
 511                 mutex_enter(&state->ms_mutex);
 512         }
 513 
 514 
 515         q->q_ptr = (caddr_t)state;
 516         WR(q)->q_ptr = (caddr_t)state;
 517         state->ms_rqp = q;
 518         state->ms_wqp = WR(q);
 519 
 520         qprocson(q);
 521 
 522         state->ms_minor = minor;
 523         state->ms_opened = B_TRUE;
 524 
 525         mutex_exit(&state->ms_mutex);
 526 
 527         return (0);
 528 }
 529 
 530 
 531 /*ARGSUSED*/
 532 static int
 533 mouse8042_close(queue_t *q, int flag, cred_t *cred_p)
 534 {
 535         struct mouse_state *state;
 536         minor_t minor;
 537 
 538         state = (struct mouse_state *)q->q_ptr;
 539 
 540         /*
 541          * Disable queue processing now, so that another reset cannot get in
 542          * after we wait for the current reset (if any) to complete.
 543          */
 544         qprocsoff(q);
 545 
 546         mutex_enter(&state->reset_mutex);
 547         while (state->reset_state != MSE_RESET_IDLE) {
 548                 /*
 549                  * Waiting for the previous reset to finish is
 550                  * non-interruptible.  Some upper-level clients
 551                  * cannot deal with EINTR and will not close the
 552                  * STREAM properly, resulting in failure to reopen it
 553                  * within the same process.
 554                  */
 555                 cv_wait(&state->reset_cv, &state->reset_mutex);
 556         }
 557 
 558         if (state->reset_tid != 0) {
 559                 (void) quntimeout(q, state->reset_tid);
 560                 state->reset_tid = 0;
 561         }
 562 
 563         if (state->reply_mp != NULL) {
 564                 freemsg(state->reply_mp);
 565                 state->reply_mp = NULL;
 566         }
 567 
 568         if (state->reset_ack_mp != NULL) {
 569                 freemsg(state->reset_ack_mp);
 570                 state->reset_ack_mp = NULL;
 571         }
 572 
 573         mutex_exit(&state->reset_mutex);
 574 
 575         mutex_enter(&state->ms_mutex);
 576 
 577         if (state->bc_id != 0) {
 578                 (void) qunbufcall(q, state->bc_id);
 579                 state->bc_id = 0;
 580         }
 581 
 582         q->q_ptr = NULL;
 583         WR(q)->q_ptr = NULL;
 584         state->ms_rqp = NULL;
 585         state->ms_wqp = NULL;
 586 
 587         state->ms_opened = B_FALSE;
 588 
 589         minor = state->ms_minor;
 590 
 591         mutex_exit(&state->ms_mutex);
 592 
 593         if (!MOUSE8042_INTERNAL_OPEN(minor)) {
 594                 /*
 595                  * Closing physical PS/2 mouse
 596                  *
 597                  * Link it back to virtual mouse, and
 598                  * mouse8042_open will be called as a result
 599                  * of the consconfig_link call.  Do NOT try
 600                  * this if the mouse is about to be detached!
 601                  *
 602                  * If linking back fails, this specific mouse
 603                  * will not be available underneath the virtual
 604                  * mouse, and can only be accessed via physical
 605                  * open.
 606                  */
 607                 consconfig_link(ddi_driver_major(mouse8042_dip),
 608                     MOUSE8042_INTERNAL_MINOR(minor));
 609         }
 610 
 611         return (0);
 612 }
 613 
 614 static void
 615 mouse8042_iocnack(
 616     queue_t *qp,
 617     mblk_t *mp,
 618     struct iocblk *iocp,
 619     int error,
 620     int rval)
 621 {
 622         mp->b_datap->db_type = M_IOCNAK;
 623         iocp->ioc_rval = rval;
 624         iocp->ioc_error = error;
 625         qreply(qp, mp);
 626 }
 627 
 628 static void
 629 mouse8042_reset_timeout(void *argp)
 630 {
 631         struct mouse_state *state = (struct mouse_state *)argp;
 632         mblk_t *mp;
 633 
 634         mutex_enter(&state->reset_mutex);
 635 
 636         /*
 637          * If the interrupt handler hasn't completed the reset handling
 638          * (reset_state would be IDLE or FAILED in that case), then
 639          * drop the 8042 lock, and send a faked retry reply upstream,
 640          * then enable the queue for further message processing.
 641          */
 642         if (state->reset_state != MSE_RESET_IDLE &&
 643             state->reset_state != MSE_RESET_FAILED) {
 644 
 645                 state->reset_tid = 0;
 646                 state->reset_state = MSE_RESET_IDLE;
 647                 cv_signal(&state->reset_cv);
 648 
 649                 (void) ddi_get8(state->ms_handle, state->ms_addr +
 650                     I8042_UNLOCK);
 651 
 652                 mp = state->reply_mp;
 653                 *mp->b_wptr++ = MSERESEND;
 654                 state->reply_mp = NULL;
 655 
 656                 if (state->ms_rqp != NULL)
 657                         putnext(state->ms_rqp, mp);
 658                 else
 659                         freemsg(mp);
 660 
 661                 ASSERT(state->ms_wqp != NULL);
 662 
 663                 enableok(state->ms_wqp);
 664                 qenable(state->ms_wqp);
 665         }
 666 
 667         mutex_exit(&state->reset_mutex);
 668 }
 669 
 670 /*
 671  * Returns 1 if the caller should put the message (bp) back on the queue
 672  */
 673 static int
 674 mouse8042_initiate_reset(queue_t *q, mblk_t *mp, struct mouse_state *state)
 675 {
 676         mutex_enter(&state->reset_mutex);
 677         /*
 678          * If we're in the middle of a reset, put the message back on the queue
 679          * for processing later.
 680          */
 681         if (state->reset_state != MSE_RESET_IDLE) {
 682                 /*
 683                  * We noenable the queue again here in case it was backenabled
 684                  * by an upper-level module.
 685                  */
 686                 noenable(q);
 687 
 688                 mutex_exit(&state->reset_mutex);
 689                 return (1);
 690         }
 691 
 692         /*
 693          * Drop the reset state lock before allocating the response message and
 694          * grabbing the 8042 exclusive-access lock (since those operations
 695          * may take an extended period of time to complete).
 696          */
 697         mutex_exit(&state->reset_mutex);
 698 
 699         if (state->reply_mp == NULL)
 700                 state->reply_mp = allocb(2, BPRI_MED);
 701         if (state->reset_ack_mp == NULL)
 702                 state->reset_ack_mp = allocb(1, BPRI_MED);
 703 
 704         if (state->reply_mp == NULL || state->reset_ack_mp == NULL) {
 705                 /*
 706                  * Allocation failed -- set up a bufcall to enable the queue
 707                  * whenever there is enough memory to allocate the response
 708                  * message.
 709                  */
 710                 state->bc_id = qbufcall(q, (state->reply_mp == NULL) ? 2 : 1,
 711                     BPRI_MED, (void (*)(void *))qenable, q);
 712 
 713                 if (state->bc_id == 0) {
 714                         /*
 715                          * If the qbufcall failed, we cannot proceed, so use the
 716                          * message we were sent to respond with an error.
 717                          */
 718                         *mp->b_rptr = MSEERROR;
 719                         mp->b_wptr = mp->b_rptr + 1;
 720                         qreply(q, mp);
 721                         return (0);
 722                 }
 723 
 724                 return (1);
 725         } else {
 726                 /* Bufcall completed successfully (or wasn't needed) */
 727                 state->bc_id = 0;
 728         }
 729 
 730         /*
 731          * Gain exclusive access to the 8042 for the duration of the reset.
 732          * The unlock will occur when the reset has either completed or timed
 733          * out.
 734          */
 735         (void) ddi_get8(state->ms_handle,
 736             state->ms_addr + I8042_LOCK);
 737 
 738         mutex_enter(&state->reset_mutex);
 739 
 740         state->reset_state = MSE_RESET_PRE;
 741         noenable(q);
 742 
 743         state->reset_tid = qtimeout(q,
 744             mouse8042_reset_timeout,
 745             state,
 746             drv_usectohz(
 747             MOUSE8042_RESET_TIMEOUT_USECS));
 748 
 749         ddi_put8(state->ms_handle,
 750             state->ms_addr +
 751             I8042_INT_OUTPUT_DATA, MSERESET);
 752 
 753         mp->b_rptr++;
 754 
 755         mutex_exit(&state->reset_mutex);
 756         return (1);
 757 }
 758 
 759 /*
 760  * Returns 1 if the caller should stop processing messages
 761  */
 762 static int
 763 mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
 764 {
 765         mblk_t *bp;
 766         mblk_t *next;
 767 
 768         bp = mp;
 769         do {
 770                 while (bp->b_rptr < bp->b_wptr) {
 771                         /*
 772                          * Detect an attempt to reset the mouse.  Lock out any
 773                          * further mouse writes until the reset has completed.
 774                          */
 775                         if (*bp->b_rptr == MSERESET) {
 776 
 777                                 /*
 778                                  * If we couldn't allocate memory and we
 779                                  * we couldn't register a bufcall,
 780                                  * mouse8042_initiate_reset returns 0 and
 781                                  * has already used the message to send an
 782                                  * error reply back upstream, so there is no
 783                                  * need to deallocate or put this message back
 784                                  * on the queue.
 785                                  */
 786                                 if (mouse8042_initiate_reset(q, bp, state) == 0)
 787                                         return (1);
 788 
 789                                 /*
 790                                  * If there's no data remaining in this block,
 791                                  * free this block and put the following blocks
 792                                  * of this message back on the queue. If putting
 793                                  * the rest of the message back on the queue
 794                                  * fails, free the the message.
 795                                  */
 796                                 if (MBLKL(bp) == 0) {
 797                                         next = bp->b_cont;
 798                                         freeb(bp);
 799                                         bp = next;
 800                                 }
 801                                 if (bp != NULL) {
 802                                         if (!putbq(q, bp))
 803                                                 freemsg(bp);
 804                                 }
 805 
 806                                 return (1);
 807 
 808                         }
 809                         ddi_put8(state->ms_handle,
 810                             state->ms_addr + I8042_INT_OUTPUT_DATA,
 811                             *bp->b_rptr++);
 812                 }
 813                 next = bp->b_cont;
 814                 freeb(bp);
 815         } while ((bp = next) != NULL);
 816 
 817         return (0);
 818 }
 819 
 820 static int
 821 mouse8042_process_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
 822 {
 823         struct iocblk *iocbp;
 824         int rv = 0;
 825 
 826         iocbp = (struct iocblk *)mp->b_rptr;
 827 
 828         switch (mp->b_datap->db_type) {
 829         case M_FLUSH:
 830                 if (*mp->b_rptr & FLUSHW) {
 831                         flushq(q, FLUSHDATA);
 832                         *mp->b_rptr &= ~FLUSHW;
 833                 }
 834                 if (*mp->b_rptr & FLUSHR) {
 835                         qreply(q, mp);
 836                 } else
 837                         freemsg(mp);
 838                 break;
 839         case M_IOCTL:
 840                 mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
 841                 break;
 842         case M_IOCDATA:
 843                 mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
 844                 break;
 845         case M_DATA:
 846                 rv = mouse8042_process_data_msg(q, mp, state);
 847                 break;
 848         default:
 849                 freemsg(mp);
 850                 break;
 851         }
 852 
 853         return (rv);
 854 }
 855 
 856 /*
 857  * This is the main mouse input routine.  Commands and parameters
 858  * from upstream are sent to the mouse device immediately, unless
 859  * the mouse is in the process of being reset, in which case
 860  * commands are queued and executed later in the service procedure.
 861  */
 862 static int
 863 mouse8042_wput(queue_t *q, mblk_t *mp)
 864 {
 865         struct mouse_state *state;
 866         state = (struct mouse_state *)q->q_ptr;
 867 
 868         /*
 869          * Process all messages immediately, unless a reset is in
 870          * progress.  If a reset is in progress, deflect processing to
 871          * the service procedure.
 872          */
 873         if (state->reset_state != MSE_RESET_IDLE)
 874                 return (putq(q, mp));
 875 
 876         /*
 877          * If there are still messages outstanding in the queue that
 878          * the service procedure hasn't processed yet, put this
 879          * message in the queue also, to ensure proper message
 880          * ordering.
 881          */
 882         if (q->q_first)
 883                 return (putq(q, mp));
 884 
 885         (void) mouse8042_process_msg(q, mp, state);
 886 
 887         return (0);
 888 }
 889 
 890 static int
 891 mouse8042_wsrv(queue_t *qp)
 892 {
 893         mblk_t *mp;
 894         struct mouse_state *state;
 895         state = (struct mouse_state *)qp->q_ptr;
 896 
 897         while ((mp = getq(qp)) != NULL) {
 898                 if (mouse8042_process_msg(qp, mp, state) != 0)
 899                         break;
 900         }
 901 
 902         return (0);
 903 }
 904 
 905 /*
 906  * Returns the next reset state, given the current state and the byte
 907  * received from the mouse.  Error and Resend codes are handled by the
 908  * caller.
 909  */
 910 static mouse8042_reset_state_e
 911 mouse8042_reset_fsm(mouse8042_reset_state_e reset_state, uint8_t mdata)
 912 {
 913         switch (reset_state) {
 914         case MSE_RESET_PRE:     /* RESET sent, now we expect an ACK */
 915                 if (mdata == MSE_ACK)   /* Got the ACK */
 916                         return (MSE_RESET_ACK);
 917                 break;
 918 
 919         case MSE_RESET_ACK:     /* ACK received; now we expect 0xAA */
 920                 if (mdata == MSE_AA)    /* Got the 0xAA */
 921                         return (MSE_RESET_AA);
 922                 break;
 923 
 924         case MSE_RESET_AA:      /* 0xAA received; now we expect 0x00 */
 925                 if (mdata == MSE_00)
 926                         return (MSE_RESET_IDLE);
 927                 break;
 928         }
 929 
 930         return (reset_state);
 931 }
 932 
 933 static uint_t
 934 mouse8042_intr(caddr_t arg)
 935 {
 936         unsigned char    mdata;
 937         mblk_t *mp;
 938         struct mouse_state *state = (struct mouse_state *)arg;
 939         int rc;
 940 
 941         mutex_enter(&state->ms_mutex);
 942 
 943         rc = DDI_INTR_UNCLAIMED;
 944 
 945         for (;;) {
 946 
 947                 if (ddi_get8(state->ms_handle,
 948                     state->ms_addr + I8042_INT_INPUT_AVAIL) == 0) {
 949                         break;
 950                 }
 951 
 952                 mdata = ddi_get8(state->ms_handle,
 953                     state->ms_addr + I8042_INT_INPUT_DATA);
 954 
 955                 rc = DDI_INTR_CLAIMED;
 956 
 957                 /*
 958                  * If we're not ready for this data, discard it.
 959                  */
 960                 if (!state->ready)
 961                         continue;
 962 
 963                 mutex_enter(&state->reset_mutex);
 964                 if (state->reset_state != MSE_RESET_IDLE) {
 965 
 966                         if (mdata == MSEERROR || mdata == MSERESET) {
 967                                 state->reset_state = MSE_RESET_FAILED;
 968                         } else {
 969                                 state->reset_state =
 970                                     mouse8042_reset_fsm(state->reset_state,
 971                                     mdata);
 972                         }
 973 
 974                         if (state->reset_state == MSE_RESET_ACK) {
 975 
 976                         /*
 977                          * We received an ACK from the mouse, so
 978                          * send it upstream immediately so that
 979                          * consumers depending on the immediate
 980                          * ACK don't time out.
 981                          */
 982                                 if (state->reset_ack_mp != NULL) {
 983 
 984                                         mp = state->reset_ack_mp;
 985 
 986                                         state->reset_ack_mp = NULL;
 987 
 988                                         if (state->ms_rqp != NULL) {
 989                                                 *mp->b_wptr++ = MSE_ACK;
 990                                                 putnext(state->ms_rqp, mp);
 991                                         } else
 992                                                 freemsg(mp);
 993                                 }
 994 
 995                                 if (state->ms_wqp != NULL) {
 996                                         enableok(state->ms_wqp);
 997                                         qenable(state->ms_wqp);
 998                                 }
 999 
1000                         } else if (state->reset_state == MSE_RESET_IDLE ||
1001                             state->reset_state == MSE_RESET_FAILED) {
1002 
1003                         /*
1004                          * If we transitioned back to the idle reset state (or
1005                          * the reset failed), disable the timeout, release the
1006                          * 8042 exclusive-access lock, then send the response
1007                          * the the upper-level modules. Finally, enable the
1008                          * queue and schedule queue service procedures so that
1009                          * upper-level modules can process the response.
1010                          * Otherwise, if we're still in the middle of the
1011                          * reset sequence, do not send the data up (since the
1012                          * response is sent at the end of the sequence, or
1013                          * on timeout/error).
1014                          */
1015 
1016                                 mutex_exit(&state->reset_mutex);
1017                                 (void) quntimeout(state->ms_wqp,
1018                                     state->reset_tid);
1019                                 mutex_enter(&state->reset_mutex);
1020 
1021                                 (void) ddi_get8(state->ms_handle,
1022                                     state->ms_addr + I8042_UNLOCK);
1023 
1024                                 state->reset_tid = 0;
1025                                 if (state->reply_mp != NULL) {
1026                                         mp = state->reply_mp;
1027                                         if (state->reset_state ==
1028                                             MSE_RESET_FAILED) {
1029                                                 *mp->b_wptr++ = mdata;
1030                                         } else {
1031                                                 *mp->b_wptr++ = MSE_AA;
1032                                                 *mp->b_wptr++ = MSE_00;
1033                                         }
1034                                         state->reply_mp = NULL;
1035                                 } else {
1036                                         mp = NULL;
1037                                 }
1038 
1039                                 state->reset_state = MSE_RESET_IDLE;
1040                                 cv_signal(&state->reset_cv);
1041 
1042                                 if (mp != NULL) {
1043                                         if (state->ms_rqp != NULL)
1044                                                 putnext(state->ms_rqp, mp);
1045                                         else
1046                                                 freemsg(mp);
1047                                 }
1048 
1049                                 if (state->ms_wqp != NULL) {
1050                                         enableok(state->ms_wqp);
1051                                         qenable(state->ms_wqp);
1052                                 }
1053                         }
1054 
1055                         mutex_exit(&state->reset_mutex);
1056                         mutex_exit(&state->ms_mutex);
1057                         return (rc);
1058                 }
1059                 mutex_exit(&state->reset_mutex);
1060 
1061                 if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) {
1062                         *mp->b_wptr++ = mdata;
1063                         putnext(state->ms_rqp, mp);
1064                 }
1065         }
1066         mutex_exit(&state->ms_mutex);
1067 
1068         return (rc);
1069 }