diff options
author | Nathan Binkert <nate@cvs.openbsd.org> | 2002-07-09 17:50:15 +0000 |
---|---|---|
committer | Nathan Binkert <nate@cvs.openbsd.org> | 2002-07-09 17:50:15 +0000 |
commit | 2621c6ba13ef1435846b92dbb93788c7ef4a07ea (patch) | |
tree | abc9c56fdd884cf4dc4a6731550208649a4300ec | |
parent | dcb90d88f68f79bfaa157bf8c7b53d98d7f8bcce (diff) |
sync with NetBSD
-rw-r--r-- | sys/dev/usb/ugen.c | 165 |
1 files changed, 90 insertions, 75 deletions
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c index 2a393c3f1df..16e11e3abe0 100644 --- a/sys/dev/usb/ugen.c +++ b/sys/dev/usb/ugen.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ugen.c,v 1.21 2002/07/09 17:41:02 nate Exp $ */ -/* $NetBSD: ugen.c,v 1.49 2001/10/24 22:31:04 augustss Exp $ */ +/* $OpenBSD: ugen.c,v 1.22 2002/07/09 17:50:14 nate Exp $ */ +/* $NetBSD: ugen.c,v 1.58 2002/02/20 20:30:12 christos Exp $ */ /* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.26 1999/11/17 22:33:41 n_hibma Exp $ */ /* @@ -20,8 +20,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. @@ -150,16 +150,16 @@ Static struct cdevsw ugen_cdevsw = { }; #endif -Static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, +Static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status); Static void ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status); Static int ugen_do_read(struct ugen_softc *, int, struct uio *, int); Static int ugen_do_write(struct ugen_softc *, int, struct uio *, int); -Static int ugen_do_ioctl(struct ugen_softc *, int, u_long, - caddr_t, int, struct proc *); +Static int ugen_do_ioctl(struct ugen_softc *, int, u_long, + caddr_t, int, usb_proc_ptr); Static int ugen_set_config(struct ugen_softc *sc, int configno); -Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc, +Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc, int index, int *lenp); Static usbd_status ugen_set_interface(struct ugen_softc *, int, int); Static int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx); @@ -201,7 +201,7 @@ USB_ATTACH(ugen) /* First set configuration index 0, the default one for ugen. */ err = usbd_set_config_index(udev, 0, 0); if (err) { - printf("%s: setting configuration index 0 failed\n", + printf("%s: setting configuration index 0 failed\n", USBDEVNAME(sc->sc_dev)); sc->sc_dying = 1; USB_ATTACH_ERROR_RETURN; @@ -211,7 +211,7 @@ USB_ATTACH(ugen) /* Set up all the local state for this configuration. */ err = ugen_set_config(sc, conf); if (err) { - printf("%s: setting configuration %d failed\n", + printf("%s: setting configuration %d failed\n", USBDEVNAME(sc->sc_dev), conf); sc->sc_dying = 1; USB_ATTACH_ERROR_RETURN; @@ -247,6 +247,19 @@ ugen_set_config(struct ugen_softc *sc, int configno) DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n", USBDEVNAME(sc->sc_dev), configno, sc)); + + /* + * We start at 1, not 0, because we don't care whether the + * control endpoint is open or not. It is always present. + */ + for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) + if (sc->sc_is_open[endptno]) { + DPRINTFN(1, + ("ugen_set_config: %s - endpoint %d is open\n", + USBDEVNAME(sc->sc_dev), endptno)); + return (USBD_IN_USE); + } + /* Avoid setting the current value. */ if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) { err = usbd_set_config_no(dev, configno, 1); @@ -272,7 +285,7 @@ ugen_set_config(struct ugen_softc *sc, int configno) dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT; sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir]; DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x" - "(%d,%d), sce=%p\n", + "(%d,%d), sce=%p\n", endptno, endpt, UE_GET_ADDR(endpt), UE_GET_DIR(endpt), sce)); sce->sc = sc; @@ -284,7 +297,7 @@ ugen_set_config(struct ugen_softc *sc, int configno) } int -ugenopen(dev_t dev, int flag, int mode, struct proc *p) +ugenopen(dev_t dev, int flag, int mode, usb_proc_ptr p) { struct ugen_softc *sc; int unit = UGENUNIT(dev); @@ -299,7 +312,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p) USB_GET_SC_OPEN(ugen, unit, sc); - DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n", + DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n", flag, mode, unit, endpt)); if (sc == NULL || sc->sc_dying) @@ -330,7 +343,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p) sce = &sc->sc_endpoints[endpt][dir]; sce->state = 0; sce->timeout = USBD_NO_TIMEOUT; - DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n", + DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n", sc, endpt, dir, sce)); edesc = sce->edesc; switch (edesc->bmAttributes & UE_XFERTYPE) { @@ -339,14 +352,14 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p) if (isize == 0) /* shouldn't happen */ return (EINVAL); sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK); - DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n", + DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n", endpt, isize)); - if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1) - return (ENOMEM); - err = usbd_open_pipe_intr(sce->iface, - edesc->bEndpointAddress, - USBD_SHORT_XFER_OK, &sce->pipeh, sce, - sce->ibuf, isize, ugenintr, + if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1) + return (ENOMEM); + err = usbd_open_pipe_intr(sce->iface, + edesc->bEndpointAddress, + USBD_SHORT_XFER_OK, &sce->pipeh, sce, + sce->ibuf, isize, ugenintr, USBD_DEFAULT_INTERVAL); if (err) { free(sce->ibuf, M_USBDEV); @@ -356,7 +369,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p) DPRINTFN(5, ("ugenopen: interrupt open done\n")); break; case UE_BULK: - err = usbd_open_pipe(sce->iface, + err = usbd_open_pipe(sce->iface, edesc->bEndpointAddress, 0, &sce->pipeh); if (err) return (EIO); @@ -371,7 +384,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p) M_USBDEV, M_WAITOK); sce->cur = sce->fill = sce->ibuf; sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES; - DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n", + DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n", endpt, isize)); err = usbd_open_pipe(sce->iface, edesc->bEndpointAddress, 0, &sce->pipeh); @@ -408,6 +421,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p) usbd_free_xfer(sce->isoreqs[i].xfer); return (ENOMEM); case UE_CONTROL: + sce->timeout = USBD_DEFAULT_TIMEOUT; return (EINVAL); } } @@ -416,7 +430,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p) } int -ugenclose(dev_t dev, int flag, int mode, struct proc *p) +ugenclose(dev_t dev, int flag, int mode, usb_proc_ptr p) { int endpt = UGENENDPOINT(dev); struct ugen_softc *sc; @@ -448,31 +462,30 @@ ugenclose(dev_t dev, int flag, int mode, struct proc *p) sce = &sc->sc_endpoints[endpt][dir]; if (sce == NULL || sce->pipeh == NULL) continue; - DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", + DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", endpt, dir, sce)); usbd_abort_pipe(sce->pipeh); usbd_close_pipe(sce->pipeh); sce->pipeh = NULL; - switch (sce->edesc->bmAttributes & UE_XFERTYPE) { - case UE_INTERRUPT: - ndflush(&sce->q, sce->q.c_cc); - clfree(&sce->q); - break; - case UE_ISOCHRONOUS: - for (i = 0; i < UGEN_NISOREQS; ++i) - usbd_free_xfer(sce->isoreqs[i].xfer); - - default: - break; + switch (sce->edesc->bmAttributes & UE_XFERTYPE) { + case UE_INTERRUPT: + ndflush(&sce->q, sce->q.c_cc); + clfree(&sce->q); + break; + case UE_ISOCHRONOUS: + for (i = 0; i < UGEN_NISOREQS; ++i) + usbd_free_xfer(sce->isoreqs[i].xfer); + + default: + break; } if (sce->ibuf != NULL) { free(sce->ibuf, M_USBDEV); sce->ibuf = NULL; clfree(&sce->q); - } } sc->sc_is_open[endpt] = 0; @@ -558,8 +571,8 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag) tn = n; err = usbd_bulk_transfer( xfer, sce->pipeh, - sce->state & UGEN_SHORT_OK ? - USBD_SHORT_XFER_OK : 0, + sce->state & UGEN_SHORT_OK ? + USBD_SHORT_XFER_OK : 0, sce->timeout, buf, &tn, "ugenrb"); if (err) { if (err == USBD_INTERRUPTED) @@ -677,7 +690,7 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag) if (error) break; DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n)); - err = usbd_bulk_transfer(xfer, sce->pipeh, 0, + err = usbd_bulk_transfer(xfer, sce->pipeh, 0, sce->timeout, buf, &n,"ugenwb"); if (err) { if (err == USBD_INTERRUPTED) @@ -798,14 +811,15 @@ ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) if (status != USBD_NORMAL_COMPLETION) { DPRINTF(("ugenintr: status=%d\n", status)); - usbd_clear_endpoint_stall_async(sce->pipeh); + if (status == USBD_STALLED) + usbd_clear_endpoint_stall_async(sce->pipeh); return; } usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); ibuf = sce->ibuf; - DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n", + DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n", xfer, status, count)); DPRINTFN(5, (" data = %02x %02x %02x\n", ibuf[0], ibuf[1], ibuf[2])); @@ -821,7 +835,7 @@ ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) } Static void -ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr, +ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) { struct isoreq *req = addr; @@ -959,7 +973,8 @@ ugen_get_cdesc(struct ugen_softc *sc, int index, int *lenp) if (lenp) *lenp = len; cdesc = malloc(len, M_TEMP, M_WAITOK); - err = usbd_get_config_desc_full(sc->sc_udev, index, cdesc,len); + err = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, + len); if (err) { free(cdesc, M_TEMP); return (0); @@ -982,7 +997,7 @@ ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx) Static int ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, - caddr_t addr, int flag, struct proc *p) + caddr_t addr, int flag, usb_proc_ptr p) { struct ugen_endpoint *sce; usbd_status err; @@ -1006,18 +1021,12 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, /* All handled in the upper FS layer. */ return (0); case USB_SET_SHORT_XFER: - /* This flag only affects read */ if (endpt == USB_CONTROL_ENDPOINT) return (EINVAL); + /* This flag only affects read */ sce = &sc->sc_endpoints[endpt][IN]; - if (sce == NULL) + if (sce == NULL || sce->pipeh == NULL) return (EINVAL); -#ifdef DIAGNOSTIC - if (sce->pipeh == NULL) { - printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n"); - return (EIO); - } -#endif if (*(int *)addr) sce->state |= UGEN_SHORT_OK; else @@ -1025,14 +1034,12 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, return (0); case USB_SET_TIMEOUT: sce = &sc->sc_endpoints[endpt][IN]; - if (sce == NULL) + if (sce == NULL + /* XXX this shouldn't happen, but the distinction between + input and output pipes isn't clear enough. + || sce->pipeh == NULL */ + ) return (EINVAL); -#ifdef DIAGNOSTIC - if (sce->pipeh == NULL) { - printf("ugenioctl: USB_SET_TIMEOUT, no pipe\n"); - return (EIO); - } -#endif sce->timeout = *(int *)addr; return (0); default: @@ -1058,12 +1065,18 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, if (!(flag & FWRITE)) return (EPERM); err = ugen_set_config(sc, *(int *)addr); - if (err) + switch (err) { + case USBD_NORMAL_COMPLETION: + break; + case USBD_IN_USE: + return (EBUSY); + default: return (EIO); + } break; case USB_GET_ALTINTERFACE: ai = (struct usb_alt_interface *)addr; - err = usbd_device2interface_handle(sc->sc_udev, + err = usbd_device2interface_handle(sc->sc_udev, ai->uai_interface_index, &iface); if (err) return (EINVAL); @@ -1076,11 +1089,12 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, if (!(flag & FWRITE)) return (EPERM); ai = (struct usb_alt_interface *)addr; - err = usbd_device2interface_handle(sc->sc_udev, + err = usbd_device2interface_handle(sc->sc_udev, ai->uai_interface_index, &iface); if (err) return (EINVAL); - err = ugen_set_interface(sc, ai->uai_interface_index, ai->uai_alt_no); + err = ugen_set_interface(sc, ai->uai_interface_index, + ai->uai_alt_no); if (err) return (EINVAL); break; @@ -1094,7 +1108,8 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, free(cdesc, M_TEMP); return (EINVAL); } - ai->uai_alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber); + ai->uai_alt_no = usbd_get_no_alts(cdesc, + idesc->bInterfaceNumber); free(cdesc, M_TEMP); break; case USB_GET_DEVICE_DESC: @@ -1137,7 +1152,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, alt = ugen_get_alt_index(sc, ed->ued_interface_index); else alt = ed->ued_alt_index; - edesc = usbd_find_edesc(cdesc, ed->ued_interface_index, + edesc = usbd_find_edesc(cdesc, ed->ued_interface_index, alt, ed->ued_endpoint_index); if (edesc == NULL) { free(cdesc, M_TEMP); @@ -1172,7 +1187,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, } case USB_GET_STRING_DESC: si = (struct usb_string_desc *)addr; - err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index, + err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index, si->usd_language_id, &si->usd_desc); if (err) return (EINVAL); @@ -1209,7 +1224,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, uio.uio_offset = 0; uio.uio_segflg = UIO_USERSPACE; uio.uio_rw = - ur->ucr_request.bmRequestType & UT_READ ? + ur->ucr_request.bmRequestType & UT_READ ? UIO_READ : UIO_WRITE; uio.uio_procp = p; ptr = malloc(len, M_TEMP, M_WAITOK); @@ -1219,9 +1234,9 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, goto ret; } } - err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request, - ptr, ur->ucr_flags, &ur->ucr_actlen, - USBD_DEFAULT_TIMEOUT); + sce = &sc->sc_endpoints[endpt][IN]; + err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request, + ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout); if (err) { error = EIO; goto ret; @@ -1249,7 +1264,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, } int -ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) +ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p) { int endpt = UGENENDPOINT(dev); struct ugen_softc *sc; @@ -1265,7 +1280,7 @@ ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) } int -ugenpoll(dev_t dev, int events, struct proc *p) +ugenpoll(dev_t dev, int events, usb_proc_ptr p) { struct ugen_softc *sc; struct ugen_endpoint *sce; @@ -1310,12 +1325,12 @@ ugenpoll(dev_t dev, int events, struct proc *p) } break; case UE_BULK: - /* + /* * We have no easy way of determining if a read will * yield any data or a write will happen. * Pretend they will. */ - revents |= events & + revents |= events & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM); break; default: |