1 /* $NetBSD: urio.c,v 1.33 2009/09/23 19:07:19 plunky Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * The inspiration and information for this driver comes from the
35 * FreeBSD driver written by Iwasa Kazmi.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: urio.c,v 1.33 2009/09/23 19:07:19 plunky Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #if defined(__NetBSD__) || defined(__OpenBSD__)
46 #include <sys/device.h>
47 #include <sys/ioctl.h>
48 #elif defined(__FreeBSD__)
49 #include <sys/module.h>
51 #include <sys/ioccom.h>
53 #include <sys/fcntl.h>
54 #include <sys/filio.h>
58 #include <sys/select.h>
60 #include <sys/vnode.h>
63 #include <dev/usb/usb.h>
64 #include <dev/usb/usbdi.h>
65 #include <dev/usb/usbdi_util.h>
67 #include <dev/usb/usbdevs.h>
68 #include <dev/usb/urio.h>
71 #define DPRINTF(x) if (uriodebug) logprintf x
72 #define DPRINTFN(n,x) if (uriodebug>(n)) logprintf x
80 #if defined(__NetBSD__)
81 dev_type_open(urioopen
);
82 dev_type_close(urioclose
);
83 dev_type_read(urioread
);
84 dev_type_write(uriowrite
);
85 dev_type_ioctl(urioioctl
);
87 const struct cdevsw urio_cdevsw
= {
88 urioopen
, urioclose
, urioread
, uriowrite
, urioioctl
,
89 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
,
91 #elif defined(__OpenBSD__)
93 #elif defined(__FreeBSD__)
100 #define URIO_CDEV_MAJOR 143
102 static struct cdevsw urio_cdevsw
= {
103 urioopen
, urioclose
, urioread
, uriowrite
,
104 urioioctl
, nopoll
, nommap
, nostrategy
,
105 "urio", URIO_CDEV_MAJOR
,nodump
, nopsize
,
108 #endif /* defined(__FreeBSD__) */
110 #define URIO_CONFIG_NO 1
111 #define URIO_IFACE_IDX 0
114 #define URIO_BSIZE 4096
118 USBBASEDEVICE sc_dev
;
119 usbd_device_handle sc_udev
;
120 usbd_interface_handle sc_iface
;
123 usbd_pipe_handle sc_in_pipe
;
125 usbd_pipe_handle sc_out_pipe
;
131 #define URIOUNIT(n) (minor(n))
133 #define URIO_RW_TIMEOUT 4000 /* ms */
135 static const struct usb_devno urio_devs
[] = {
136 { USB_VENDOR_DIAMOND
, USB_PRODUCT_DIAMOND_RIO500USB
},
137 { USB_VENDOR_DIAMOND2
, USB_PRODUCT_DIAMOND2_RIO600USB
},
138 { USB_VENDOR_DIAMOND2
, USB_PRODUCT_DIAMOND2_RIO800USB
},
139 { USB_VENDOR_DIAMOND2
, USB_PRODUCT_DIAMOND2_PSAPLAY120
},
141 #define urio_lookup(v, p) usb_lookup(urio_devs, v, p)
143 USB_DECLARE_DRIVER(urio
);
147 USB_MATCH_START(urio
, uaa
);
149 DPRINTFN(50,("urio_match\n"));
151 return (urio_lookup(uaa
->vendor
, uaa
->product
) != NULL
?
152 UMATCH_VENDOR_PRODUCT
: UMATCH_NONE
);
157 USB_ATTACH_START(urio
, sc
, uaa
);
158 usbd_device_handle dev
= uaa
->device
;
159 usbd_interface_handle iface
;
162 usb_endpoint_descriptor_t
*ed
;
166 DPRINTFN(10,("urio_attach: sc=%p\n", sc
));
173 devinfop
= usbd_devinfo_alloc(dev
, 0);
174 aprint_normal_dev(self
, "%s\n", devinfop
);
175 usbd_devinfo_free(devinfop
);
177 err
= usbd_set_config_no(dev
, URIO_CONFIG_NO
, 1);
179 aprint_error_dev(self
, "setting config no failed\n");
180 USB_ATTACH_ERROR_RETURN
;
183 err
= usbd_device2interface_handle(dev
, URIO_IFACE_IDX
, &iface
);
185 aprint_error_dev(self
, "getting interface handle failed\n");
186 USB_ATTACH_ERROR_RETURN
;
190 sc
->sc_iface
= iface
;
193 (void)usbd_endpoint_count(iface
, &epcount
);
196 sc
->sc_out_addr
= -1;
197 for (i
= 0; i
< epcount
; i
++) {
198 ed
= usbd_interface2endpoint_descriptor(iface
, i
);
200 aprint_error_dev(self
, "couldn't get ep %d\n", i
);
201 USB_ATTACH_ERROR_RETURN
;
203 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
204 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
205 sc
->sc_in_addr
= ed
->bEndpointAddress
;
206 } else if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_OUT
&&
207 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
208 sc
->sc_out_addr
= ed
->bEndpointAddress
;
211 if (sc
->sc_in_addr
== -1 || sc
->sc_out_addr
== -1) {
212 aprint_error_dev(self
, "missing endpoint\n");
213 USB_ATTACH_ERROR_RETURN
;
216 #if defined(__FreeBSD__)
217 /* XXX no error trapping, no storing of dev_t */
218 (void)make_dev(&urio_cdevsw
, device_get_unit(self
),
219 UID_ROOT
, GID_OPERATOR
,
220 0644, "urio%d", device_get_unit(self
));
221 #endif /* defined(__FreeBSD__) */
223 DPRINTFN(10, ("urio_attach: %p\n", sc
->sc_udev
));
225 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH
, sc
->sc_udev
,
228 USB_ATTACH_SUCCESS_RETURN
;
233 USB_DETACH_START(urio
, sc
);
235 #if defined(__NetBSD__) || defined(__OpenBSD__)
238 DPRINTF(("urio_detach: sc=%p flags=%d\n", sc
, flags
));
239 #elif defined(__FreeBSD__)
240 DPRINTF(("urio_detach: sc=%p\n", sc
));
244 /* Abort all pipes. Causes processes waiting for transfer to wake. */
245 if (sc
->sc_in_pipe
!= NULL
) {
246 usbd_abort_pipe(sc
->sc_in_pipe
);
247 usbd_close_pipe(sc
->sc_in_pipe
);
248 sc
->sc_in_pipe
= NULL
;
250 if (sc
->sc_out_pipe
!= NULL
) {
251 usbd_abort_pipe(sc
->sc_out_pipe
);
252 usbd_close_pipe(sc
->sc_out_pipe
);
253 sc
->sc_out_pipe
= NULL
;
257 if (--sc
->sc_refcnt
>= 0) {
258 /* Wait for processes to go away. */
259 usb_detach_wait(USBDEV(sc
->sc_dev
));
263 #if defined(__NetBSD__) || defined(__OpenBSD__)
264 /* locate the major number */
265 #if defined(__NetBSD__)
266 maj
= cdevsw_lookup_major(&urio_cdevsw
);
267 #elif defined(__OpenBSD__)
268 for (maj
= 0; maj
< nchrdev
; maj
++)
269 if (cdevsw
[maj
].d_open
== urioopen
)
273 /* Nuke the vnodes for any open instances (calls close). */
274 mn
= device_unit(self
);
275 vdevgone(maj
, mn
, mn
, VCHR
);
276 #elif defined(__FreeBSD__)
277 /* XXX not implemented yet */
280 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH
, sc
->sc_udev
,
286 #if defined(__NetBSD__) || defined(__OpenBSD__)
288 urio_activate(device_ptr_t self
, enum devact act
)
290 struct urio_softc
*sc
= device_private(self
);
293 case DVACT_DEACTIVATE
:
303 urioopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
305 struct urio_softc
*sc
;
308 USB_GET_SC_OPEN(urio
, URIOUNIT(dev
), sc
);
310 DPRINTFN(5, ("urioopen: flag=%d, mode=%d, unit=%d\n",
311 flag
, mode
, URIOUNIT(dev
)));
316 if (sc
->sc_in_pipe
!= NULL
)
319 if ((flag
& (FWRITE
|FREAD
)) != (FWRITE
|FREAD
))
322 err
= usbd_open_pipe(sc
->sc_iface
, sc
->sc_in_addr
, 0, &sc
->sc_in_pipe
);
325 err
= usbd_open_pipe(sc
->sc_iface
, sc
->sc_out_addr
,0,&sc
->sc_out_pipe
);
327 usbd_close_pipe(sc
->sc_in_pipe
);
328 sc
->sc_in_pipe
= NULL
;
336 urioclose(dev_t dev
, int flag
, int mode
,
339 struct urio_softc
*sc
;
340 USB_GET_SC(urio
, URIOUNIT(dev
), sc
);
342 DPRINTFN(5, ("urioclose: flag=%d, mode=%d, unit=%d\n",
343 flag
, mode
, URIOUNIT(dev
)));
345 if (sc
->sc_in_pipe
!= NULL
) {
346 usbd_abort_pipe(sc
->sc_in_pipe
);
347 usbd_close_pipe(sc
->sc_in_pipe
);
348 sc
->sc_in_pipe
= NULL
;
350 if (sc
->sc_out_pipe
!= NULL
) {
351 usbd_abort_pipe(sc
->sc_out_pipe
);
352 usbd_close_pipe(sc
->sc_out_pipe
);
353 sc
->sc_out_pipe
= NULL
;
360 urioread(dev_t dev
, struct uio
*uio
, int flag
)
362 struct urio_softc
*sc
;
363 usbd_xfer_handle xfer
;
369 USB_GET_SC(urio
, URIOUNIT(dev
), sc
);
371 DPRINTFN(5, ("urioread: %d\n", URIOUNIT(dev
)));
376 xfer
= usbd_alloc_xfer(sc
->sc_udev
);
379 bufp
= usbd_alloc_buffer(xfer
, URIO_BSIZE
);
381 usbd_free_xfer(xfer
);
387 while ((n
= min(URIO_BSIZE
, uio
->uio_resid
)) != 0) {
388 DPRINTFN(1, ("urioread: start transfer %d bytes\n", n
));
390 err
= usbd_bulk_transfer(xfer
, sc
->sc_in_pipe
, USBD_NO_COPY
,
391 URIO_RW_TIMEOUT
, bufp
, &tn
, "uriors");
393 if (err
== USBD_INTERRUPTED
)
395 else if (err
== USBD_TIMEOUT
)
402 DPRINTFN(1, ("urioread: got %d bytes\n", tn
));
404 error
= uiomove(bufp
, tn
, uio
);
408 usbd_free_xfer(xfer
);
410 if (--sc
->sc_refcnt
< 0)
411 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
417 uriowrite(dev_t dev
, struct uio
*uio
, int flag
)
419 struct urio_softc
*sc
;
420 usbd_xfer_handle xfer
;
426 USB_GET_SC(urio
, URIOUNIT(dev
), sc
);
428 DPRINTFN(5, ("uriowrite: unit=%d, len=%ld\n", URIOUNIT(dev
),
429 (long)uio
->uio_resid
));
434 xfer
= usbd_alloc_xfer(sc
->sc_udev
);
437 bufp
= usbd_alloc_buffer(xfer
, URIO_BSIZE
);
439 usbd_free_xfer(xfer
);
445 while ((n
= min(URIO_BSIZE
, uio
->uio_resid
)) != 0) {
446 error
= uiomove(bufp
, n
, uio
);
450 DPRINTFN(1, ("uriowrite: transfer %d bytes\n", n
));
452 err
= usbd_bulk_transfer(xfer
, sc
->sc_out_pipe
, USBD_NO_COPY
,
453 URIO_RW_TIMEOUT
, bufp
, &n
, "uriowr");
454 DPRINTFN(2, ("uriowrite: err=%d\n", err
));
456 if (err
== USBD_INTERRUPTED
)
458 else if (err
== USBD_TIMEOUT
)
466 usbd_free_xfer(xfer
);
468 if (--sc
->sc_refcnt
< 0)
469 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
471 DPRINTFN(5, ("uriowrite: done unit=%d, error=%d\n", URIOUNIT(dev
),
479 urioioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
481 struct urio_softc
* sc
;
482 int unit
= URIOUNIT(dev
);
483 struct urio_command
*rcmd
;
484 int requesttype
, len
;
487 usb_device_request_t req
;
490 u_int32_t req_actlen
= 0;
494 USB_GET_SC(urio
, unit
, sc
);
499 rcmd
= (struct urio_command
*)addr
;
502 case URIO_RECV_COMMAND
:
503 requesttype
= rcmd
->requesttype
| UT_READ_VENDOR_DEVICE
;
506 case URIO_SEND_COMMAND
:
507 requesttype
= rcmd
->requesttype
| UT_WRITE_VENDOR_DEVICE
;
515 if (!(flag
& FWRITE
))
519 DPRINTFN(1,("urio_ioctl: cmd=0x%08lx reqtype=0x%0x req=0x%0x "
520 "value=0x%0x index=0x%0x len=0x%0x\n",
521 cmd
, requesttype
, rcmd
->request
, rcmd
->value
,
524 /* Send rio control message */
525 req
.bmRequestType
= requesttype
;
526 req
.bRequest
= rcmd
->request
;
527 USETW(req
.wValue
, rcmd
->value
);
528 USETW(req
.wIndex
, rcmd
->index
);
529 USETW(req
.wLength
, len
);
531 if (len
< 0 || len
> 32767)
534 iov
.iov_base
= (void *)rcmd
->buffer
;
540 uio
.uio_rw
= req
.bmRequestType
& UT_READ
?
541 UIO_READ
: UIO_WRITE
;
542 uio
.uio_vmspace
= l
->l_proc
->p_vmspace
;
543 ptr
= malloc(len
, M_TEMP
, M_WAITOK
);
544 if (uio
.uio_rw
== UIO_WRITE
) {
545 error
= uiomove(ptr
, len
, &uio
);
553 err
= usbd_do_request_flags(sc
->sc_udev
, &req
, ptr
, req_flags
,
554 &req_actlen
, USBD_DEFAULT_TIMEOUT
);
556 if (--sc
->sc_refcnt
< 0)
557 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
562 if (len
!= 0 && uio
.uio_rw
== UIO_READ
)
563 error
= uiomove(ptr
, len
, &uio
);
572 #if defined(__OpenBSD__)
574 urioselect(dev_t dev
, int events
, struct lwp
*l
)
580 #if defined(__FreeBSD__)
581 DRIVER_MODULE(urio
, uhub
, urio_driver
, urio_devclass
, usbd_driver_load
, 0);
582 #endif /* defined(__FreeBSD__) */