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