Module Name: src
Committed By: pooka
Date: Mon Mar 22 12:05:45 UTC 2010
Modified Files:
src/sys/rump/dev/lib/libugenhc: ugenhc.c
Log Message:
* support isochronous transfers (for as much as they can be supported
considering our ugen driver doesn't support isochronous write.
kern/25960 seems to contain a patch and could be investigated for that)
* add a dirty rotten hack which makes interrupt transfers of >16
work for me
To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/sys/rump/dev/lib/libugenhc/ugenhc.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/rump/dev/lib/libugenhc/ugenhc.c
diff -u src/sys/rump/dev/lib/libugenhc/ugenhc.c:1.8 src/sys/rump/dev/lib/libugenhc/ugenhc.c:1.9
--- src/sys/rump/dev/lib/libugenhc/ugenhc.c:1.8 Tue Feb 23 14:05:04 2010
+++ src/sys/rump/dev/lib/libugenhc/ugenhc.c Mon Mar 22 12:05:45 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: ugenhc.c,v 1.8 2010/02/23 14:05:04 pooka Exp $ */
+/* $NetBSD: ugenhc.c,v 1.9 2010/03/22 12:05:45 pooka Exp $ */
/*
* Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.8 2010/02/23 14:05:04 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.9 2010/03/22 12:05:45 pooka Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -506,6 +506,7 @@
case C(0x22, UT_WRITE_CLASS_INTERFACE):
case C(0x0a, UT_WRITE_CLASS_INTERFACE):
case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
+ case C(0x00, UT_WRITE_CLASS_DEVICE):
case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
case C(UR_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
@@ -718,40 +719,46 @@
rumpusb_device_bulk_start(usbd_xfer_handle xfer)
{
struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
+ usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
ssize_t n;
ssize_t done;
bool isread;
int len, error, endpt;
uint8_t *buf;
int xfererr = USBD_NORMAL_COMPLETION;
- int val;
+ int shortval, i;
- endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
+ ed = xfer->pipe->endpoint->edesc;
+ endpt = ed->bEndpointAddress;
isread = UE_GET_DIR(endpt) == UE_DIR_IN;
endpt = UE_GET_ADDR(endpt);
KASSERT(endpt < UGEN_NEPTS);
- KASSERT(xfer->length);
- len = xfer->length;
buf = KERNADDR(&xfer->dmabuf, 0);
done = 0;
+ if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) {
+ for (i = 0, len = 0; i < xfer->nframes; i++)
+ len += xfer->frlengths[i];
+ } else {
+ KASSERT(xfer->length);
+ len = xfer->length;
+ }
+ shortval = (xfer->flags & USBD_SHORT_XFER_OK) != 0;
while (RUSB(xfer)->rusb_status == 0) {
if (isread) {
- if (xfer->flags & USBD_SHORT_XFER_OK)
- val = 1;
- else
- val = 0;
rumpuser_ioctl(sc->sc_ugenfd[endpt],
- USB_SET_SHORT_XFER, &val, &error);
+ USB_SET_SHORT_XFER, &shortval, &error);
n = rumpuser_read(sc->sc_ugenfd[endpt],
buf+done, len-done, &error);
if (n == -1) {
- if (error == ETIMEDOUT)
- continue;
n = 0;
- xfererr = USBD_IOERROR;
- goto out;
+ if (done == 0) {
+ if (error == ETIMEDOUT)
+ continue;
+ xfererr = USBD_IOERROR;
+ goto out;
+ }
}
done += n;
if (done == len)
@@ -769,8 +776,23 @@
goto out;
}
- if (xfer->flags & USBD_SHORT_XFER_OK)
- break;
+ if (shortval) {
+ /*
+ * Holy XXX, bitman. I get >16byte interrupt
+ * transfers from ugen in 16 byte chunks.
+ * Don't know how to better fix this for now.
+ * Of course this hack will fail e.g. if someone
+ * sports other magic values or if the transfer
+ * happens to be an integral multiple of 16
+ * in size ....
+ */
+ if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT
+ && n == 16) {
+ continue;
+ } else {
+ break;
+ }
+ }
}
if (RUSB(xfer)->rusb_status == 0) {
@@ -780,6 +802,9 @@
RUSB(xfer)->rusb_status = 2;
}
out:
+ if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS)
+ if (done != len)
+ panic("lazy bum");
xfer->status = xfererr;
usb_transfer_complete(xfer);
return (USBD_IN_PROGRESS);
@@ -918,6 +943,7 @@
break;
case UE_INTERRUPT:
case UE_BULK:
+ case UE_ISOCHRONOUS:
pipe->methods = &rumpusb_device_bulk_methods;
endpt = pipe->endpoint->edesc->bEndpointAddress;
if (UE_GET_DIR(endpt) == UE_DIR_IN) {
@@ -927,6 +953,11 @@
}
endpt = UE_GET_ADDR(endpt);
+ if (oflags != O_RDONLY && xfertype == UE_ISOCHRONOUS) {
+ printf("WARNING: faking isoc write open\n");
+ oflags = O_RDONLY;
+ }
+
if (sc->sc_fdmodes[endpt] == oflags
|| sc->sc_fdmodes[endpt] == O_RDWR)
break;
@@ -939,14 +970,16 @@
makeugendevstr(sc->sc_devnum, endpt, buf);
fd = rumpuser_open(buf, oflags, &error);
- if (fd == -1)
+ if (fd == -1) {
return USBD_INVAL; /* XXX: no mapping */
+ }
val = 100;
if (rumpuser_ioctl(fd, USB_SET_TIMEOUT, &val,
&error) == -1)
panic("timeout set failed");
sc->sc_ugenfd[endpt] = fd;
sc->sc_fdmodes[endpt] = oflags;
+
break;
default:
panic("%d not supported", xfertype);