xref: /onnv-gate/usr/src/uts/sun4u/grover/io/grfans.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2000-2003 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate #include <sys/stat.h>
9*0Sstevel@tonic-gate #include <sys/file.h>
10*0Sstevel@tonic-gate #include <sys/uio.h>
11*0Sstevel@tonic-gate #include <sys/modctl.h>
12*0Sstevel@tonic-gate #include <sys/open.h>
13*0Sstevel@tonic-gate #include <sys/types.h>
14*0Sstevel@tonic-gate #include <sys/kmem.h>
15*0Sstevel@tonic-gate #include <sys/systm.h>
16*0Sstevel@tonic-gate #include <sys/ddi.h>
17*0Sstevel@tonic-gate #include <sys/sunddi.h>
18*0Sstevel@tonic-gate #include <sys/conf.h>
19*0Sstevel@tonic-gate #include <sys/mode.h>
20*0Sstevel@tonic-gate #include <sys/policy.h>
21*0Sstevel@tonic-gate 
22*0Sstevel@tonic-gate #include <sys/grfans.h>
23*0Sstevel@tonic-gate 
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate  * cb ops
26*0Sstevel@tonic-gate  */
27*0Sstevel@tonic-gate static int grfans_open(dev_t *, int, int, cred_t *);
28*0Sstevel@tonic-gate static int grfans_close(dev_t, int, int, cred_t *);
29*0Sstevel@tonic-gate static int grfans_read(dev_t dev, struct uio *uiop, cred_t *cred_p);
30*0Sstevel@tonic-gate static int grfans_write(dev_t dev, struct uio *uiop, cred_t *cred_p);
31*0Sstevel@tonic-gate static int grfans_io(dev_t dev, struct uio *uiop, int rw);
32*0Sstevel@tonic-gate /*
33*0Sstevel@tonic-gate  * dev ops
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate static int grfans_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
36*0Sstevel@tonic-gate 		void **result);
37*0Sstevel@tonic-gate static int grfans_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
38*0Sstevel@tonic-gate static int grfans_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate static struct cb_ops grfans_cbops = {
41*0Sstevel@tonic-gate 	grfans_open,		/* open */
42*0Sstevel@tonic-gate 	grfans_close,		/* close */
43*0Sstevel@tonic-gate 	nodev,			/* strategy */
44*0Sstevel@tonic-gate 	nodev,			/* print */
45*0Sstevel@tonic-gate 	nodev,			/* dump */
46*0Sstevel@tonic-gate 	grfans_read,		/* read */
47*0Sstevel@tonic-gate 	grfans_write,		/* write */
48*0Sstevel@tonic-gate 	nodev,			/* ioctl */
49*0Sstevel@tonic-gate 	nodev,			/* devmap */
50*0Sstevel@tonic-gate 	nodev,			/* mmap */
51*0Sstevel@tonic-gate 	nodev,			/* segmap */
52*0Sstevel@tonic-gate 	nochpoll,		/* poll */
53*0Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
54*0Sstevel@tonic-gate 	NULL,			/* streamtab */
55*0Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */
56*0Sstevel@tonic-gate 	CB_REV,			/* rev */
57*0Sstevel@tonic-gate 	nodev,			/* int (*cb_aread)() */
58*0Sstevel@tonic-gate 	nodev			/* int (*cb_awrite)() */
59*0Sstevel@tonic-gate };
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate static struct dev_ops grfans_ops = {
62*0Sstevel@tonic-gate 	DEVO_REV,
63*0Sstevel@tonic-gate 	0,
64*0Sstevel@tonic-gate 	grfans_info,
65*0Sstevel@tonic-gate 	nulldev,
66*0Sstevel@tonic-gate 	nulldev,
67*0Sstevel@tonic-gate 	grfans_attach,
68*0Sstevel@tonic-gate 	grfans_detach,
69*0Sstevel@tonic-gate 	nodev,
70*0Sstevel@tonic-gate 	&grfans_cbops,
71*0Sstevel@tonic-gate 	NULL
72*0Sstevel@tonic-gate };
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate static struct modldrv grfans_modldrv = {
75*0Sstevel@tonic-gate 	&mod_driverops,		/* type of module - driver */
76*0Sstevel@tonic-gate 	"grfans device driver v%I%",
77*0Sstevel@tonic-gate 	&grfans_ops,
78*0Sstevel@tonic-gate };
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate static struct modlinkage grfans_modlinkage = {
81*0Sstevel@tonic-gate 	MODREV_1,
82*0Sstevel@tonic-gate 	&grfans_modldrv,
83*0Sstevel@tonic-gate 	0
84*0Sstevel@tonic-gate };
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate static void *grfans_soft_statep;
87*0Sstevel@tonic-gate static int grfans_debug = 0;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate int
90*0Sstevel@tonic-gate _init(void)
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate 	int    error;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	error = mod_install(&grfans_modlinkage);
95*0Sstevel@tonic-gate 	if (error == 0) {
96*0Sstevel@tonic-gate 		(void) ddi_soft_state_init(&grfans_soft_statep,
97*0Sstevel@tonic-gate 			sizeof (struct grfans_unit), 1);
98*0Sstevel@tonic-gate 	}
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	return (error);
101*0Sstevel@tonic-gate }
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate int
104*0Sstevel@tonic-gate _fini(void)
105*0Sstevel@tonic-gate {
106*0Sstevel@tonic-gate 	int    error;
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 	error = mod_remove(&grfans_modlinkage);
109*0Sstevel@tonic-gate 	if (error == 0) {
110*0Sstevel@tonic-gate 		ddi_soft_state_fini(&grfans_soft_statep);
111*0Sstevel@tonic-gate 	}
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	return (error);
114*0Sstevel@tonic-gate }
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate int
117*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
118*0Sstevel@tonic-gate {
119*0Sstevel@tonic-gate 	return (mod_info(&grfans_modlinkage, modinfop));
120*0Sstevel@tonic-gate }
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate /* ARGSUSED */
123*0Sstevel@tonic-gate static int
124*0Sstevel@tonic-gate grfans_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
125*0Sstevel@tonic-gate {
126*0Sstevel@tonic-gate 	dev_t	dev;
127*0Sstevel@tonic-gate 	int	instance;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
130*0Sstevel@tonic-gate 		dev = (dev_t)arg;
131*0Sstevel@tonic-gate 		instance = MINOR_TO_DEVINST(dev);
132*0Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
133*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
134*0Sstevel@tonic-gate 	}
135*0Sstevel@tonic-gate 	return (DDI_FAILURE);
136*0Sstevel@tonic-gate }
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate static int
139*0Sstevel@tonic-gate grfans_do_attach(dev_info_t *dip)
140*0Sstevel@tonic-gate {
141*0Sstevel@tonic-gate 	struct grfans_unit *unitp;
142*0Sstevel@tonic-gate 	int instance;
143*0Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
144*0Sstevel@tonic-gate 	int nregs;
145*0Sstevel@tonic-gate 	char name[32];
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(grfans_soft_statep, instance) != 0) {
150*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d failed to zalloc softstate",
151*0Sstevel@tonic-gate 		    ddi_get_name(dip), instance);
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 		return (DDI_FAILURE);
154*0Sstevel@tonic-gate 	}
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	if (grfans_debug) {
157*0Sstevel@tonic-gate 		printf("attached instance number %d\n", instance);
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	unitp = ddi_get_soft_state(grfans_soft_statep, instance);
161*0Sstevel@tonic-gate 	if (unitp == NULL)
162*0Sstevel@tonic-gate 		return (DDI_FAILURE);
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	(void) snprintf(name, sizeof (name), "%s%d", ddi_driver_name(dip),
165*0Sstevel@tonic-gate 	    instance);
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
168*0Sstevel@tonic-gate 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
169*0Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	if (grfans_debug) {
172*0Sstevel@tonic-gate 		printf("number of registers is %d\n",
173*0Sstevel@tonic-gate 		    ddi_dev_nregs(dip, &nregs));
174*0Sstevel@tonic-gate 	}
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, 0,
177*0Sstevel@tonic-gate 	    (caddr_t *)&unitp->cpufan_reg,
178*0Sstevel@tonic-gate 	    3, 1, &attr, &unitp->cpufan_rhandle) != DDI_SUCCESS) {
179*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ddi_regs_map_setup failed for regset "
180*0Sstevel@tonic-gate 		    "0", name);
181*0Sstevel@tonic-gate 		ddi_soft_state_free(grfans_soft_statep, instance);
182*0Sstevel@tonic-gate 		return (DDI_FAILURE);
183*0Sstevel@tonic-gate 	}
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, 1,
186*0Sstevel@tonic-gate 	    (caddr_t *)&unitp->sysfan_reg,
187*0Sstevel@tonic-gate 	    0, 1, &attr, &unitp->sysfan_rhandle) != DDI_SUCCESS) {
188*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ddi_regs_map_setup failed for regset "
189*0Sstevel@tonic-gate 		    "1", name);
190*0Sstevel@tonic-gate 		ddi_regs_map_free(&unitp->cpufan_rhandle);
191*0Sstevel@tonic-gate 		ddi_soft_state_free(grfans_soft_statep, instance);
192*0Sstevel@tonic-gate 		return (DDI_FAILURE);
193*0Sstevel@tonic-gate 	}
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "cpu_fan", S_IFCHR,
196*0Sstevel@tonic-gate 	    DEVINST_TO_MINOR(instance) | CHANNEL_TO_MINOR(CPU_FAN_CHANNEL),
197*0Sstevel@tonic-gate 	    FANS_NODE_TYPE, NULL) == DDI_FAILURE) {
198*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ddi_create_minor_node failed"
199*0Sstevel@tonic-gate 		    " for cpu fan", name);
200*0Sstevel@tonic-gate 		ddi_regs_map_free(&unitp->cpufan_rhandle);
201*0Sstevel@tonic-gate 		ddi_regs_map_free(&unitp->sysfan_rhandle);
202*0Sstevel@tonic-gate 		ddi_soft_state_free(grfans_soft_statep, instance);
203*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 		return (DDI_FAILURE);
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "sys_fan", S_IFCHR,
209*0Sstevel@tonic-gate 	    DEVINST_TO_MINOR(instance) | CHANNEL_TO_MINOR(SYSTEM_FAN_CHANNEL),
210*0Sstevel@tonic-gate 	    FANS_NODE_TYPE, NULL) == DDI_FAILURE) {
211*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ddi_create_minor_node failed"
212*0Sstevel@tonic-gate 		    " for system fan", name);
213*0Sstevel@tonic-gate 		ddi_regs_map_free(&unitp->cpufan_rhandle);
214*0Sstevel@tonic-gate 		ddi_regs_map_free(&unitp->sysfan_rhandle);
215*0Sstevel@tonic-gate 		ddi_soft_state_free(grfans_soft_statep, instance);
216*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 		return (DDI_FAILURE);
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	mutex_init(&unitp->mutex, NULL, MUTEX_DRIVER, NULL);
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
224*0Sstevel@tonic-gate }
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate static int
227*0Sstevel@tonic-gate grfans_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
228*0Sstevel@tonic-gate {
229*0Sstevel@tonic-gate 	switch (cmd) {
230*0Sstevel@tonic-gate 	case DDI_ATTACH:
231*0Sstevel@tonic-gate 		return (grfans_do_attach(dip));
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	case DDI_RESUME:
234*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	default:
237*0Sstevel@tonic-gate 		return (DDI_FAILURE);
238*0Sstevel@tonic-gate 	}
239*0Sstevel@tonic-gate }
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate static int
242*0Sstevel@tonic-gate grfans_do_detach(dev_info_t *dip)
243*0Sstevel@tonic-gate {
244*0Sstevel@tonic-gate 	struct grfans_unit *unitp;
245*0Sstevel@tonic-gate 	int instance;
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
248*0Sstevel@tonic-gate 	unitp = ddi_get_soft_state(grfans_soft_statep, instance);
249*0Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	ddi_regs_map_free(&unitp->cpufan_rhandle);
252*0Sstevel@tonic-gate 	ddi_regs_map_free(&unitp->sysfan_rhandle);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	mutex_destroy(&unitp->mutex);
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	ddi_soft_state_free(grfans_soft_statep, instance);
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
259*0Sstevel@tonic-gate }
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate static int
262*0Sstevel@tonic-gate grfans_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
263*0Sstevel@tonic-gate {
264*0Sstevel@tonic-gate 	switch (cmd) {
265*0Sstevel@tonic-gate 	case DDI_DETACH:
266*0Sstevel@tonic-gate 		return (grfans_do_detach(dip));
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	case DDI_SUSPEND:
269*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	default:
272*0Sstevel@tonic-gate 		return (DDI_FAILURE);
273*0Sstevel@tonic-gate 	}
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate /*ARGSUSED*/
277*0Sstevel@tonic-gate static int
278*0Sstevel@tonic-gate grfans_open(dev_t *devp, int flags, int otyp, cred_t *credp)
279*0Sstevel@tonic-gate {
280*0Sstevel@tonic-gate 	struct grfans_unit *unitp;
281*0Sstevel@tonic-gate 	int err = 0;
282*0Sstevel@tonic-gate 	int instance = MINOR_TO_DEVINST(*devp);
283*0Sstevel@tonic-gate 	int channel;
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	/*
286*0Sstevel@tonic-gate 	 * must be privileged to access this device
287*0Sstevel@tonic-gate 	 */
288*0Sstevel@tonic-gate 	if (secpolicy_sys_config(credp, B_FALSE) != 0)
289*0Sstevel@tonic-gate 		return (EPERM);
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if (instance < 0) {
292*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "grfan: instance less than 0:  %d\n",
293*0Sstevel@tonic-gate 		    instance);
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 		return (ENXIO);
296*0Sstevel@tonic-gate 	}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	unitp = ddi_get_soft_state(grfans_soft_statep, instance);
299*0Sstevel@tonic-gate 	if (unitp == NULL) {
300*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "grfan: no soft state for instance %d\n",
301*0Sstevel@tonic-gate 		    instance);
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 		return (ENXIO);
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
307*0Sstevel@tonic-gate 		return (EINVAL);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	channel = MINOR_TO_CHANNEL(getminor(*devp));
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	mutex_enter(&unitp->mutex);
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	if (flags & FEXCL) {
314*0Sstevel@tonic-gate 		if (unitp->oflag[channel] != 0)
315*0Sstevel@tonic-gate 			err = EBUSY;
316*0Sstevel@tonic-gate 		else
317*0Sstevel@tonic-gate 			unitp->oflag[channel] = FEXCL;
318*0Sstevel@tonic-gate 	} else {
319*0Sstevel@tonic-gate 		if (unitp->oflag[channel] == FEXCL)
320*0Sstevel@tonic-gate 			err = EBUSY;
321*0Sstevel@tonic-gate 		else
322*0Sstevel@tonic-gate 			unitp->oflag[channel] = FOPEN;
323*0Sstevel@tonic-gate 	}
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	mutex_exit(&unitp->mutex);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	return (err);
328*0Sstevel@tonic-gate }
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate /*ARGSUSED*/
331*0Sstevel@tonic-gate static int
332*0Sstevel@tonic-gate grfans_close(dev_t dev, int flags, int otyp, cred_t *credp)
333*0Sstevel@tonic-gate {
334*0Sstevel@tonic-gate 	struct grfans_unit *unitp;
335*0Sstevel@tonic-gate 	int instance = MINOR_TO_DEVINST(dev);
336*0Sstevel@tonic-gate 	int channel;
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	if (instance < 0)
339*0Sstevel@tonic-gate 		return (ENXIO);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	unitp = ddi_get_soft_state(grfans_soft_statep, instance);
342*0Sstevel@tonic-gate 	if (unitp == NULL)
343*0Sstevel@tonic-gate 		return (ENXIO);
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	channel = MINOR_TO_CHANNEL(getminor(dev));
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	unitp->oflag[channel] = 0;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
350*0Sstevel@tonic-gate }
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate /*ARGSUSED*/
353*0Sstevel@tonic-gate static int
354*0Sstevel@tonic-gate grfans_read(dev_t dev, struct uio *uiop, cred_t *cred_p)
355*0Sstevel@tonic-gate {
356*0Sstevel@tonic-gate 	return (grfans_io(dev, uiop, B_READ));
357*0Sstevel@tonic-gate }
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate /*ARGSUSED*/
360*0Sstevel@tonic-gate static int
361*0Sstevel@tonic-gate grfans_write(dev_t dev, struct uio *uiop, cred_t *cred_p)
362*0Sstevel@tonic-gate {
363*0Sstevel@tonic-gate 	return (grfans_io(dev, uiop, B_WRITE));
364*0Sstevel@tonic-gate }
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate static int
367*0Sstevel@tonic-gate grfans_io(dev_t dev, struct uio *uiop, int rw)
368*0Sstevel@tonic-gate {
369*0Sstevel@tonic-gate 	struct grfans_unit *unitp;
370*0Sstevel@tonic-gate 	int instance = MINOR_TO_DEVINST(getminor(dev));
371*0Sstevel@tonic-gate 	int ret = 0;
372*0Sstevel@tonic-gate 	size_t len = uiop->uio_resid;
373*0Sstevel@tonic-gate 	int8_t out_value, req_value, reg_value;
374*0Sstevel@tonic-gate 	caddr_t outputaddr;
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	if (instance < 0)
377*0Sstevel@tonic-gate 		return (ENXIO);
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	if (len == 0)
380*0Sstevel@tonic-gate 		return (0);
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	unitp = ddi_get_soft_state(grfans_soft_statep, instance);
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	if (unitp == NULL)
385*0Sstevel@tonic-gate 		return (ENXIO);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	if (MINOR_TO_CHANNEL(getminor(dev)) == CPU_FAN_CHANNEL)
388*0Sstevel@tonic-gate 		outputaddr = &unitp->cpufan_output;
389*0Sstevel@tonic-gate 	else
390*0Sstevel@tonic-gate 		outputaddr = &unitp->sysfan_output;
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	if (rw == B_READ) {
393*0Sstevel@tonic-gate 		if (*outputaddr == UNKNOWN_OUT)
394*0Sstevel@tonic-gate 			return (EIO);
395*0Sstevel@tonic-gate 		return (uiomove(outputaddr, 1, UIO_READ, uiop));
396*0Sstevel@tonic-gate 	}
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	/*
399*0Sstevel@tonic-gate 	 * rw == B_WRITE.
400*0Sstevel@tonic-gate 	 */
401*0Sstevel@tonic-gate 	if ((ret = uiomove(&req_value, sizeof (req_value), UIO_WRITE,
402*0Sstevel@tonic-gate 	    uiop)) == 0) {
403*0Sstevel@tonic-gate 		if (MINOR_TO_CHANNEL(dev) == CPU_FAN_CHANNEL) {
404*0Sstevel@tonic-gate 			/*
405*0Sstevel@tonic-gate 			 * Check bounds for cpu fan
406*0Sstevel@tonic-gate 			 */
407*0Sstevel@tonic-gate 			if (req_value == 0) {
408*0Sstevel@tonic-gate 				reg_value = CPU_FAN_0;
409*0Sstevel@tonic-gate 				out_value = 0;
410*0Sstevel@tonic-gate 			} else if (req_value <= 25) {
411*0Sstevel@tonic-gate 				reg_value = CPU_FAN_25;
412*0Sstevel@tonic-gate 				out_value = 25;
413*0Sstevel@tonic-gate 			} else if (req_value <= 50) {
414*0Sstevel@tonic-gate 				reg_value = CPU_FAN_50;
415*0Sstevel@tonic-gate 				out_value = 50;
416*0Sstevel@tonic-gate 			} else if (req_value <= 75) {
417*0Sstevel@tonic-gate 				reg_value = CPU_FAN_75;
418*0Sstevel@tonic-gate 				out_value = 75;
419*0Sstevel@tonic-gate 			} else if (req_value <= 100) {
420*0Sstevel@tonic-gate 				reg_value = CPU_FAN_100;
421*0Sstevel@tonic-gate 				out_value = 100;
422*0Sstevel@tonic-gate 			} else
423*0Sstevel@tonic-gate 				ret = EINVAL;
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 			if (ret != EINVAL) {
426*0Sstevel@tonic-gate 				uint8_t reg;
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 				*outputaddr = out_value;
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 				reg = ddi_get8(unitp->cpufan_rhandle,
431*0Sstevel@tonic-gate 				    unitp->cpufan_reg);
432*0Sstevel@tonic-gate 				reg = (reg & ~CPU_FAN_MASK) | reg_value;
433*0Sstevel@tonic-gate 				ddi_put8(unitp->cpufan_rhandle,
434*0Sstevel@tonic-gate 				    unitp->cpufan_reg, reg);
435*0Sstevel@tonic-gate 				(void) ddi_get8(unitp->cpufan_rhandle,
436*0Sstevel@tonic-gate 				    unitp->cpufan_reg);
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 				if (grfans_debug) {
439*0Sstevel@tonic-gate 					printf("set output to %d at addr %p\n",
440*0Sstevel@tonic-gate 					    out_value,
441*0Sstevel@tonic-gate 					    unitp->cpufan_reg);
442*0Sstevel@tonic-gate 				}
443*0Sstevel@tonic-gate 			}
444*0Sstevel@tonic-gate 		} else {
445*0Sstevel@tonic-gate 			if (req_value == 0) {
446*0Sstevel@tonic-gate 				reg_value = SYS_FAN_OFF;
447*0Sstevel@tonic-gate 				out_value = 0;
448*0Sstevel@tonic-gate 			} else if (req_value > 0) {
449*0Sstevel@tonic-gate 				reg_value = SYS_FAN_ON;
450*0Sstevel@tonic-gate 				out_value = 100;
451*0Sstevel@tonic-gate 			} else {
452*0Sstevel@tonic-gate 				ret = EINVAL;
453*0Sstevel@tonic-gate 			}
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 			if (ret != EINVAL) {
456*0Sstevel@tonic-gate 				*outputaddr = out_value;
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 				ddi_put8(unitp->sysfan_rhandle,
459*0Sstevel@tonic-gate 				    unitp->sysfan_reg,
460*0Sstevel@tonic-gate 				    reg_value);
461*0Sstevel@tonic-gate 				(void) ddi_get8(unitp->sysfan_rhandle,
462*0Sstevel@tonic-gate 				    unitp->sysfan_reg);
463*0Sstevel@tonic-gate 				if (grfans_debug) {
464*0Sstevel@tonic-gate 					printf("set SYSFAN output to %d at "
465*0Sstevel@tonic-gate 					    "addr %p\n", out_value,
466*0Sstevel@tonic-gate 					    unitp->sysfan_reg);
467*0Sstevel@tonic-gate 				}
468*0Sstevel@tonic-gate 			}
469*0Sstevel@tonic-gate 		}
470*0Sstevel@tonic-gate 	} else {
471*0Sstevel@tonic-gate 		ret = EFAULT;
472*0Sstevel@tonic-gate 	}
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	return (ret);
475*0Sstevel@tonic-gate }
476