aboutsummaryrefslogtreecommitdiff
path: root/hw/usb
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-06-02 17:07:21 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-06-02 17:07:21 +0100
commit82ea61c6da4daa81d8614297391b8087e806ded9 (patch)
tree5e5bcd8610952ca6b11e0af70d8d011563321167 /hw/usb
parent1673e89e93e08cbfee7c9b552008e5b39469ad0e (diff)
parent7bafd8889ea3599285a8fcb1262d50e52d941c0e (diff)
downloadqemu-82ea61c6da4daa81d8614297391b8087e806ded9.zip
qemu-82ea61c6da4daa81d8614297391b8087e806ded9.tar.gz
qemu-82ea61c6da4daa81d8614297391b8087e806ded9.tar.bz2
Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-8' into staging
qtest: improve ehci/uhci test usb: misc fixes, mostly for usb3/xhci # gpg: Signature made Mon 02 Jun 2014 15:40:34 BST using RSA key ID D3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" * remotes/kraxel/tags/pull-usb-8: xhci: order superspeed ports first xhci: make port reset trace point more verbose usb: add usb_pick_speed usb-host: add HAVE_STREAMS define usb-host: allow attaching usb3 devices to ehci usb: improve ehci/uhci test usb: move ehci register defines to header file usb: add uhci port status reserved bit usb: move uhci register defines to header file qtest: fix qpci_config_writel Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/usb')
-rw-r--r--hw/usb/core.c21
-rw-r--r--hw/usb/desc.c12
-rw-r--r--hw/usb/hcd-ehci.c79
-rw-r--r--hw/usb/hcd-uhci.c36
-rw-r--r--hw/usb/hcd-xhci.c47
-rw-r--r--hw/usb/host-libusb.c76
6 files changed, 124 insertions, 147 deletions
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 67ba7d6..cf34755 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -28,6 +28,26 @@
#include "qemu/iov.h"
#include "trace.h"
+void usb_pick_speed(USBPort *port)
+{
+ static const int speeds[] = {
+ USB_SPEED_SUPER,
+ USB_SPEED_HIGH,
+ USB_SPEED_FULL,
+ USB_SPEED_LOW,
+ };
+ USBDevice *udev = port->dev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(speeds); i++) {
+ if ((udev->speedmask & (1 << speeds[i])) &&
+ (port->speedmask & (1 << speeds[i]))) {
+ udev->speed = speeds[i];
+ return;
+ }
+ }
+}
+
void usb_attach(USBPort *port)
{
USBDevice *dev = port->dev;
@@ -35,6 +55,7 @@ void usb_attach(USBPort *port)
assert(dev != NULL);
assert(dev->attached);
assert(dev->state == USB_STATE_NOTATTACHED);
+ usb_pick_speed(port);
port->ops->attach(port);
dev->state = USB_STATE_ATTACHED;
usb_device_handle_attach(dev);
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index ab48691..b82c397 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -518,18 +518,6 @@ void usb_desc_init(USBDevice *dev)
void usb_desc_attach(USBDevice *dev)
{
- const USBDesc *desc = usb_device_get_usb_desc(dev);
-
- assert(desc != NULL);
- if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) {
- dev->speed = USB_SPEED_SUPER;
- } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
- dev->speed = USB_SPEED_HIGH;
- } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
- dev->speed = USB_SPEED_FULL;
- } else {
- return;
- }
usb_desc_setdefaults(dev);
}
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index a3ae9f2..a00a93c 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -27,87 +27,10 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "hw/usb/ehci-regs.h"
#include "hw/usb/hcd-ehci.h"
#include "trace.h"
-/* Capability Registers Base Address - section 2.2 */
-#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
-#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
-#define HCSPARAMS 0x0004 /* 4-bytes, structural params */
-#define HCCPARAMS 0x0008 /* 4-bytes, capability params */
-#define EECP HCCPARAMS + 1
-#define HCSPPORTROUTE1 0x000c
-#define HCSPPORTROUTE2 0x0010
-
-#define USBCMD 0x0000
-#define USBCMD_RUNSTOP (1 << 0) // run / Stop
-#define USBCMD_HCRESET (1 << 1) // HC Reset
-#define USBCMD_FLS (3 << 2) // Frame List Size
-#define USBCMD_FLS_SH 2 // Frame List Size Shift
-#define USBCMD_PSE (1 << 4) // Periodic Schedule Enable
-#define USBCMD_ASE (1 << 5) // Asynch Schedule Enable
-#define USBCMD_IAAD (1 << 6) // Int Asynch Advance Doorbell
-#define USBCMD_LHCR (1 << 7) // Light Host Controller Reset
-#define USBCMD_ASPMC (3 << 8) // Async Sched Park Mode Count
-#define USBCMD_ASPME (1 << 11) // Async Sched Park Mode Enable
-#define USBCMD_ITC (0x7f << 16) // Int Threshold Control
-#define USBCMD_ITC_SH 16 // Int Threshold Control Shift
-
-#define USBSTS 0x0004
-#define USBSTS_RO_MASK 0x0000003f
-#define USBSTS_INT (1 << 0) // USB Interrupt
-#define USBSTS_ERRINT (1 << 1) // Error Interrupt
-#define USBSTS_PCD (1 << 2) // Port Change Detect
-#define USBSTS_FLR (1 << 3) // Frame List Rollover
-#define USBSTS_HSE (1 << 4) // Host System Error
-#define USBSTS_IAA (1 << 5) // Interrupt on Async Advance
-#define USBSTS_HALT (1 << 12) // HC Halted
-#define USBSTS_REC (1 << 13) // Reclamation
-#define USBSTS_PSS (1 << 14) // Periodic Schedule Status
-#define USBSTS_ASS (1 << 15) // Asynchronous Schedule Status
-
-/*
- * Interrupt enable bits correspond to the interrupt active bits in USBSTS
- * so no need to redefine here.
- */
-#define USBINTR 0x0008
-#define USBINTR_MASK 0x0000003f
-
-#define FRINDEX 0x000c
-#define CTRLDSSEGMENT 0x0010
-#define PERIODICLISTBASE 0x0014
-#define ASYNCLISTADDR 0x0018
-#define ASYNCLISTADDR_MASK 0xffffffe0
-
-#define CONFIGFLAG 0x0040
-
-/*
- * Bits that are reserved or are read-only are masked out of values
- * written to us by software
- */
-#define PORTSC_RO_MASK 0x007001c0
-#define PORTSC_RWC_MASK 0x0000002a
-#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
-#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
-#define PORTSC_WKCN_E (1 << 20) // Wake on Connect Enable
-#define PORTSC_PTC (15 << 16) // Port Test Control
-#define PORTSC_PTC_SH 16 // Port Test Control shift
-#define PORTSC_PIC (3 << 14) // Port Indicator Control
-#define PORTSC_PIC_SH 14 // Port Indicator Control Shift
-#define PORTSC_POWNER (1 << 13) // Port Owner
-#define PORTSC_PPOWER (1 << 12) // Port Power
-#define PORTSC_LINESTAT (3 << 10) // Port Line Status
-#define PORTSC_LINESTAT_SH 10 // Port Line Status Shift
-#define PORTSC_PRESET (1 << 8) // Port Reset
-#define PORTSC_SUSPEND (1 << 7) // Port Suspend
-#define PORTSC_FPRES (1 << 6) // Force Port Resume
-#define PORTSC_OCC (1 << 5) // Over Current Change
-#define PORTSC_OCA (1 << 4) // Over Current Active
-#define PORTSC_PEDC (1 << 3) // Port Enable/Disable Change
-#define PORTSC_PED (1 << 2) // Port Enable/Disable
-#define PORTSC_CSC (1 << 1) // Connect Status Change
-#define PORTSC_CONNECT (1 << 0) // Current Connect Status
-
#define FRAME_TIMER_FREQ 1000
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 9b1166b..c3bf72c 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -27,6 +27,7 @@
*/
#include "hw/hw.h"
#include "hw/usb.h"
+#include "hw/usb/uhci-regs.h"
#include "hw/pci/pci.h"
#include "qemu/timer.h"
#include "qemu/iov.h"
@@ -37,41 +38,6 @@
//#define DEBUG
//#define DEBUG_DUMP_DATA
-#define UHCI_CMD_FGR (1 << 4)
-#define UHCI_CMD_EGSM (1 << 3)
-#define UHCI_CMD_GRESET (1 << 2)
-#define UHCI_CMD_HCRESET (1 << 1)
-#define UHCI_CMD_RS (1 << 0)
-
-#define UHCI_STS_HCHALTED (1 << 5)
-#define UHCI_STS_HCPERR (1 << 4)
-#define UHCI_STS_HSERR (1 << 3)
-#define UHCI_STS_RD (1 << 2)
-#define UHCI_STS_USBERR (1 << 1)
-#define UHCI_STS_USBINT (1 << 0)
-
-#define TD_CTRL_SPD (1 << 29)
-#define TD_CTRL_ERROR_SHIFT 27
-#define TD_CTRL_IOS (1 << 25)
-#define TD_CTRL_IOC (1 << 24)
-#define TD_CTRL_ACTIVE (1 << 23)
-#define TD_CTRL_STALL (1 << 22)
-#define TD_CTRL_BABBLE (1 << 20)
-#define TD_CTRL_NAK (1 << 19)
-#define TD_CTRL_TIMEOUT (1 << 18)
-
-#define UHCI_PORT_SUSPEND (1 << 12)
-#define UHCI_PORT_RESET (1 << 9)
-#define UHCI_PORT_LSDA (1 << 8)
-#define UHCI_PORT_RD (1 << 6)
-#define UHCI_PORT_ENC (1 << 3)
-#define UHCI_PORT_EN (1 << 2)
-#define UHCI_PORT_CSC (1 << 1)
-#define UHCI_PORT_CCS (1 << 0)
-
-#define UHCI_PORT_READ_ONLY (0x1bb)
-#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC)
-
#define FRAME_TIMER_FREQ 1000
#define FRAME_MAX_LOOPS 256
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 54dea16..7f2af89 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -498,6 +498,7 @@ typedef struct XHCIEvRingSeg {
enum xhci_flags {
XHCI_FLAG_USE_MSI = 1,
XHCI_FLAG_USE_MSI_X,
+ XHCI_FLAG_SS_FIRST,
};
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
@@ -714,10 +715,18 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
case USB_SPEED_LOW:
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
- index = uport->index;
+ if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+ index = uport->index + xhci->numports_3;
+ } else {
+ index = uport->index;
+ }
break;
case USB_SPEED_SUPER:
- index = uport->index + xhci->numports_2;
+ if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+ index = uport->index;
+ } else {
+ index = uport->index + xhci->numports_2;
+ }
break;
default:
return NULL;
@@ -2856,7 +2865,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach)
static void xhci_port_reset(XHCIPort *port, bool warm_reset)
{
- trace_usb_xhci_port_reset(port->portnr);
+ trace_usb_xhci_port_reset(port->portnr, warm_reset);
if (!xhci_port_have_device(port)) {
return;
@@ -2972,7 +2981,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
ret = 0x20425355; /* "USB " */
break;
case 0x28: /* Supported Protocol:08 */
- ret = 0x00000001 | (xhci->numports_2<<8);
+ if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+ ret = (xhci->numports_2<<8) | (xhci->numports_3+1);
+ } else {
+ ret = (xhci->numports_2<<8) | 1;
+ }
break;
case 0x2c: /* Supported Protocol:0c */
ret = 0x00000000; /* reserved */
@@ -2984,7 +2997,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
ret = 0x20425355; /* "USB " */
break;
case 0x38: /* Supported Protocol:08 */
- ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8);
+ if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+ ret = (xhci->numports_3<<8) | 1;
+ } else {
+ ret = (xhci->numports_3<<8) | (xhci->numports_2+1);
+ }
break;
case 0x3c: /* Supported Protocol:0c */
ret = 0x00000000; /* reserved */
@@ -3517,8 +3534,13 @@ static void usb_xhci_init(XHCIState *xhci)
for (i = 0; i < usbports; i++) {
speedmask = 0;
if (i < xhci->numports_2) {
- port = &xhci->ports[i];
- port->portnr = i + 1;
+ if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+ port = &xhci->ports[i + xhci->numports_3];
+ port->portnr = i + 1 + xhci->numports_3;
+ } else {
+ port = &xhci->ports[i];
+ port->portnr = i + 1;
+ }
port->uport = &xhci->uports[i];
port->speedmask =
USB_SPEED_MASK_LOW |
@@ -3528,8 +3550,13 @@ static void usb_xhci_init(XHCIState *xhci)
speedmask |= port->speedmask;
}
if (i < xhci->numports_3) {
- port = &xhci->ports[i + xhci->numports_2];
- port->portnr = i + 1 + xhci->numports_2;
+ if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+ port = &xhci->ports[i];
+ port->portnr = i + 1;
+ } else {
+ port = &xhci->ports[i + xhci->numports_2];
+ port->portnr = i + 1 + xhci->numports_2;
+ }
port->uport = &xhci->uports[i];
port->speedmask = USB_SPEED_MASK_SUPER;
snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
@@ -3788,6 +3815,8 @@ static const VMStateDescription vmstate_xhci = {
static Property xhci_properties[] = {
DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
+ DEFINE_PROP_BIT("superspeed-ports-first",
+ XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 8007d1d..afbf156 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -111,6 +111,7 @@ struct USBHostRequest {
unsigned char *buffer;
unsigned char *cbuf;
unsigned int clen;
+ bool usb3ep0quirk;
QTAILQ_ENTRY(USBHostRequest) next;
};
@@ -146,6 +147,10 @@ static void usb_host_attach_kernel(USBHostDevice *s);
#define BULK_TIMEOUT 0 /* unlimited */
#define INTR_TIMEOUT 0 /* unlimited */
+#if LIBUSBX_API_VERSION >= 0x01000103
+# define HAVE_STREAMS 1
+#endif
+
static const char *speed_name[] = {
[LIBUSB_SPEED_UNKNOWN] = "?",
[LIBUSB_SPEED_LOW] = "1.5",
@@ -346,6 +351,13 @@ static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
r->p->actual_length = xfer->actual_length;
if (r->in && xfer->actual_length) {
memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
+
+ /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
+ * to work redirected to a not superspeed capable hcd */
+ if (r->usb3ep0quirk && xfer->actual_length >= 18 &&
+ r->cbuf[7] == 9) {
+ r->cbuf[7] = 64;
+ }
}
trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
r->p->status, r->p->actual_length);
@@ -672,11 +684,17 @@ static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p)
/* ------------------------------------------------------------------------ */
-static bool usb_host_full_speed_compat(USBHostDevice *s)
+static void usb_host_speed_compat(USBHostDevice *s)
{
+ USBDevice *udev = USB_DEVICE(s);
struct libusb_config_descriptor *conf;
const struct libusb_interface_descriptor *intf;
const struct libusb_endpoint_descriptor *endp;
+#ifdef HAVE_STREAMS
+ struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
+#endif
+ bool compat_high = true;
+ bool compat_full = true;
uint8_t type;
int rc, c, i, a, e;
@@ -693,10 +711,27 @@ static bool usb_host_full_speed_compat(USBHostDevice *s)
type = endp->bmAttributes & 0x3;
switch (type) {
case 0x01: /* ISO */
- return false;
+ compat_full = false;
+ compat_high = false;
+ break;
+ case 0x02: /* BULK */
+#ifdef HAVE_STREAMS
+ rc = libusb_get_ss_endpoint_companion_descriptor
+ (ctx, endp, &endp_ss_comp);
+ if (rc == LIBUSB_SUCCESS) {
+ libusb_free_ss_endpoint_companion_descriptor
+ (endp_ss_comp);
+ compat_full = false;
+ compat_high = false;
+ }
+#endif
+ break;
case 0x03: /* INTERRUPT */
if (endp->wMaxPacketSize > 64) {
- return false;
+ compat_full = false;
+ }
+ if (endp->wMaxPacketSize > 1024) {
+ compat_high = false;
}
break;
}
@@ -705,7 +740,17 @@ static bool usb_host_full_speed_compat(USBHostDevice *s)
}
libusb_free_config_descriptor(conf);
}
- return true;
+
+ udev->speedmask = (1 << udev->speed);
+ if (udev->speed == USB_SPEED_SUPER && compat_high) {
+ udev->speedmask |= USB_SPEED_HIGH;
+ }
+ if (udev->speed == USB_SPEED_SUPER && compat_full) {
+ udev->speedmask |= USB_SPEED_FULL;
+ }
+ if (udev->speed == USB_SPEED_HIGH && compat_full) {
+ udev->speedmask |= USB_SPEED_FULL;
+ }
}
static void usb_host_ep_update(USBHostDevice *s)
@@ -720,7 +765,7 @@ static void usb_host_ep_update(USBHostDevice *s)
struct libusb_config_descriptor *conf;
const struct libusb_interface_descriptor *intf;
const struct libusb_endpoint_descriptor *endp;
-#if LIBUSBX_API_VERSION >= 0x01000103
+#ifdef HAVE_STREAMS
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
#endif
uint8_t devep, type;
@@ -768,7 +813,7 @@ static void usb_host_ep_update(USBHostDevice *s)
usb_ep_set_type(udev, pid, ep, type);
usb_ep_set_ifnum(udev, pid, ep, i);
usb_ep_set_halted(udev, pid, ep, 0);
-#if LIBUSBX_API_VERSION >= 0x01000103
+#ifdef HAVE_STREAMS
if (type == LIBUSB_TRANSFER_TYPE_BULK &&
libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
&endp_ss_comp) == LIBUSB_SUCCESS) {
@@ -813,10 +858,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev)
usb_host_ep_update(s);
udev->speed = speed_map[libusb_get_device_speed(dev)];
- udev->speedmask = (1 << udev->speed);
- if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) {
- udev->speedmask |= USB_SPEED_MASK_FULL;
- }
+ usb_host_speed_compat(s);
if (s->ddesc.iProduct) {
libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
@@ -1162,6 +1204,14 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
memcpy(r->buffer + 8, r->cbuf, r->clen);
}
+ /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
+ * to work redirected to a not superspeed capable hcd */
+ if (udev->speed == USB_SPEED_SUPER &&
+ !((udev->port->speedmask & USB_SPEED_MASK_SUPER)) &&
+ request == 0x8006 && value == 0x100 && index == 0) {
+ r->usb3ep0quirk = true;
+ }
+
libusb_fill_control_transfer(r->xfer, s->dh, r->buffer,
usb_host_req_complete_ctrl, r,
CONTROL_TIMEOUT);
@@ -1215,7 +1265,7 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
}
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
if (p->stream) {
-#if LIBUSBX_API_VERSION >= 0x01000103
+#ifdef HAVE_STREAMS
libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
r->buffer, size,
usb_host_req_complete_data, r,
@@ -1296,7 +1346,7 @@ static void usb_host_handle_reset(USBDevice *udev)
static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
int nr_eps, int streams)
{
-#if LIBUSBX_API_VERSION >= 0x01000103
+#ifdef HAVE_STREAMS
USBHostDevice *s = USB_HOST_DEVICE(udev);
unsigned char endpoints[30];
int i, rc;
@@ -1326,7 +1376,7 @@ static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
int nr_eps)
{
-#if LIBUSBX_API_VERSION >= 0x01000103
+#ifdef HAVE_STREAMS
USBHostDevice *s = USB_HOST_DEVICE(udev);
unsigned char endpoints[30];
int i;