1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/inline.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/i8042.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> /* for prom_printf */ 37*7c478bd9Sstevel@tonic-gate #include <sys/note.h> 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate /* 40*7c478bd9Sstevel@tonic-gate * Note: this driver is only used to attach a keyboard when 41*7c478bd9Sstevel@tonic-gate * booting with ACPI enumeration turned off (acpi-enum=off). 42*7c478bd9Sstevel@tonic-gate */ 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /* 45*7c478bd9Sstevel@tonic-gate * Unfortunately, soft interrupts are implemented poorly. Each additional 46*7c478bd9Sstevel@tonic-gate * soft interrupt user impacts the performance of all existing soft interrupt 47*7c478bd9Sstevel@tonic-gate * users. 48*7c478bd9Sstevel@tonic-gate */ 49*7c478bd9Sstevel@tonic-gate #undef USE_SOFT_INTRS 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate #define BUFSIZ 64 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate enum i8042_ports { 54*7c478bd9Sstevel@tonic-gate MAIN_PORT = 0, 55*7c478bd9Sstevel@tonic-gate AUX_PORT 56*7c478bd9Sstevel@tonic-gate }; 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #define NUM_PORTS 2 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* 61*7c478bd9Sstevel@tonic-gate * One of these for each port - main (keyboard) and aux (mouse). 62*7c478bd9Sstevel@tonic-gate */ 63*7c478bd9Sstevel@tonic-gate struct i8042_port { 64*7c478bd9Sstevel@tonic-gate boolean_t initialized; 65*7c478bd9Sstevel@tonic-gate dev_info_t *dip; 66*7c478bd9Sstevel@tonic-gate int inumber; 67*7c478bd9Sstevel@tonic-gate enum i8042_ports which; /* main or aux port */ 68*7c478bd9Sstevel@tonic-gate #if defined(USE_SOFT_INTRS) 69*7c478bd9Sstevel@tonic-gate ddi_softint_handle_t soft_hdl; 70*7c478bd9Sstevel@tonic-gate boolean_t soft_intr_enabled; 71*7c478bd9Sstevel@tonic-gate #else 72*7c478bd9Sstevel@tonic-gate uint_t (*intr_func)(caddr_t arg1, caddr_t arg2); 73*7c478bd9Sstevel@tonic-gate caddr_t intr_arg1; 74*7c478bd9Sstevel@tonic-gate caddr_t intr_arg2; 75*7c478bd9Sstevel@tonic-gate kmutex_t intr_mutex; 76*7c478bd9Sstevel@tonic-gate #endif 77*7c478bd9Sstevel@tonic-gate struct i8042 *i8042_global; 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * wptr is next byte to write 80*7c478bd9Sstevel@tonic-gate */ 81*7c478bd9Sstevel@tonic-gate int wptr; 82*7c478bd9Sstevel@tonic-gate /* 83*7c478bd9Sstevel@tonic-gate * rptr is next byte to read, == wptr means empty 84*7c478bd9Sstevel@tonic-gate * NB: At full, one byte is unused. 85*7c478bd9Sstevel@tonic-gate */ 86*7c478bd9Sstevel@tonic-gate int rptr; 87*7c478bd9Sstevel@tonic-gate int overruns; 88*7c478bd9Sstevel@tonic-gate unsigned char buf[BUFSIZ]; 89*7c478bd9Sstevel@tonic-gate }; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * Describes entire 8042 device. 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate struct i8042 { 95*7c478bd9Sstevel@tonic-gate struct i8042_port i8042_ports[NUM_PORTS]; 96*7c478bd9Sstevel@tonic-gate kmutex_t i8042_mutex; 97*7c478bd9Sstevel@tonic-gate kmutex_t i8042_out_mutex; 98*7c478bd9Sstevel@tonic-gate boolean_t initialized; 99*7c478bd9Sstevel@tonic-gate ddi_acc_handle_t io_handle; 100*7c478bd9Sstevel@tonic-gate uint8_t *io_addr; 101*7c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie_0; 102*7c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie_1; 103*7c478bd9Sstevel@tonic-gate }; 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate /* 106*7c478bd9Sstevel@tonic-gate * i8042 hardware register definitions 107*7c478bd9Sstevel@tonic-gate */ 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /* 110*7c478bd9Sstevel@tonic-gate * These are I/O registers, relative to the device's base (normally 0x60). 111*7c478bd9Sstevel@tonic-gate */ 112*7c478bd9Sstevel@tonic-gate #define I8042_DATA 0x00 /* read/write data here */ 113*7c478bd9Sstevel@tonic-gate #define I8042_STAT 0x04 /* read status here */ 114*7c478bd9Sstevel@tonic-gate #define I8042_CMD 0x04 /* write commands here */ 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate /* 117*7c478bd9Sstevel@tonic-gate * These are bits in I8042_STAT. 118*7c478bd9Sstevel@tonic-gate */ 119*7c478bd9Sstevel@tonic-gate #define I8042_STAT_OUTBF 0x01 /* Output (to host) buffer full */ 120*7c478bd9Sstevel@tonic-gate #define I8042_STAT_INBF 0x02 /* Input (from host) buffer full */ 121*7c478bd9Sstevel@tonic-gate #define I8042_STAT_AUXBF 0x20 /* Output buffer data is from aux */ 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* 124*7c478bd9Sstevel@tonic-gate * These are commands to the i8042 itself (as distinct from the devices 125*7c478bd9Sstevel@tonic-gate * attached to it). 126*7c478bd9Sstevel@tonic-gate */ 127*7c478bd9Sstevel@tonic-gate #define I8042_CMD_RCB 0x20 /* Read command byte (we don't use) */ 128*7c478bd9Sstevel@tonic-gate #define I8042_CMD_WCB 0x60 /* Write command byte */ 129*7c478bd9Sstevel@tonic-gate #define I8042_CMD_WRITE_AUX 0xD4 /* Send next data byte to aux port */ 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate /* 132*7c478bd9Sstevel@tonic-gate * function prototypes for bus ops routines: 133*7c478bd9Sstevel@tonic-gate */ 134*7c478bd9Sstevel@tonic-gate static int i8042_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 135*7c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *addrp); 136*7c478bd9Sstevel@tonic-gate static int i8042_ctlops(dev_info_t *dip, dev_info_t *rdip, 137*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result); 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* 140*7c478bd9Sstevel@tonic-gate * function prototypes for dev ops routines: 141*7c478bd9Sstevel@tonic-gate */ 142*7c478bd9Sstevel@tonic-gate static int i8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 143*7c478bd9Sstevel@tonic-gate static int i8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 144*7c478bd9Sstevel@tonic-gate static int i8042_intr_ops(dev_info_t *dip, dev_info_t *rdip, 145*7c478bd9Sstevel@tonic-gate ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result); 146*7c478bd9Sstevel@tonic-gate static int i8042_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, 147*7c478bd9Sstevel@tonic-gate void *, dev_info_t **); 148*7c478bd9Sstevel@tonic-gate static int i8042_bus_unconfig(dev_info_t *, uint_t, 149*7c478bd9Sstevel@tonic-gate ddi_bus_config_op_t, void *); 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate /* 152*7c478bd9Sstevel@tonic-gate * bus ops and dev ops structures: 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate static struct bus_ops i8042_bus_ops = { 155*7c478bd9Sstevel@tonic-gate BUSO_REV, 156*7c478bd9Sstevel@tonic-gate i8042_map, 157*7c478bd9Sstevel@tonic-gate NULL, 158*7c478bd9Sstevel@tonic-gate NULL, 159*7c478bd9Sstevel@tonic-gate NULL, 160*7c478bd9Sstevel@tonic-gate NULL, /* ddi_map_fault */ 161*7c478bd9Sstevel@tonic-gate NULL, /* ddi_dma_map */ 162*7c478bd9Sstevel@tonic-gate NULL, /* ddi_dma_allochdl */ 163*7c478bd9Sstevel@tonic-gate NULL, /* ddi_dma_freehdl */ 164*7c478bd9Sstevel@tonic-gate NULL, /* ddi_dma_bindhdl */ 165*7c478bd9Sstevel@tonic-gate NULL, /* ddi_dma_unbindhdl */ 166*7c478bd9Sstevel@tonic-gate NULL, /* ddi_dma_flush */ 167*7c478bd9Sstevel@tonic-gate NULL, /* ddi_dma_win */ 168*7c478bd9Sstevel@tonic-gate NULL, /* ddi_dma_mctl */ 169*7c478bd9Sstevel@tonic-gate i8042_ctlops, 170*7c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 171*7c478bd9Sstevel@tonic-gate NULL, /* (*bus_get_eventcookie)(); */ 172*7c478bd9Sstevel@tonic-gate NULL, /* (*bus_add_eventcall)(); */ 173*7c478bd9Sstevel@tonic-gate NULL, /* (*bus_remove_eventcall)(); */ 174*7c478bd9Sstevel@tonic-gate NULL, /* (*bus_post_event)(); */ 175*7c478bd9Sstevel@tonic-gate NULL, /* bus_intr_ctl */ 176*7c478bd9Sstevel@tonic-gate i8042_bus_config, /* bus_config */ 177*7c478bd9Sstevel@tonic-gate i8042_bus_unconfig, /* bus_unconfig */ 178*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_init */ 179*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_fini */ 180*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_access_enter */ 181*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_access_exit */ 182*7c478bd9Sstevel@tonic-gate NULL, /* bus_power */ 183*7c478bd9Sstevel@tonic-gate i8042_intr_ops /* bus_intr_op */ 184*7c478bd9Sstevel@tonic-gate }; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate static struct dev_ops i8042_ops = { 187*7c478bd9Sstevel@tonic-gate DEVO_REV, 188*7c478bd9Sstevel@tonic-gate 0, 189*7c478bd9Sstevel@tonic-gate ddi_no_info, 190*7c478bd9Sstevel@tonic-gate nulldev, 191*7c478bd9Sstevel@tonic-gate 0, 192*7c478bd9Sstevel@tonic-gate i8042_attach, 193*7c478bd9Sstevel@tonic-gate i8042_detach, 194*7c478bd9Sstevel@tonic-gate nodev, 195*7c478bd9Sstevel@tonic-gate (struct cb_ops *)0, 196*7c478bd9Sstevel@tonic-gate &i8042_bus_ops 197*7c478bd9Sstevel@tonic-gate }; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate /* 201*7c478bd9Sstevel@tonic-gate * module definitions: 202*7c478bd9Sstevel@tonic-gate */ 203*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 204*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 207*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 208*7c478bd9Sstevel@tonic-gate "i8042 nexus driver %I%", /* Name of module. */ 209*7c478bd9Sstevel@tonic-gate &i8042_ops, /* driver ops */ 210*7c478bd9Sstevel@tonic-gate }; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 213*7c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 214*7c478bd9Sstevel@tonic-gate }; 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate int 217*7c478bd9Sstevel@tonic-gate _init(void) 218*7c478bd9Sstevel@tonic-gate { 219*7c478bd9Sstevel@tonic-gate int e; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* 222*7c478bd9Sstevel@tonic-gate * Install the module. 223*7c478bd9Sstevel@tonic-gate */ 224*7c478bd9Sstevel@tonic-gate e = mod_install(&modlinkage); 225*7c478bd9Sstevel@tonic-gate return (e); 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate int 229*7c478bd9Sstevel@tonic-gate _fini(void) 230*7c478bd9Sstevel@tonic-gate { 231*7c478bd9Sstevel@tonic-gate int e; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate /* 234*7c478bd9Sstevel@tonic-gate * Remove the module. 235*7c478bd9Sstevel@tonic-gate */ 236*7c478bd9Sstevel@tonic-gate e = mod_remove(&modlinkage); 237*7c478bd9Sstevel@tonic-gate if (e != 0) 238*7c478bd9Sstevel@tonic-gate return (e); 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate return (e); 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate int 244*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 245*7c478bd9Sstevel@tonic-gate { 246*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate #define DRIVER_NAME(dip) ddi_driver_name(dip) 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate static unsigned int i8042_intr(caddr_t arg); 252*7c478bd9Sstevel@tonic-gate static void i8042_write_command_byte(struct i8042_port *, unsigned char); 253*7c478bd9Sstevel@tonic-gate static uint8_t i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr); 254*7c478bd9Sstevel@tonic-gate static void i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, 255*7c478bd9Sstevel@tonic-gate uint8_t value); 256*7c478bd9Sstevel@tonic-gate static void i8042_send(struct i8042 *global, int reg, unsigned char cmd); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate unsigned int i8042_unclaimed_interrupts = 0; 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate static int 261*7c478bd9Sstevel@tonic-gate i8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 262*7c478bd9Sstevel@tonic-gate { 263*7c478bd9Sstevel@tonic-gate struct i8042_port *port; 264*7c478bd9Sstevel@tonic-gate enum i8042_ports which_port; 265*7c478bd9Sstevel@tonic-gate int rc; 266*7c478bd9Sstevel@tonic-gate unsigned char stat; 267*7c478bd9Sstevel@tonic-gate static ddi_device_acc_attr_t attr = { 268*7c478bd9Sstevel@tonic-gate DDI_DEVICE_ATTR_V0, 269*7c478bd9Sstevel@tonic-gate DDI_NEVERSWAP_ACC, 270*7c478bd9Sstevel@tonic-gate DDI_STRICTORDER_ACC, 271*7c478bd9Sstevel@tonic-gate }; 272*7c478bd9Sstevel@tonic-gate struct i8042 *global; 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) { 275*7c478bd9Sstevel@tonic-gate /* 276*7c478bd9Sstevel@tonic-gate * We don't support anything but DDI_ATTACH. Eventually 277*7c478bd9Sstevel@tonic-gate * we probably should. 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate global = kmem_zalloc(sizeof (*global), KM_SLEEP); 283*7c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, global); 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate /* 286*7c478bd9Sstevel@tonic-gate * We're evil - we never release this. 287*7c478bd9Sstevel@tonic-gate * 288*7c478bd9Sstevel@tonic-gate * Well, we will when we have a detach routine. 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&global->io_addr, 291*7c478bd9Sstevel@tonic-gate (offset_t)0, (offset_t)0, &attr, &global->io_handle); 292*7c478bd9Sstevel@tonic-gate if (rc != DDI_SUCCESS) 293*7c478bd9Sstevel@tonic-gate goto fail_1; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate rc = ddi_get_iblock_cookie(dip, 0, &global->iblock_cookie_0); 296*7c478bd9Sstevel@tonic-gate if (rc != DDI_SUCCESS) 297*7c478bd9Sstevel@tonic-gate goto fail_2; 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate mutex_init(&global->i8042_mutex, NULL, MUTEX_DRIVER, 300*7c478bd9Sstevel@tonic-gate global->iblock_cookie_0); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate mutex_init(&global->i8042_out_mutex, NULL, MUTEX_DRIVER, NULL); 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate for (which_port = 0; which_port < NUM_PORTS; ++which_port) { 305*7c478bd9Sstevel@tonic-gate port = &global->i8042_ports[which_port]; 306*7c478bd9Sstevel@tonic-gate port->initialized = B_FALSE; 307*7c478bd9Sstevel@tonic-gate port->i8042_global = global; 308*7c478bd9Sstevel@tonic-gate port->which = which_port; 309*7c478bd9Sstevel@tonic-gate mutex_init(&port->intr_mutex, NULL, MUTEX_DRIVER, 310*7c478bd9Sstevel@tonic-gate global->iblock_cookie_0); 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate /* 314*7c478bd9Sstevel@tonic-gate * Disable input and interrupts from both the main and aux ports. 315*7c478bd9Sstevel@tonic-gate * 316*7c478bd9Sstevel@tonic-gate * It is difficult if not impossible to read the command byte in 317*7c478bd9Sstevel@tonic-gate * a completely clean way. Reading the command byte may cause 318*7c478bd9Sstevel@tonic-gate * an interrupt, and there is no way to suppress interrupts without 319*7c478bd9Sstevel@tonic-gate * writing the command byte. On a PC we might rely on the fact 320*7c478bd9Sstevel@tonic-gate * that IRQ 1 is disabled and guaranteed not shared, but on 321*7c478bd9Sstevel@tonic-gate * other platforms the interrupt line might be shared and so 322*7c478bd9Sstevel@tonic-gate * causing an interrupt could be bad. 323*7c478bd9Sstevel@tonic-gate * 324*7c478bd9Sstevel@tonic-gate * Since we can't read the command byte and update it, we 325*7c478bd9Sstevel@tonic-gate * just set it to static values: 326*7c478bd9Sstevel@tonic-gate * 327*7c478bd9Sstevel@tonic-gate * 0x80: 0 = Reserved, must be zero. 328*7c478bd9Sstevel@tonic-gate * 0x40: 1 = Translate to XT codes. 329*7c478bd9Sstevel@tonic-gate * 0x20: 1 = Disable aux (mouse) port. 330*7c478bd9Sstevel@tonic-gate * 0x10: 1 = Disable main (keyboard) port. 331*7c478bd9Sstevel@tonic-gate * 0x08: 0 = Reserved, must be zero. 332*7c478bd9Sstevel@tonic-gate * 0x04: 1 = System flag, 1 means passed self-test. 333*7c478bd9Sstevel@tonic-gate * Caution: setting this bit to zero causes some 334*7c478bd9Sstevel@tonic-gate * systems (HP Kayak XA) to fail to reboot without 335*7c478bd9Sstevel@tonic-gate * a hard reset. 336*7c478bd9Sstevel@tonic-gate * 0x02: 0 = Disable aux port interrupts. 337*7c478bd9Sstevel@tonic-gate * 0x01: 0 = Disable main port interrupts. 338*7c478bd9Sstevel@tonic-gate */ 339*7c478bd9Sstevel@tonic-gate i8042_write_command_byte(&global->i8042_ports[0], 0x74); 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate global->initialized = B_TRUE; 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate rc = ddi_add_intr(dip, 0, 344*7c478bd9Sstevel@tonic-gate (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL, 345*7c478bd9Sstevel@tonic-gate i8042_intr, (caddr_t)global); 346*7c478bd9Sstevel@tonic-gate if (rc != DDI_SUCCESS) 347*7c478bd9Sstevel@tonic-gate goto fail_2; 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate /* 350*7c478bd9Sstevel@tonic-gate * Some systems (SPARCengine-6) have both interrupts wired to 351*7c478bd9Sstevel@tonic-gate * a single interrupt line. We should try to detect this case 352*7c478bd9Sstevel@tonic-gate * and not call ddi_add_intr twice. 353*7c478bd9Sstevel@tonic-gate */ 354*7c478bd9Sstevel@tonic-gate rc = ddi_add_intr(dip, 1, 355*7c478bd9Sstevel@tonic-gate &global->iblock_cookie_1, (ddi_idevice_cookie_t *)NULL, 356*7c478bd9Sstevel@tonic-gate i8042_intr, (caddr_t)global); 357*7c478bd9Sstevel@tonic-gate if (rc != DDI_SUCCESS) 358*7c478bd9Sstevel@tonic-gate goto fail_3; 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate /* Discard any junk data that may have been left around */ 361*7c478bd9Sstevel@tonic-gate for (;;) { 362*7c478bd9Sstevel@tonic-gate stat = ddi_get8(global->io_handle, 363*7c478bd9Sstevel@tonic-gate global->io_addr + I8042_STAT); 364*7c478bd9Sstevel@tonic-gate if (! (stat & I8042_STAT_OUTBF)) 365*7c478bd9Sstevel@tonic-gate break; 366*7c478bd9Sstevel@tonic-gate (void) ddi_get8(global->io_handle, 367*7c478bd9Sstevel@tonic-gate global->io_addr + I8042_DATA); 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * As noted above, we simply set the command byte to the 373*7c478bd9Sstevel@tonic-gate * desired value. For normal operation, that value is: 374*7c478bd9Sstevel@tonic-gate * 375*7c478bd9Sstevel@tonic-gate * 0x80: 0 = Reserved, must be zero. 376*7c478bd9Sstevel@tonic-gate * 0x40: 1 = Translate to XT codes. 377*7c478bd9Sstevel@tonic-gate * 0x20: 0 = Enable aux (mouse) port. 378*7c478bd9Sstevel@tonic-gate * 0x10: 0 = Enable main (keyboard) port. 379*7c478bd9Sstevel@tonic-gate * 0x08: 0 = Reserved, must be zero. 380*7c478bd9Sstevel@tonic-gate * 0x04: 1 = System flag, 1 means passed self-test. 381*7c478bd9Sstevel@tonic-gate * Caution: setting this bit to zero causes some 382*7c478bd9Sstevel@tonic-gate * systems (HP Kayak XA) to fail to reboot without 383*7c478bd9Sstevel@tonic-gate * a hard reset. 384*7c478bd9Sstevel@tonic-gate * 0x02: 1 = Enable aux port interrupts. 385*7c478bd9Sstevel@tonic-gate * 0x01: 1 = Enable main port interrupts. 386*7c478bd9Sstevel@tonic-gate */ 387*7c478bd9Sstevel@tonic-gate i8042_write_command_byte(&global->i8042_ports[0], 0x47); 388*7c478bd9Sstevel@tonic-gate return (rc); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate fail_3: 391*7c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, global->iblock_cookie_0); 392*7c478bd9Sstevel@tonic-gate fail_2: 393*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&global->io_handle); 394*7c478bd9Sstevel@tonic-gate fail_1: 395*7c478bd9Sstevel@tonic-gate kmem_free(global, sizeof (*global)); 396*7c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, NULL); 397*7c478bd9Sstevel@tonic-gate return (rc); 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 401*7c478bd9Sstevel@tonic-gate static int 402*7c478bd9Sstevel@tonic-gate i8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 403*7c478bd9Sstevel@tonic-gate { 404*7c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 405*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate /* 408*7c478bd9Sstevel@tonic-gate * We do not support detach. Eventually we probably should, but 409*7c478bd9Sstevel@tonic-gate * (a) detach of nexus drivers is iffy at present, and (b) 410*7c478bd9Sstevel@tonic-gate * realistically, the keyboard never detaches. This assumption 411*7c478bd9Sstevel@tonic-gate * might come into question when USB keyboards are introduced. 412*7c478bd9Sstevel@tonic-gate */ 413*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "i8042_detach: detach not supported"); 414*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate /* 418*7c478bd9Sstevel@tonic-gate * The primary interface to us from our children is via virtual registers. 419*7c478bd9Sstevel@tonic-gate * This is the entry point that allows our children to "map" these 420*7c478bd9Sstevel@tonic-gate * virtual registers. 421*7c478bd9Sstevel@tonic-gate */ 422*7c478bd9Sstevel@tonic-gate static int 423*7c478bd9Sstevel@tonic-gate i8042_map( 424*7c478bd9Sstevel@tonic-gate dev_info_t *dip, 425*7c478bd9Sstevel@tonic-gate dev_info_t *rdip, 426*7c478bd9Sstevel@tonic-gate ddi_map_req_t *mp, 427*7c478bd9Sstevel@tonic-gate off_t offset, 428*7c478bd9Sstevel@tonic-gate off_t len, 429*7c478bd9Sstevel@tonic-gate caddr_t *addrp) 430*7c478bd9Sstevel@tonic-gate { 431*7c478bd9Sstevel@tonic-gate struct i8042_port *port; 432*7c478bd9Sstevel@tonic-gate struct i8042 *global; 433*7c478bd9Sstevel@tonic-gate enum i8042_ports which_port; 434*7c478bd9Sstevel@tonic-gate int *iprop; 435*7c478bd9Sstevel@tonic-gate unsigned int iprop_len; 436*7c478bd9Sstevel@tonic-gate int rnumber; 437*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *handle; 438*7c478bd9Sstevel@tonic-gate ddi_acc_impl_t *ap; 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate global = ddi_get_driver_private(dip); 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate switch (mp->map_type) { 443*7c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 444*7c478bd9Sstevel@tonic-gate which_port = *(int *)mp->map_obj.rp; 445*7c478bd9Sstevel@tonic-gate break; 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: 448*7c478bd9Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 449*7c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 450*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", &iprop, &iprop_len) != 451*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 452*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 453*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s #%d: Missing 'reg' on %s@%s", 454*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), ddi_get_instance(dip), 455*7c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip)); 456*7c478bd9Sstevel@tonic-gate #endif 457*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 460*7c478bd9Sstevel@tonic-gate if (iprop_len != 1) { 461*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s #%d: Malformed 'reg' on %s@%s", 462*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), ddi_get_instance(dip), 463*7c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip)); 464*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate if (rnumber < 0 || rnumber >= iprop_len) { 467*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s #%d: bad map request for %s@%s", 468*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), ddi_get_instance(dip), 469*7c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip)); 470*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate #endif 473*7c478bd9Sstevel@tonic-gate which_port = iprop[rnumber]; 474*7c478bd9Sstevel@tonic-gate ddi_prop_free((void *)iprop); 475*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 476*7c478bd9Sstevel@tonic-gate if (which_port != MAIN_PORT && which_port != AUX_PORT) { 477*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 478*7c478bd9Sstevel@tonic-gate "%s #%d: bad 'reg' value %d on %s@%s", 479*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), ddi_get_instance(dip), 480*7c478bd9Sstevel@tonic-gate which_port, 481*7c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip)); 482*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate #endif 485*7c478bd9Sstevel@tonic-gate break; 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate default: 488*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 489*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s #%d: unknown map type %d for %s@%s", 490*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), ddi_get_instance(dip), 491*7c478bd9Sstevel@tonic-gate mp->map_type, 492*7c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip)); 493*7c478bd9Sstevel@tonic-gate #endif 494*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 498*7c478bd9Sstevel@tonic-gate if (offset != 0 || len != 0) { 499*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 500*7c478bd9Sstevel@tonic-gate "%s #%d: partial mapping attempt for %s@%s ignored", 501*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), ddi_get_instance(dip), 502*7c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip)); 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate #endif 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate port = &global->i8042_ports[which_port]; 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate switch (mp->map_op) { 509*7c478bd9Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 510*7c478bd9Sstevel@tonic-gate #if defined(USE_SOFT_INTRS) 511*7c478bd9Sstevel@tonic-gate port->soft_intr_enabled = B_FALSE; 512*7c478bd9Sstevel@tonic-gate #else 513*7c478bd9Sstevel@tonic-gate port->intr_func = NULL; 514*7c478bd9Sstevel@tonic-gate #endif 515*7c478bd9Sstevel@tonic-gate port->wptr = 0; 516*7c478bd9Sstevel@tonic-gate port->rptr = 0; 517*7c478bd9Sstevel@tonic-gate port->dip = dip; 518*7c478bd9Sstevel@tonic-gate port->inumber = 0; 519*7c478bd9Sstevel@tonic-gate port->initialized = B_TRUE; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate handle = mp->map_handlep; 522*7c478bd9Sstevel@tonic-gate handle->ah_bus_private = port; 523*7c478bd9Sstevel@tonic-gate handle->ah_addr = 0; 524*7c478bd9Sstevel@tonic-gate ap = (ddi_acc_impl_t *)handle->ah_platform_private; 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Only single get/put 8 is supported on this "bus". 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate ap->ahi_put8 = i8042_put8; 529*7c478bd9Sstevel@tonic-gate ap->ahi_get8 = i8042_get8; 530*7c478bd9Sstevel@tonic-gate ap->ahi_put16 = NULL; 531*7c478bd9Sstevel@tonic-gate ap->ahi_get16 = NULL; 532*7c478bd9Sstevel@tonic-gate ap->ahi_put32 = NULL; 533*7c478bd9Sstevel@tonic-gate ap->ahi_get32 = NULL; 534*7c478bd9Sstevel@tonic-gate ap->ahi_put64 = NULL; 535*7c478bd9Sstevel@tonic-gate ap->ahi_get64 = NULL; 536*7c478bd9Sstevel@tonic-gate ap->ahi_rep_put8 = NULL; 537*7c478bd9Sstevel@tonic-gate ap->ahi_rep_get8 = NULL; 538*7c478bd9Sstevel@tonic-gate ap->ahi_rep_put16 = NULL; 539*7c478bd9Sstevel@tonic-gate ap->ahi_rep_get16 = NULL; 540*7c478bd9Sstevel@tonic-gate ap->ahi_rep_put32 = NULL; 541*7c478bd9Sstevel@tonic-gate ap->ahi_rep_get32 = NULL; 542*7c478bd9Sstevel@tonic-gate ap->ahi_rep_put64 = NULL; 543*7c478bd9Sstevel@tonic-gate ap->ahi_rep_get64 = NULL; 544*7c478bd9Sstevel@tonic-gate *addrp = 0; 545*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate case DDI_MO_UNMAP: 548*7c478bd9Sstevel@tonic-gate port->initialized = B_FALSE; 549*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate default: 552*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: map operation %d not supported", 553*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), mp->map_op); 554*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate /* 559*7c478bd9Sstevel@tonic-gate * i8042 hardware interrupt routine. Called for both main and aux port 560*7c478bd9Sstevel@tonic-gate * interrupts. 561*7c478bd9Sstevel@tonic-gate */ 562*7c478bd9Sstevel@tonic-gate static unsigned int 563*7c478bd9Sstevel@tonic-gate i8042_intr(caddr_t arg) 564*7c478bd9Sstevel@tonic-gate { 565*7c478bd9Sstevel@tonic-gate struct i8042 *global = (struct i8042 *)arg; 566*7c478bd9Sstevel@tonic-gate enum i8042_ports which_port; 567*7c478bd9Sstevel@tonic-gate unsigned char stat; 568*7c478bd9Sstevel@tonic-gate unsigned char byte; 569*7c478bd9Sstevel@tonic-gate int new_wptr; 570*7c478bd9Sstevel@tonic-gate struct i8042_port *port; 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate mutex_enter(&global->i8042_mutex); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate stat = ddi_get8(global->io_handle, global->io_addr + I8042_STAT); 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate if (! (stat & I8042_STAT_OUTBF)) { 577*7c478bd9Sstevel@tonic-gate ++i8042_unclaimed_interrupts; 578*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 579*7c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate byte = ddi_get8(global->io_handle, global->io_addr + I8042_DATA); 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate which_port = (stat & I8042_STAT_AUXBF) ? AUX_PORT : MAIN_PORT; 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate port = &global->i8042_ports[which_port]; 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate if (! port->initialized) { 589*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 590*7c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate new_wptr = (port->wptr + 1) % BUFSIZ; 594*7c478bd9Sstevel@tonic-gate if (new_wptr == port->rptr) { 595*7c478bd9Sstevel@tonic-gate port->overruns++; 596*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 597*7c478bd9Sstevel@tonic-gate if (port->overruns % 50 == 1) { 598*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "i8042/%d: %d overruns\n", 599*7c478bd9Sstevel@tonic-gate which_port, port->overruns); 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate #endif 602*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 603*7c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate port->buf[port->wptr] = byte; 607*7c478bd9Sstevel@tonic-gate port->wptr = new_wptr; 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate #if defined(USE_SOFT_INTRS) 610*7c478bd9Sstevel@tonic-gate if (port->soft_intr_enabled) 611*7c478bd9Sstevel@tonic-gate (void) ddi_intr_trigger_softint(port->soft_hdl, NULL); 612*7c478bd9Sstevel@tonic-gate #endif 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate #if !defined(USE_SOFT_INTRS) 617*7c478bd9Sstevel@tonic-gate mutex_enter(&port->intr_mutex); 618*7c478bd9Sstevel@tonic-gate if (port->intr_func != NULL) 619*7c478bd9Sstevel@tonic-gate port->intr_func(port->intr_arg1, NULL); 620*7c478bd9Sstevel@tonic-gate mutex_exit(&port->intr_mutex); 621*7c478bd9Sstevel@tonic-gate #endif 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate static void 627*7c478bd9Sstevel@tonic-gate i8042_write_command_byte(struct i8042_port *port, unsigned char cb) 628*7c478bd9Sstevel@tonic-gate { 629*7c478bd9Sstevel@tonic-gate struct i8042 *global; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate global = port->i8042_global; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate mutex_enter(&global->i8042_mutex); 634*7c478bd9Sstevel@tonic-gate i8042_send(global, I8042_CMD, I8042_CMD_WCB); 635*7c478bd9Sstevel@tonic-gate i8042_send(global, I8042_DATA, cb); 636*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate /* 640*7c478bd9Sstevel@tonic-gate * Send a byte to either the i8042 command or data register, depending on 641*7c478bd9Sstevel@tonic-gate * the argument. 642*7c478bd9Sstevel@tonic-gate */ 643*7c478bd9Sstevel@tonic-gate static void 644*7c478bd9Sstevel@tonic-gate i8042_send(struct i8042 *global, int reg, unsigned char val) 645*7c478bd9Sstevel@tonic-gate { 646*7c478bd9Sstevel@tonic-gate uint8_t stat; 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate /* 649*7c478bd9Sstevel@tonic-gate * First, wait for the i8042 to be ready to accept data. 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate do { 652*7c478bd9Sstevel@tonic-gate stat = ddi_get8(global->io_handle, 653*7c478bd9Sstevel@tonic-gate global->io_addr + I8042_STAT); 654*7c478bd9Sstevel@tonic-gate } while (stat & I8042_STAT_INBF); 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate /* 657*7c478bd9Sstevel@tonic-gate * ... and then send the data. 658*7c478bd9Sstevel@tonic-gate */ 659*7c478bd9Sstevel@tonic-gate ddi_put8(global->io_handle, global->io_addr+reg, val); 660*7c478bd9Sstevel@tonic-gate } 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate /* 663*7c478bd9Sstevel@tonic-gate * Here's the interface to the virtual registers on the device. 664*7c478bd9Sstevel@tonic-gate * 665*7c478bd9Sstevel@tonic-gate * Normal interrupt-driven I/O: 666*7c478bd9Sstevel@tonic-gate * 667*7c478bd9Sstevel@tonic-gate * I8042_INT_INPUT_AVAIL (r/o) 668*7c478bd9Sstevel@tonic-gate * Interrupt mode input bytes available? Zero = No. 669*7c478bd9Sstevel@tonic-gate * I8042_INT_INPUT_DATA (r/o) 670*7c478bd9Sstevel@tonic-gate * Fetch interrupt mode input byte. 671*7c478bd9Sstevel@tonic-gate * I8042_INT_OUTPUT_DATA (w/o) 672*7c478bd9Sstevel@tonic-gate * Interrupt mode output byte. 673*7c478bd9Sstevel@tonic-gate * 674*7c478bd9Sstevel@tonic-gate * Polled I/O, used by (e.g.) kmdb, when normal system services are 675*7c478bd9Sstevel@tonic-gate * unavailable: 676*7c478bd9Sstevel@tonic-gate * 677*7c478bd9Sstevel@tonic-gate * I8042_POLL_INPUT_AVAIL (r/o) 678*7c478bd9Sstevel@tonic-gate * Polled mode input bytes available? Zero = No. 679*7c478bd9Sstevel@tonic-gate * I8042_POLL_INPUT_DATA (r/o) 680*7c478bd9Sstevel@tonic-gate * Polled mode input byte. 681*7c478bd9Sstevel@tonic-gate * I8042_POLL_OUTPUT_DATA (w/o) 682*7c478bd9Sstevel@tonic-gate * Polled mode output byte. 683*7c478bd9Sstevel@tonic-gate * 684*7c478bd9Sstevel@tonic-gate * Note that in polled mode we cannot use cmn_err; only prom_printf is safe. 685*7c478bd9Sstevel@tonic-gate */ 686*7c478bd9Sstevel@tonic-gate static uint8_t 687*7c478bd9Sstevel@tonic-gate i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr) 688*7c478bd9Sstevel@tonic-gate { 689*7c478bd9Sstevel@tonic-gate struct i8042_port *port; 690*7c478bd9Sstevel@tonic-gate struct i8042 *global; 691*7c478bd9Sstevel@tonic-gate uint8_t ret; 692*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *h; 693*7c478bd9Sstevel@tonic-gate uint8_t stat; 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate h = (ddi_acc_hdl_t *)handlep; 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate port = (struct i8042_port *)h->ah_bus_private; 698*7c478bd9Sstevel@tonic-gate global = port->i8042_global; 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate switch ((uintptr_t)addr) { 701*7c478bd9Sstevel@tonic-gate case I8042_INT_INPUT_AVAIL: 702*7c478bd9Sstevel@tonic-gate mutex_enter(&global->i8042_mutex); 703*7c478bd9Sstevel@tonic-gate ret = port->rptr != port->wptr; 704*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 705*7c478bd9Sstevel@tonic-gate return (ret); 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate case I8042_INT_INPUT_DATA: 708*7c478bd9Sstevel@tonic-gate mutex_enter(&global->i8042_mutex); 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate if (port->rptr != port->wptr) { 711*7c478bd9Sstevel@tonic-gate ret = port->buf[port->rptr]; 712*7c478bd9Sstevel@tonic-gate port->rptr = (port->rptr + 1) % BUFSIZ; 713*7c478bd9Sstevel@tonic-gate } else { 714*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 715*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 716*7c478bd9Sstevel@tonic-gate "i8042: Tried to read from empty buffer"); 717*7c478bd9Sstevel@tonic-gate #endif 718*7c478bd9Sstevel@tonic-gate ret = 0; 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate break; 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 727*7c478bd9Sstevel@tonic-gate case I8042_INT_OUTPUT_DATA: 728*7c478bd9Sstevel@tonic-gate case I8042_POLL_OUTPUT_DATA: 729*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "i8042: read of write-only register 0x%p", 730*7c478bd9Sstevel@tonic-gate (void *)addr); 731*7c478bd9Sstevel@tonic-gate ret = 0; 732*7c478bd9Sstevel@tonic-gate break; 733*7c478bd9Sstevel@tonic-gate #endif 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate case I8042_POLL_INPUT_AVAIL: 736*7c478bd9Sstevel@tonic-gate if (port->rptr != port->wptr) 737*7c478bd9Sstevel@tonic-gate return (B_TRUE); 738*7c478bd9Sstevel@tonic-gate for (;;) { 739*7c478bd9Sstevel@tonic-gate stat = ddi_get8(global->io_handle, 740*7c478bd9Sstevel@tonic-gate global->io_addr + I8042_STAT); 741*7c478bd9Sstevel@tonic-gate if ((stat & I8042_STAT_OUTBF) == 0) 742*7c478bd9Sstevel@tonic-gate return (B_FALSE); 743*7c478bd9Sstevel@tonic-gate switch (port->which) { 744*7c478bd9Sstevel@tonic-gate case MAIN_PORT: 745*7c478bd9Sstevel@tonic-gate if ((stat & I8042_STAT_AUXBF) == 0) 746*7c478bd9Sstevel@tonic-gate return (B_TRUE); 747*7c478bd9Sstevel@tonic-gate break; 748*7c478bd9Sstevel@tonic-gate case AUX_PORT: 749*7c478bd9Sstevel@tonic-gate if ((stat & I8042_STAT_AUXBF) != 0) 750*7c478bd9Sstevel@tonic-gate return (B_TRUE); 751*7c478bd9Sstevel@tonic-gate break; 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate /* 754*7c478bd9Sstevel@tonic-gate * Data for wrong port pending; discard it. 755*7c478bd9Sstevel@tonic-gate */ 756*7c478bd9Sstevel@tonic-gate (void) ddi_get8(global->io_handle, 757*7c478bd9Sstevel@tonic-gate global->io_addr + I8042_DATA); 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate case I8042_POLL_INPUT_DATA: 763*7c478bd9Sstevel@tonic-gate if (port->rptr != port->wptr) { 764*7c478bd9Sstevel@tonic-gate ret = port->buf[port->rptr]; 765*7c478bd9Sstevel@tonic-gate port->rptr = (port->rptr + 1) % BUFSIZ; 766*7c478bd9Sstevel@tonic-gate return (ret); 767*7c478bd9Sstevel@tonic-gate } 768*7c478bd9Sstevel@tonic-gate 769*7c478bd9Sstevel@tonic-gate stat = ddi_get8(global->io_handle, 770*7c478bd9Sstevel@tonic-gate global->io_addr + I8042_STAT); 771*7c478bd9Sstevel@tonic-gate if ((stat & I8042_STAT_OUTBF) == 0) { 772*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 773*7c478bd9Sstevel@tonic-gate prom_printf("I8042_POLL_INPUT_DATA: no data!\n"); 774*7c478bd9Sstevel@tonic-gate #endif 775*7c478bd9Sstevel@tonic-gate return (0); 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate ret = ddi_get8(global->io_handle, 778*7c478bd9Sstevel@tonic-gate global->io_addr + I8042_DATA); 779*7c478bd9Sstevel@tonic-gate switch (port->which) { 780*7c478bd9Sstevel@tonic-gate case MAIN_PORT: 781*7c478bd9Sstevel@tonic-gate if ((stat & I8042_STAT_AUXBF) == 0) 782*7c478bd9Sstevel@tonic-gate return (ret); 783*7c478bd9Sstevel@tonic-gate break; 784*7c478bd9Sstevel@tonic-gate case AUX_PORT: 785*7c478bd9Sstevel@tonic-gate if ((stat & I8042_STAT_AUXBF) != 0) 786*7c478bd9Sstevel@tonic-gate return (ret); 787*7c478bd9Sstevel@tonic-gate break; 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 790*7c478bd9Sstevel@tonic-gate prom_printf("I8042_POLL_INPUT_DATA: data for wrong port!\n"); 791*7c478bd9Sstevel@tonic-gate #endif 792*7c478bd9Sstevel@tonic-gate return (0); 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate default: 795*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 796*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "i8042: read of undefined register 0x%p", 797*7c478bd9Sstevel@tonic-gate (void *)addr); 798*7c478bd9Sstevel@tonic-gate #endif 799*7c478bd9Sstevel@tonic-gate ret = 0; 800*7c478bd9Sstevel@tonic-gate break; 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate return (ret); 803*7c478bd9Sstevel@tonic-gate } 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate static void 806*7c478bd9Sstevel@tonic-gate i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value) 807*7c478bd9Sstevel@tonic-gate { 808*7c478bd9Sstevel@tonic-gate struct i8042_port *port; 809*7c478bd9Sstevel@tonic-gate struct i8042 *global; 810*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *h; 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate h = (ddi_acc_hdl_t *)handlep; 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate port = (struct i8042_port *)h->ah_bus_private; 815*7c478bd9Sstevel@tonic-gate global = port->i8042_global; 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate switch ((uintptr_t)addr) { 818*7c478bd9Sstevel@tonic-gate case I8042_INT_OUTPUT_DATA: 819*7c478bd9Sstevel@tonic-gate case I8042_POLL_OUTPUT_DATA: 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA) 822*7c478bd9Sstevel@tonic-gate mutex_enter(&global->i8042_out_mutex); 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate if (port->which == AUX_PORT) 825*7c478bd9Sstevel@tonic-gate i8042_send(global, I8042_CMD, I8042_CMD_WRITE_AUX); 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate i8042_send(global, I8042_DATA, value); 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA) 830*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_out_mutex); 831*7c478bd9Sstevel@tonic-gate break; 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 835*7c478bd9Sstevel@tonic-gate case I8042_INT_INPUT_AVAIL: 836*7c478bd9Sstevel@tonic-gate case I8042_INT_INPUT_DATA: 837*7c478bd9Sstevel@tonic-gate case I8042_POLL_INPUT_AVAIL: 838*7c478bd9Sstevel@tonic-gate case I8042_POLL_INPUT_DATA: 839*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "i8042: write of read-only register 0x%p", 840*7c478bd9Sstevel@tonic-gate (void *)addr); 841*7c478bd9Sstevel@tonic-gate break; 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate default: 844*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "i8042: read of undefined register 0x%p", 845*7c478bd9Sstevel@tonic-gate (void *)addr); 846*7c478bd9Sstevel@tonic-gate break; 847*7c478bd9Sstevel@tonic-gate #endif 848*7c478bd9Sstevel@tonic-gate } 849*7c478bd9Sstevel@tonic-gate } 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 853*7c478bd9Sstevel@tonic-gate static int 854*7c478bd9Sstevel@tonic-gate i8042_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 855*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 856*7c478bd9Sstevel@tonic-gate { 857*7c478bd9Sstevel@tonic-gate struct i8042_port *port; 858*7c478bd9Sstevel@tonic-gate #if defined(USE_SOFT_INTRS) 859*7c478bd9Sstevel@tonic-gate struct i8042 *global; 860*7c478bd9Sstevel@tonic-gate int ret; 861*7c478bd9Sstevel@tonic-gate #endif 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate switch (intr_op) { 864*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 865*7c478bd9Sstevel@tonic-gate *(int *)result = DDI_INTR_TYPE_FIXED; 866*7c478bd9Sstevel@tonic-gate break; 867*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 868*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 869*7c478bd9Sstevel@tonic-gate /* 870*7c478bd9Sstevel@tonic-gate * For sparc, there is concern to pass to its parent, 871*7c478bd9Sstevel@tonic-gate * so just hard code it to 0 872*7c478bd9Sstevel@tonic-gate */ 873*7c478bd9Sstevel@tonic-gate *(int *)result = 0; 874*7c478bd9Sstevel@tonic-gate #else 875*7c478bd9Sstevel@tonic-gate if (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result) 876*7c478bd9Sstevel@tonic-gate == DDI_FAILURE) 877*7c478bd9Sstevel@tonic-gate *(int *)result = 0; 878*7c478bd9Sstevel@tonic-gate #endif /* defined(__sparc) */ 879*7c478bd9Sstevel@tonic-gate break; 880*7c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 881*7c478bd9Sstevel@tonic-gate *(int *)result = 1; 882*7c478bd9Sstevel@tonic-gate break; 883*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 884*7c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 885*7c478bd9Sstevel@tonic-gate break; 886*7c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 887*7c478bd9Sstevel@tonic-gate break; 888*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 889*7c478bd9Sstevel@tonic-gate /* Hard coding it for x86 */ 890*7c478bd9Sstevel@tonic-gate *(int *)result = 5; 891*7c478bd9Sstevel@tonic-gate break; 892*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 893*7c478bd9Sstevel@tonic-gate port = ddi_get_parent_data(rdip); 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate #if defined(USE_SOFT_INTRS) 896*7c478bd9Sstevel@tonic-gate global = port->i8042_global; 897*7c478bd9Sstevel@tonic-gate ret = ddi_intr_add_softint(rdip, &port->soft_hdl, 898*7c478bd9Sstevel@tonic-gate I8042_SOFTINT_PRI, hdlp->ih_cb_func, hdlp->ih_cb_arg1); 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 901*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 902*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s #%d: " 903*7c478bd9Sstevel@tonic-gate "Cannot add soft interrupt for %s #%d, ret=%d.", 904*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), ddi_get_instance(dip), 905*7c478bd9Sstevel@tonic-gate DRIVER_NAME(rdip), ddi_get_instance(rdip), ret); 906*7c478bd9Sstevel@tonic-gate #endif /* defined(DEBUG) */ 907*7c478bd9Sstevel@tonic-gate return (ret); 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate #else /* defined(USE_SOFT_INTRS) */ 911*7c478bd9Sstevel@tonic-gate mutex_enter(&port->intr_mutex); 912*7c478bd9Sstevel@tonic-gate port->intr_func = hdlp->ih_cb_func; 913*7c478bd9Sstevel@tonic-gate port->intr_arg1 = hdlp->ih_cb_arg1; 914*7c478bd9Sstevel@tonic-gate port->intr_arg2 = hdlp->ih_cb_arg2; 915*7c478bd9Sstevel@tonic-gate mutex_exit(&port->intr_mutex); 916*7c478bd9Sstevel@tonic-gate #endif /* defined(USE_SOFT_INTRS) */ 917*7c478bd9Sstevel@tonic-gate break; 918*7c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 919*7c478bd9Sstevel@tonic-gate port = ddi_get_parent_data(rdip); 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate #if defined(USE_SOFT_INTRS) 922*7c478bd9Sstevel@tonic-gate global = port->i8042_global; 923*7c478bd9Sstevel@tonic-gate mutex_enter(&global->i8042_mutex); 924*7c478bd9Sstevel@tonic-gate port->soft_hdl = 0; 925*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 926*7c478bd9Sstevel@tonic-gate #else /* defined(USE_SOFT_INTRS) */ 927*7c478bd9Sstevel@tonic-gate mutex_enter(&port->intr_mutex); 928*7c478bd9Sstevel@tonic-gate port->intr_func = NULL; 929*7c478bd9Sstevel@tonic-gate mutex_exit(&port->intr_mutex); 930*7c478bd9Sstevel@tonic-gate #endif /* defined(USE_SOFT_INTRS) */ 931*7c478bd9Sstevel@tonic-gate break; 932*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 933*7c478bd9Sstevel@tonic-gate port = ddi_get_parent_data(rdip); 934*7c478bd9Sstevel@tonic-gate #if defined(USE_SOFT_INTRS) 935*7c478bd9Sstevel@tonic-gate global = port->i8042_global; 936*7c478bd9Sstevel@tonic-gate mutex_enter(&global->i8042_mutex); 937*7c478bd9Sstevel@tonic-gate port->soft_intr_enabled = B_TRUE; 938*7c478bd9Sstevel@tonic-gate if (port->wptr != port->rptr) 939*7c478bd9Sstevel@tonic-gate (void) ddi_intr_trigger_softint(port->soft_hdl, NULL); 940*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 941*7c478bd9Sstevel@tonic-gate #else /* defined(USE_SOFT_INTRS) */ 942*7c478bd9Sstevel@tonic-gate mutex_enter(&port->intr_mutex); 943*7c478bd9Sstevel@tonic-gate if (port->wptr != port->rptr) 944*7c478bd9Sstevel@tonic-gate port->intr_func(port->intr_arg1, port->intr_arg2); 945*7c478bd9Sstevel@tonic-gate mutex_exit(&port->intr_mutex); 946*7c478bd9Sstevel@tonic-gate #endif /* defined(USE_SOFT_INTRS) */ 947*7c478bd9Sstevel@tonic-gate break; 948*7c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 949*7c478bd9Sstevel@tonic-gate #if defined(USE_SOFT_INTRS) 950*7c478bd9Sstevel@tonic-gate port = ddi_get_parent_data(rdip); 951*7c478bd9Sstevel@tonic-gate global = port->i8042_global; 952*7c478bd9Sstevel@tonic-gate mutex_enter(&global->i8042_mutex); 953*7c478bd9Sstevel@tonic-gate port->soft_intr_enabled = B_FALSE; 954*7c478bd9Sstevel@tonic-gate (void) ddi_intr_remove_softint((port->soft_hdl); 955*7c478bd9Sstevel@tonic-gate mutex_exit(&global->i8042_mutex); 956*7c478bd9Sstevel@tonic-gate #endif /* defined(USE_SOFT_INTRS) */ 957*7c478bd9Sstevel@tonic-gate break; 958*7c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 959*7c478bd9Sstevel@tonic-gate *(int *)result = 1; 960*7c478bd9Sstevel@tonic-gate break; 961*7c478bd9Sstevel@tonic-gate default: 962*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 963*7c478bd9Sstevel@tonic-gate } 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 966*7c478bd9Sstevel@tonic-gate } 967*7c478bd9Sstevel@tonic-gate 968*7c478bd9Sstevel@tonic-gate static int 969*7c478bd9Sstevel@tonic-gate i8042_ctlops(dev_info_t *dip, dev_info_t *rdip, 970*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 971*7c478bd9Sstevel@tonic-gate { 972*7c478bd9Sstevel@tonic-gate int *iprop; 973*7c478bd9Sstevel@tonic-gate unsigned int iprop_len; 974*7c478bd9Sstevel@tonic-gate int which_port; 975*7c478bd9Sstevel@tonic-gate char name[16]; 976*7c478bd9Sstevel@tonic-gate struct i8042 *global; 977*7c478bd9Sstevel@tonic-gate dev_info_t *child; 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate global = ddi_get_driver_private(dip); 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate switch (op) { 982*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 983*7c478bd9Sstevel@tonic-gate child = (dev_info_t *)arg; 984*7c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 985*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", &iprop, &iprop_len) != 986*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 987*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 988*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s #%d: Missing 'reg' on %s@???", 989*7c478bd9Sstevel@tonic-gate DRIVER_NAME(dip), ddi_get_instance(dip), 990*7c478bd9Sstevel@tonic-gate ddi_node_name(child)); 991*7c478bd9Sstevel@tonic-gate #endif 992*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 993*7c478bd9Sstevel@tonic-gate } 994*7c478bd9Sstevel@tonic-gate which_port = iprop[0]; 995*7c478bd9Sstevel@tonic-gate ddi_prop_free((void *)iprop); 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate (void) sprintf(name, "%d", which_port); 998*7c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 999*7c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, 1000*7c478bd9Sstevel@tonic-gate (caddr_t)&global->i8042_ports[which_port]); 1001*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 1004*7c478bd9Sstevel@tonic-gate child = (dev_info_t *)arg; 1005*7c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 1006*7c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 1007*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1008*7c478bd9Sstevel@tonic-gate 1009*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 1010*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?8042 device: %s@%s, %s # %d\n", 1011*7c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip), 1012*7c478bd9Sstevel@tonic-gate DRIVER_NAME(rdip), ddi_get_instance(rdip)); 1013*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate default: 1016*7c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 1017*7c478bd9Sstevel@tonic-gate } 1018*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate 1021*7c478bd9Sstevel@tonic-gate static void 1022*7c478bd9Sstevel@tonic-gate alloc_kb_mouse(dev_info_t *i8042_dip) 1023*7c478bd9Sstevel@tonic-gate { 1024*7c478bd9Sstevel@tonic-gate static int alloced = 0; 1025*7c478bd9Sstevel@tonic-gate int circ, acpi_off = 0; 1026*7c478bd9Sstevel@tonic-gate dev_info_t *xdip; 1027*7c478bd9Sstevel@tonic-gate char *acpi_prop; 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate ndi_devi_enter(i8042_dip, &circ); 1031*7c478bd9Sstevel@tonic-gate if (alloced) { /* just in case we are multi-threaded */ 1032*7c478bd9Sstevel@tonic-gate ndi_devi_exit(i8042_dip, circ); 1033*7c478bd9Sstevel@tonic-gate return; 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate alloced = 1; 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate /* don't alloc unless acpi is off */ 1038*7c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1039*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) { 1040*7c478bd9Sstevel@tonic-gate if (strcmp("off", acpi_prop) == 0) { 1041*7c478bd9Sstevel@tonic-gate acpi_off = 1; 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate ddi_prop_free(acpi_prop); 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate if (acpi_off == 0) { 1046*7c478bd9Sstevel@tonic-gate ndi_devi_exit(i8042_dip, circ); 1047*7c478bd9Sstevel@tonic-gate return; 1048*7c478bd9Sstevel@tonic-gate } 1049*7c478bd9Sstevel@tonic-gate 1050*7c478bd9Sstevel@tonic-gate /* mouse */ 1051*7c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(i8042_dip, "mouse", 1052*7c478bd9Sstevel@tonic-gate (dnode_t)DEVI_SID_NODEID, &xdip); 1053*7c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 1054*7c478bd9Sstevel@tonic-gate "reg", 1); 1055*7c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1056*7c478bd9Sstevel@tonic-gate "compatible", "pnpPNP,f03"); 1057*7c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1058*7c478bd9Sstevel@tonic-gate "device-type", "mouse"); 1059*7c478bd9Sstevel@tonic-gate (void) ndi_devi_bind_driver(xdip, 0); 1060*7c478bd9Sstevel@tonic-gate 1061*7c478bd9Sstevel@tonic-gate /* keyboard */ 1062*7c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(i8042_dip, "keyboard", 1063*7c478bd9Sstevel@tonic-gate (dnode_t)DEVI_SID_NODEID, &xdip); 1064*7c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 1065*7c478bd9Sstevel@tonic-gate "reg", 0); 1066*7c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1067*7c478bd9Sstevel@tonic-gate "compatible", "pnpPNP,303"); 1068*7c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1069*7c478bd9Sstevel@tonic-gate "device-type", "keyboard"); 1070*7c478bd9Sstevel@tonic-gate (void) ndi_devi_bind_driver(xdip, 0); 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate ndi_devi_exit(i8042_dip, circ); 1073*7c478bd9Sstevel@tonic-gate } 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate static int 1076*7c478bd9Sstevel@tonic-gate i8042_bus_config(dev_info_t *parent, uint_t flags, 1077*7c478bd9Sstevel@tonic-gate ddi_bus_config_op_t op, void *arg, dev_info_t **childp) 1078*7c478bd9Sstevel@tonic-gate { 1079*7c478bd9Sstevel@tonic-gate alloc_kb_mouse(parent); 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate return (ndi_busop_bus_config(parent, flags, op, arg, childp, 0)); 1082*7c478bd9Sstevel@tonic-gate } 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate static int 1085*7c478bd9Sstevel@tonic-gate i8042_bus_unconfig(dev_info_t *parent, uint_t flags, 1086*7c478bd9Sstevel@tonic-gate ddi_bus_config_op_t op, void *arg) 1087*7c478bd9Sstevel@tonic-gate { 1088*7c478bd9Sstevel@tonic-gate return (ndi_busop_bus_unconfig(parent, flags, op, arg)); 1089*7c478bd9Sstevel@tonic-gate } 1090