urio.c revision 185087
1216829Syongari/*-
2216829Syongari * Copyright (c) 2000 Iwasa Kazmi
3216829Syongari * All rights reserved.
4216829Syongari *
5216829Syongari * Redistribution and use in source and binary forms, with or without
6216829Syongari * modification, are permitted provided that the following conditions
7216829Syongari * are met:
8216829Syongari * 1. Redistributions of source code must retain the above copyright
9216829Syongari *    notice, this list of conditions, and the following disclaimer.
10216829Syongari * 2. Redistributions in binary form must reproduce the above copyright
11216829Syongari *    notice, this list of conditions and the following disclaimer in the
12216829Syongari *    documentation and/or other materials provided with the distribution.
13216829Syongari *
14216829Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15216829Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16216829Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17216829Syongari * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18216829Syongari * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19216829Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20216829Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21216829Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22216829Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23216829Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24216829Syongari * SUCH DAMAGE.
25216829Syongari *
26216829Syongari * This code is based on ugen.c and ulpt.c developed by Lennart Augustsson.
27216829Syongari * This code includes software developed by the NetBSD Foundation, Inc. and
28216829Syongari * its contributors.
29216829Syongari */
30216829Syongari
31216829Syongari#include <sys/cdefs.h>
32216829Syongari__FBSDID("$FreeBSD: head/sys/dev/usb2/storage/urio2.c 185087 2008-11-19 08:56:35Z alfred $");
33216829Syongari
34216829Syongari
35216829Syongari/*
36216829Syongari * 2000/3/24  added NetBSD/OpenBSD support (from Alex Nemirovsky)
37216829Syongari * 2000/3/07  use two bulk-pipe handles for read and write (Dirk)
38216829Syongari * 2000/3/06  change major number(143), and copyright header
39216829Syongari *            some fix for 4.0 (Dirk)
40216829Syongari * 2000/3/05  codes for FreeBSD 4.x - CURRENT (Thanks to Dirk-Willem van Gulik)
41216829Syongari * 2000/3/01  remove retry code from urioioctl()
42216829Syongari *            change method of bulk transfer (no interrupt)
43216829Syongari * 2000/2/28  small fixes for new rio_usb.h
44216829Syongari * 2000/2/24  first version.
45216829Syongari */
46216829Syongari
47216829Syongari#include <dev/usb2/include/usb2_devid.h>
48216829Syongari#include <dev/usb2/include/usb2_standard.h>
49216829Syongari#include <dev/usb2/include/usb2_mfunc.h>
50216829Syongari#include <dev/usb2/include/usb2_error.h>
51216829Syongari#include <dev/usb2/include/usb2_ioctl.h>
52216829Syongari#include <dev/usb/rio500_usb.h>
53216829Syongari
54216829Syongari#define	USB_DEBUG_VAR urio_debug
55216829Syongari
56216829Syongari#include <dev/usb2/core/usb2_core.h>
57216829Syongari#include <dev/usb2/core/usb2_debug.h>
58216829Syongari#include <dev/usb2/core/usb2_process.h>
59216829Syongari#include <dev/usb2/core/usb2_config_td.h>
60216829Syongari#include <dev/usb2/core/usb2_request.h>
61216829Syongari#include <dev/usb2/core/usb2_lookup.h>
62216829Syongari#include <dev/usb2/core/usb2_util.h>
63216829Syongari#include <dev/usb2/core/usb2_busdma.h>
64216829Syongari#include <dev/usb2/core/usb2_mbuf.h>
65216829Syongari#include <dev/usb2/core/usb2_dev.h>
66216829Syongari#include <dev/usb2/core/usb2_generic.h>
67216829Syongari
68216829Syongari#if USB_DEBUG
69216829Syongaristatic int urio_debug = 0;
70216829Syongari
71216829SyongariSYSCTL_NODE(_hw_usb2, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio");
72216829SyongariSYSCTL_INT(_hw_usb2_urio, OID_AUTO, debug, CTLFLAG_RW,
73216829Syongari    &urio_debug, 0, "urio debug level");
74216829Syongari#endif
75216829Syongari
76216829Syongari#define	URIO_T_WR     0
77216829Syongari#define	URIO_T_RD     1
78216829Syongari#define	URIO_T_WR_CS  2
79216829Syongari#define	URIO_T_RD_CS  3
80216829Syongari#define	URIO_T_MAX    4
81216829Syongari
82216829Syongari#define	URIO_BSIZE	(1<<12)		/* bytes */
83216829Syongari#define	URIO_IFQ_MAXLEN      2		/* units */
84216829Syongari
85216829Syongaristruct urio_softc {
86216829Syongari	struct usb2_fifo_sc sc_fifo;
87216829Syongari	struct mtx sc_mtx;
88216829Syongari
89216829Syongari	struct usb2_device *sc_udev;
90216829Syongari	struct usb2_xfer *sc_xfer[URIO_T_MAX];
91216829Syongari
92216829Syongari	uint8_t	sc_flags;
93216829Syongari#define	URIO_FLAG_READ_STALL    0x01	/* read transfer stalled */
94216829Syongari#define	URIO_FLAG_WRITE_STALL   0x02	/* write transfer stalled */
95216829Syongari
96216829Syongari	uint8_t	sc_name[16];
97216829Syongari};
98216829Syongari
99216829Syongari/* prototypes */
100216829Syongari
101216829Syongaristatic device_probe_t urio_probe;
102216829Syongaristatic device_attach_t urio_attach;
103216829Syongaristatic device_detach_t urio_detach;
104216829Syongari
105216829Syongaristatic usb2_callback_t urio_write_callback;
106216829Syongaristatic usb2_callback_t urio_write_clear_stall_callback;
107216829Syongaristatic usb2_callback_t urio_read_callback;
108216829Syongaristatic usb2_callback_t urio_read_clear_stall_callback;
109216829Syongari
110216829Syongaristatic usb2_fifo_close_t urio_close;
111216829Syongaristatic usb2_fifo_cmd_t urio_start_read;
112216829Syongaristatic usb2_fifo_cmd_t urio_start_write;
113216829Syongaristatic usb2_fifo_cmd_t urio_stop_read;
114216829Syongaristatic usb2_fifo_cmd_t urio_stop_write;
115216829Syongaristatic usb2_fifo_ioctl_t urio_ioctl;
116216829Syongaristatic usb2_fifo_open_t urio_open;
117216829Syongari
118216829Syongaristatic struct usb2_fifo_methods urio_fifo_methods = {
119216829Syongari	.f_close = &urio_close,
120216829Syongari	.f_ioctl = &urio_ioctl,
121216829Syongari	.f_open = &urio_open,
122216829Syongari	.f_start_read = &urio_start_read,
123216829Syongari	.f_start_write = &urio_start_write,
124216829Syongari	.f_stop_read = &urio_stop_read,
125216829Syongari	.f_stop_write = &urio_stop_write,
126216829Syongari	.basename[0] = "urio",
127216829Syongari};
128216829Syongari
129216829Syongaristatic const struct usb2_config urio_config[URIO_T_MAX] = {
130216829Syongari	[URIO_T_WR] = {
131216829Syongari		.type = UE_BULK,
132216829Syongari		.endpoint = UE_ADDR_ANY,
133216829Syongari		.direction = UE_DIR_OUT,
134216829Syongari		.mh.bufsize = URIO_BSIZE,
135216829Syongari		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,.proxy_buffer = 1,},
136216829Syongari		.mh.callback = &urio_write_callback,
137216829Syongari	},
138216829Syongari
139216829Syongari	[URIO_T_RD] = {
140216829Syongari		.type = UE_BULK,
141216829Syongari		.endpoint = UE_ADDR_ANY,
142216829Syongari		.direction = UE_DIR_IN,
143216829Syongari		.mh.bufsize = URIO_BSIZE,
144216829Syongari		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,},
145216829Syongari		.mh.callback = &urio_read_callback,
146216829Syongari	},
147216829Syongari
148216829Syongari	[URIO_T_WR_CS] = {
149216829Syongari		.type = UE_CONTROL,
150216829Syongari		.endpoint = 0x00,	/* Control pipe */
151216829Syongari		.direction = UE_DIR_ANY,
152216829Syongari		.mh.bufsize = sizeof(struct usb2_device_request),
153216829Syongari		.mh.flags = {},
154216829Syongari		.mh.callback = &urio_write_clear_stall_callback,
155216829Syongari		.mh.timeout = 1000,	/* 1 second */
156216829Syongari		.mh.interval = 50,	/* 50ms */
157216829Syongari	},
158216829Syongari
159216829Syongari	[URIO_T_RD_CS] = {
160216829Syongari		.type = UE_CONTROL,
161216829Syongari		.endpoint = 0x00,	/* Control pipe */
162216829Syongari		.direction = UE_DIR_ANY,
163216829Syongari		.mh.bufsize = sizeof(struct usb2_device_request),
164216829Syongari		.mh.flags = {},
165216829Syongari		.mh.callback = &urio_read_clear_stall_callback,
166216829Syongari		.mh.timeout = 1000,	/* 1 second */
167216829Syongari		.mh.interval = 50,	/* 50ms */
168216829Syongari	},
169216829Syongari};
170216829Syongari
171216829Syongaristatic devclass_t urio_devclass;
172216829Syongari
173216829Syongaristatic device_method_t urio_methods[] = {
174216829Syongari	/* Device interface */
175216829Syongari	DEVMETHOD(device_probe, urio_probe),
176216829Syongari	DEVMETHOD(device_attach, urio_attach),
177216829Syongari	DEVMETHOD(device_detach, urio_detach),
178216829Syongari	{0, 0}
179216829Syongari};
180216829Syongari
181216829Syongaristatic driver_t urio_driver = {
182216829Syongari	.name = "urio",
183216829Syongari	.methods = urio_methods,
184216829Syongari	.size = sizeof(struct urio_softc),
185216829Syongari};
186216829Syongari
187216829SyongariDRIVER_MODULE(urio, ushub, urio_driver, urio_devclass, NULL, 0);
188216829SyongariMODULE_DEPEND(urio, usb2_storage, 1, 1, 1);
189216829SyongariMODULE_DEPEND(urio, usb2_core, 1, 1, 1);
190216829Syongari
191216829Syongaristatic int
192216829Syongariurio_probe(device_t dev)
193216829Syongari{
194216829Syongari	struct usb2_attach_arg *uaa = device_get_ivars(dev);
195216829Syongari
196216829Syongari	if (uaa->usb2_mode != USB_MODE_HOST) {
197216829Syongari		return (ENXIO);
198216829Syongari	}
199216829Syongari	if ((((uaa->info.idVendor == USB_VENDOR_DIAMOND) &&
200216829Syongari	    (uaa->info.idProduct == USB_PRODUCT_DIAMOND_RIO500USB)) ||
201216829Syongari	    ((uaa->info.idVendor == USB_VENDOR_DIAMOND2) &&
202216829Syongari	    ((uaa->info.idProduct == USB_PRODUCT_DIAMOND2_RIO600USB) ||
203216829Syongari	    (uaa->info.idProduct == USB_PRODUCT_DIAMOND2_RIO800USB)))))
204216829Syongari		return (0);
205216829Syongari	else
206216829Syongari		return (ENXIO);
207216829Syongari}
208216829Syongari
209216829Syongaristatic int
210216829Syongariurio_attach(device_t dev)
211216829Syongari{
212216829Syongari	struct usb2_attach_arg *uaa = device_get_ivars(dev);
213216829Syongari	struct urio_softc *sc = device_get_softc(dev);
214216829Syongari	int error;
215216829Syongari
216216829Syongari	if (sc == NULL) {
217216829Syongari		return (ENOMEM);
218216829Syongari	}
219216829Syongari	device_set_usb2_desc(dev);
220216829Syongari
221216829Syongari	sc->sc_udev = uaa->device;
222216829Syongari
223216829Syongari	mtx_init(&sc->sc_mtx, "urio lock", NULL, MTX_DEF | MTX_RECURSE);
224216829Syongari
225216829Syongari	snprintf(sc->sc_name, sizeof(sc->sc_name),
226216829Syongari	    "%s", device_get_nameunit(dev));
227216829Syongari
228216829Syongari	error = usb2_transfer_setup(uaa->device,
229216829Syongari	    &uaa->info.bIfaceIndex, sc->sc_xfer,
230216829Syongari	    urio_config, URIO_T_MAX, sc, &sc->sc_mtx);
231216829Syongari
232216829Syongari	if (error) {
233216829Syongari		DPRINTF("error=%s\n", usb2_errstr(error));
234216829Syongari		goto detach;
235216829Syongari	}
236216829Syongari	/* set interface permissions */
237216829Syongari	usb2_set_iface_perm(uaa->device, uaa->info.bIfaceIndex,
238216829Syongari	    UID_ROOT, GID_OPERATOR, 0644);
239216829Syongari
240216829Syongari	error = usb2_fifo_attach(uaa->device, sc, &sc->sc_mtx,
241216829Syongari	    &urio_fifo_methods, &sc->sc_fifo,
242216829Syongari	    device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex);
243216829Syongari	if (error) {
244216829Syongari		goto detach;
245216829Syongari	}
246216829Syongari	return (0);			/* success */
247216829Syongari
248216829Syongaridetach:
249216829Syongari	urio_detach(dev);
250216829Syongari	return (ENOMEM);		/* failure */
251216829Syongari}
252216829Syongari
253216829Syongaristatic void
254216829Syongariurio_write_callback(struct usb2_xfer *xfer)
255216829Syongari{
256216829Syongari	struct urio_softc *sc = xfer->priv_sc;
257216829Syongari	struct usb2_fifo *f = sc->sc_fifo.fp[USB_FIFO_TX];
258216829Syongari	uint32_t actlen;
259216829Syongari
260216829Syongari	switch (USB_GET_STATE(xfer)) {
261216829Syongari	case USB_ST_TRANSFERRED:
262216829Syongari	case USB_ST_SETUP:
263216829Syongari		if (sc->sc_flags & URIO_FLAG_WRITE_STALL) {
264216829Syongari			usb2_transfer_start(sc->sc_xfer[URIO_T_WR_CS]);
265216829Syongari			return;
266216829Syongari		}
267216829Syongari		if (usb2_fifo_get_data(f, xfer->frbuffers, 0,
268216829Syongari		    xfer->max_data_length, &actlen, 0)) {
269216829Syongari
270216829Syongari			xfer->frlengths[0] = actlen;
271216829Syongari			usb2_start_hardware(xfer);
272216829Syongari		}
273216829Syongari		return;
274216829Syongari
275216829Syongari	default:			/* Error */
276216829Syongari		if (xfer->error != USB_ERR_CANCELLED) {
277216829Syongari			/* try to clear stall first */
278216829Syongari			sc->sc_flags |= URIO_FLAG_WRITE_STALL;
279216829Syongari			usb2_transfer_start(sc->sc_xfer[URIO_T_WR_CS]);
280216829Syongari		}
281216829Syongari		return;
282216829Syongari	}
283216829Syongari}
284216829Syongari
285216829Syongaristatic void
286216829Syongariurio_write_clear_stall_callback(struct usb2_xfer *xfer)
287216829Syongari{
288216829Syongari	struct urio_softc *sc = xfer->priv_sc;
289216829Syongari	struct usb2_xfer *xfer_other = sc->sc_xfer[URIO_T_WR];
290216829Syongari
291216829Syongari	if (usb2_clear_stall_callback(xfer, xfer_other)) {
292216829Syongari		DPRINTF("stall cleared\n");
293216829Syongari		sc->sc_flags &= ~URIO_FLAG_WRITE_STALL;
294216829Syongari		usb2_transfer_start(xfer_other);
295216829Syongari	}
296216829Syongari	return;
297216829Syongari}
298216829Syongari
299216829Syongaristatic void
300216829Syongariurio_read_callback(struct usb2_xfer *xfer)
301216829Syongari{
302216829Syongari	struct urio_softc *sc = xfer->priv_sc;
303216829Syongari	struct usb2_fifo *f = sc->sc_fifo.fp[USB_FIFO_RX];
304216829Syongari
305216829Syongari	switch (USB_GET_STATE(xfer)) {
306216829Syongari	case USB_ST_TRANSFERRED:
307216829Syongari		usb2_fifo_put_data(f, xfer->frbuffers, 0,
308216829Syongari		    xfer->actlen, 1);
309216829Syongari
310216829Syongari	case USB_ST_SETUP:
311216829Syongari		if (sc->sc_flags & URIO_FLAG_READ_STALL) {
312216829Syongari			usb2_transfer_start(sc->sc_xfer[URIO_T_RD_CS]);
313216829Syongari			return;
314216829Syongari		}
315216829Syongari		if (usb2_fifo_put_bytes_max(f) != 0) {
316216829Syongari			xfer->frlengths[0] = xfer->max_data_length;
317216829Syongari			usb2_start_hardware(xfer);
318216829Syongari		}
319216829Syongari		return;
320216829Syongari
321216829Syongari	default:			/* Error */
322216829Syongari		if (xfer->error != USB_ERR_CANCELLED) {
323216829Syongari			/* try to clear stall first */
324216829Syongari			sc->sc_flags |= URIO_FLAG_READ_STALL;
325216829Syongari			usb2_transfer_start(sc->sc_xfer[URIO_T_RD_CS]);
326216829Syongari		}
327216829Syongari		return;
328216829Syongari	}
329216829Syongari}
330216829Syongari
331216829Syongaristatic void
332216829Syongariurio_read_clear_stall_callback(struct usb2_xfer *xfer)
333216829Syongari{
334216829Syongari	struct urio_softc *sc = xfer->priv_sc;
335216829Syongari	struct usb2_xfer *xfer_other = sc->sc_xfer[URIO_T_RD];
336216829Syongari
337216829Syongari	if (usb2_clear_stall_callback(xfer, xfer_other)) {
338216829Syongari		DPRINTF("stall cleared\n");
339216829Syongari		sc->sc_flags &= ~URIO_FLAG_READ_STALL;
340216829Syongari		usb2_transfer_start(xfer_other);
341216829Syongari	}
342216829Syongari	return;
343216829Syongari}
344216829Syongari
345216829Syongaristatic void
346216829Syongariurio_start_read(struct usb2_fifo *fifo)
347216829Syongari{
348216829Syongari	struct urio_softc *sc = fifo->priv_sc0;
349216829Syongari
350216829Syongari	usb2_transfer_start(sc->sc_xfer[URIO_T_RD]);
351216829Syongari	return;
352216829Syongari}
353216829Syongari
354216829Syongaristatic void
355216829Syongariurio_stop_read(struct usb2_fifo *fifo)
356216829Syongari{
357216829Syongari	struct urio_softc *sc = fifo->priv_sc0;
358216829Syongari
359216829Syongari	usb2_transfer_stop(sc->sc_xfer[URIO_T_RD_CS]);
360216829Syongari	usb2_transfer_stop(sc->sc_xfer[URIO_T_RD]);
361216829Syongari	return;
362216829Syongari}
363216829Syongari
364216829Syongaristatic void
365216829Syongariurio_start_write(struct usb2_fifo *fifo)
366216829Syongari{
367216829Syongari	struct urio_softc *sc = fifo->priv_sc0;
368216829Syongari
369216829Syongari	usb2_transfer_start(sc->sc_xfer[URIO_T_WR]);
370216829Syongari	return;
371216829Syongari}
372216829Syongari
373216829Syongaristatic void
374216829Syongariurio_stop_write(struct usb2_fifo *fifo)
375216829Syongari{
376216829Syongari	struct urio_softc *sc = fifo->priv_sc0;
377216829Syongari
378216829Syongari	usb2_transfer_stop(sc->sc_xfer[URIO_T_WR_CS]);
379216829Syongari	usb2_transfer_stop(sc->sc_xfer[URIO_T_WR]);
380216829Syongari	return;
381216829Syongari}
382216829Syongari
383216829Syongaristatic int
384216829Syongariurio_open(struct usb2_fifo *fifo, int fflags, struct thread *td)
385216829Syongari{
386216829Syongari	struct urio_softc *sc = fifo->priv_sc0;
387216829Syongari
388216829Syongari	if ((fflags & (FWRITE | FREAD)) != (FWRITE | FREAD)) {
389216829Syongari		return (EACCES);
390216829Syongari	}
391216829Syongari	if (fflags & FREAD) {
392216829Syongari		/* clear stall first */
393216829Syongari		mtx_lock(&sc->sc_mtx);
394216829Syongari		sc->sc_flags |= URIO_FLAG_READ_STALL;
395216829Syongari		mtx_unlock(&sc->sc_mtx);
396216829Syongari
397216829Syongari		if (usb2_fifo_alloc_buffer(fifo,
398216829Syongari		    sc->sc_xfer[URIO_T_RD]->max_data_length,
399216829Syongari		    URIO_IFQ_MAXLEN)) {
400216829Syongari			return (ENOMEM);
401216829Syongari		}
402216829Syongari	}
403216829Syongari	if (fflags & FWRITE) {
404216829Syongari		/* clear stall first */
405216829Syongari		sc->sc_flags |= URIO_FLAG_WRITE_STALL;
406216829Syongari
407216829Syongari		if (usb2_fifo_alloc_buffer(fifo,
408216829Syongari		    sc->sc_xfer[URIO_T_WR]->max_data_length,
409216829Syongari		    URIO_IFQ_MAXLEN)) {
410216829Syongari			return (ENOMEM);
411216829Syongari		}
412216829Syongari	}
413216829Syongari	return (0);			/* success */
414216829Syongari}
415216829Syongari
416216829Syongaristatic void
417216829Syongariurio_close(struct usb2_fifo *fifo, int fflags, struct thread *td)
418216829Syongari{
419216829Syongari	if (fflags & (FREAD | FWRITE)) {
420216829Syongari		usb2_fifo_free_buffer(fifo);
421216829Syongari	}
422216829Syongari	return;
423216829Syongari}
424216829Syongari
425216829Syongaristatic int
426216829Syongariurio_ioctl(struct usb2_fifo *fifo, u_long cmd, void *addr,
427216829Syongari    int fflags, struct thread *td)
428216829Syongari{
429216829Syongari	struct usb2_ctl_request ur;
430216829Syongari	struct RioCommand *rio_cmd;
431216829Syongari	int error;
432216829Syongari
433216829Syongari	switch (cmd) {
434216829Syongari	case RIO_RECV_COMMAND:
435216829Syongari		if (!(fflags & FWRITE)) {
436216829Syongari			error = EPERM;
437216829Syongari			goto done;
438216829Syongari		}
439216829Syongari		bzero(&ur, sizeof(ur));
440216829Syongari		rio_cmd = addr;
441216829Syongari		ur.ucr_request.bmRequestType =
442216829Syongari		    rio_cmd->requesttype | UT_READ_VENDOR_DEVICE;
443216829Syongari		break;
444216829Syongari
445216829Syongari	case RIO_SEND_COMMAND:
446216829Syongari		if (!(fflags & FWRITE)) {
447216829Syongari			error = EPERM;
448216829Syongari			goto done;
449216829Syongari		}
450216829Syongari		bzero(&ur, sizeof(ur));
451216829Syongari		rio_cmd = addr;
452216829Syongari		ur.ucr_request.bmRequestType =
453216829Syongari		    rio_cmd->requesttype | UT_WRITE_VENDOR_DEVICE;
454216829Syongari		break;
455216829Syongari
456216829Syongari	default:
457216829Syongari		error = EINVAL;
458216829Syongari		goto done;
459216829Syongari	}
460216829Syongari
461216829Syongari	DPRINTFN(2, "Sending command\n");
462216829Syongari
463216829Syongari	/* Send rio control message */
464216829Syongari	ur.ucr_request.bRequest = rio_cmd->request;
465216829Syongari	USETW(ur.ucr_request.wValue, rio_cmd->value);
466216829Syongari	USETW(ur.ucr_request.wIndex, rio_cmd->index);
467216829Syongari	USETW(ur.ucr_request.wLength, rio_cmd->length);
468216829Syongari	ur.ucr_data = rio_cmd->buffer;
469216829Syongari
470216829Syongari	/* reuse generic USB code */
471216829Syongari	error = ugen_do_request(fifo, &ur);
472216829Syongari
473216829Syongaridone:
474216829Syongari	return (error);
475216829Syongari}
476216829Syongari
477216829Syongaristatic int
478216829Syongariurio_detach(device_t dev)
479216829Syongari{
480216829Syongari	struct urio_softc *sc = device_get_softc(dev);
481216829Syongari
482216829Syongari	DPRINTF("\n");
483216829Syongari
484216829Syongari	usb2_fifo_detach(&sc->sc_fifo);
485216829Syongari
486216829Syongari	usb2_transfer_unsetup(sc->sc_xfer, URIO_T_MAX);
487216829Syongari
488216829Syongari	mtx_destroy(&sc->sc_mtx);
489216829Syongari
490216829Syongari	return (0);
491216829Syongari}
492216829Syongari