No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / usb / urio.c
blobe1afae0c612cd4fde98e8eb529a95c15506bc564
1 /* $NetBSD: urio.c,v 1.33 2009/09/23 19:07:19 plunky Exp $ */
3 /*
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
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
13 * are met:
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>
50 #include <sys/bus.h>
51 #include <sys/ioccom.h>
52 #include <sys/conf.h>
53 #include <sys/fcntl.h>
54 #include <sys/filio.h>
55 #endif
56 #include <sys/conf.h>
57 #include <sys/file.h>
58 #include <sys/select.h>
59 #include <sys/proc.h>
60 #include <sys/vnode.h>
61 #include <sys/poll.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>
70 #ifdef URIO_DEBUG
71 #define DPRINTF(x) if (uriodebug) logprintf x
72 #define DPRINTFN(n,x) if (uriodebug>(n)) logprintf x
73 int uriodebug = 0;
74 #else
75 #define DPRINTF(x)
76 #define DPRINTFN(n,x)
77 #endif
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__)
92 cdev_decl(urio);
93 #elif defined(__FreeBSD__)
94 d_open_t urioopen;
95 d_close_t urioclose;
96 d_read_t urioread;
97 d_write_t uriowrite;
98 d_ioctl_t urioioctl;
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,
106 0, -1
108 #endif /* defined(__FreeBSD__) */
110 #define URIO_CONFIG_NO 1
111 #define URIO_IFACE_IDX 0
114 #define URIO_BSIZE 4096
117 struct urio_softc {
118 USBBASEDEVICE sc_dev;
119 usbd_device_handle sc_udev;
120 usbd_interface_handle sc_iface;
122 int sc_in_addr;
123 usbd_pipe_handle sc_in_pipe;
124 int sc_out_addr;
125 usbd_pipe_handle sc_out_pipe;
127 int sc_refcnt;
128 char sc_dying;
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);
145 USB_MATCH(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);
155 USB_ATTACH(urio)
157 USB_ATTACH_START(urio, sc, uaa);
158 usbd_device_handle dev = uaa->device;
159 usbd_interface_handle iface;
160 char *devinfop;
161 usbd_status err;
162 usb_endpoint_descriptor_t *ed;
163 u_int8_t epcount;
164 int i;
166 DPRINTFN(10,("urio_attach: sc=%p\n", sc));
168 sc->sc_dev = self;
170 aprint_naive("\n");
171 aprint_normal("\n");
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);
178 if (err) {
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);
184 if (err) {
185 aprint_error_dev(self, "getting interface handle failed\n");
186 USB_ATTACH_ERROR_RETURN;
189 sc->sc_udev = dev;
190 sc->sc_iface = iface;
192 epcount = 0;
193 (void)usbd_endpoint_count(iface, &epcount);
195 sc->sc_in_addr = -1;
196 sc->sc_out_addr = -1;
197 for (i = 0; i < epcount; i++) {
198 ed = usbd_interface2endpoint_descriptor(iface, i);
199 if (ed == NULL) {
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,
226 USBDEV(sc->sc_dev));
228 USB_ATTACH_SUCCESS_RETURN;
231 USB_DETACH(urio)
233 USB_DETACH_START(urio, sc);
234 int s;
235 #if defined(__NetBSD__) || defined(__OpenBSD__)
236 int maj, mn;
238 DPRINTF(("urio_detach: sc=%p flags=%d\n", sc, flags));
239 #elif defined(__FreeBSD__)
240 DPRINTF(("urio_detach: sc=%p\n", sc));
241 #endif
243 sc->sc_dying = 1;
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;
256 s = splusb();
257 if (--sc->sc_refcnt >= 0) {
258 /* Wait for processes to go away. */
259 usb_detach_wait(USBDEV(sc->sc_dev));
261 splx(s);
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)
270 break;
271 #endif
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 */
278 #endif
280 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
281 USBDEV(sc->sc_dev));
283 return (0);
286 #if defined(__NetBSD__) || defined(__OpenBSD__)
288 urio_activate(device_ptr_t self, enum devact act)
290 struct urio_softc *sc = device_private(self);
292 switch (act) {
293 case DVACT_DEACTIVATE:
294 sc->sc_dying = 1;
295 return 0;
296 default:
297 return EOPNOTSUPP;
300 #endif
303 urioopen(dev_t dev, int flag, int mode, struct lwp *l)
305 struct urio_softc *sc;
306 usbd_status err;
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)));
313 if (sc->sc_dying)
314 return (EIO);
316 if (sc->sc_in_pipe != NULL)
317 return (EBUSY);
319 if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
320 return (EACCES);
322 err = usbd_open_pipe(sc->sc_iface, sc->sc_in_addr, 0, &sc->sc_in_pipe);
323 if (err)
324 return (EIO);
325 err = usbd_open_pipe(sc->sc_iface, sc->sc_out_addr,0,&sc->sc_out_pipe);
326 if (err) {
327 usbd_close_pipe(sc->sc_in_pipe);
328 sc->sc_in_pipe = NULL;
329 return (EIO);
332 return (0);
336 urioclose(dev_t dev, int flag, int mode,
337 struct lwp *l)
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;
356 return (0);
360 urioread(dev_t dev, struct uio *uio, int flag)
362 struct urio_softc *sc;
363 usbd_xfer_handle xfer;
364 usbd_status err;
365 void *bufp;
366 u_int32_t n, tn;
367 int error = 0;
369 USB_GET_SC(urio, URIOUNIT(dev), sc);
371 DPRINTFN(5, ("urioread: %d\n", URIOUNIT(dev)));
373 if (sc->sc_dying)
374 return (EIO);
376 xfer = usbd_alloc_xfer(sc->sc_udev);
377 if (xfer == NULL)
378 return (ENOMEM);
379 bufp = usbd_alloc_buffer(xfer, URIO_BSIZE);
380 if (bufp == NULL) {
381 usbd_free_xfer(xfer);
382 return (ENOMEM);
385 sc->sc_refcnt++;
387 while ((n = min(URIO_BSIZE, uio->uio_resid)) != 0) {
388 DPRINTFN(1, ("urioread: start transfer %d bytes\n", n));
389 tn = n;
390 err = usbd_bulk_transfer(xfer, sc->sc_in_pipe, USBD_NO_COPY,
391 URIO_RW_TIMEOUT, bufp, &tn, "uriors");
392 if (err) {
393 if (err == USBD_INTERRUPTED)
394 error = EINTR;
395 else if (err == USBD_TIMEOUT)
396 error = ETIMEDOUT;
397 else
398 error = EIO;
399 break;
402 DPRINTFN(1, ("urioread: got %d bytes\n", tn));
404 error = uiomove(bufp, tn, uio);
405 if (error || tn < n)
406 break;
408 usbd_free_xfer(xfer);
410 if (--sc->sc_refcnt < 0)
411 usb_detach_wakeup(USBDEV(sc->sc_dev));
413 return (error);
417 uriowrite(dev_t dev, struct uio *uio, int flag)
419 struct urio_softc *sc;
420 usbd_xfer_handle xfer;
421 usbd_status err;
422 void *bufp;
423 u_int32_t n;
424 int error = 0;
426 USB_GET_SC(urio, URIOUNIT(dev), sc);
428 DPRINTFN(5, ("uriowrite: unit=%d, len=%ld\n", URIOUNIT(dev),
429 (long)uio->uio_resid));
431 if (sc->sc_dying)
432 return (EIO);
434 xfer = usbd_alloc_xfer(sc->sc_udev);
435 if (xfer == NULL)
436 return (ENOMEM);
437 bufp = usbd_alloc_buffer(xfer, URIO_BSIZE);
438 if (bufp == NULL) {
439 usbd_free_xfer(xfer);
440 return (ENOMEM);
443 sc->sc_refcnt++;
445 while ((n = min(URIO_BSIZE, uio->uio_resid)) != 0) {
446 error = uiomove(bufp, n, uio);
447 if (error)
448 break;
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));
455 if (err) {
456 if (err == USBD_INTERRUPTED)
457 error = EINTR;
458 else if (err == USBD_TIMEOUT)
459 error = ETIMEDOUT;
460 else
461 error = EIO;
462 break;
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),
472 error));
474 return (error);
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;
485 struct iovec iov;
486 struct uio uio;
487 usb_device_request_t req;
488 usbd_status err;
489 int req_flags = 0;
490 u_int32_t req_actlen = 0;
491 void *ptr = NULL;
492 int error = 0;
494 USB_GET_SC(urio, unit, sc);
496 if (sc->sc_dying)
497 return (EIO);
499 rcmd = (struct urio_command *)addr;
501 switch (cmd) {
502 case URIO_RECV_COMMAND:
503 requesttype = rcmd->requesttype | UT_READ_VENDOR_DEVICE;
504 break;
506 case URIO_SEND_COMMAND:
507 requesttype = rcmd->requesttype | UT_WRITE_VENDOR_DEVICE;
508 break;
510 default:
511 return (EINVAL);
512 break;
515 if (!(flag & FWRITE))
516 return (EPERM);
517 len = rcmd->length;
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,
522 rcmd->index, len));
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)
532 return (EINVAL);
533 if (len != 0) {
534 iov.iov_base = (void *)rcmd->buffer;
535 iov.iov_len = len;
536 uio.uio_iov = &iov;
537 uio.uio_iovcnt = 1;
538 uio.uio_resid = len;
539 uio.uio_offset = 0;
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);
546 if (error)
547 goto ret;
551 sc->sc_refcnt++;
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));
559 if (err) {
560 error = EIO;
561 } else {
562 if (len != 0 && uio.uio_rw == UIO_READ)
563 error = uiomove(ptr, len, &uio);
566 ret:
567 if (ptr != NULL)
568 free(ptr, M_TEMP);
569 return (error);
572 #if defined(__OpenBSD__)
574 urioselect(dev_t dev, int events, struct lwp *l)
576 return (0);
578 #endif
580 #if defined(__FreeBSD__)
581 DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, usbd_driver_load, 0);
582 #endif /* defined(__FreeBSD__) */