qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/22] usb patch queue
@ 2012-10-30 14:26 Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 01/22] xhci: add {get, set}_field macros & enum for pls Gerd Hoffmann
                   ` (21 more replies)
  0 siblings, 22 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

  Hi,

Current state of the usb patch queue, including all experimental bits.
Overview:

   1 ->  8  --  A bunch of xhci bugfixes.  IMO ready to merge.
   9 -> 14  --  Separate core + pci bits of ehci, add sysfs ehci.
                Should be (almost) ready for merge too.
  15 -> 20  --  Experiments with dynamic type generation for
                UHCI and EHCI.  Does also provide a helper function
                for q35 usb bus creation.  QOM folks should have a
                look at this.  I expect discussions ;)
  21        --  Experimental USB Media Transfer Protocol implementation
                for easy filesharing.
  22        --  Unrelated trace patch.

/me plans to send out a pull request for 1 -> 14 before kvm forum.

Reviews & comments and test results are welcome.

Bits are also available from:
  git://git.kraxel.org/qemu rebase/usb-next   [ warning: moving target ]

cheers,
  Gerd

Gerd Hoffmann (18):
  xhci: add {get,set}_field macros & enum for pls
  xhci: s/xhci_update_port/xhci_port_update/
  xhci: add xhci_port_have_device
  xhci: add xhci_port_notify
  xhci: add xhci_port_reset
  xhci: set pls in xhci_port_update & xhci_port_reset
  xhci: add port trace points
  xhci: allow address slot being called multiple times
  usb/ehci: split into multiple source files
  usb/ehci: add sysbus variant
  uhci: dynamic type generation
  uhci: stick irq routing info into UHCIInfo too.
  uhci: add ich9 00:1a.* variants
  usb/ehci-pci: dynamic type generation
  usb/ehci-pci: add ich9 00:1a.* variant
  usb/ehci-pci: add helper to create ich9 usb controllers
  [RfC] usb: mtp filesharing
  trace: allow disabling events in events file

Peter Crosthwaite (4):
  usb/ehci: parameterise the register region offsets
  usb/ehci: Abstract away PCI DMA API
  usb/ehci: seperate out PCIisms
  usb/ehci: Guard definition of EHCI_DEBUG

 hw/usb.h                 |    2 +
 hw/usb/Makefile.objs     |    3 +-
 hw/usb/dev-mtp.c         | 1086 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/usb/hcd-ehci-pci.c    |  200 +++++++++
 hw/usb/hcd-ehci-sysbus.c |   77 ++++
 hw/usb/hcd-ehci.c        |  465 ++------------------
 hw/usb/hcd-ehci.h        |  320 ++++++++++++++
 hw/usb/hcd-uhci.c        |  249 +++++------
 hw/usb/hcd-xhci.c        |  134 +++++--
 trace-events             |   24 +
 trace/control.c          |    9 +-
 11 files changed, 1968 insertions(+), 601 deletions(-)
 create mode 100644 hw/usb/dev-mtp.c
 create mode 100644 hw/usb/hcd-ehci-pci.c
 create mode 100644 hw/usb/hcd-ehci-sysbus.c
 create mode 100644 hw/usb/hcd-ehci.h

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 01/22] xhci: add {get, set}_field macros & enum for pls
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 02/22] xhci: s/xhci_update_port/xhci_port_update/ Gerd Hoffmann
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add {get,set}_field macros (simliar to ehci) to read and update
some bits of a word.  Put them into use for updating pls (port
link state) values.  Also add a enum for pls values.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |   39 +++++++++++++++++++++++++++++++--------
 1 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 7b65741..c062330 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -146,6 +146,21 @@ typedef struct XHCITRB {
     bool ccs;
 } XHCITRB;
 
+enum {
+    PLS_U0              =  0,
+    PLS_U1              =  1,
+    PLS_U2              =  2,
+    PLS_U3              =  3,
+    PLS_DISABLED        =  4,
+    PLS_RX_DETECT       =  5,
+    PLS_INACTIVE        =  6,
+    PLS_POLLING         =  7,
+    PLS_RECOVERY        =  8,
+    PLS_HOT_RESET       =  9,
+    PLS_COMPILANCE_MODE = 10,
+    PLS_TEST_MODE       = 11,
+    PLS_RESUME          = 15,
+};
 
 typedef enum TRBType {
     TRB_RESERVED = 0,
@@ -287,6 +302,16 @@ typedef enum TRBCCode {
 
 typedef struct XHCIState XHCIState;
 
+#define get_field(data, field)                  \
+    (((data) >> field##_SHIFT) & field##_MASK)
+
+#define set_field(data, newval, field) do {                     \
+        uint32_t val = *data;                                   \
+        val &= ~(field##_MASK << field##_SHIFT);                \
+        val |= ((newval) & field##_MASK) << field##_SHIFT;      \
+        *data = val;                                            \
+    } while (0)
+
 typedef enum EPType {
     ET_INVALID = 0,
     ET_ISO_OUT,
@@ -2334,7 +2359,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
         }
     }
 
-    if (xhci_running(xhci)) {
+    if (xhci_running(port->xhci)) {
         port->portsc |= PORTSC_CSC;
         XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
                          port->portnr << 24};
@@ -2368,7 +2393,7 @@ static void xhci_reset(DeviceState *dev)
     }
 
     for (i = 0; i < xhci->numports; i++) {
-        xhci_update_port(xhci, xhci->ports + i, 0);
+        xhci_update_port(xhci->ports + i, 0);
     }
 
     for (i = 0; i < xhci->numintrs; i++) {
@@ -2499,8 +2524,8 @@ static void xhci_port_write(void *ptr, hwaddr reg,
                            PORTSC_PRC|PORTSC_PLC|PORTSC_CEC));
         if (val & PORTSC_LWS) {
             /* overwrite PLS only when LWS=1 */
-            portsc &= ~(PORTSC_PLS_MASK << PORTSC_PLS_SHIFT);
-            portsc |= val & (PORTSC_PLS_MASK << PORTSC_PLS_SHIFT);
+            uint32_t pls = get_field(val, PORTSC_PLS);
+            set_field(&portsc, pls, PORTSC_PLS);
         }
         /* read/write bits */
         portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE);
@@ -2832,13 +2857,11 @@ static void xhci_wakeup(USBPort *usbport)
     XHCIPort *port = xhci_lookup_port(xhci, usbport);
     XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
                      port->portnr << 24};
-    uint32_t pls;
 
-    pls = (port->portsc >> PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK;
-    if (pls != 3) {
+    if (get_field(port->portsc, PORTSC_PLS) != PLS_U3) {
         return;
     }
-    port->portsc |= 0xf << PORTSC_PLS_SHIFT;
+    set_field(&port->portsc, PLS_RESUME, PORTSC_PLS);
     if (port->portsc & PORTSC_PLC) {
         return;
     }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 02/22] xhci: s/xhci_update_port/xhci_port_update/
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 01/22] xhci: add {get, set}_field macros & enum for pls Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 03/22] xhci: add xhci_port_have_device Gerd Hoffmann
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Rename the function for xhci_port_* naming scheme, also drop
the xhci parameter as port carries a pointer to xhci anyway.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index c062330..f5ab692 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2337,7 +2337,7 @@ static void xhci_process_commands(XHCIState *xhci)
     }
 }
 
-static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
+static void xhci_port_update(XHCIPort *port, int is_detach)
 {
     port->portsc = PORTSC_PP;
     if (port->uport->dev && port->uport->dev->attached && !is_detach &&
@@ -2363,7 +2363,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
         port->portsc |= PORTSC_CSC;
         XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
                          port->portnr << 24};
-        xhci_event(xhci, &ev, 0);
+        xhci_event(port->xhci, &ev, 0);
         DPRINTF("xhci: port change event for port %d\n", port->portnr);
     }
 }
@@ -2393,7 +2393,7 @@ static void xhci_reset(DeviceState *dev)
     }
 
     for (i = 0; i < xhci->numports; i++) {
-        xhci_update_port(xhci->ports + i, 0);
+        xhci_port_update(xhci->ports + i, 0);
     }
 
     for (i = 0; i < xhci->numintrs; i++) {
@@ -2840,7 +2840,7 @@ static void xhci_attach(USBPort *usbport)
     XHCIState *xhci = usbport->opaque;
     XHCIPort *port = xhci_lookup_port(xhci, usbport);
 
-    xhci_update_port(xhci, port, 0);
+    xhci_port_update(port, 0);
 }
 
 static void xhci_detach(USBPort *usbport)
@@ -2848,7 +2848,7 @@ static void xhci_detach(USBPort *usbport)
     XHCIState *xhci = usbport->opaque;
     XHCIPort *port = xhci_lookup_port(xhci, usbport);
 
-    xhci_update_port(xhci, port, 1);
+    xhci_port_update(port, 1);
 }
 
 static void xhci_wakeup(USBPort *usbport)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 03/22] xhci: add xhci_port_have_device
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 01/22] xhci: add {get, set}_field macros & enum for pls Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 02/22] xhci: s/xhci_update_port/xhci_port_update/ Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 04/22] xhci: add xhci_port_notify Gerd Hoffmann
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Factor out the code which checks whenever a usb device is attached
to the port in question.  No functional change.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index f5ab692..62cca90 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2337,11 +2337,21 @@ static void xhci_process_commands(XHCIState *xhci)
     }
 }
 
+static bool xhci_port_have_device(XHCIPort *port)
+{
+    if (!port->uport->dev || !port->uport->dev->attached) {
+        return false; /* no device present */
+    }
+    if (!((1 << port->uport->dev->speed) & port->speedmask)) {
+        return false; /* speed mismatch */
+    }
+    return true;
+}
+
 static void xhci_port_update(XHCIPort *port, int is_detach)
 {
     port->portsc = PORTSC_PP;
-    if (port->uport->dev && port->uport->dev->attached && !is_detach &&
-        (1 << port->uport->dev->speed) & port->speedmask) {
+    if (!is_detach && xhci_port_have_device(port)) {
         port->portsc |= PORTSC_CCS;
         switch (port->uport->dev->speed) {
         case USB_SPEED_LOW:
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 04/22] xhci: add xhci_port_notify
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 03/22] xhci: add xhci_port_have_device Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 05/22] xhci: add xhci_port_reset Gerd Hoffmann
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Create a function to notify the guest about port
status changes and put it into use.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |   31 +++++++++++++++++--------------
 1 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 62cca90..3af4639 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2348,6 +2348,21 @@ static bool xhci_port_have_device(XHCIPort *port)
     return true;
 }
 
+static void xhci_port_notify(XHCIPort *port, uint32_t bits)
+{
+    XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
+                     port->portnr << 24 };
+
+    if ((port->portsc & bits) == bits) {
+        return;
+    }
+    port->portsc |= bits;
+    if (!xhci_running(port->xhci)) {
+        return;
+    }
+    xhci_event(port->xhci, &ev, 0);
+}
+
 static void xhci_port_update(XHCIPort *port, int is_detach)
 {
     port->portsc = PORTSC_PP;
@@ -2369,13 +2384,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach)
         }
     }
 
-    if (xhci_running(port->xhci)) {
-        port->portsc |= PORTSC_CSC;
-        XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
-                         port->portnr << 24};
-        xhci_event(port->xhci, &ev, 0);
-        DPRINTF("xhci: port change event for port %d\n", port->portnr);
-    }
+    xhci_port_notify(port, PORTSC_CSC);
 }
 
 static void xhci_reset(DeviceState *dev)
@@ -2865,18 +2874,12 @@ static void xhci_wakeup(USBPort *usbport)
 {
     XHCIState *xhci = usbport->opaque;
     XHCIPort *port = xhci_lookup_port(xhci, usbport);
-    XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
-                     port->portnr << 24};
 
     if (get_field(port->portsc, PORTSC_PLS) != PLS_U3) {
         return;
     }
     set_field(&port->portsc, PLS_RESUME, PORTSC_PLS);
-    if (port->portsc & PORTSC_PLC) {
-        return;
-    }
-    port->portsc |= PORTSC_PLC;
-    xhci_event(xhci, &ev, 0);
+    xhci_port_notify(port, PORTSC_PLC);
 }
 
 static void xhci_complete(USBPort *port, USBPacket *packet)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 05/22] xhci: add xhci_port_reset
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 04/22] xhci: add xhci_port_notify Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 06/22] xhci: set pls in xhci_port_update & xhci_port_reset Gerd Hoffmann
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Move port reset logic to its own function.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 3af4639..1db803c 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2387,6 +2387,13 @@ static void xhci_port_update(XHCIPort *port, int is_detach)
     xhci_port_notify(port, PORTSC_CSC);
 }
 
+static void xhci_port_reset(XHCIPort *port)
+{
+    DPRINTF("xhci: port %d reset\n", port);
+    usb_device_reset(port->uport->dev);
+    port->portsc |= PORTSC_PRC | PORTSC_PED;
+}
+
 static void xhci_reset(DeviceState *dev)
 {
     XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev.qdev, dev);
@@ -2549,13 +2556,11 @@ static void xhci_port_write(void *ptr, hwaddr reg,
         /* read/write bits */
         portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE);
         portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE));
+        port->portsc = portsc;
         /* write-1-to-start bits */
         if (val & PORTSC_PR) {
-            DPRINTF("xhci: port %d reset\n", port);
-            usb_device_reset(port->uport->dev);
-            portsc |= PORTSC_PRC | PORTSC_PED;
+            xhci_port_reset(port);
         }
-        port->portsc = portsc;
         break;
     case 0x04: /* PORTPMSC */
     case 0x08: /* PORTLI */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 06/22] xhci: set pls in xhci_port_update & xhci_port_reset
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 05/22] xhci: add xhci_port_reset Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 07/22] xhci: add port trace points Gerd Hoffmann
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Set the port link state to the correct values in xhci_port_update and
xhci_port_reset functions.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |   26 ++++++++++++++++++++++++--
 1 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 1db803c..84d1b26 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2365,33 +2365,55 @@ static void xhci_port_notify(XHCIPort *port, uint32_t bits)
 
 static void xhci_port_update(XHCIPort *port, int is_detach)
 {
+    uint32_t pls = PLS_RX_DETECT;
+
     port->portsc = PORTSC_PP;
     if (!is_detach && xhci_port_have_device(port)) {
         port->portsc |= PORTSC_CCS;
         switch (port->uport->dev->speed) {
         case USB_SPEED_LOW:
             port->portsc |= PORTSC_SPEED_LOW;
+            pls = PLS_POLLING;
             break;
         case USB_SPEED_FULL:
             port->portsc |= PORTSC_SPEED_FULL;
+            pls = PLS_POLLING;
             break;
         case USB_SPEED_HIGH:
             port->portsc |= PORTSC_SPEED_HIGH;
+            pls = PLS_POLLING;
             break;
         case USB_SPEED_SUPER:
             port->portsc |= PORTSC_SPEED_SUPER;
+            port->portsc |= PORTSC_PED;
+            pls = PLS_U0;
             break;
         }
     }
-
+    set_field(&port->portsc, pls, PORTSC_PLS);
     xhci_port_notify(port, PORTSC_CSC);
 }
 
 static void xhci_port_reset(XHCIPort *port)
 {
     DPRINTF("xhci: port %d reset\n", port);
+    if (!xhci_port_have_device(port)) {
+        return;
+    }
+
     usb_device_reset(port->uport->dev);
-    port->portsc |= PORTSC_PRC | PORTSC_PED;
+
+    switch (port->uport->dev->speed) {
+    case USB_SPEED_LOW:
+    case USB_SPEED_FULL:
+    case USB_SPEED_HIGH:
+        set_field(&port->portsc, PLS_U0, PORTSC_PLS);
+        port->portsc |= PORTSC_PED;
+        break;
+    }
+
+    port->portsc &= ~PORTSC_PR;
+    xhci_port_notify(port, PORTSC_PRC);
 }
 
 static void xhci_reset(DeviceState *dev)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 07/22] xhci: add port trace points
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 06/22] xhci: set pls in xhci_port_update & xhci_port_reset Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 08/22] xhci: allow address slot being called multiple times Gerd Hoffmann
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |    6 +++++-
 trace-events      |    2 ++
 2 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 84d1b26..3259638 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2391,12 +2391,14 @@ static void xhci_port_update(XHCIPort *port, int is_detach)
         }
     }
     set_field(&port->portsc, pls, PORTSC_PLS);
+    trace_usb_xhci_port_link(port->portnr, pls);
     xhci_port_notify(port, PORTSC_CSC);
 }
 
 static void xhci_port_reset(XHCIPort *port)
 {
-    DPRINTF("xhci: port %d reset\n", port);
+    trace_usb_xhci_port_reset(port->portnr);
+
     if (!xhci_port_have_device(port)) {
         return;
     }
@@ -2408,6 +2410,7 @@ static void xhci_port_reset(XHCIPort *port)
     case USB_SPEED_FULL:
     case USB_SPEED_HIGH:
         set_field(&port->portsc, PLS_U0, PORTSC_PLS);
+        trace_usb_xhci_port_link(port->portnr, PLS_U0);
         port->portsc |= PORTSC_PED;
         break;
     }
@@ -2574,6 +2577,7 @@ static void xhci_port_write(void *ptr, hwaddr reg,
             /* overwrite PLS only when LWS=1 */
             uint32_t pls = get_field(val, PORTSC_PLS);
             set_field(&portsc, pls, PORTSC_PLS);
+            trace_usb_xhci_port_link(port->portnr, pls);
         }
         /* read/write bits */
         portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE);
diff --git a/trace-events b/trace-events
index 7ee21e5..0cb991e 100644
--- a/trace-events
+++ b/trace-events
@@ -333,6 +333,8 @@ usb_xhci_irq_msix_use(uint32_t nr) "nr %d"
 usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d"
 usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
 usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
+usb_xhci_port_reset(uint32_t port) "port %d"
+usb_xhci_port_link(uint32_t port, uint32_t pls) "port %d, pls %d"
 usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
 usb_xhci_slot_disable(uint32_t slotid) "slotid %d"
 usb_xhci_slot_address(uint32_t slotid) "slotid %d"
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 08/22] xhci: allow address slot being called multiple times
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (6 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 07/22] xhci: add port trace points Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 09/22] usb/ehci: parameterise the register region offsets Gerd Hoffmann
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

win8 guests do that for some reason ...

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 3259638..900abf5 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -483,6 +483,8 @@ enum xhci_flags {
 
 static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
                          unsigned int epid);
+static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
+                                unsigned int epid);
 static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
 static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v);
 
@@ -1075,8 +1077,7 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
 
     slot = &xhci->slots[slotid-1];
     if (slot->eps[epid-1]) {
-        fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid);
-        return CC_TRB_ERROR;
+        xhci_disable_ep(xhci, slotid, epid);
     }
 
     epctx = g_malloc(sizeof(XHCIEPContext));
@@ -1919,6 +1920,9 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
     }
 
     for (i = 0; i < xhci->numslots; i++) {
+        if (i == slotid-1) {
+            continue;
+        }
         if (xhci->slots[i].uport == uport) {
             fprintf(stderr, "xhci: port %s already assigned to slot %d\n",
                     uport->path, i+1);
@@ -1936,6 +1940,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
         slot->devaddr = xhci->devaddr++;
         slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr;
         DPRINTF("xhci: device address is %d\n", slot->devaddr);
+        usb_device_reset(dev);
         usb_device_handle_control(dev, NULL,
                                   DeviceOutRequest | USB_REQ_SET_ADDRESS,
                                   slot->devaddr, 0, 0, NULL);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 09/22] usb/ehci: parameterise the register region offsets
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (7 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 08/22] xhci: allow address slot being called multiple times Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 10/22] usb/ehci: Abstract away PCI DMA API Gerd Hoffmann
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Crosthwaite, Gerd Hoffmann

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

The capabilities register and operational register offsets can vary from one
EHCI implementation to the next. Parameterise accordingly.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-ehci.c |   68 ++++++++++++++++++++++++++++-------------------------
 1 files changed, 36 insertions(+), 32 deletions(-)

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index f14f9d7..7f04322 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -48,20 +48,18 @@
 #define USB_RET_PROCERR   (-99)
 
 #define MMIO_SIZE        0x1000
+#define CAPA_SIZE        0x10
 
 /* Capability Registers Base Address - section 2.2 */
-#define CAPREGBASE       0x0000
-#define CAPLENGTH        CAPREGBASE + 0x0000  // 1-byte, 0x0001 reserved
-#define HCIVERSION       CAPREGBASE + 0x0002  // 2-bytes, i/f version #
-#define HCSPARAMS        CAPREGBASE + 0x0004  // 4-bytes, structural params
-#define HCCPARAMS        CAPREGBASE + 0x0008  // 4-bytes, capability params
+#define CAPLENGTH        0x0000  /* 1-byte, 0x0001 reserved */
+#define HCIVERSION       0x0002  /* 2-bytes, i/f version # */
+#define HCSPARAMS        0x0004  /* 4-bytes, structural params */
+#define HCCPARAMS        0x0008  /* 4-bytes, capability params */
 #define EECP             HCCPARAMS + 1
-#define HCSPPORTROUTE1   CAPREGBASE + 0x000c
-#define HCSPPORTROUTE2   CAPREGBASE + 0x0010
+#define HCSPPORTROUTE1   0x000c
+#define HCSPPORTROUTE2   0x0010
 
-#define OPREGBASE        0x0020        // Operational Registers Base Address
-
-#define USBCMD           OPREGBASE + 0x0000
+#define USBCMD           0x0000
 #define USBCMD_RUNSTOP   (1 << 0)      // run / Stop
 #define USBCMD_HCRESET   (1 << 1)      // HC Reset
 #define USBCMD_FLS       (3 << 2)      // Frame List Size
@@ -75,7 +73,7 @@
 #define USBCMD_ITC       (0x7f << 16)  // Int Threshold Control
 #define USBCMD_ITC_SH    16            // Int Threshold Control Shift
 
-#define USBSTS           OPREGBASE + 0x0004
+#define USBSTS           0x0004
 #define USBSTS_RO_MASK   0x0000003f
 #define USBSTS_INT       (1 << 0)      // USB Interrupt
 #define USBSTS_ERRINT    (1 << 1)      // Error Interrupt
@@ -92,18 +90,18 @@
  *  Interrupt enable bits correspond to the interrupt active bits in USBSTS
  *  so no need to redefine here.
  */
-#define USBINTR              OPREGBASE + 0x0008
+#define USBINTR              0x0008
 #define USBINTR_MASK         0x0000003f
 
-#define FRINDEX              OPREGBASE + 0x000c
-#define CTRLDSSEGMENT        OPREGBASE + 0x0010
-#define PERIODICLISTBASE     OPREGBASE + 0x0014
-#define ASYNCLISTADDR        OPREGBASE + 0x0018
+#define FRINDEX              0x000c
+#define CTRLDSSEGMENT        0x0010
+#define PERIODICLISTBASE     0x0014
+#define ASYNCLISTADDR        0x0018
 #define ASYNCLISTADDR_MASK   0xffffffe0
 
-#define CONFIGFLAG           OPREGBASE + 0x0040
+#define CONFIGFLAG           0x0040
 
-#define PORTSC               (OPREGBASE + 0x0044)
+#define PORTSC               0x0044
 #define PORTSC_BEGIN         PORTSC
 #define PORTSC_END           (PORTSC + 4 * NB_PORTS)
 /*
@@ -395,6 +393,8 @@ struct EHCIState {
     MemoryRegion mem_opreg;
     MemoryRegion mem_ports;
     int companion_count;
+    uint16_t capsbase;
+    uint16_t opregbase;
 
     /* properties */
     uint32_t maxframes;
@@ -403,9 +403,9 @@ struct EHCIState {
      *  EHCI spec version 1.0 Section 2.3
      *  Host Controller Operational Registers
      */
-    uint8_t caps[OPREGBASE];
+    uint8_t caps[CAPA_SIZE];
     union {
-        uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)];
+        uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)];
         struct {
             uint32_t usbcmd;
             uint32_t usbsts;
@@ -506,8 +506,7 @@ static const char *state2str(uint32_t state)
 
 static const char *addr2str(hwaddr addr)
 {
-    return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names),
-                  addr + OPREGBASE);
+    return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
 }
 
 static void ehci_trace_usbsts(uint32_t mask, int state)
@@ -1115,7 +1114,7 @@ static uint64_t ehci_opreg_read(void *ptr, hwaddr addr,
     uint32_t val;
 
     val = s->opreg[addr >> 2];
-    trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val);
+    trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val);
     return val;
 }
 
@@ -1211,9 +1210,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
     uint32_t old = *mmio;
     int i;
 
-    trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val);
+    trace_usb_ehci_opreg_write(addr + s->opregbase, addr2str(addr), val);
 
-    switch (addr + OPREGBASE) {
+    switch (addr) {
     case USBCMD:
         if (val & USBCMD_HCRESET) {
             ehci_reset(s);
@@ -1291,7 +1290,8 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
     }
 
     *mmio = val;
-    trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old);
+    trace_usb_ehci_opreg_change(addr + s->opregbase, addr2str(addr),
+                                *mmio, old);
 }
 
 
@@ -2731,8 +2731,11 @@ static int usb_ehci_initfn(PCIDevice *dev)
     pci_conf[0x6e] = 0x00;
     pci_conf[0x6f] = 0xc0;  // USBLEFCTLSTS
 
+    s->capsbase = 0x00;
+    s->opregbase = 0x20;
+
     /* 2.2 host controller interface version */
-    s->caps[0x00] = (uint8_t) OPREGBASE;
+    s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
     s->caps[0x01] = 0x00;
     s->caps[0x02] = 0x00;
     s->caps[0x03] = 0x01;        /* HC version */
@@ -2765,15 +2768,16 @@ static int usb_ehci_initfn(PCIDevice *dev)
 
     memory_region_init(&s->mem, "ehci", MMIO_SIZE);
     memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s,
-                          "capabilities", OPREGBASE);
+                          "capabilities", CAPA_SIZE);
     memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s,
-                          "operational", PORTSC_BEGIN - OPREGBASE);
+                          "operational", PORTSC_BEGIN);
     memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s,
                           "ports", PORTSC_END - PORTSC_BEGIN);
 
-    memory_region_add_subregion(&s->mem, 0,            &s->mem_caps);
-    memory_region_add_subregion(&s->mem, OPREGBASE,    &s->mem_opreg);
-    memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports);
+    memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps);
+    memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
+    memory_region_add_subregion(&s->mem, s->opregbase + PORTSC_BEGIN,
+                                &s->mem_ports);
 
     pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 10/22] usb/ehci: Abstract away PCI DMA API
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (8 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 09/22] usb/ehci: parameterise the register region offsets Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 11/22] usb/ehci: seperate out PCIisms Gerd Hoffmann
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Crosthwaite, Gerd Hoffmann

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Pull the DMAContext for the PCI DMA out at device init time and put it into
the device state. Use dma_memory_read/write() instead of pci specific versions.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-ehci.c |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 7f04322..28890b5 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -389,6 +389,7 @@ struct EHCIState {
     USBBus bus;
     qemu_irq irq;
     MemoryRegion mem;
+    DMAContext *dma;
     MemoryRegion mem_caps;
     MemoryRegion mem_opreg;
     MemoryRegion mem_ports;
@@ -1304,7 +1305,7 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr,
     int i;
 
     for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
-        pci_dma_read(&ehci->dev, addr, buf, sizeof(*buf));
+        dma_memory_read(ehci->dma, addr, buf, sizeof(*buf));
         *buf = le32_to_cpu(*buf);
     }
 
@@ -1319,7 +1320,7 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr,
 
     for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
         uint32_t tmp = cpu_to_le32(*buf);
-        pci_dma_write(&ehci->dev, addr, &tmp, sizeof(tmp));
+        dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp));
     }
 
     return 1;
@@ -1402,7 +1403,7 @@ static int ehci_init_transfer(EHCIPacket *p)
     cpage  = get_field(p->qtd.token, QTD_TOKEN_CPAGE);
     bytes  = get_field(p->qtd.token, QTD_TOKEN_TBYTES);
     offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK;
-    pci_dma_sglist_init(&p->sgl, &p->queue->ehci->dev, 5);
+    qemu_sglist_init(&p->sgl, 5, p->queue->ehci->dma);
 
     while (bytes > 0) {
         if (cpage > 4) {
@@ -1647,7 +1648,7 @@ static int ehci_process_itd(EHCIState *ehci,
                 return USB_RET_PROCERR;
             }
 
-            pci_dma_sglist_init(&ehci->isgl, &ehci->dev, 2);
+            qemu_sglist_init(&ehci->isgl, 2, ehci->dma);
             if (off + len > 4096) {
                 /* transfer crosses page border */
                 uint32_t len2 = off + len - 4096;
@@ -2402,7 +2403,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
         }
         list |= ((ehci->frindex & 0x1ff8) >> 1);
 
-        pci_dma_read(&ehci->dev, list, &entry, sizeof entry);
+        dma_memory_read(ehci->dma, list, &entry, sizeof entry);
         entry = le32_to_cpu(entry);
 
         DPRINTF("PERIODIC state adv fr=%d.  [%08X] -> %08X\n",
@@ -2750,6 +2751,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
 
     s->irq = s->dev.irq[3];
 
+    s->dma = pci_dma_context(dev);
+
     usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
     for(i = 0; i < NB_PORTS; i++) {
         usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 11/22] usb/ehci: seperate out PCIisms
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (9 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 10/22] usb/ehci: Abstract away PCI DMA API Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 12/22] usb/ehci: Guard definition of EHCI_DEBUG Gerd Hoffmann
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Crosthwaite, Gerd Hoffmann

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Seperate the PCI stuff from the EHCI components. Extracted the PCIDevice
out into a new wrapper struct to make EHCIState non-PCI-specific. Seperated
tho non PCI init component out into a seperate "common" init function.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-ehci.c |  124 +++++++++++++++++++++++++++++++----------------------
 1 files changed, 72 insertions(+), 52 deletions(-)

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 28890b5..59580fc 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -385,7 +385,6 @@ struct EHCIQueue {
 typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
 
 struct EHCIState {
-    PCIDevice dev;
     USBBus bus;
     qemu_irq irq;
     MemoryRegion mem;
@@ -447,6 +446,11 @@ struct EHCIState {
     bool int_req_by_async;
 };
 
+typedef struct EHCIPCIState {
+    PCIDevice pcidev;
+    EHCIState ehci;
+} EHCIPCIState;
+
 #define SET_LAST_RUN_CLOCK(s) \
     (s)->last_run_ns = qemu_get_clock_ns(vm_clock);
 
@@ -2553,7 +2557,7 @@ static const MemoryRegionOps ehci_mmio_port_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static int usb_ehci_initfn(PCIDevice *dev);
+static int usb_ehci_pci_initfn(PCIDevice *dev);
 
 static USBPortOps ehci_port_ops = {
     .attach = ehci_attach,
@@ -2614,12 +2618,11 @@ static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
 }
 
 static const VMStateDescription vmstate_ehci = {
-    .name        = "ehci",
+    .name        = "ehci-core",
     .version_id  = 2,
     .minimum_version_id  = 1,
     .post_load   = usb_ehci_post_load,
     .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, EHCIState),
         /* mmio registers */
         VMSTATE_UINT32(usbcmd, EHCIState),
         VMSTATE_UINT32(usbsts, EHCIState),
@@ -2650,8 +2653,19 @@ static const VMStateDescription vmstate_ehci = {
     }
 };
 
-static Property ehci_properties[] = {
-    DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
+static const VMStateDescription vmstate_ehci_pci = {
+    .name        = "ehci",
+    .version_id  = 2,
+    .minimum_version_id  = 1,
+    .post_load   = usb_ehci_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
+        VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
+    }
+};
+
+static Property ehci_pci_properties[] = {
+    DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -2660,13 +2674,13 @@ static void ehci_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
-    k->init = usb_ehci_initfn;
+    k->init = usb_ehci_pci_initfn;
     k->vendor_id = PCI_VENDOR_ID_INTEL;
     k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
     k->revision = 0x10;
     k->class_id = PCI_CLASS_SERIAL_USB;
     dc->vmsd = &vmstate_ehci;
-    dc->props = ehci_properties;
+    dc->props = ehci_pci_properties;
 }
 
 static TypeInfo ehci_info = {
@@ -2681,13 +2695,13 @@ static void ich9_ehci_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
-    k->init = usb_ehci_initfn;
+    k->init = usb_ehci_pci_initfn;
     k->vendor_id = PCI_VENDOR_ID_INTEL;
     k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
     k->revision = 0x03;
     k->class_id = PCI_CLASS_SERIAL_USB;
     dc->vmsd = &vmstate_ehci;
-    dc->props = ehci_properties;
+    dc->props = ehci_pci_properties;
 }
 
 static TypeInfo ich9_ehci_info = {
@@ -2697,44 +2711,10 @@ static TypeInfo ich9_ehci_info = {
     .class_init    = ich9_ehci_class_init,
 };
 
-static int usb_ehci_initfn(PCIDevice *dev)
+static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
 {
-    EHCIState *s = DO_UPCAST(EHCIState, dev, dev);
-    uint8_t *pci_conf = s->dev.config;
     int i;
 
-    pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-
-    /* capabilities pointer */
-    pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
-    //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50);
-
-    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
-    pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
-    pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
-
-    // pci_conf[0x50] = 0x01; // power management caps
-
-    pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); // release number (2.1.4)
-    pci_set_byte(&pci_conf[0x61], 0x20);  // frame length adjustment (2.1.5)
-    pci_set_word(&pci_conf[0x62], 0x00);  // port wake up capability (2.1.6)
-
-    pci_conf[0x64] = 0x00;
-    pci_conf[0x65] = 0x00;
-    pci_conf[0x66] = 0x00;
-    pci_conf[0x67] = 0x00;
-    pci_conf[0x68] = 0x01;
-    pci_conf[0x69] = 0x00;
-    pci_conf[0x6a] = 0x00;
-    pci_conf[0x6b] = 0x00;  // USBLEGSUP
-    pci_conf[0x6c] = 0x00;
-    pci_conf[0x6d] = 0x00;
-    pci_conf[0x6e] = 0x00;
-    pci_conf[0x6f] = 0xc0;  // USBLEFCTLSTS
-
-    s->capsbase = 0x00;
-    s->opregbase = 0x20;
-
     /* 2.2 host controller interface version */
     s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
     s->caps[0x01] = 0x00;
@@ -2745,15 +2725,10 @@ static int usb_ehci_initfn(PCIDevice *dev)
     s->caps[0x06] = 0x00;
     s->caps[0x07] = 0x00;
     s->caps[0x08] = 0x80;        /* We can cache whole frame, no 64-bit */
-    s->caps[0x09] = 0x68;        /* EECP */
     s->caps[0x0a] = 0x00;
     s->caps[0x0b] = 0x00;
 
-    s->irq = s->dev.irq[3];
-
-    s->dma = pci_dma_context(dev);
-
-    usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
+    usb_bus_new(&s->bus, &ehci_bus_ops, dev);
     for(i = 0; i < NB_PORTS; i++) {
         usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
                           USB_SPEED_MASK_HIGH);
@@ -2781,8 +2756,53 @@ static int usb_ehci_initfn(PCIDevice *dev)
     memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
     memory_region_add_subregion(&s->mem, s->opregbase + PORTSC_BEGIN,
                                 &s->mem_ports);
+}
+
+static int usb_ehci_pci_initfn(PCIDevice *dev)
+{
+    EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
+    EHCIState *s = &i->ehci;
+    uint8_t *pci_conf = dev->config;
+
+    pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
+
+    /* capabilities pointer */
+    pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
+    /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
+
+    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
+    pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
+    pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
+
+    /* pci_conf[0x50] = 0x01; *//* power management caps */
+
+    pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
+    pci_set_byte(&pci_conf[0x61], 0x20);  /* frame length adjustment (2.1.5) */
+    pci_set_word(&pci_conf[0x62], 0x00);  /* port wake up capability (2.1.6) */
+
+    pci_conf[0x64] = 0x00;
+    pci_conf[0x65] = 0x00;
+    pci_conf[0x66] = 0x00;
+    pci_conf[0x67] = 0x00;
+    pci_conf[0x68] = 0x01;
+    pci_conf[0x69] = 0x00;
+    pci_conf[0x6a] = 0x00;
+    pci_conf[0x6b] = 0x00;  /* USBLEGSUP */
+    pci_conf[0x6c] = 0x00;
+    pci_conf[0x6d] = 0x00;
+    pci_conf[0x6e] = 0x00;
+    pci_conf[0x6f] = 0xc0;  /* USBLEFCTLSTS */
+
+    s->caps[0x09] = 0x68;        /* EECP */
+
+    s->irq = dev->irq[3];
+    s->dma = pci_dma_context(dev);
+
+    s->capsbase = 0x00;
+    s->opregbase = 0x20;
 
-    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+    usb_ehci_initfn(s, DEVICE(dev));
+    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
 
     return 0;
 }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 12/22] usb/ehci: Guard definition of EHCI_DEBUG
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (10 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 11/22] usb/ehci: seperate out PCIisms Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 13/22] usb/ehci: split into multiple source files Gerd Hoffmann
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Crosthwaite, Gerd Hoffmann

From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Guard against re-definition of EHCI_DEBUG. Allows for turning on of debug info
from configure (using --qemu-extra-cflags="-DEHCI_DEBUG=1") rather than source
code hacking.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-ehci.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 59580fc..d3168c9 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -36,7 +36,9 @@
 #include "dma.h"
 #include "sysemu.h"
 
+#ifndef EHCI_DEBUG
 #define EHCI_DEBUG   0
+#endif
 
 #if EHCI_DEBUG
 #define DPRINTF printf
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 13/22] usb/ehci: split into multiple source files
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (11 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 12/22] usb/ehci: Guard definition of EHCI_DEBUG Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 14/22] usb/ehci: add sysbus variant Gerd Hoffmann
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/Makefile.objs  |    2 +-
 hw/usb/hcd-ehci-pci.c |  138 ++++++++++++++++
 hw/usb/hcd-ehci.c     |  426 +------------------------------------------------
 hw/usb/hcd-ehci.h     |  320 +++++++++++++++++++++++++++++++++++++
 4 files changed, 462 insertions(+), 424 deletions(-)
 create mode 100644 hw/usb/hcd-ehci-pci.c
 create mode 100644 hw/usb/hcd-ehci.h

diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 6425c1f..5c7b024 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -1,6 +1,6 @@
 common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
 common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
-common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o
+common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
 common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
 common-obj-y += libhw.o
 
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
new file mode 100644
index 0000000..daac41d
--- /dev/null
+++ b/hw/usb/hcd-ehci-pci.c
@@ -0,0 +1,138 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/usb/hcd-ehci.h"
+#include "hw/pci.h"
+
+typedef struct EHCIPCIState {
+    PCIDevice pcidev;
+    EHCIState ehci;
+} EHCIPCIState;
+
+static int usb_ehci_pci_initfn(PCIDevice *dev)
+{
+    EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
+    EHCIState *s = &i->ehci;
+    uint8_t *pci_conf = dev->config;
+
+    pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
+
+    /* capabilities pointer */
+    pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
+    /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
+
+    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
+    pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
+    pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
+
+    /* pci_conf[0x50] = 0x01; *//* power management caps */
+
+    pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
+    pci_set_byte(&pci_conf[0x61], 0x20);  /* frame length adjustment (2.1.5) */
+    pci_set_word(&pci_conf[0x62], 0x00);  /* port wake up capability (2.1.6) */
+
+    pci_conf[0x64] = 0x00;
+    pci_conf[0x65] = 0x00;
+    pci_conf[0x66] = 0x00;
+    pci_conf[0x67] = 0x00;
+    pci_conf[0x68] = 0x01;
+    pci_conf[0x69] = 0x00;
+    pci_conf[0x6a] = 0x00;
+    pci_conf[0x6b] = 0x00;  /* USBLEGSUP */
+    pci_conf[0x6c] = 0x00;
+    pci_conf[0x6d] = 0x00;
+    pci_conf[0x6e] = 0x00;
+    pci_conf[0x6f] = 0xc0;  /* USBLEFCTLSTS */
+
+    s->caps[0x09] = 0x68;        /* EECP */
+
+    s->irq = dev->irq[3];
+    s->dma = pci_dma_context(dev);
+
+    s->capsbase = 0x00;
+    s->opregbase = 0x20;
+
+    usb_ehci_initfn(s, DEVICE(dev));
+    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+
+    return 0;
+}
+
+static Property ehci_pci_properties[] = {
+    DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_ehci_pci = {
+    .name        = "ehci",
+    .version_id  = 2,
+    .minimum_version_id  = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
+        VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
+    }
+};
+
+static void ehci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_ehci_pci_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
+    k->revision = 0x10;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_ehci;
+    dc->props = ehci_pci_properties;
+}
+
+static TypeInfo ehci_info = {
+    .name          = "usb-ehci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(EHCIState),
+    .class_init    = ehci_class_init,
+};
+
+static void ich9_ehci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_ehci_pci_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_ehci;
+    dc->props = ehci_pci_properties;
+}
+
+static TypeInfo ich9_ehci_info = {
+    .name          = "ich9-usb-ehci1",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(EHCIState),
+    .class_init    = ich9_ehci_class_init,
+};
+
+static void ehci_pci_register_types(void)
+{
+    type_register_static(&ehci_info);
+    type_register_static(&ich9_ehci_info);
+}
+
+type_init(ehci_pci_register_types)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index d3168c9..d9dc576 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -27,31 +27,11 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "hw/hw.h"
-#include "qemu-timer.h"
-#include "hw/usb.h"
-#include "hw/pci.h"
-#include "monitor.h"
-#include "trace.h"
-#include "dma.h"
-#include "sysemu.h"
-
-#ifndef EHCI_DEBUG
-#define EHCI_DEBUG   0
-#endif
-
-#if EHCI_DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
+#include "hw/usb/hcd-ehci.h"
 
 /* internal processing - reset HC to try and recover */
 #define USB_RET_PROCERR   (-99)
 
-#define MMIO_SIZE        0x1000
-#define CAPA_SIZE        0x10
-
 /* Capability Registers Base Address - section 2.2 */
 #define CAPLENGTH        0x0000  /* 1-byte, 0x0001 reserved */
 #define HCIVERSION       0x0002  /* 2-bytes, i/f version # */
@@ -103,9 +83,6 @@
 
 #define CONFIGFLAG           0x0040
 
-#define PORTSC               0x0044
-#define PORTSC_BEGIN         PORTSC
-#define PORTSC_END           (PORTSC + 4 * NB_PORTS)
 /*
  * Bits that are reserved or are read-only are masked out of values
  * written to us by software
@@ -137,7 +114,6 @@
 #define FRAME_TIMER_NS   (1000000000 / FRAME_TIMER_FREQ)
 
 #define NB_MAXINTRATE    8        // Max rate at which controller issues ints
-#define NB_PORTS         6        // Number of downstream ports
 #define BUFF_SIZE        5*4096   // Max bytes to transfer per transaction
 #define MAX_QH           100      // Max allowable queue heads in a chain
 #define MIN_FR_PER_TICK  3        // Min frames to process when catching up
@@ -174,285 +150,6 @@ typedef enum {
 #define NLPTR_TYPE_STITD         2     // split xaction, isoc xfer descriptor
 #define NLPTR_TYPE_FSTN          3     // frame span traversal node
 
-
-/*  EHCI spec version 1.0 Section 3.3
- */
-typedef struct EHCIitd {
-    uint32_t next;
-
-    uint32_t transact[8];
-#define ITD_XACT_ACTIVE          (1 << 31)
-#define ITD_XACT_DBERROR         (1 << 30)
-#define ITD_XACT_BABBLE          (1 << 29)
-#define ITD_XACT_XACTERR         (1 << 28)
-#define ITD_XACT_LENGTH_MASK     0x0fff0000
-#define ITD_XACT_LENGTH_SH       16
-#define ITD_XACT_IOC             (1 << 15)
-#define ITD_XACT_PGSEL_MASK      0x00007000
-#define ITD_XACT_PGSEL_SH        12
-#define ITD_XACT_OFFSET_MASK     0x00000fff
-
-    uint32_t bufptr[7];
-#define ITD_BUFPTR_MASK          0xfffff000
-#define ITD_BUFPTR_SH            12
-#define ITD_BUFPTR_EP_MASK       0x00000f00
-#define ITD_BUFPTR_EP_SH         8
-#define ITD_BUFPTR_DEVADDR_MASK  0x0000007f
-#define ITD_BUFPTR_DEVADDR_SH    0
-#define ITD_BUFPTR_DIRECTION     (1 << 11)
-#define ITD_BUFPTR_MAXPKT_MASK   0x000007ff
-#define ITD_BUFPTR_MAXPKT_SH     0
-#define ITD_BUFPTR_MULT_MASK     0x00000003
-#define ITD_BUFPTR_MULT_SH       0
-} EHCIitd;
-
-/*  EHCI spec version 1.0 Section 3.4
- */
-typedef struct EHCIsitd {
-    uint32_t next;                  // Standard next link pointer
-    uint32_t epchar;
-#define SITD_EPCHAR_IO              (1 << 31)
-#define SITD_EPCHAR_PORTNUM_MASK    0x7f000000
-#define SITD_EPCHAR_PORTNUM_SH      24
-#define SITD_EPCHAR_HUBADD_MASK     0x007f0000
-#define SITD_EPCHAR_HUBADDR_SH      16
-#define SITD_EPCHAR_EPNUM_MASK      0x00000f00
-#define SITD_EPCHAR_EPNUM_SH        8
-#define SITD_EPCHAR_DEVADDR_MASK    0x0000007f
-
-    uint32_t uframe;
-#define SITD_UFRAME_CMASK_MASK      0x0000ff00
-#define SITD_UFRAME_CMASK_SH        8
-#define SITD_UFRAME_SMASK_MASK      0x000000ff
-
-    uint32_t results;
-#define SITD_RESULTS_IOC              (1 << 31)
-#define SITD_RESULTS_PGSEL            (1 << 30)
-#define SITD_RESULTS_TBYTES_MASK      0x03ff0000
-#define SITD_RESULTS_TYBYTES_SH       16
-#define SITD_RESULTS_CPROGMASK_MASK   0x0000ff00
-#define SITD_RESULTS_CPROGMASK_SH     8
-#define SITD_RESULTS_ACTIVE           (1 << 7)
-#define SITD_RESULTS_ERR              (1 << 6)
-#define SITD_RESULTS_DBERR            (1 << 5)
-#define SITD_RESULTS_BABBLE           (1 << 4)
-#define SITD_RESULTS_XACTERR          (1 << 3)
-#define SITD_RESULTS_MISSEDUF         (1 << 2)
-#define SITD_RESULTS_SPLITXSTATE      (1 << 1)
-
-    uint32_t bufptr[2];
-#define SITD_BUFPTR_MASK              0xfffff000
-#define SITD_BUFPTR_CURROFF_MASK      0x00000fff
-#define SITD_BUFPTR_TPOS_MASK         0x00000018
-#define SITD_BUFPTR_TPOS_SH           3
-#define SITD_BUFPTR_TCNT_MASK         0x00000007
-
-    uint32_t backptr;                 // Standard next link pointer
-} EHCIsitd;
-
-/*  EHCI spec version 1.0 Section 3.5
- */
-typedef struct EHCIqtd {
-    uint32_t next;                    // Standard next link pointer
-    uint32_t altnext;                 // Standard next link pointer
-    uint32_t token;
-#define QTD_TOKEN_DTOGGLE             (1 << 31)
-#define QTD_TOKEN_TBYTES_MASK         0x7fff0000
-#define QTD_TOKEN_TBYTES_SH           16
-#define QTD_TOKEN_IOC                 (1 << 15)
-#define QTD_TOKEN_CPAGE_MASK          0x00007000
-#define QTD_TOKEN_CPAGE_SH            12
-#define QTD_TOKEN_CERR_MASK           0x00000c00
-#define QTD_TOKEN_CERR_SH             10
-#define QTD_TOKEN_PID_MASK            0x00000300
-#define QTD_TOKEN_PID_SH              8
-#define QTD_TOKEN_ACTIVE              (1 << 7)
-#define QTD_TOKEN_HALT                (1 << 6)
-#define QTD_TOKEN_DBERR               (1 << 5)
-#define QTD_TOKEN_BABBLE              (1 << 4)
-#define QTD_TOKEN_XACTERR             (1 << 3)
-#define QTD_TOKEN_MISSEDUF            (1 << 2)
-#define QTD_TOKEN_SPLITXSTATE         (1 << 1)
-#define QTD_TOKEN_PING                (1 << 0)
-
-    uint32_t bufptr[5];               // Standard buffer pointer
-#define QTD_BUFPTR_MASK               0xfffff000
-#define QTD_BUFPTR_SH                 12
-} EHCIqtd;
-
-/*  EHCI spec version 1.0 Section 3.6
- */
-typedef struct EHCIqh {
-    uint32_t next;                    // Standard next link pointer
-
-    /* endpoint characteristics */
-    uint32_t epchar;
-#define QH_EPCHAR_RL_MASK             0xf0000000
-#define QH_EPCHAR_RL_SH               28
-#define QH_EPCHAR_C                   (1 << 27)
-#define QH_EPCHAR_MPLEN_MASK          0x07FF0000
-#define QH_EPCHAR_MPLEN_SH            16
-#define QH_EPCHAR_H                   (1 << 15)
-#define QH_EPCHAR_DTC                 (1 << 14)
-#define QH_EPCHAR_EPS_MASK            0x00003000
-#define QH_EPCHAR_EPS_SH              12
-#define EHCI_QH_EPS_FULL              0
-#define EHCI_QH_EPS_LOW               1
-#define EHCI_QH_EPS_HIGH              2
-#define EHCI_QH_EPS_RESERVED          3
-
-#define QH_EPCHAR_EP_MASK             0x00000f00
-#define QH_EPCHAR_EP_SH               8
-#define QH_EPCHAR_I                   (1 << 7)
-#define QH_EPCHAR_DEVADDR_MASK        0x0000007f
-#define QH_EPCHAR_DEVADDR_SH          0
-
-    /* endpoint capabilities */
-    uint32_t epcap;
-#define QH_EPCAP_MULT_MASK            0xc0000000
-#define QH_EPCAP_MULT_SH              30
-#define QH_EPCAP_PORTNUM_MASK         0x3f800000
-#define QH_EPCAP_PORTNUM_SH           23
-#define QH_EPCAP_HUBADDR_MASK         0x007f0000
-#define QH_EPCAP_HUBADDR_SH           16
-#define QH_EPCAP_CMASK_MASK           0x0000ff00
-#define QH_EPCAP_CMASK_SH             8
-#define QH_EPCAP_SMASK_MASK           0x000000ff
-#define QH_EPCAP_SMASK_SH             0
-
-    uint32_t current_qtd;             // Standard next link pointer
-    uint32_t next_qtd;                // Standard next link pointer
-    uint32_t altnext_qtd;
-#define QH_ALTNEXT_NAKCNT_MASK        0x0000001e
-#define QH_ALTNEXT_NAKCNT_SH          1
-
-    uint32_t token;                   // Same as QTD token
-    uint32_t bufptr[5];               // Standard buffer pointer
-#define BUFPTR_CPROGMASK_MASK         0x000000ff
-#define BUFPTR_FRAMETAG_MASK          0x0000001f
-#define BUFPTR_SBYTES_MASK            0x00000fe0
-#define BUFPTR_SBYTES_SH              5
-} EHCIqh;
-
-/*  EHCI spec version 1.0 Section 3.7
- */
-typedef struct EHCIfstn {
-    uint32_t next;                    // Standard next link pointer
-    uint32_t backptr;                 // Standard next link pointer
-} EHCIfstn;
-
-typedef struct EHCIPacket EHCIPacket;
-typedef struct EHCIQueue EHCIQueue;
-typedef struct EHCIState EHCIState;
-
-enum async_state {
-    EHCI_ASYNC_NONE = 0,
-    EHCI_ASYNC_INITIALIZED,
-    EHCI_ASYNC_INFLIGHT,
-    EHCI_ASYNC_FINISHED,
-};
-
-struct EHCIPacket {
-    EHCIQueue *queue;
-    QTAILQ_ENTRY(EHCIPacket) next;
-
-    EHCIqtd qtd;           /* copy of current QTD (being worked on) */
-    uint32_t qtdaddr;      /* address QTD read from                 */
-
-    USBPacket packet;
-    QEMUSGList sgl;
-    int pid;
-    enum async_state async;
-    int usb_status;
-};
-
-struct EHCIQueue {
-    EHCIState *ehci;
-    QTAILQ_ENTRY(EHCIQueue) next;
-    uint32_t seen;
-    uint64_t ts;
-    int async;
-    int transact_ctr;
-
-    /* cached data from guest - needs to be flushed
-     * when guest removes an entry (doorbell, handshake sequence)
-     */
-    EHCIqh qh;             /* copy of current QH (being worked on) */
-    uint32_t qhaddr;       /* address QH read from                 */
-    uint32_t qtdaddr;      /* address QTD read from                */
-    USBDevice *dev;
-    QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
-};
-
-typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
-
-struct EHCIState {
-    USBBus bus;
-    qemu_irq irq;
-    MemoryRegion mem;
-    DMAContext *dma;
-    MemoryRegion mem_caps;
-    MemoryRegion mem_opreg;
-    MemoryRegion mem_ports;
-    int companion_count;
-    uint16_t capsbase;
-    uint16_t opregbase;
-
-    /* properties */
-    uint32_t maxframes;
-
-    /*
-     *  EHCI spec version 1.0 Section 2.3
-     *  Host Controller Operational Registers
-     */
-    uint8_t caps[CAPA_SIZE];
-    union {
-        uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)];
-        struct {
-            uint32_t usbcmd;
-            uint32_t usbsts;
-            uint32_t usbintr;
-            uint32_t frindex;
-            uint32_t ctrldssegment;
-            uint32_t periodiclistbase;
-            uint32_t asynclistaddr;
-            uint32_t notused[9];
-            uint32_t configflag;
-        };
-    };
-    uint32_t portsc[NB_PORTS];
-
-    /*
-     *  Internal states, shadow registers, etc
-     */
-    QEMUTimer *frame_timer;
-    QEMUBH *async_bh;
-    uint32_t astate;         /* Current state in asynchronous schedule */
-    uint32_t pstate;         /* Current state in periodic schedule     */
-    USBPort ports[NB_PORTS];
-    USBPort *companion_ports[NB_PORTS];
-    uint32_t usbsts_pending;
-    uint32_t usbsts_frindex;
-    EHCIQueueHead aqueues;
-    EHCIQueueHead pqueues;
-
-    /* which address to look at next */
-    uint32_t a_fetch_addr;
-    uint32_t p_fetch_addr;
-
-    USBPacket ipacket;
-    QEMUSGList isgl;
-
-    uint64_t last_run_ns;
-    uint32_t async_stepdown;
-    bool int_req_by_async;
-};
-
-typedef struct EHCIPCIState {
-    PCIDevice pcidev;
-    EHCIState ehci;
-} EHCIPCIState;
-
 #define SET_LAST_RUN_CLOCK(s) \
     (s)->last_run_ns = qemu_get_clock_ns(vm_clock);
 
@@ -2559,8 +2256,6 @@ static const MemoryRegionOps ehci_mmio_port_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static int usb_ehci_pci_initfn(PCIDevice *dev);
-
 static USBPortOps ehci_port_ops = {
     .attach = ehci_attach,
     .detach = ehci_detach,
@@ -2619,7 +2314,7 @@ static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
     }
 }
 
-static const VMStateDescription vmstate_ehci = {
+const VMStateDescription vmstate_ehci = {
     .name        = "ehci-core",
     .version_id  = 2,
     .minimum_version_id  = 1,
@@ -2655,65 +2350,7 @@ static const VMStateDescription vmstate_ehci = {
     }
 };
 
-static const VMStateDescription vmstate_ehci_pci = {
-    .name        = "ehci",
-    .version_id  = 2,
-    .minimum_version_id  = 1,
-    .post_load   = usb_ehci_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
-        VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
-    }
-};
-
-static Property ehci_pci_properties[] = {
-    DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ehci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_ehci_pci_initfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
-    k->revision = 0x10;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    dc->vmsd = &vmstate_ehci;
-    dc->props = ehci_pci_properties;
-}
-
-static TypeInfo ehci_info = {
-    .name          = "usb-ehci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(EHCIState),
-    .class_init    = ehci_class_init,
-};
-
-static void ich9_ehci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_ehci_pci_initfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
-    k->revision = 0x03;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    dc->vmsd = &vmstate_ehci;
-    dc->props = ehci_pci_properties;
-}
-
-static TypeInfo ich9_ehci_info = {
-    .name          = "ich9-usb-ehci1",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(EHCIState),
-    .class_init    = ich9_ehci_class_init,
-};
-
-static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
+void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
 {
     int i;
 
@@ -2760,63 +2397,6 @@ static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
                                 &s->mem_ports);
 }
 
-static int usb_ehci_pci_initfn(PCIDevice *dev)
-{
-    EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
-    EHCIState *s = &i->ehci;
-    uint8_t *pci_conf = dev->config;
-
-    pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-
-    /* capabilities pointer */
-    pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
-    /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
-
-    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
-    pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
-    pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
-
-    /* pci_conf[0x50] = 0x01; *//* power management caps */
-
-    pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
-    pci_set_byte(&pci_conf[0x61], 0x20);  /* frame length adjustment (2.1.5) */
-    pci_set_word(&pci_conf[0x62], 0x00);  /* port wake up capability (2.1.6) */
-
-    pci_conf[0x64] = 0x00;
-    pci_conf[0x65] = 0x00;
-    pci_conf[0x66] = 0x00;
-    pci_conf[0x67] = 0x00;
-    pci_conf[0x68] = 0x01;
-    pci_conf[0x69] = 0x00;
-    pci_conf[0x6a] = 0x00;
-    pci_conf[0x6b] = 0x00;  /* USBLEGSUP */
-    pci_conf[0x6c] = 0x00;
-    pci_conf[0x6d] = 0x00;
-    pci_conf[0x6e] = 0x00;
-    pci_conf[0x6f] = 0xc0;  /* USBLEFCTLSTS */
-
-    s->caps[0x09] = 0x68;        /* EECP */
-
-    s->irq = dev->irq[3];
-    s->dma = pci_dma_context(dev);
-
-    s->capsbase = 0x00;
-    s->opregbase = 0x20;
-
-    usb_ehci_initfn(s, DEVICE(dev));
-    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
-
-    return 0;
-}
-
-static void ehci_register_types(void)
-{
-    type_register_static(&ehci_info);
-    type_register_static(&ich9_ehci_info);
-}
-
-type_init(ehci_register_types)
-
 /*
  * vim: expandtab ts=4
  */
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
new file mode 100644
index 0000000..0ec675c
--- /dev/null
+++ b/hw/usb/hcd-ehci.h
@@ -0,0 +1,320 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "hw/usb.h"
+#include "monitor.h"
+#include "trace.h"
+#include "dma.h"
+#include "sysemu.h"
+
+#ifndef EHCI_DEBUG
+#define EHCI_DEBUG   0
+#endif
+
+#if EHCI_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+#define MMIO_SIZE        0x1000
+#define CAPA_SIZE        0x10
+
+#define PORTSC               0x0044
+#define PORTSC_BEGIN         PORTSC
+#define PORTSC_END           (PORTSC + 4 * NB_PORTS)
+
+#define NB_PORTS         6        /* Number of downstream ports */
+
+typedef struct EHCIPacket EHCIPacket;
+typedef struct EHCIQueue EHCIQueue;
+typedef struct EHCIState EHCIState;
+
+/*  EHCI spec version 1.0 Section 3.3
+ */
+typedef struct EHCIitd {
+    uint32_t next;
+
+    uint32_t transact[8];
+#define ITD_XACT_ACTIVE          (1 << 31)
+#define ITD_XACT_DBERROR         (1 << 30)
+#define ITD_XACT_BABBLE          (1 << 29)
+#define ITD_XACT_XACTERR         (1 << 28)
+#define ITD_XACT_LENGTH_MASK     0x0fff0000
+#define ITD_XACT_LENGTH_SH       16
+#define ITD_XACT_IOC             (1 << 15)
+#define ITD_XACT_PGSEL_MASK      0x00007000
+#define ITD_XACT_PGSEL_SH        12
+#define ITD_XACT_OFFSET_MASK     0x00000fff
+
+    uint32_t bufptr[7];
+#define ITD_BUFPTR_MASK          0xfffff000
+#define ITD_BUFPTR_SH            12
+#define ITD_BUFPTR_EP_MASK       0x00000f00
+#define ITD_BUFPTR_EP_SH         8
+#define ITD_BUFPTR_DEVADDR_MASK  0x0000007f
+#define ITD_BUFPTR_DEVADDR_SH    0
+#define ITD_BUFPTR_DIRECTION     (1 << 11)
+#define ITD_BUFPTR_MAXPKT_MASK   0x000007ff
+#define ITD_BUFPTR_MAXPKT_SH     0
+#define ITD_BUFPTR_MULT_MASK     0x00000003
+#define ITD_BUFPTR_MULT_SH       0
+} EHCIitd;
+
+/*  EHCI spec version 1.0 Section 3.4
+ */
+typedef struct EHCIsitd {
+    uint32_t next;                  /* Standard next link pointer */
+    uint32_t epchar;
+#define SITD_EPCHAR_IO              (1 << 31)
+#define SITD_EPCHAR_PORTNUM_MASK    0x7f000000
+#define SITD_EPCHAR_PORTNUM_SH      24
+#define SITD_EPCHAR_HUBADD_MASK     0x007f0000
+#define SITD_EPCHAR_HUBADDR_SH      16
+#define SITD_EPCHAR_EPNUM_MASK      0x00000f00
+#define SITD_EPCHAR_EPNUM_SH        8
+#define SITD_EPCHAR_DEVADDR_MASK    0x0000007f
+
+    uint32_t uframe;
+#define SITD_UFRAME_CMASK_MASK      0x0000ff00
+#define SITD_UFRAME_CMASK_SH        8
+#define SITD_UFRAME_SMASK_MASK      0x000000ff
+
+    uint32_t results;
+#define SITD_RESULTS_IOC              (1 << 31)
+#define SITD_RESULTS_PGSEL            (1 << 30)
+#define SITD_RESULTS_TBYTES_MASK      0x03ff0000
+#define SITD_RESULTS_TYBYTES_SH       16
+#define SITD_RESULTS_CPROGMASK_MASK   0x0000ff00
+#define SITD_RESULTS_CPROGMASK_SH     8
+#define SITD_RESULTS_ACTIVE           (1 << 7)
+#define SITD_RESULTS_ERR              (1 << 6)
+#define SITD_RESULTS_DBERR            (1 << 5)
+#define SITD_RESULTS_BABBLE           (1 << 4)
+#define SITD_RESULTS_XACTERR          (1 << 3)
+#define SITD_RESULTS_MISSEDUF         (1 << 2)
+#define SITD_RESULTS_SPLITXSTATE      (1 << 1)
+
+    uint32_t bufptr[2];
+#define SITD_BUFPTR_MASK              0xfffff000
+#define SITD_BUFPTR_CURROFF_MASK      0x00000fff
+#define SITD_BUFPTR_TPOS_MASK         0x00000018
+#define SITD_BUFPTR_TPOS_SH           3
+#define SITD_BUFPTR_TCNT_MASK         0x00000007
+
+    uint32_t backptr;                 /* Standard next link pointer */
+} EHCIsitd;
+
+/*  EHCI spec version 1.0 Section 3.5
+ */
+typedef struct EHCIqtd {
+    uint32_t next;                    /* Standard next link pointer */
+    uint32_t altnext;                 /* Standard next link pointer */
+    uint32_t token;
+#define QTD_TOKEN_DTOGGLE             (1 << 31)
+#define QTD_TOKEN_TBYTES_MASK         0x7fff0000
+#define QTD_TOKEN_TBYTES_SH           16
+#define QTD_TOKEN_IOC                 (1 << 15)
+#define QTD_TOKEN_CPAGE_MASK          0x00007000
+#define QTD_TOKEN_CPAGE_SH            12
+#define QTD_TOKEN_CERR_MASK           0x00000c00
+#define QTD_TOKEN_CERR_SH             10
+#define QTD_TOKEN_PID_MASK            0x00000300
+#define QTD_TOKEN_PID_SH              8
+#define QTD_TOKEN_ACTIVE              (1 << 7)
+#define QTD_TOKEN_HALT                (1 << 6)
+#define QTD_TOKEN_DBERR               (1 << 5)
+#define QTD_TOKEN_BABBLE              (1 << 4)
+#define QTD_TOKEN_XACTERR             (1 << 3)
+#define QTD_TOKEN_MISSEDUF            (1 << 2)
+#define QTD_TOKEN_SPLITXSTATE         (1 << 1)
+#define QTD_TOKEN_PING                (1 << 0)
+
+    uint32_t bufptr[5];               /* Standard buffer pointer */
+#define QTD_BUFPTR_MASK               0xfffff000
+#define QTD_BUFPTR_SH                 12
+} EHCIqtd;
+
+/*  EHCI spec version 1.0 Section 3.6
+ */
+typedef struct EHCIqh {
+    uint32_t next;                    /* Standard next link pointer */
+
+    /* endpoint characteristics */
+    uint32_t epchar;
+#define QH_EPCHAR_RL_MASK             0xf0000000
+#define QH_EPCHAR_RL_SH               28
+#define QH_EPCHAR_C                   (1 << 27)
+#define QH_EPCHAR_MPLEN_MASK          0x07FF0000
+#define QH_EPCHAR_MPLEN_SH            16
+#define QH_EPCHAR_H                   (1 << 15)
+#define QH_EPCHAR_DTC                 (1 << 14)
+#define QH_EPCHAR_EPS_MASK            0x00003000
+#define QH_EPCHAR_EPS_SH              12
+#define EHCI_QH_EPS_FULL              0
+#define EHCI_QH_EPS_LOW               1
+#define EHCI_QH_EPS_HIGH              2
+#define EHCI_QH_EPS_RESERVED          3
+
+#define QH_EPCHAR_EP_MASK             0x00000f00
+#define QH_EPCHAR_EP_SH               8
+#define QH_EPCHAR_I                   (1 << 7)
+#define QH_EPCHAR_DEVADDR_MASK        0x0000007f
+#define QH_EPCHAR_DEVADDR_SH          0
+
+    /* endpoint capabilities */
+    uint32_t epcap;
+#define QH_EPCAP_MULT_MASK            0xc0000000
+#define QH_EPCAP_MULT_SH              30
+#define QH_EPCAP_PORTNUM_MASK         0x3f800000
+#define QH_EPCAP_PORTNUM_SH           23
+#define QH_EPCAP_HUBADDR_MASK         0x007f0000
+#define QH_EPCAP_HUBADDR_SH           16
+#define QH_EPCAP_CMASK_MASK           0x0000ff00
+#define QH_EPCAP_CMASK_SH             8
+#define QH_EPCAP_SMASK_MASK           0x000000ff
+#define QH_EPCAP_SMASK_SH             0
+
+    uint32_t current_qtd;             /* Standard next link pointer */
+    uint32_t next_qtd;                /* Standard next link pointer */
+    uint32_t altnext_qtd;
+#define QH_ALTNEXT_NAKCNT_MASK        0x0000001e
+#define QH_ALTNEXT_NAKCNT_SH          1
+
+    uint32_t token;                   /* Same as QTD token */
+    uint32_t bufptr[5];               /* Standard buffer pointer */
+#define BUFPTR_CPROGMASK_MASK         0x000000ff
+#define BUFPTR_FRAMETAG_MASK          0x0000001f
+#define BUFPTR_SBYTES_MASK            0x00000fe0
+#define BUFPTR_SBYTES_SH              5
+} EHCIqh;
+
+/*  EHCI spec version 1.0 Section 3.7
+ */
+typedef struct EHCIfstn {
+    uint32_t next;                    /* Standard next link pointer */
+    uint32_t backptr;                 /* Standard next link pointer */
+} EHCIfstn;
+
+enum async_state {
+    EHCI_ASYNC_NONE = 0,
+    EHCI_ASYNC_INITIALIZED,
+    EHCI_ASYNC_INFLIGHT,
+    EHCI_ASYNC_FINISHED,
+};
+
+struct EHCIPacket {
+    EHCIQueue *queue;
+    QTAILQ_ENTRY(EHCIPacket) next;
+
+    EHCIqtd qtd;           /* copy of current QTD (being worked on) */
+    uint32_t qtdaddr;      /* address QTD read from                 */
+
+    USBPacket packet;
+    QEMUSGList sgl;
+    int pid;
+    enum async_state async;
+    int usb_status;
+};
+
+struct EHCIQueue {
+    EHCIState *ehci;
+    QTAILQ_ENTRY(EHCIQueue) next;
+    uint32_t seen;
+    uint64_t ts;
+    int async;
+    int transact_ctr;
+
+    /* cached data from guest - needs to be flushed
+     * when guest removes an entry (doorbell, handshake sequence)
+     */
+    EHCIqh qh;             /* copy of current QH (being worked on) */
+    uint32_t qhaddr;       /* address QH read from                 */
+    uint32_t qtdaddr;      /* address QTD read from                */
+    USBDevice *dev;
+    QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
+};
+
+typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
+
+struct EHCIState {
+    USBBus bus;
+    qemu_irq irq;
+    MemoryRegion mem;
+    DMAContext *dma;
+    MemoryRegion mem_caps;
+    MemoryRegion mem_opreg;
+    MemoryRegion mem_ports;
+    int companion_count;
+    uint16_t capsbase;
+    uint16_t opregbase;
+
+    /* properties */
+    uint32_t maxframes;
+
+    /*
+     *  EHCI spec version 1.0 Section 2.3
+     *  Host Controller Operational Registers
+     */
+    uint8_t caps[CAPA_SIZE];
+    union {
+        uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)];
+        struct {
+            uint32_t usbcmd;
+            uint32_t usbsts;
+            uint32_t usbintr;
+            uint32_t frindex;
+            uint32_t ctrldssegment;
+            uint32_t periodiclistbase;
+            uint32_t asynclistaddr;
+            uint32_t notused[9];
+            uint32_t configflag;
+        };
+    };
+    uint32_t portsc[NB_PORTS];
+
+    /*
+     *  Internal states, shadow registers, etc
+     */
+    QEMUTimer *frame_timer;
+    QEMUBH *async_bh;
+    uint32_t astate;         /* Current state in asynchronous schedule */
+    uint32_t pstate;         /* Current state in periodic schedule     */
+    USBPort ports[NB_PORTS];
+    USBPort *companion_ports[NB_PORTS];
+    uint32_t usbsts_pending;
+    uint32_t usbsts_frindex;
+    EHCIQueueHead aqueues;
+    EHCIQueueHead pqueues;
+
+    /* which address to look at next */
+    uint32_t a_fetch_addr;
+    uint32_t p_fetch_addr;
+
+    USBPacket ipacket;
+    QEMUSGList isgl;
+
+    uint64_t last_run_ns;
+    uint32_t async_stepdown;
+    bool int_req_by_async;
+};
+
+extern const VMStateDescription vmstate_ehci;
+
+void usb_ehci_initfn(EHCIState *s, DeviceState *dev);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 14/22] usb/ehci: add sysbus variant
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (12 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 13/22] usb/ehci: split into multiple source files Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-31  5:57   ` Peter Crosthwaite
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 15/22] uhci: dynamic type generation Gerd Hoffmann
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/Makefile.objs     |    2 +-
 hw/usb/hcd-ehci-sysbus.c |   77 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+), 1 deletions(-)
 create mode 100644 hw/usb/hcd-ehci-sysbus.c

diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 5c7b024..7669938 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -1,6 +1,6 @@
 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
+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
 
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
new file mode 100644
index 0000000..1584079
--- /dev/null
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -0,0 +1,77 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/usb/hcd-ehci.h"
+#include "hw/sysbus.h"
+
+typedef struct EHCISysBusState {
+    SysBusDevice busdev;
+    EHCIState ehci;
+} EHCISysBusState;
+
+static const VMStateDescription vmstate_ehci_sysbus = {
+    .name        = "ehci-sysbus",
+    .version_id  = 2,
+    .minimum_version_id  = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property ehci_sysbus_properties[] = {
+    DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int usb_ehci_sysbus_initfn(SysBusDevice *dev)
+{
+    EHCISysBusState *i = FROM_SYSBUS(EHCISysBusState, dev);
+    EHCIState *s = &i->ehci;
+
+    s->capsbase = 0x100;
+    s->opregbase = 0x140;
+
+    usb_ehci_initfn(s, DEVICE(dev));
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_mmio(dev, &s->mem);
+    return 0;
+}
+
+static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = usb_ehci_sysbus_initfn;
+    dc->vmsd = &vmstate_ehci_sysbus;
+    dc->props = ehci_sysbus_properties;
+}
+
+TypeInfo ehci_xlnx_type_info = {
+    .name          = "xlnx,ps7-usb",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(EHCISysBusState),
+    .class_init    = ehci_sysbus_class_init,
+};
+
+static void ehci_sysbus_register_types(void)
+{
+    type_register_static(&ehci_xlnx_type_info);
+}
+
+type_init(ehci_sysbus_register_types)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 15/22] uhci: dynamic type generation
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (13 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 14/22] usb/ehci: add sysbus variant Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 16/22] uhci: stick irq routing info into UHCIInfo too Gerd Hoffmann
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-uhci.c |  196 +++++++++++++++++++----------------------------------
 1 files changed, 70 insertions(+), 126 deletions(-)

diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index b6b972f..925c738 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -88,6 +88,16 @@ enum {
 typedef struct UHCIState UHCIState;
 typedef struct UHCIAsync UHCIAsync;
 typedef struct UHCIQueue UHCIQueue;
+typedef struct UHCIInfo UHCIInfo;
+
+struct UHCIInfo {
+    const char *name;
+    uint16_t   vendor_id;
+    uint16_t   device_id;
+    uint8_t    revision;
+    int        (*initfn)(PCIDevice *dev);
+    bool       unplug;
+};
 
 /* 
  * Pending async transaction.
@@ -1293,143 +1303,77 @@ static Property uhci_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void piix3_uhci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_uhci_common_initfn;
-    k->exit = usb_uhci_exit;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82371SB_2;
-    k->revision = 0x01;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    dc->vmsd = &vmstate_uhci;
-    dc->props = uhci_properties;
-}
-
-static TypeInfo piix3_uhci_info = {
-    .name          = "piix3-usb-uhci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(UHCIState),
-    .class_init    = piix3_uhci_class_init,
-};
-
-static void piix4_uhci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_uhci_common_initfn;
-    k->exit = usb_uhci_exit;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_2;
-    k->revision = 0x01;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    dc->vmsd = &vmstate_uhci;
-    dc->props = uhci_properties;
-}
-
-static TypeInfo piix4_uhci_info = {
-    .name          = "piix4-usb-uhci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(UHCIState),
-    .class_init    = piix4_uhci_class_init,
-};
-
-static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_uhci_vt82c686b_initfn;
-    k->exit = usb_uhci_exit;
-    k->vendor_id = PCI_VENDOR_ID_VIA;
-    k->device_id = PCI_DEVICE_ID_VIA_UHCI;
-    k->revision = 0x01;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    dc->vmsd = &vmstate_uhci;
-    dc->props = uhci_properties;
-}
-
-static TypeInfo vt82c686b_uhci_info = {
-    .name          = "vt82c686b-usb-uhci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(UHCIState),
-    .class_init    = vt82c686b_uhci_class_init,
-};
-
-static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_uhci_common_initfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1;
-    k->revision = 0x03;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    dc->vmsd = &vmstate_uhci;
-    dc->props = uhci_properties;
-}
-
-static TypeInfo ich9_uhci1_info = {
-    .name          = "ich9-usb-uhci1",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(UHCIState),
-    .class_init    = ich9_uhci1_class_init,
-};
-
-static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_uhci_common_initfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2;
-    k->revision = 0x03;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    dc->vmsd = &vmstate_uhci;
-    dc->props = uhci_properties;
-}
-
-static TypeInfo ich9_uhci2_info = {
-    .name          = "ich9-usb-uhci2",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(UHCIState),
-    .class_init    = ich9_uhci2_class_init,
-};
-
-static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
+static void uhci_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_uhci_common_initfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3;
-    k->revision = 0x03;
-    k->class_id = PCI_CLASS_SERIAL_USB;
+    UHCIInfo *info = data;
+
+    k->init = info->initfn ? info->initfn : usb_uhci_common_initfn;
+    k->exit = info->unplug ? usb_uhci_exit : NULL;
+    k->vendor_id = info->vendor_id;
+    k->device_id = info->device_id;
+    k->revision  = info->revision;
+    k->class_id  = PCI_CLASS_SERIAL_USB;
     dc->vmsd = &vmstate_uhci;
     dc->props = uhci_properties;
 }
 
-static TypeInfo ich9_uhci3_info = {
-    .name          = "ich9-usb-uhci3",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(UHCIState),
-    .class_init    = ich9_uhci3_class_init,
+static UHCIInfo uhci_info[] = {
+    {
+        .name       = "piix3-usb-uhci",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
+        .revision  = 0x01,
+        .unplug    = true,
+    },{
+        .name      = "piix4-usb-uhci",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
+        .revision  = 0x01,
+        .unplug    = true,
+    },{
+        .name      = "vt82c686b-usb-uhci",
+        .vendor_id = PCI_VENDOR_ID_VIA,
+        .device_id = PCI_DEVICE_ID_VIA_UHCI,
+        .revision  = 0x01,
+        .initfn    = usb_uhci_vt82c686b_initfn,
+        .unplug    = true,
+    },{
+        .name      = "ich9-usb-uhci1",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
+        .revision  = 0x03,
+        .unplug    = false,
+    },{
+        .name      = "ich9-usb-uhci2",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
+        .revision  = 0x03,
+        .unplug    = false,
+    },{
+        .name      = "ich9-usb-uhci3",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
+        .revision  = 0x03,
+        .unplug    = false,
+    }
 };
 
 static void uhci_register_types(void)
 {
-    type_register_static(&piix3_uhci_info);
-    type_register_static(&piix4_uhci_info);
-    type_register_static(&vt82c686b_uhci_info);
-    type_register_static(&ich9_uhci1_info);
-    type_register_static(&ich9_uhci2_info);
-    type_register_static(&ich9_uhci3_info);
+    TypeInfo uhci_type_info = {
+        .parent        = TYPE_PCI_DEVICE,
+        .instance_size = sizeof(UHCIState),
+        .class_init    = uhci_class_init,
+    };
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(uhci_info); i++) {
+        uhci_type_info.name = uhci_info[i].name;
+        uhci_type_info.class_data = uhci_info + i;
+        type_register(&uhci_type_info);
+    }
 }
 
 type_init(uhci_register_types)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 16/22] uhci: stick irq routing info into UHCIInfo too.
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (14 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 15/22] uhci: dynamic type generation Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 17/22] uhci: add ich9 00:1a.* variants Gerd Hoffmann
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Kills the ugly "switch (device_id) { ... }" struct and makes it easier
to figure what the differences between the uhci variants are.

Need our own DeviceClass struct for that so we can allocate some space
to store UHCIInfo.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-uhci.c |   32 ++++++++++++++++++--------------
 1 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 925c738..27046b6 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -89,16 +89,23 @@ typedef struct UHCIState UHCIState;
 typedef struct UHCIAsync UHCIAsync;
 typedef struct UHCIQueue UHCIQueue;
 typedef struct UHCIInfo UHCIInfo;
+typedef struct UHCIPCIDeviceClass UHCIPCIDeviceClass;
 
 struct UHCIInfo {
     const char *name;
     uint16_t   vendor_id;
     uint16_t   device_id;
     uint8_t    revision;
+    uint8_t    irq_pin;
     int        (*initfn)(PCIDevice *dev);
     bool       unplug;
 };
 
+struct UHCIPCIDeviceClass {
+    PCIDeviceClass parent_class;
+    UHCIInfo       info;
+};
+
 /* 
  * Pending async transaction.
  * 'packet' must be the first field because completion
@@ -1218,6 +1225,7 @@ static USBBusOps uhci_bus_ops = {
 static int usb_uhci_common_initfn(PCIDevice *dev)
 {
     PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+    UHCIPCIDeviceClass *u = container_of(pc, UHCIPCIDeviceClass, parent_class);
     UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
     uint8_t *pci_conf = s->dev.config;
     int i;
@@ -1226,20 +1234,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
     /* TODO: reset value should be 0. */
     pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
 
-    switch (pc->device_id) {
-    case PCI_DEVICE_ID_INTEL_82801I_UHCI1:
-        s->irq_pin = 0;  /* A */
-        break;
-    case PCI_DEVICE_ID_INTEL_82801I_UHCI2:
-        s->irq_pin = 1;  /* B */
-        break;
-    case PCI_DEVICE_ID_INTEL_82801I_UHCI3:
-        s->irq_pin = 2;  /* C */
-        break;
-    default:
-        s->irq_pin = 3;  /* D */
-        break;
-    }
+    s->irq_pin = u->info.irq_pin;
     pci_config_set_interrupt_pin(pci_conf, s->irq_pin + 1);
 
     if (s->masterbus) {
@@ -1307,6 +1302,7 @@ static void uhci_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    UHCIPCIDeviceClass *u = container_of(k, UHCIPCIDeviceClass, parent_class);
     UHCIInfo *info = data;
 
     k->init = info->initfn ? info->initfn : usb_uhci_common_initfn;
@@ -1317,6 +1313,7 @@ static void uhci_class_init(ObjectClass *klass, void *data)
     k->class_id  = PCI_CLASS_SERIAL_USB;
     dc->vmsd = &vmstate_uhci;
     dc->props = uhci_properties;
+    u->info = *info;
 }
 
 static UHCIInfo uhci_info[] = {
@@ -1325,18 +1322,21 @@ static UHCIInfo uhci_info[] = {
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
         .revision  = 0x01,
+        .irq_pin   = 3,
         .unplug    = true,
     },{
         .name      = "piix4-usb-uhci",
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
         .revision  = 0x01,
+        .irq_pin   = 3,
         .unplug    = true,
     },{
         .name      = "vt82c686b-usb-uhci",
         .vendor_id = PCI_VENDOR_ID_VIA,
         .device_id = PCI_DEVICE_ID_VIA_UHCI,
         .revision  = 0x01,
+        .irq_pin   = 3,
         .initfn    = usb_uhci_vt82c686b_initfn,
         .unplug    = true,
     },{
@@ -1344,18 +1344,21 @@ static UHCIInfo uhci_info[] = {
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
         .revision  = 0x03,
+        .irq_pin   = 0,
         .unplug    = false,
     },{
         .name      = "ich9-usb-uhci2",
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
         .revision  = 0x03,
+        .irq_pin   = 1,
         .unplug    = false,
     },{
         .name      = "ich9-usb-uhci3",
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
         .revision  = 0x03,
+        .irq_pin   = 2,
         .unplug    = false,
     }
 };
@@ -1365,6 +1368,7 @@ static void uhci_register_types(void)
     TypeInfo uhci_type_info = {
         .parent        = TYPE_PCI_DEVICE,
         .instance_size = sizeof(UHCIState),
+        .class_size    = sizeof(UHCIPCIDeviceClass),
         .class_init    = uhci_class_init,
     };
     int i;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 17/22] uhci: add ich9 00:1a.* variants
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (15 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 16/22] uhci: stick irq routing info into UHCIInfo too Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 18/22] usb/ehci-pci: dynamic type generation Gerd Hoffmann
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-uhci.c |   27 ++++++++++++++++++++++++---
 1 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 27046b6..71263fe 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -1340,26 +1340,47 @@ static UHCIInfo uhci_info[] = {
         .initfn    = usb_uhci_vt82c686b_initfn,
         .unplug    = true,
     },{
-        .name      = "ich9-usb-uhci1",
+        .name      = "ich9-usb-uhci1", /* 00:1d.0 */
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
         .revision  = 0x03,
         .irq_pin   = 0,
         .unplug    = false,
     },{
-        .name      = "ich9-usb-uhci2",
+        .name      = "ich9-usb-uhci2", /* 00:1d.1 */
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
         .revision  = 0x03,
         .irq_pin   = 1,
         .unplug    = false,
     },{
-        .name      = "ich9-usb-uhci3",
+        .name      = "ich9-usb-uhci3", /* 00:1d.2 */
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
         .revision  = 0x03,
         .irq_pin   = 2,
         .unplug    = false,
+    },{
+        .name      = "ich9-usb-uhci4", /* 00:1a.0 */
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4,
+        .revision  = 0x03,
+        .irq_pin   = 0,
+        .unplug    = false,
+    },{
+        .name      = "ich9-usb-uhci5", /* 00:1a.1 */
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5,
+        .revision  = 0x03,
+        .irq_pin   = 1,
+        .unplug    = false,
+    },{
+        .name      = "ich9-usb-uhci6", /* 00:1a.2 */
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6,
+        .revision  = 0x03,
+        .irq_pin   = 2,
+        .unplug    = false,
     }
 };
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 18/22] usb/ehci-pci: dynamic type generation
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (16 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 17/22] uhci: add ich9 00:1a.* variants Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 19/22] usb/ehci-pci: add ich9 00:1a.* variant Gerd Hoffmann
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-ehci-pci.c |   66 ++++++++++++++++++++++++++-----------------------
 1 files changed, 35 insertions(+), 31 deletions(-)

diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index daac41d..df137cc 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -23,6 +23,13 @@ typedef struct EHCIPCIState {
     EHCIState ehci;
 } EHCIPCIState;
 
+typedef struct EHCIPCIInfo {
+    const char *name;
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint8_t  revision;
+} EHCIPCIInfo;
+
 static int usb_ehci_pci_initfn(PCIDevice *dev)
 {
     EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
@@ -91,48 +98,45 @@ static void ehci_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    EHCIPCIInfo *i = data;
 
     k->init = usb_ehci_pci_initfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
-    k->revision = 0x10;
+    k->vendor_id = i->vendor_id;
+    k->device_id = i->device_id;
+    k->revision = i->revision;
     k->class_id = PCI_CLASS_SERIAL_USB;
     dc->vmsd = &vmstate_ehci;
     dc->props = ehci_pci_properties;
 }
 
-static TypeInfo ehci_info = {
-    .name          = "usb-ehci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(EHCIState),
-    .class_init    = ehci_class_init,
-};
-
-static void ich9_ehci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = usb_ehci_pci_initfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
-    k->revision = 0x03;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    dc->vmsd = &vmstate_ehci;
-    dc->props = ehci_pci_properties;
-}
-
-static TypeInfo ich9_ehci_info = {
-    .name          = "ich9-usb-ehci1",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(EHCIState),
-    .class_init    = ich9_ehci_class_init,
+static struct EHCIPCIInfo ehci_pci_info[] = {
+    {
+        .name      = "usb-ehci",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
+        .revision  = 0x10,
+    },{
+        .name      = "ich9-usb-ehci1",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
+        .revision  = 0x03,
+    }
 };
 
 static void ehci_pci_register_types(void)
 {
-    type_register_static(&ehci_info);
-    type_register_static(&ich9_ehci_info);
+    TypeInfo ehci_type_info = {
+        .parent        = TYPE_PCI_DEVICE,
+        .instance_size = sizeof(EHCIPCIState),
+        .class_init    = ehci_class_init,
+    };
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) {
+        ehci_type_info.name = ehci_pci_info[i].name;
+        ehci_type_info.class_data = ehci_pci_info + i;
+        type_register(&ehci_type_info);
+    }
 }
 
 type_init(ehci_pci_register_types)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 19/22] usb/ehci-pci: add ich9 00:1a.* variant
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (17 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 18/22] usb/ehci-pci: dynamic type generation Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 20/22] usb/ehci-pci: add helper to create ich9 usb controllers Gerd Hoffmann
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-ehci-pci.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index df137cc..79bc276 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -116,10 +116,15 @@ static struct EHCIPCIInfo ehci_pci_info[] = {
         .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
         .revision  = 0x10,
     },{
-        .name      = "ich9-usb-ehci1",
+        .name      = "ich9-usb-ehci1", /* 00:1d.7 */
         .vendor_id = PCI_VENDOR_ID_INTEL,
         .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
         .revision  = 0x03,
+    },{
+        .name      = "ich9-usb-ehci2", /* 00:1a.7 */
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI2,
+        .revision  = 0x03,
     }
 };
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 20/22] usb/ehci-pci: add helper to create ich9 usb controllers
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (18 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 19/22] usb/ehci-pci: add ich9 00:1a.* variant Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 21/22] [RfC] usb: mtp filesharing Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 22/22] trace: allow disabling events in events file Gerd Hoffmann
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb.h              |    2 +
 hw/usb/hcd-ehci-pci.c |   53 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/hw/usb.h b/hw/usb.h
index 3a6cc84..1837bf7 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -524,5 +524,7 @@ const char *usb_device_get_product_desc(USBDevice *dev);
 
 const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
 
+int ehci_create_ich9_with_companions(PCIBus *bus, int slot);
+
 #endif
 
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index 79bc276..d5c7d46 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -145,3 +145,56 @@ static void ehci_pci_register_types(void)
 }
 
 type_init(ehci_pci_register_types)
+
+struct ehci_companions {
+    const char *name;
+    int func;
+    int port;
+};
+
+static const struct ehci_companions ich9_1d[] = {
+    { .name = "ich9-usb-uhci1", .func = 0, .port = 0 },
+    { .name = "ich9-usb-uhci2", .func = 1, .port = 2 },
+    { .name = "ich9-usb-uhci3", .func = 2, .port = 4 },
+};
+
+static const struct ehci_companions ich9_1a[] = {
+    { .name = "ich9-usb-uhci4", .func = 0, .port = 0 },
+    { .name = "ich9-usb-uhci5", .func = 1, .port = 2 },
+    { .name = "ich9-usb-uhci6", .func = 2, .port = 4 },
+};
+
+int ehci_create_ich9_with_companions(PCIBus *bus, int slot)
+{
+    const struct ehci_companions *comp;
+    PCIDevice *ehci, *uhci;
+    BusState *usbbus;
+    const char *name;
+    int i;
+
+    switch (slot) {
+    case 0x1d:
+        name = "ich9-usb-ehci1";
+        comp = ich9_1d;
+        break;
+    case 0x1a:
+        name = "ich9-usb-ehci2";
+        comp = ich9_1a;
+        break;
+    default:
+        return -1;
+    }
+
+    ehci = pci_create_multifunction(bus, PCI_DEVFN(slot, 7), true, name);
+    qdev_init_nofail(&ehci->qdev);
+    usbbus = QLIST_FIRST(&ehci->qdev.child_bus);
+
+    for (i = 0; i < 3; i++) {
+        uhci = pci_create_multifunction(bus, PCI_DEVFN(slot, comp[i].func),
+                                        true, comp[i].name);
+        qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name);
+        qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port);
+        qdev_init_nofail(&uhci->qdev);
+    }
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 21/22] [RfC] usb: mtp filesharing
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (19 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 20/22] usb/ehci-pci: add helper to create ich9 usb controllers Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 22/22] trace: allow disabling events in events file Gerd Hoffmann
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Proof-of-Concept implementation of a USB Media Transfer Device
device for easy filesharing.

Limitations:
  * No write support.
  * No funky access control options.
  * No async I/O.
  * Doesn't build on mingw.

Guest status:
  * Win7 handles the device just fine.
  * gphoto2 can see the device but fails to fetch files,
    seems to expect some PTP-specific command being supported.
  * more tests to be done.

Known issues:
  * Burns CPU like mad with Win7 guest, in ehci periodic schedule
    emulation, due to Win7 polling the event endpoint.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/Makefile.objs |    1 +
 hw/usb/dev-mtp.c     | 1086 ++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events         |   22 +
 3 files changed, 1109 insertions(+), 0 deletions(-)
 create mode 100644 hw/usb/dev-mtp.c

diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 7669938..00e271f 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -12,3 +12,4 @@ 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-uas.o
+common-obj-$(CONFIG_LINUX) += dev-mtp.o
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
new file mode 100644
index 0000000..e20d54f
--- /dev/null
+++ b/hw/usb/dev-mtp.c
@@ -0,0 +1,1086 @@
+/*
+ * Media Transfer Protocol implementation, backed by host filesystem.
+ *
+ * Written by Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This code is licensed under the GPLv2+.
+ */
+
+#include <wchar.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+
+#include "qemu-common.h"
+#include "iov.h"
+#include "trace.h"
+#include "hw/usb.h"
+#include "hw/usb/desc.h"
+
+/* ----------------------------------------------------------------------- */
+
+enum mtp_container_type {
+    TYPE_COMMAND  = 1,
+    TYPE_DATA     = 2,
+    TYPE_RESPONSE = 3,
+    TYPE_EVENT    = 4,
+};
+
+enum mtp_code {
+    /* command codes */
+    CMD_GET_DEVICE_INFO            = 0x1001,
+    CMD_OPEN_SESSION               = 0x1002,
+    CMD_CLOSE_SESSION              = 0x1003,
+    CMD_GET_STORAGE_IDS            = 0x1004,
+    CMD_GET_STORAGE_INFO           = 0x1005,
+    CMD_GET_NUM_OBJECTS            = 0x1006,
+    CMD_GET_OBJECT_HANDLES         = 0x1007,
+    CMD_GET_OBJECT_INFO            = 0x1008,
+    CMD_GET_OBJECT                 = 0x1009,
+    CMD_GET_PARTIAL_OBJECT         = 0x101b,
+
+    /* response codes */
+    RES_OK                         = 0x2001,
+    RES_SESSION_NOT_OPEN           = 0x2003,
+    RES_INVALID_TRANSACTION_ID     = 0x2004,
+    RES_OPERATION_NOT_SUPPORTED    = 0x2005,
+    RES_PARAMETER_NOT_SUPPORTED    = 0x2006,
+    RES_INVALID_STORAGE_ID         = 0x2008,
+    RES_INVALID_OBJECT_HANDLE      = 0x2009,
+    RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
+    RES_INVALID_PARENT_OBJECT      = 0x201a,
+    RES_INVALID_PARAMETER          = 0x201d,
+    RES_SESSION_ALREADY_OPEN       = 0x201e,
+
+    /* format codes */
+    FMT_UNDEFINED_OBJECT           = 0x3000,
+    FMT_ASSOCIATION                = 0x3001,
+};
+
+typedef struct {
+    uint32_t length;
+    uint16_t type;
+    uint16_t code;
+    uint32_t trans;
+} QEMU_PACKED mtp_container;
+
+/* ----------------------------------------------------------------------- */
+
+typedef struct MTPState MTPState;
+typedef struct MTPControl MTPControl;
+typedef struct MTPData MTPData;
+typedef struct MTPObject MTPObject;
+
+enum {
+    EP_DATA_IN = 1,
+    EP_DATA_OUT,
+    EP_EVENT,
+};
+
+struct MTPControl {
+    uint16_t     code;
+    uint32_t     trans;
+    int          argc;
+    uint32_t     argv[5];
+};
+
+struct MTPData {
+    uint16_t     code;
+    uint32_t     trans;
+    uint32_t     offset;
+    uint32_t     length;
+    uint32_t     alloc;
+    uint8_t      *data;
+    bool         first;
+    int          fd;
+};
+
+struct MTPObject {
+    uint32_t     handle;
+    uint16_t     format;
+    char         *name;
+    char         *path;
+    struct stat  stat;
+    MTPObject    *parent;
+    MTPObject    **children;
+    int32_t      nchildren;
+    QTAILQ_ENTRY(MTPObject) next;
+};
+
+struct MTPState {
+    USBDevice    dev;
+    char         *root;
+    char         *desc;
+    uint32_t     flags;
+
+    MTPData      *data_in;
+    MTPData      *data_out;
+    MTPControl   *result;
+    uint32_t     session;
+    uint32_t     next_handle;
+
+    QTAILQ_HEAD(, MTPObject) objects;
+};
+
+#define QEMU_STORAGE_ID 0x00010001
+
+#define MTP_FLAG_WRITABLE 0
+
+#define FLAG_SET(_mtp, _flag)  ((_mtp)->flags & (1 << (_flag)))
+
+/* ----------------------------------------------------------------------- */
+
+#define MTP_MANUFACTURER  "QEMU"
+#define MTP_PRODUCT       "QEMU filesharing"
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+    STR_CONFIG_FULL,
+    STR_CONFIG_HIGH,
+    STR_CONFIG_SUPER,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER] = MTP_MANUFACTURER,
+    [STR_PRODUCT]      = MTP_PRODUCT,
+    [STR_SERIALNUMBER] = "34617",
+    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
+    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
+    [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
+};
+
+static const USBDescIface desc_iface_full = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 3,
+    .bInterfaceClass               = USB_CLASS_STILL_IMAGE,
+    .bInterfaceSubClass            = 0x01,
+    .bInterfaceProtocol            = 0x01,
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | EP_DATA_IN,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | EP_DATA_OUT,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | EP_EVENT,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 8,
+            .bInterval             = 0x0a,
+        },
+    }
+};
+
+static const USBDescDevice desc_device_full = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_FULL,
+            .bmAttributes          = 0xe0,
+            .bMaxPower             = 2,
+            .nif = 1,
+            .ifs = &desc_iface_full,
+        },
+    },
+};
+
+static const USBDescIface desc_iface_high = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 3,
+    .bInterfaceClass               = USB_CLASS_STILL_IMAGE,
+    .bInterfaceSubClass            = 0x01,
+    .bInterfaceProtocol            = 0x01,
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | EP_DATA_IN,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 512,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | EP_DATA_OUT,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 512,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | EP_EVENT,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 8,
+            .bInterval             = 0x0a,
+        },
+    }
+};
+
+static const USBDescDevice desc_device_high = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_HIGH,
+            .bmAttributes          = 0xe0,
+            .bMaxPower             = 2,
+            .nif = 1,
+            .ifs = &desc_iface_high,
+        },
+    },
+};
+
+static const USBDesc desc = {
+    .id = {
+        .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
+        .idProduct         = 0x0004,
+        .bcdDevice         = 0,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full  = &desc_device_full,
+    .high  = &desc_device_high,
+    .str   = desc_strings,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
+                                       MTPObject *parent, char *name)
+{
+    MTPObject *o = g_new0(MTPObject, 1);
+
+    if (name[0] == '.') {
+        goto ignore;
+    }
+
+    o->handle = handle;
+    o->parent = parent;
+    o->name = g_strdup(name);
+    o->nchildren = -1;
+    if (parent == NULL) {
+        o->path = g_strdup(name);
+    } else {
+        o->path = g_strdup_printf("%s/%s", parent->path, name);
+    }
+
+    if (lstat(o->path, &o->stat) != 0) {
+        goto ignore;
+    }
+    if (S_ISREG(o->stat.st_mode)) {
+        o->format = FMT_UNDEFINED_OBJECT;
+    } else if (S_ISDIR(o->stat.st_mode)) {
+        o->format = FMT_ASSOCIATION;
+    } else {
+        goto ignore;
+    }
+
+    if (access(o->path, R_OK) != 0) {
+        goto ignore;
+    }
+
+    fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+
+    QTAILQ_INSERT_TAIL(&s->objects, o, next);
+    return o;
+
+ignore:
+    g_free(o->name);
+    g_free(o->path);
+    g_free(o);
+    return NULL;
+}
+
+static void usb_mtp_object_free(MTPState *s, MTPObject *o)
+{
+    int i;
+
+    fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+
+    QTAILQ_REMOVE(&s->objects, o, next);
+    for (i = 0; i < o->nchildren; i++) {
+        usb_mtp_object_free(s, o->children[i]);
+    }
+    g_free(o->children);
+    g_free(o->name);
+    g_free(o->path);
+    g_free(o);
+}
+
+static MTPObject *usb_mtp_object_lookup(MTPState *s, uint32_t handle)
+{
+    MTPObject *o;
+
+    QTAILQ_FOREACH(o, &s->objects, next) {
+        if (o->handle == handle) {
+            return o;
+        }
+    }
+    return NULL;
+}
+
+static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
+{
+    struct dirent *entry;
+    DIR *dir;
+
+    o->nchildren = 0;
+    dir = opendir(o->path);
+    if (!dir) {
+        return;
+    }
+    while ((entry = readdir(dir)) != NULL) {
+        if ((o->nchildren % 32) == 0) {
+            o->children = g_realloc(o->children,
+                                    (o->nchildren + 32) * sizeof(MTPObject *));
+        }
+        o->children[o->nchildren] =
+            usb_mtp_object_alloc(s, s->next_handle++, o, entry->d_name);
+        if (o->children[o->nchildren] != NULL) {
+            o->nchildren++;
+        }
+    }
+    closedir(dir);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static MTPData *usb_mtp_data_alloc(MTPControl *c)
+{
+    MTPData *data = g_new0(MTPData, 1);
+
+    data->code  = c->code;
+    data->trans = c->trans;
+    data->fd    = -1;
+    data->first = true;
+    return data;
+}
+
+static void usb_mtp_data_free(MTPData *data)
+{
+    if (data == NULL) {
+        return;
+    }
+    if (data->fd != -1) {
+        close(data->fd);
+    }
+    g_free(data->data);
+    g_free(data);
+}
+
+static void usb_mtp_realloc(MTPData *data, uint32_t bytes)
+{
+    if (data->length + bytes <= data->alloc) {
+        return;
+    }
+    data->alloc = (data->length + bytes + 0xff) & ~0xff;
+    data->data  = g_realloc(data->data, data->alloc);
+}
+
+static void usb_mtp_add_u8(MTPData *data, uint8_t val)
+{
+    usb_mtp_realloc(data, 1);
+    data->data[data->length++] = val;
+}
+
+static void usb_mtp_add_u16(MTPData *data, uint16_t val)
+{
+    usb_mtp_realloc(data, 2);
+    data->data[data->length++] = (val >> 0) & 0xff;
+    data->data[data->length++] = (val >> 8) & 0xff;
+}
+
+static void usb_mtp_add_u32(MTPData *data, uint32_t val)
+{
+    usb_mtp_realloc(data, 4);
+    data->data[data->length++] = (val >>  0) & 0xff;
+    data->data[data->length++] = (val >>  8) & 0xff;
+    data->data[data->length++] = (val >> 16) & 0xff;
+    data->data[data->length++] = (val >> 24) & 0xff;
+}
+
+static void usb_mtp_add_u64(MTPData *data, uint64_t val)
+{
+    usb_mtp_realloc(data, 4);
+    data->data[data->length++] = (val >>  0) & 0xff;
+    data->data[data->length++] = (val >>  8) & 0xff;
+    data->data[data->length++] = (val >> 16) & 0xff;
+    data->data[data->length++] = (val >> 24) & 0xff;
+    data->data[data->length++] = (val >> 32) & 0xff;
+    data->data[data->length++] = (val >> 40) & 0xff;
+    data->data[data->length++] = (val >> 48) & 0xff;
+    data->data[data->length++] = (val >> 54) & 0xff;
+}
+
+static void usb_mtp_add_u16_array(MTPData *data, uint32_t len,
+                                  const uint16_t *vals)
+{
+    int i;
+
+    usb_mtp_add_u32(data, len);
+    for (i = 0; i < len; i++) {
+        usb_mtp_add_u16(data, vals[i]);
+    }
+}
+
+static void usb_mtp_add_u32_array(MTPData *data, uint32_t len,
+                                  const uint32_t *vals)
+{
+    int i;
+
+    usb_mtp_add_u32(data, len);
+    for (i = 0; i < len; i++) {
+        usb_mtp_add_u32(data, vals[i]);
+    }
+}
+
+static void usb_mtp_add_wstr(MTPData *data, const wchar_t *str)
+{
+    uint32_t len = wcslen(str);
+    int i;
+
+    if (len > 0) {
+        len++; /* include terminating L'\0' */
+    }
+
+    usb_mtp_add_u8(data, len);
+    for (i = 0; i < len; i++) {
+        usb_mtp_add_u16(data, str[i]);
+    }
+}
+
+static void usb_mtp_add_str(MTPData *data, const char *str)
+{
+    uint32_t len = strlen(str)+1;
+    wchar_t wstr[len];
+    size_t ret;
+
+    ret = mbstowcs(wstr, str, len);
+    if (ret == -1) {
+        usb_mtp_add_wstr(data, L"Oops");
+    } else {
+        usb_mtp_add_wstr(data, wstr);
+    }
+}
+
+static void usb_mtp_add_time(MTPData *data, time_t time)
+{
+    char buf[16];
+    struct tm tm;
+
+    gmtime_r(&time, &tm);
+    strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm);
+    usb_mtp_add_str(data, buf);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void usb_mtp_queue_result(MTPState *s, uint16_t code, uint32_t trans,
+                                 int argc, uint32_t arg0, uint32_t arg1)
+{
+    MTPControl *c = g_new0(MTPControl, 1);
+
+    c->code  = code;
+    c->trans = trans;
+    c->argc  = argc;
+    if (argc > 0) {
+        c->argv[0] = arg0;
+    }
+    if (argc > 1) {
+        c->argv[1] = arg1;
+    }
+
+    assert(s->result == NULL);
+    s->result = c;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
+{
+    static const uint16_t ops[] = {
+        CMD_GET_DEVICE_INFO,
+        CMD_OPEN_SESSION,
+        CMD_CLOSE_SESSION,
+        CMD_GET_STORAGE_IDS,
+        CMD_GET_STORAGE_INFO,
+        CMD_GET_NUM_OBJECTS,
+        CMD_GET_OBJECT_HANDLES,
+        CMD_GET_OBJECT_INFO,
+        CMD_GET_OBJECT,
+        CMD_GET_PARTIAL_OBJECT,
+    };
+    static const uint16_t fmt[] = {
+        FMT_UNDEFINED_OBJECT,
+        FMT_ASSOCIATION,
+    };
+    MTPData *d = usb_mtp_data_alloc(c);
+
+    trace_usb_mtp_op_get_device_info(s->dev.addr);
+
+    usb_mtp_add_u16(d, 0x0100);
+    usb_mtp_add_u32(d, 0xffffffff);
+    usb_mtp_add_u16(d, 0x0101);
+    usb_mtp_add_wstr(d, L"");
+    usb_mtp_add_u16(d, 0x0000);
+
+    usb_mtp_add_u16_array(d, ARRAY_SIZE(ops), ops);
+    usb_mtp_add_u16_array(d, 0, NULL);
+    usb_mtp_add_u16_array(d, 0, NULL);
+    usb_mtp_add_u16_array(d, 0, NULL);
+    usb_mtp_add_u16_array(d, ARRAY_SIZE(fmt), fmt);
+
+    usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER);
+    usb_mtp_add_wstr(d, L"" MTP_PRODUCT);
+    usb_mtp_add_wstr(d, L"0.1");
+    usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef");
+
+    return d;
+}
+
+static MTPData *usb_mtp_get_storage_ids(MTPState *s, MTPControl *c)
+{
+    static const uint32_t ids[] = {
+        QEMU_STORAGE_ID,
+    };
+    MTPData *d = usb_mtp_data_alloc(c);
+
+    trace_usb_mtp_op_get_storage_ids(s->dev.addr);
+
+    usb_mtp_add_u32_array(d, ARRAY_SIZE(ids), ids);
+
+    return d;
+}
+
+static MTPData *usb_mtp_get_storage_info(MTPState *s, MTPControl *c)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+    struct statvfs buf;
+    int rc;
+
+    trace_usb_mtp_op_get_storage_info(s->dev.addr);
+
+    if (FLAG_SET(s, MTP_FLAG_WRITABLE)) {
+        usb_mtp_add_u16(d, 0x0003);
+        usb_mtp_add_u16(d, 0x0002);
+        usb_mtp_add_u16(d, 0x0000);
+    } else {
+        usb_mtp_add_u16(d, 0x0001);
+        usb_mtp_add_u16(d, 0x0002);
+        usb_mtp_add_u16(d, 0x0001);
+    }
+
+    rc = statvfs(s->root, &buf);
+    if (rc == 0) {
+        usb_mtp_add_u64(d, (uint64_t)buf.f_frsize * buf.f_blocks);
+        usb_mtp_add_u64(d, (uint64_t)buf.f_bavail * buf.f_blocks);
+        usb_mtp_add_u32(d, buf.f_ffree);
+    } else {
+        usb_mtp_add_u64(d, 0xffffffff);
+        usb_mtp_add_u64(d, 0xffffffff);
+        usb_mtp_add_u32(d, 0xffffffff);
+    }
+
+    usb_mtp_add_str(d, s->desc);
+    usb_mtp_add_wstr(d, L"123456789abcdef");
+    return d;
+}
+
+static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c,
+                                           MTPObject *o)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+    uint32_t i, handles[o->nchildren];
+
+    trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path);
+
+    for (i = 0; i < o->nchildren; i++) {
+        handles[i] = o->children[i]->handle;
+    }
+    usb_mtp_add_u32_array(d, o->nchildren, handles);
+
+    return d;
+}
+
+static MTPData *usb_mtp_get_object_info(MTPState *s, MTPControl *c,
+                                        MTPObject *o)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+
+    trace_usb_mtp_op_get_object_info(s->dev.addr, o->handle, o->path);
+
+    usb_mtp_add_u32(d, QEMU_STORAGE_ID);
+    usb_mtp_add_u16(d, o->format);
+    usb_mtp_add_u16(d, 0);
+    usb_mtp_add_u32(d, o->stat.st_size);
+
+    usb_mtp_add_u16(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+
+    if (o->parent) {
+        usb_mtp_add_u32(d, o->parent->handle);
+    } else {
+        usb_mtp_add_u32(d, 0);
+    }
+    if (o->format == FMT_ASSOCIATION) {
+        usb_mtp_add_u16(d, 0x0001);
+        usb_mtp_add_u32(d, 0x00000001);
+        usb_mtp_add_u32(d, 0);
+    } else {
+        usb_mtp_add_u16(d, 0);
+        usb_mtp_add_u32(d, 0);
+        usb_mtp_add_u32(d, 0);
+    }
+
+    usb_mtp_add_str(d, o->name);
+    usb_mtp_add_time(d, o->stat.st_ctime);
+    usb_mtp_add_time(d, o->stat.st_mtime);
+    usb_mtp_add_wstr(d, L"");
+
+    return d;
+}
+
+static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
+                                   MTPObject *o)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+
+    trace_usb_mtp_op_get_object(s->dev.addr, o->handle, o->path);
+
+    d->fd = open(o->path, O_RDONLY);
+    if (d->fd == -1) {
+        return NULL;
+    }
+    d->length = o->stat.st_size;
+    d->alloc  = 512;
+    d->data   = g_malloc(d->alloc);
+    return d;
+}
+
+static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
+                                           MTPObject *o)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+    off_t offset;
+
+    trace_usb_mtp_op_get_partial_object(s->dev.addr, o->handle, o->path,
+                                        c->argv[1], c->argv[2]);
+
+    d->fd = open(o->path, O_RDONLY);
+    if (d->fd == -1) {
+        return NULL;
+    }
+
+    offset = c->argv[1];
+    if (offset > o->stat.st_size) {
+        offset = o->stat.st_size;
+    }
+    lseek(d->fd, offset, SEEK_SET);
+
+    d->length = c->argv[2];
+    if (d->length > o->stat.st_size - offset) {
+        d->length = o->stat.st_size - offset;
+    }
+
+    return d;
+}
+
+static void usb_mtp_command(MTPState *s, MTPControl *c)
+{
+    MTPData *data_in = NULL;
+    MTPObject *o;
+    uint32_t nres = 0, res0 = 0;
+
+    /* sanity checks */
+    if (c->code >= CMD_CLOSE_SESSION && s->session == 0) {
+        usb_mtp_queue_result(s, RES_SESSION_NOT_OPEN,
+                             c->trans, 0, 0, 0);
+        return;
+    }
+
+    /* process commands */
+    switch (c->code) {
+    case CMD_GET_DEVICE_INFO:
+        data_in = usb_mtp_get_device_info(s, c);
+        break;
+    case CMD_OPEN_SESSION:
+        if (s->session) {
+            usb_mtp_queue_result(s, RES_SESSION_ALREADY_OPEN,
+                                 c->trans, 1, s->session, 0);
+            return;
+        }
+        if (c->argv[0] == 0) {
+            usb_mtp_queue_result(s, RES_INVALID_PARAMETER,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        trace_usb_mtp_op_open_session(s->dev.addr);
+        s->session = c->argv[0];
+        usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root);
+        break;
+    case CMD_CLOSE_SESSION:
+        trace_usb_mtp_op_close_session(s->dev.addr);
+        s->session = 0;
+        s->next_handle = 0;
+        usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
+        assert(QTAILQ_EMPTY(&s->objects));
+        break;
+    case CMD_GET_STORAGE_IDS:
+        data_in = usb_mtp_get_storage_ids(s, c);
+        break;
+    case CMD_GET_STORAGE_INFO:
+        if (c->argv[0] != QEMU_STORAGE_ID &&
+            c->argv[0] != 0xffffffff) {
+            usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        data_in = usb_mtp_get_storage_info(s, c);
+        break;
+    case CMD_GET_NUM_OBJECTS:
+    case CMD_GET_OBJECT_HANDLES:
+        if (c->argv[0] != QEMU_STORAGE_ID &&
+            c->argv[0] != 0xffffffff) {
+            usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (c->argv[1] != 0x00000000) {
+            usb_mtp_queue_result(s, RES_SPEC_BY_FORMAT_UNSUPPORTED,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (c->argv[2] == 0x00000000 ||
+            c->argv[2] == 0xffffffff) {
+            o = QTAILQ_FIRST(&s->objects);
+        } else {
+            o = usb_mtp_object_lookup(s, c->argv[2]);
+        }
+        if (o == NULL) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (o->format != FMT_ASSOCIATION) {
+            usb_mtp_queue_result(s, RES_INVALID_PARENT_OBJECT,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (o->nchildren == -1) {
+            usb_mtp_object_readdir(s, o);
+        }
+        if (c->code == CMD_GET_NUM_OBJECTS) {
+            trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
+            nres = 1;
+            res0 = o->nchildren;
+        } else {
+            data_in = usb_mtp_get_object_handles(s, c, o);
+        }
+        break;
+    case CMD_GET_OBJECT_INFO:
+        o = usb_mtp_object_lookup(s, c->argv[0]);
+        if (o == NULL) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        data_in = usb_mtp_get_object_info(s, c, o);
+        break;
+    case CMD_GET_OBJECT:
+        o = usb_mtp_object_lookup(s, c->argv[0]);
+        if (o == NULL) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (o->format == FMT_ASSOCIATION) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        data_in = usb_mtp_get_object(s, c, o);
+        if (NULL == data_in) {
+            fprintf(stderr, "%s: TODO: handle error\n", __func__);
+        }
+        break;
+    case CMD_GET_PARTIAL_OBJECT:
+        o = usb_mtp_object_lookup(s, c->argv[0]);
+        if (o == NULL) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (o->format == FMT_ASSOCIATION) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        data_in = usb_mtp_get_partial_object(s, c, o);
+        if (NULL == data_in) {
+            fprintf(stderr, "%s: TODO: handle error\n", __func__);
+        }
+        nres = 1;
+        res0 = data_in->length;
+        break;
+    default:
+        fprintf(stderr, "%s: unknown command code 0x%04x\n",
+                __func__, c->code);
+        usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
+                             c->trans, 0, 0, 0);
+        return;
+    }
+
+    /* return results on success */
+    if (data_in) {
+        assert(s->data_in == NULL);
+        s->data_in = data_in;
+    }
+    usb_mtp_queue_result(s, RES_OK, c->trans, nres, res0, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void usb_mtp_handle_reset(USBDevice *dev)
+{
+    MTPState *s = DO_UPCAST(MTPState, dev, dev);
+
+    trace_usb_mtp_reset(s->dev.addr);
+
+    s->session = 0;
+    usb_mtp_data_free(s->data_in);
+    s->data_in = NULL;
+    usb_mtp_data_free(s->data_out);
+    s->data_out = NULL;
+    g_free(s->result);
+    s->result = NULL;
+}
+
+static int usb_mtp_handle_control(USBDevice *dev, USBPacket *p,
+                                  int request, int value, int index,
+                                  int length, uint8_t *data)
+{
+    int ret;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    trace_usb_mtp_stall(dev->addr, "unknown control request");
+    return USB_RET_STALL;
+}
+
+static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
+{
+    fprintf(stderr, "%s\n", __func__);
+}
+
+static int usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
+{
+    MTPState *s = DO_UPCAST(MTPState, dev, dev);
+    MTPControl cmd;
+    mtp_container container;
+    uint32_t params[5];
+    int i, rc;
+
+    switch (p->ep->nr) {
+    case EP_DATA_IN:
+        if (s->data_out != NULL) {
+            /* guest bug */
+            trace_usb_mtp_stall(s->dev.addr, "awaiting data-out");
+            return USB_RET_STALL;
+        }
+        if (p->iov.size < sizeof(container)) {
+            trace_usb_mtp_stall(s->dev.addr, "packet too small");
+            return USB_RET_STALL;
+        }
+        if (s->data_in !=  NULL) {
+            MTPData *d = s->data_in;
+            int dlen = d->length - d->offset;
+            if (d->first) {
+                trace_usb_mtp_data_in(s->dev.addr, d->trans, d->length);
+                container.length = cpu_to_le32(d->length + sizeof(container));
+                container.type   = cpu_to_le16(TYPE_DATA);
+                container.code   = cpu_to_le16(d->code);
+                container.trans  = cpu_to_le32(d->trans);
+                usb_packet_copy(p, &container, sizeof(container));
+                d->first = false;
+                if (dlen > p->iov.size - sizeof(container)) {
+                    dlen = p->iov.size - sizeof(container);
+                }
+            } else {
+                if (dlen > p->iov.size) {
+                    dlen = p->iov.size;
+                }
+            }
+            if (d->fd == -1) {
+                usb_packet_copy(p, d->data + d->offset, dlen);
+            } else {
+                if (d->alloc < p->iov.size) {
+                    d->alloc = p->iov.size;
+                    d->data = g_realloc(d->data, d->alloc);
+                }
+                rc = read(d->fd, d->data, dlen);
+                if (rc != dlen) {
+                    fprintf(stderr, "%s: TODO: handle read error\n", __func__);
+                }
+                usb_packet_copy(p, d->data, dlen);
+            }
+            d->offset += dlen;
+            if (d->offset == d->length) {
+                usb_mtp_data_free(s->data_in);
+                s->data_in = NULL;
+            }
+        } else if (s->result != NULL) {
+            MTPControl *r = s->result;
+            int length = sizeof(container) + r->argc * sizeof(uint32_t);
+            if (r->code == RES_OK) {
+                trace_usb_mtp_success(s->dev.addr, r->trans,
+                                      (r->argc > 0) ? r->argv[0] : 0,
+                                      (r->argc > 1) ? r->argv[1] : 0);
+            } else {
+                trace_usb_mtp_error(s->dev.addr, r->code, r->trans,
+                                    (r->argc > 0) ? r->argv[0] : 0,
+                                    (r->argc > 1) ? r->argv[1] : 0);
+            }
+            container.length = cpu_to_le32(length);
+            container.type   = cpu_to_le16(TYPE_RESPONSE);
+            container.code   = cpu_to_le16(r->code);
+            container.trans  = cpu_to_le32(r->trans);
+            for (i = 0; i < r->argc; i++) {
+                params[i] = cpu_to_le32(r->argv[i]);
+            }
+            usb_packet_copy(p, &container, sizeof(container));
+            usb_packet_copy(p, &params, length - sizeof(container));
+            g_free(s->result);
+            s->result = NULL;
+        }
+        break;
+    case EP_DATA_OUT:
+        if (p->iov.size < sizeof(container)) {
+            trace_usb_mtp_stall(s->dev.addr, "packet too small");
+            return USB_RET_STALL;
+        }
+        usb_packet_copy(p, &container, sizeof(container));
+        switch (le16_to_cpu(container.type)) {
+        case TYPE_COMMAND:
+            if (s->data_in || s->data_out || s->result) {
+                trace_usb_mtp_stall(s->dev.addr, "transaction inflight");
+                return USB_RET_STALL;
+            }
+            cmd.code = le16_to_cpu(container.code);
+            cmd.argc = (le32_to_cpu(container.length) - sizeof(container))
+                / sizeof(uint32_t);
+            cmd.trans = le32_to_cpu(container.trans);
+            usb_packet_copy(p, &params, cmd.argc * sizeof(uint32_t));
+            for (i = 0; i < cmd.argc; i++) {
+                cmd.argv[i] = le32_to_cpu(params[i]);
+            }
+            trace_usb_mtp_command(s->dev.addr, cmd.code, cmd.trans,
+                                  (cmd.argc > 0) ? cmd.argv[0] : 0,
+                                  (cmd.argc > 1) ? cmd.argv[1] : 0,
+                                  (cmd.argc > 2) ? cmd.argv[2] : 0,
+                                  (cmd.argc > 3) ? cmd.argv[3] : 0,
+                                  (cmd.argc > 4) ? cmd.argv[4] : 0);
+            usb_mtp_command(s, &cmd);
+            break;
+        default:
+            iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32);
+            trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out");
+            return USB_RET_STALL;
+        }
+        break;
+    case EP_EVENT:
+        return USB_RET_NAK;
+        break;
+    default:
+        trace_usb_mtp_stall(s->dev.addr, "invalid endpoint");
+        return USB_RET_STALL;
+    }
+
+    if (p->result == 0) {
+        trace_usb_mtp_nak(s->dev.addr, p->ep->nr);
+        return USB_RET_NAK;
+    } else {
+        trace_usb_mtp_xfer(s->dev.addr, p->ep->nr, p->result, p->iov.size);
+        return p->result;
+    }
+}
+
+static int usb_mtp_initfn(USBDevice *dev)
+{
+    MTPState *s = DO_UPCAST(MTPState, dev, dev);
+
+    usb_desc_create_serial(dev);
+    usb_desc_init(dev);
+    QTAILQ_INIT(&s->objects);
+    if (s->desc == NULL) {
+        s->desc = strrchr(s->root, '/');
+        if (s->desc) {
+            s->desc = g_strdup(s->desc + 1);
+        } else {
+            s->desc = g_strdup("none");
+        }
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_usb_mtp = {
+    .name = "usb-mtp",
+    .unmigratable = 1,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_USB_DEVICE(dev, MTPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property mtp_properties[] = {
+    DEFINE_PROP_STRING("root", MTPState, root),
+    DEFINE_PROP_STRING("desc", MTPState, desc),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_mtp_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_mtp_initfn;
+    uc->product_desc   = "QEMU USB MTP";
+    uc->usb_desc       = &desc;
+    uc->cancel_packet  = usb_mtp_cancel_packet;
+    uc->handle_attach  = usb_desc_attach;
+    uc->handle_reset   = usb_mtp_handle_reset;
+    uc->handle_control = usb_mtp_handle_control;
+    uc->handle_data    = usb_mtp_handle_data;
+    dc->fw_name = "mtp";
+    dc->vmsd = &vmstate_usb_mtp;
+    dc->props = mtp_properties;
+}
+
+static TypeInfo mtp_info = {
+    .name          = "usb-mtp",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(MTPState),
+    .class_init    = usb_mtp_class_initfn,
+};
+
+static void usb_mtp_register_types(void)
+{
+    type_register_static(&mtp_info);
+}
+
+type_init(usb_mtp_register_types)
diff --git a/trace-events b/trace-events
index 0cb991e..f8d9c2f 100644
--- a/trace-events
+++ b/trace-events
@@ -390,6 +390,28 @@ usb_uas_tmf_abort_task(int addr, uint16_t tag, uint16_t task_tag) "dev %d, tag 0
 usb_uas_tmf_logical_unit_reset(int addr, uint16_t tag, int lun) "dev %d, tag 0x%x, lun %d"
 usb_uas_tmf_unsupported(int addr, uint16_t tag, uint32_t function) "dev %d, tag 0x%x, function 0x%x"
 
+# hw/usb/dev-mtp.c
+usb_mtp_reset(int addr) "dev %d"
+usb_mtp_command(int dev, uint16_t code, uint32_t trans, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) "dev %d, code 0x%x, trans 0x%x, args 0x%x, 0x%x, 0x%x, 0x%x, 0x%x"
+usb_mtp_success(int dev, uint32_t trans, uint32_t arg0, uint32_t arg1) "dev %d, trans 0x%x, args 0x%x, 0x%x"
+usb_mtp_error(int dev, uint16_t code, uint32_t trans, uint32_t arg0, uint32_t arg1) "dev %d, code 0x%x, trans 0x%x, args 0x%x, 0x%x"
+usb_mtp_data_in(int dev, uint32_t trans, uint32_t len) "dev %d, trans 0x%x, len %d"
+usb_mtp_data_out(int dev, uint32_t trans, uint32_t len) "dev %d, trans 0x%x, len %d"
+usb_mtp_xfer(int dev, uint32_t ep, uint32_t dlen, uint32_t plen) "dev %d, ep %d, %d/%d"
+usb_mtp_nak(int dev, uint32_t ep) "dev %d, ep %d"
+usb_mtp_stall(int dev, const char *reason) "dev %d, reason: %s"
+usb_mtp_op_get_device_info(int dev) "dev %d"
+usb_mtp_op_open_session(int dev) "dev %d"
+usb_mtp_op_close_session(int dev) "dev %d"
+usb_mtp_op_get_storage_ids(int dev) "dev %d"
+usb_mtp_op_get_storage_info(int dev) "dev %d"
+usb_mtp_op_get_num_objects(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_op_get_object_handles(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_op_get_object_info(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_op_get_object(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_op_get_partial_object(int dev, uint32_t handle, const char *path, uint32_t offset, uint32_t length) "dev %d, handle 0x%x, path %s, off %d, len %d"
+
+
 # hw/usb/host-linux.c
 usb_host_open_started(int bus, int addr) "dev %d:%d"
 usb_host_open_success(int bus, int addr) "dev %d:%d"
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 22/22] trace: allow disabling events in events file
  2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
                   ` (20 preceding siblings ...)
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 21/22] [RfC] usb: mtp filesharing Gerd Hoffmann
@ 2012-10-30 14:26 ` Gerd Hoffmann
  21 siblings, 0 replies; 24+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Disable trace events prefixed with a '-'.  Useful
to enable a group of tracepoints with exceptions,
like this:

  usb_xhci_port_*
  -usb_xhci_port_read

which will enable all xhci port tracepoints except reads.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 trace/control.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/trace/control.c b/trace/control.c
index 22d5863..be05efb 100644
--- a/trace/control.c
+++ b/trace/control.c
@@ -12,6 +12,8 @@
 
 void trace_backend_init_events(const char *fname)
 {
+    int ret;
+
     if (fname == NULL) {
         return;
     }
@@ -30,7 +32,12 @@ void trace_backend_init_events(const char *fname)
             if ('#' == line_buf[0]) { /* skip commented lines */
                 continue;
             }
-            if (!trace_event_set_state(line_buf, true)) {
+            if ('-' == line_buf[0]) {
+                ret = trace_event_set_state(line_buf+1, false);
+            } else {
+                ret = trace_event_set_state(line_buf, true);
+            }
+            if (!ret) {
                 fprintf(stderr,
                         "error: trace event '%s' does not exist\n", line_buf);
                 exit(1);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 14/22] usb/ehci: add sysbus variant
  2012-10-30 14:26 ` [Qemu-devel] [PATCH 14/22] usb/ehci: add sysbus variant Gerd Hoffmann
@ 2012-10-31  5:57   ` Peter Crosthwaite
  0 siblings, 0 replies; 24+ messages in thread
From: Peter Crosthwaite @ 2012-10-31  5:57 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3769 bytes --]

All good,

Needs a hack to get around the dma_memory_foo segfault (attached), but
that will come out in the wash with the memory API refactorings.

Regards,
Peter

On Tue, 2012-10-30 at 15:26 +0100, Gerd Hoffmann wrote:
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Tested-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

> ---
>  hw/usb/Makefile.objs     |    2 +-
>  hw/usb/hcd-ehci-sysbus.c |   77 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 78 insertions(+), 1 deletions(-)
>  create mode 100644 hw/usb/hcd-ehci-sysbus.c
> 
> diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
> index 5c7b024..7669938 100644
> --- a/hw/usb/Makefile.objs
> +++ b/hw/usb/Makefile.objs
> @@ -1,6 +1,6 @@
>  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
> +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
>  
> diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
> new file mode 100644
> index 0000000..1584079
> --- /dev/null
> +++ b/hw/usb/hcd-ehci-sysbus.c
> @@ -0,0 +1,77 @@
> +/*
> + * QEMU USB EHCI Emulation
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or(at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "hw/usb/hcd-ehci.h"
> +#include "hw/sysbus.h"
> +
> +typedef struct EHCISysBusState {
> +    SysBusDevice busdev;
> +    EHCIState ehci;
> +} EHCISysBusState;
> +
> +static const VMStateDescription vmstate_ehci_sysbus = {
> +    .name        = "ehci-sysbus",
> +    .version_id  = 2,
> +    .minimum_version_id  = 1,
> +    .fields      = (VMStateField[]) {
> +        VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property ehci_sysbus_properties[] = {
> +    DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static int usb_ehci_sysbus_initfn(SysBusDevice *dev)
> +{
> +    EHCISysBusState *i = FROM_SYSBUS(EHCISysBusState, dev);
> +    EHCIState *s = &i->ehci;
> +
> +    s->capsbase = 0x100;
> +    s->opregbase = 0x140;
> +
> +    usb_ehci_initfn(s, DEVICE(dev));
> +    sysbus_init_irq(dev, &s->irq);
> +    sysbus_init_mmio(dev, &s->mem);
> +    return 0;
> +}
> +
> +static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +
> +    k->init = usb_ehci_sysbus_initfn;
> +    dc->vmsd = &vmstate_ehci_sysbus;
> +    dc->props = ehci_sysbus_properties;
> +}
> +
> +TypeInfo ehci_xlnx_type_info = {
> +    .name          = "xlnx,ps7-usb",
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(EHCISysBusState),
> +    .class_init    = ehci_sysbus_class_init,
> +};
> +
> +static void ehci_sysbus_register_types(void)
> +{
> +    type_register_static(&ehci_xlnx_type_info);
> +}
> +
> +type_init(ehci_sysbus_register_types)


[-- Attachment #2: 0001-dma-Define-dma_context_memory-and-use-by-default.patch --]
[-- Type: text/x-patch, Size: 3679 bytes --]

>From b3dc8992bbea0358752efdd8ca8803c8f150f083 Mon Sep 17 00:00:00 2001
From: Peter Maydell <peter.maydell@linaro.org>
Date: Tue, 23 Oct 2012 18:26:51 +0100
Subject: [PATCH] dma: Define dma_context_memory and use by default

Define a new global dma_context_memory which is a DMAContext corresponding
to the global address_space_memory AddressSpace. This can be used by
sysbus peripherals like sysbus-ohci which need to do DMA.

[PC] Use this dma context by default if NULL is passed to the dma API for
DMAContext *dma

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
 dma.h  |   17 +++++++++++++++++
 exec.c |    5 +++++
 2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/dma.h b/dma.h
index 91ccdb5..defed50 100644
--- a/dma.h
+++ b/dma.h
@@ -68,6 +68,11 @@ struct DMAContext {
     DMAUnmapFunc *unmap;
 };
 
+/* A global DMA context corresponding to the address_space_memory
+ * AddressSpace, for sysbus devices which do DMA.
+ */
+extern DMAContext dma_context_memory;
+
 static inline void dma_barrier(DMAContext *dma, DMADirection dir)
 {
     /*
@@ -107,6 +112,9 @@ static inline bool dma_memory_valid(DMAContext *dma,
                                     dma_addr_t addr, dma_addr_t len,
                                     DMADirection dir)
 {
+    if (!dma) {
+        dma = &dma_context_memory;
+    }
     if (!dma_has_iommu(dma)) {
         return true;
     } else {
@@ -120,6 +128,9 @@ static inline int dma_memory_rw_relaxed(DMAContext *dma, dma_addr_t addr,
                                         void *buf, dma_addr_t len,
                                         DMADirection dir)
 {
+    if (!dma) {
+        dma = &dma_context_memory;
+    }
     if (!dma_has_iommu(dma)) {
         /* Fast-path for no IOMMU */
         address_space_rw(dma->as, addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE);
@@ -176,6 +187,9 @@ static inline void *dma_memory_map(DMAContext *dma,
                                    dma_addr_t addr, dma_addr_t *len,
                                    DMADirection dir)
 {
+    if (!dma) {
+        dma = &dma_context_memory;
+    }
     if (!dma_has_iommu(dma)) {
         hwaddr xlen = *len;
         void *p;
@@ -195,6 +209,9 @@ static inline void dma_memory_unmap(DMAContext *dma,
                                     void *buffer, dma_addr_t len,
                                     DMADirection dir, dma_addr_t access_len)
 {
+    if (!dma) {
+        dma = &dma_context_memory;
+    }
     if (!dma_has_iommu(dma)) {
         address_space_unmap(dma->as, buffer, (hwaddr)len,
                             dir == DMA_DIRECTION_FROM_DEVICE, access_len);
diff --git a/exec.c b/exec.c
index b0ed593..d2f6e79 100644
--- a/exec.c
+++ b/exec.c
@@ -34,6 +34,7 @@
 #include "hw/xen.h"
 #include "qemu-timer.h"
 #include "memory.h"
+#include "dma.h"
 #include "exec-memory.h"
 #if defined(CONFIG_USER_ONLY)
 #include <qemu.h>
@@ -103,6 +104,7 @@ static MemoryRegion *system_io;
 
 AddressSpace address_space_io;
 AddressSpace address_space_memory;
+DMAContext dma_context_memory;
 
 MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty;
 static MemoryRegion io_mem_subpage_ram;
@@ -3276,6 +3278,9 @@ static void memory_map_init(void)
     memory_listener_register(&core_memory_listener, &address_space_memory);
     memory_listener_register(&io_memory_listener, &address_space_io);
     memory_listener_register(&tcg_memory_listener, &address_space_memory);
+
+    dma_context_init(&dma_context_memory, &address_space_memory,
+                     NULL, NULL, NULL);
 }
 
 MemoryRegion *get_system_memory(void)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2012-10-31  5:57 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-10-30 14:26 [Qemu-devel] [PATCH 00/22] usb patch queue Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 01/22] xhci: add {get, set}_field macros & enum for pls Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 02/22] xhci: s/xhci_update_port/xhci_port_update/ Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 03/22] xhci: add xhci_port_have_device Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 04/22] xhci: add xhci_port_notify Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 05/22] xhci: add xhci_port_reset Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 06/22] xhci: set pls in xhci_port_update & xhci_port_reset Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 07/22] xhci: add port trace points Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 08/22] xhci: allow address slot being called multiple times Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 09/22] usb/ehci: parameterise the register region offsets Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 10/22] usb/ehci: Abstract away PCI DMA API Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 11/22] usb/ehci: seperate out PCIisms Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 12/22] usb/ehci: Guard definition of EHCI_DEBUG Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 13/22] usb/ehci: split into multiple source files Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 14/22] usb/ehci: add sysbus variant Gerd Hoffmann
2012-10-31  5:57   ` Peter Crosthwaite
2012-10-30 14:26 ` [Qemu-devel] [PATCH 15/22] uhci: dynamic type generation Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 16/22] uhci: stick irq routing info into UHCIInfo too Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 17/22] uhci: add ich9 00:1a.* variants Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 18/22] usb/ehci-pci: dynamic type generation Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 19/22] usb/ehci-pci: add ich9 00:1a.* variant Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 20/22] usb/ehci-pci: add helper to create ich9 usb controllers Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 21/22] [RfC] usb: mtp filesharing Gerd Hoffmann
2012-10-30 14:26 ` [Qemu-devel] [PATCH 22/22] trace: allow disabling events in events file Gerd Hoffmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).