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