#ifdef VERBOSE #define VDBG(fmt, args...) pr_debug("[%s] " fmt, \
__func__, ## args) #else #define VDBG(stuff...) do {} while (0) #endif
/* Change USB protocol when there is a protocol change */ staticint otg_set_protocol(struct otg_fsm *fsm, int protocol)
{ int ret = 0;
if (fsm->protocol != protocol) {
VDBG("Changing role fsm->protocol= %d; new protocol= %d\n",
fsm->protocol, protocol); /* stop old protocol */ if (fsm->protocol == PROTO_HOST)
ret = otg_start_host(fsm, 0); elseif (fsm->protocol == PROTO_GADGET)
ret = otg_start_gadget(fsm, 0); if (ret) return ret;
/* start new protocol */ if (protocol == PROTO_HOST)
ret = otg_start_host(fsm, 1); elseif (protocol == PROTO_GADGET)
ret = otg_start_gadget(fsm, 1); if (ret) return ret;
fsm->protocol = protocol; return 0;
}
return 0;
}
/* Called when leaving a state. Do state clean up jobs here */ staticvoid otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
{ switch (old_state) { case OTG_STATE_B_IDLE:
otg_del_timer(fsm, B_SE0_SRP);
fsm->b_se0_srp = 0;
fsm->adp_sns = 0;
fsm->adp_prb = 0; break; case OTG_STATE_B_SRP_INIT:
fsm->data_pulse = 0;
fsm->b_srp_done = 0; break; case OTG_STATE_B_PERIPHERAL: if (fsm->otg->gadget)
fsm->otg->gadget->host_request_flag = 0; break; case OTG_STATE_B_WAIT_ACON:
otg_del_timer(fsm, B_ASE0_BRST);
fsm->b_ase0_brst_tmout = 0; break; case OTG_STATE_B_HOST: break; case OTG_STATE_A_IDLE:
fsm->adp_prb = 0; break; case OTG_STATE_A_WAIT_VRISE:
otg_del_timer(fsm, A_WAIT_VRISE);
fsm->a_wait_vrise_tmout = 0; break; case OTG_STATE_A_WAIT_BCON:
otg_del_timer(fsm, A_WAIT_BCON);
fsm->a_wait_bcon_tmout = 0; break; case OTG_STATE_A_HOST:
otg_del_timer(fsm, A_WAIT_ENUM); break; case OTG_STATE_A_SUSPEND:
otg_del_timer(fsm, A_AIDL_BDIS);
fsm->a_aidl_bdis_tmout = 0;
fsm->a_suspend_req_inf = 0; break; case OTG_STATE_A_PERIPHERAL:
otg_del_timer(fsm, A_BIDL_ADIS);
fsm->a_bidl_adis_tmout = 0; if (fsm->otg->gadget)
fsm->otg->gadget->host_request_flag = 0; break; case OTG_STATE_A_WAIT_VFALL:
otg_del_timer(fsm, A_WAIT_VFALL);
fsm->a_wait_vfall_tmout = 0;
otg_del_timer(fsm, A_WAIT_VRISE); break; case OTG_STATE_A_VBUS_ERR: break; default: break;
}
}
if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST) return;
udev = usb_hub_find_child(fsm->otg->host->root_hub, 1); if (!udev) {
dev_err(fsm->otg->host->controller, "no usb dev connected, can't start HNP polling\n"); return;
}
*fsm->host_req_flag = 0; /* Get host request flag from connected USB device */
retval = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
USB_REQ_GET_STATUS,
USB_DIR_IN | USB_RECIP_DEVICE,
0,
OTG_STS_SELECTOR,
fsm->host_req_flag,
1,
USB_CTRL_GET_TIMEOUT); if (retval != 1) {
dev_err(&udev->dev, "Get one byte OTG status failed\n"); return;
}
flag = *fsm->host_req_flag; if (flag == 0) { /* Continue HNP polling */
schedule_delayed_work(&fsm->hnp_polling_work,
msecs_to_jiffies(T_HOST_REQ_POLL)); return;
} elseif (flag != HOST_REQUEST_FLAG) {
dev_err(&udev->dev, "host request flag %d is invalid\n", flag); return;
}
/* Host request flag is set */ if (state == OTG_STATE_A_HOST) { /* Set b_hnp_enable */ if (!fsm->otg->host->b_hnp_enable) {
retval = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE, 0,
USB_DEVICE_B_HNP_ENABLE,
0, NULL, 0,
USB_CTRL_SET_TIMEOUT); if (retval >= 0)
fsm->otg->host->b_hnp_enable = 1;
}
fsm->a_bus_req = 0;
} elseif (state == OTG_STATE_B_HOST) {
fsm->b_bus_req = 0;
}
otg_statemachine(fsm);
}
staticvoid otg_start_hnp_polling(struct otg_fsm *fsm)
{ /* * The memory of host_req_flag should be allocated by * controller driver, otherwise, hnp polling is not started.
*/ if (!fsm->host_req_flag) return;
if (!fsm->hnp_work_inited) {
INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work);
fsm->hnp_work_inited = true;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.