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