From: Li Jun <b47624@xxxxxxxxxxxxx> OTG in host mode call this function to poll peripheral if it wants to be host role. Signed-off-by: Li Jun <jun.li@xxxxxxxxxxxxx> --- drivers/usb/common/usb-otg-fsm.c | 75 ++++++++++++++++++++++++++++++++++++++ include/linux/usb/otg-fsm.h | 10 +++++ 2 files changed, 85 insertions(+) diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c index 862eb04..1cd8995 100644 --- a/drivers/usb/common/usb-otg-fsm.c +++ b/drivers/usb/common/usb-otg-fsm.c @@ -367,3 +367,78 @@ int otg_statemachine(struct otg_fsm *fsm) return state_changed; } EXPORT_SYMBOL_GPL(otg_statemachine); + +/* + * Called by host to poll if peripheral wants to be host + * Return value: + * - host request flag(1) if the device wants to be host; + * - host request flag(0) if the device keeps peripheral role; + * - otherwise, error code. + */ +int otg_hnp_polling(struct otg_fsm *fsm) +{ + struct usb_device *udev; + u8 host_req_flag; + int retval; + enum usb_otg_state state = fsm->otg->state; + + if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST) + return -EINVAL; + + 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 -ENODEV; + } + + /* 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, + &host_req_flag, + 1, + USB_CTRL_GET_TIMEOUT); + if (retval != 1) { + dev_err(&udev->dev, "Get one byte OTG status failed\n"); + return -EIO; + } + + if (host_req_flag == 0) { + /* Continue HNP polling */ + otg_add_timer(fsm, HNP_POLLING); + return 0; + } else if (host_req_flag != HOST_REQUEST_FLAG) { + dev_err(&udev->dev, "host request flag is invalid\n"); + return -EINVAL; + } + + /* 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) { + dev_err(&udev->dev, + "can't enable HNP %d\n", retval); + return -EINVAL; + } + fsm->otg->host->b_hnp_enable = 1; + } + + fsm->a_bus_req = 0; + } else if (state == OTG_STATE_B_HOST) { + fsm->b_bus_req = 0; + } + + return HOST_REQUEST_FLAG; +} +EXPORT_SYMBOL_GPL(otg_hnp_polling); diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h index d1b3415..562f35b 100644 --- a/include/linux/usb/otg-fsm.h +++ b/include/linux/usb/otg-fsm.h @@ -40,6 +40,15 @@ #define PROTO_HOST (1) #define PROTO_GADGET (2) +#define OTG_STS_SELECTOR 0xF000 /* OTG status selector, according to + * OTG and EH 2.0 Charpter 6.2.3 + * Table:6-4 + */ +#define HOST_REQUEST_FLAG 1 /* Host request flag, according to + * OTG and EH 2.0 Charpter 6.2.3 + * Table:6-5 + */ + enum otg_fsm_timer { /* Standard OTG timers */ A_WAIT_VRISE, @@ -243,5 +252,6 @@ static inline int otg_start_gadget(struct otg_fsm *fsm, int on) } int otg_statemachine(struct otg_fsm *fsm); +int otg_hnp_polling(struct otg_fsm *fsm); #endif /* __LINUX_USB_OTG_FSM_H */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html