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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)205 _info(struct modinfo *modinfop)
206 {
207 return (mod_info(&adm1031_modlinkage, modinfop));
208 }
209
210 static int
adm1031_resume(dev_info_t * dip)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
adm1031_detach(dev_info_t * dip)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
adm1031_intr(caddr_t arg)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
adm1031_attach(dev_info_t * dip)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
adm1031_s_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
adm1031_suspend(dev_info_t * dip)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
adm1031_s_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
adm1031_open(dev_t * devp,int flags,int otyp,cred_t * credp)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
adm1031_close(dev_t dev,int flags,int otyp,cred_t * credp)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
adm1031_s_ioctl(dev_t dev,int cmd,intptr_t arg,int mode)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
adm1031_i_ioctl(dev_t dev,int cmd,intptr_t arg,int mode)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
adm1031_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)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