xref: /illumos-gate/usr/src/uts/sun4u/io/epic.c (revision bd9d7d01f0d32a91d43d2004867fc442f5c3ef98)
1d58fda43Sjbeloro /*
2d58fda43Sjbeloro  * CDDL HEADER START
3d58fda43Sjbeloro  *
4d58fda43Sjbeloro  * The contents of this file are subject to the terms of the
5d58fda43Sjbeloro  * Common Development and Distribution License, Version 1.0 only
6d58fda43Sjbeloro  * (the "License").  You may not use this file except in compliance
7d58fda43Sjbeloro  * with the License.
8d58fda43Sjbeloro  *
9d58fda43Sjbeloro  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10d58fda43Sjbeloro  * or http://www.opensolaris.org/os/licensing.
11d58fda43Sjbeloro  * See the License for the specific language governing permissions
12d58fda43Sjbeloro  * and limitations under the License.
13d58fda43Sjbeloro  *
14d58fda43Sjbeloro  * When distributing Covered Code, include this CDDL HEADER in each
15d58fda43Sjbeloro  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16d58fda43Sjbeloro  * If applicable, add the following below this CDDL HEADER, with the
17d58fda43Sjbeloro  * fields enclosed by brackets "[]" replaced with your own identifying
18d58fda43Sjbeloro  * information: Portions Copyright [yyyy] [name of copyright owner]
19d58fda43Sjbeloro  *
20d58fda43Sjbeloro  * CDDL HEADER END
21d58fda43Sjbeloro  */
22d58fda43Sjbeloro 
23d58fda43Sjbeloro /*
24d58fda43Sjbeloro  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25d58fda43Sjbeloro  * Use is subject to license terms.
26d58fda43Sjbeloro  */
27d58fda43Sjbeloro 
28d58fda43Sjbeloro #pragma ident	"%Z%%M%	%I%	%E% SMI"
29d58fda43Sjbeloro 
30d58fda43Sjbeloro /*
31d58fda43Sjbeloro  * Driver to control Alert and Power LEDs  for the Seattle platform.
32d58fda43Sjbeloro  * Alert LED is also known as Service (required).
33d58fda43Sjbeloro  * Power LED is also known as Activity.
34d58fda43Sjbeloro  */
35d58fda43Sjbeloro #include <sys/types.h>
36d58fda43Sjbeloro #include <sys/time.h>
37d58fda43Sjbeloro #include <sys/errno.h>
38d58fda43Sjbeloro #include <sys/cmn_err.h>
39d58fda43Sjbeloro #include <sys/param.h>
40d58fda43Sjbeloro #include <sys/modctl.h>
41d58fda43Sjbeloro #include <sys/conf.h>
42d58fda43Sjbeloro #include <sys/open.h>
43d58fda43Sjbeloro #include <sys/stat.h>
44d58fda43Sjbeloro #include <sys/clock.h>
45d58fda43Sjbeloro #include <sys/ddi.h>
46d58fda43Sjbeloro #include <sys/sunddi.h>
47d58fda43Sjbeloro #include <sys/file.h>
48d58fda43Sjbeloro #include <sys/note.h>
49d58fda43Sjbeloro #include <sys/epic.h>
50d58fda43Sjbeloro 
51d58fda43Sjbeloro 
52d58fda43Sjbeloro /*
53d58fda43Sjbeloro  * Some #defs that must be here as they differ for power.c
54d58fda43Sjbeloro  * and epic.c
55d58fda43Sjbeloro  */
56d58fda43Sjbeloro #define	EPIC_REGS_OFFSET	0x00
57d58fda43Sjbeloro #define	EPIC_REGS_LEN		0x80
58d58fda43Sjbeloro 
59d58fda43Sjbeloro #define	EPIC_IND_DATA		0x40
60d58fda43Sjbeloro #define	EPIC_IND_ADDR		0x41
61d58fda43Sjbeloro #define	EPIC_WRITE_MASK		0x80
62d58fda43Sjbeloro 
63d58fda43Sjbeloro /* dev_ops and cb_ops entry point function declarations */
64d58fda43Sjbeloro static int	epic_attach(dev_info_t *, ddi_attach_cmd_t);
65d58fda43Sjbeloro static int	epic_detach(dev_info_t *, ddi_detach_cmd_t);
66d58fda43Sjbeloro static int	epic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
67d58fda43Sjbeloro static int	epic_open(dev_t *, int, int, cred_t *);
68d58fda43Sjbeloro static int	epic_close(dev_t, int, int, cred_t *);
69d58fda43Sjbeloro static int	epic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
70d58fda43Sjbeloro 
71d58fda43Sjbeloro struct cb_ops epic_cb_ops = {
72d58fda43Sjbeloro 	epic_open,		/* open */
73d58fda43Sjbeloro 	epic_close,		/* close */
74d58fda43Sjbeloro 	nodev,			/* strategy */
75d58fda43Sjbeloro 	nodev,			/* print */
76d58fda43Sjbeloro 	nodev,			/* dump */
77d58fda43Sjbeloro 	nodev,			/* read */
78d58fda43Sjbeloro 	nodev,			/* write */
79d58fda43Sjbeloro 	epic_ioctl,		/* ioctl */
80d58fda43Sjbeloro 	nodev,			/* devmap */
81d58fda43Sjbeloro 	nodev,			/* mmap */
82d58fda43Sjbeloro 	ddi_segmap,		/* segmap */
83d58fda43Sjbeloro 	nochpoll,		/* poll */
84d58fda43Sjbeloro 	ddi_prop_op,		/* cb_prop_op */
85d58fda43Sjbeloro 	NULL,			/* streamtab - for STREAMS drivers */
86d58fda43Sjbeloro 	D_NEW | D_MP		/* driver compatibility flag */
87d58fda43Sjbeloro };
88d58fda43Sjbeloro 
89d58fda43Sjbeloro static struct dev_ops epic_dev_ops = {
90d58fda43Sjbeloro 	DEVO_REV,		/* driver build version */
91d58fda43Sjbeloro 	0,			/* device reference count */
92d58fda43Sjbeloro 	epic_getinfo,
93d58fda43Sjbeloro 	nulldev,
94d58fda43Sjbeloro 	nulldev,		/* probe */
95d58fda43Sjbeloro 	epic_attach,
96d58fda43Sjbeloro 	epic_detach,
97d58fda43Sjbeloro 	nulldev,		/* reset */
98d58fda43Sjbeloro 	&epic_cb_ops,
99d58fda43Sjbeloro 	(struct bus_ops *)NULL,
100d58fda43Sjbeloro 	nulldev			/* power */
101d58fda43Sjbeloro };
102d58fda43Sjbeloro 
103d58fda43Sjbeloro 
104d58fda43Sjbeloro /*
105d58fda43Sjbeloro  * Soft state
106d58fda43Sjbeloro  */
107d58fda43Sjbeloro struct epic_softc {
108d58fda43Sjbeloro 	dev_info_t	*dip;
109d58fda43Sjbeloro 	kmutex_t	mutex;
110d58fda43Sjbeloro 	uint8_t		*cmd_reg;
111d58fda43Sjbeloro 	ddi_acc_handle_t cmd_handle;
112d58fda43Sjbeloro };
113d58fda43Sjbeloro 
114d58fda43Sjbeloro #define	getsoftc(inst)	((struct epic_softc *)ddi_get_soft_state(statep, \
115d58fda43Sjbeloro (inst)))
116d58fda43Sjbeloro 
117d58fda43Sjbeloro /* module configuration stuff */
118d58fda43Sjbeloro static void    *statep;
119d58fda43Sjbeloro extern struct mod_ops mod_driverops;
120d58fda43Sjbeloro 
121d58fda43Sjbeloro static struct modldrv modldrv = {
122d58fda43Sjbeloro 	&mod_driverops,
123d58fda43Sjbeloro 	"epic_client driver v%I%",
124d58fda43Sjbeloro 	&epic_dev_ops
125d58fda43Sjbeloro };
126d58fda43Sjbeloro 
127d58fda43Sjbeloro static struct modlinkage modlinkage = {
128d58fda43Sjbeloro 	MODREV_1,
129d58fda43Sjbeloro 	&modldrv,
130d58fda43Sjbeloro 	0
131d58fda43Sjbeloro };
132d58fda43Sjbeloro 
133d58fda43Sjbeloro int
134d58fda43Sjbeloro _init(void)
135d58fda43Sjbeloro {
136d58fda43Sjbeloro 	int e;
137d58fda43Sjbeloro 
138d58fda43Sjbeloro 	if ((e = ddi_soft_state_init(&statep,
139d58fda43Sjbeloro 		sizeof (struct epic_softc), 0)) != 0) {
140d58fda43Sjbeloro 		return (e);
141d58fda43Sjbeloro 	}
142d58fda43Sjbeloro 
143d58fda43Sjbeloro 	if ((e = mod_install(&modlinkage)) != 0)
144d58fda43Sjbeloro 		ddi_soft_state_fini(&statep);
145d58fda43Sjbeloro 
146d58fda43Sjbeloro 	return (e);
147d58fda43Sjbeloro }
148d58fda43Sjbeloro 
149d58fda43Sjbeloro int
150d58fda43Sjbeloro _fini(void)
151d58fda43Sjbeloro {
152d58fda43Sjbeloro 	int e;
153d58fda43Sjbeloro 
154d58fda43Sjbeloro 	if ((e = mod_remove(&modlinkage)) != 0)
155d58fda43Sjbeloro 		return (e);
156d58fda43Sjbeloro 
157d58fda43Sjbeloro 	ddi_soft_state_fini(&statep);
158d58fda43Sjbeloro 
159d58fda43Sjbeloro 	return (DDI_SUCCESS);
160d58fda43Sjbeloro }
161d58fda43Sjbeloro 
162d58fda43Sjbeloro int
163d58fda43Sjbeloro _info(struct modinfo *modinfop)
164d58fda43Sjbeloro {
165d58fda43Sjbeloro 	return (mod_info(&modlinkage, modinfop));
166d58fda43Sjbeloro }
167d58fda43Sjbeloro 
168d58fda43Sjbeloro /*ARGSUSED*/
169d58fda43Sjbeloro static int
170d58fda43Sjbeloro epic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
171d58fda43Sjbeloro {
172d58fda43Sjbeloro 	int	inst;
173d58fda43Sjbeloro 	int	retval = DDI_SUCCESS;
174d58fda43Sjbeloro 	struct epic_softc *softc;
175d58fda43Sjbeloro 
176d58fda43Sjbeloro 	inst = (getminor((dev_t)arg));
177d58fda43Sjbeloro 
178d58fda43Sjbeloro 	switch (cmd) {
179d58fda43Sjbeloro 	case DDI_INFO_DEVT2DEVINFO:
180d58fda43Sjbeloro 		if ((softc = getsoftc(inst)) == NULL) {
181d58fda43Sjbeloro 			*result = (void *)NULL;
182d58fda43Sjbeloro 			retval = DDI_FAILURE;
183d58fda43Sjbeloro 		} else
184d58fda43Sjbeloro 			*result = (void *)softc->dip;
185d58fda43Sjbeloro 		break;
186d58fda43Sjbeloro 
187d58fda43Sjbeloro 	case DDI_INFO_DEVT2INSTANCE:
188*bd9d7d01Sanovick 		*result = (void *)(uintptr_t)inst;
189d58fda43Sjbeloro 		break;
190d58fda43Sjbeloro 
191d58fda43Sjbeloro 	default:
192d58fda43Sjbeloro 		retval = DDI_FAILURE;
193d58fda43Sjbeloro 	}
194d58fda43Sjbeloro 
195d58fda43Sjbeloro 	return (retval);
196d58fda43Sjbeloro }
197d58fda43Sjbeloro 
198d58fda43Sjbeloro static int
199d58fda43Sjbeloro epic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
200d58fda43Sjbeloro {
201d58fda43Sjbeloro 	int inst;
202d58fda43Sjbeloro 	struct epic_softc *softc = NULL;
203d58fda43Sjbeloro 	int minor;
204d58fda43Sjbeloro 	char name[MAXNAMELEN];
205d58fda43Sjbeloro 	ddi_device_acc_attr_t dev_attr;
206d58fda43Sjbeloro 	int res;
207d58fda43Sjbeloro 
208d58fda43Sjbeloro 	switch (cmd) {
209d58fda43Sjbeloro 	case DDI_ATTACH:
210d58fda43Sjbeloro 		inst = ddi_get_instance(dip);
211d58fda43Sjbeloro 		(void) sprintf(name, "env-monitor%d", inst);
212d58fda43Sjbeloro 		minor = inst;
213d58fda43Sjbeloro 		if (ddi_create_minor_node(dip, name, S_IFCHR, minor,
214d58fda43Sjbeloro 		    DDI_PSEUDO, NULL) == DDI_FAILURE) {
215d58fda43Sjbeloro 			cmn_err(CE_WARN,
216d58fda43Sjbeloro 			    "ddi_create_minor_node() failed for inst %d\n",
217d58fda43Sjbeloro 			    inst);
218d58fda43Sjbeloro 			return (DDI_FAILURE);
219d58fda43Sjbeloro 		}
220d58fda43Sjbeloro 
221d58fda43Sjbeloro 		/* Allocate a soft state structure for this instance */
222d58fda43Sjbeloro 		if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS) {
223d58fda43Sjbeloro 			cmn_err(CE_WARN, " ddi_soft_state_zalloc() failed "
224d58fda43Sjbeloro 			    "for inst %d\n", inst);
225d58fda43Sjbeloro 			break;
226d58fda43Sjbeloro 		}
227d58fda43Sjbeloro 
228d58fda43Sjbeloro 		/* Setup soft state */
229d58fda43Sjbeloro 		if ((softc = getsoftc(inst)) == NULL) {
230d58fda43Sjbeloro 			break;
231d58fda43Sjbeloro 		}
232d58fda43Sjbeloro 		softc->dip = dip;
233d58fda43Sjbeloro 		mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL);
234d58fda43Sjbeloro 
235d58fda43Sjbeloro 		/* Setup device attributes */
236d58fda43Sjbeloro 		dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
237d58fda43Sjbeloro 		dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
238d58fda43Sjbeloro 		dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
239d58fda43Sjbeloro 
240d58fda43Sjbeloro 		res = ddi_regs_map_setup(dip, 0, (caddr_t *)&softc->cmd_reg,
241d58fda43Sjbeloro 			EPIC_REGS_OFFSET, EPIC_REGS_LEN, &dev_attr,
242d58fda43Sjbeloro 			&softc->cmd_handle);
243d58fda43Sjbeloro 
244d58fda43Sjbeloro 		if (res != DDI_SUCCESS) {
245d58fda43Sjbeloro 			cmn_err(CE_WARN, "ddi_regs_map_setup() failed\n");
246d58fda43Sjbeloro 			break;
247d58fda43Sjbeloro 		}
248d58fda43Sjbeloro 
249d58fda43Sjbeloro 		ddi_report_dev(dip);
250d58fda43Sjbeloro 
251d58fda43Sjbeloro 
252d58fda43Sjbeloro 		return (DDI_SUCCESS);
253d58fda43Sjbeloro 
254d58fda43Sjbeloro 	case DDI_RESUME:
255d58fda43Sjbeloro 		return (DDI_SUCCESS);
256d58fda43Sjbeloro 
257d58fda43Sjbeloro 	default:
258d58fda43Sjbeloro 		return (DDI_FAILURE);
259d58fda43Sjbeloro 	}
260d58fda43Sjbeloro 
261d58fda43Sjbeloro 	/* Attach failed */
262d58fda43Sjbeloro 	/* Free soft state, if allocated. remove minor node if added earlier */
263d58fda43Sjbeloro 	if (softc)
264d58fda43Sjbeloro 		ddi_soft_state_free(statep, inst);
265d58fda43Sjbeloro 
266d58fda43Sjbeloro 	ddi_remove_minor_node(dip, NULL);
267d58fda43Sjbeloro 
268d58fda43Sjbeloro 	return (DDI_FAILURE);
269d58fda43Sjbeloro }
270d58fda43Sjbeloro 
271d58fda43Sjbeloro static int
272d58fda43Sjbeloro epic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
273d58fda43Sjbeloro {
274d58fda43Sjbeloro 	int inst;
275d58fda43Sjbeloro 	struct epic_softc *softc;
276d58fda43Sjbeloro 
277d58fda43Sjbeloro 	switch (cmd) {
278d58fda43Sjbeloro 	case DDI_DETACH:
279d58fda43Sjbeloro 		inst = ddi_get_instance(dip);
280d58fda43Sjbeloro 		if ((softc = getsoftc(inst)) == NULL)
281d58fda43Sjbeloro 			return (ENXIO);
282d58fda43Sjbeloro 
283d58fda43Sjbeloro 		(void) ddi_regs_map_free(&softc->cmd_handle);
284d58fda43Sjbeloro 
285d58fda43Sjbeloro 
286d58fda43Sjbeloro 		/* Free the soft state and remove minor node added earlier */
287d58fda43Sjbeloro 		mutex_destroy(&softc->mutex);
288d58fda43Sjbeloro 		ddi_soft_state_free(statep, inst);
289d58fda43Sjbeloro 		ddi_remove_minor_node(dip, NULL);
290d58fda43Sjbeloro 		return (DDI_SUCCESS);
291d58fda43Sjbeloro 
292d58fda43Sjbeloro 	case DDI_SUSPEND:
293d58fda43Sjbeloro 		return (DDI_SUCCESS);
294d58fda43Sjbeloro 
295d58fda43Sjbeloro 	default:
296d58fda43Sjbeloro 		return (DDI_FAILURE);
297d58fda43Sjbeloro 	}
298d58fda43Sjbeloro }
299d58fda43Sjbeloro 
300d58fda43Sjbeloro /*ARGSUSED*/
301d58fda43Sjbeloro static int
302d58fda43Sjbeloro epic_open(dev_t *devp, int flag, int otyp, cred_t *credp)
303d58fda43Sjbeloro {
304d58fda43Sjbeloro 	_NOTE(ARGUNUSED(flag))
305d58fda43Sjbeloro 	_NOTE(ARGUNUSED(otyp))
306d58fda43Sjbeloro 	_NOTE(ARGUNUSED(credp))
307d58fda43Sjbeloro 
308d58fda43Sjbeloro 	int	inst = getminor(*devp);
309d58fda43Sjbeloro 
310d58fda43Sjbeloro 	return (getsoftc(inst) == NULL ? ENXIO : 0);
311d58fda43Sjbeloro }
312d58fda43Sjbeloro 
313d58fda43Sjbeloro /*ARGSUSED*/
314d58fda43Sjbeloro static int
315d58fda43Sjbeloro epic_close(dev_t dev, int flag, int otyp, cred_t *credp)
316d58fda43Sjbeloro {
317d58fda43Sjbeloro 	_NOTE(ARGUNUSED(flag))
318d58fda43Sjbeloro 	_NOTE(ARGUNUSED(otyp))
319d58fda43Sjbeloro 	_NOTE(ARGUNUSED(credp))
320d58fda43Sjbeloro 
321d58fda43Sjbeloro 	int	inst = getminor(dev);
322d58fda43Sjbeloro 
323d58fda43Sjbeloro 	return (getsoftc(inst) == NULL ? ENXIO : 0);
324d58fda43Sjbeloro }
325d58fda43Sjbeloro 
326d58fda43Sjbeloro /*ARGSUSED*/
327d58fda43Sjbeloro static int
328d58fda43Sjbeloro epic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
329d58fda43Sjbeloro int *rvalp)
330d58fda43Sjbeloro {
331d58fda43Sjbeloro 	_NOTE(ARGUNUSED(credp))
332d58fda43Sjbeloro 
333d58fda43Sjbeloro 	int	inst;
334d58fda43Sjbeloro 	struct epic_softc *softc;
335d58fda43Sjbeloro 	uint8_t	in_command;
336d58fda43Sjbeloro 
337d58fda43Sjbeloro 	inst = getminor(dev);
338d58fda43Sjbeloro 	if ((softc = getsoftc(inst)) == NULL)
339d58fda43Sjbeloro 		return (ENXIO);
340d58fda43Sjbeloro 
341d58fda43Sjbeloro 	mutex_enter(&softc->mutex);
342d58fda43Sjbeloro 
343d58fda43Sjbeloro 	switch (cmd) {
344d58fda43Sjbeloro 	case EPIC_SET_POWER_LED:
345d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
346d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
347d58fda43Sjbeloro 			EPIC_POWER_LED_ON);
348d58fda43Sjbeloro 	    break;
349d58fda43Sjbeloro 	case EPIC_RESET_POWER_LED:
350d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
351d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
352d58fda43Sjbeloro 			EPIC_POWER_LED_OFF);
353d58fda43Sjbeloro 	    break;
354d58fda43Sjbeloro 	case EPIC_SB_BL_POWER_LED:
355d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
356d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
357d58fda43Sjbeloro 			EPIC_POWER_LED_SB_BLINK);
358d58fda43Sjbeloro 	    break;
359d58fda43Sjbeloro 	case EPIC_FAST_BL_POWER_LED:
360d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
361d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
362d58fda43Sjbeloro 			EPIC_POWER_LED_FAST_BLINK);
363d58fda43Sjbeloro 	    break;
364d58fda43Sjbeloro 	case EPIC_SET_ALERT_LED:
365d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
366d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_ALERT_LED_MASK,
367d58fda43Sjbeloro 			EPIC_ALERT_LED_ON);
368d58fda43Sjbeloro 	    break;
369d58fda43Sjbeloro 	case EPIC_RESET_ALERT_LED:
370d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
371d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_ALERT_LED_MASK,
372d58fda43Sjbeloro 			EPIC_ALERT_LED_OFF);
373d58fda43Sjbeloro 	    break;
374d58fda43Sjbeloro 	case EPIC_GET_FW:
375d58fda43Sjbeloro 	    EPIC_READ(softc->cmd_handle, softc->cmd_reg,
376d58fda43Sjbeloro 			in_command, EPIC_IND_FW_VERSION);
377d58fda43Sjbeloro 	    if (ddi_copyout((void *)(&in_command), (void *)arg,
378d58fda43Sjbeloro 			sizeof (in_command), mode) != DDI_SUCCESS) {
379d58fda43Sjbeloro 		    mutex_exit(&softc->mutex);
380d58fda43Sjbeloro 		    return (EFAULT);
381d58fda43Sjbeloro 	    }
382d58fda43Sjbeloro 	    break;
383d58fda43Sjbeloro 	default:
384d58fda43Sjbeloro 		mutex_exit(&softc->mutex);
385d58fda43Sjbeloro 		cmn_err(CE_WARN, "epic: cmd %d is not valid", cmd);
386d58fda43Sjbeloro 		return (EINVAL);
387d58fda43Sjbeloro 	}
388d58fda43Sjbeloro 
389d58fda43Sjbeloro 	mutex_exit(&softc->mutex);
390d58fda43Sjbeloro 	return (0);
391d58fda43Sjbeloro }
392