17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
519397407SSherry Moore * Common Development and Distribution License (the "License").
619397407SSherry Moore * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
227c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
237c478bd9Sstevel@tonic-gate /* All Rights Reserved */
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate /*
2615bfc6b7SSeth Goldberg * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
277c478bd9Sstevel@tonic-gate * Use is subject to license terms.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate * PS/2 type Mouse Module - Streams
337c478bd9Sstevel@tonic-gate */
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate #include <sys/param.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
387c478bd9Sstevel@tonic-gate #include <sys/signal.h>
397c478bd9Sstevel@tonic-gate #include <sys/errno.h>
407c478bd9Sstevel@tonic-gate #include <sys/file.h>
417c478bd9Sstevel@tonic-gate #include <sys/termio.h>
427c478bd9Sstevel@tonic-gate #include <sys/stream.h>
437c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
447c478bd9Sstevel@tonic-gate #include <sys/strtty.h>
4515bfc6b7SSeth Goldberg #include <sys/strsun.h>
467c478bd9Sstevel@tonic-gate #include <sys/debug.h>
477c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
507c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate #include <sys/promif.h>
537c478bd9Sstevel@tonic-gate #include <sys/cred.h>
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate #include <sys/i8042.h>
567c478bd9Sstevel@tonic-gate #include <sys/note.h>
5715bfc6b7SSeth Goldberg #include <sys/mouse.h>
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #define DRIVER_NAME(dip) ddi_driver_name(dip)
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate #define MOUSE8042_INTERNAL_OPEN(minor) (((minor) & 0x1) == 1)
627c478bd9Sstevel@tonic-gate #define MOUSE8042_MINOR_TO_INSTANCE(minor) ((minor) / 2)
637c478bd9Sstevel@tonic-gate #define MOUSE8042_INTERNAL_MINOR(minor) ((minor) + 1)
647c478bd9Sstevel@tonic-gate
6515bfc6b7SSeth Goldberg #define MOUSE8042_RESET_TIMEOUT_USECS 500000 /* 500 ms */
6615bfc6b7SSeth Goldberg
677c478bd9Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
687c478bd9Sstevel@tonic-gate extern void consconfig_link(major_t major, minor_t minor);
697c478bd9Sstevel@tonic-gate extern int consconfig_unlink(major_t major, minor_t minor);
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate /*
737c478bd9Sstevel@tonic-gate *
747c478bd9Sstevel@tonic-gate * Local Static Data
757c478bd9Sstevel@tonic-gate *
767c478bd9Sstevel@tonic-gate */
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate * We only support one instance. Yes, it's theoretically possible to
807c478bd9Sstevel@tonic-gate * plug in more than one, but it's not worth the implementation cost.
817c478bd9Sstevel@tonic-gate *
827c478bd9Sstevel@tonic-gate * The introduction of USB keyboards might make it worth reassessing
837c478bd9Sstevel@tonic-gate * this decision, as they might free up the keyboard port for a second
847c478bd9Sstevel@tonic-gate * PS/2 style mouse.
857c478bd9Sstevel@tonic-gate */
867c478bd9Sstevel@tonic-gate static dev_info_t *mouse8042_dip;
877c478bd9Sstevel@tonic-gate
8815bfc6b7SSeth Goldberg /*
8915bfc6b7SSeth Goldberg * RESET states
9015bfc6b7SSeth Goldberg */
9115bfc6b7SSeth Goldberg typedef enum {
9215bfc6b7SSeth Goldberg MSE_RESET_IDLE, /* No reset in progress */
9315bfc6b7SSeth Goldberg MSE_RESET_PRE, /* Send reset, waiting for ACK */
9415bfc6b7SSeth Goldberg MSE_RESET_ACK, /* Got ACK, waiting for 0xAA */
9515bfc6b7SSeth Goldberg MSE_RESET_AA, /* Got 0xAA, waiting for 0x00 */
9615bfc6b7SSeth Goldberg MSE_RESET_FAILED
9715bfc6b7SSeth Goldberg } mouse8042_reset_state_e;
9815bfc6b7SSeth Goldberg
997c478bd9Sstevel@tonic-gate struct mouse_state {
1007c478bd9Sstevel@tonic-gate queue_t *ms_rqp;
1017c478bd9Sstevel@tonic-gate queue_t *ms_wqp;
1027c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t ms_iblock_cookie;
1037c478bd9Sstevel@tonic-gate ddi_acc_handle_t ms_handle;
1047c478bd9Sstevel@tonic-gate uint8_t *ms_addr;
1057c478bd9Sstevel@tonic-gate kmutex_t ms_mutex;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate minor_t ms_minor;
1087c478bd9Sstevel@tonic-gate boolean_t ms_opened;
10915bfc6b7SSeth Goldberg kmutex_t reset_mutex;
110*5b81b7caSSeth Goldberg kcondvar_t reset_cv;
11115bfc6b7SSeth Goldberg mouse8042_reset_state_e reset_state;
11215bfc6b7SSeth Goldberg timeout_id_t reset_tid;
11315bfc6b7SSeth Goldberg int ready;
11415bfc6b7SSeth Goldberg mblk_t *reply_mp;
115*5b81b7caSSeth Goldberg mblk_t *reset_ack_mp;
11615bfc6b7SSeth Goldberg bufcall_id_t bc_id;
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate static uint_t mouse8042_intr(caddr_t arg);
1207c478bd9Sstevel@tonic-gate static int mouse8042_open(queue_t *q, dev_t *devp, int flag, int sflag,
1217c478bd9Sstevel@tonic-gate cred_t *cred_p);
1227c478bd9Sstevel@tonic-gate static int mouse8042_close(queue_t *q, int flag, cred_t *cred_p);
12315bfc6b7SSeth Goldberg static int mouse8042_wsrv(queue_t *qp);
124*5b81b7caSSeth Goldberg static int mouse8042_wput(queue_t *q, mblk_t *mp);
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate static int mouse8042_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
1277c478bd9Sstevel@tonic-gate void *arg, void **result);
1287c478bd9Sstevel@tonic-gate static int mouse8042_attach(dev_info_t *dev, ddi_attach_cmd_t cmd);
1297c478bd9Sstevel@tonic-gate static int mouse8042_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate * Streams module info.
1347c478bd9Sstevel@tonic-gate */
1357c478bd9Sstevel@tonic-gate #define MODULE_NAME "mouse8042"
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate static struct module_info mouse8042_minfo = {
1387c478bd9Sstevel@tonic-gate 23, /* Module ID number */
1397c478bd9Sstevel@tonic-gate MODULE_NAME,
1407c478bd9Sstevel@tonic-gate 0, INFPSZ, /* minimum & maximum packet sizes */
1417c478bd9Sstevel@tonic-gate 256, 128 /* hi and low water marks */
1427c478bd9Sstevel@tonic-gate };
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate static struct qinit mouse8042_rinit = {
1457c478bd9Sstevel@tonic-gate NULL, /* put */
1467c478bd9Sstevel@tonic-gate NULL, /* service */
1477c478bd9Sstevel@tonic-gate mouse8042_open,
1487c478bd9Sstevel@tonic-gate mouse8042_close,
1497c478bd9Sstevel@tonic-gate NULL, /* admin */
1507c478bd9Sstevel@tonic-gate &mouse8042_minfo,
1517c478bd9Sstevel@tonic-gate NULL /* statistics */
1527c478bd9Sstevel@tonic-gate };
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate static struct qinit mouse8042_winit = {
155*5b81b7caSSeth Goldberg mouse8042_wput, /* put */
15615bfc6b7SSeth Goldberg mouse8042_wsrv, /* service */
1577c478bd9Sstevel@tonic-gate NULL, /* open */
1587c478bd9Sstevel@tonic-gate NULL, /* close */
1597c478bd9Sstevel@tonic-gate NULL, /* admin */
1607c478bd9Sstevel@tonic-gate &mouse8042_minfo,
1617c478bd9Sstevel@tonic-gate NULL /* statistics */
1627c478bd9Sstevel@tonic-gate };
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate static struct streamtab mouse8042_strinfo = {
1657c478bd9Sstevel@tonic-gate &mouse8042_rinit,
1667c478bd9Sstevel@tonic-gate &mouse8042_winit,
1677c478bd9Sstevel@tonic-gate NULL, /* muxrinit */
1687c478bd9Sstevel@tonic-gate NULL, /* muxwinit */
1697c478bd9Sstevel@tonic-gate };
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate * Local Function Declarations
1737c478bd9Sstevel@tonic-gate */
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate static struct cb_ops mouse8042_cb_ops = {
1767c478bd9Sstevel@tonic-gate nodev, /* open */
1777c478bd9Sstevel@tonic-gate nodev, /* close */
1787c478bd9Sstevel@tonic-gate nodev, /* strategy */
1797c478bd9Sstevel@tonic-gate nodev, /* print */
1807c478bd9Sstevel@tonic-gate nodev, /* dump */
1817c478bd9Sstevel@tonic-gate nodev, /* read */
1827c478bd9Sstevel@tonic-gate nodev, /* write */
1837c478bd9Sstevel@tonic-gate nodev, /* ioctl */
1847c478bd9Sstevel@tonic-gate nodev, /* devmap */
1857c478bd9Sstevel@tonic-gate nodev, /* mmap */
1867c478bd9Sstevel@tonic-gate nodev, /* segmap */
1877c478bd9Sstevel@tonic-gate nochpoll, /* poll */
1887c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
1897c478bd9Sstevel@tonic-gate &mouse8042_strinfo, /* streamtab */
1907c478bd9Sstevel@tonic-gate D_MP | D_NEW
1917c478bd9Sstevel@tonic-gate };
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate static struct dev_ops mouse8042_ops = {
1957c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */
1967c478bd9Sstevel@tonic-gate 0, /* refcnt */
1977c478bd9Sstevel@tonic-gate mouse8042_getinfo, /* getinfo */
1987c478bd9Sstevel@tonic-gate nulldev, /* identify */
1997c478bd9Sstevel@tonic-gate nulldev, /* probe */
2007c478bd9Sstevel@tonic-gate mouse8042_attach, /* attach */
2017c478bd9Sstevel@tonic-gate mouse8042_detach, /* detach */
2027c478bd9Sstevel@tonic-gate nodev, /* reset */
2037c478bd9Sstevel@tonic-gate &mouse8042_cb_ops, /* driver operations */
20419397407SSherry Moore (struct bus_ops *)0, /* bus operations */
20519397407SSherry Moore NULL, /* power */
20619397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */
2077c478bd9Sstevel@tonic-gate };
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate * This is the loadable module wrapper.
2117c478bd9Sstevel@tonic-gate */
2127c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate * Module linkage information for the kernel.
2187c478bd9Sstevel@tonic-gate */
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
2217c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
22219397407SSherry Moore "PS/2 Mouse",
2237c478bd9Sstevel@tonic-gate &mouse8042_ops, /* driver ops */
2247c478bd9Sstevel@tonic-gate };
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
2277c478bd9Sstevel@tonic-gate MODREV_1,
2287c478bd9Sstevel@tonic-gate (void *)&modldrv,
2297c478bd9Sstevel@tonic-gate NULL
2307c478bd9Sstevel@tonic-gate };
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate /*
2337c478bd9Sstevel@tonic-gate * This is the driver initialization routine.
2347c478bd9Sstevel@tonic-gate */
2357c478bd9Sstevel@tonic-gate int
_init()2367c478bd9Sstevel@tonic-gate _init()
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate int rv;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate rv = mod_install(&modlinkage);
2417c478bd9Sstevel@tonic-gate return (rv);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate int
_fini(void)2467c478bd9Sstevel@tonic-gate _fini(void)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage));
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2537c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate static int
mouse8042_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2597c478bd9Sstevel@tonic-gate mouse8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate struct mouse_state *state;
262fd9cb95cSsethg mblk_t *mp;
2637c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
2647c478bd9Sstevel@tonic-gate static ddi_device_acc_attr_t attr = {
2657c478bd9Sstevel@tonic-gate DDI_DEVICE_ATTR_V0,
2667c478bd9Sstevel@tonic-gate DDI_NEVERSWAP_ACC,
2677c478bd9Sstevel@tonic-gate DDI_STRICTORDER_ACC,
2687c478bd9Sstevel@tonic-gate };
2697c478bd9Sstevel@tonic-gate int rc;
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate
272fd9cb95cSsethg if (cmd == DDI_RESUME) {
273fd9cb95cSsethg state = (struct mouse_state *)ddi_get_driver_private(dip);
274fd9cb95cSsethg
27515bfc6b7SSeth Goldberg /* Ready to handle inbound data from mouse8042_intr */
27615bfc6b7SSeth Goldberg state->ready = 1;
27715bfc6b7SSeth Goldberg
278fd9cb95cSsethg /*
279fd9cb95cSsethg * Send a 0xaa 0x00 upstream.
280fd9cb95cSsethg * This causes the vuid module to reset the mouse.
281fd9cb95cSsethg */
282fd9cb95cSsethg if (state->ms_rqp != NULL) {
283fd9cb95cSsethg if (mp = allocb(1, BPRI_MED)) {
284fd9cb95cSsethg *mp->b_wptr++ = 0xaa;
285fd9cb95cSsethg putnext(state->ms_rqp, mp);
286fd9cb95cSsethg }
287fd9cb95cSsethg if (mp = allocb(1, BPRI_MED)) {
288fd9cb95cSsethg *mp->b_wptr++ = 0x0;
289fd9cb95cSsethg putnext(state->ms_rqp, mp);
290fd9cb95cSsethg }
291fd9cb95cSsethg }
292fd9cb95cSsethg return (DDI_SUCCESS);
293fd9cb95cSsethg }
294fd9cb95cSsethg
2957c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH)
2967c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate if (mouse8042_dip != NULL)
2997c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate /* allocate and initialize state structure */
3027c478bd9Sstevel@tonic-gate state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP);
3037c478bd9Sstevel@tonic-gate state->ms_opened = B_FALSE;
30415bfc6b7SSeth Goldberg state->reset_state = MSE_RESET_IDLE;
30515bfc6b7SSeth Goldberg state->reset_tid = 0;
30615bfc6b7SSeth Goldberg state->bc_id = 0;
3077c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, state);
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate * In order to support virtual keyboard/mouse, we should distinguish
3117c478bd9Sstevel@tonic-gate * between internal virtual open and external physical open.
3127c478bd9Sstevel@tonic-gate *
3137c478bd9Sstevel@tonic-gate * When the physical devices are opened by application, they will
3147c478bd9Sstevel@tonic-gate * be unlinked from the virtual device and their data stream will
3157c478bd9Sstevel@tonic-gate * not be sent to the virtual device. When the opened physical
3167c478bd9Sstevel@tonic-gate * devices are closed, they will be relinked to the virtual devices.
3177c478bd9Sstevel@tonic-gate *
3187c478bd9Sstevel@tonic-gate * All these automatic switch between virtual and physical are
3197c478bd9Sstevel@tonic-gate * transparent.
3207c478bd9Sstevel@tonic-gate *
3217c478bd9Sstevel@tonic-gate * So we change minor node numbering scheme to be:
3227c478bd9Sstevel@tonic-gate * external node minor num == instance * 2
3237c478bd9Sstevel@tonic-gate * internal node minor num == instance * 2 + 1
3247c478bd9Sstevel@tonic-gate */
325fd9cb95cSsethg rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2,
3267c478bd9Sstevel@tonic-gate DDI_NT_MOUSE, NULL);
3277c478bd9Sstevel@tonic-gate if (rc != DDI_SUCCESS) {
3287c478bd9Sstevel@tonic-gate goto fail_1;
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR,
3327c478bd9Sstevel@tonic-gate instance * 2 + 1) != DDI_SUCCESS) {
3337c478bd9Sstevel@tonic-gate goto fail_2;
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr,
3377c478bd9Sstevel@tonic-gate (offset_t)0, (offset_t)0, &attr, &state->ms_handle);
3387c478bd9Sstevel@tonic-gate if (rc != DDI_SUCCESS) {
3397c478bd9Sstevel@tonic-gate goto fail_2;
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie);
3437c478bd9Sstevel@tonic-gate if (rc != DDI_SUCCESS) {
3447c478bd9Sstevel@tonic-gate goto fail_3;
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER,
3487c478bd9Sstevel@tonic-gate state->ms_iblock_cookie);
34915bfc6b7SSeth Goldberg mutex_init(&state->reset_mutex, NULL, MUTEX_DRIVER,
35015bfc6b7SSeth Goldberg state->ms_iblock_cookie);
351*5b81b7caSSeth Goldberg cv_init(&state->reset_cv, NULL, CV_DRIVER, NULL);
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate rc = ddi_add_intr(dip, 0,
3547c478bd9Sstevel@tonic-gate (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL,
3557c478bd9Sstevel@tonic-gate mouse8042_intr, (caddr_t)state);
3567c478bd9Sstevel@tonic-gate if (rc != DDI_SUCCESS) {
3577c478bd9Sstevel@tonic-gate goto fail_3;
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate mouse8042_dip = dip;
3617c478bd9Sstevel@tonic-gate
36215bfc6b7SSeth Goldberg /* Ready to handle inbound data from mouse8042_intr */
36315bfc6b7SSeth Goldberg state->ready = 1;
36415bfc6b7SSeth Goldberg
3657c478bd9Sstevel@tonic-gate /* Now that we're attached, announce our presence to the world. */
3667c478bd9Sstevel@tonic-gate ddi_report_dev(dip);
3677c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate fail_3:
3707c478bd9Sstevel@tonic-gate ddi_regs_map_free(&state->ms_handle);
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate fail_2:
3737c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL);
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate fail_1:
3767c478bd9Sstevel@tonic-gate kmem_free(state, sizeof (struct mouse_state));
3777c478bd9Sstevel@tonic-gate return (rc);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3817c478bd9Sstevel@tonic-gate static int
mouse8042_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3827c478bd9Sstevel@tonic-gate mouse8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3837c478bd9Sstevel@tonic-gate {
3847c478bd9Sstevel@tonic-gate struct mouse_state *state;
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate state = ddi_get_driver_private(dip);
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate switch (cmd) {
389fd9cb95cSsethg case DDI_SUSPEND:
39015bfc6b7SSeth Goldberg /* Ignore all data from mouse8042_intr until we fully resume */
39115bfc6b7SSeth Goldberg state->ready = 0;
392fd9cb95cSsethg return (DDI_SUCCESS);
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate case DDI_DETACH:
3957c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, state->ms_iblock_cookie);
3967c478bd9Sstevel@tonic-gate mouse8042_dip = NULL;
397*5b81b7caSSeth Goldberg cv_destroy(&state->reset_cv);
39815bfc6b7SSeth Goldberg mutex_destroy(&state->reset_mutex);
3997c478bd9Sstevel@tonic-gate mutex_destroy(&state->ms_mutex);
4007c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip);
4017c478bd9Sstevel@tonic-gate ddi_regs_map_free(&state->ms_handle);
4027c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL);
4037c478bd9Sstevel@tonic-gate kmem_free(state, sizeof (struct mouse_state));
4047c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate default:
4077c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate /* ARGSUSED */
4137c478bd9Sstevel@tonic-gate static int
mouse8042_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4147c478bd9Sstevel@tonic-gate mouse8042_getinfo(
4157c478bd9Sstevel@tonic-gate dev_info_t *dip,
4167c478bd9Sstevel@tonic-gate ddi_info_cmd_t infocmd,
4177c478bd9Sstevel@tonic-gate void *arg,
4187c478bd9Sstevel@tonic-gate void **result)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate dev_t dev = (dev_t)arg;
4217c478bd9Sstevel@tonic-gate minor_t minor = getminor(dev);
4227c478bd9Sstevel@tonic-gate int instance = MOUSE8042_MINOR_TO_INSTANCE(minor);
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate switch (infocmd) {
4257c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
4267c478bd9Sstevel@tonic-gate if (mouse8042_dip == NULL)
4277c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate *result = (void *)mouse8042_dip;
4307c478bd9Sstevel@tonic-gate break;
4317c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
4327c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance;
4337c478bd9Sstevel@tonic-gate break;
4347c478bd9Sstevel@tonic-gate default:
4357c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4417c478bd9Sstevel@tonic-gate static int
mouse8042_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * cred_p)4427c478bd9Sstevel@tonic-gate mouse8042_open(
4437c478bd9Sstevel@tonic-gate queue_t *q,
4447c478bd9Sstevel@tonic-gate dev_t *devp,
4457c478bd9Sstevel@tonic-gate int flag,
4467c478bd9Sstevel@tonic-gate int sflag,
4477c478bd9Sstevel@tonic-gate cred_t *cred_p)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate struct mouse_state *state;
4507c478bd9Sstevel@tonic-gate minor_t minor = getminor(*devp);
4517c478bd9Sstevel@tonic-gate int rval;
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate if (mouse8042_dip == NULL)
4547c478bd9Sstevel@tonic-gate return (ENXIO);
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate state = ddi_get_driver_private(mouse8042_dip);
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate mutex_enter(&state->ms_mutex);
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate if (state->ms_opened) {
4617c478bd9Sstevel@tonic-gate /*
4627c478bd9Sstevel@tonic-gate * Exit if the same minor node is already open
4637c478bd9Sstevel@tonic-gate */
4647c478bd9Sstevel@tonic-gate if (state->ms_minor == minor) {
4657c478bd9Sstevel@tonic-gate mutex_exit(&state->ms_mutex);
4667c478bd9Sstevel@tonic-gate return (0);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate * Check whether it is switch between physical and virtual
4717c478bd9Sstevel@tonic-gate *
4727c478bd9Sstevel@tonic-gate * Opening from virtual while the device is being physically
4737c478bd9Sstevel@tonic-gate * opened by an application should not happen. So we ASSERT
4747c478bd9Sstevel@tonic-gate * this in DEBUG version, and return error in the non-DEBUG
4757c478bd9Sstevel@tonic-gate * case.
4767c478bd9Sstevel@tonic-gate */
4777c478bd9Sstevel@tonic-gate ASSERT(!MOUSE8042_INTERNAL_OPEN(minor));
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate if (MOUSE8042_INTERNAL_OPEN(minor)) {
4807c478bd9Sstevel@tonic-gate mutex_exit(&state->ms_mutex);
4817c478bd9Sstevel@tonic-gate return (EINVAL);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate * Opening the physical one while it is being underneath
4867c478bd9Sstevel@tonic-gate * the virtual one.
4877c478bd9Sstevel@tonic-gate *
4887c478bd9Sstevel@tonic-gate * consconfig_unlink is called to unlink this device from
4897c478bd9Sstevel@tonic-gate * the virtual one, thus the old stream serving for this
4907c478bd9Sstevel@tonic-gate * device under the virtual one is closed, and then the
4917c478bd9Sstevel@tonic-gate * lower driver's close routine (here is mouse8042_close)
4927c478bd9Sstevel@tonic-gate * is also called to accomplish the whole stream close.
4937c478bd9Sstevel@tonic-gate * Here we have to drop the lock because mouse8042_close
4947c478bd9Sstevel@tonic-gate * also needs the lock.
4957c478bd9Sstevel@tonic-gate *
4967c478bd9Sstevel@tonic-gate * For mouse, the old stream is:
4977c478bd9Sstevel@tonic-gate * consms->["pushmod"->]"mouse_vp driver"
4987c478bd9Sstevel@tonic-gate *
4997c478bd9Sstevel@tonic-gate * After the consconfig_unlink returns, the old stream is closed
5007c478bd9Sstevel@tonic-gate * and we grab the lock again to reopen this device as normal.
5017c478bd9Sstevel@tonic-gate */
5027c478bd9Sstevel@tonic-gate mutex_exit(&state->ms_mutex);
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate * If unlink fails, fail the physical open.
5067c478bd9Sstevel@tonic-gate */
5077c478bd9Sstevel@tonic-gate if ((rval = consconfig_unlink(ddi_driver_major(mouse8042_dip),
5087c478bd9Sstevel@tonic-gate MOUSE8042_INTERNAL_MINOR(minor))) != 0) {
5097c478bd9Sstevel@tonic-gate return (rval);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate mutex_enter(&state->ms_mutex);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate q->q_ptr = (caddr_t)state;
5177c478bd9Sstevel@tonic-gate WR(q)->q_ptr = (caddr_t)state;
5187c478bd9Sstevel@tonic-gate state->ms_rqp = q;
5197c478bd9Sstevel@tonic-gate state->ms_wqp = WR(q);
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate qprocson(q);
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate state->ms_minor = minor;
5247c478bd9Sstevel@tonic-gate state->ms_opened = B_TRUE;
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate mutex_exit(&state->ms_mutex);
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate return (0);
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5337c478bd9Sstevel@tonic-gate static int
mouse8042_close(queue_t * q,int flag,cred_t * cred_p)5347c478bd9Sstevel@tonic-gate mouse8042_close(queue_t *q, int flag, cred_t *cred_p)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate struct mouse_state *state;
5377c478bd9Sstevel@tonic-gate minor_t minor;
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate state = (struct mouse_state *)q->q_ptr;
5407c478bd9Sstevel@tonic-gate
541*5b81b7caSSeth Goldberg /*
542*5b81b7caSSeth Goldberg * Disable queue processing now, so that another reset cannot get in
543*5b81b7caSSeth Goldberg * after we wait for the current reset (if any) to complete.
544*5b81b7caSSeth Goldberg */
5457c478bd9Sstevel@tonic-gate qprocsoff(q);
5467c478bd9Sstevel@tonic-gate
547*5b81b7caSSeth Goldberg mutex_enter(&state->reset_mutex);
548*5b81b7caSSeth Goldberg while (state->reset_state != MSE_RESET_IDLE) {
549*5b81b7caSSeth Goldberg /*
550*5b81b7caSSeth Goldberg * Waiting for the previous reset to finish is
551*5b81b7caSSeth Goldberg * non-interruptible. Some upper-level clients
552*5b81b7caSSeth Goldberg * cannot deal with EINTR and will not close the
553*5b81b7caSSeth Goldberg * STREAM properly, resulting in failure to reopen it
554*5b81b7caSSeth Goldberg * within the same process.
555*5b81b7caSSeth Goldberg */
556*5b81b7caSSeth Goldberg cv_wait(&state->reset_cv, &state->reset_mutex);
557*5b81b7caSSeth Goldberg }
558*5b81b7caSSeth Goldberg
55915bfc6b7SSeth Goldberg if (state->reset_tid != 0) {
56015bfc6b7SSeth Goldberg (void) quntimeout(q, state->reset_tid);
56115bfc6b7SSeth Goldberg state->reset_tid = 0;
56215bfc6b7SSeth Goldberg }
563*5b81b7caSSeth Goldberg
56415bfc6b7SSeth Goldberg if (state->reply_mp != NULL) {
56515bfc6b7SSeth Goldberg freemsg(state->reply_mp);
56615bfc6b7SSeth Goldberg state->reply_mp = NULL;
56715bfc6b7SSeth Goldberg }
56815bfc6b7SSeth Goldberg
569*5b81b7caSSeth Goldberg if (state->reset_ack_mp != NULL) {
570*5b81b7caSSeth Goldberg freemsg(state->reset_ack_mp);
571*5b81b7caSSeth Goldberg state->reset_ack_mp = NULL;
572*5b81b7caSSeth Goldberg }
573*5b81b7caSSeth Goldberg
574*5b81b7caSSeth Goldberg mutex_exit(&state->reset_mutex);
575*5b81b7caSSeth Goldberg
576*5b81b7caSSeth Goldberg mutex_enter(&state->ms_mutex);
577*5b81b7caSSeth Goldberg
578*5b81b7caSSeth Goldberg if (state->bc_id != 0) {
579*5b81b7caSSeth Goldberg (void) qunbufcall(q, state->bc_id);
580*5b81b7caSSeth Goldberg state->bc_id = 0;
581*5b81b7caSSeth Goldberg }
582*5b81b7caSSeth Goldberg
5837c478bd9Sstevel@tonic-gate q->q_ptr = NULL;
5847c478bd9Sstevel@tonic-gate WR(q)->q_ptr = NULL;
5857c478bd9Sstevel@tonic-gate state->ms_rqp = NULL;
5867c478bd9Sstevel@tonic-gate state->ms_wqp = NULL;
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate state->ms_opened = B_FALSE;
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate minor = state->ms_minor;
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate mutex_exit(&state->ms_mutex);
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate if (!MOUSE8042_INTERNAL_OPEN(minor)) {
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * Closing physical PS/2 mouse
5977c478bd9Sstevel@tonic-gate *
5987c478bd9Sstevel@tonic-gate * Link it back to virtual mouse, and
5997c478bd9Sstevel@tonic-gate * mouse8042_open will be called as a result
600fd9cb95cSsethg * of the consconfig_link call. Do NOT try
601fd9cb95cSsethg * this if the mouse is about to be detached!
6027c478bd9Sstevel@tonic-gate *
6037c478bd9Sstevel@tonic-gate * If linking back fails, this specific mouse
6047c478bd9Sstevel@tonic-gate * will not be available underneath the virtual
6057c478bd9Sstevel@tonic-gate * mouse, and can only be accessed via physical
6067c478bd9Sstevel@tonic-gate * open.
6077c478bd9Sstevel@tonic-gate */
6087c478bd9Sstevel@tonic-gate consconfig_link(ddi_driver_major(mouse8042_dip),
6097c478bd9Sstevel@tonic-gate MOUSE8042_INTERNAL_MINOR(minor));
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate return (0);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate static void
mouse8042_iocnack(queue_t * qp,mblk_t * mp,struct iocblk * iocp,int error,int rval)6167c478bd9Sstevel@tonic-gate mouse8042_iocnack(
6177c478bd9Sstevel@tonic-gate queue_t *qp,
6187c478bd9Sstevel@tonic-gate mblk_t *mp,
6197c478bd9Sstevel@tonic-gate struct iocblk *iocp,
6207c478bd9Sstevel@tonic-gate int error,
6217c478bd9Sstevel@tonic-gate int rval)
6227c478bd9Sstevel@tonic-gate {
6237c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK;
6247c478bd9Sstevel@tonic-gate iocp->ioc_rval = rval;
6257c478bd9Sstevel@tonic-gate iocp->ioc_error = error;
6267c478bd9Sstevel@tonic-gate qreply(qp, mp);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
62915bfc6b7SSeth Goldberg static void
mouse8042_reset_timeout(void * argp)63015bfc6b7SSeth Goldberg mouse8042_reset_timeout(void *argp)
6317c478bd9Sstevel@tonic-gate {
63215bfc6b7SSeth Goldberg struct mouse_state *state = (struct mouse_state *)argp;
63315bfc6b7SSeth Goldberg mblk_t *mp;
63415bfc6b7SSeth Goldberg
63515bfc6b7SSeth Goldberg mutex_enter(&state->reset_mutex);
63615bfc6b7SSeth Goldberg
63715bfc6b7SSeth Goldberg /*
63815bfc6b7SSeth Goldberg * If the interrupt handler hasn't completed the reset handling
63915bfc6b7SSeth Goldberg * (reset_state would be IDLE or FAILED in that case), then
64015bfc6b7SSeth Goldberg * drop the 8042 lock, and send a faked retry reply upstream,
64115bfc6b7SSeth Goldberg * then enable the queue for further message processing.
64215bfc6b7SSeth Goldberg */
64315bfc6b7SSeth Goldberg if (state->reset_state != MSE_RESET_IDLE &&
64415bfc6b7SSeth Goldberg state->reset_state != MSE_RESET_FAILED) {
64515bfc6b7SSeth Goldberg
64615bfc6b7SSeth Goldberg state->reset_tid = 0;
64715bfc6b7SSeth Goldberg state->reset_state = MSE_RESET_IDLE;
648*5b81b7caSSeth Goldberg cv_signal(&state->reset_cv);
64915bfc6b7SSeth Goldberg
65015bfc6b7SSeth Goldberg (void) ddi_get8(state->ms_handle, state->ms_addr +
65115bfc6b7SSeth Goldberg I8042_UNLOCK);
65215bfc6b7SSeth Goldberg
65315bfc6b7SSeth Goldberg mp = state->reply_mp;
65415bfc6b7SSeth Goldberg *mp->b_wptr++ = MSERESEND;
65515bfc6b7SSeth Goldberg state->reply_mp = NULL;
65615bfc6b7SSeth Goldberg
65715bfc6b7SSeth Goldberg if (state->ms_rqp != NULL)
65815bfc6b7SSeth Goldberg putnext(state->ms_rqp, mp);
65915bfc6b7SSeth Goldberg else
66015bfc6b7SSeth Goldberg freemsg(mp);
66115bfc6b7SSeth Goldberg
66215bfc6b7SSeth Goldberg ASSERT(state->ms_wqp != NULL);
66315bfc6b7SSeth Goldberg
66415bfc6b7SSeth Goldberg enableok(state->ms_wqp);
66515bfc6b7SSeth Goldberg qenable(state->ms_wqp);
66615bfc6b7SSeth Goldberg }
66715bfc6b7SSeth Goldberg
66815bfc6b7SSeth Goldberg mutex_exit(&state->reset_mutex);
66915bfc6b7SSeth Goldberg }
67015bfc6b7SSeth Goldberg
67115bfc6b7SSeth Goldberg /*
67215bfc6b7SSeth Goldberg * Returns 1 if the caller should put the message (bp) back on the queue
67315bfc6b7SSeth Goldberg */
67415bfc6b7SSeth Goldberg static int
mouse8042_initiate_reset(queue_t * q,mblk_t * mp,struct mouse_state * state)675*5b81b7caSSeth Goldberg mouse8042_initiate_reset(queue_t *q, mblk_t *mp, struct mouse_state *state)
67615bfc6b7SSeth Goldberg {
67715bfc6b7SSeth Goldberg mutex_enter(&state->reset_mutex);
67815bfc6b7SSeth Goldberg /*
67915bfc6b7SSeth Goldberg * If we're in the middle of a reset, put the message back on the queue
68015bfc6b7SSeth Goldberg * for processing later.
68115bfc6b7SSeth Goldberg */
68215bfc6b7SSeth Goldberg if (state->reset_state != MSE_RESET_IDLE) {
68315bfc6b7SSeth Goldberg /*
68415bfc6b7SSeth Goldberg * We noenable the queue again here in case it was backenabled
68515bfc6b7SSeth Goldberg * by an upper-level module.
68615bfc6b7SSeth Goldberg */
68715bfc6b7SSeth Goldberg noenable(q);
68815bfc6b7SSeth Goldberg
68915bfc6b7SSeth Goldberg mutex_exit(&state->reset_mutex);
69015bfc6b7SSeth Goldberg return (1);
69115bfc6b7SSeth Goldberg }
69215bfc6b7SSeth Goldberg
69315bfc6b7SSeth Goldberg /*
69415bfc6b7SSeth Goldberg * Drop the reset state lock before allocating the response message and
69515bfc6b7SSeth Goldberg * grabbing the 8042 exclusive-access lock (since those operations
69615bfc6b7SSeth Goldberg * may take an extended period of time to complete).
69715bfc6b7SSeth Goldberg */
69815bfc6b7SSeth Goldberg mutex_exit(&state->reset_mutex);
69915bfc6b7SSeth Goldberg
700*5b81b7caSSeth Goldberg if (state->reply_mp == NULL)
701*5b81b7caSSeth Goldberg state->reply_mp = allocb(2, BPRI_MED);
702*5b81b7caSSeth Goldberg if (state->reset_ack_mp == NULL)
703*5b81b7caSSeth Goldberg state->reset_ack_mp = allocb(1, BPRI_MED);
704*5b81b7caSSeth Goldberg
705*5b81b7caSSeth Goldberg if (state->reply_mp == NULL || state->reset_ack_mp == NULL) {
70615bfc6b7SSeth Goldberg /*
70715bfc6b7SSeth Goldberg * Allocation failed -- set up a bufcall to enable the queue
70815bfc6b7SSeth Goldberg * whenever there is enough memory to allocate the response
70915bfc6b7SSeth Goldberg * message.
71015bfc6b7SSeth Goldberg */
711*5b81b7caSSeth Goldberg state->bc_id = qbufcall(q, (state->reply_mp == NULL) ? 2 : 1,
712*5b81b7caSSeth Goldberg BPRI_MED, (void (*)(void *))qenable, q);
71315bfc6b7SSeth Goldberg
71415bfc6b7SSeth Goldberg if (state->bc_id == 0) {
71515bfc6b7SSeth Goldberg /*
71615bfc6b7SSeth Goldberg * If the qbufcall failed, we cannot proceed, so use the
71715bfc6b7SSeth Goldberg * message we were sent to respond with an error.
71815bfc6b7SSeth Goldberg */
71915bfc6b7SSeth Goldberg *mp->b_rptr = MSEERROR;
72015bfc6b7SSeth Goldberg mp->b_wptr = mp->b_rptr + 1;
72115bfc6b7SSeth Goldberg qreply(q, mp);
72215bfc6b7SSeth Goldberg return (0);
72315bfc6b7SSeth Goldberg }
72415bfc6b7SSeth Goldberg
72515bfc6b7SSeth Goldberg return (1);
726*5b81b7caSSeth Goldberg } else {
727*5b81b7caSSeth Goldberg /* Bufcall completed successfully (or wasn't needed) */
728*5b81b7caSSeth Goldberg state->bc_id = 0;
72915bfc6b7SSeth Goldberg }
73015bfc6b7SSeth Goldberg
73115bfc6b7SSeth Goldberg /*
73215bfc6b7SSeth Goldberg * Gain exclusive access to the 8042 for the duration of the reset.
73315bfc6b7SSeth Goldberg * The unlock will occur when the reset has either completed or timed
73415bfc6b7SSeth Goldberg * out.
73515bfc6b7SSeth Goldberg */
73615bfc6b7SSeth Goldberg (void) ddi_get8(state->ms_handle,
73715bfc6b7SSeth Goldberg state->ms_addr + I8042_LOCK);
73815bfc6b7SSeth Goldberg
73915bfc6b7SSeth Goldberg mutex_enter(&state->reset_mutex);
74015bfc6b7SSeth Goldberg
74115bfc6b7SSeth Goldberg state->reset_state = MSE_RESET_PRE;
74215bfc6b7SSeth Goldberg noenable(q);
74315bfc6b7SSeth Goldberg
74415bfc6b7SSeth Goldberg state->reset_tid = qtimeout(q,
74515bfc6b7SSeth Goldberg mouse8042_reset_timeout,
74615bfc6b7SSeth Goldberg state,
74715bfc6b7SSeth Goldberg drv_usectohz(
74815bfc6b7SSeth Goldberg MOUSE8042_RESET_TIMEOUT_USECS));
74915bfc6b7SSeth Goldberg
75015bfc6b7SSeth Goldberg ddi_put8(state->ms_handle,
75115bfc6b7SSeth Goldberg state->ms_addr +
75215bfc6b7SSeth Goldberg I8042_INT_OUTPUT_DATA, MSERESET);
75315bfc6b7SSeth Goldberg
75415bfc6b7SSeth Goldberg mp->b_rptr++;
75515bfc6b7SSeth Goldberg
75615bfc6b7SSeth Goldberg mutex_exit(&state->reset_mutex);
75715bfc6b7SSeth Goldberg return (1);
75815bfc6b7SSeth Goldberg }
75915bfc6b7SSeth Goldberg
76015bfc6b7SSeth Goldberg /*
76115bfc6b7SSeth Goldberg * Returns 1 if the caller should stop processing messages
76215bfc6b7SSeth Goldberg */
76315bfc6b7SSeth Goldberg static int
mouse8042_process_data_msg(queue_t * q,mblk_t * mp,struct mouse_state * state)76415bfc6b7SSeth Goldberg mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
76515bfc6b7SSeth Goldberg {
7667c478bd9Sstevel@tonic-gate mblk_t *bp;
7677c478bd9Sstevel@tonic-gate mblk_t *next;
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate bp = mp;
7707c478bd9Sstevel@tonic-gate do {
7717c478bd9Sstevel@tonic-gate while (bp->b_rptr < bp->b_wptr) {
77215bfc6b7SSeth Goldberg /*
77315bfc6b7SSeth Goldberg * Detect an attempt to reset the mouse. Lock out any
77415bfc6b7SSeth Goldberg * further mouse writes until the reset has completed.
77515bfc6b7SSeth Goldberg */
77615bfc6b7SSeth Goldberg if (*bp->b_rptr == MSERESET) {
77715bfc6b7SSeth Goldberg
77815bfc6b7SSeth Goldberg /*
77915bfc6b7SSeth Goldberg * If we couldn't allocate memory and we
78015bfc6b7SSeth Goldberg * we couldn't register a bufcall,
781*5b81b7caSSeth Goldberg * mouse8042_initiate_reset returns 0 and
78215bfc6b7SSeth Goldberg * has already used the message to send an
78315bfc6b7SSeth Goldberg * error reply back upstream, so there is no
78415bfc6b7SSeth Goldberg * need to deallocate or put this message back
78515bfc6b7SSeth Goldberg * on the queue.
78615bfc6b7SSeth Goldberg */
787*5b81b7caSSeth Goldberg if (mouse8042_initiate_reset(q, bp, state) == 0)
78815bfc6b7SSeth Goldberg return (1);
78915bfc6b7SSeth Goldberg
79015bfc6b7SSeth Goldberg /*
79115bfc6b7SSeth Goldberg * If there's no data remaining in this block,
79215bfc6b7SSeth Goldberg * free this block and put the following blocks
79315bfc6b7SSeth Goldberg * of this message back on the queue. If putting
79415bfc6b7SSeth Goldberg * the rest of the message back on the queue
79515bfc6b7SSeth Goldberg * fails, free the the message.
79615bfc6b7SSeth Goldberg */
79715bfc6b7SSeth Goldberg if (MBLKL(bp) == 0) {
79815bfc6b7SSeth Goldberg next = bp->b_cont;
79915bfc6b7SSeth Goldberg freeb(bp);
80015bfc6b7SSeth Goldberg bp = next;
8017c478bd9Sstevel@tonic-gate }
80215bfc6b7SSeth Goldberg if (bp != NULL) {
80315bfc6b7SSeth Goldberg if (!putbq(q, bp))
80415bfc6b7SSeth Goldberg freemsg(bp);
8057c478bd9Sstevel@tonic-gate }
80615bfc6b7SSeth Goldberg
80715bfc6b7SSeth Goldberg return (1);
80815bfc6b7SSeth Goldberg
80915bfc6b7SSeth Goldberg }
8107c478bd9Sstevel@tonic-gate ddi_put8(state->ms_handle,
8117c478bd9Sstevel@tonic-gate state->ms_addr + I8042_INT_OUTPUT_DATA,
8127c478bd9Sstevel@tonic-gate *bp->b_rptr++);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate next = bp->b_cont;
8157c478bd9Sstevel@tonic-gate freeb(bp);
8167c478bd9Sstevel@tonic-gate } while ((bp = next) != NULL);
81715bfc6b7SSeth Goldberg
81815bfc6b7SSeth Goldberg return (0);
81915bfc6b7SSeth Goldberg }
82015bfc6b7SSeth Goldberg
82115bfc6b7SSeth Goldberg static int
mouse8042_process_msg(queue_t * q,mblk_t * mp,struct mouse_state * state)82215bfc6b7SSeth Goldberg mouse8042_process_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
82315bfc6b7SSeth Goldberg {
82415bfc6b7SSeth Goldberg struct iocblk *iocbp;
82515bfc6b7SSeth Goldberg int rv = 0;
82615bfc6b7SSeth Goldberg
82715bfc6b7SSeth Goldberg iocbp = (struct iocblk *)mp->b_rptr;
82815bfc6b7SSeth Goldberg
82915bfc6b7SSeth Goldberg switch (mp->b_datap->db_type) {
83015bfc6b7SSeth Goldberg case M_FLUSH:
83115bfc6b7SSeth Goldberg if (*mp->b_rptr & FLUSHW) {
83215bfc6b7SSeth Goldberg flushq(q, FLUSHDATA);
83315bfc6b7SSeth Goldberg *mp->b_rptr &= ~FLUSHW;
83415bfc6b7SSeth Goldberg }
83515bfc6b7SSeth Goldberg if (*mp->b_rptr & FLUSHR) {
83615bfc6b7SSeth Goldberg qreply(q, mp);
83715bfc6b7SSeth Goldberg } else
83815bfc6b7SSeth Goldberg freemsg(mp);
83915bfc6b7SSeth Goldberg break;
84015bfc6b7SSeth Goldberg case M_IOCTL:
84115bfc6b7SSeth Goldberg mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
84215bfc6b7SSeth Goldberg break;
84315bfc6b7SSeth Goldberg case M_IOCDATA:
84415bfc6b7SSeth Goldberg mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
84515bfc6b7SSeth Goldberg break;
84615bfc6b7SSeth Goldberg case M_DATA:
84715bfc6b7SSeth Goldberg rv = mouse8042_process_data_msg(q, mp, state);
8487c478bd9Sstevel@tonic-gate break;
8497c478bd9Sstevel@tonic-gate default:
8507c478bd9Sstevel@tonic-gate freemsg(mp);
8517c478bd9Sstevel@tonic-gate break;
8527c478bd9Sstevel@tonic-gate }
85315bfc6b7SSeth Goldberg
85415bfc6b7SSeth Goldberg return (rv);
85515bfc6b7SSeth Goldberg }
85615bfc6b7SSeth Goldberg
857*5b81b7caSSeth Goldberg /*
858*5b81b7caSSeth Goldberg * This is the main mouse input routine. Commands and parameters
859*5b81b7caSSeth Goldberg * from upstream are sent to the mouse device immediately, unless
860*5b81b7caSSeth Goldberg * the mouse is in the process of being reset, in which case
861*5b81b7caSSeth Goldberg * commands are queued and executed later in the service procedure.
862*5b81b7caSSeth Goldberg */
863*5b81b7caSSeth Goldberg static int
mouse8042_wput(queue_t * q,mblk_t * mp)864*5b81b7caSSeth Goldberg mouse8042_wput(queue_t *q, mblk_t *mp)
865*5b81b7caSSeth Goldberg {
866*5b81b7caSSeth Goldberg struct mouse_state *state;
867*5b81b7caSSeth Goldberg state = (struct mouse_state *)q->q_ptr;
868*5b81b7caSSeth Goldberg
869*5b81b7caSSeth Goldberg /*
870*5b81b7caSSeth Goldberg * Process all messages immediately, unless a reset is in
871*5b81b7caSSeth Goldberg * progress. If a reset is in progress, deflect processing to
872*5b81b7caSSeth Goldberg * the service procedure.
873*5b81b7caSSeth Goldberg */
874*5b81b7caSSeth Goldberg if (state->reset_state != MSE_RESET_IDLE)
875*5b81b7caSSeth Goldberg return (putq(q, mp));
876*5b81b7caSSeth Goldberg
877*5b81b7caSSeth Goldberg /*
878*5b81b7caSSeth Goldberg * If there are still messages outstanding in the queue that
879*5b81b7caSSeth Goldberg * the service procedure hasn't processed yet, put this
880*5b81b7caSSeth Goldberg * message in the queue also, to ensure proper message
881*5b81b7caSSeth Goldberg * ordering.
882*5b81b7caSSeth Goldberg */
883*5b81b7caSSeth Goldberg if (q->q_first)
884*5b81b7caSSeth Goldberg return (putq(q, mp));
885*5b81b7caSSeth Goldberg
886*5b81b7caSSeth Goldberg (void) mouse8042_process_msg(q, mp, state);
887*5b81b7caSSeth Goldberg
888*5b81b7caSSeth Goldberg return (0);
889*5b81b7caSSeth Goldberg }
890*5b81b7caSSeth Goldberg
89115bfc6b7SSeth Goldberg static int
mouse8042_wsrv(queue_t * qp)89215bfc6b7SSeth Goldberg mouse8042_wsrv(queue_t *qp)
89315bfc6b7SSeth Goldberg {
89415bfc6b7SSeth Goldberg mblk_t *mp;
89515bfc6b7SSeth Goldberg struct mouse_state *state;
89615bfc6b7SSeth Goldberg state = (struct mouse_state *)qp->q_ptr;
89715bfc6b7SSeth Goldberg
89815bfc6b7SSeth Goldberg while ((mp = getq(qp)) != NULL) {
89915bfc6b7SSeth Goldberg if (mouse8042_process_msg(qp, mp, state) != 0)
90015bfc6b7SSeth Goldberg break;
90115bfc6b7SSeth Goldberg }
90215bfc6b7SSeth Goldberg
90315bfc6b7SSeth Goldberg return (0);
90415bfc6b7SSeth Goldberg }
90515bfc6b7SSeth Goldberg
90615bfc6b7SSeth Goldberg /*
90715bfc6b7SSeth Goldberg * Returns the next reset state, given the current state and the byte
90815bfc6b7SSeth Goldberg * received from the mouse. Error and Resend codes are handled by the
90915bfc6b7SSeth Goldberg * caller.
91015bfc6b7SSeth Goldberg */
91115bfc6b7SSeth Goldberg static mouse8042_reset_state_e
mouse8042_reset_fsm(mouse8042_reset_state_e reset_state,uint8_t mdata)91215bfc6b7SSeth Goldberg mouse8042_reset_fsm(mouse8042_reset_state_e reset_state, uint8_t mdata)
91315bfc6b7SSeth Goldberg {
91415bfc6b7SSeth Goldberg switch (reset_state) {
91515bfc6b7SSeth Goldberg case MSE_RESET_PRE: /* RESET sent, now we expect an ACK */
91615bfc6b7SSeth Goldberg if (mdata == MSE_ACK) /* Got the ACK */
91715bfc6b7SSeth Goldberg return (MSE_RESET_ACK);
91815bfc6b7SSeth Goldberg break;
91915bfc6b7SSeth Goldberg
92015bfc6b7SSeth Goldberg case MSE_RESET_ACK: /* ACK received; now we expect 0xAA */
92115bfc6b7SSeth Goldberg if (mdata == MSE_AA) /* Got the 0xAA */
92215bfc6b7SSeth Goldberg return (MSE_RESET_AA);
92315bfc6b7SSeth Goldberg break;
92415bfc6b7SSeth Goldberg
92515bfc6b7SSeth Goldberg case MSE_RESET_AA: /* 0xAA received; now we expect 0x00 */
92615bfc6b7SSeth Goldberg if (mdata == MSE_00)
92715bfc6b7SSeth Goldberg return (MSE_RESET_IDLE);
92815bfc6b7SSeth Goldberg break;
92915bfc6b7SSeth Goldberg }
93015bfc6b7SSeth Goldberg
93115bfc6b7SSeth Goldberg return (reset_state);
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate static uint_t
mouse8042_intr(caddr_t arg)9357c478bd9Sstevel@tonic-gate mouse8042_intr(caddr_t arg)
9367c478bd9Sstevel@tonic-gate {
9377c478bd9Sstevel@tonic-gate unsigned char mdata;
9387c478bd9Sstevel@tonic-gate mblk_t *mp;
9397c478bd9Sstevel@tonic-gate struct mouse_state *state = (struct mouse_state *)arg;
9407c478bd9Sstevel@tonic-gate int rc;
9417c478bd9Sstevel@tonic-gate
9427c478bd9Sstevel@tonic-gate mutex_enter(&state->ms_mutex);
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate rc = DDI_INTR_UNCLAIMED;
9457c478bd9Sstevel@tonic-gate
9467c478bd9Sstevel@tonic-gate for (;;) {
9477c478bd9Sstevel@tonic-gate
9487c478bd9Sstevel@tonic-gate if (ddi_get8(state->ms_handle,
9497c478bd9Sstevel@tonic-gate state->ms_addr + I8042_INT_INPUT_AVAIL) == 0) {
9507c478bd9Sstevel@tonic-gate break;
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate mdata = ddi_get8(state->ms_handle,
9547c478bd9Sstevel@tonic-gate state->ms_addr + I8042_INT_INPUT_DATA);
9557c478bd9Sstevel@tonic-gate
9567c478bd9Sstevel@tonic-gate rc = DDI_INTR_CLAIMED;
9577c478bd9Sstevel@tonic-gate
95815bfc6b7SSeth Goldberg /*
95915bfc6b7SSeth Goldberg * If we're not ready for this data, discard it.
96015bfc6b7SSeth Goldberg */
96115bfc6b7SSeth Goldberg if (!state->ready)
96215bfc6b7SSeth Goldberg continue;
96315bfc6b7SSeth Goldberg
96415bfc6b7SSeth Goldberg mutex_enter(&state->reset_mutex);
96515bfc6b7SSeth Goldberg if (state->reset_state != MSE_RESET_IDLE) {
96615bfc6b7SSeth Goldberg
96715bfc6b7SSeth Goldberg if (mdata == MSEERROR || mdata == MSERESET) {
96815bfc6b7SSeth Goldberg state->reset_state = MSE_RESET_FAILED;
96915bfc6b7SSeth Goldberg } else {
97015bfc6b7SSeth Goldberg state->reset_state =
97115bfc6b7SSeth Goldberg mouse8042_reset_fsm(state->reset_state,
97215bfc6b7SSeth Goldberg mdata);
97315bfc6b7SSeth Goldberg }
97415bfc6b7SSeth Goldberg
975*5b81b7caSSeth Goldberg if (state->reset_state == MSE_RESET_ACK) {
976*5b81b7caSSeth Goldberg
977*5b81b7caSSeth Goldberg /*
978*5b81b7caSSeth Goldberg * We received an ACK from the mouse, so
979*5b81b7caSSeth Goldberg * send it upstream immediately so that
980*5b81b7caSSeth Goldberg * consumers depending on the immediate
981*5b81b7caSSeth Goldberg * ACK don't time out.
982*5b81b7caSSeth Goldberg */
983*5b81b7caSSeth Goldberg if (state->reset_ack_mp != NULL) {
984*5b81b7caSSeth Goldberg
985*5b81b7caSSeth Goldberg mp = state->reset_ack_mp;
986*5b81b7caSSeth Goldberg
987*5b81b7caSSeth Goldberg state->reset_ack_mp = NULL;
988*5b81b7caSSeth Goldberg
989*5b81b7caSSeth Goldberg if (state->ms_rqp != NULL) {
990*5b81b7caSSeth Goldberg *mp->b_wptr++ = MSE_ACK;
991*5b81b7caSSeth Goldberg putnext(state->ms_rqp, mp);
992*5b81b7caSSeth Goldberg } else
993*5b81b7caSSeth Goldberg freemsg(mp);
994*5b81b7caSSeth Goldberg }
995*5b81b7caSSeth Goldberg
996*5b81b7caSSeth Goldberg if (state->ms_wqp != NULL) {
997*5b81b7caSSeth Goldberg enableok(state->ms_wqp);
998*5b81b7caSSeth Goldberg qenable(state->ms_wqp);
999*5b81b7caSSeth Goldberg }
1000*5b81b7caSSeth Goldberg
1001*5b81b7caSSeth Goldberg } else if (state->reset_state == MSE_RESET_IDLE ||
1002*5b81b7caSSeth Goldberg state->reset_state == MSE_RESET_FAILED) {
1003*5b81b7caSSeth Goldberg
100415bfc6b7SSeth Goldberg /*
100515bfc6b7SSeth Goldberg * If we transitioned back to the idle reset state (or
100615bfc6b7SSeth Goldberg * the reset failed), disable the timeout, release the
100715bfc6b7SSeth Goldberg * 8042 exclusive-access lock, then send the response
100815bfc6b7SSeth Goldberg * the the upper-level modules. Finally, enable the
100915bfc6b7SSeth Goldberg * queue and schedule queue service procedures so that
101015bfc6b7SSeth Goldberg * upper-level modules can process the response.
101115bfc6b7SSeth Goldberg * Otherwise, if we're still in the middle of the
101215bfc6b7SSeth Goldberg * reset sequence, do not send the data up (since the
101315bfc6b7SSeth Goldberg * response is sent at the end of the sequence, or
101415bfc6b7SSeth Goldberg * on timeout/error).
101515bfc6b7SSeth Goldberg */
101615bfc6b7SSeth Goldberg
101715bfc6b7SSeth Goldberg mutex_exit(&state->reset_mutex);
101815bfc6b7SSeth Goldberg (void) quntimeout(state->ms_wqp,
101915bfc6b7SSeth Goldberg state->reset_tid);
102015bfc6b7SSeth Goldberg mutex_enter(&state->reset_mutex);
102115bfc6b7SSeth Goldberg
102215bfc6b7SSeth Goldberg (void) ddi_get8(state->ms_handle,
102315bfc6b7SSeth Goldberg state->ms_addr + I8042_UNLOCK);
102415bfc6b7SSeth Goldberg
102515bfc6b7SSeth Goldberg state->reset_tid = 0;
1026*5b81b7caSSeth Goldberg if (state->reply_mp != NULL) {
102715bfc6b7SSeth Goldberg mp = state->reply_mp;
1028*5b81b7caSSeth Goldberg if (state->reset_state ==
1029*5b81b7caSSeth Goldberg MSE_RESET_FAILED) {
103015bfc6b7SSeth Goldberg *mp->b_wptr++ = mdata;
103115bfc6b7SSeth Goldberg } else {
103215bfc6b7SSeth Goldberg *mp->b_wptr++ = MSE_AA;
103315bfc6b7SSeth Goldberg *mp->b_wptr++ = MSE_00;
103415bfc6b7SSeth Goldberg }
103515bfc6b7SSeth Goldberg state->reply_mp = NULL;
1036*5b81b7caSSeth Goldberg } else {
1037*5b81b7caSSeth Goldberg mp = NULL;
1038*5b81b7caSSeth Goldberg }
103915bfc6b7SSeth Goldberg
104015bfc6b7SSeth Goldberg state->reset_state = MSE_RESET_IDLE;
1041*5b81b7caSSeth Goldberg cv_signal(&state->reset_cv);
104215bfc6b7SSeth Goldberg
1043*5b81b7caSSeth Goldberg if (mp != NULL) {
104415bfc6b7SSeth Goldberg if (state->ms_rqp != NULL)
104515bfc6b7SSeth Goldberg putnext(state->ms_rqp, mp);
104615bfc6b7SSeth Goldberg else
104715bfc6b7SSeth Goldberg freemsg(mp);
1048*5b81b7caSSeth Goldberg }
104915bfc6b7SSeth Goldberg
1050*5b81b7caSSeth Goldberg if (state->ms_wqp != NULL) {
105115bfc6b7SSeth Goldberg enableok(state->ms_wqp);
105215bfc6b7SSeth Goldberg qenable(state->ms_wqp);
105315bfc6b7SSeth Goldberg }
1054*5b81b7caSSeth Goldberg }
105515bfc6b7SSeth Goldberg
105615bfc6b7SSeth Goldberg mutex_exit(&state->reset_mutex);
105715bfc6b7SSeth Goldberg mutex_exit(&state->ms_mutex);
105815bfc6b7SSeth Goldberg return (rc);
105915bfc6b7SSeth Goldberg }
106015bfc6b7SSeth Goldberg mutex_exit(&state->reset_mutex);
106115bfc6b7SSeth Goldberg
10627c478bd9Sstevel@tonic-gate if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) {
10637c478bd9Sstevel@tonic-gate *mp->b_wptr++ = mdata;
10647c478bd9Sstevel@tonic-gate putnext(state->ms_rqp, mp);
10657c478bd9Sstevel@tonic-gate }
10667c478bd9Sstevel@tonic-gate }
10677c478bd9Sstevel@tonic-gate mutex_exit(&state->ms_mutex);
10687c478bd9Sstevel@tonic-gate
10697c478bd9Sstevel@tonic-gate return (rc);
10707c478bd9Sstevel@tonic-gate }
1071