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:
parent
200281abc1
commit
6035292097
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=88728
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user