aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-02-21 09:39:17 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2013-02-21 09:39:17 -0600
commit70aa41b56ce3f34fceac44e828ba2d8cc19523ee (patch)
tree360b9559d0ed7faa747da79e5ae2958e933cb785
parent259dc0c1ce8eef14e5e0c349bc68ba05c9d5d82f (diff)
parent89a453d4a5c195e6d0a3c3d4fcaacb447447115f (diff)
downloadqemu-arm-70aa41b56ce3f34fceac44e828ba2d8cc19523ee.tar.gz
Merge remote-tracking branch 'kraxel/usb.78' into staging
# By Gerd Hoffmann # Via Gerd Hoffmann * kraxel/usb.78: uas-uas: usb3 streams usb-xhci: usb3 streams usb-core: usb3 streams usb: fix endpoint descriptor ordering usb-redir: simplify packet copy usb: make usb_packet_copy operate on combined packets usb: add usb_ep_set_halted usb-host: remove usb_host_device_close usb-host: move legacy cmd line bits usb-storage: use scsi_req_enqueue return value allow disabling usb smartcard support make usb devices configurable fix scripts/make_device_config.sh usb: Makefile cleanup
-rwxr-xr-xconfigure2
-rw-r--r--default-configs/alpha-softmmu.mak1
-rw-r--r--default-configs/arm-softmmu.mak1
-rw-r--r--default-configs/i386-softmmu.mak1
-rw-r--r--default-configs/m68k-softmmu.mak1
-rw-r--r--default-configs/mips-softmmu.mak1
-rw-r--r--default-configs/mips64-softmmu.mak1
-rw-r--r--default-configs/mips64el-softmmu.mak1
-rw-r--r--default-configs/mipsel-softmmu.mak1
-rw-r--r--default-configs/ppc-softmmu.mak1
-rw-r--r--default-configs/ppc64-softmmu.mak1
-rw-r--r--default-configs/ppcemb-softmmu.mak1
-rw-r--r--default-configs/sh4-softmmu.mak1
-rw-r--r--default-configs/sh4eb-softmmu.mak1
-rw-r--r--default-configs/sparc64-softmmu.mak1
-rw-r--r--default-configs/usb.mak8
-rw-r--r--default-configs/x86_64-softmmu.mak1
-rw-r--r--hw/Makefile.objs2
-rw-r--r--hw/usb.h13
-rw-r--r--hw/usb/Makefile.objs30
-rw-r--r--hw/usb/core.c35
-rw-r--r--hw/usb/desc.c9
-rw-r--r--hw/usb/dev-bluetooth.c2
-rw-r--r--hw/usb/dev-hid.c2
-rw-r--r--hw/usb/dev-hub.c10
-rw-r--r--hw/usb/dev-network.c2
-rw-r--r--hw/usb/dev-smartcard-reader.c2
-rw-r--r--hw/usb/dev-storage.c5
-rw-r--r--hw/usb/dev-uas.c247
-rw-r--r--hw/usb/dev-wacom.c4
-rw-r--r--hw/usb/hcd-ehci.c7
-rw-r--r--hw/usb/hcd-musb.c2
-rw-r--r--hw/usb/hcd-ohci.c4
-rw-r--r--hw/usb/hcd-uhci.c2
-rw-r--r--hw/usb/hcd-xhci.c275
-rw-r--r--hw/usb/host-bsd.c6
-rw-r--r--hw/usb/host-legacy.c144
-rw-r--r--hw/usb/host-linux.c125
-rw-r--r--hw/usb/host-stub.c5
-rw-r--r--hw/usb/host.h44
-rw-r--r--hw/usb/redirect.c18
-rw-r--r--scripts/make_device_config.sh2
-rw-r--r--trace-events6
-rw-r--r--vl.c5
44 files changed, 742 insertions, 291 deletions
diff --git a/configure b/configure
index bf5970f74b..42cb3144a5 100755
--- a/configure
+++ b/configure
@@ -3723,7 +3723,7 @@ fi
# USB host support
case "$usb" in
linux)
- echo "HOST_USB=linux" >> $config_host_mak
+ echo "HOST_USB=linux legacy" >> $config_host_mak
;;
bsd)
echo "HOST_USB=bsd" >> $config_host_mak
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
index 501dd413b7..2dbee94c89 100644
--- a/default-configs/alpha-softmmu.mak
+++ b/default-configs/alpha-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for alpha-softmmu
include pci.mak
+include usb.mak
CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 2f1a5c9943..b40f7b08e2 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for arm-softmmu
include pci.mak
+include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_VGA=y
CONFIG_ISA_MMIO=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 2c78175ae7..1b23025a98 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for i386-softmmu
include pci.mak
+include usb.mak
CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
index 3e2ec3716c..778ea82a10 100644
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -1,5 +1,6 @@
# Default configuration for m68k-softmmu
include pci.mak
+include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_PTIMER=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index a271b1c6da..4f04a33732 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for mips-softmmu
include pci.mak
+include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index 0510bb6a53..a5b6c3c36a 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for mips64-softmmu
include pci.mak
+include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index ed3bed3b8d..a0e6de8e68 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for mips64el-softmmu
include pci.mak
+include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index fa3a2cacdd..753dd76a21 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for mipsel-softmmu
include pci.mak
+include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 1f4a1cff61..f9f8a8159b 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for ppc-softmmu
include pci.mak
+include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index 5ff406caa5..dc44294378 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for ppc64-softmmu
include pci.mak
+include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index aaa9cdc1f7..1c6bcf93fc 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for ppcemb-softmmu
include pci.mak
+include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak
index 5c69acc5f5..e08b2ee106 100644
--- a/default-configs/sh4-softmmu.mak
+++ b/default-configs/sh4-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for sh4-softmmu
include pci.mak
+include usb.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak
index 7cdc122201..3a8453552b 100644
--- a/default-configs/sh4eb-softmmu.mak
+++ b/default-configs/sh4eb-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for sh4eb-softmmu
include pci.mak
+include usb.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index 03e8b42712..2145b6b29f 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for sparc64-softmmu
include pci.mak
+include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_M48T59=y
CONFIG_PTIMER=y
diff --git a/default-configs/usb.mak b/default-configs/usb.mak
new file mode 100644
index 0000000000..1bf9075e85
--- /dev/null
+++ b/default-configs/usb.mak
@@ -0,0 +1,8 @@
+CONFIG_USB_TABLET_WACOM=y
+CONFIG_USB_STORAGE_BOT=y
+CONFIG_USB_STORAGE_UAS=y
+CONFIG_USB_SMARTCARD=y
+CONFIG_USB_AUDIO=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_NETWORK=y
+CONFIG_USB_BLUETOOTH=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 233a8564eb..3392f5abd6 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -1,6 +1,7 @@
# Default configuration for x86_64-softmmu
include pci.mak
+include usb.mak
CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 447e32a42e..a1f3a808ac 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -38,8 +38,10 @@ common-obj-$(CONFIG_DMA) += dma.o
common-obj-$(CONFIG_I82374) += i82374.o
common-obj-$(CONFIG_HPET) += hpet.o
common-obj-$(CONFIG_APPLESMC) += applesmc.o
+ifeq ($(CONFIG_USB_SMARTCARD),y)
common-obj-y += ccid-card-passthru.o
common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
+endif
common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
common-obj-y += fifo.o
common-obj-y += pam.o
diff --git a/hw/usb.h b/hw/usb.h
index bc42639b16..382496cf82 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -361,6 +361,7 @@ struct USBPacket {
int pid;
uint64_t id;
USBEndpoint *ep;
+ unsigned int stream;
QEMUIOVector iov;
uint64_t parameter; /* control transfers */
bool short_not_ok;
@@ -383,13 +384,15 @@ struct USBCombinedPacket {
void usb_packet_init(USBPacket *p);
void usb_packet_set_state(USBPacket *p, USBPacketState state);
void usb_packet_check_state(USBPacket *p, USBPacketState expected);
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
- bool short_not_ok, bool int_req);
+void usb_packet_setup(USBPacket *p, int pid,
+ USBEndpoint *ep, unsigned int stream,
+ uint64_t id, bool short_not_ok, bool int_req);
void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl);
void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
void usb_packet_skip(USBPacket *p, size_t bytes);
+size_t usb_packet_size(USBPacket *p);
void usb_packet_cleanup(USBPacket *p);
static inline bool usb_packet_is_inflight(USBPacket *p)
@@ -417,6 +420,7 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
uint16_t raw);
int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled);
+void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted);
USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
uint64_t id);
@@ -428,13 +432,12 @@ void usb_attach(USBPort *port);
void usb_detach(USBPort *port);
void usb_port_reset(USBPort *port);
void usb_device_reset(USBDevice *dev);
-void usb_wakeup(USBEndpoint *ep);
+void usb_wakeup(USBEndpoint *ep, unsigned int stream);
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
int set_usb_string(uint8_t *buf, const char *str);
/* usb-linux.c */
USBDevice *usb_host_device_open(USBBus *bus, const char *devname);
-int usb_host_device_close(const char *devname);
void usb_host_info(Monitor *mon, const QDict *qdict);
/* usb-bt.c */
@@ -488,7 +491,7 @@ struct USBBus {
struct USBBusOps {
int (*register_companion)(USBBus *bus, USBPort *ports[],
uint32_t portcount, uint32_t firstport);
- void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep);
+ void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep, unsigned int stream);
};
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index d1bbbc06e7..e63e287ce0 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -1,14 +1,30 @@
+# usb subsystem core
+common-obj-y += core.o combined-packet.o bus.o desc.o
+common-obj-y += libhw.o
+
+# usb host adapters
common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
-common-obj-y += libhw.o
+# emulated usb devices
+common-obj-y += dev-hub.o
+common-obj-y += dev-hid.o
+common-obj-$(CONFIG_USB_TABLET_WACOM) += dev-wacom.o
+common-obj-$(CONFIG_USB_STORAGE_BOT) += dev-storage.o
+common-obj-$(CONFIG_USB_STORAGE_UAS) += dev-uas.o
+common-obj-$(CONFIG_USB_AUDIO) += dev-audio.o
+common-obj-$(CONFIG_USB_SERIAL) += dev-serial.o
+common-obj-$(CONFIG_USB_NETWORK) += dev-network.o
+
+# FIXME: make configurable too
+CONFIG_USB_BLUETOOTH := y
+common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o
+common-obj-$(CONFIG_USB_SMARTCARD) += dev-smartcard-reader.o
+
+# usb redirection
common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
-common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o
-common-obj-y += host-$(HOST_USB).o dev-bluetooth.o
-common-obj-y += dev-hid.o dev-storage.o dev-wacom.o
-common-obj-y += dev-serial.o dev-network.o dev-audio.o
-common-obj-y += dev-smartcard-reader.o
-common-obj-y += dev-uas.o
+# usb pass-through
+common-obj-y += $(patsubst %,host-%.o,$(HOST_USB))
diff --git a/hw/usb/core.c b/hw/usb/core.c
index d057aab900..15a150aea0 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -71,7 +71,7 @@ void usb_device_reset(USBDevice *dev)
usb_device_handle_reset(dev);
}
-void usb_wakeup(USBEndpoint *ep)
+void usb_wakeup(USBEndpoint *ep, unsigned int stream)
{
USBDevice *dev = ep->dev;
USBBus *bus = usb_bus_from_device(dev);
@@ -80,7 +80,7 @@ void usb_wakeup(USBEndpoint *ep)
dev->port->ops->wakeup(dev->port);
}
if (bus->ops->wakeup_endpoint) {
- bus->ops->wakeup_endpoint(bus, ep);
+ bus->ops->wakeup_endpoint(bus, ep, stream);
}
}
@@ -545,14 +545,16 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state)
p->state = state;
}
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
- bool short_not_ok, bool int_req)
+void usb_packet_setup(USBPacket *p, int pid,
+ USBEndpoint *ep, unsigned int stream,
+ uint64_t id, bool short_not_ok, bool int_req)
{
assert(!usb_packet_is_inflight(p));
assert(p->iov.iov != NULL);
p->id = id;
p->pid = pid;
p->ep = ep;
+ p->stream = stream;
p->status = USB_RET_SUCCESS;
p->actual_length = 0;
p->parameter = 0;
@@ -570,15 +572,17 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
{
+ QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
+
assert(p->actual_length >= 0);
- assert(p->actual_length + bytes <= p->iov.size);
+ assert(p->actual_length + bytes <= iov->size);
switch (p->pid) {
case USB_TOKEN_SETUP:
case USB_TOKEN_OUT:
- iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
+ iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
break;
case USB_TOKEN_IN:
- iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
+ iov_from_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
break;
default:
fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
@@ -589,14 +593,21 @@ void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
void usb_packet_skip(USBPacket *p, size_t bytes)
{
+ QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
+
assert(p->actual_length >= 0);
- assert(p->actual_length + bytes <= p->iov.size);
+ assert(p->actual_length + bytes <= iov->size);
if (p->pid == USB_TOKEN_IN) {
- iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes);
+ iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes);
}
p->actual_length += bytes;
}
+size_t usb_packet_size(USBPacket *p)
+{
+ return p->combined ? p->combined->iov.size : p->iov.size;
+}
+
void usb_packet_cleanup(USBPacket *p)
{
assert(!usb_packet_is_inflight(p));
@@ -755,6 +766,12 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled)
uep->pipeline = enabled;
}
+void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ uep->halted = halted;
+}
+
USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
uint64_t id)
{
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index b7c32333d7..b389381326 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -225,12 +225,9 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
d->u.endpoint.bRefresh = ep->bRefresh;
d->u.endpoint.bSynchAddress = ep->bSynchAddress;
}
- if (ep->extra) {
- memcpy(dest + bLength, ep->extra, extralen);
- }
if (superlen) {
- USBDescriptor *d = (void *)(dest + bLength + extralen);
+ USBDescriptor *d = (void *)(dest + bLength);
d->bLength = 0x06;
d->bDescriptorType = USB_DT_ENDPOINT_COMPANION;
@@ -243,6 +240,10 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
usb_hi(ep->wBytesPerInterval);
}
+ if (ep->extra) {
+ memcpy(dest + bLength + superlen, ep->extra, extralen);
+ }
+
return bLength + extralen + superlen;
}
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index adbf9d4697..0f8aa48c85 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -478,7 +478,7 @@ static void usb_bt_out_hci_packet_event(void *opaque,
struct USBBtState *s = (struct USBBtState *) opaque;
if (s->evt.len == 0) {
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
usb_bt_fifo_enqueue(&s->evt, data, len);
}
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 29b64819ab..9701048887 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -423,7 +423,7 @@ static void usb_hid_changed(HIDState *hs)
{
USBHIDState *us = container_of(hs, USBHIDState, hid);
- usb_wakeup(us->intr);
+ usb_wakeup(us->intr, 0);
}
static void usb_hid_handle_reset(USBDevice *dev)
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 79f2f46d55..504c98c350 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -164,7 +164,7 @@ static void usb_hub_attach(USBPort *port1)
} else {
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
}
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
static void usb_hub_detach(USBPort *port1)
@@ -173,7 +173,7 @@ static void usb_hub_detach(USBPort *port1)
USBHubPort *port = &s->ports[port1->index];
trace_usb_hub_detach(s->dev.addr, port1->index + 1);
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
/* Let upstream know the device on this port is gone */
s->dev.port->ops->child_detach(s->dev.port, port1->dev);
@@ -184,7 +184,7 @@ static void usb_hub_detach(USBPort *port1)
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
@@ -202,7 +202,7 @@ static void usb_hub_wakeup(USBPort *port1)
if (port->wPortStatus & PORT_STAT_SUSPEND) {
port->wPortChange |= PORT_STAT_C_SUSPEND;
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
}
@@ -364,7 +364,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
port->wPortChange |= PORT_STAT_C_RESET;
/* set enable bit */
port->wPortStatus |= PORT_STAT_ENABLE;
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
break;
case PORT_POWER:
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index a01a5e793a..c08718b679 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -855,7 +855,7 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length)
g_malloc0(sizeof(struct rndis_response) + length);
if (QTAILQ_EMPTY(&s->rndis_resp)) {
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 979a473b37..caebc1c3ff 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -839,7 +839,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full)
s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
}
s->notify_slot_change = true;
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
static void ccid_write_data_block_error(
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index b89d00f7cf..d3f01aa2a7 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -400,6 +400,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
struct usb_msd_cbw cbw;
uint8_t devep = p->ep->nr;
SCSIDevice *scsi_dev;
+ uint32_t len;
switch (p->pid) {
case USB_TOKEN_OUT:
@@ -441,8 +442,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
#ifdef DEBUG_MSD
scsi_req_print(s->req);
#endif
- scsi_req_enqueue(s->req);
- if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
+ len = scsi_req_enqueue(s->req);
+ if (len) {
scsi_req_continue(s->req);
}
break;
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index d904d1a40b..1ac5117ba7 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -99,6 +99,9 @@ typedef struct {
/* --------------------------------------------------------------------- */
+#define UAS_STREAM_BM_ATTR 4
+#define UAS_MAX_STREAMS (1 << UAS_STREAM_BM_ATTR)
+
typedef struct UASDevice UASDevice;
typedef struct UASRequest UASRequest;
typedef struct UASStatus UASStatus;
@@ -106,12 +109,18 @@ typedef struct UASStatus UASStatus;
struct UASDevice {
USBDevice dev;
SCSIBus bus;
- UASRequest *datain;
- UASRequest *dataout;
- USBPacket *status;
QEMUBH *status_bh;
QTAILQ_HEAD(, UASStatus) results;
QTAILQ_HEAD(, UASRequest) requests;
+
+ /* usb 2.0 only */
+ USBPacket *status2;
+ UASRequest *datain2;
+ UASRequest *dataout2;
+
+ /* usb 3.0 only */
+ USBPacket *data3[UAS_MAX_STREAMS];
+ USBPacket *status3[UAS_MAX_STREAMS];
};
struct UASRequest {
@@ -132,6 +141,7 @@ struct UASRequest {
};
struct UASStatus {
+ uint32_t stream;
uas_ui status;
uint32_t length;
QTAILQ_ENTRY(UASStatus) next;
@@ -144,6 +154,7 @@ enum {
STR_PRODUCT,
STR_SERIALNUMBER,
STR_CONFIG_HIGH,
+ STR_CONFIG_SUPER,
};
static const USBDescStrings desc_strings = {
@@ -151,6 +162,7 @@ static const USBDescStrings desc_strings = {
[STR_PRODUCT] = "USB Attached SCSI HBA",
[STR_SERIALNUMBER] = "27842",
[STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
+ [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
};
static const USBDescIface desc_iface_high = {
@@ -204,6 +216,64 @@ static const USBDescIface desc_iface_high = {
}
};
+static const USBDescIface desc_iface_super = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 4,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = 0x06, /* SCSI */
+ .bInterfaceProtocol = 0x62, /* UAS */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 1024,
+ .bMaxBurst = 15,
+ .extra = (uint8_t[]) {
+ 0x04, /* u8 bLength */
+ 0x24, /* u8 bDescriptorType */
+ UAS_PIPE_ID_COMMAND,
+ 0x00, /* u8 bReserved */
+ },
+ },{
+ .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 1024,
+ .bMaxBurst = 15,
+ .bmAttributes_super = UAS_STREAM_BM_ATTR,
+ .extra = (uint8_t[]) {
+ 0x04, /* u8 bLength */
+ 0x24, /* u8 bDescriptorType */
+ UAS_PIPE_ID_STATUS,
+ 0x00, /* u8 bReserved */
+ },
+ },{
+ .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 1024,
+ .bMaxBurst = 15,
+ .bmAttributes_super = UAS_STREAM_BM_ATTR,
+ .extra = (uint8_t[]) {
+ 0x04, /* u8 bLength */
+ 0x24, /* u8 bDescriptorType */
+ UAS_PIPE_ID_DATA_IN,
+ 0x00, /* u8 bReserved */
+ },
+ },{
+ .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 1024,
+ .bMaxBurst = 15,
+ .bmAttributes_super = UAS_STREAM_BM_ATTR,
+ .extra = (uint8_t[]) {
+ 0x04, /* u8 bLength */
+ 0x24, /* u8 bDescriptorType */
+ UAS_PIPE_ID_DATA_OUT,
+ 0x00, /* u8 bReserved */
+ },
+ },
+ }
+};
+
static const USBDescDevice desc_device_high = {
.bcdUSB = 0x0200,
.bMaxPacketSize0 = 64,
@@ -220,6 +290,22 @@ static const USBDescDevice desc_device_high = {
},
};
+static const USBDescDevice desc_device_super = {
+ .bcdUSB = 0x0300,
+ .bMaxPacketSize0 = 64,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG_SUPER,
+ .bmAttributes = 0xc0,
+ .nif = 1,
+ .ifs = &desc_iface_super,
+ },
+ },
+};
+
static const USBDesc desc = {
.id = {
.idVendor = 0x46f4, /* CRC16() of "QEMU" */
@@ -229,45 +315,68 @@ static const USBDesc desc = {
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER,
},
- .high = &desc_device_high,
- .str = desc_strings,
+ .high = &desc_device_high,
+ .super = &desc_device_super,
+ .str = desc_strings,
};
/* --------------------------------------------------------------------- */
-static UASStatus *usb_uas_alloc_status(uint8_t id, uint16_t tag)
+static bool uas_using_streams(UASDevice *uas)
+{
+ return uas->dev.speed == USB_SPEED_SUPER;
+}
+
+/* --------------------------------------------------------------------- */
+
+static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
{
UASStatus *st = g_new0(UASStatus, 1);
st->status.hdr.id = id;
st->status.hdr.tag = cpu_to_be16(tag);
st->length = sizeof(uas_ui_header);
+ if (uas_using_streams(uas)) {
+ st->stream = tag;
+ }
return st;
}
static void usb_uas_send_status_bh(void *opaque)
{
UASDevice *uas = opaque;
- UASStatus *st = QTAILQ_FIRST(&uas->results);
- USBPacket *p = uas->status;
+ UASStatus *st;
+ USBPacket *p;
- assert(p != NULL);
- assert(st != NULL);
+ while ((st = QTAILQ_FIRST(&uas->results)) != NULL) {
+ if (uas_using_streams(uas)) {
+ p = uas->status3[st->stream];
+ uas->status3[st->stream] = NULL;
+ } else {
+ p = uas->status2;
+ uas->status2 = NULL;
+ }
+ if (p == NULL) {
+ break;
+ }
- uas->status = NULL;
- usb_packet_copy(p, &st->status, st->length);
- QTAILQ_REMOVE(&uas->results, st, next);
- g_free(st);
+ usb_packet_copy(p, &st->status, st->length);
+ QTAILQ_REMOVE(&uas->results, st, next);
+ g_free(st);
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_packet_complete(&uas->dev, p);
+ p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
+ usb_packet_complete(&uas->dev, p);
+ }
}
static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
{
+ USBPacket *p = uas_using_streams(uas) ?
+ uas->status3[st->stream] : uas->status2;
+
st->length += length;
QTAILQ_INSERT_TAIL(&uas->results, st, next);
- if (uas->status) {
+ if (p) {
/*
* Just schedule bh make sure any in-flight data transaction
* is finished before completing (sending) the status packet.
@@ -276,14 +385,14 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
} else {
USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN,
UAS_PIPE_ID_STATUS);
- usb_wakeup(ep);
+ usb_wakeup(ep, st->stream);
}
}
static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
uint8_t code, uint16_t add_info)
{
- UASStatus *st = usb_uas_alloc_status(UAS_UI_RESPONSE, tag);
+ UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
trace_usb_uas_response(uas->dev.addr, tag, code);
st->status.response.response_code = code;
@@ -293,7 +402,7 @@ static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
{
- UASStatus *st = usb_uas_alloc_status(UAS_UI_SENSE, req->tag);
+ UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_SENSE, req->tag);
int len, slen = 0;
trace_usb_uas_sense(req->uas->dev.addr, req->tag, status);
@@ -310,7 +419,8 @@ static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
static void usb_uas_queue_read_ready(UASRequest *req)
{
- UASStatus *st = usb_uas_alloc_status(UAS_UI_READ_READY, req->tag);
+ UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY,
+ req->tag);
trace_usb_uas_read_ready(req->uas->dev.addr, req->tag);
usb_uas_queue_status(req->uas, st, 0);
@@ -318,7 +428,8 @@ static void usb_uas_queue_read_ready(UASRequest *req)
static void usb_uas_queue_write_ready(UASRequest *req)
{
- UASStatus *st = usb_uas_alloc_status(UAS_UI_WRITE_READY, req->tag);
+ UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_WRITE_READY,
+ req->tag);
trace_usb_uas_write_ready(req->uas->dev.addr, req->tag);
usb_uas_queue_status(req->uas, st, 0);
@@ -381,18 +492,22 @@ static void usb_uas_start_next_transfer(UASDevice *uas)
{
UASRequest *req;
+ if (uas_using_streams(uas)) {
+ return;
+ }
+
QTAILQ_FOREACH(req, &uas->requests, next) {
if (req->active || req->complete) {
continue;
}
- if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain == NULL) {
- uas->datain = req;
+ if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain2 == NULL) {
+ uas->datain2 = req;
usb_uas_queue_read_ready(req);
req->active = true;
return;
}
- if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout == NULL) {
- uas->dataout = req;
+ if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout2 == NULL) {
+ uas->dataout2 = req;
usb_uas_queue_write_ready(req);
req->active = true;
return;
@@ -417,11 +532,11 @@ static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
UASRequest *req = priv;
UASDevice *uas = req->uas;
- if (req == uas->datain) {
- uas->datain = NULL;
+ if (req == uas->datain2) {
+ uas->datain2 = NULL;
}
- if (req == uas->dataout) {
- uas->dataout = NULL;
+ if (req == uas->dataout2) {
+ uas->dataout2 = NULL;
}
QTAILQ_REMOVE(&uas->requests, req, next);
g_free(req);
@@ -522,12 +637,25 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
{
UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
UASRequest *req, *nreq;
+ int i;
- if (uas->status == p) {
- uas->status = NULL;
+ if (uas->status2 == p) {
+ uas->status2 = NULL;
qemu_bh_cancel(uas->status_bh);
return;
}
+ if (uas_using_streams(uas)) {
+ for (i = 0; i < UAS_MAX_STREAMS; i++) {
+ if (uas->status3[i] == p) {
+ uas->status3[i] = NULL;
+ return;
+ }
+ if (uas->data3[i] == p) {
+ uas->data3[i] = NULL;
+ return;
+ }
+ }
+ }
QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
if (req->data == p) {
req->data = NULL;
@@ -555,9 +683,18 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui)
usb_uas_get_lun(req->lun),
req->lun >> 32, req->lun & 0xffffffff);
QTAILQ_INSERT_TAIL(&uas->requests, req, next);
+ if (uas_using_streams(uas) && uas->data3[req->tag] != NULL) {
+ req->data = uas->data3[req->tag];
+ req->data_async = true;
+ uas->data3[req->tag] = NULL;
+ }
+
req->req = scsi_req_new(req->dev, req->tag,
usb_uas_get_lun(req->lun),
ui->command.cdb, req);
+#if 1
+ scsi_req_print(req->req);
+#endif
len = scsi_req_enqueue(req->req);
if (len) {
req->data_size = len;
@@ -669,12 +806,26 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
}
break;
case UAS_PIPE_ID_STATUS:
- st = QTAILQ_FIRST(&uas->results);
- if (st == NULL) {
- assert(uas->status == NULL);
- uas->status = p;
- p->status = USB_RET_ASYNC;
- break;
+ if (p->stream) {
+ QTAILQ_FOREACH(st, &uas->results, next) {
+ if (st->stream == p->stream) {
+ break;
+ }
+ }
+ if (st == NULL) {
+ assert(uas->status3[p->stream] == NULL);
+ uas->status3[p->stream] = p;
+ p->status = USB_RET_ASYNC;
+ break;
+ }
+ } else {
+ st = QTAILQ_FIRST(&uas->results);
+ if (st == NULL) {
+ assert(uas->status2 == NULL);
+ uas->status2 = p;
+ p->status = USB_RET_ASYNC;
+ break;
+ }
}
usb_packet_copy(p, &st->status, st->length);
QTAILQ_REMOVE(&uas->results, st, next);
@@ -682,11 +833,23 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
break;
case UAS_PIPE_ID_DATA_IN:
case UAS_PIPE_ID_DATA_OUT:
- req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout;
+ if (p->stream) {
+ req = usb_uas_find_request(uas, p->stream);
+ } else {
+ req = (p->ep->nr == UAS_PIPE_ID_DATA_IN)
+ ? uas->datain2 : uas->dataout2;
+ }
if (req == NULL) {
- fprintf(stderr, "%s: no inflight request\n", __func__);
- p->status = USB_RET_STALL;
- break;
+ if (p->stream) {
+ assert(uas->data3[p->stream] == NULL);
+ uas->data3[p->stream] = p;
+ p->status = USB_RET_ASYNC;
+ break;
+ } else {
+ fprintf(stderr, "%s: no inflight request\n", __func__);
+ p->status = USB_RET_STALL;
+ break;
+ }
}
scsi_req_ref(req->req);
req->data = p;
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index ab9fa2ef48..3be5cdefda 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -138,7 +138,7 @@ static void usb_mouse_event(void *opaque,
s->dz += dz1;
s->buttons_state = buttons_state;
s->changed = 1;
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
static void usb_wacom_event(void *opaque,
@@ -152,7 +152,7 @@ static void usb_wacom_event(void *opaque,
s->dz += dz;
s->buttons_state = buttons_state;
s->changed = 1;
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
static inline int int_clamp(int val, int vmin, int vmax)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 70406592ef..5176251cb4 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -874,7 +874,8 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
return 0;
}
-static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
+static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
+ unsigned int stream)
{
EHCIState *s = container_of(bus, EHCIState, bus);
uint32_t portsc = s->portsc[ep->dev->port->index];
@@ -1420,7 +1421,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
}
spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
- usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr, spd,
+ usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd,
(p->qtd.token & QTD_TOKEN_IOC) != 0);
usb_packet_map(&p->packet, &p->sgl);
p->async = EHCI_ASYNC_INITIALIZED;
@@ -1493,7 +1494,7 @@ static int ehci_process_itd(EHCIState *ehci,
dev = ehci_find_device(ehci, devaddr);
ep = usb_ep_get(dev, pid, endp);
if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
- usb_packet_setup(&ehci->ipacket, pid, ep, addr, false,
+ usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
(itd->transact[i] & ITD_XACT_IOC) != 0);
usb_packet_map(&ehci->ipacket, &ehci->isgl);
usb_handle_packet(dev, &ehci->ipacket);
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
index 64e9e834bf..7968e17c34 100644
--- a/hw/usb/hcd-musb.c
+++ b/hw/usb/hcd-musb.c
@@ -625,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
/* A wild guess on the FADDR semantics... */
dev = usb_find_device(&s->port, ep->faddr[idx]);
uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
- usb_packet_setup(&ep->packey[dir].p, pid, uep,
+ usb_packet_setup(&ep->packey[dir].p, pid, uep, 0,
(dev->addr << 16) | (uep->nr << 8) | pid, false, true);
usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep;
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index dd9967b13d..51241cda78 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -830,7 +830,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
OHCI_BM(iso_td.flags, TD_DI) == 0;
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep, addr, false, int_req);
+ usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
usb_handle_packet(dev, &ohci->usb_packet);
if (ohci->usb_packet.status == USB_RET_ASYNC) {
@@ -1034,7 +1034,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep, addr, !flag_r,
+ usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
OHCI_BM(td.flags, TD_DI) == 0);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
usb_handle_packet(dev, &ohci->usb_packet);
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 60645aa21f..f8c42864d1 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -879,7 +879,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
max_len = ((td->token >> 21) + 1) & 0x7ff;
spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
- usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd,
+ usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
(td->ctrl & TD_CTRL_IOC) != 0);
qemu_sglist_add(&async->sgl, td->buffer, max_len);
usb_packet_map(&async->packet, &async->sgl);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 5fb0c488e8..5796102f3a 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -34,8 +34,8 @@
#else
#define DPRINTF(...) do {} while (0)
#endif
-#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
- __func__, __LINE__); abort(); } while (0)
+#define FIXME(_msg) do { fprintf(stderr, "FIXME %s:%d %s\n", \
+ __func__, __LINE__, _msg); abort(); } while (0)
#define MAXPORTS_2 15
#define MAXPORTS_3 15
@@ -301,6 +301,8 @@ typedef enum TRBCCode {
#define SLOT_CONTEXT_ENTRIES_SHIFT 27
typedef struct XHCIState XHCIState;
+typedef struct XHCIStreamContext XHCIStreamContext;
+typedef struct XHCIEPContext XHCIEPContext;
#define get_field(data, field) \
(((data) >> field##_SHIFT) & field##_MASK)
@@ -351,6 +353,7 @@ typedef struct XHCITransfer {
unsigned int iso_pkts;
unsigned int slotid;
unsigned int epid;
+ unsigned int streamid;
bool in_xfer;
bool iso_xfer;
@@ -367,7 +370,14 @@ typedef struct XHCITransfer {
uint64_t mfindex_kick;
} XHCITransfer;
-typedef struct XHCIEPContext {
+struct XHCIStreamContext {
+ dma_addr_t pctx;
+ unsigned int sct;
+ XHCIRing ring;
+ XHCIStreamContext *sstreams;
+};
+
+struct XHCIEPContext {
XHCIState *xhci;
unsigned int slotid;
unsigned int epid;
@@ -382,11 +392,17 @@ typedef struct XHCIEPContext {
unsigned int max_psize;
uint32_t state;
+ /* streams */
+ unsigned int max_pstreams;
+ bool lsa;
+ unsigned int nr_pstreams;
+ XHCIStreamContext *pstreams;
+
/* iso xfer scheduling */
unsigned int interval;
int64_t mfindex_last;
QEMUTimer *kick_timer;
-} XHCIEPContext;
+};
typedef struct XHCISlot {
bool enabled;
@@ -482,7 +498,7 @@ enum xhci_flags {
};
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid);
+ unsigned int epid, unsigned int streamid);
static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
unsigned int epid);
static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
@@ -1068,18 +1084,116 @@ static void xhci_stop(XHCIState *xhci)
xhci->crcr_low &= ~CRCR_CRR;
}
+static XHCIStreamContext *xhci_alloc_stream_contexts(unsigned count,
+ dma_addr_t base)
+{
+ XHCIStreamContext *stctx;
+ unsigned int i;
+
+ stctx = g_new0(XHCIStreamContext, count);
+ for (i = 0; i < count; i++) {
+ stctx[i].pctx = base + i * 16;
+ stctx[i].sct = -1;
+ }
+ return stctx;
+}
+
+static void xhci_reset_streams(XHCIEPContext *epctx)
+{
+ unsigned int i;
+
+ for (i = 0; i < epctx->nr_pstreams; i++) {
+ epctx->pstreams[i].sct = -1;
+ g_free(epctx->pstreams[i].sstreams);
+ }
+}
+
+static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base)
+{
+ assert(epctx->pstreams == NULL);
+ epctx->nr_pstreams = 2 << epctx->max_pstreams;
+ epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base);
+}
+
+static void xhci_free_streams(XHCIEPContext *epctx)
+{
+ int i;
+
+ assert(epctx->pstreams != NULL);
+
+ if (!epctx->lsa) {
+ for (i = 0; i < epctx->nr_pstreams; i++) {
+ g_free(epctx->pstreams[i].sstreams);
+ }
+ }
+ g_free(epctx->pstreams);
+ epctx->pstreams = NULL;
+ epctx->nr_pstreams = 0;
+}
+
+static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
+ unsigned int streamid,
+ uint32_t *cc_error)
+{
+ XHCIStreamContext *sctx;
+ dma_addr_t base;
+ uint32_t ctx[2], sct;
+
+ assert(streamid != 0);
+ if (epctx->lsa) {
+ if (streamid >= epctx->nr_pstreams) {
+ *cc_error = CC_INVALID_STREAM_ID_ERROR;
+ return NULL;
+ }
+ sctx = epctx->pstreams + streamid;
+ } else {
+ FIXME("secondary streams not implemented yet");
+ }
+
+ if (sctx->sct == -1) {
+ xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx));
+ fprintf(stderr, "%s: init sctx #%d @ %lx: %08x %08x\n", __func__,
+ streamid, sctx->pctx, ctx[0], ctx[1]);
+ sct = (ctx[0] >> 1) & 0x07;
+ if (epctx->lsa && sct != 1) {
+ *cc_error = CC_INVALID_STREAM_TYPE_ERROR;
+ return NULL;
+ }
+ sctx->sct = sct;
+ base = xhci_addr64(ctx[0] & ~0xf, ctx[1]);
+ xhci_ring_init(epctx->xhci, &sctx->ring, base);
+ }
+ return sctx;
+}
+
static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
- uint32_t state)
+ XHCIStreamContext *sctx, uint32_t state)
{
uint32_t ctx[5];
+ uint32_t ctx2[2];
+ fprintf(stderr, "%s: epid %d, state %d\n",
+ __func__, epctx->epid, state);
xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
ctx[0] &= ~EP_STATE_MASK;
ctx[0] |= state;
- ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
- ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
- DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
- epctx->pctx, state, ctx[3], ctx[2]);
+
+ /* update ring dequeue ptr */
+ if (epctx->nr_pstreams) {
+ if (sctx != NULL) {
+ xhci_dma_read_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
+ ctx2[0] &= 0xe;
+ ctx2[0] |= sctx->ring.dequeue | sctx->ring.ccs;
+ ctx2[1] = (sctx->ring.dequeue >> 16) >> 16;
+ xhci_dma_write_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
+ }
+ } else {
+ ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
+ ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
+ DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
+ epctx->pctx, state, ctx[3], ctx[2]);
+ }
+
xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
epctx->state = state;
}
@@ -1087,7 +1201,7 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
static void xhci_ep_kick_timer(void *opaque)
{
XHCIEPContext *epctx = opaque;
- xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid);
+ xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0);
}
static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
@@ -1117,16 +1231,22 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
slot->eps[epid-1] = epctx;
dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
- xhci_ring_init(xhci, &epctx->ring, dequeue);
- epctx->ring.ccs = ctx[2] & 1;
epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type);
epctx->pctx = pctx;
epctx->max_psize = ctx[1]>>16;
epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
+ epctx->max_pstreams = (ctx[0] >> 10) & 0xf;
+ epctx->lsa = (ctx[0] >> 15) & 1;
DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
epid/2, epid%2, epctx->max_psize);
+ if (epctx->max_pstreams) {
+ xhci_alloc_streams(epctx, dequeue);
+ } else {
+ xhci_ring_init(xhci, &epctx->ring, dequeue);
+ epctx->ring.ccs = ctx[2] & 1;
+ }
for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
usb_packet_init(&epctx->transfers[i].packet);
}
@@ -1227,7 +1347,11 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
epctx = slot->eps[epid-1];
- xhci_set_ep_state(xhci, epctx, EP_DISABLED);
+ if (epctx->nr_pstreams) {
+ xhci_free_streams(epctx);
+ }
+
+ xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED);
qemu_free_timer(epctx->kick_timer);
g_free(epctx);
@@ -1264,7 +1388,11 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
epctx = slot->eps[epid-1];
- xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+ xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
+
+ if (epctx->nr_pstreams) {
+ xhci_reset_streams(epctx);
+ }
return CC_SUCCESS;
}
@@ -1315,16 +1443,22 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
return CC_USB_TRANSACTION_ERROR;
}
- xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+ xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
+
+ if (epctx->nr_pstreams) {
+ xhci_reset_streams(epctx);
+ }
return CC_SUCCESS;
}
static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, uint64_t pdequeue)
+ unsigned int epid, unsigned int streamid,
+ uint64_t pdequeue)
{
XHCISlot *slot;
XHCIEPContext *epctx;
+ XHCIStreamContext *sctx;
dma_addr_t dequeue;
assert(slotid >= 1 && slotid <= xhci->numslots);
@@ -1334,7 +1468,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
return CC_TRB_ERROR;
}
- trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue);
+ trace_usb_xhci_ep_set_dequeue(slotid, epid, streamid, pdequeue);
dequeue = xhci_mask64(pdequeue);
slot = &xhci->slots[slotid-1];
@@ -1346,16 +1480,26 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
epctx = slot->eps[epid-1];
-
if (epctx->state != EP_STOPPED) {
fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
return CC_CONTEXT_STATE_ERROR;
}
- xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
- epctx->ring.ccs = dequeue & 1;
+ if (epctx->nr_pstreams) {
+ uint32_t err;
+ sctx = xhci_find_stream(epctx, streamid, &err);
+ if (sctx == NULL) {
+ return err;
+ }
+ xhci_ring_init(xhci, &sctx->ring, dequeue & ~0xf);
+ sctx->ring.ccs = dequeue & 1;
+ } else {
+ sctx = NULL;
+ xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
+ epctx->ring.ccs = dequeue & 1;
+ }
- xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+ xhci_set_ep_state(xhci, epctx, sctx, EP_STOPPED);
return CC_SUCCESS;
}
@@ -1484,12 +1628,22 @@ static void xhci_stall_ep(XHCITransfer *xfer)
XHCIState *xhci = xfer->xhci;
XHCISlot *slot = &xhci->slots[xfer->slotid-1];
XHCIEPContext *epctx = slot->eps[xfer->epid-1];
+ uint32_t err;
+ XHCIStreamContext *sctx;
- epctx->ring.dequeue = xfer->trbs[0].addr;
- epctx->ring.ccs = xfer->trbs[0].ccs;
- xhci_set_ep_state(xhci, epctx, EP_HALTED);
- DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid);
- DPRINTF("xhci: will continue at "DMA_ADDR_FMT"\n", epctx->ring.dequeue);
+ if (epctx->nr_pstreams) {
+ sctx = xhci_find_stream(epctx, xfer->streamid, &err);
+ if (sctx == NULL) {
+ return;
+ }
+ sctx->ring.dequeue = xfer->trbs[0].addr;
+ sctx->ring.ccs = xfer->trbs[0].ccs;
+ xhci_set_ep_state(xhci, epctx, sctx, EP_HALTED);
+ } else {
+ epctx->ring.dequeue = xfer->trbs[0].addr;
+ epctx->ring.ccs = xfer->trbs[0].ccs;
+ xhci_set_ep_state(xhci, epctx, NULL, EP_HALTED);
+ }
}
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
@@ -1518,8 +1672,8 @@ static int xhci_setup_packet(XHCITransfer *xfer)
}
xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
- usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr, false,
- xfer->int_req);
+ usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid,
+ xfer->trbs[0].addr, false, xfer->int_req);
usb_packet_map(&xfer->packet, &xfer->sgl);
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
xfer->packet.pid, dev->addr, ep->nr);
@@ -1572,7 +1726,7 @@ static int xhci_complete_packet(XHCITransfer *xfer)
default:
fprintf(stderr, "%s: FIXME: status = %d\n", __func__,
xfer->packet.status);
- FIXME();
+ FIXME("unhandled USB_RET_*");
}
return 0;
}
@@ -1585,7 +1739,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
trb_setup = &xfer->trbs[0];
trb_status = &xfer->trbs[xfer->trb_count-1];
- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
+ trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
/* at most one Event Data TRB allowed after STATUS */
if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
@@ -1627,7 +1781,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
xhci_complete_packet(xfer);
if (!xfer->running_async && !xfer->running_retry) {
- xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+ xhci_kick_ep(xhci, xfer->slotid, xfer->epid, 0);
}
return 0;
}
@@ -1710,26 +1864,29 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
xhci_complete_packet(xfer);
if (!xfer->running_async && !xfer->running_retry) {
- xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+ xhci_kick_ep(xhci, xfer->slotid, xfer->epid, xfer->streamid);
}
return 0;
}
static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
{
- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
+ trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
return xhci_submit(xhci, xfer, epctx);
}
-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid, unsigned int streamid)
{
+ XHCIStreamContext *stctx;
XHCIEPContext *epctx;
+ XHCIRing *ring;
USBEndpoint *ep = NULL;
uint64_t mfindex;
int length;
int i;
- trace_usb_xhci_ep_kick(slotid, epid);
+ trace_usb_xhci_ep_kick(slotid, epid, streamid);
assert(slotid >= 1 && slotid <= xhci->numslots);
assert(epid >= 1 && epid <= 31);
@@ -1782,14 +1939,28 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
return;
}
- xhci_set_ep_state(xhci, epctx, EP_RUNNING);
+
+ if (epctx->nr_pstreams) {
+ uint32_t err;
+ stctx = xhci_find_stream(epctx, streamid, &err);
+ if (stctx == NULL) {
+ return;
+ }
+ ring = &stctx->ring;
+ xhci_set_ep_state(xhci, epctx, stctx, EP_RUNNING);
+ } else {
+ ring = &epctx->ring;
+ streamid = 0;
+ xhci_set_ep_state(xhci, epctx, NULL, EP_RUNNING);
+ }
+ assert(ring->base != 0);
while (1) {
XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
if (xfer->running_async || xfer->running_retry) {
break;
}
- length = xhci_ring_chain_length(xhci, &epctx->ring);
+ length = xhci_ring_chain_length(xhci, ring);
if (length < 0) {
break;
} else if (length == 0) {
@@ -1808,11 +1979,12 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
xfer->trb_count = length;
for (i = 0; i < length; i++) {
- assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL));
+ assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL));
}
xfer->xhci = xhci;
xfer->epid = epid;
xfer->slotid = slotid;
+ xfer->streamid = streamid;
if (epid == 1) {
if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
@@ -1977,7 +2149,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: device address is %d\n", slot->devaddr);
usb_device_reset(dev);
usb_packet_setup(&p, USB_TOKEN_OUT,
- usb_ep_get(dev, USB_TOKEN_OUT, 0),
+ usb_ep_get(dev, USB_TOKEN_OUT, 0), 0,
0, false, false);
usb_device_handle_control(dev, &p,
DeviceOutRequest | USB_REQ_SET_ADDRESS,
@@ -2357,11 +2529,14 @@ static void xhci_process_commands(XHCIState *xhci)
}
break;
case CR_SET_TR_DEQUEUE:
+ fprintf(stderr, "%s: CR_SET_TR_DEQUEUE\n", __func__);
slotid = xhci_get_slot(xhci, &event, &trb);
if (slotid) {
unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
& TRB_CR_EPID_MASK;
- event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid,
+ unsigned int streamid = (trb.status >> 16) & 0xffff;
+ event.ccode = xhci_set_ep_dequeue(xhci, slotid,
+ epid, streamid,
trb.parameter);
}
break;
@@ -2554,9 +2729,9 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
break;
case 0x10: /* HCCPARAMS */
if (sizeof(dma_addr_t) == 4) {
- ret = 0x00081000;
+ ret = 0x00087000;
} else {
- ret = 0x00081001;
+ ret = 0x00087001;
}
break;
case 0x14: /* DBOFF */
@@ -2880,6 +3055,7 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
uint64_t val, unsigned size)
{
XHCIState *xhci = ptr;
+ unsigned int epid, streamid;
trace_usb_xhci_doorbell_write(reg, val);
@@ -2898,13 +3074,15 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
(uint32_t)val);
}
} else {
+ epid = val & 0xff;
+ streamid = (val >> 16) & 0xffff;
if (reg > xhci->numslots) {
fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg);
- } else if (val > 31) {
+ } else if (epid > 31) {
fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n",
(int)reg, (uint32_t)val);
} else {
- xhci_kick_ep(xhci, reg, val);
+ xhci_kick_ep(xhci, reg, epid, streamid);
}
}
}
@@ -2988,7 +3166,7 @@ static void xhci_complete(USBPort *port, USBPacket *packet)
return;
}
xhci_complete_packet(xfer);
- xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
+ xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid);
}
static void xhci_child_detach(USBPort *uport, USBDevice *child)
@@ -3033,7 +3211,8 @@ static int xhci_find_epid(USBEndpoint *ep)
}
}
-static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
+static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
+ unsigned int stream)
{
XHCIState *xhci = container_of(bus, XHCIState, bus);
int slotid;
@@ -3044,7 +3223,7 @@ static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
return;
}
- xhci_kick_ep(xhci, slotid, xhci_find_epid(ep));
+ xhci_kick_ep(xhci, slotid, xhci_find_epid(ep), stream);
}
static USBBusOps xhci_bus_ops = {
diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c
index 07f0e01cc0..39f22810b3 100644
--- a/hw/usb/host-bsd.c
+++ b/hw/usb/host-bsd.c
@@ -637,9 +637,3 @@ void usb_host_info(Monitor *mon, const QDict *qdict)
{
usb_host_scan(mon, usb_host_info_device);
}
-
-/* XXX add this */
-int usb_host_device_close(const char *devname)
-{
- return 0;
-}
diff --git a/hw/usb/host-legacy.c b/hw/usb/host-legacy.c
new file mode 100644
index 0000000000..3a5f705721
--- /dev/null
+++ b/hw/usb/host-legacy.c
@@ -0,0 +1,144 @@
+/*
+ * Linux host USB redirector
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Copyright (c) 2008 Max Krasnyansky
+ * Support for host device auto connect & disconnect
+ * Major rewrite to support fully async operation
+ *
+ * Copyright 2008 TJ <linux@tjworld.net>
+ * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
+ * to the legacy /proc/bus/usb USB device discovery and handling
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "hw/usb.h"
+#include "hw/usb/host.h"
+
+/*
+ * Autoconnect filter
+ * Format:
+ * auto:bus:dev[:vid:pid]
+ * auto:bus.dev[:vid:pid]
+ *
+ * bus - bus number (dec, * means any)
+ * dev - device number (dec, * means any)
+ * vid - vendor id (hex, * means any)
+ * pid - product id (hex, * means any)
+ *
+ * See 'lsusb' output.
+ */
+static int parse_filter(const char *spec, struct USBAutoFilter *f)
+{
+ enum { BUS, DEV, VID, PID, DONE };
+ const char *p = spec;
+ int i;
+
+ f->bus_num = 0;
+ f->addr = 0;
+ f->vendor_id = 0;
+ f->product_id = 0;
+
+ for (i = BUS; i < DONE; i++) {
+ p = strpbrk(p, ":.");
+ if (!p) {
+ break;
+ }
+ p++;
+
+ if (*p == '*') {
+ continue;
+ }
+ switch (i) {
+ case BUS:
+ f->bus_num = strtol(p, NULL, 10);
+ break;
+ case DEV:
+ f->addr = strtol(p, NULL, 10);
+ break;
+ case VID:
+ f->vendor_id = strtol(p, NULL, 16);
+ break;
+ case PID:
+ f->product_id = strtol(p, NULL, 16);
+ break;
+ }
+ }
+
+ if (i < DEV) {
+ fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
+ return -1;
+ }
+
+ return 0;
+}
+
+USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
+{
+ struct USBAutoFilter filter;
+ USBDevice *dev;
+ char *p;
+
+ dev = usb_create(bus, "usb-host");
+
+ if (strstr(devname, "auto:")) {
+ if (parse_filter(devname, &filter) < 0) {
+ goto fail;
+ }
+ } else {
+ p = strchr(devname, '.');
+ if (p) {
+ filter.bus_num = strtoul(devname, NULL, 0);
+ filter.addr = strtoul(p + 1, NULL, 0);
+ filter.vendor_id = 0;
+ filter.product_id = 0;
+ } else {
+ p = strchr(devname, ':');
+ if (p) {
+ filter.bus_num = 0;
+ filter.addr = 0;
+ filter.vendor_id = strtoul(devname, NULL, 16);
+ filter.product_id = strtoul(p + 1, NULL, 16);
+ } else {
+ goto fail;
+ }
+ }
+ }
+
+ qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
+ qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
+ qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
+ qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
+ qdev_init_nofail(&dev->qdev);
+ return dev;
+
+fail:
+ qdev_free(&dev->qdev);
+ return NULL;
+}
+
+static void usb_host_register_types(void)
+{
+ usb_legacy_register("usb-host", "host", usb_host_device_open);
+}
+
+type_init(usb_host_register_types)
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index a2cff8a74d..b67aeba096 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -43,6 +43,7 @@
#include <linux/version.h>
#include "hw/usb.h"
#include "hw/usb/desc.h"
+#include "hw/usb/host.h"
/* We redefine it to avoid version problems */
struct usb_ctrltransfer {
@@ -87,14 +88,6 @@ struct endp_data {
int inflight;
};
-struct USBAutoFilter {
- uint32_t bus_num;
- uint32_t addr;
- char *port;
- uint32_t vendor_id;
- uint32_t product_id;
-};
-
enum USBHostDeviceOptions {
USB_HOST_OPT_PIPELINE,
};
@@ -131,7 +124,6 @@ typedef struct USBHostDevice {
static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
static int usb_host_close(USBHostDevice *dev);
-static int parse_filter(const char *spec, struct USBAutoFilter *f);
static void usb_host_auto_check(void *unused);
static int usb_host_read_file(char *line, size_t line_size,
const char *device_file, const char *device_name);
@@ -1544,75 +1536,10 @@ static const TypeInfo usb_host_dev_info = {
static void usb_host_register_types(void)
{
type_register_static(&usb_host_dev_info);
- usb_legacy_register("usb-host", "host", usb_host_device_open);
}
type_init(usb_host_register_types)
-USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
-{
- struct USBAutoFilter filter;
- USBDevice *dev;
- char *p;
-
- dev = usb_create(bus, "usb-host");
-
- if (strstr(devname, "auto:")) {
- if (parse_filter(devname, &filter) < 0) {
- goto fail;
- }
- } else {
- if ((p = strchr(devname, '.'))) {
- filter.bus_num = strtoul(devname, NULL, 0);
- filter.addr = strtoul(p + 1, NULL, 0);
- filter.vendor_id = 0;
- filter.product_id = 0;
- } else if ((p = strchr(devname, ':'))) {
- filter.bus_num = 0;
- filter.addr = 0;
- filter.vendor_id = strtoul(devname, NULL, 16);
- filter.product_id = strtoul(p + 1, NULL, 16);
- } else {
- goto fail;
- }
- }
-
- qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
- qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
- qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
- qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
- qdev_init_nofail(&dev->qdev);
- return dev;
-
-fail:
- qdev_free(&dev->qdev);
- return NULL;
-}
-
-int usb_host_device_close(const char *devname)
-{
-#if 0
- char product_name[PRODUCT_NAME_SZ];
- int bus_num, addr;
- USBHostDevice *s;
-
- if (strstr(devname, "auto:")) {
- return usb_host_auto_del(devname);
- }
- if (usb_host_find_device(&bus_num, &addr, product_name,
- sizeof(product_name), devname) < 0) {
- return -1;
- }
- s = hostdev_find(bus_num, addr);
- if (s) {
- usb_device_delete_addr(s->bus_num, s->dev.addr);
- return 0;
- }
-#endif
-
- return -1;
-}
-
/*
* Read sys file-system device file
*
@@ -1840,56 +1767,6 @@ static void usb_host_auto_check(void *unused)
qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
}
-/*
- * Autoconnect filter
- * Format:
- * auto:bus:dev[:vid:pid]
- * auto:bus.dev[:vid:pid]
- *
- * bus - bus number (dec, * means any)
- * dev - device number (dec, * means any)
- * vid - vendor id (hex, * means any)
- * pid - product id (hex, * means any)
- *
- * See 'lsusb' output.
- */
-static int parse_filter(const char *spec, struct USBAutoFilter *f)
-{
- enum { BUS, DEV, VID, PID, DONE };
- const char *p = spec;
- int i;
-
- f->bus_num = 0;
- f->addr = 0;
- f->vendor_id = 0;
- f->product_id = 0;
-
- for (i = BUS; i < DONE; i++) {
- p = strpbrk(p, ":.");
- if (!p) {
- break;
- }
- p++;
-
- if (*p == '*') {
- continue;
- }
- switch(i) {
- case BUS: f->bus_num = strtol(p, NULL, 10); break;
- case DEV: f->addr = strtol(p, NULL, 10); break;
- case VID: f->vendor_id = strtol(p, NULL, 16); break;
- case PID: f->product_id = strtol(p, NULL, 16); break;
- }
- }
-
- if (i < DEV) {
- fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
- return -1;
- }
-
- return 0;
-}
-
/**********************/
/* USB host device info */
diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c
index 8affba76c1..28d8032caf 100644
--- a/hw/usb/host-stub.c
+++ b/hw/usb/host-stub.c
@@ -45,8 +45,3 @@ USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
{
return NULL;
}
-
-int usb_host_device_close(const char *devname)
-{
- return 0;
-}
diff --git a/hw/usb/host.h b/hw/usb/host.h
new file mode 100644
index 0000000000..048ff3b482
--- /dev/null
+++ b/hw/usb/host.h
@@ -0,0 +1,44 @@
+/*
+ * Linux host USB redirector
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Copyright (c) 2008 Max Krasnyansky
+ * Support for host device auto connect & disconnect
+ * Major rewrite to support fully async operation
+ *
+ * Copyright 2008 TJ <linux@tjworld.net>
+ * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
+ * to the legacy /proc/bus/usb USB device discovery and handling
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_USB_HOST_H
+#define QEMU_USB_HOST_H
+
+struct USBAutoFilter {
+ uint32_t bus_num;
+ uint32_t addr;
+ char *port;
+ uint32_t vendor_id;
+ uint32_t product_id;
+};
+
+#endif /* QEMU_USB_HOST_H */
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 8c0ead07c5..7078403904 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -737,7 +737,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
uint8_t ep)
{
struct usb_redir_bulk_packet_header bulk_packet;
- size_t size = (p->combined) ? p->combined->iov.size : p->iov.size;
+ size_t size = usb_packet_size(p);
const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
if (usbredir_already_in_flight(dev, p->id)) {
@@ -771,12 +771,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
&bulk_packet, NULL, 0);
} else {
uint8_t buf[size];
- if (p->combined) {
- iov_to_buf(p->combined->iov.iov, p->combined->iov.niov,
- 0, buf, size);
- } else {
- usb_packet_copy(p, buf, size);
- }
+ usb_packet_copy(p, buf, size);
usbredir_log_data(dev, "bulk data out:", buf, size);
usbredirparser_send_bulk_packet(dev->parser, p->id,
&bulk_packet, buf, size);
@@ -1830,7 +1825,7 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
p = usbredir_find_packet_by_id(dev, ep, id);
if (p) {
- size_t size = (p->combined) ? p->combined->iov.size : p->iov.size;
+ size_t size = usb_packet_size(p);
usbredir_handle_status(dev, p, bulk_packet->status);
if (data_len > 0) {
usbredir_log_data(dev, "bulk data in:", data, data_len);
@@ -1840,12 +1835,7 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
p->status = USB_RET_BABBLE;
data_len = len = size;
}
- if (p->combined) {
- iov_from_buf(p->combined->iov.iov, p->combined->iov.niov,
- 0, data, data_len);
- } else {
- usb_packet_copy(p, data, data_len);
- }
+ usb_packet_copy(p, data, data_len);
}
p->actual_length = len;
if (p->pid == USB_TOKEN_IN && p->ep->pipeline) {
diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh
index 0778fe2a42..81fe94259d 100644
--- a/scripts/make_device_config.sh
+++ b/scripts/make_device_config.sh
@@ -18,7 +18,7 @@ process_includes () {
f=$src
while [ -n "$f" ] ; do
- f=`tr -d '\r' < $f | awk '/^include / {printf "'$src_dir'/%s", $2}'`
+ f=`cat $f | tr -d '\r' | awk '/^include / {printf "'$src_dir'/%s ", $2}'`
[ $? = 0 ] || exit 1
all_includes="$all_includes $f"
done
diff --git a/trace-events b/trace-events
index 1011f27676..a27ae43032 100644
--- a/trace-events
+++ b/trace-events
@@ -370,11 +370,11 @@ usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d"
usb_xhci_slot_reset(uint32_t slotid) "slotid %d"
usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
-usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint64_t param) "slotid %d, epid %d, ptr %016" PRIx64
-usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
+usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint32_t streamid, uint64_t param) "slotid %d, epid %d, streamid %d, ptr %016" PRIx64
+usb_xhci_ep_kick(uint32_t slotid, uint32_t epid, uint32_t streamid) "slotid %d, epid %d, streamid %d"
usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
-usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d"
+usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t streamid) "%p: slotid %d, epid %d, streamid %d"
usb_xhci_xfer_async(void *xfer) "%p"
usb_xhci_xfer_nak(void *xfer) "%p"
usb_xhci_xfer_retry(void *xfer) "%p"
diff --git a/vl.c b/vl.c
index c5b0eea29b..955d2ffe0f 100644
--- a/vl.c
+++ b/vl.c
@@ -1427,8 +1427,9 @@ static int usb_device_del(const char *devname)
int bus_num, addr;
const char *p;
- if (strstart(devname, "host:", &p))
- return usb_host_device_close(p);
+ if (strstart(devname, "host:", &p)) {
+ return -1;
+ }
if (!usb_enabled(false)) {
return -1;