Merge remote-tracking branch 'kraxel/usb.78' into staging
authorAnthony Liguori <aliguori@us.ibm.com>
Thu, 21 Feb 2013 15:39:17 +0000 (09:39 -0600)
committerAnthony Liguori <aliguori@us.ibm.com>
Thu, 21 Feb 2013 15:39:17 +0000 (09:39 -0600)
# 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

44 files changed:
configure
default-configs/alpha-softmmu.mak
default-configs/arm-softmmu.mak
default-configs/i386-softmmu.mak
default-configs/m68k-softmmu.mak
default-configs/mips-softmmu.mak
default-configs/mips64-softmmu.mak
default-configs/mips64el-softmmu.mak
default-configs/mipsel-softmmu.mak
default-configs/ppc-softmmu.mak
default-configs/ppc64-softmmu.mak
default-configs/ppcemb-softmmu.mak
default-configs/sh4-softmmu.mak
default-configs/sh4eb-softmmu.mak
default-configs/sparc64-softmmu.mak
default-configs/usb.mak [new file with mode: 0644]
default-configs/x86_64-softmmu.mak
hw/Makefile.objs
hw/usb.h
hw/usb/Makefile.objs
hw/usb/core.c
hw/usb/desc.c
hw/usb/dev-bluetooth.c
hw/usb/dev-hid.c
hw/usb/dev-hub.c
hw/usb/dev-network.c
hw/usb/dev-smartcard-reader.c
hw/usb/dev-storage.c
hw/usb/dev-uas.c
hw/usb/dev-wacom.c
hw/usb/hcd-ehci.c
hw/usb/hcd-musb.c
hw/usb/hcd-ohci.c
hw/usb/hcd-uhci.c
hw/usb/hcd-xhci.c
hw/usb/host-bsd.c
hw/usb/host-legacy.c [new file with mode: 0644]
hw/usb/host-linux.c
hw/usb/host-stub.c
hw/usb/host.h [new file with mode: 0644]
hw/usb/redirect.c
scripts/make_device_config.sh
trace-events
vl.c

index bf5970f74bc365a4a49b305006529b4f06bddc55..42cb3144a5be447930e02e0bd2a349a87214e382 100755 (executable)
--- 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
index 501dd413b74ab05542356d6783301736770abfd6..2dbee94c89d8fb26077754d886866a4ba6ccf582 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for alpha-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_SERIAL=y
 CONFIG_I8254=y
 CONFIG_PCKBD=y
index 2f1a5c994300871165ed7240133ce890bf061b28..b40f7b08e2e6a4840eb8888c56a4873e539c41ea 100644 (file)
@@ -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
index 2c78175ae7405aea494675af23f799dfabbde2e1..1b23025a98598e2683ad5fc281b8099b5d56de55 100644 (file)
@@ -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
index 3e2ec3716c5222c2c6459a55d6d5de76ed43fb39..778ea82a10fb7311252c54a84223c13c5bd1ec9a 100644 (file)
@@ -1,5 +1,6 @@
 # Default configuration for m68k-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_PTIMER=y
index a271b1c6da23b9707771308f540a2c9d0d3769a4..4f04a337324f89fe37c30323c9bc4d3da64a0f97 100644 (file)
@@ -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
index 0510bb6a5336b73fa54d7ec189a71c701ec0f525..a5b6c3c36a4fbff34bae61fb8af706d8b9393575 100644 (file)
@@ -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
index ed3bed3b8d276788540c038b518fee961cbb98e1..a0e6de8e68db02da5c93c532c01d72a369520df8 100644 (file)
@@ -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
index fa3a2cacdd39f19010f81176d31148b054c5a83a..753dd76a218da6272e05ea5aa1be533df3a6d1d3 100644 (file)
@@ -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
index 1f4a1cff61d0bd7b6dabb1d6c8306ffd50adbf9c..f9f8a8159b4ad0a5deafbaf77f2e37e4f8f20408 100644 (file)
@@ -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
index 5ff406caa518f328774f7bb2846a569c00d72b24..dc4429437838f01f17984dadbcb7575d19531745 100644 (file)
@@ -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
index aaa9cdc1f76d824b44936c4fb8efc940bcca721c..1c6bcf93fc129d7523702e55244a1998f65aae5c 100644 (file)
@@ -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
index 5c69acc5f53762a5406d5e6b9490ee8128303f2c..e08b2ee1064ca3a56d1187022f7f9f174a025115 100644 (file)
@@ -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
index 7cdc122201d2094c83fe47c2efc325cf5b178140..3a8453552bdc10342841405cc1ec06f5089e76cf 100644 (file)
@@ -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
index 03e8b4271244a782a905859cec75f102dc7fc304..2145b6b29f4232e066ada1ecb79f4c15e096b8b9 100644 (file)
@@ -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 (file)
index 0000000..1bf9075
--- /dev/null
@@ -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
index 233a8564ebc4b74ecf38f3180cc6bbaa3f6b30cd..3392f5abd6531a49009a3897ae77280de600e446 100644 (file)
@@ -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
index 447e32a42e3a52b0ca9b68eedcc4862a9bb2f736..a1f3a808acced8356fae309835105e8e75fce15b 100644 (file)
@@ -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
index bc42639b167aed356c37eaa4f069f416ea5b61c1..382496cf8230730ba1cbe37306dfa8932a6d7be1 100644 (file)
--- 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);
index d1bbbc06e7e490563cf0fea53e2e65da21977776..e63e287ce0db32d46246c09a3f890af674af978b 100644 (file)
@@ -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))
index d057aab90000eb87dae2995e2156337ce0631fbf..15a150aea03806fded1adbb193bb0b41505aef6d 100644 (file)
@@ -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)
 {
index b7c32333d70032a98fdff56f17006ba6e7af9c72..b38938132699f352f151f3a7b04ac57949f82161 100644 (file)
@@ -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;
 }
 
index adbf9d46970d9b6f527f4baa875f6638c7f11508..0f8aa48c85a8d411c3fa1553eb4e1feb8cf38441 100644 (file)
@@ -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);
 }
index 29b64819abdbaf6b549b90c38d4f135e202a9b37..97010488872cacd0aa529a17da07b1ca004e14de 100644 (file)
@@ -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)
index 79f2f46d554d4f65a3c1f6e25791485e501b3443..504c98c35008f0f0490967fc9343d36300e59322 100644 (file)
@@ -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:
index a01a5e793a7733d1691c3fe8169d554ef74b6d39..c08718b6791daf023f88a4a19eb87b4898be37fc 100644 (file)
@@ -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);
index 979a473b37813f01109a8d807a263ab0b11dcb54..caebc1c3fffa8e27476184bb41b564a960a141cb 100644 (file)
@@ -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(
index b89d00f7cf1aa4cd22479898677bffcf97232a86..d3f01aa2a75d531570865c5d5f2db8f73cdbc6dc 100644 (file)
@@ -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;
index d904d1a40b9238bab18d17ab121097bf2230b5dc..1ac5117ba77f8e3efef39a50b667d50fef349886 100644 (file)
@@ -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;
index ab9fa2ef48923bd20b8d7d035dbd9b14f0f32a05..3be5cdefdaa722e43b04140fd685ba9c2567187c 100644 (file)
@@ -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)
index 70406592ef47fa3c396adc1fda05c7a592aa83d4..5176251cb44640d358206c382225f5dffcccf803 100644 (file)
@@ -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);
index 64e9e834bf150d14ff20e64d3cc4ae4d33abe0b3..7968e17c3474027b3add19ae584a16130be67eb5 100644 (file)
@@ -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;
index dd9967b13d888776c4d37b2e0219b4d3d92f566f..51241cda78cca93ed580938b13baf9b990ad0a36 100644 (file)
@@ -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);
index 60645aa21ff1566ee7b17760942d62a2432307ee..f8c42864d14acf8f8b0f7f5027762fc34807d116 100644 (file)
@@ -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);
index 5fb0c488e815a486060d6b883ec9a30ad24370b7..5796102f3a289bc074170b2632e97172954aa261 100644 (file)
@@ -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 = {
index 07f0e01cc004296295a8beda816437d5207cbaf7..39f22810b394db0909f99b932509ef82eb4ddb41 100644 (file)
@@ -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 (file)
index 0000000..3a5f705
--- /dev/null
@@ -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)
index a2cff8a74dd426139183dfe6a7a893081996b651..b67aeba0964a6756fbe0754e551bbd54f9a315b1 100644 (file)
@@ -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 */
 
index 8affba76c1f18eb80f5e4b2e2e76d002bae1dc81..28d8032caf7e968a440a179ce6edcd81782181f3 100644 (file)
@@ -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 (file)
index 0000000..048ff3b
--- /dev/null
@@ -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 */
index 8c0ead07c5f45494ac6ae8f709af14025be7913c..7078403904d909de86ec98e99af5eaae65c86bf6 100644 (file)
@@ -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) {
index 0778fe2a420148934ee51a7378b9b82c8e8fa02e..81fe94259d6561074d4f9ee01ca7ab5067ee42fa 100644 (file)
@@ -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
index 1011f27676609e6d9b0ba13ab44c652aedb7f6d2..a27ae430320722901f769aeccc0f2fecf37fc983 100644 (file)
@@ -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 c5b0eea29b6a37bb95f0ebdd8197acb51bec2bac..955d2ffe0fc25a18fdd83892300c1be5e1e7da98 100644 (file)
--- 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;