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 1999-2002 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/stat.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/open.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/note.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/i2c/misc/i2c_svc.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/seeprom_impl.h> 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate /* 43*7c478bd9Sstevel@tonic-gate * cb ops 44*7c478bd9Sstevel@tonic-gate */ 45*7c478bd9Sstevel@tonic-gate static int seeprom_open(dev_t *, int, int, cred_t *); 46*7c478bd9Sstevel@tonic-gate static int seeprom_close(dev_t, int, int, cred_t *); 47*7c478bd9Sstevel@tonic-gate static int seeprom_read(dev_t, struct uio *, cred_t *); 48*7c478bd9Sstevel@tonic-gate static int seeprom_write(dev_t, struct uio *, cred_t *); 49*7c478bd9Sstevel@tonic-gate static int seeprom_io(dev_t, struct uio *, int); 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* 52*7c478bd9Sstevel@tonic-gate * dev ops 53*7c478bd9Sstevel@tonic-gate */ 54*7c478bd9Sstevel@tonic-gate static int seeprom_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 55*7c478bd9Sstevel@tonic-gate static int seeprom_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 56*7c478bd9Sstevel@tonic-gate static int seeprom_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate static struct cb_ops seeprom_cbops = { 59*7c478bd9Sstevel@tonic-gate seeprom_open, /* open */ 60*7c478bd9Sstevel@tonic-gate seeprom_close, /* close */ 61*7c478bd9Sstevel@tonic-gate nodev, /* strategy */ 62*7c478bd9Sstevel@tonic-gate nodev, /* print */ 63*7c478bd9Sstevel@tonic-gate nodev, /* dump */ 64*7c478bd9Sstevel@tonic-gate seeprom_read, /* read */ 65*7c478bd9Sstevel@tonic-gate seeprom_write, /* write */ 66*7c478bd9Sstevel@tonic-gate nodev, /* ioctl */ 67*7c478bd9Sstevel@tonic-gate nodev, /* devmap */ 68*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 69*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 70*7c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 71*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 72*7c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 73*7c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 74*7c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 75*7c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 76*7c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 77*7c478bd9Sstevel@tonic-gate }; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate static struct dev_ops seeprom_ops = { 80*7c478bd9Sstevel@tonic-gate DEVO_REV, 81*7c478bd9Sstevel@tonic-gate 0, 82*7c478bd9Sstevel@tonic-gate seeprom_info, 83*7c478bd9Sstevel@tonic-gate nulldev, 84*7c478bd9Sstevel@tonic-gate nulldev, 85*7c478bd9Sstevel@tonic-gate seeprom_attach, 86*7c478bd9Sstevel@tonic-gate seeprom_detach, 87*7c478bd9Sstevel@tonic-gate nodev, 88*7c478bd9Sstevel@tonic-gate &seeprom_cbops, 89*7c478bd9Sstevel@tonic-gate NULL 90*7c478bd9Sstevel@tonic-gate }; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate static struct modldrv seeprom_modldrv = { 93*7c478bd9Sstevel@tonic-gate &mod_driverops, /* type of module - driver */ 94*7c478bd9Sstevel@tonic-gate "I2C serial EEPROM device driver v%I%", 95*7c478bd9Sstevel@tonic-gate &seeprom_ops, 96*7c478bd9Sstevel@tonic-gate }; 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate static struct modlinkage seeprom_modlinkage = { 99*7c478bd9Sstevel@tonic-gate MODREV_1, 100*7c478bd9Sstevel@tonic-gate &seeprom_modldrv, 101*7c478bd9Sstevel@tonic-gate 0 102*7c478bd9Sstevel@tonic-gate }; 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* 105*7c478bd9Sstevel@tonic-gate * globals 106*7c478bd9Sstevel@tonic-gate */ 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate static void *seepromsoft_statep; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate int 111*7c478bd9Sstevel@tonic-gate _init(void) 112*7c478bd9Sstevel@tonic-gate { 113*7c478bd9Sstevel@tonic-gate int error; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate error = mod_install(&seeprom_modlinkage); 116*7c478bd9Sstevel@tonic-gate if (error == 0) { 117*7c478bd9Sstevel@tonic-gate (void) ddi_soft_state_init(&seepromsoft_statep, 118*7c478bd9Sstevel@tonic-gate sizeof (struct seepromunit), 1); 119*7c478bd9Sstevel@tonic-gate } 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate return (error); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate int 125*7c478bd9Sstevel@tonic-gate _fini(void) 126*7c478bd9Sstevel@tonic-gate { 127*7c478bd9Sstevel@tonic-gate int error; 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate error = mod_remove(&seeprom_modlinkage); 130*7c478bd9Sstevel@tonic-gate if (error == 0) { 131*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&seepromsoft_statep); 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate return (error); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate int 138*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 139*7c478bd9Sstevel@tonic-gate { 140*7c478bd9Sstevel@tonic-gate return (mod_info(&seeprom_modlinkage, modinfop)); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate static int 144*7c478bd9Sstevel@tonic-gate seeprom_do_attach(dev_info_t *dip) 145*7c478bd9Sstevel@tonic-gate { 146*7c478bd9Sstevel@tonic-gate struct seepromunit *unitp; 147*7c478bd9Sstevel@tonic-gate int instance; 148*7c478bd9Sstevel@tonic-gate dev_t dev; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(seepromsoft_statep, instance) != 0) { 153*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s_%d: failed to zalloc softstate", 154*7c478bd9Sstevel@tonic-gate ddi_node_name(dip), instance); 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate unitp = ddi_get_soft_state(seepromsoft_statep, instance); 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate unitp->seeprom_dip = dip; 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate (void) snprintf(unitp->seeprom_name, sizeof (unitp->seeprom_name), 164*7c478bd9Sstevel@tonic-gate "%s%d", ddi_driver_name(dip), instance); 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, ddi_node_name(dip), S_IFCHR, 167*7c478bd9Sstevel@tonic-gate instance, SEEPROM_NODE_TYPE, NULL) == DDI_FAILURE) { 168*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s ddi_create_minor_node failed for '%s'", 169*7c478bd9Sstevel@tonic-gate unitp->seeprom_name, ddi_node_name(dip)); 170*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(seepromsoft_statep, instance); 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate if (i2c_client_register(dip, &unitp->seeprom_hdl) != I2C_SUCCESS) { 176*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "i2c_client_register failed\n"); 177*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 178*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(seepromsoft_statep, instance); 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate if (strcmp(ddi_binding_name(dip), "i2c-at34c02") == 0) { 184*7c478bd9Sstevel@tonic-gate unitp->seeprom_addrsize = AT34C02_ADDRSIZE; 185*7c478bd9Sstevel@tonic-gate unitp->seeprom_memsize = AT34C02_MEMSIZE; 186*7c478bd9Sstevel@tonic-gate unitp->seeprom_pagesize = AT34C02_PAGESIZE; 187*7c478bd9Sstevel@tonic-gate unitp->seeprom_pagemask = AT34C02_PAGEMASK; 188*7c478bd9Sstevel@tonic-gate } else { 189*7c478bd9Sstevel@tonic-gate /* 190*7c478bd9Sstevel@tonic-gate * Default is i2c-at24c64 191*7c478bd9Sstevel@tonic-gate */ 192*7c478bd9Sstevel@tonic-gate unitp->seeprom_addrsize = AT24C64_ADDRSIZE; 193*7c478bd9Sstevel@tonic-gate unitp->seeprom_memsize = AT24C64_MEMSIZE; 194*7c478bd9Sstevel@tonic-gate unitp->seeprom_pagesize = AT24C64_PAGESIZE; 195*7c478bd9Sstevel@tonic-gate unitp->seeprom_pagemask = AT24C64_PAGEMASK; 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate dev = makedevice(DDI_MAJOR_T_UNKNOWN, instance); 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate (void) ddi_prop_create(dev, dip, DDI_PROP_CANSLEEP, "size", 200*7c478bd9Sstevel@tonic-gate (caddr_t)&unitp->seeprom_memsize, sizeof (unitp->seeprom_memsize)); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate mutex_init(&unitp->seeprom_mutex, NULL, MUTEX_DRIVER, NULL); 203*7c478bd9Sstevel@tonic-gate cv_init(&unitp->seeprom_cv, NULL, CV_DRIVER, NULL); 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate static int 209*7c478bd9Sstevel@tonic-gate seeprom_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 210*7c478bd9Sstevel@tonic-gate { 211*7c478bd9Sstevel@tonic-gate switch (cmd) { 212*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate return (seeprom_do_attach(dip)); 215*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * No state to restore. 218*7c478bd9Sstevel@tonic-gate */ 219*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 220*7c478bd9Sstevel@tonic-gate default: 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate static int 227*7c478bd9Sstevel@tonic-gate seeprom_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 228*7c478bd9Sstevel@tonic-gate { 229*7c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(dip)) 230*7c478bd9Sstevel@tonic-gate struct seepromunit *unitp; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate switch (infocmd) { 233*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 234*7c478bd9Sstevel@tonic-gate unitp = ddi_get_soft_state(seepromsoft_statep, 235*7c478bd9Sstevel@tonic-gate getminor((dev_t)arg)); 236*7c478bd9Sstevel@tonic-gate if (unitp == NULL) { 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate return (ENXIO); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate *result = (void *)unitp->seeprom_dip; 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 243*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 244*7c478bd9Sstevel@tonic-gate *result = (void *)getminor((dev_t)arg); 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 247*7c478bd9Sstevel@tonic-gate default: 248*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate static int 254*7c478bd9Sstevel@tonic-gate seeprom_do_detach(dev_info_t *dip) 255*7c478bd9Sstevel@tonic-gate { 256*7c478bd9Sstevel@tonic-gate struct seepromunit *unitp; 257*7c478bd9Sstevel@tonic-gate int instance; 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 260*7c478bd9Sstevel@tonic-gate unitp = ddi_get_soft_state(seepromsoft_statep, instance); 261*7c478bd9Sstevel@tonic-gate i2c_client_unregister(unitp->seeprom_hdl); 262*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 263*7c478bd9Sstevel@tonic-gate mutex_destroy(&unitp->seeprom_mutex); 264*7c478bd9Sstevel@tonic-gate cv_destroy(&unitp->seeprom_cv); 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(seepromsoft_statep, instance); 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate static int 272*7c478bd9Sstevel@tonic-gate seeprom_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 273*7c478bd9Sstevel@tonic-gate { 274*7c478bd9Sstevel@tonic-gate switch (cmd) { 275*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate return (seeprom_do_detach(dip)); 278*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 279*7c478bd9Sstevel@tonic-gate /* 280*7c478bd9Sstevel@tonic-gate * No state to save. IO will be blocked by nexus. 281*7c478bd9Sstevel@tonic-gate */ 282*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 283*7c478bd9Sstevel@tonic-gate default: 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate static int 290*7c478bd9Sstevel@tonic-gate seeprom_open(dev_t *devp, int flags, int otyp, cred_t *credp) 291*7c478bd9Sstevel@tonic-gate { 292*7c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(credp)) 293*7c478bd9Sstevel@tonic-gate struct seepromunit *unitp; 294*7c478bd9Sstevel@tonic-gate int instance; 295*7c478bd9Sstevel@tonic-gate int err = 0; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) { 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate return (EINVAL); 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate instance = getminor(*devp); 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate unitp = (struct seepromunit *) 305*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(seepromsoft_statep, instance); 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate if (unitp == NULL) { 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate return (ENXIO); 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate mutex_enter(&unitp->seeprom_mutex); 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate if (flags & FEXCL) { 315*7c478bd9Sstevel@tonic-gate if (unitp->seeprom_oflag != 0) { 316*7c478bd9Sstevel@tonic-gate err = EBUSY; 317*7c478bd9Sstevel@tonic-gate } else { 318*7c478bd9Sstevel@tonic-gate unitp->seeprom_oflag = FEXCL; 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate } else { 321*7c478bd9Sstevel@tonic-gate if (unitp->seeprom_oflag == FEXCL) { 322*7c478bd9Sstevel@tonic-gate err = EBUSY; 323*7c478bd9Sstevel@tonic-gate } else { 324*7c478bd9Sstevel@tonic-gate unitp->seeprom_oflag = FOPEN; 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate mutex_exit(&unitp->seeprom_mutex); 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate return (err); 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate static int 334*7c478bd9Sstevel@tonic-gate seeprom_close(dev_t dev, int flags, int otyp, cred_t *credp) 335*7c478bd9Sstevel@tonic-gate { 336*7c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(flags, otyp, credp)) 337*7c478bd9Sstevel@tonic-gate struct seepromunit *unitp; 338*7c478bd9Sstevel@tonic-gate int instance; 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate instance = getminor(dev); 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate unitp = (struct seepromunit *) 343*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(seepromsoft_statep, instance); 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate if (unitp == NULL) { 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate return (ENXIO); 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate mutex_enter(&unitp->seeprom_mutex); 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate unitp->seeprom_oflag = 0; 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate mutex_exit(&unitp->seeprom_mutex); 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate static int 360*7c478bd9Sstevel@tonic-gate seeprom_read(dev_t dev, struct uio *uiop, cred_t *cred_p) 361*7c478bd9Sstevel@tonic-gate { 362*7c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(cred_p)) 363*7c478bd9Sstevel@tonic-gate return (seeprom_io(dev, uiop, B_READ)); 364*7c478bd9Sstevel@tonic-gate } 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate static int 367*7c478bd9Sstevel@tonic-gate seeprom_write(dev_t dev, struct uio *uiop, cred_t *cred_p) 368*7c478bd9Sstevel@tonic-gate { 369*7c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(cred_p)) 370*7c478bd9Sstevel@tonic-gate return (seeprom_io(dev, uiop, B_WRITE)); 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate static int 374*7c478bd9Sstevel@tonic-gate seeprom_io(dev_t dev, struct uio *uiop, int rw) 375*7c478bd9Sstevel@tonic-gate { 376*7c478bd9Sstevel@tonic-gate struct seepromunit *unitp; 377*7c478bd9Sstevel@tonic-gate int instance = getminor(dev); 378*7c478bd9Sstevel@tonic-gate int seeprom_addr; 379*7c478bd9Sstevel@tonic-gate int bytes_to_rw; 380*7c478bd9Sstevel@tonic-gate int err = 0; 381*7c478bd9Sstevel@tonic-gate int current_xfer_len; 382*7c478bd9Sstevel@tonic-gate int actual_data_xfer; 383*7c478bd9Sstevel@tonic-gate i2c_transfer_t *i2ctp = NULL; 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate unitp = (struct seepromunit *) 386*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(seepromsoft_statep, instance); 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate if (unitp == NULL) { 390*7c478bd9Sstevel@tonic-gate return (ENXIO); 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate if (uiop->uio_offset >= unitp->seeprom_memsize) { 394*7c478bd9Sstevel@tonic-gate /* 395*7c478bd9Sstevel@tonic-gate * Exceeded seeprom size. 396*7c478bd9Sstevel@tonic-gate */ 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate return (ENXIO); 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate seeprom_addr = uiop->uio_offset; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate if (uiop->uio_resid == 0) { 404*7c478bd9Sstevel@tonic-gate return (0); 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate bytes_to_rw = min(uiop->uio_resid, 408*7c478bd9Sstevel@tonic-gate unitp->seeprom_memsize - uiop->uio_offset); 409*7c478bd9Sstevel@tonic-gate /* 410*7c478bd9Sstevel@tonic-gate * Serialize access here to prevent a transaction starting 411*7c478bd9Sstevel@tonic-gate * until after 20 ms delay if last operation was a write. 412*7c478bd9Sstevel@tonic-gate */ 413*7c478bd9Sstevel@tonic-gate mutex_enter(&unitp->seeprom_mutex); 414*7c478bd9Sstevel@tonic-gate while ((unitp->seeprom_flags & SEEPROM_BUSY) == SEEPROM_BUSY) { 415*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&unitp->seeprom_cv, 416*7c478bd9Sstevel@tonic-gate &unitp->seeprom_mutex) <= 0) { 417*7c478bd9Sstevel@tonic-gate mutex_exit(&unitp->seeprom_mutex); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate return (EINTR); 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate unitp->seeprom_flags |= SEEPROM_BUSY; 423*7c478bd9Sstevel@tonic-gate mutex_exit(&unitp->seeprom_mutex); 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate while ((bytes_to_rw != 0) && (err == 0)) { 426*7c478bd9Sstevel@tonic-gate current_xfer_len = min(bytes_to_rw, unitp->seeprom_pagesize - 427*7c478bd9Sstevel@tonic-gate (seeprom_addr & unitp->seeprom_pagemask)); 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate if (rw == B_WRITE) { 430*7c478bd9Sstevel@tonic-gate if (i2ctp == NULL) { 431*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(unitp->seeprom_hdl, 432*7c478bd9Sstevel@tonic-gate &i2ctp, 433*7c478bd9Sstevel@tonic-gate unitp->seeprom_addrsize + current_xfer_len, 434*7c478bd9Sstevel@tonic-gate 0, 435*7c478bd9Sstevel@tonic-gate I2C_SLEEP); 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate if ((err = uiomove(&i2ctp->i2c_wbuf[ 438*7c478bd9Sstevel@tonic-gate unitp->seeprom_addrsize], 439*7c478bd9Sstevel@tonic-gate current_xfer_len, UIO_WRITE, uiop)) != 0) { 440*7c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->seeprom_hdl, 441*7c478bd9Sstevel@tonic-gate i2ctp); 442*7c478bd9Sstevel@tonic-gate break; 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate i2ctp->i2c_version = I2C_XFER_REV; 445*7c478bd9Sstevel@tonic-gate i2ctp->i2c_flags = I2C_WR; 446*7c478bd9Sstevel@tonic-gate } else { 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate /* 449*7c478bd9Sstevel@tonic-gate * not all bytes were sent in previous attempt. 450*7c478bd9Sstevel@tonic-gate * Adjust the write pointer to the unsent data. 451*7c478bd9Sstevel@tonic-gate */ 452*7c478bd9Sstevel@tonic-gate /*LINTED*/ 453*7c478bd9Sstevel@tonic-gate i2ctp->i2c_wbuf += actual_data_xfer; 454*7c478bd9Sstevel@tonic-gate /*LINTED*/ 455*7c478bd9Sstevel@tonic-gate i2ctp->i2c_wlen -= actual_data_xfer; 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate if (unitp->seeprom_addrsize == 2) { 459*7c478bd9Sstevel@tonic-gate i2ctp->i2c_wbuf[0] = (seeprom_addr >> 8); 460*7c478bd9Sstevel@tonic-gate i2ctp->i2c_wbuf[1] = (uchar_t)seeprom_addr; 461*7c478bd9Sstevel@tonic-gate } else { 462*7c478bd9Sstevel@tonic-gate i2ctp->i2c_wbuf[0] = (uchar_t)seeprom_addr; 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate if ((err = i2c_transfer(unitp->seeprom_hdl, i2ctp)) != 466*7c478bd9Sstevel@tonic-gate I2C_SUCCESS) { 467*7c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->seeprom_hdl, i2ctp); 468*7c478bd9Sstevel@tonic-gate break; 469*7c478bd9Sstevel@tonic-gate } 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate actual_data_xfer = i2ctp->i2c_wlen - 472*7c478bd9Sstevel@tonic-gate i2ctp->i2c_w_resid - unitp->seeprom_addrsize; 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate if (i2ctp->i2c_w_resid == 0) { 475*7c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->seeprom_hdl, i2ctp); 476*7c478bd9Sstevel@tonic-gate i2ctp = NULL; 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate /* 479*7c478bd9Sstevel@tonic-gate * 20 ms(20000 Microsec) delay is required before 480*7c478bd9Sstevel@tonic-gate * issuing another transaction. This enforces that 481*7c478bd9Sstevel@tonic-gate * wait. 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(20000)); 484*7c478bd9Sstevel@tonic-gate } else { 485*7c478bd9Sstevel@tonic-gate /* 486*7c478bd9Sstevel@tonic-gate * SEEPROM read. First write out the address to read. 487*7c478bd9Sstevel@tonic-gate */ 488*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(unitp->seeprom_hdl, &i2ctp, 489*7c478bd9Sstevel@tonic-gate unitp->seeprom_addrsize, current_xfer_len, 490*7c478bd9Sstevel@tonic-gate I2C_SLEEP); 491*7c478bd9Sstevel@tonic-gate i2ctp->i2c_version = I2C_XFER_REV; 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate if (unitp->seeprom_addrsize == 2) { 494*7c478bd9Sstevel@tonic-gate i2ctp->i2c_wbuf[0] = (seeprom_addr >> 8); 495*7c478bd9Sstevel@tonic-gate i2ctp->i2c_wbuf[1] = (uchar_t)seeprom_addr; 496*7c478bd9Sstevel@tonic-gate } else { 497*7c478bd9Sstevel@tonic-gate i2ctp->i2c_wbuf[0] = (uchar_t)seeprom_addr; 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate i2ctp->i2c_flags = I2C_WR_RD; 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate if ((err = i2c_transfer(unitp->seeprom_hdl, i2ctp)) != 503*7c478bd9Sstevel@tonic-gate I2C_SUCCESS) { 504*7c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->seeprom_hdl, i2ctp); 505*7c478bd9Sstevel@tonic-gate break; 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate actual_data_xfer = i2ctp->i2c_rlen - i2ctp->i2c_r_resid; 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate err = uiomove(i2ctp->i2c_rbuf, actual_data_xfer, 511*7c478bd9Sstevel@tonic-gate UIO_READ, uiop); 512*7c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->seeprom_hdl, i2ctp); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate bytes_to_rw -= actual_data_xfer; 516*7c478bd9Sstevel@tonic-gate seeprom_addr += actual_data_xfer; 517*7c478bd9Sstevel@tonic-gate } 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate mutex_enter(&unitp->seeprom_mutex); 520*7c478bd9Sstevel@tonic-gate unitp->seeprom_flags = 0; 521*7c478bd9Sstevel@tonic-gate cv_signal(&unitp->seeprom_cv); 522*7c478bd9Sstevel@tonic-gate mutex_exit(&unitp->seeprom_mutex); 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate return (err); 525*7c478bd9Sstevel@tonic-gate } 526