1*d58fda43Sjbeloro /* 2*d58fda43Sjbeloro * CDDL HEADER START 3*d58fda43Sjbeloro * 4*d58fda43Sjbeloro * The contents of this file are subject to the terms of the 5*d58fda43Sjbeloro * Common Development and Distribution License, Version 1.0 only 6*d58fda43Sjbeloro * (the "License"). You may not use this file except in compliance 7*d58fda43Sjbeloro * with the License. 8*d58fda43Sjbeloro * 9*d58fda43Sjbeloro * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*d58fda43Sjbeloro * or http://www.opensolaris.org/os/licensing. 11*d58fda43Sjbeloro * See the License for the specific language governing permissions 12*d58fda43Sjbeloro * and limitations under the License. 13*d58fda43Sjbeloro * 14*d58fda43Sjbeloro * When distributing Covered Code, include this CDDL HEADER in each 15*d58fda43Sjbeloro * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*d58fda43Sjbeloro * If applicable, add the following below this CDDL HEADER, with the 17*d58fda43Sjbeloro * fields enclosed by brackets "[]" replaced with your own identifying 18*d58fda43Sjbeloro * information: Portions Copyright [yyyy] [name of copyright owner] 19*d58fda43Sjbeloro * 20*d58fda43Sjbeloro * CDDL HEADER END 21*d58fda43Sjbeloro */ 22*d58fda43Sjbeloro 23*d58fda43Sjbeloro /* 24*d58fda43Sjbeloro * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25*d58fda43Sjbeloro * Use is subject to license terms. 26*d58fda43Sjbeloro */ 27*d58fda43Sjbeloro 28*d58fda43Sjbeloro #pragma ident "%Z%%M% %I% %E% SMI" 29*d58fda43Sjbeloro 30*d58fda43Sjbeloro /* 31*d58fda43Sjbeloro * Driver to control Alert and Power LEDs for the Seattle platform. 32*d58fda43Sjbeloro * Alert LED is also known as Service (required). 33*d58fda43Sjbeloro * Power LED is also known as Activity. 34*d58fda43Sjbeloro */ 35*d58fda43Sjbeloro #include <sys/types.h> 36*d58fda43Sjbeloro #include <sys/time.h> 37*d58fda43Sjbeloro #include <sys/errno.h> 38*d58fda43Sjbeloro #include <sys/cmn_err.h> 39*d58fda43Sjbeloro #include <sys/param.h> 40*d58fda43Sjbeloro #include <sys/modctl.h> 41*d58fda43Sjbeloro #include <sys/conf.h> 42*d58fda43Sjbeloro #include <sys/open.h> 43*d58fda43Sjbeloro #include <sys/stat.h> 44*d58fda43Sjbeloro #include <sys/clock.h> 45*d58fda43Sjbeloro #include <sys/ddi.h> 46*d58fda43Sjbeloro #include <sys/sunddi.h> 47*d58fda43Sjbeloro #include <sys/file.h> 48*d58fda43Sjbeloro #include <sys/note.h> 49*d58fda43Sjbeloro #include <sys/epic.h> 50*d58fda43Sjbeloro 51*d58fda43Sjbeloro 52*d58fda43Sjbeloro /* 53*d58fda43Sjbeloro * Some #defs that must be here as they differ for power.c 54*d58fda43Sjbeloro * and epic.c 55*d58fda43Sjbeloro */ 56*d58fda43Sjbeloro #define EPIC_REGS_OFFSET 0x00 57*d58fda43Sjbeloro #define EPIC_REGS_LEN 0x80 58*d58fda43Sjbeloro 59*d58fda43Sjbeloro #define EPIC_IND_DATA 0x40 60*d58fda43Sjbeloro #define EPIC_IND_ADDR 0x41 61*d58fda43Sjbeloro #define EPIC_WRITE_MASK 0x80 62*d58fda43Sjbeloro 63*d58fda43Sjbeloro /* dev_ops and cb_ops entry point function declarations */ 64*d58fda43Sjbeloro static int epic_attach(dev_info_t *, ddi_attach_cmd_t); 65*d58fda43Sjbeloro static int epic_detach(dev_info_t *, ddi_detach_cmd_t); 66*d58fda43Sjbeloro static int epic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 67*d58fda43Sjbeloro static int epic_open(dev_t *, int, int, cred_t *); 68*d58fda43Sjbeloro static int epic_close(dev_t, int, int, cred_t *); 69*d58fda43Sjbeloro static int epic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 70*d58fda43Sjbeloro 71*d58fda43Sjbeloro struct cb_ops epic_cb_ops = { 72*d58fda43Sjbeloro epic_open, /* open */ 73*d58fda43Sjbeloro epic_close, /* close */ 74*d58fda43Sjbeloro nodev, /* strategy */ 75*d58fda43Sjbeloro nodev, /* print */ 76*d58fda43Sjbeloro nodev, /* dump */ 77*d58fda43Sjbeloro nodev, /* read */ 78*d58fda43Sjbeloro nodev, /* write */ 79*d58fda43Sjbeloro epic_ioctl, /* ioctl */ 80*d58fda43Sjbeloro nodev, /* devmap */ 81*d58fda43Sjbeloro nodev, /* mmap */ 82*d58fda43Sjbeloro ddi_segmap, /* segmap */ 83*d58fda43Sjbeloro nochpoll, /* poll */ 84*d58fda43Sjbeloro ddi_prop_op, /* cb_prop_op */ 85*d58fda43Sjbeloro NULL, /* streamtab - for STREAMS drivers */ 86*d58fda43Sjbeloro D_NEW | D_MP /* driver compatibility flag */ 87*d58fda43Sjbeloro }; 88*d58fda43Sjbeloro 89*d58fda43Sjbeloro static struct dev_ops epic_dev_ops = { 90*d58fda43Sjbeloro DEVO_REV, /* driver build version */ 91*d58fda43Sjbeloro 0, /* device reference count */ 92*d58fda43Sjbeloro epic_getinfo, 93*d58fda43Sjbeloro nulldev, 94*d58fda43Sjbeloro nulldev, /* probe */ 95*d58fda43Sjbeloro epic_attach, 96*d58fda43Sjbeloro epic_detach, 97*d58fda43Sjbeloro nulldev, /* reset */ 98*d58fda43Sjbeloro &epic_cb_ops, 99*d58fda43Sjbeloro (struct bus_ops *)NULL, 100*d58fda43Sjbeloro nulldev /* power */ 101*d58fda43Sjbeloro }; 102*d58fda43Sjbeloro 103*d58fda43Sjbeloro 104*d58fda43Sjbeloro /* 105*d58fda43Sjbeloro * Soft state 106*d58fda43Sjbeloro */ 107*d58fda43Sjbeloro struct epic_softc { 108*d58fda43Sjbeloro dev_info_t *dip; 109*d58fda43Sjbeloro kmutex_t mutex; 110*d58fda43Sjbeloro uint8_t *cmd_reg; 111*d58fda43Sjbeloro ddi_acc_handle_t cmd_handle; 112*d58fda43Sjbeloro }; 113*d58fda43Sjbeloro 114*d58fda43Sjbeloro #define getsoftc(inst) ((struct epic_softc *)ddi_get_soft_state(statep, \ 115*d58fda43Sjbeloro (inst))) 116*d58fda43Sjbeloro 117*d58fda43Sjbeloro /* module configuration stuff */ 118*d58fda43Sjbeloro static void *statep; 119*d58fda43Sjbeloro extern struct mod_ops mod_driverops; 120*d58fda43Sjbeloro 121*d58fda43Sjbeloro static struct modldrv modldrv = { 122*d58fda43Sjbeloro &mod_driverops, 123*d58fda43Sjbeloro "epic_client driver v%I%", 124*d58fda43Sjbeloro &epic_dev_ops 125*d58fda43Sjbeloro }; 126*d58fda43Sjbeloro 127*d58fda43Sjbeloro static struct modlinkage modlinkage = { 128*d58fda43Sjbeloro MODREV_1, 129*d58fda43Sjbeloro &modldrv, 130*d58fda43Sjbeloro 0 131*d58fda43Sjbeloro }; 132*d58fda43Sjbeloro 133*d58fda43Sjbeloro int 134*d58fda43Sjbeloro _init(void) 135*d58fda43Sjbeloro { 136*d58fda43Sjbeloro int e; 137*d58fda43Sjbeloro 138*d58fda43Sjbeloro if ((e = ddi_soft_state_init(&statep, 139*d58fda43Sjbeloro sizeof (struct epic_softc), 0)) != 0) { 140*d58fda43Sjbeloro return (e); 141*d58fda43Sjbeloro } 142*d58fda43Sjbeloro 143*d58fda43Sjbeloro if ((e = mod_install(&modlinkage)) != 0) 144*d58fda43Sjbeloro ddi_soft_state_fini(&statep); 145*d58fda43Sjbeloro 146*d58fda43Sjbeloro return (e); 147*d58fda43Sjbeloro } 148*d58fda43Sjbeloro 149*d58fda43Sjbeloro int 150*d58fda43Sjbeloro _fini(void) 151*d58fda43Sjbeloro { 152*d58fda43Sjbeloro int e; 153*d58fda43Sjbeloro 154*d58fda43Sjbeloro if ((e = mod_remove(&modlinkage)) != 0) 155*d58fda43Sjbeloro return (e); 156*d58fda43Sjbeloro 157*d58fda43Sjbeloro ddi_soft_state_fini(&statep); 158*d58fda43Sjbeloro 159*d58fda43Sjbeloro return (DDI_SUCCESS); 160*d58fda43Sjbeloro } 161*d58fda43Sjbeloro 162*d58fda43Sjbeloro int 163*d58fda43Sjbeloro _info(struct modinfo *modinfop) 164*d58fda43Sjbeloro { 165*d58fda43Sjbeloro return (mod_info(&modlinkage, modinfop)); 166*d58fda43Sjbeloro } 167*d58fda43Sjbeloro 168*d58fda43Sjbeloro /*ARGSUSED*/ 169*d58fda43Sjbeloro static int 170*d58fda43Sjbeloro epic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 171*d58fda43Sjbeloro { 172*d58fda43Sjbeloro int inst; 173*d58fda43Sjbeloro int retval = DDI_SUCCESS; 174*d58fda43Sjbeloro struct epic_softc *softc; 175*d58fda43Sjbeloro 176*d58fda43Sjbeloro inst = (getminor((dev_t)arg)); 177*d58fda43Sjbeloro 178*d58fda43Sjbeloro switch (cmd) { 179*d58fda43Sjbeloro case DDI_INFO_DEVT2DEVINFO: 180*d58fda43Sjbeloro if ((softc = getsoftc(inst)) == NULL) { 181*d58fda43Sjbeloro *result = (void *)NULL; 182*d58fda43Sjbeloro retval = DDI_FAILURE; 183*d58fda43Sjbeloro } else 184*d58fda43Sjbeloro *result = (void *)softc->dip; 185*d58fda43Sjbeloro break; 186*d58fda43Sjbeloro 187*d58fda43Sjbeloro case DDI_INFO_DEVT2INSTANCE: 188*d58fda43Sjbeloro *result = (void *)inst; 189*d58fda43Sjbeloro break; 190*d58fda43Sjbeloro 191*d58fda43Sjbeloro default: 192*d58fda43Sjbeloro retval = DDI_FAILURE; 193*d58fda43Sjbeloro } 194*d58fda43Sjbeloro 195*d58fda43Sjbeloro return (retval); 196*d58fda43Sjbeloro } 197*d58fda43Sjbeloro 198*d58fda43Sjbeloro static int 199*d58fda43Sjbeloro epic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 200*d58fda43Sjbeloro { 201*d58fda43Sjbeloro int inst; 202*d58fda43Sjbeloro struct epic_softc *softc = NULL; 203*d58fda43Sjbeloro int minor; 204*d58fda43Sjbeloro char name[MAXNAMELEN]; 205*d58fda43Sjbeloro ddi_device_acc_attr_t dev_attr; 206*d58fda43Sjbeloro int res; 207*d58fda43Sjbeloro 208*d58fda43Sjbeloro switch (cmd) { 209*d58fda43Sjbeloro case DDI_ATTACH: 210*d58fda43Sjbeloro inst = ddi_get_instance(dip); 211*d58fda43Sjbeloro (void) sprintf(name, "env-monitor%d", inst); 212*d58fda43Sjbeloro minor = inst; 213*d58fda43Sjbeloro if (ddi_create_minor_node(dip, name, S_IFCHR, minor, 214*d58fda43Sjbeloro DDI_PSEUDO, NULL) == DDI_FAILURE) { 215*d58fda43Sjbeloro cmn_err(CE_WARN, 216*d58fda43Sjbeloro "ddi_create_minor_node() failed for inst %d\n", 217*d58fda43Sjbeloro inst); 218*d58fda43Sjbeloro return (DDI_FAILURE); 219*d58fda43Sjbeloro } 220*d58fda43Sjbeloro 221*d58fda43Sjbeloro /* Allocate a soft state structure for this instance */ 222*d58fda43Sjbeloro if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS) { 223*d58fda43Sjbeloro cmn_err(CE_WARN, " ddi_soft_state_zalloc() failed " 224*d58fda43Sjbeloro "for inst %d\n", inst); 225*d58fda43Sjbeloro break; 226*d58fda43Sjbeloro } 227*d58fda43Sjbeloro 228*d58fda43Sjbeloro /* Setup soft state */ 229*d58fda43Sjbeloro if ((softc = getsoftc(inst)) == NULL) { 230*d58fda43Sjbeloro break; 231*d58fda43Sjbeloro } 232*d58fda43Sjbeloro softc->dip = dip; 233*d58fda43Sjbeloro mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL); 234*d58fda43Sjbeloro 235*d58fda43Sjbeloro /* Setup device attributes */ 236*d58fda43Sjbeloro dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 237*d58fda43Sjbeloro dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 238*d58fda43Sjbeloro dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 239*d58fda43Sjbeloro 240*d58fda43Sjbeloro res = ddi_regs_map_setup(dip, 0, (caddr_t *)&softc->cmd_reg, 241*d58fda43Sjbeloro EPIC_REGS_OFFSET, EPIC_REGS_LEN, &dev_attr, 242*d58fda43Sjbeloro &softc->cmd_handle); 243*d58fda43Sjbeloro 244*d58fda43Sjbeloro if (res != DDI_SUCCESS) { 245*d58fda43Sjbeloro cmn_err(CE_WARN, "ddi_regs_map_setup() failed\n"); 246*d58fda43Sjbeloro break; 247*d58fda43Sjbeloro } 248*d58fda43Sjbeloro 249*d58fda43Sjbeloro ddi_report_dev(dip); 250*d58fda43Sjbeloro 251*d58fda43Sjbeloro 252*d58fda43Sjbeloro return (DDI_SUCCESS); 253*d58fda43Sjbeloro 254*d58fda43Sjbeloro case DDI_RESUME: 255*d58fda43Sjbeloro return (DDI_SUCCESS); 256*d58fda43Sjbeloro 257*d58fda43Sjbeloro default: 258*d58fda43Sjbeloro return (DDI_FAILURE); 259*d58fda43Sjbeloro } 260*d58fda43Sjbeloro 261*d58fda43Sjbeloro /* Attach failed */ 262*d58fda43Sjbeloro /* Free soft state, if allocated. remove minor node if added earlier */ 263*d58fda43Sjbeloro if (softc) 264*d58fda43Sjbeloro ddi_soft_state_free(statep, inst); 265*d58fda43Sjbeloro 266*d58fda43Sjbeloro ddi_remove_minor_node(dip, NULL); 267*d58fda43Sjbeloro 268*d58fda43Sjbeloro return (DDI_FAILURE); 269*d58fda43Sjbeloro } 270*d58fda43Sjbeloro 271*d58fda43Sjbeloro static int 272*d58fda43Sjbeloro epic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 273*d58fda43Sjbeloro { 274*d58fda43Sjbeloro int inst; 275*d58fda43Sjbeloro struct epic_softc *softc; 276*d58fda43Sjbeloro 277*d58fda43Sjbeloro switch (cmd) { 278*d58fda43Sjbeloro case DDI_DETACH: 279*d58fda43Sjbeloro inst = ddi_get_instance(dip); 280*d58fda43Sjbeloro if ((softc = getsoftc(inst)) == NULL) 281*d58fda43Sjbeloro return (ENXIO); 282*d58fda43Sjbeloro 283*d58fda43Sjbeloro (void) ddi_regs_map_free(&softc->cmd_handle); 284*d58fda43Sjbeloro 285*d58fda43Sjbeloro 286*d58fda43Sjbeloro /* Free the soft state and remove minor node added earlier */ 287*d58fda43Sjbeloro mutex_destroy(&softc->mutex); 288*d58fda43Sjbeloro ddi_soft_state_free(statep, inst); 289*d58fda43Sjbeloro ddi_remove_minor_node(dip, NULL); 290*d58fda43Sjbeloro return (DDI_SUCCESS); 291*d58fda43Sjbeloro 292*d58fda43Sjbeloro case DDI_SUSPEND: 293*d58fda43Sjbeloro return (DDI_SUCCESS); 294*d58fda43Sjbeloro 295*d58fda43Sjbeloro default: 296*d58fda43Sjbeloro return (DDI_FAILURE); 297*d58fda43Sjbeloro } 298*d58fda43Sjbeloro } 299*d58fda43Sjbeloro 300*d58fda43Sjbeloro /*ARGSUSED*/ 301*d58fda43Sjbeloro static int 302*d58fda43Sjbeloro epic_open(dev_t *devp, int flag, int otyp, cred_t *credp) 303*d58fda43Sjbeloro { 304*d58fda43Sjbeloro _NOTE(ARGUNUSED(flag)) 305*d58fda43Sjbeloro _NOTE(ARGUNUSED(otyp)) 306*d58fda43Sjbeloro _NOTE(ARGUNUSED(credp)) 307*d58fda43Sjbeloro 308*d58fda43Sjbeloro int inst = getminor(*devp); 309*d58fda43Sjbeloro 310*d58fda43Sjbeloro return (getsoftc(inst) == NULL ? ENXIO : 0); 311*d58fda43Sjbeloro } 312*d58fda43Sjbeloro 313*d58fda43Sjbeloro /*ARGSUSED*/ 314*d58fda43Sjbeloro static int 315*d58fda43Sjbeloro epic_close(dev_t dev, int flag, int otyp, cred_t *credp) 316*d58fda43Sjbeloro { 317*d58fda43Sjbeloro _NOTE(ARGUNUSED(flag)) 318*d58fda43Sjbeloro _NOTE(ARGUNUSED(otyp)) 319*d58fda43Sjbeloro _NOTE(ARGUNUSED(credp)) 320*d58fda43Sjbeloro 321*d58fda43Sjbeloro int inst = getminor(dev); 322*d58fda43Sjbeloro 323*d58fda43Sjbeloro return (getsoftc(inst) == NULL ? ENXIO : 0); 324*d58fda43Sjbeloro } 325*d58fda43Sjbeloro 326*d58fda43Sjbeloro /*ARGSUSED*/ 327*d58fda43Sjbeloro static int 328*d58fda43Sjbeloro epic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 329*d58fda43Sjbeloro int *rvalp) 330*d58fda43Sjbeloro { 331*d58fda43Sjbeloro _NOTE(ARGUNUSED(credp)) 332*d58fda43Sjbeloro 333*d58fda43Sjbeloro int inst; 334*d58fda43Sjbeloro struct epic_softc *softc; 335*d58fda43Sjbeloro uint8_t in_command; 336*d58fda43Sjbeloro 337*d58fda43Sjbeloro inst = getminor(dev); 338*d58fda43Sjbeloro if ((softc = getsoftc(inst)) == NULL) 339*d58fda43Sjbeloro return (ENXIO); 340*d58fda43Sjbeloro 341*d58fda43Sjbeloro mutex_enter(&softc->mutex); 342*d58fda43Sjbeloro 343*d58fda43Sjbeloro switch (cmd) { 344*d58fda43Sjbeloro case EPIC_SET_POWER_LED: 345*d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg, 346*d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK, 347*d58fda43Sjbeloro EPIC_POWER_LED_ON); 348*d58fda43Sjbeloro break; 349*d58fda43Sjbeloro case EPIC_RESET_POWER_LED: 350*d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg, 351*d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK, 352*d58fda43Sjbeloro EPIC_POWER_LED_OFF); 353*d58fda43Sjbeloro break; 354*d58fda43Sjbeloro case EPIC_SB_BL_POWER_LED: 355*d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg, 356*d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK, 357*d58fda43Sjbeloro EPIC_POWER_LED_SB_BLINK); 358*d58fda43Sjbeloro break; 359*d58fda43Sjbeloro case EPIC_FAST_BL_POWER_LED: 360*d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg, 361*d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK, 362*d58fda43Sjbeloro EPIC_POWER_LED_FAST_BLINK); 363*d58fda43Sjbeloro break; 364*d58fda43Sjbeloro case EPIC_SET_ALERT_LED: 365*d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg, 366*d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_ALERT_LED_MASK, 367*d58fda43Sjbeloro EPIC_ALERT_LED_ON); 368*d58fda43Sjbeloro break; 369*d58fda43Sjbeloro case EPIC_RESET_ALERT_LED: 370*d58fda43Sjbeloro EPIC_WRITE(softc->cmd_handle, softc->cmd_reg, 371*d58fda43Sjbeloro EPIC_IND_LED_STATE0, EPIC_ALERT_LED_MASK, 372*d58fda43Sjbeloro EPIC_ALERT_LED_OFF); 373*d58fda43Sjbeloro break; 374*d58fda43Sjbeloro case EPIC_GET_FW: 375*d58fda43Sjbeloro EPIC_READ(softc->cmd_handle, softc->cmd_reg, 376*d58fda43Sjbeloro in_command, EPIC_IND_FW_VERSION); 377*d58fda43Sjbeloro if (ddi_copyout((void *)(&in_command), (void *)arg, 378*d58fda43Sjbeloro sizeof (in_command), mode) != DDI_SUCCESS) { 379*d58fda43Sjbeloro mutex_exit(&softc->mutex); 380*d58fda43Sjbeloro return (EFAULT); 381*d58fda43Sjbeloro } 382*d58fda43Sjbeloro break; 383*d58fda43Sjbeloro default: 384*d58fda43Sjbeloro mutex_exit(&softc->mutex); 385*d58fda43Sjbeloro cmn_err(CE_WARN, "epic: cmd %d is not valid", cmd); 386*d58fda43Sjbeloro return (EINVAL); 387*d58fda43Sjbeloro } 388*d58fda43Sjbeloro 389*d58fda43Sjbeloro mutex_exit(&softc->mutex); 390*d58fda43Sjbeloro return (0); 391*d58fda43Sjbeloro } 392