Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1de00dae authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman
Browse files

musb: make initial HNP roleswitch work (v2)



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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent f7f9d63e
Loading
Loading
Loading
Loading
+16 −11
Original line number Original line Diff line number Diff line
@@ -587,28 +587,23 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
		if (devctl & MUSB_DEVCTL_LSDEV)
		if (devctl & MUSB_DEVCTL_LSDEV)
			musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
			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 */
		/* indicate new connection to OTG machine */
		switch (musb->xceiv->state) {
		switch (musb->xceiv->state) {
		case OTG_STATE_B_PERIPHERAL:
		case OTG_STATE_B_PERIPHERAL:
			if (int_usb & MUSB_INTR_SUSPEND) {
			if (int_usb & MUSB_INTR_SUSPEND) {
				DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
				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;
				int_usb &= ~MUSB_INTR_SUSPEND;
				goto b_host;
			} else
			} else
				DBG(1, "CONNECT as b_peripheral???\n");
				DBG(1, "CONNECT as b_peripheral???\n");
			break;
			break;
		case OTG_STATE_B_WAIT_ACON:
		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;
			musb->xceiv->state = OTG_STATE_B_HOST;
			hcd->self.is_b_host = 1;
			hcd->self.is_b_host = 1;
			musb->ignore_disconnect = 0;
			del_timer(&musb->otg_timer);
			break;
			break;
		default:
		default:
			if ((devctl & MUSB_DEVCTL_VBUS)
			if ((devctl & MUSB_DEVCTL_VBUS)
@@ -618,6 +613,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
			}
			}
			break;
			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",
		DBG(1, "CONNECT (%s) devctl %02x\n",
				otg_state_string(musb), devctl);
				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)));
					+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
				break;
				break;
			case OTG_STATE_A_PERIPHERAL:
			case OTG_STATE_A_PERIPHERAL:
				musb_hnp_stop(musb);
				musb->ignore_disconnect = 0;
				del_timer(&musb->otg_timer);
				musb_g_reset(musb);
				break;
				break;
			case OTG_STATE_B_WAIT_ACON:
			case OTG_STATE_B_WAIT_ACON:
				DBG(1, "HNP: RESET (%s), to b_peripheral\n",
				DBG(1, "HNP: RESET (%s), to b_peripheral\n",
+1 −1
Original line number Original line Diff line number Diff line
@@ -1964,7 +1964,7 @@ void musb_g_disconnect(struct musb *musb)
		musb->xceiv->state = OTG_STATE_A_IDLE;
		musb->xceiv->state = OTG_STATE_A_IDLE;
		break;
		break;
	case OTG_STATE_A_PERIPHERAL:
	case OTG_STATE_A_PERIPHERAL:
		musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
		musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
		break;
		break;
	case OTG_STATE_B_WAIT_ACON:
	case OTG_STATE_B_WAIT_ACON:
	case OTG_STATE_B_HOST:
	case OTG_STATE_B_HOST:
+10 −1
Original line number Original line Diff line number Diff line
@@ -187,8 +187,17 @@ void musb_root_disconnect(struct musb *musb)
	musb->is_active = 0;
	musb->is_active = 0;


	switch (musb->xceiv->state) {
	switch (musb->xceiv->state) {
	case OTG_STATE_A_HOST:
	case OTG_STATE_A_SUSPEND:
	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->xceiv->state = OTG_STATE_A_WAIT_BCON;
		musb->is_active = 0;
		musb->is_active = 0;
		break;
		break;