10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Driver to map the PIC for the chicago platform. 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/time.h> 340Sstevel@tonic-gate #include <sys/errno.h> 350Sstevel@tonic-gate #include <sys/cmn_err.h> 360Sstevel@tonic-gate #include <sys/param.h> 370Sstevel@tonic-gate #include <sys/modctl.h> 380Sstevel@tonic-gate #include <sys/conf.h> 390Sstevel@tonic-gate #include <sys/open.h> 400Sstevel@tonic-gate #include <sys/stat.h> 410Sstevel@tonic-gate #include <sys/clock.h> 420Sstevel@tonic-gate #include <sys/pic.h> 430Sstevel@tonic-gate #include <sys/pic16f747.h> 440Sstevel@tonic-gate #include <sys/ddi.h> 450Sstevel@tonic-gate #include <sys/sunddi.h> 460Sstevel@tonic-gate #include <sys/file.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate /* dev_ops and cb_ops entry point function declarations */ 490Sstevel@tonic-gate static int pic_attach(dev_info_t *, ddi_attach_cmd_t); 500Sstevel@tonic-gate static int pic_detach(dev_info_t *, ddi_detach_cmd_t); 510Sstevel@tonic-gate static int pic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 520Sstevel@tonic-gate static int pic_open(dev_t *, int, int, cred_t *); 530Sstevel@tonic-gate static int pic_close(dev_t, int, int, cred_t *); 540Sstevel@tonic-gate static int pic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 550Sstevel@tonic-gate 560Sstevel@tonic-gate struct cb_ops pic_cb_ops = { 570Sstevel@tonic-gate pic_open, 580Sstevel@tonic-gate pic_close, 590Sstevel@tonic-gate nodev, 600Sstevel@tonic-gate nodev, 610Sstevel@tonic-gate nodev, /* dump */ 620Sstevel@tonic-gate nodev, 630Sstevel@tonic-gate nodev, 640Sstevel@tonic-gate pic_ioctl, 650Sstevel@tonic-gate nodev, /* devmap */ 660Sstevel@tonic-gate nodev, 670Sstevel@tonic-gate ddi_segmap, /* segmap */ 680Sstevel@tonic-gate nochpoll, 690Sstevel@tonic-gate ddi_prop_op, 700Sstevel@tonic-gate NULL, /* for STREAMS drivers */ 710Sstevel@tonic-gate D_NEW | D_MP /* driver compatibility flag */ 720Sstevel@tonic-gate }; 730Sstevel@tonic-gate 740Sstevel@tonic-gate static struct dev_ops pic_dev_ops = { 750Sstevel@tonic-gate DEVO_REV, /* driver build version */ 760Sstevel@tonic-gate 0, /* device reference count */ 770Sstevel@tonic-gate pic_getinfo, 780Sstevel@tonic-gate nulldev, 790Sstevel@tonic-gate nulldev, /* probe */ 800Sstevel@tonic-gate pic_attach, 810Sstevel@tonic-gate pic_detach, 820Sstevel@tonic-gate nulldev, /* reset */ 830Sstevel@tonic-gate &pic_cb_ops, 840Sstevel@tonic-gate (struct bus_ops *)NULL, 850Sstevel@tonic-gate nulldev /* power */ 860Sstevel@tonic-gate }; 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * Fans' and sensors' node names and register offsets 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate static struct minor_node_info pic_nodes[N_PIC_NODES] = { 920Sstevel@tonic-gate {NULL, 0, 0}, /* Reserved */ 93*707Svenki {"fan_0", RF_FAN0_PERIOD, F0_FLT_BIT}, /* System Fan 0 */ 94*707Svenki {"fan_1", RF_FAN1_PERIOD, F1_FLT_BIT}, /* System Fan 1 */ 95*707Svenki {"fan_2", RF_FAN2_PERIOD, F2_FLT_BIT}, /* System Fan 2 */ 96*707Svenki {"fan_3", RF_FAN3_PERIOD, F3_FLT_BIT}, /* System Fan 3 */ 97*707Svenki {"fan_4", RF_FAN4_PERIOD, F4_FLT_BIT}, /* System Fan 4 */ 980Sstevel@tonic-gate {"adt7462", RF_LOCAL_TEMP, 0}, /* ADT7462 Local Temperature */ 990Sstevel@tonic-gate {"cpu_0", RF_REMOTE1_TEMP, 0}, /* CPU 0 temp */ 1000Sstevel@tonic-gate {"cpu_1", RF_REMOTE2_TEMP, 0}, /* CPU 1 temp */ 1010Sstevel@tonic-gate {"mb", RF_REMOTE3_TEMP, 0}, /* Motherboard temp */ 1020Sstevel@tonic-gate {"lm95221", RF_LM95221_TEMP, 0}, /* LM95221 Local Temperature */ 1030Sstevel@tonic-gate {"fire", RF_FIRE_TEMP, 0}, /* FIRE Temp */ 1040Sstevel@tonic-gate {"lsi1064", RF_LSI1064_TEMP, 0}, /* LSI1064 Temp */ 105*707Svenki {"front_panel", RF_FRONT_TEMP, 0}, /* Front Panel Temperature */ 106*707Svenki {"psu", RF_PSU_TEMP, PSUF_FLT_BIT} /* PSU Temp (and ffault) */ 1070Sstevel@tonic-gate }; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate /* 1100Sstevel@tonic-gate * Soft state 1110Sstevel@tonic-gate */ 1120Sstevel@tonic-gate struct pic_softc { 1130Sstevel@tonic-gate dev_info_t *dip; 1140Sstevel@tonic-gate kmutex_t mutex; 1150Sstevel@tonic-gate uint8_t *cmd_reg; 1160Sstevel@tonic-gate ddi_acc_handle_t cmd_handle; 1170Sstevel@tonic-gate }; 1180Sstevel@tonic-gate #define getsoftc(inst) ((struct pic_softc *)ddi_get_soft_state(statep, (inst))) 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate /* module configuration stuff */ 1210Sstevel@tonic-gate static void *statep; 1220Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate static struct modldrv modldrv = { 1250Sstevel@tonic-gate &mod_driverops, 1260Sstevel@tonic-gate "pic_client driver (v.%I%) ", 1270Sstevel@tonic-gate &pic_dev_ops 1280Sstevel@tonic-gate }; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate static struct modlinkage modlinkage = { 1310Sstevel@tonic-gate MODREV_1, 1320Sstevel@tonic-gate &modldrv, 1330Sstevel@tonic-gate 0 1340Sstevel@tonic-gate }; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate int 1370Sstevel@tonic-gate _init(void) 1380Sstevel@tonic-gate { 1390Sstevel@tonic-gate int e; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate if (e = ddi_soft_state_init(&statep, sizeof (struct pic_softc), 1420Sstevel@tonic-gate MAX_PIC_INSTANCES)) { 1430Sstevel@tonic-gate return (e); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) 1470Sstevel@tonic-gate ddi_soft_state_fini(&statep); 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate return (e); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate int 1530Sstevel@tonic-gate _fini(void) 1540Sstevel@tonic-gate { 1550Sstevel@tonic-gate int e; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) 1580Sstevel@tonic-gate return (e); 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate ddi_soft_state_fini(&statep); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate return (DDI_SUCCESS); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate int 1660Sstevel@tonic-gate _info(struct modinfo *modinfop) 1670Sstevel@tonic-gate { 1680Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /*ARGSUSED*/ 1720Sstevel@tonic-gate static int 1730Sstevel@tonic-gate pic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 1740Sstevel@tonic-gate { 1750Sstevel@tonic-gate int inst; 1760Sstevel@tonic-gate int retval = DDI_SUCCESS; 1770Sstevel@tonic-gate struct pic_softc *softc; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate inst = PIC_MINOR_TO_INST(getminor((dev_t)arg)); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate switch (cmd) { 1820Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1830Sstevel@tonic-gate if ((softc = getsoftc(inst)) == NULL) { 1840Sstevel@tonic-gate *result = (void *)NULL; 1850Sstevel@tonic-gate retval = DDI_FAILURE; 1860Sstevel@tonic-gate } else 1870Sstevel@tonic-gate *result = (void *)softc->dip; 1880Sstevel@tonic-gate break; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 191592Svenki *result = (void *)((uintptr_t)inst); 1920Sstevel@tonic-gate break; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate default: 1950Sstevel@tonic-gate retval = DDI_FAILURE; 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate return (retval); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate static int 2020Sstevel@tonic-gate pic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2030Sstevel@tonic-gate { 2040Sstevel@tonic-gate int inst; 2050Sstevel@tonic-gate int i; 2060Sstevel@tonic-gate struct pic_softc *softc = NULL; 2070Sstevel@tonic-gate char *minor_name; 2080Sstevel@tonic-gate int minor; 2090Sstevel@tonic-gate char name[80]; 2100Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 2110Sstevel@tonic-gate int res; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate switch (cmd) { 2140Sstevel@tonic-gate case DDI_ATTACH: 2150Sstevel@tonic-gate inst = ddi_get_instance(dip); 2160Sstevel@tonic-gate if (inst >= MAX_PIC_INSTANCES) { 2170Sstevel@tonic-gate cmn_err(CE_WARN, "attach failed, too many instances\n"); 2180Sstevel@tonic-gate return (DDI_FAILURE); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate (void) sprintf(name, "env-monitor%d", inst); 2220Sstevel@tonic-gate minor = PIC_INST_TO_MINOR(inst) | PIC_UNIT_TO_MINOR(0); 2230Sstevel@tonic-gate if (ddi_create_minor_node(dip, name, S_IFCHR, minor, 2240Sstevel@tonic-gate DDI_PSEUDO, NULL) == DDI_FAILURE) { 2250Sstevel@tonic-gate cmn_err(CE_WARN, 2260Sstevel@tonic-gate "ddi_create_minor_node() failed for inst %d\n", 2270Sstevel@tonic-gate inst); 2280Sstevel@tonic-gate return (DDI_FAILURE); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* Allocate a soft state structure for this instance */ 2320Sstevel@tonic-gate if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS) { 2330Sstevel@tonic-gate cmn_err(CE_WARN, " ddi_soft_state_zalloc() failed " 2340Sstevel@tonic-gate "for inst %d\n", inst); 2350Sstevel@tonic-gate goto attach_failed; 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate /* Setup soft state */ 2390Sstevel@tonic-gate softc = getsoftc(inst); 2400Sstevel@tonic-gate softc->dip = dip; 2410Sstevel@tonic-gate mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL); 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* Setup device attributes */ 2440Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 2450Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 2460Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * The RF_COMMAND/RF_STATUS and RF_IND_DATA/RF_IND_ADDR 2500Sstevel@tonic-gate * register pairs are mapped as one register set starting 2510Sstevel@tonic-gate * from 0x0 and length 0x42. 2520Sstevel@tonic-gate */ 2530Sstevel@tonic-gate res = ddi_regs_map_setup(dip, 0, (caddr_t *)&softc->cmd_reg, 2540Sstevel@tonic-gate 0, 0x42, &dev_attr, &softc->cmd_handle); 2550Sstevel@tonic-gate if (res != DDI_SUCCESS) { 2560Sstevel@tonic-gate cmn_err(CE_WARN, "ddi_regs_map_setup() failed\n"); 2570Sstevel@tonic-gate goto attach_failed; 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* Set up fans' and sensors' device minor nodes */ 2610Sstevel@tonic-gate for (i = 1; i < N_PIC_NODES; i++) { 2620Sstevel@tonic-gate minor_name = pic_nodes[i].minor_name; 2630Sstevel@tonic-gate minor = PIC_INST_TO_MINOR(inst) | PIC_UNIT_TO_MINOR(i); 2640Sstevel@tonic-gate if (ddi_create_minor_node(dip, minor_name, S_IFCHR, 2650Sstevel@tonic-gate minor, PICDEV_NODE_TYPE, NULL) == DDI_FAILURE) { 2660Sstevel@tonic-gate cmn_err(CE_WARN, 2670Sstevel@tonic-gate "%s:%d ddi_create_minor_node failed", 2680Sstevel@tonic-gate ddi_driver_name(dip), inst); 2690Sstevel@tonic-gate (void) pic_detach(dip, DDI_DETACH); 2700Sstevel@tonic-gate return (DDI_FAILURE); 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* Create main environmental node */ 2750Sstevel@tonic-gate ddi_report_dev(dip); 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate return (DDI_SUCCESS); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate case DDI_RESUME: 2800Sstevel@tonic-gate return (DDI_SUCCESS); 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate default: 2830Sstevel@tonic-gate return (DDI_FAILURE); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate attach_failed: 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate /* Free soft state, if allocated. remove minor node if added earlier */ 2890Sstevel@tonic-gate if (softc) 2900Sstevel@tonic-gate ddi_soft_state_free(statep, inst); 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate return (DDI_FAILURE); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate static int 2980Sstevel@tonic-gate pic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2990Sstevel@tonic-gate { 3000Sstevel@tonic-gate int inst; 3010Sstevel@tonic-gate struct pic_softc *softc; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate switch (cmd) { 3040Sstevel@tonic-gate case DDI_DETACH: 3050Sstevel@tonic-gate inst = ddi_get_instance(dip); 3060Sstevel@tonic-gate if ((softc = getsoftc(inst)) == NULL) 3070Sstevel@tonic-gate return (ENXIO); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate (void) ddi_regs_map_free(&softc->cmd_handle); 3100Sstevel@tonic-gate /* Free the soft state and remove minor node added earlier */ 3110Sstevel@tonic-gate mutex_destroy(&softc->mutex); 3120Sstevel@tonic-gate ddi_soft_state_free(statep, inst); 3130Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 3140Sstevel@tonic-gate return (DDI_SUCCESS); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate case DDI_SUSPEND: 3170Sstevel@tonic-gate return (DDI_SUCCESS); 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate default: 3200Sstevel@tonic-gate return (DDI_FAILURE); 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /*ARGSUSED*/ 3250Sstevel@tonic-gate static int 3260Sstevel@tonic-gate pic_open(dev_t *devp, int flag, int otyp, cred_t *credp) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate int inst = PIC_MINOR_TO_INST(getminor(*devp)); 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate return (getsoftc(inst) == NULL ? ENXIO : 0); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate /*ARGSUSED*/ 3340Sstevel@tonic-gate static int 3350Sstevel@tonic-gate pic_close(dev_t dev, int flag, int otyp, cred_t *credp) 3360Sstevel@tonic-gate { 3370Sstevel@tonic-gate int inst = PIC_MINOR_TO_INST(getminor(dev)); 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate return (getsoftc(inst) == NULL ? ENXIO : 0); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate /*ARGSUSED*/ 3430Sstevel@tonic-gate static int 3440Sstevel@tonic-gate pic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 3450Sstevel@tonic-gate { 3460Sstevel@tonic-gate int inst; 3470Sstevel@tonic-gate int node; 3480Sstevel@tonic-gate struct pic_softc *softc; 3490Sstevel@tonic-gate uint8_t in_command; 3500Sstevel@tonic-gate int16_t tempr; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate inst = PIC_MINOR_TO_INST(getminor(dev)); 3530Sstevel@tonic-gate if ((softc = getsoftc(inst)) == NULL) 3540Sstevel@tonic-gate return (ENXIO); 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate mutex_enter(&softc->mutex); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &in_command, sizeof (in_command), 3590Sstevel@tonic-gate mode) != DDI_SUCCESS) { 3600Sstevel@tonic-gate mutex_exit(&softc->mutex); 3610Sstevel@tonic-gate return (EFAULT); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate node = PIC_MINOR_TO_UNIT(getminor(dev)); 3650Sstevel@tonic-gate if ((node >= N_PIC_NODES) || (node < 1)) { 3660Sstevel@tonic-gate mutex_exit(&softc->mutex); 3670Sstevel@tonic-gate return (ENXIO); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate switch (cmd) { 3710Sstevel@tonic-gate case PIC_GET_TEMPERATURE: 372138Svenki drv_usecwait(10); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* select the temp sensor */ 3750Sstevel@tonic-gate (void) ddi_put8(softc->cmd_handle, (uint8_t *)softc->cmd_reg + 3760Sstevel@tonic-gate RF_IND_ADDR, pic_nodes[node].reg_offset); 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /* retrieve temperature data */ 3790Sstevel@tonic-gate tempr = (int16_t)ddi_get8(softc->cmd_handle, 3800Sstevel@tonic-gate (uint8_t *)softc->cmd_reg + RF_IND_DATA); 381138Svenki mutex_exit(&softc->mutex); 3820Sstevel@tonic-gate 383138Svenki if (tempr == 0xff) 3840Sstevel@tonic-gate return (EIO); 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate /* 3870Sstevel@tonic-gate * The temp is passed in as a uint8 value, we need to convert 3880Sstevel@tonic-gate * it to a signed 16 bit value to be able to handle the range 3890Sstevel@tonic-gate * of -64 to 190 degrees. 3900Sstevel@tonic-gate */ 3910Sstevel@tonic-gate tempr -= 64; 3920Sstevel@tonic-gate (void) ddi_copyout(&tempr, (caddr_t)arg, sizeof (tempr), mode); 3930Sstevel@tonic-gate return (0); 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate case PIC_GET_FAN_SPEED: 396138Svenki drv_usecwait(10); 397138Svenki 3980Sstevel@tonic-gate /* select fan */ 3990Sstevel@tonic-gate (void) ddi_put8(softc->cmd_handle, (uint8_t *)softc->cmd_reg + 4000Sstevel@tonic-gate RF_IND_ADDR, pic_nodes[node].reg_offset); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate /* retrieve fan data */ 4030Sstevel@tonic-gate in_command = ddi_get8(softc->cmd_handle, 4040Sstevel@tonic-gate (uint8_t *)softc->cmd_reg + RF_IND_DATA); 405138Svenki mutex_exit(&softc->mutex); 4060Sstevel@tonic-gate 407138Svenki if (in_command == 0xff) 408138Svenki return (EIO); 409138Svenki 410138Svenki (void) ddi_copyout(&in_command, (caddr_t)arg, 1, mode); 411138Svenki return (0); 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate case PIC_SET_FAN_SPEED: 4140Sstevel@tonic-gate /* select fan */ 4150Sstevel@tonic-gate (void) ddi_put8(softc->cmd_handle, (uint8_t *)softc->cmd_reg + 4160Sstevel@tonic-gate RF_IND_ADDR, pic_nodes[node].reg_offset); 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate /* send the fan data */ 4190Sstevel@tonic-gate (void) ddi_put8(softc->cmd_handle, 4200Sstevel@tonic-gate (uint8_t *)softc->cmd_reg + RF_IND_DATA, in_command); 4210Sstevel@tonic-gate 422138Svenki mutex_exit(&softc->mutex); 423138Svenki return (0); 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate case PIC_GET_STATUS: 426138Svenki mutex_exit(&softc->mutex); 427138Svenki 428365Svenki /* we don't read the status reg anymore */ 429365Svenki in_command = 0; 430138Svenki (void) ddi_copyout(&in_command, (caddr_t)arg, 1, mode); 431138Svenki 432138Svenki return (0); 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate case PIC_GET_FAN_STATUS: 435138Svenki drv_usecwait(10); 436138Svenki 4370Sstevel@tonic-gate /* read ffault register */ 4380Sstevel@tonic-gate (void) ddi_put8(softc->cmd_handle, (uint8_t *)softc->cmd_reg + 4390Sstevel@tonic-gate RF_IND_ADDR, RF_FAN_STATUS); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate /* retrieve fan failure status */ 4420Sstevel@tonic-gate in_command = ddi_get8(softc->cmd_handle, 4430Sstevel@tonic-gate (uint8_t *)softc->cmd_reg + RF_IND_DATA); 444138Svenki mutex_exit(&softc->mutex); 4450Sstevel@tonic-gate 446138Svenki if (in_command == 0xff) 447138Svenki return (EIO); 4480Sstevel@tonic-gate 449138Svenki in_command = (in_command >> pic_nodes[node].ff_shift) & 0x1; 450138Svenki (void) ddi_copyout(&in_command, (caddr_t)arg, 1, mode); 451138Svenki return (0); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate case PIC_SET_ESTAR_MODE: 4540Sstevel@tonic-gate (void) ddi_put8(softc->cmd_handle, 4550Sstevel@tonic-gate (uint8_t *)softc->cmd_reg + RF_COMMAND, CMD_TO_ESTAR); 456365Svenki mutex_exit(&softc->mutex); 457138Svenki return (0); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate default: 4600Sstevel@tonic-gate mutex_exit(&softc->mutex); 4610Sstevel@tonic-gate cmn_err(CE_NOTE, "cmd %d isnt valid", cmd); 4620Sstevel@tonic-gate return (EINVAL); 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate } 465