usb: rework attach/detach workflow

Add separate detach callback to USBPortOps, split
uhci/ohci/musb/usbhub attach functions into two.

Move common code to the usb_attach() function, only
the hardware-specific bits remain in the attach/detach
callbacks.

Keep track of the port it is attached to for each usb device.

[ v3: fix tyops in usb-musb.c ]

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 0f9ef1e..5e2e34a 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -307,8 +307,6 @@
     return match;
 }
 
-static void uhci_attach(USBPort *port1, USBDevice *dev);
-
 static void uhci_update_irq(UHCIState *s)
 {
     int level;
@@ -348,8 +346,9 @@
     for(i = 0; i < NB_PORTS; i++) {
         port = &s->ports[i];
         port->ctrl = 0x0080;
-        if (port->port.dev)
-            uhci_attach(&port->port, port->port.dev);
+        if (port->port.dev) {
+            usb_attach(&port->port, port->port.dev);
+        }
     }
 
     uhci_async_cancel_all(s);
@@ -593,50 +592,41 @@
     }
 }
 
-static void uhci_attach(USBPort *port1, USBDevice *dev)
+static void uhci_attach(USBPort *port1)
 {
     UHCIState *s = port1->opaque;
     UHCIPort *port = &s->ports[port1->index];
 
-    if (dev) {
-        if (port->port.dev) {
-            usb_attach(port1, NULL);
-        }
-        /* set connect status */
-        port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+    /* set connect status */
+    port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
 
-        /* update speed */
-        if (dev->speed == USB_SPEED_LOW)
-            port->ctrl |= UHCI_PORT_LSDA;
-        else
-            port->ctrl &= ~UHCI_PORT_LSDA;
-
-        uhci_resume(s);
-
-        port->port.dev = dev;
-        /* send the attach message */
-        usb_send_msg(dev, USB_MSG_ATTACH);
+    /* update speed */
+    if (port->port.dev->speed == USB_SPEED_LOW) {
+        port->ctrl |= UHCI_PORT_LSDA;
     } else {
-        /* set connect status */
-        if (port->ctrl & UHCI_PORT_CCS) {
-            port->ctrl &= ~UHCI_PORT_CCS;
-            port->ctrl |= UHCI_PORT_CSC;
-        }
-        /* disable port */
-        if (port->ctrl & UHCI_PORT_EN) {
-            port->ctrl &= ~UHCI_PORT_EN;
-            port->ctrl |= UHCI_PORT_ENC;
-        }
-
-        uhci_resume(s);
-
-        dev = port->port.dev;
-        if (dev) {
-            /* send the detach message */
-            usb_send_msg(dev, USB_MSG_DETACH);
-        }
-        port->port.dev = NULL;
+        port->ctrl &= ~UHCI_PORT_LSDA;
     }
+
+    uhci_resume(s);
+}
+
+static void uhci_detach(USBPort *port1)
+{
+    UHCIState *s = port1->opaque;
+    UHCIPort *port = &s->ports[port1->index];
+
+    /* set connect status */
+    if (port->ctrl & UHCI_PORT_CCS) {
+        port->ctrl &= ~UHCI_PORT_CCS;
+        port->ctrl |= UHCI_PORT_CSC;
+    }
+    /* disable port */
+    if (port->ctrl & UHCI_PORT_EN) {
+        port->ctrl &= ~UHCI_PORT_EN;
+        port->ctrl |= UHCI_PORT_ENC;
+    }
+
+    uhci_resume(s);
 }
 
 static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
@@ -1103,6 +1093,7 @@
 
 static USBPortOps uhci_port_ops = {
     .attach = uhci_attach,
+    .detach = uhci_detach,
 };
 
 static int usb_uhci_common_initfn(UHCIState *s)