/* State change judgement */ int otg_statemachine(struct otg_fsm *fsm) { enum usb_otg_state state; unsigned long flags; spin_lock_irqsave(&fsm->lock, flags); state = fsm->transceiver->state; state_changed = 0; /* State machine state change judgement */ VDBG("top: curr state=%s", state_string(state)); switch (state) { case OTG_STATE_UNDEFINED: VDBG("fsm->id = %d", fsm->id); if (fsm->id) otg_set_state(fsm, OTG_STATE_B_IDLE); else otg_set_state(fsm, OTG_STATE_A_IDLE); break; case OTG_STATE_B_IDLE: VDBG("gadget: %p", fsm->transceiver->gadget); if (!fsm->id) otg_set_state(fsm, OTG_STATE_A_IDLE); else if (fsm->b_sess_vld && fsm->transceiver->gadget) otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp) otg_set_state(fsm, OTG_STATE_B_SRP_INIT); break; case OTG_STATE_B_SRP_INIT: if (!fsm->id || fsm->b_srp_done) otg_set_state(fsm, OTG_STATE_B_IDLE); break; case OTG_STATE_B_PERIPHERAL: if (!fsm->id || !fsm->b_sess_vld) otg_set_state(fsm, OTG_STATE_B_IDLE); else if (fsm->b_bus_req && fsm->transceiver->gadget->b_hnp_enable && fsm->a_bus_suspend) otg_set_state(fsm, OTG_STATE_B_WAIT_ACON); break; case OTG_STATE_B_WAIT_ACON: if (fsm->a_conn) otg_set_state(fsm, OTG_STATE_B_HOST); else if (!fsm->id || !fsm->b_sess_vld) otg_set_state(fsm, OTG_STATE_B_IDLE); else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) { fsm->b_ase0_brst_tmout = 0; otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); } break; case OTG_STATE_B_HOST: if (!fsm->id || !fsm->b_sess_vld) otg_set_state(fsm, OTG_STATE_B_IDLE); else if (!fsm->b_bus_req || !fsm->a_conn) otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); break; case OTG_STATE_A_IDLE: if (fsm->id) otg_set_state(fsm, OTG_STATE_B_IDLE); else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det)) otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE); break; case OTG_STATE_A_WAIT_VRISE: if (fsm->id || fsm->a_bus_drop || fsm->a_vbus_vld || fsm->a_wait_vrise_tmout) { otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); } break; case OTG_STATE_A_WAIT_BCON: if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); else if (fsm->b_conn) otg_set_state(fsm, OTG_STATE_A_HOST); else if (fsm->id | fsm->a_bus_drop | fsm->a_wait_bcon_tmout) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); break; case OTG_STATE_A_HOST: if ((!fsm->a_bus_req || fsm->a_suspend_req) && fsm->transceiver->host->b_hnp_enable) otg_set_state(fsm, OTG_STATE_A_SUSPEND); else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop) otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); else if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); break; case OTG_STATE_A_SUSPEND: if (!fsm->b_conn && fsm->transceiver->host->b_hnp_enable) otg_set_state(fsm, OTG_STATE_A_PERIPHERAL); else if (!fsm->b_conn && !fsm->transceiver->host->b_hnp_enable) otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); else if (fsm->a_bus_req || fsm->b_bus_resume) otg_set_state(fsm, OTG_STATE_A_HOST); else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); else if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); break; case OTG_STATE_A_PERIPHERAL: if (fsm->id || fsm->a_bus_drop) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); else if (fsm->b_bus_suspend) otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); else if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); break; case OTG_STATE_A_WAIT_VFALL: if (fsm->id || fsm->a_bus_req || (!fsm->a_sess_vld && !fsm->b_conn)) otg_set_state(fsm, OTG_STATE_A_IDLE); break; case OTG_STATE_A_VBUS_ERR: if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); break; default: break; } spin_unlock_irqrestore(&fsm->lock, flags); return state_changed; }
/* State change judgement */ int otg_statemachine(struct otg_fsm *fsm) { enum usb_otg_state state; mutex_lock(&fsm->lock); state = fsm->otg->phy->state; state_changed = 0; /* State machine state change judgement */ switch (state) { case OTG_STATE_UNDEFINED: VDBG("fsm->id = %d\n", fsm->id); if (fsm->id) otg_set_state(fsm, OTG_STATE_B_IDLE); else otg_set_state(fsm, OTG_STATE_A_IDLE); break; case OTG_STATE_B_IDLE: if (!fsm->id) otg_set_state(fsm, OTG_STATE_A_IDLE); else if (fsm->b_sess_vld && fsm->otg->gadget) otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) && fsm->b_ssend_srp && fsm->b_se0_srp) otg_set_state(fsm, OTG_STATE_B_SRP_INIT); break; case OTG_STATE_B_SRP_INIT: if (!fsm->id || fsm->b_srp_done) otg_set_state(fsm, OTG_STATE_B_IDLE); break; case OTG_STATE_B_PERIPHERAL: if (!fsm->id || !fsm->b_sess_vld) otg_set_state(fsm, OTG_STATE_B_IDLE); else if (fsm->b_bus_req && fsm->otg-> gadget->b_hnp_enable && fsm->a_bus_suspend) otg_set_state(fsm, OTG_STATE_B_WAIT_ACON); break; case OTG_STATE_B_WAIT_ACON: if (fsm->a_conn) otg_set_state(fsm, OTG_STATE_B_HOST); else if (!fsm->id || !fsm->b_sess_vld) otg_set_state(fsm, OTG_STATE_B_IDLE); else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) { fsm->b_ase0_brst_tmout = 0; otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); } break; case OTG_STATE_B_HOST: if (!fsm->id || !fsm->b_sess_vld) otg_set_state(fsm, OTG_STATE_B_IDLE); else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device) otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); break; case OTG_STATE_A_IDLE: if (fsm->id) otg_set_state(fsm, OTG_STATE_B_IDLE); else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det || fsm->adp_change || fsm->power_up)) otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE); break; case OTG_STATE_A_WAIT_VRISE: if (fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_vrise_tmout) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); break; case OTG_STATE_A_WAIT_BCON: if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); else if (fsm->b_conn) otg_set_state(fsm, OTG_STATE_A_HOST); else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_bcon_tmout) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); break; case OTG_STATE_A_HOST: if (fsm->id || fsm->a_bus_drop) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) && fsm->otg->host->b_hnp_enable) otg_set_state(fsm, OTG_STATE_A_SUSPEND); else if (!fsm->b_conn) otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); else if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); break; case OTG_STATE_A_SUSPEND: if (!fsm->b_conn && fsm->otg->host->b_hnp_enable) otg_set_state(fsm, OTG_STATE_A_PERIPHERAL); else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable) otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); else if (fsm->a_bus_req || fsm->b_bus_resume) otg_set_state(fsm, OTG_STATE_A_HOST); else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); else if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); break; case OTG_STATE_A_PERIPHERAL: if (fsm->id || fsm->a_bus_drop) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend) otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); else if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); break; case OTG_STATE_A_WAIT_VFALL: if (fsm->a_wait_vfall_tmout) otg_set_state(fsm, OTG_STATE_A_IDLE); break; case OTG_STATE_A_VBUS_ERR: if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); break; default: break; } mutex_unlock(&fsm->lock); VDBG("quit statemachine, changed = %d\n", state_changed); return state_changed; }