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/file.h> 29 #include <sys/uio.h> 30 #include <sys/modctl.h> 31 #include <sys/open.h> 32 #include <sys/types.h> 33 #include <sys/kmem.h> 34 #include <sys/systm.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/conf.h> 38 #include <sys/mode.h> 39 #include <sys/promif.h> 40 #include <sys/note.h> 41 #include <sys/i2c/misc/i2c_svc.h> 42 #include <sys/i2c/clients/i2c_client.h> 43 #include <sys/i2c/clients/adm1031.h> 44 #include <sys/i2c/clients/adm1031_impl.h> 45 46 /* 47 * ADM1031 is an Intelligent Temperature Monitor and Dual PWM Fan Controller. 48 * The functions supported by the driver are: 49 * Reading sensed temperatures. 50 * Setting temperature limits which control fan speeds. 51 * Reading fan speeds. 52 * Setting fan outputs. 53 * Reading internal registers. 54 * Setting internal registers. 55 */ 56 57 /* 58 * A pointer to an int16_t is expected as an ioctl argument for all temperature 59 * related commands and a pointer to a uint8_t is expected for all other 60 * commands. If the parameter is to be read the value is copied into it and 61 * if it is to be written, the integer referred to should have the appropriate 62 * value. 63 * 64 * For all temperature related commands, a temperature minor node should be 65 * passed as the argument to open(2) and correspondingly, a fan minor node 66 * should be used for all fan related commands. Commands which do not fall in 67 * either of the two categories are control commands and involve 68 * reading/writing to the internal registers of the device or switching from 69 * automatic monitoring mode to manual mode and vice-versa. A control minor 70 * node is created by the driver which has to be used for control commands. 71 * 72 * Fan Speed in RPM = (frequency * 60)/Count * N, where Count is the value 73 * received in the fan speed register and N is Speed Range. 74 */ 75 76 /* 77 * cb ops 78 */ 79 static int adm1031_open(dev_t *, int, int, cred_t *); 80 static int adm1031_close(dev_t, int, int, cred_t *); 81 static int adm1031_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 82 83 /* 84 * dev ops 85 */ 86 static int adm1031_s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 87 static int adm1031_s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 88 89 static struct cb_ops adm1031_cb_ops = { 90 adm1031_open, /* open */ 91 adm1031_close, /* close */ 92 nodev, /* strategy */ 93 nodev, /* print */ 94 nodev, /* dump */ 95 nodev, /* read */ 96 nodev, /* write */ 97 adm1031_ioctl, /* ioctl */ 98 nodev, /* devmap */ 99 nodev, /* mmap */ 100 nodev, /* segmap */ 101 nochpoll, /* poll */ 102 ddi_prop_op, /* cb_prop_op */ 103 NULL, /* streamtab */ 104 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 105 }; 106 107 static struct dev_ops adm1031_dev_ops = { 108 DEVO_REV, 109 0, 110 ddi_no_info, 111 nulldev, 112 nulldev, 113 adm1031_s_attach, 114 adm1031_s_detach, 115 nodev, 116 &adm1031_cb_ops, 117 NULL, 118 NULL, 119 ddi_quiesce_not_supported, /* devo_quiesce */ 120 }; 121 122 static uint8_t adm1031_control_regs[] = { 123 0x00, 124 ADM1031_STAT_1_REG, 125 ADM1031_STAT_2_REG, 126 ADM1031_DEVICE_ID_REG, 127 ADM1031_CONFIG_REG_1, 128 ADM1031_CONFIG_REG_2, 129 ADM1031_FAN_CHAR_1_REG, 130 ADM1031_FAN_CHAR_2_REG, 131 ADM1031_FAN_SPEED_CONFIG_REG, 132 ADM1031_FAN_HIGH_LIMIT_1_REG, 133 ADM1031_FAN_HIGH_LIMIT_2_REG, 134 ADM1031_LOCAL_TEMP_RANGE_REG, 135 ADM1031_REMOTE_TEMP_RANGE_1_REG, 136 ADM1031_REMOTE_TEMP_RANGE_2_REG, 137 ADM1031_EXTD_TEMP_RESL_REG, 138 ADM1031_LOCAL_TEMP_OFFSET_REG, 139 ADM1031_REMOTE_TEMP_OFFSET_1_REG, 140 ADM1031_REMOTE_TEMP_OFFSET_2_REG, 141 ADM1031_LOCAL_TEMP_HIGH_LIMIT_REG, 142 ADM1031_REMOTE_TEMP_HIGH_LIMIT_1_REG, 143 ADM1031_REMOTE_TEMP_HIGH_LIMIT_2_REG, 144 ADM1031_LOCAL_TEMP_LOW_LIMIT_REG, 145 ADM1031_REMOTE_TEMP_LOW_LIMIT_1_REG, 146 ADM1031_REMOTE_TEMP_LOW_LIMIT_2_REG, 147 ADM1031_LOCAL_TEMP_THERM_LIMIT_REG, 148 ADM1031_REMOTE_TEMP_THERM_LIMIT_1_REG, 149 ADM1031_REMOTE_TEMP_THERM_LIMIT_2_REG 150 }; 151 152 static minor_info temperatures[ADM1031_TEMP_CHANS] = { 153 {"local", ADM1031_LOCAL_TEMP_INST_REG }, /* Local Temperature */ 154 {"remote_1", ADM1031_REMOTE_TEMP_INST_REG_1 }, /* Remote 1 */ 155 {"remote_2", ADM1031_REMOTE_TEMP_INST_REG_2 } /* Remote 2 */ 156 }; 157 158 static minor_info fans[ADM1031_FAN_SPEED_CHANS] = { 159 {"fan_1", ADM1031_FAN_SPEED_INST_REG_1}, 160 {"fan_2", ADM1031_FAN_SPEED_INST_REG_2} 161 }; 162 163 static struct modldrv adm1031_modldrv = { 164 &mod_driverops, /* type of module - driver */ 165 "adm1031 device driver", 166 &adm1031_dev_ops, 167 }; 168 169 static struct modlinkage adm1031_modlinkage = { 170 MODREV_1, 171 &adm1031_modldrv, 172 0 173 }; 174 175 static void *adm1031_soft_statep; 176 int adm1031_pil = ADM1031_PIL; 177 178 179 int 180 _init(void) 181 { 182 int err; 183 184 err = mod_install(&adm1031_modlinkage); 185 if (err == 0) { 186 (void) ddi_soft_state_init(&adm1031_soft_statep, 187 sizeof (adm1031_unit_t), 1); 188 } 189 return (err); 190 } 191 192 int 193 _fini(void) 194 { 195 int err; 196 197 err = mod_remove(&adm1031_modlinkage); 198 if (err == 0) { 199 ddi_soft_state_fini(&adm1031_soft_statep); 200 } 201 return (err); 202 } 203 204 int 205 _info(struct modinfo *modinfop) 206 { 207 return (mod_info(&adm1031_modlinkage, modinfop)); 208 } 209 210 static int 211 adm1031_resume(dev_info_t *dip) 212 { 213 int instance = ddi_get_instance(dip); 214 adm1031_unit_t *admp; 215 int err = DDI_SUCCESS; 216 217 admp = (adm1031_unit_t *) 218 ddi_get_soft_state(adm1031_soft_statep, instance); 219 220 if (admp == NULL) { 221 return (DDI_FAILURE); 222 } 223 224 /* 225 * Restore registers to state existing before cpr 226 */ 227 admp->adm1031_transfer->i2c_flags = I2C_WR; 228 admp->adm1031_transfer->i2c_wlen = 2; 229 admp->adm1031_transfer->i2c_rlen = 0; 230 231 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_CONFIG_REG_1; 232 admp->adm1031_transfer->i2c_wbuf[1] = 233 admp->adm1031_cpr_state.config_reg_1; 234 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 235 DDI_SUCCESS) { 236 err = DDI_FAILURE; 237 goto done; 238 } 239 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_CONFIG_REG_2; 240 admp->adm1031_transfer->i2c_wbuf[1] = 241 admp->adm1031_cpr_state.config_reg_2; 242 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 243 DDI_SUCCESS) { 244 err = DDI_FAILURE; 245 goto done; 246 } 247 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_FAN_SPEED_CONFIG_REG; 248 admp->adm1031_transfer->i2c_wbuf[1] = 249 admp->adm1031_cpr_state.fan_speed_reg; 250 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 251 DDI_SUCCESS) { 252 err = DDI_FAILURE; 253 goto done; 254 } 255 256 /* 257 * Clear busy flag so that transactions may continue 258 */ 259 mutex_enter(&admp->adm1031_mutex); 260 admp->adm1031_flags = admp->adm1031_flags & ~ADM1031_BUSYFLAG; 261 cv_signal(&admp->adm1031_cv); 262 mutex_exit(&admp->adm1031_mutex); 263 264 done: 265 if (err != DDI_SUCCESS) { 266 cmn_err(CE_WARN, "%s:%d Registers not restored correctly", 267 admp->adm1031_name, instance); 268 } 269 return (err); 270 } 271 272 static void 273 adm1031_detach(dev_info_t *dip) 274 { 275 adm1031_unit_t *admp; 276 int instance = ddi_get_instance(dip); 277 278 admp = ddi_get_soft_state(adm1031_soft_statep, instance); 279 280 if (admp->adm1031_flags & ADM1031_REGFLAG) { 281 i2c_client_unregister(admp->adm1031_hdl); 282 } 283 if (admp->adm1031_flags & ADM1031_TBUFFLAG) { 284 i2c_transfer_free(admp->adm1031_hdl, admp->adm1031_transfer); 285 } 286 if (admp->adm1031_flags & ADM1031_INTRFLAG) { 287 ddi_remove_intr(dip, 0, admp->adm1031_icookie); 288 cv_destroy(&admp->adm1031_icv); 289 mutex_destroy(&admp->adm1031_imutex); 290 } 291 292 (void) ddi_prop_remove_all(dip); 293 ddi_remove_minor_node(dip, NULL); 294 cv_destroy(&admp->adm1031_cv); 295 mutex_destroy(&admp->adm1031_mutex); 296 ddi_soft_state_free(adm1031_soft_statep, instance); 297 298 } 299 300 static uint_t 301 adm1031_intr(caddr_t arg) 302 { 303 adm1031_unit_t *admp = (adm1031_unit_t *)arg; 304 305 306 if (admp->adm1031_cvwaiting == 0) 307 return (DDI_INTR_CLAIMED); 308 309 mutex_enter(&admp->adm1031_imutex); 310 cv_broadcast(&admp->adm1031_icv); 311 admp->adm1031_cvwaiting = 0; 312 mutex_exit(&admp->adm1031_imutex); 313 314 return (DDI_INTR_CLAIMED); 315 } 316 317 static int 318 adm1031_attach(dev_info_t *dip) 319 { 320 adm1031_unit_t *admp; 321 int instance = ddi_get_instance(dip); 322 minor_t minor; 323 int i; 324 char *minor_name; 325 int err = 0; 326 327 if (ddi_soft_state_zalloc(adm1031_soft_statep, instance) != 0) { 328 cmn_err(CE_WARN, "%s:%d failed to zalloc softstate", 329 ddi_get_name(dip), instance); 330 return (DDI_FAILURE); 331 } 332 admp = ddi_get_soft_state(adm1031_soft_statep, instance); 333 if (admp == NULL) { 334 return (DDI_FAILURE); 335 } 336 admp->adm1031_dip = dip; 337 mutex_init(&admp->adm1031_mutex, NULL, MUTEX_DRIVER, NULL); 338 cv_init(&admp->adm1031_cv, NULL, CV_DRIVER, NULL); 339 340 (void) snprintf(admp->adm1031_name, sizeof (admp->adm1031_name), 341 "%s_%d", ddi_driver_name(dip), instance); 342 343 /* 344 * Create minor node for all temperature functions. 345 */ 346 for (i = 0; i < ADM1031_TEMP_CHANS; i++) { 347 348 minor_name = temperatures[i].minor_name; 349 minor = ADM1031_INST_TO_MINOR(instance) | 350 ADM1031_FCN_TO_MINOR(ADM1031_TEMPERATURES) | 351 ADM1031_FCNINST_TO_MINOR(i); 352 353 if (ddi_create_minor_node(dip, minor_name, S_IFCHR, minor, 354 ADM1031_NODE_TYPE, NULL) == DDI_FAILURE) { 355 cmn_err(CE_WARN, "%s:%d ddi_create_minor_node failed", 356 admp->adm1031_name, instance); 357 adm1031_detach(dip); 358 return (DDI_FAILURE); 359 } 360 } 361 362 /* 363 * Create minor node for all fan functions. 364 */ 365 for (i = 0; i < ADM1031_FAN_SPEED_CHANS; i++) { 366 367 minor_name = fans[i].minor_name; 368 minor = ADM1031_INST_TO_MINOR(instance) | 369 ADM1031_FCN_TO_MINOR(ADM1031_FANS) | 370 ADM1031_FCNINST_TO_MINOR(i); 371 372 if (ddi_create_minor_node(dip, minor_name, S_IFCHR, minor, 373 ADM1031_NODE_TYPE, NULL) == DDI_FAILURE) { 374 cmn_err(CE_WARN, "%s:%d ddi_create_minor_node failed", 375 admp->adm1031_name, instance); 376 adm1031_detach(dip); 377 return (DDI_FAILURE); 378 } 379 } 380 381 /* 382 * Create minor node for all control functions. 383 */ 384 minor = ADM1031_INST_TO_MINOR(instance) | 385 ADM1031_FCN_TO_MINOR(ADM1031_CONTROL) | 386 ADM1031_FCNINST_TO_MINOR(0); 387 388 if (ddi_create_minor_node(dip, "control", S_IFCHR, minor, 389 ADM1031_NODE_TYPE, NULL) == DDI_FAILURE) { 390 cmn_err(CE_WARN, "%s:%d ddi_create_minor_node failed", 391 admp->adm1031_name, instance); 392 adm1031_detach(dip); 393 return (DDI_FAILURE); 394 } 395 396 /* 397 * preallocate a single buffer for all reads and writes 398 */ 399 if (i2c_transfer_alloc(admp->adm1031_hdl, &admp->adm1031_transfer, 400 ADM1031_MAX_XFER, ADM1031_MAX_XFER, I2C_SLEEP) != I2C_SUCCESS) { 401 cmn_err(CE_WARN, "%s:%d i2c_transfer_alloc failed", 402 admp->adm1031_name, instance); 403 adm1031_detach(dip); 404 return (DDI_FAILURE); 405 } 406 admp->adm1031_flags |= ADM1031_TBUFFLAG; 407 admp->adm1031_transfer->i2c_version = I2C_XFER_REV; 408 409 if (i2c_client_register(dip, &admp->adm1031_hdl) != I2C_SUCCESS) { 410 cmn_err(CE_WARN, "%s:%d i2c_client_register failed", 411 admp->adm1031_name, instance); 412 adm1031_detach(dip); 413 return (DDI_FAILURE); 414 } 415 admp->adm1031_flags |= ADM1031_REGFLAG; 416 417 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 418 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 419 "interrupt-priorities") != 1) { 420 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 421 DDI_PROP_CANSLEEP, "interrupt-priorities", 422 (void *)&adm1031_pil, sizeof (adm1031_pil)); 423 } 424 err = ddi_get_iblock_cookie(dip, 0, &admp->adm1031_icookie); 425 if (err == DDI_SUCCESS) { 426 mutex_init(&admp->adm1031_imutex, NULL, MUTEX_DRIVER, 427 (void *)admp->adm1031_icookie); 428 cv_init(&admp->adm1031_icv, NULL, CV_DRIVER, NULL); 429 if (ddi_add_intr(dip, 0, NULL, NULL, adm1031_intr, 430 (caddr_t)admp) == DDI_SUCCESS) { 431 admp->adm1031_flags |= ADM1031_INTRFLAG; 432 } else { 433 cmn_err(CE_WARN, "%s:%d failed to add interrupt", 434 admp->adm1031_name, instance); 435 } 436 } 437 438 /* 439 * The system comes up in Automatic Monitor Mode. 440 */ 441 admp->adm1031_flags |= ADM1031_AUTOFLAG; 442 443 return (DDI_SUCCESS); 444 } 445 446 static int 447 adm1031_s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 448 { 449 switch (cmd) { 450 case DDI_ATTACH: 451 return (adm1031_attach(dip)); 452 case DDI_RESUME: 453 return (adm1031_resume(dip)); 454 default: 455 return (DDI_FAILURE); 456 } 457 } 458 459 static int 460 adm1031_suspend(dev_info_t *dip) 461 { 462 adm1031_unit_t *admp; 463 int instance = ddi_get_instance(dip); 464 int err = DDI_SUCCESS; 465 466 admp = ddi_get_soft_state(adm1031_soft_statep, instance); 467 468 /* 469 * Set the busy flag so that future transactions block 470 * until resume. 471 */ 472 mutex_enter(&admp->adm1031_mutex); 473 while (admp->adm1031_flags & ADM1031_BUSYFLAG) { 474 if (cv_wait_sig(&admp->adm1031_cv, 475 &admp->adm1031_mutex) <= 0) { 476 mutex_exit(&admp->adm1031_mutex); 477 return (DDI_FAILURE); 478 } 479 } 480 admp->adm1031_flags |= ADM1031_BUSYFLAG; 481 mutex_exit(&admp->adm1031_mutex); 482 483 /* 484 * Save the state of the threshold registers. 485 */ 486 admp->adm1031_transfer->i2c_flags = I2C_WR_RD; 487 admp->adm1031_transfer->i2c_wlen = 1; 488 admp->adm1031_transfer->i2c_rlen = 1; 489 490 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_CONFIG_REG_1; 491 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 492 DDI_SUCCESS) { 493 err = DDI_FAILURE; 494 goto done; 495 } 496 admp->adm1031_cpr_state.config_reg_1 = 497 admp->adm1031_transfer->i2c_rbuf[0]; 498 499 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_CONFIG_REG_2; 500 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 501 DDI_SUCCESS) { 502 err = DDI_FAILURE; 503 goto done; 504 } 505 admp->adm1031_cpr_state.config_reg_2 = 506 admp->adm1031_transfer->i2c_rbuf[0]; 507 508 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_FAN_SPEED_CONFIG_REG; 509 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 510 DDI_SUCCESS) { 511 err = DDI_FAILURE; 512 goto done; 513 } 514 admp->adm1031_cpr_state.fan_speed_reg = 515 admp->adm1031_transfer->i2c_rbuf[0]; 516 done: 517 if (err != DDI_SUCCESS) { 518 mutex_enter(&admp->adm1031_mutex); 519 admp->adm1031_flags = admp->adm1031_flags & ~ADM1031_BUSYFLAG; 520 cv_broadcast(&admp->adm1031_cv); 521 mutex_exit(&admp->adm1031_mutex); 522 cmn_err(CE_WARN, "%s:%d Suspend failed,\ 523 unable to save registers", admp->adm1031_name, instance); 524 } 525 return (err); 526 527 } 528 529 static int 530 adm1031_s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 531 { 532 switch (cmd) { 533 case DDI_DETACH: 534 adm1031_detach(dip); 535 return (DDI_SUCCESS); 536 case DDI_SUSPEND: 537 return (adm1031_suspend(dip)); 538 default: 539 return (DDI_FAILURE); 540 } 541 } 542 543 static int 544 adm1031_open(dev_t *devp, int flags, int otyp, cred_t *credp) 545 { 546 int instance; 547 adm1031_unit_t *admp; 548 int err = EBUSY; 549 550 /* must be root to access this device */ 551 if (drv_priv(credp) != 0) { 552 return (EPERM); 553 } 554 555 /* 556 * Make sure the open is for the right file type 557 */ 558 if (otyp != OTYP_CHR) { 559 return (EINVAL); 560 } 561 instance = ADM1031_MINOR_TO_INST(getminor(*devp)); 562 admp = (adm1031_unit_t *) 563 ddi_get_soft_state(adm1031_soft_statep, instance); 564 if (admp == NULL) { 565 return (ENXIO); 566 } 567 568 /* 569 * Enforce exclusive access if required. 570 */ 571 mutex_enter(&admp->adm1031_mutex); 572 if (flags & FEXCL) { 573 if (admp->adm1031_oflag == 0) { 574 admp->adm1031_oflag = FEXCL; 575 err = 0; 576 } 577 } else if (admp->adm1031_oflag != FEXCL) { 578 admp->adm1031_oflag = FOPEN; 579 err = 0; 580 } 581 mutex_exit(&admp->adm1031_mutex); 582 return (err); 583 } 584 585 static int 586 adm1031_close(dev_t dev, int flags, int otyp, cred_t *credp) 587 { 588 int instance; 589 adm1031_unit_t *admp; 590 591 _NOTE(ARGUNUSED(flags, otyp, credp)) 592 593 instance = ADM1031_MINOR_TO_INST(getminor(dev)); 594 admp = (adm1031_unit_t *) 595 ddi_get_soft_state(adm1031_soft_statep, instance); 596 if (admp == NULL) { 597 return (ENXIO); 598 } 599 600 mutex_enter(&admp->adm1031_mutex); 601 admp->adm1031_oflag = 0; 602 mutex_exit(&admp->adm1031_mutex); 603 return (0); 604 } 605 606 static int 607 adm1031_s_ioctl(dev_t dev, int cmd, intptr_t arg, int mode) 608 { 609 adm1031_unit_t *admp; 610 int err = 0, cmd_c = 0; 611 uint8_t speed = 0, f_set = 0, temp = 0, write_value = 0; 612 int16_t temp16 = 0, write_value16 = 0; 613 minor_t minor = getminor(dev); 614 int instance = ADM1031_MINOR_TO_INST(minor); 615 int fcn = ADM1031_MINOR_TO_FCN(minor); 616 int fcn_inst = ADM1031_MINOR_TO_FCNINST(minor); 617 618 admp = (adm1031_unit_t *) 619 ddi_get_soft_state(adm1031_soft_statep, instance); 620 621 /* 622 * We serialize here and block pending transactions. 623 */ 624 mutex_enter(&admp->adm1031_mutex); 625 while (admp->adm1031_flags & ADM1031_BUSYFLAG) { 626 if (cv_wait_sig(&admp->adm1031_cv, 627 &admp->adm1031_mutex) <= 0) { 628 mutex_exit(&admp->adm1031_mutex); 629 return (EINTR); 630 } 631 } 632 admp->adm1031_flags |= ADM1031_BUSYFLAG; 633 mutex_exit(&admp->adm1031_mutex); 634 635 switch (fcn) { 636 case ADM1031_TEMPERATURES: 637 if (cmd == I2C_GET_TEMPERATURE) { 638 admp->adm1031_transfer->i2c_wbuf[0] = 639 temperatures[fcn_inst].reg; 640 goto copyout; 641 } else { 642 cmd = cmd - ADM1031_PVT_BASE_IOCTL; 643 cmd_c = ADM1031_CHECK_FOR_WRITES(cmd) ? 644 (cmd - ADM1031_WRITE_COMMAND_BASE) + fcn_inst : 645 cmd + fcn_inst; 646 if (!ADM1031_CHECK_TEMPERATURE_CMD(cmd_c)) { 647 err = EINVAL; 648 goto done; 649 } 650 admp->adm1031_transfer->i2c_wbuf[0] = 651 adm1031_control_regs[cmd_c]; 652 if (ADM1031_CHECK_FOR_WRITES(cmd)) 653 goto writes; 654 else 655 goto copyout; 656 } 657 case ADM1031_FANS: 658 if (cmd == I2C_GET_FAN_SPEED) { 659 admp->adm1031_transfer->i2c_wbuf[0] = 660 fans[fcn_inst].reg; 661 goto copyout; 662 } else if (cmd == ADM1031_GET_FAN_CONFIG) { 663 admp->adm1031_transfer->i2c_wbuf[0] = 664 ADM1031_FAN_SPEED_CONFIG_REG; 665 goto copyout; 666 } else if (cmd == I2C_SET_FAN_SPEED) { 667 if (ddi_copyin((void *)arg, &write_value, 668 sizeof (write_value), mode) != DDI_SUCCESS) { 669 670 err = EFAULT; 671 goto done; 672 } 673 speed = write_value; 674 if ((admp->adm1031_flags & ADM1031_AUTOFLAG)) { 675 err = EBUSY; 676 goto done; 677 } 678 if (ADM1031_CHECK_INVALID_SPEED(speed)) { 679 err = EINVAL; 680 goto done; 681 } 682 admp->adm1031_transfer->i2c_wbuf[0] = 683 ADM1031_FAN_SPEED_CONFIG_REG; 684 admp->adm1031_transfer->i2c_flags = I2C_WR_RD; 685 admp->adm1031_transfer->i2c_wlen = 1; 686 admp->adm1031_transfer->i2c_rlen = 1; 687 if (i2c_transfer(admp->adm1031_hdl, 688 admp->adm1031_transfer) != I2C_SUCCESS) { 689 err = EIO; 690 goto done; 691 } 692 f_set = admp->adm1031_transfer->i2c_rbuf[0]; 693 f_set = (fcn_inst == 0) ? (MLSN(f_set) | speed): 694 (MMSN(f_set) | (speed << 4)); 695 696 admp->adm1031_transfer->i2c_wbuf[1] = f_set; 697 admp->adm1031_transfer->i2c_flags = I2C_WR; 698 admp->adm1031_transfer->i2c_wlen = 2; 699 if (i2c_transfer(admp->adm1031_hdl, 700 admp->adm1031_transfer) != I2C_SUCCESS) { 701 err = EIO; 702 } 703 goto done; 704 } 705 cmd = cmd - ADM1031_PVT_BASE_IOCTL; 706 cmd_c = ADM1031_CHECK_FOR_WRITES(cmd) ? 707 (cmd - ADM1031_WRITE_COMMAND_BASE) + fcn_inst : 708 cmd + fcn_inst; 709 if (!ADM1031_CHECK_FAN_CMD(cmd_c)) { 710 err = EINVAL; 711 goto done; 712 } 713 admp->adm1031_transfer->i2c_wbuf[0] = 714 adm1031_control_regs[cmd_c]; 715 if (ADM1031_CHECK_FOR_WRITES(cmd)) 716 goto writes; 717 else 718 goto copyout; 719 case ADM1031_CONTROL: 720 721 /* 722 * Read the primary configuration register in advance. 723 */ 724 admp->adm1031_transfer->i2c_wbuf[0] = 725 ADM1031_CONFIG_REG_1; 726 admp->adm1031_transfer->i2c_flags = I2C_WR_RD; 727 admp->adm1031_transfer->i2c_wlen = 1; 728 admp->adm1031_transfer->i2c_rlen = 1; 729 if (i2c_transfer(admp->adm1031_hdl, 730 admp->adm1031_transfer) != I2C_SUCCESS) { 731 err = EIO; 732 goto done; 733 } 734 switch (cmd) { 735 case ADM1031_GET_MONITOR_MODE: 736 temp = ADM1031_AUTOFLAG & 737 admp->adm1031_transfer->i2c_rbuf[0]; 738 temp = temp >> 7; 739 if (ddi_copyout((void *)&temp, (void *)arg, 740 sizeof (temp), mode) != DDI_SUCCESS) { 741 err = EFAULT; 742 } 743 goto done; 744 case ADM1031_SET_MONITOR_MODE: 745 if (ddi_copyin((void *)arg, &write_value, 746 sizeof (write_value), mode) != DDI_SUCCESS) { 747 err = EFAULT; 748 goto done; 749 } 750 if (write_value == ADM1031_AUTO_MODE) { 751 temp = ADM1031_AUTOFLAG | 752 admp->adm1031_transfer->i2c_rbuf[0]; 753 admp->adm1031_flags |= ADM1031_AUTOFLAG; 754 } else if (write_value == ADM1031_MANUAL_MODE) { 755 temp = admp->adm1031_transfer->i2c_rbuf[0] & 756 (~ADM1031_AUTOFLAG); 757 admp->adm1031_flags &= ~ADM1031_AUTOFLAG; 758 } else { 759 err = EINVAL; 760 goto done; 761 } 762 admp->adm1031_transfer->i2c_wbuf[1] = temp; 763 admp->adm1031_transfer->i2c_flags = I2C_WR; 764 admp->adm1031_transfer->i2c_wlen = 2; 765 if (i2c_transfer(admp->adm1031_hdl, 766 admp->adm1031_transfer) != I2C_SUCCESS) { 767 err = EIO; 768 } 769 goto done; 770 default: 771 goto control; 772 } 773 default: 774 err = EINVAL; 775 goto done; 776 } 777 778 control: 779 cmd = cmd - ADM1031_PVT_BASE_IOCTL; 780 781 if (ADM1031_CHECK_FOR_WRITES(cmd)) { 782 cmd_c = (cmd - ADM1031_WRITE_COMMAND_BASE) + fcn_inst; 783 admp->adm1031_transfer->i2c_wbuf[0] = 784 adm1031_control_regs[cmd_c]; 785 786 goto writes; 787 } 788 cmd_c = cmd + fcn_inst; 789 admp->adm1031_transfer->i2c_wbuf[0] = adm1031_control_regs[cmd_c]; 790 goto copyout; 791 792 writes: 793 if (fcn == ADM1031_TEMPERATURES) { 794 if (ddi_copyin((void *)arg, &write_value16, 795 sizeof (write_value16), mode) != DDI_SUCCESS) { 796 797 err = EFAULT; 798 goto done; 799 } 800 write_value = (uint8_t)((int8_t)(write_value16)); 801 } else { 802 if (ddi_copyin((void *)arg, &write_value, 803 sizeof (write_value), mode) != DDI_SUCCESS) { 804 805 err = EFAULT; 806 goto done; 807 } 808 } 809 admp->adm1031_transfer->i2c_flags = I2C_WR; 810 admp->adm1031_transfer->i2c_wlen = 2; 811 admp->adm1031_transfer->i2c_rlen = 0; 812 admp->adm1031_transfer->i2c_wbuf[1] = write_value; 813 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 814 I2C_SUCCESS) { 815 816 err = EIO; 817 } 818 goto done; 819 820 copyout: 821 admp->adm1031_transfer->i2c_flags = I2C_WR_RD; 822 admp->adm1031_transfer->i2c_wlen = 1; 823 admp->adm1031_transfer->i2c_rlen = 1; 824 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 825 I2C_SUCCESS) { 826 827 err = EIO; 828 goto done; 829 } 830 temp = admp->adm1031_transfer->i2c_rbuf[0]; 831 if (fcn == ADM1031_TEMPERATURES) { 832 /* 833 * Workaround for bug in ADM1031 which reports -128 (0x80) 834 * when the temperature transitions from 0C to -1C. 835 * All other -ve temperatures are not affected. We map 836 * 0x80 to 0xFF(-1) since we don't ever expect to see -128C on a 837 * sensor. 838 */ 839 if (temp == 0x80) { 840 temp = 0xFF; 841 } 842 temp16 = (int16_t)((int8_t)temp); 843 if (ddi_copyout((void *)&temp16, (void *)arg, sizeof (temp16), 844 mode) != DDI_SUCCESS) 845 err = EFAULT; 846 } else { 847 if (ddi_copyout((void *)&temp, (void *)arg, sizeof (temp), 848 mode) != DDI_SUCCESS) 849 err = EFAULT; 850 } 851 852 done: 853 mutex_enter(&admp->adm1031_mutex); 854 admp->adm1031_flags = admp->adm1031_flags & (~ADM1031_BUSYFLAG); 855 cv_signal(&admp->adm1031_cv); 856 mutex_exit(&admp->adm1031_mutex); 857 return (err); 858 } 859 860 /* 861 * The interrupt ioctl is a private handshake between the user and the driver 862 * and is a mechanism to asynchronously inform the user of a system event such 863 * as a fan fault or a temperature limit being exceeded. 864 * 865 * Step 1): 866 * User(or environmental monitoring software) calls the ioctl routine 867 * which blocks as it waits on a condition. The open(2) call has to be 868 * called with the _control minor node. The ioctl routine requires 869 * ADM1031_INTERRUPT_WAIT as the command and a pointer to an array of 870 * uint8_t as the third argument. 871 * Step 2): 872 * A system event occurs which unblocks the ioctl and returns the call 873 * to the user. 874 * Step 3): 875 * User reads the contents of the array (which actually contains the values 876 * of the devices' status registers) to determine the exact nature of the 877 * event. 878 */ 879 static int 880 adm1031_i_ioctl(dev_t dev, int cmd, intptr_t arg, int mode) 881 { 882 _NOTE(ARGUNUSED(cmd)) 883 adm1031_unit_t *admp; 884 uint8_t i = 0; 885 minor_t minor = getminor(dev); 886 int fcn = ADM1031_MINOR_TO_FCN(minor); 887 int instance = ADM1031_MINOR_TO_INST(minor); 888 int err = 0; 889 uint8_t temp[2]; 890 uint8_t temp1; 891 892 893 if (fcn != ADM1031_CONTROL) 894 return (EINVAL); 895 896 admp = (adm1031_unit_t *) 897 ddi_get_soft_state(adm1031_soft_statep, instance); 898 899 if (!(admp->adm1031_flags & ADM1031_INTRFLAG)) { 900 cmn_err(CE_WARN, "%s:%d No interrupt handler registered\n", 901 admp->adm1031_name, instance); 902 return (EBUSY); 903 } 904 905 admp->adm1031_transfer->i2c_flags = I2C_WR_RD; 906 admp->adm1031_transfer->i2c_wlen = 1; 907 admp->adm1031_transfer->i2c_rlen = 1; 908 909 /* 910 * The register has to be read to clear the previous status. 911 */ 912 913 for (i = 0; i < 2; i++) { 914 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_STAT_1_REG; 915 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) 916 != I2C_SUCCESS) { 917 return (EIO); 918 } 919 temp[0] = admp->adm1031_transfer->i2c_rbuf[0]; 920 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_STAT_2_REG; 921 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) 922 != I2C_SUCCESS) { 923 return (EIO); 924 } 925 } 926 temp[1] = admp->adm1031_transfer->i2c_rbuf[0]; 927 928 if ((temp[0] != 0) || (temp[1] != 0)) { 929 goto copyout; 930 } 931 932 /* 933 * Enable the interrupt and fan fault alert. 934 */ 935 mutex_enter(&admp->adm1031_mutex); 936 while (admp->adm1031_flags & ADM1031_BUSYFLAG) { 937 if (cv_wait_sig(&admp->adm1031_cv, 938 &admp->adm1031_mutex) <= 0) { 939 mutex_exit(&admp->adm1031_mutex); 940 return (EINTR); 941 } 942 } 943 admp->adm1031_flags |= ADM1031_BUSYFLAG; 944 945 mutex_exit(&admp->adm1031_mutex); 946 947 admp->adm1031_transfer->i2c_flags = I2C_WR_RD; 948 admp->adm1031_transfer->i2c_wlen = 1; 949 admp->adm1031_transfer->i2c_rlen = 1; 950 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_CONFIG_REG_1; 951 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 952 I2C_SUCCESS) { 953 err = EIO; 954 goto err; 955 } 956 957 temp1 = admp->adm1031_transfer->i2c_rbuf[0]; 958 959 admp->adm1031_transfer->i2c_flags = I2C_WR; 960 admp->adm1031_transfer->i2c_wlen = 2; 961 admp->adm1031_transfer->i2c_wbuf[1] = (temp1 | 0x12); 962 963 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 964 I2C_SUCCESS) { 965 err = EIO; 966 goto err; 967 } 968 969 970 mutex_enter(&admp->adm1031_mutex); 971 admp->adm1031_flags = admp->adm1031_flags & (~ADM1031_BUSYFLAG); 972 cv_signal(&admp->adm1031_cv); 973 mutex_exit(&admp->adm1031_mutex); 974 975 976 977 mutex_enter(&admp->adm1031_imutex); 978 admp->adm1031_cvwaiting = 1; 979 (void) cv_wait_sig(&admp->adm1031_icv, &admp->adm1031_imutex); 980 mutex_exit(&admp->adm1031_imutex); 981 982 983 /* 984 * Disable the interrupt and fan fault alert. 985 */ 986 mutex_enter(&admp->adm1031_mutex); 987 988 while (admp->adm1031_flags & ADM1031_BUSYFLAG) { 989 if (cv_wait_sig(&admp->adm1031_cv, 990 &admp->adm1031_mutex) <= 0) { 991 mutex_exit(&admp->adm1031_mutex); 992 return (EINTR); 993 } 994 } 995 admp->adm1031_flags |= ADM1031_BUSYFLAG; 996 997 admp->adm1031_transfer->i2c_flags = I2C_WR_RD; 998 admp->adm1031_transfer->i2c_wlen = 1; 999 admp->adm1031_transfer->i2c_rlen = 1; 1000 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_CONFIG_REG_1; 1001 1002 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 1003 I2C_SUCCESS) { 1004 err = EIO; 1005 goto err; 1006 } 1007 1008 1009 temp1 = admp->adm1031_transfer->i2c_rbuf[0]; 1010 admp->adm1031_transfer->i2c_flags = I2C_WR; 1011 admp->adm1031_transfer->i2c_wlen = 2; 1012 admp->adm1031_transfer->i2c_wbuf[1] = (temp1 & (~0x12)); 1013 1014 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 1015 I2C_SUCCESS) { 1016 err = (EIO); 1017 goto err; 1018 } 1019 1020 admp->adm1031_flags = admp->adm1031_flags & (~ADM1031_BUSYFLAG); 1021 cv_signal(&admp->adm1031_cv); 1022 mutex_exit(&admp->adm1031_mutex); 1023 1024 admp->adm1031_transfer->i2c_flags = I2C_WR_RD; 1025 admp->adm1031_transfer->i2c_wlen = 1; 1026 admp->adm1031_transfer->i2c_rlen = 1; 1027 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_STAT_1_REG; 1028 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 1029 I2C_SUCCESS) { 1030 1031 return (EIO); 1032 } 1033 temp[0] = admp->adm1031_transfer->i2c_rbuf[0]; 1034 1035 admp->adm1031_transfer->i2c_wbuf[0] = ADM1031_STAT_2_REG; 1036 if (i2c_transfer(admp->adm1031_hdl, admp->adm1031_transfer) != 1037 I2C_SUCCESS) { 1038 1039 return (EIO); 1040 } 1041 temp[1] = admp->adm1031_transfer->i2c_rbuf[0]; 1042 1043 copyout: 1044 if (ddi_copyout((void *)&temp, (void *)arg, sizeof (temp), 1045 mode) != DDI_SUCCESS) { 1046 1047 return (EFAULT); 1048 } 1049 1050 return (0); 1051 1052 err: 1053 mutex_enter(&admp->adm1031_mutex); 1054 admp->adm1031_flags = admp->adm1031_flags & (~ADM1031_BUSYFLAG); 1055 cv_signal(&admp->adm1031_cv); 1056 mutex_exit(&admp->adm1031_mutex); 1057 1058 return (err); 1059 } 1060 1061 static int 1062 adm1031_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1063 int *rvalp) 1064 { 1065 _NOTE(ARGUNUSED(credp, rvalp)) 1066 1067 if (cmd == ADM1031_INTERRUPT_WAIT) { 1068 1069 return (adm1031_i_ioctl(dev, cmd, arg, mode)); 1070 } else { 1071 return (adm1031_s_ioctl(dev, cmd, arg, mode)); 1072 } 1073 } 1074