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