Synchronise with NetBSD.

In order of importance:
* Make ugen use updated frlengths.
* More tests for NULL pipes.
* Generate better error codes on bulk write.
* Error messages in general.
This commit is contained in:
Josef Karthauser 2001-12-31 00:52:17 +00:00
parent 200281abc1
commit 6035292097
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=88728

View File

@ -1,4 +1,4 @@
/* $NetBSD: ugen.c,v 1.27 1999/10/28 12:08:38 augustss Exp $ */ /* $NetBSD: ugen.c,v 1.51 2001/11/13 07:59:32 augustss Exp $ */
/* $FreeBSD$ */ /* $FreeBSD$ */
/* /*
@ -178,6 +178,10 @@ USB_MATCH(ugen)
{ {
USB_MATCH_START(ugen, uaa); USB_MATCH_START(ugen, uaa);
#if 0
if (uaa->matchlvl)
return (uaa->matchlvl);
#endif
if (uaa->usegeneric) if (uaa->usegeneric)
return (UMATCH_GENERIC); return (UMATCH_GENERIC);
else else
@ -314,9 +318,9 @@ ugen_set_config(struct ugen_softc *sc, int configno)
return (USBD_IN_USE); return (USBD_IN_USE);
} }
/* Avoid setting the current value. */
if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) { if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
/* Avoid setting the current value. */ err = usbd_set_config_no(dev, configno, 1);
err = usbd_set_config_no(dev, configno, 0);
if (err) if (err)
return (err); return (err);
} }
@ -335,15 +339,13 @@ ugen_set_config(struct ugen_softc *sc, int configno)
return (err); return (err);
for (endptno = 0; endptno < nendpt; endptno++) { for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno); ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = UE_GET_ADDR(ed->bEndpointAddress); endpt = ed->bEndpointAddress;
dir = UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN? dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
IN : OUT; sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
sce = &sc->sc_endpoints[endpt][dir];
DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x" DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
"(%d,%d), sce=%p\n", "(%d,%d), sce=%p\n",
endptno, endpt, endpt, dir, sce)); endptno, endpt, UE_GET_ADDR(endpt),
UE_GET_DIR(endpt), sce));
sce->sc = sc; sce->sc = sc;
sce->edesc = ed; sce->edesc = ed;
sce->iface = iface; sce->iface = iface;
@ -544,6 +546,7 @@ ugenclose(dev_t dev, int flag, int mode, struct thread *td)
if (sce->ibuf != NULL) { if (sce->ibuf != NULL) {
free(sce->ibuf, M_USBDEV); free(sce->ibuf, M_USBDEV);
sce->ibuf = NULL; sce->ibuf = NULL;
clfree(&sce->q);
} }
} }
sc->sc_is_open[endpt] = 0; sc->sc_is_open[endpt] = 0;
@ -554,7 +557,7 @@ ugenclose(dev_t dev, int flag, int mode, struct thread *td)
Static int Static int
ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag) ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
{ {
struct ugen_endpoint *sce; struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
u_int32_t n, tn; u_int32_t n, tn;
char buf[UGEN_BBSIZE]; char buf[UGEN_BBSIZE];
usbd_xfer_handle xfer; usbd_xfer_handle xfer;
@ -571,13 +574,21 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
if (endpt == USB_CONTROL_ENDPOINT) if (endpt == USB_CONTROL_ENDPOINT)
return (ENODEV); return (ENODEV);
sce = &sc->sc_endpoints[endpt][IN]; if (sce == NULL)
if (sce == NULL || sce->edesc == NULL || sce->pipeh == NULL)
return (EINVAL); return (EINVAL);
if (sce->edesc == NULL) {
printf("ugenread: no edesc\n");
return (EIO);
}
if (sce->pipeh == NULL) {
printf("ugenread: no pipe\n");
return (EIO);
}
switch (sce->edesc->bmAttributes & UE_XFERTYPE) { switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
case UE_INTERRUPT: case UE_INTERRUPT:
/* Block until activity occured. */ /* Block until activity occurred. */
s = splusb(); s = splusb();
while (sce->q.c_cc == 0) { while (sce->q.c_cc == 0) {
if (flag & IO_NDELAY) { if (flag & IO_NDELAY) {
@ -585,7 +596,7 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
return (EWOULDBLOCK); return (EWOULDBLOCK);
} }
sce->state |= UGEN_ASLP; sce->state |= UGEN_ASLP;
DPRINTFN(5, ("ugenread: sleep on %p\n", sc)); DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
error = tsleep(sce, PZERO | PCATCH, "ugenri", 0); error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
DPRINTFN(5, ("ugenread: woke, error=%d\n", error)); DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
if (sc->sc_dying) if (sc->sc_dying)
@ -649,7 +660,7 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
return (EWOULDBLOCK); return (EWOULDBLOCK);
} }
sce->state |= UGEN_ASLP; sce->state |= UGEN_ASLP;
DPRINTFN(5, ("ugenread: sleep on %p\n", sc)); DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
error = tsleep(sce, PZERO | PCATCH, "ugenri", 0); error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
DPRINTFN(5, ("ugenread: woke, error=%d\n", error)); DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
if (sc->sc_dying) if (sc->sc_dying)
@ -705,14 +716,14 @@ ugenread(dev_t dev, struct uio *uio, int flag)
Static int Static int
ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag) ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
{ {
struct ugen_endpoint *sce; struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
u_int32_t n; u_int32_t n;
int error = 0; int error = 0;
char buf[UGEN_BBSIZE]; char buf[UGEN_BBSIZE];
usbd_xfer_handle xfer; usbd_xfer_handle xfer;
usbd_status err; usbd_status err;
DPRINTFN(5, ("%s: ugen_do_write: %d\n", USBDEVNAME(sc->sc_dev), endpt)); DPRINTFN(5, ("%s: ugenwrite: %d\n", USBDEVNAME(sc->sc_dev), endpt));
if (sc->sc_dying) if (sc->sc_dying)
return (EIO); return (EIO);
@ -720,10 +731,18 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
if (endpt == USB_CONTROL_ENDPOINT) if (endpt == USB_CONTROL_ENDPOINT)
return (ENODEV); return (ENODEV);
sce = &sc->sc_endpoints[endpt][OUT]; if (sce == NULL)
if (sce == NULL || sce->edesc == NULL || sce->pipeh == NULL)
return (EINVAL); return (EINVAL);
if (sce->edesc == NULL) {
printf("ugenwrite: no edesc\n");
return (EIO);
}
if (sce->pipeh == NULL) {
printf("ugenwrite: no pipe\n");
return (EIO);
}
switch (sce->edesc->bmAttributes & UE_XFERTYPE) { switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
case UE_BULK: case UE_BULK:
xfer = usbd_alloc_xfer(sc->sc_udev); xfer = usbd_alloc_xfer(sc->sc_udev);
@ -733,12 +752,14 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
error = uiomove(buf, n, uio); error = uiomove(buf, n, uio);
if (error) if (error)
break; break;
DPRINTFN(1, ("ugen_do_write: transfer %d bytes\n", n)); 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"); sce->timeout, buf, &n,"ugenwb");
if (err) { if (err) {
if (err == USBD_INTERRUPTED) if (err == USBD_INTERRUPTED)
error = EINTR; error = EINTR;
else if (err == USBD_TIMEOUT)
error = ETIMEDOUT;
else else
error = EIO; error = EIO;
break; break;
@ -891,6 +912,7 @@ ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
struct isoreq *req = addr; struct isoreq *req = addr;
struct ugen_endpoint *sce = req->sce; struct ugen_endpoint *sce = req->sce;
u_int32_t count, n; u_int32_t count, n;
int i, isize;
/* Return if we are aborting. */ /* Return if we are aborting. */
if (status == USBD_CANCELLED) if (status == USBD_CANCELLED)
@ -909,15 +931,25 @@ ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
count)); count));
} }
/* copy data to buffer */ isize = UGETW(sce->edesc->wMaxPacketSize);
while (count > 0) { for (i = 0; i < UGEN_NISORFRMS; i++) {
n = min(count, sce->limit - sce->fill); u_int32_t actlen = req->sizes[i];
memcpy(sce->fill, req->dmabuf, n); char const *buf = (char const *)req->dmabuf + isize * i;
count -= n; /* copy data to buffer */
sce->fill += n; while (actlen > 0) {
if(sce->fill == sce->limit) n = min(actlen, sce->limit - sce->fill);
sce->fill = sce->ibuf; memcpy(sce->fill, buf, n);
buf += n;
actlen -= n;
sce->fill += n;
if(sce->fill == sce->limit)
sce->fill = sce->ibuf;
}
/* setup size for next transfer */
req->sizes[i] = isize;
} }
usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS, usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS,
@ -956,6 +988,7 @@ ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
err = usbd_endpoint_count(iface, &nendpt); err = usbd_endpoint_count(iface, &nendpt);
if (err) if (err)
return (err); return (err);
/* XXX should only do this after setting new altno has succeeded */
for (endptno = 0; endptno < nendpt; endptno++) { for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno); ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress; endpt = ed->bEndpointAddress;
@ -1064,27 +1097,30 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
sce = &sc->sc_endpoints[endpt][IN]; sce = &sc->sc_endpoints[endpt][IN];
if (sce == NULL) if (sce == NULL)
return (EINVAL); return (EINVAL);
#ifdef DIAGNOSTIC
if (sce->pipeh == NULL) { if (sce->pipeh == NULL) {
printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n"); printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n");
return (EIO); return (EIO);
} }
#endif
if (*(int *)addr) if (*(int *)addr)
sce->state |= UGEN_SHORT_OK; sce->state |= UGEN_SHORT_OK;
else else
sce->state &= ~UGEN_SHORT_OK; sce->state &= ~UGEN_SHORT_OK;
return (0); return (0);
case USB_SET_TIMEOUT: case USB_SET_TIMEOUT:
if (endpt == USB_CONTROL_ENDPOINT) {
/* XXX the lower levels don't support this yet. */
return (EINVAL);
}
sce = &sc->sc_endpoints[endpt][IN]; sce = &sc->sc_endpoints[endpt][IN];
if (sce == NULL) if (sce == NULL)
return (EINVAL); return (EINVAL);
#ifdef DIAGNOSTIC
if (sce->pipeh == NULL) { if (sce->pipeh == NULL) {
printf("ugenioctl: USB_SET_TIMEOUT, no pipe\n"); printf("ugenioctl: USB_SET_TIMEOUT, no pipe\n");
return (EIO); return (EIO);
} }
#endif
sce->timeout = *(int *)addr; sce->timeout = *(int *)addr;
return (0); return (0);
default: default:
@ -1340,9 +1376,18 @@ ugenpoll(dev_t dev, int events, struct thread *td)
/* XXX always IN */ /* XXX always IN */
sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN]; sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
if (sce == NULL || sce->edesc == NULL || sce->pipeh == NULL) if (sce == NULL)
return (EINVAL); return (EINVAL);
if (!sce->edesc) {
printf("ugenpoll: no edesc\n");
return (EIO);
}
if (!sce->pipeh) {
printf("ugenpoll: no pipe\n");
return (EIO);
}
s = splusb(); s = splusb();
switch (sce->edesc->bmAttributes & UE_XFERTYPE) { switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
case UE_INTERRUPT: case UE_INTERRUPT: