10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 220Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 230Sstevel@tonic-gate /* All Rights Reserved */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate /* 26*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 270Sstevel@tonic-gate * Use is subject to license terms. 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate 310Sstevel@tonic-gate /* 320Sstevel@tonic-gate * PS/2 type Mouse Module - Streams 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <sys/param.h> 360Sstevel@tonic-gate #include <sys/types.h> 370Sstevel@tonic-gate #include <sys/kmem.h> 380Sstevel@tonic-gate #include <sys/signal.h> 390Sstevel@tonic-gate #include <sys/errno.h> 400Sstevel@tonic-gate #include <sys/file.h> 410Sstevel@tonic-gate #include <sys/termio.h> 420Sstevel@tonic-gate #include <sys/stream.h> 430Sstevel@tonic-gate #include <sys/stropts.h> 440Sstevel@tonic-gate #include <sys/strtty.h> 450Sstevel@tonic-gate #include <sys/debug.h> 460Sstevel@tonic-gate #include <sys/ddi.h> 470Sstevel@tonic-gate #include <sys/stat.h> 480Sstevel@tonic-gate #include <sys/cmn_err.h> 490Sstevel@tonic-gate #include <sys/sunddi.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #include <sys/promif.h> 520Sstevel@tonic-gate #include <sys/cred.h> 530Sstevel@tonic-gate 540Sstevel@tonic-gate #include <sys/i8042.h> 550Sstevel@tonic-gate #include <sys/note.h> 560Sstevel@tonic-gate 570Sstevel@tonic-gate #define DRIVER_NAME(dip) ddi_driver_name(dip) 580Sstevel@tonic-gate 590Sstevel@tonic-gate #ifdef DEBUG 600Sstevel@tonic-gate #define MOUSE8042_DEBUG 610Sstevel@tonic-gate #endif 620Sstevel@tonic-gate 630Sstevel@tonic-gate #define MOUSE8042_INTERNAL_OPEN(minor) (((minor) & 0x1) == 1) 640Sstevel@tonic-gate #define MOUSE8042_MINOR_TO_INSTANCE(minor) ((minor) / 2) 650Sstevel@tonic-gate #define MOUSE8042_INTERNAL_MINOR(minor) ((minor) + 1) 660Sstevel@tonic-gate 670Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t); 680Sstevel@tonic-gate extern void consconfig_link(major_t major, minor_t minor); 690Sstevel@tonic-gate extern int consconfig_unlink(major_t major, minor_t minor); 700Sstevel@tonic-gate 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * 740Sstevel@tonic-gate * Local Static Data 750Sstevel@tonic-gate * 760Sstevel@tonic-gate */ 770Sstevel@tonic-gate 780Sstevel@tonic-gate /* 790Sstevel@tonic-gate * We only support one instance. Yes, it's theoretically possible to 800Sstevel@tonic-gate * plug in more than one, but it's not worth the implementation cost. 810Sstevel@tonic-gate * 820Sstevel@tonic-gate * The introduction of USB keyboards might make it worth reassessing 830Sstevel@tonic-gate * this decision, as they might free up the keyboard port for a second 840Sstevel@tonic-gate * PS/2 style mouse. 850Sstevel@tonic-gate */ 860Sstevel@tonic-gate static dev_info_t *mouse8042_dip; 870Sstevel@tonic-gate 880Sstevel@tonic-gate struct mouse_state { 890Sstevel@tonic-gate queue_t *ms_rqp; 900Sstevel@tonic-gate queue_t *ms_wqp; 910Sstevel@tonic-gate ddi_iblock_cookie_t ms_iblock_cookie; 920Sstevel@tonic-gate ddi_acc_handle_t ms_handle; 930Sstevel@tonic-gate uint8_t *ms_addr; 940Sstevel@tonic-gate kmutex_t ms_mutex; 950Sstevel@tonic-gate 960Sstevel@tonic-gate minor_t ms_minor; 970Sstevel@tonic-gate boolean_t ms_opened; 980Sstevel@tonic-gate }; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 1010Sstevel@tonic-gate int mouse8042_debug = 0; 1020Sstevel@tonic-gate int mouse8042_debug_minimal = 0; 1030Sstevel@tonic-gate #endif 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate static uint_t mouse8042_intr(caddr_t arg); 1060Sstevel@tonic-gate static int mouse8042_open(queue_t *q, dev_t *devp, int flag, int sflag, 1070Sstevel@tonic-gate cred_t *cred_p); 1080Sstevel@tonic-gate static int mouse8042_close(queue_t *q, int flag, cred_t *cred_p); 1090Sstevel@tonic-gate static int mouse8042_wput(queue_t *q, mblk_t *mp); 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate static int mouse8042_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, 1120Sstevel@tonic-gate void *arg, void **result); 1130Sstevel@tonic-gate static int mouse8042_attach(dev_info_t *dev, ddi_attach_cmd_t cmd); 1140Sstevel@tonic-gate static int mouse8042_detach(dev_info_t *dev, ddi_detach_cmd_t cmd); 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* 1180Sstevel@tonic-gate * Streams module info. 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate #define MODULE_NAME "mouse8042" 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static struct module_info mouse8042_minfo = { 1230Sstevel@tonic-gate 23, /* Module ID number */ 1240Sstevel@tonic-gate MODULE_NAME, 1250Sstevel@tonic-gate 0, INFPSZ, /* minimum & maximum packet sizes */ 1260Sstevel@tonic-gate 256, 128 /* hi and low water marks */ 1270Sstevel@tonic-gate }; 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate static struct qinit mouse8042_rinit = { 1300Sstevel@tonic-gate NULL, /* put */ 1310Sstevel@tonic-gate NULL, /* service */ 1320Sstevel@tonic-gate mouse8042_open, 1330Sstevel@tonic-gate mouse8042_close, 1340Sstevel@tonic-gate NULL, /* admin */ 1350Sstevel@tonic-gate &mouse8042_minfo, 1360Sstevel@tonic-gate NULL /* statistics */ 1370Sstevel@tonic-gate }; 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate static struct qinit mouse8042_winit = { 1400Sstevel@tonic-gate mouse8042_wput, /* put */ 1410Sstevel@tonic-gate NULL, /* service */ 1420Sstevel@tonic-gate NULL, /* open */ 1430Sstevel@tonic-gate NULL, /* close */ 1440Sstevel@tonic-gate NULL, /* admin */ 1450Sstevel@tonic-gate &mouse8042_minfo, 1460Sstevel@tonic-gate NULL /* statistics */ 1470Sstevel@tonic-gate }; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate static struct streamtab mouse8042_strinfo = { 1500Sstevel@tonic-gate &mouse8042_rinit, 1510Sstevel@tonic-gate &mouse8042_winit, 1520Sstevel@tonic-gate NULL, /* muxrinit */ 1530Sstevel@tonic-gate NULL, /* muxwinit */ 1540Sstevel@tonic-gate }; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate /* 1570Sstevel@tonic-gate * Local Function Declarations 1580Sstevel@tonic-gate */ 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate static struct cb_ops mouse8042_cb_ops = { 1610Sstevel@tonic-gate nodev, /* open */ 1620Sstevel@tonic-gate nodev, /* close */ 1630Sstevel@tonic-gate nodev, /* strategy */ 1640Sstevel@tonic-gate nodev, /* print */ 1650Sstevel@tonic-gate nodev, /* dump */ 1660Sstevel@tonic-gate nodev, /* read */ 1670Sstevel@tonic-gate nodev, /* write */ 1680Sstevel@tonic-gate nodev, /* ioctl */ 1690Sstevel@tonic-gate nodev, /* devmap */ 1700Sstevel@tonic-gate nodev, /* mmap */ 1710Sstevel@tonic-gate nodev, /* segmap */ 1720Sstevel@tonic-gate nochpoll, /* poll */ 1730Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1740Sstevel@tonic-gate &mouse8042_strinfo, /* streamtab */ 1750Sstevel@tonic-gate D_MP | D_NEW 1760Sstevel@tonic-gate }; 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate static struct dev_ops mouse8042_ops = { 1800Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1810Sstevel@tonic-gate 0, /* refcnt */ 1820Sstevel@tonic-gate mouse8042_getinfo, /* getinfo */ 1830Sstevel@tonic-gate nulldev, /* identify */ 1840Sstevel@tonic-gate nulldev, /* probe */ 1850Sstevel@tonic-gate mouse8042_attach, /* attach */ 1860Sstevel@tonic-gate mouse8042_detach, /* detach */ 1870Sstevel@tonic-gate nodev, /* reset */ 1880Sstevel@tonic-gate &mouse8042_cb_ops, /* driver operations */ 189*7656SSherry.Moore@Sun.COM (struct bus_ops *)0, /* bus operations */ 190*7656SSherry.Moore@Sun.COM NULL, /* power */ 191*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 1920Sstevel@tonic-gate }; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * This is the loadable module wrapper. 1960Sstevel@tonic-gate */ 1970Sstevel@tonic-gate #include <sys/modctl.h> 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate extern struct mod_ops mod_driverops; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Module linkage information for the kernel. 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate static struct modldrv modldrv = { 2060Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 207*7656SSherry.Moore@Sun.COM "PS/2 Mouse", 2080Sstevel@tonic-gate &mouse8042_ops, /* driver ops */ 2090Sstevel@tonic-gate }; 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate static struct modlinkage modlinkage = { 2120Sstevel@tonic-gate MODREV_1, 2130Sstevel@tonic-gate (void *)&modldrv, 2140Sstevel@tonic-gate NULL 2150Sstevel@tonic-gate }; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate /* 2180Sstevel@tonic-gate * This is the driver initialization routine. 2190Sstevel@tonic-gate */ 2200Sstevel@tonic-gate int 2210Sstevel@tonic-gate _init() 2220Sstevel@tonic-gate { 2230Sstevel@tonic-gate int rv; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate rv = mod_install(&modlinkage); 2260Sstevel@tonic-gate return (rv); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate int 2310Sstevel@tonic-gate _fini(void) 2320Sstevel@tonic-gate { 2330Sstevel@tonic-gate return (mod_remove(&modlinkage)); 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate int 2380Sstevel@tonic-gate _info(struct modinfo *modinfop) 2390Sstevel@tonic-gate { 2400Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate static int 2440Sstevel@tonic-gate mouse8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2450Sstevel@tonic-gate { 2460Sstevel@tonic-gate struct mouse_state *state; 247822Ssethg mblk_t *mp; 2480Sstevel@tonic-gate int instance = ddi_get_instance(dip); 2490Sstevel@tonic-gate static ddi_device_acc_attr_t attr = { 2500Sstevel@tonic-gate DDI_DEVICE_ATTR_V0, 2510Sstevel@tonic-gate DDI_NEVERSWAP_ACC, 2520Sstevel@tonic-gate DDI_STRICTORDER_ACC, 2530Sstevel@tonic-gate }; 2540Sstevel@tonic-gate int rc; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 2580Sstevel@tonic-gate if (mouse8042_debug) { 2590Sstevel@tonic-gate cmn_err(CE_CONT, MODULE_NAME "_attach entry\n"); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate #endif 2620Sstevel@tonic-gate 263822Ssethg if (cmd == DDI_RESUME) { 264822Ssethg state = (struct mouse_state *)ddi_get_driver_private(dip); 265822Ssethg 266822Ssethg /* 267822Ssethg * Send a 0xaa 0x00 upstream. 268822Ssethg * This causes the vuid module to reset the mouse. 269822Ssethg */ 270822Ssethg if (state->ms_rqp != NULL) { 271822Ssethg if (mp = allocb(1, BPRI_MED)) { 272822Ssethg *mp->b_wptr++ = 0xaa; 273822Ssethg putnext(state->ms_rqp, mp); 274822Ssethg } 275822Ssethg if (mp = allocb(1, BPRI_MED)) { 276822Ssethg *mp->b_wptr++ = 0x0; 277822Ssethg putnext(state->ms_rqp, mp); 278822Ssethg } 279822Ssethg } 280822Ssethg return (DDI_SUCCESS); 281822Ssethg } 282822Ssethg 2830Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2840Sstevel@tonic-gate return (DDI_FAILURE); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate if (mouse8042_dip != NULL) 2870Sstevel@tonic-gate return (DDI_FAILURE); 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* allocate and initialize state structure */ 2900Sstevel@tonic-gate state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP); 2910Sstevel@tonic-gate state->ms_opened = B_FALSE; 2920Sstevel@tonic-gate ddi_set_driver_private(dip, state); 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* 2950Sstevel@tonic-gate * In order to support virtual keyboard/mouse, we should distinguish 2960Sstevel@tonic-gate * between internal virtual open and external physical open. 2970Sstevel@tonic-gate * 2980Sstevel@tonic-gate * When the physical devices are opened by application, they will 2990Sstevel@tonic-gate * be unlinked from the virtual device and their data stream will 3000Sstevel@tonic-gate * not be sent to the virtual device. When the opened physical 3010Sstevel@tonic-gate * devices are closed, they will be relinked to the virtual devices. 3020Sstevel@tonic-gate * 3030Sstevel@tonic-gate * All these automatic switch between virtual and physical are 3040Sstevel@tonic-gate * transparent. 3050Sstevel@tonic-gate * 3060Sstevel@tonic-gate * So we change minor node numbering scheme to be: 3070Sstevel@tonic-gate * external node minor num == instance * 2 3080Sstevel@tonic-gate * internal node minor num == instance * 2 + 1 3090Sstevel@tonic-gate */ 310822Ssethg rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2, 3110Sstevel@tonic-gate DDI_NT_MOUSE, NULL); 3120Sstevel@tonic-gate if (rc != DDI_SUCCESS) { 3130Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 3140Sstevel@tonic-gate cmn_err(CE_CONT, 3150Sstevel@tonic-gate MODULE_NAME "_attach: ddi_create_minor_node failed\n"); 3160Sstevel@tonic-gate #endif 3170Sstevel@tonic-gate goto fail_1; 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR, 321*7656SSherry.Moore@Sun.COM instance * 2 + 1) != DDI_SUCCESS) { 3220Sstevel@tonic-gate goto fail_2; 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr, 326*7656SSherry.Moore@Sun.COM (offset_t)0, (offset_t)0, &attr, &state->ms_handle); 3270Sstevel@tonic-gate if (rc != DDI_SUCCESS) { 3280Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 3290Sstevel@tonic-gate cmn_err(CE_WARN, MODULE_NAME "_attach: can't map registers"); 3300Sstevel@tonic-gate #endif 3310Sstevel@tonic-gate goto fail_2; 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie); 3350Sstevel@tonic-gate if (rc != DDI_SUCCESS) { 3360Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 3370Sstevel@tonic-gate cmn_err(CE_WARN, 3380Sstevel@tonic-gate MODULE_NAME "_attach: Can't get iblock cookie"); 3390Sstevel@tonic-gate #endif 3400Sstevel@tonic-gate goto fail_3; 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER, 3440Sstevel@tonic-gate state->ms_iblock_cookie); 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate rc = ddi_add_intr(dip, 0, 347*7656SSherry.Moore@Sun.COM (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL, 348*7656SSherry.Moore@Sun.COM mouse8042_intr, (caddr_t)state); 3490Sstevel@tonic-gate if (rc != DDI_SUCCESS) { 3500Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 3510Sstevel@tonic-gate cmn_err(CE_WARN, MODULE_NAME "_attach: cannot add interrupt"); 3520Sstevel@tonic-gate #endif 3530Sstevel@tonic-gate goto fail_3; 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate mouse8042_dip = dip; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* Now that we're attached, announce our presence to the world. */ 3590Sstevel@tonic-gate ddi_report_dev(dip); 3600Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 361*7656SSherry.Moore@Sun.COM cmn_err(CE_CONT, "?%s #%d\n", DRIVER_NAME(dip), ddi_get_instance(dip)); 3620Sstevel@tonic-gate #endif 3630Sstevel@tonic-gate return (DDI_SUCCESS); 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate fail_3: 3660Sstevel@tonic-gate ddi_regs_map_free(&state->ms_handle); 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate fail_2: 3690Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate fail_1: 3720Sstevel@tonic-gate kmem_free(state, sizeof (struct mouse_state)); 3730Sstevel@tonic-gate return (rc); 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /*ARGSUSED*/ 3770Sstevel@tonic-gate static int 3780Sstevel@tonic-gate mouse8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3790Sstevel@tonic-gate { 3800Sstevel@tonic-gate struct mouse_state *state; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate state = ddi_get_driver_private(dip); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate switch (cmd) { 385822Ssethg case DDI_SUSPEND: 386822Ssethg return (DDI_SUCCESS); 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate case DDI_DETACH: 3890Sstevel@tonic-gate ddi_remove_intr(dip, 0, state->ms_iblock_cookie); 3900Sstevel@tonic-gate mouse8042_dip = NULL; 3910Sstevel@tonic-gate mutex_destroy(&state->ms_mutex); 3920Sstevel@tonic-gate ddi_prop_remove_all(dip); 3930Sstevel@tonic-gate ddi_regs_map_free(&state->ms_handle); 3940Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 3950Sstevel@tonic-gate kmem_free(state, sizeof (struct mouse_state)); 3960Sstevel@tonic-gate return (DDI_SUCCESS); 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate default: 3990Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 4000Sstevel@tonic-gate if (mouse8042_debug) { 4010Sstevel@tonic-gate cmn_err(CE_CONT, 4020Sstevel@tonic-gate "mouse8042_detach: cmd = %d unknown\n", cmd); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate #endif 4050Sstevel@tonic-gate return (DDI_FAILURE); 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate /* ARGSUSED */ 4110Sstevel@tonic-gate static int 4120Sstevel@tonic-gate mouse8042_getinfo( 4130Sstevel@tonic-gate dev_info_t *dip, 4140Sstevel@tonic-gate ddi_info_cmd_t infocmd, 4150Sstevel@tonic-gate void *arg, 4160Sstevel@tonic-gate void **result) 4170Sstevel@tonic-gate { 4180Sstevel@tonic-gate dev_t dev = (dev_t)arg; 4190Sstevel@tonic-gate minor_t minor = getminor(dev); 4200Sstevel@tonic-gate int instance = MOUSE8042_MINOR_TO_INSTANCE(minor); 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 4230Sstevel@tonic-gate if (mouse8042_debug) 4240Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_getinfo: call\n"); 4250Sstevel@tonic-gate #endif 4260Sstevel@tonic-gate switch (infocmd) { 4270Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 4280Sstevel@tonic-gate if (mouse8042_dip == NULL) 4290Sstevel@tonic-gate return (DDI_FAILURE); 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate *result = (void *)mouse8042_dip; 4320Sstevel@tonic-gate break; 4330Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 4340Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 4350Sstevel@tonic-gate break; 4360Sstevel@tonic-gate default: 4370Sstevel@tonic-gate return (DDI_FAILURE); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate return (DDI_SUCCESS); 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /*ARGSUSED*/ 4430Sstevel@tonic-gate static int 4440Sstevel@tonic-gate mouse8042_open( 4450Sstevel@tonic-gate queue_t *q, 4460Sstevel@tonic-gate dev_t *devp, 4470Sstevel@tonic-gate int flag, 4480Sstevel@tonic-gate int sflag, 4490Sstevel@tonic-gate cred_t *cred_p) 4500Sstevel@tonic-gate { 4510Sstevel@tonic-gate struct mouse_state *state; 4520Sstevel@tonic-gate minor_t minor = getminor(*devp); 4530Sstevel@tonic-gate int rval; 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate if (mouse8042_dip == NULL) 4560Sstevel@tonic-gate return (ENXIO); 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate state = ddi_get_driver_private(mouse8042_dip); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 4610Sstevel@tonic-gate if (mouse8042_debug) 4620Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_open:entered\n"); 4630Sstevel@tonic-gate #endif 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate mutex_enter(&state->ms_mutex); 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate if (state->ms_opened) { 4680Sstevel@tonic-gate /* 4690Sstevel@tonic-gate * Exit if the same minor node is already open 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate if (state->ms_minor == minor) { 4720Sstevel@tonic-gate mutex_exit(&state->ms_mutex); 4730Sstevel@tonic-gate return (0); 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * Check whether it is switch between physical and virtual 4780Sstevel@tonic-gate * 4790Sstevel@tonic-gate * Opening from virtual while the device is being physically 4800Sstevel@tonic-gate * opened by an application should not happen. So we ASSERT 4810Sstevel@tonic-gate * this in DEBUG version, and return error in the non-DEBUG 4820Sstevel@tonic-gate * case. 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate ASSERT(!MOUSE8042_INTERNAL_OPEN(minor)); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate if (MOUSE8042_INTERNAL_OPEN(minor)) { 4870Sstevel@tonic-gate mutex_exit(&state->ms_mutex); 4880Sstevel@tonic-gate return (EINVAL); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * Opening the physical one while it is being underneath 4930Sstevel@tonic-gate * the virtual one. 4940Sstevel@tonic-gate * 4950Sstevel@tonic-gate * consconfig_unlink is called to unlink this device from 4960Sstevel@tonic-gate * the virtual one, thus the old stream serving for this 4970Sstevel@tonic-gate * device under the virtual one is closed, and then the 4980Sstevel@tonic-gate * lower driver's close routine (here is mouse8042_close) 4990Sstevel@tonic-gate * is also called to accomplish the whole stream close. 5000Sstevel@tonic-gate * Here we have to drop the lock because mouse8042_close 5010Sstevel@tonic-gate * also needs the lock. 5020Sstevel@tonic-gate * 5030Sstevel@tonic-gate * For mouse, the old stream is: 5040Sstevel@tonic-gate * consms->["pushmod"->]"mouse_vp driver" 5050Sstevel@tonic-gate * 5060Sstevel@tonic-gate * After the consconfig_unlink returns, the old stream is closed 5070Sstevel@tonic-gate * and we grab the lock again to reopen this device as normal. 5080Sstevel@tonic-gate */ 5090Sstevel@tonic-gate mutex_exit(&state->ms_mutex); 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * If unlink fails, fail the physical open. 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate if ((rval = consconfig_unlink(ddi_driver_major(mouse8042_dip), 5150Sstevel@tonic-gate MOUSE8042_INTERNAL_MINOR(minor))) != 0) { 5160Sstevel@tonic-gate return (rval); 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate mutex_enter(&state->ms_mutex); 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate q->q_ptr = (caddr_t)state; 5240Sstevel@tonic-gate WR(q)->q_ptr = (caddr_t)state; 5250Sstevel@tonic-gate state->ms_rqp = q; 5260Sstevel@tonic-gate state->ms_wqp = WR(q); 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate qprocson(q); 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate state->ms_minor = minor; 5310Sstevel@tonic-gate state->ms_opened = B_TRUE; 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate mutex_exit(&state->ms_mutex); 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate return (0); 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate /*ARGSUSED*/ 5400Sstevel@tonic-gate static int 5410Sstevel@tonic-gate mouse8042_close(queue_t *q, int flag, cred_t *cred_p) 5420Sstevel@tonic-gate { 5430Sstevel@tonic-gate struct mouse_state *state; 5440Sstevel@tonic-gate minor_t minor; 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate state = (struct mouse_state *)q->q_ptr; 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 5490Sstevel@tonic-gate if (mouse8042_debug) 5500Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_close:entered\n"); 5510Sstevel@tonic-gate #endif 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate mutex_enter(&state->ms_mutex); 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate qprocsoff(q); 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate q->q_ptr = NULL; 5580Sstevel@tonic-gate WR(q)->q_ptr = NULL; 5590Sstevel@tonic-gate state->ms_rqp = NULL; 5600Sstevel@tonic-gate state->ms_wqp = NULL; 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate state->ms_opened = B_FALSE; 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate minor = state->ms_minor; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate mutex_exit(&state->ms_mutex); 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate if (!MOUSE8042_INTERNAL_OPEN(minor)) { 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate * Closing physical PS/2 mouse 5710Sstevel@tonic-gate * 5720Sstevel@tonic-gate * Link it back to virtual mouse, and 5730Sstevel@tonic-gate * mouse8042_open will be called as a result 574822Ssethg * of the consconfig_link call. Do NOT try 575822Ssethg * this if the mouse is about to be detached! 5760Sstevel@tonic-gate * 5770Sstevel@tonic-gate * If linking back fails, this specific mouse 5780Sstevel@tonic-gate * will not be available underneath the virtual 5790Sstevel@tonic-gate * mouse, and can only be accessed via physical 5800Sstevel@tonic-gate * open. 5810Sstevel@tonic-gate */ 5820Sstevel@tonic-gate consconfig_link(ddi_driver_major(mouse8042_dip), 5830Sstevel@tonic-gate MOUSE8042_INTERNAL_MINOR(minor)); 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate return (0); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate static void 5900Sstevel@tonic-gate mouse8042_iocnack( 5910Sstevel@tonic-gate queue_t *qp, 5920Sstevel@tonic-gate mblk_t *mp, 5930Sstevel@tonic-gate struct iocblk *iocp, 5940Sstevel@tonic-gate int error, 5950Sstevel@tonic-gate int rval) 5960Sstevel@tonic-gate { 5970Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 5980Sstevel@tonic-gate iocp->ioc_rval = rval; 5990Sstevel@tonic-gate iocp->ioc_error = error; 6000Sstevel@tonic-gate qreply(qp, mp); 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate static int 6040Sstevel@tonic-gate mouse8042_wput(queue_t *q, mblk_t *mp) 6050Sstevel@tonic-gate { 6060Sstevel@tonic-gate struct iocblk *iocbp; 6070Sstevel@tonic-gate mblk_t *bp; 6080Sstevel@tonic-gate mblk_t *next; 6090Sstevel@tonic-gate struct mouse_state *state; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate state = (struct mouse_state *)q->q_ptr; 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 6140Sstevel@tonic-gate if (mouse8042_debug) 6150Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_wput:entered\n"); 6160Sstevel@tonic-gate #endif 6170Sstevel@tonic-gate iocbp = (struct iocblk *)mp->b_rptr; 6180Sstevel@tonic-gate switch (mp->b_datap->db_type) { 6190Sstevel@tonic-gate case M_FLUSH: 6200Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 6210Sstevel@tonic-gate if (mouse8042_debug) 6220Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_wput:M_FLUSH\n"); 6230Sstevel@tonic-gate #endif 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) 6260Sstevel@tonic-gate flushq(q, FLUSHDATA); 6270Sstevel@tonic-gate qreply(q, mp); 6280Sstevel@tonic-gate break; 6290Sstevel@tonic-gate case M_IOCTL: 6300Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 6310Sstevel@tonic-gate if (mouse8042_debug) 6320Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_wput:M_IOCTL\n"); 6330Sstevel@tonic-gate #endif 6340Sstevel@tonic-gate mouse8042_iocnack(q, mp, iocbp, EINVAL, 0); 6350Sstevel@tonic-gate break; 6360Sstevel@tonic-gate case M_IOCDATA: 6370Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 6380Sstevel@tonic-gate if (mouse8042_debug) 6390Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_wput:M_IOCDATA\n"); 6400Sstevel@tonic-gate #endif 6410Sstevel@tonic-gate mouse8042_iocnack(q, mp, iocbp, EINVAL, 0); 6420Sstevel@tonic-gate break; 6430Sstevel@tonic-gate case M_DATA: 6440Sstevel@tonic-gate bp = mp; 6450Sstevel@tonic-gate do { 6460Sstevel@tonic-gate while (bp->b_rptr < bp->b_wptr) { 6470Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 6480Sstevel@tonic-gate if (mouse8042_debug) { 6490Sstevel@tonic-gate cmn_err(CE_CONT, 6500Sstevel@tonic-gate "mouse8042: send %2x\n", 6510Sstevel@tonic-gate *bp->b_rptr); 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate if (mouse8042_debug_minimal) { 6540Sstevel@tonic-gate cmn_err(CE_CONT, ">a:%2x ", 6550Sstevel@tonic-gate *bp->b_rptr); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate #endif 6580Sstevel@tonic-gate ddi_put8(state->ms_handle, 659*7656SSherry.Moore@Sun.COM state->ms_addr + I8042_INT_OUTPUT_DATA, 660*7656SSherry.Moore@Sun.COM *bp->b_rptr++); 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate next = bp->b_cont; 6630Sstevel@tonic-gate freeb(bp); 6640Sstevel@tonic-gate } while ((bp = next) != NULL); 6650Sstevel@tonic-gate break; 6660Sstevel@tonic-gate default: 6670Sstevel@tonic-gate freemsg(mp); 6680Sstevel@tonic-gate break; 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 6710Sstevel@tonic-gate if (mouse8042_debug) 6720Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_wput:leaving\n"); 6730Sstevel@tonic-gate #endif 6740Sstevel@tonic-gate return (0); /* ignored */ 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate static uint_t 6780Sstevel@tonic-gate mouse8042_intr(caddr_t arg) 6790Sstevel@tonic-gate { 6800Sstevel@tonic-gate unsigned char mdata; 6810Sstevel@tonic-gate mblk_t *mp; 6820Sstevel@tonic-gate struct mouse_state *state = (struct mouse_state *)arg; 6830Sstevel@tonic-gate int rc; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate mutex_enter(&state->ms_mutex); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 6880Sstevel@tonic-gate if (mouse8042_debug) 6890Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_intr()\n"); 6900Sstevel@tonic-gate #endif 6910Sstevel@tonic-gate rc = DDI_INTR_UNCLAIMED; 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate for (;;) { 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate if (ddi_get8(state->ms_handle, 696*7656SSherry.Moore@Sun.COM state->ms_addr + I8042_INT_INPUT_AVAIL) == 0) { 6970Sstevel@tonic-gate break; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate mdata = ddi_get8(state->ms_handle, 701*7656SSherry.Moore@Sun.COM state->ms_addr + I8042_INT_INPUT_DATA); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate #if defined(MOUSE8042_DEBUG) 7040Sstevel@tonic-gate if (mouse8042_debug) 7050Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_intr: got %2x\n", mdata); 7060Sstevel@tonic-gate if (mouse8042_debug_minimal) 7070Sstevel@tonic-gate cmn_err(CE_CONT, "<A:%2x ", mdata); 7080Sstevel@tonic-gate #endif 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate rc = DDI_INTR_CLAIMED; 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) { 7130Sstevel@tonic-gate *mp->b_wptr++ = mdata; 7140Sstevel@tonic-gate putnext(state->ms_rqp, mp); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate #ifdef MOUSE8042_DEBUG 7180Sstevel@tonic-gate if (mouse8042_debug) 7190Sstevel@tonic-gate cmn_err(CE_CONT, "mouse8042_intr() ok\n"); 7200Sstevel@tonic-gate #endif 7210Sstevel@tonic-gate mutex_exit(&state->ms_mutex); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate return (rc); 7240Sstevel@tonic-gate } 725