musb: make initial HNP roleswitch work (v2)
authorDavid Brownell <dbrownell@users.sourceforge.net>
Thu, 2 Apr 2009 17:16:11 +0000 (10:16 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 16 Jun 2009 04:44:41 +0000 (21:44 -0700)
Minor HNP bugfixes, so the initial role switch works:

 - A-Device:
     * disconnect-during-suspend enters A_PERIPHERAL state
     * kill OTG timer after reset as A_PERIPHERAL ...
     * ... and also pass that reset to the gadget
     * once HNP succeeds, clear the "ignore_disconnect" flag
     * from A_PERIPHERAL, disconnect transitions to A_WAIT_BCON

 - B-Device:
     * kill OTG timer on entry to B_HOST state (HNP succeeded)
     * once HNP succeeds, clear "ignore_disconnect" flag
     * kick the root hub only _after_ the state is adjusted

Other state transitions are left alone.  Notably, exit paths from
the "roles have switched" state ... A_PERIPHERAL handling of that
stays seriously broken.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_virthub.c

index 8bd6bb1b04effac31292954a2ae7d411ef55e671..93dd23a7eb6cc929ad083a34cd349b91bf3f11cb 100644 (file)
@@ -587,28 +587,23 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                if (devctl & MUSB_DEVCTL_LSDEV)
                        musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
 
-               if (hcd->status_urb)
-                       usb_hcd_poll_rh_status(hcd);
-               else
-                       usb_hcd_resume_root_hub(hcd);
-
-               MUSB_HST_MODE(musb);
-
                /* indicate new connection to OTG machine */
                switch (musb->xceiv->state) {
                case OTG_STATE_B_PERIPHERAL:
                        if (int_usb & MUSB_INTR_SUSPEND) {
                                DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
-                               musb->xceiv->state = OTG_STATE_B_HOST;
-                               hcd->self.is_b_host = 1;
                                int_usb &= ~MUSB_INTR_SUSPEND;
+                               goto b_host;
                        } else
                                DBG(1, "CONNECT as b_peripheral???\n");
                        break;
                case OTG_STATE_B_WAIT_ACON:
-                       DBG(1, "HNP: Waiting to switch to b_host state\n");
+                       DBG(1, "HNP: CONNECT, now b_host\n");
+b_host:
                        musb->xceiv->state = OTG_STATE_B_HOST;
                        hcd->self.is_b_host = 1;
+                       musb->ignore_disconnect = 0;
+                       del_timer(&musb->otg_timer);
                        break;
                default:
                        if ((devctl & MUSB_DEVCTL_VBUS)
@@ -618,6 +613,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        }
                        break;
                }
+
+               /* poke the root hub */
+               MUSB_HST_MODE(musb);
+               if (hcd->status_urb)
+                       usb_hcd_poll_rh_status(hcd);
+               else
+                       usb_hcd_resume_root_hub(hcd);
+
                DBG(1, "CONNECT (%s) devctl %02x\n",
                                otg_state_string(musb), devctl);
        }
@@ -662,7 +665,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                        + msecs_to_jiffies(TA_WAIT_BCON(musb)));
                                break;
                        case OTG_STATE_A_PERIPHERAL:
-                               musb_hnp_stop(musb);
+                               musb->ignore_disconnect = 0;
+                               del_timer(&musb->otg_timer);
+                               musb_g_reset(musb);
                                break;
                        case OTG_STATE_B_WAIT_ACON:
                                DBG(1, "HNP: RESET (%s), to b_peripheral\n",
index 8dfad1189da20720dcc5b70a409669e4c156fff9..3c4da75fbc7be73afb62c6a16d85afd05d91061d 100644 (file)
@@ -1964,7 +1964,7 @@ void musb_g_disconnect(struct musb *musb)
                musb->xceiv->state = OTG_STATE_A_IDLE;
                break;
        case OTG_STATE_A_PERIPHERAL:
-               musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+               musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
                break;
        case OTG_STATE_B_WAIT_ACON:
        case OTG_STATE_B_HOST:
index d7e1bc44f00ab9b8fe9f30d8c7d7842e27d59697..c85a82a41d5ccea4f759e86a71af4cd40c463758 100644 (file)
@@ -187,8 +187,17 @@ void musb_root_disconnect(struct musb *musb)
        musb->is_active = 0;
 
        switch (musb->xceiv->state) {
-       case OTG_STATE_A_HOST:
        case OTG_STATE_A_SUSPEND:
+#ifdef CONFIG_USB_MUSB_OTG
+               if (is_otg_enabled(musb)
+                               && musb->xceiv->host->b_hnp_enable) {
+                       musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
+                       musb->g.is_a_peripheral = 1;
+                       break;
+               }
+#endif
+               /* FALLTHROUGH */
+       case OTG_STATE_A_HOST:
                musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
                musb->is_active = 0;
                break;