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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * Driver to map the PIC for the chicago platform.
30 #include <sys/types.h>
32 #include <sys/errno.h>
33 #include <sys/cmn_err.h>
34 #include <sys/param.h>
35 #include <sys/modctl.h>
39 #include <sys/clock.h>
41 #include <sys/pic16f747.h>
43 #include <sys/sunddi.h>
46 /* dev_ops and cb_ops entry point function declarations */
47 static int pic_attach(dev_info_t
*, ddi_attach_cmd_t
);
48 static int pic_detach(dev_info_t
*, ddi_detach_cmd_t
);
49 static int pic_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
50 static int pic_open(dev_t
*, int, int, cred_t
*);
51 static int pic_close(dev_t
, int, int, cred_t
*);
52 static int pic_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
54 struct cb_ops pic_cb_ops
= {
65 ddi_segmap
, /* segmap */
68 NULL
, /* for STREAMS drivers */
69 D_NEW
| D_MP
/* driver compatibility flag */
72 static struct dev_ops pic_dev_ops
= {
73 DEVO_REV
, /* driver build version */
74 0, /* device reference count */
82 (struct bus_ops
*)NULL
,
84 ddi_quiesce_not_supported
, /* devo_quiesce */
88 * Fans' and sensors' node names and register offsets
90 static struct minor_node_info pic_nodes
[N_PIC_NODES
] = {
91 {NULL
, 0, 0}, /* Reserved */
92 {"fan_0", RF_FAN0_PERIOD
, F0_FLT_BIT
}, /* System Fan 0 */
93 {"fan_1", RF_FAN1_PERIOD
, F1_FLT_BIT
}, /* System Fan 1 */
94 {"fan_2", RF_FAN2_PERIOD
, F2_FLT_BIT
}, /* System Fan 2 */
95 {"fan_3", RF_FAN3_PERIOD
, F3_FLT_BIT
}, /* System Fan 3 */
96 {"fan_4", RF_FAN4_PERIOD
, F4_FLT_BIT
}, /* System Fan 4 */
97 {"adt7462", RF_LOCAL_TEMP
, 0}, /* ADT7462 Local Temperature */
98 {"cpu_0", RF_REMOTE1_TEMP
, 0}, /* CPU 0 temp */
99 {"cpu_1", RF_REMOTE2_TEMP
, 0}, /* CPU 1 temp */
100 {"mb", RF_REMOTE3_TEMP
, 0}, /* Motherboard temp */
101 {"lm95221", RF_LM95221_TEMP
, 0}, /* LM95221 Local Temperature */
102 {"fire", RF_FIRE_TEMP
, 0}, /* FIRE Temp */
103 {"lsi1064", RF_LSI1064_TEMP
, 0}, /* LSI1064 Temp */
104 {"front_panel", RF_FRONT_TEMP
, 0}, /* Front Panel Temperature */
105 {"psu", RF_PSU_TEMP
, PSUF_FLT_BIT
} /* PSU Temp (and ffault) */
115 ddi_acc_handle_t cmd_handle
;
117 #define getsoftc(inst) ((struct pic_softc *)ddi_get_soft_state(statep, (inst)))
119 /* module configuration stuff */
121 extern struct mod_ops mod_driverops
;
123 static struct modldrv modldrv
= {
129 static struct modlinkage modlinkage
= {
140 if (e
= ddi_soft_state_init(&statep
, sizeof (struct pic_softc
),
141 MAX_PIC_INSTANCES
)) {
145 if ((e
= mod_install(&modlinkage
)) != 0)
146 ddi_soft_state_fini(&statep
);
156 if ((e
= mod_remove(&modlinkage
)) != 0)
159 ddi_soft_state_fini(&statep
);
161 return (DDI_SUCCESS
);
165 _info(struct modinfo
*modinfop
)
167 return (mod_info(&modlinkage
, modinfop
));
172 pic_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
175 int retval
= DDI_SUCCESS
;
176 struct pic_softc
*softc
;
178 inst
= PIC_MINOR_TO_INST(getminor((dev_t
)arg
));
181 case DDI_INFO_DEVT2DEVINFO
:
182 if ((softc
= getsoftc(inst
)) == NULL
) {
183 *result
= (void *)NULL
;
184 retval
= DDI_FAILURE
;
186 *result
= (void *)softc
->dip
;
189 case DDI_INFO_DEVT2INSTANCE
:
190 *result
= (void *)((uintptr_t)inst
);
194 retval
= DDI_FAILURE
;
201 pic_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
205 struct pic_softc
*softc
= NULL
;
209 ddi_device_acc_attr_t dev_attr
;
214 inst
= ddi_get_instance(dip
);
215 if (inst
>= MAX_PIC_INSTANCES
) {
216 cmn_err(CE_WARN
, "attach failed, too many instances\n");
217 return (DDI_FAILURE
);
220 (void) sprintf(name
, "env-monitor%d", inst
);
221 minor
= PIC_INST_TO_MINOR(inst
) | PIC_UNIT_TO_MINOR(0);
222 if (ddi_create_minor_node(dip
, name
, S_IFCHR
, minor
,
223 DDI_PSEUDO
, NULL
) == DDI_FAILURE
) {
225 "ddi_create_minor_node() failed for inst %d\n",
227 return (DDI_FAILURE
);
230 /* Allocate a soft state structure for this instance */
231 if (ddi_soft_state_zalloc(statep
, inst
) != DDI_SUCCESS
) {
232 cmn_err(CE_WARN
, " ddi_soft_state_zalloc() failed "
233 "for inst %d\n", inst
);
237 /* Setup soft state */
238 softc
= getsoftc(inst
);
240 mutex_init(&softc
->mutex
, NULL
, MUTEX_DRIVER
, NULL
);
242 /* Setup device attributes */
243 dev_attr
.devacc_attr_version
= DDI_DEVICE_ATTR_V0
;
244 dev_attr
.devacc_attr_endian_flags
= DDI_STRUCTURE_LE_ACC
;
245 dev_attr
.devacc_attr_dataorder
= DDI_STRICTORDER_ACC
;
248 * The RF_COMMAND/RF_STATUS and RF_IND_DATA/RF_IND_ADDR
249 * register pairs are mapped as one register set starting
250 * from 0x0 and length 0x42.
252 res
= ddi_regs_map_setup(dip
, 0, (caddr_t
*)&softc
->cmd_reg
,
253 0, 0x42, &dev_attr
, &softc
->cmd_handle
);
254 if (res
!= DDI_SUCCESS
) {
255 cmn_err(CE_WARN
, "ddi_regs_map_setup() failed\n");
259 /* Set up fans' and sensors' device minor nodes */
260 for (i
= 1; i
< N_PIC_NODES
; i
++) {
261 minor_name
= pic_nodes
[i
].minor_name
;
262 minor
= PIC_INST_TO_MINOR(inst
) | PIC_UNIT_TO_MINOR(i
);
263 if (ddi_create_minor_node(dip
, minor_name
, S_IFCHR
,
264 minor
, PICDEV_NODE_TYPE
, NULL
) == DDI_FAILURE
) {
266 "%s:%d ddi_create_minor_node failed",
267 ddi_driver_name(dip
), inst
);
268 (void) pic_detach(dip
, DDI_DETACH
);
269 return (DDI_FAILURE
);
273 /* Create main environmental node */
276 return (DDI_SUCCESS
);
279 return (DDI_SUCCESS
);
282 return (DDI_FAILURE
);
287 /* Free soft state, if allocated. remove minor node if added earlier */
289 ddi_soft_state_free(statep
, inst
);
291 ddi_remove_minor_node(dip
, NULL
);
293 return (DDI_FAILURE
);
297 pic_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
300 struct pic_softc
*softc
;
304 inst
= ddi_get_instance(dip
);
305 if ((softc
= getsoftc(inst
)) == NULL
)
308 (void) ddi_regs_map_free(&softc
->cmd_handle
);
309 /* Free the soft state and remove minor node added earlier */
310 mutex_destroy(&softc
->mutex
);
311 ddi_soft_state_free(statep
, inst
);
312 ddi_remove_minor_node(dip
, NULL
);
313 return (DDI_SUCCESS
);
316 return (DDI_SUCCESS
);
319 return (DDI_FAILURE
);
325 pic_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*credp
)
327 int inst
= PIC_MINOR_TO_INST(getminor(*devp
));
329 return (getsoftc(inst
) == NULL
? ENXIO
: 0);
334 pic_close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
)
336 int inst
= PIC_MINOR_TO_INST(getminor(dev
));
338 return (getsoftc(inst
) == NULL
? ENXIO
: 0);
343 pic_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
, int *rvalp
)
347 struct pic_softc
*softc
;
351 inst
= PIC_MINOR_TO_INST(getminor(dev
));
352 if ((softc
= getsoftc(inst
)) == NULL
)
355 mutex_enter(&softc
->mutex
);
357 if (ddi_copyin((caddr_t
)arg
, &in_command
, sizeof (in_command
),
358 mode
) != DDI_SUCCESS
) {
359 mutex_exit(&softc
->mutex
);
363 node
= PIC_MINOR_TO_UNIT(getminor(dev
));
364 if ((node
>= N_PIC_NODES
) || (node
< 1)) {
365 mutex_exit(&softc
->mutex
);
370 case PIC_GET_TEMPERATURE
:
373 /* select the temp sensor */
374 (void) ddi_put8(softc
->cmd_handle
, (uint8_t *)softc
->cmd_reg
+
375 RF_IND_ADDR
, pic_nodes
[node
].reg_offset
);
377 /* retrieve temperature data */
378 tempr
= (int16_t)ddi_get8(softc
->cmd_handle
,
379 (uint8_t *)softc
->cmd_reg
+ RF_IND_DATA
);
380 mutex_exit(&softc
->mutex
);
386 * The temp is passed in as a uint8 value, we need to convert
387 * it to a signed 16 bit value to be able to handle the range
388 * of -64 to 190 degrees.
391 (void) ddi_copyout(&tempr
, (caddr_t
)arg
, sizeof (tempr
), mode
);
394 case PIC_GET_FAN_SPEED
:
398 (void) ddi_put8(softc
->cmd_handle
, (uint8_t *)softc
->cmd_reg
+
399 RF_IND_ADDR
, pic_nodes
[node
].reg_offset
);
401 /* retrieve fan data */
402 in_command
= ddi_get8(softc
->cmd_handle
,
403 (uint8_t *)softc
->cmd_reg
+ RF_IND_DATA
);
404 mutex_exit(&softc
->mutex
);
406 if (in_command
== 0xff)
409 (void) ddi_copyout(&in_command
, (caddr_t
)arg
, 1, mode
);
412 case PIC_SET_FAN_SPEED
:
414 (void) ddi_put8(softc
->cmd_handle
, (uint8_t *)softc
->cmd_reg
+
415 RF_IND_ADDR
, pic_nodes
[node
].reg_offset
);
417 /* send the fan data */
418 (void) ddi_put8(softc
->cmd_handle
,
419 (uint8_t *)softc
->cmd_reg
+ RF_IND_DATA
, in_command
);
421 mutex_exit(&softc
->mutex
);
425 mutex_exit(&softc
->mutex
);
427 /* we don't read the status reg anymore */
429 (void) ddi_copyout(&in_command
, (caddr_t
)arg
, 1, mode
);
433 case PIC_GET_FAN_STATUS
:
436 /* read ffault register */
437 (void) ddi_put8(softc
->cmd_handle
, (uint8_t *)softc
->cmd_reg
+
438 RF_IND_ADDR
, RF_FAN_STATUS
);
440 /* retrieve fan failure status */
441 in_command
= ddi_get8(softc
->cmd_handle
,
442 (uint8_t *)softc
->cmd_reg
+ RF_IND_DATA
);
443 mutex_exit(&softc
->mutex
);
445 if (in_command
== 0xff)
448 in_command
= (in_command
>> pic_nodes
[node
].ff_shift
) & 0x1;
449 (void) ddi_copyout(&in_command
, (caddr_t
)arg
, 1, mode
);
452 case PIC_SET_ESTAR_MODE
:
453 (void) ddi_put8(softc
->cmd_handle
,
454 (uint8_t *)softc
->cmd_reg
+ RF_COMMAND
, CMD_TO_ESTAR
);
455 mutex_exit(&softc
->mutex
);
459 mutex_exit(&softc
->mutex
);
460 cmn_err(CE_NOTE
, "cmd %d isnt valid", cmd
);