On Tue, Mar 17, 2015 at 10:37:47PM +0800, Li Jun wrote:
> Adds HNP polling timer when transits to host state, the OTG status request
> will be sent to peripheral after timeout, if host request flag is set, it will
> switch to peripheral state, otherwise it will repeat HNP polling every 1.5s
> and
> maintain the current session.
>
> Signed-off-by: Li Jun <[email protected]>
> ---
> drivers/usb/common/usb-otg-fsm.c | 84
> ++++++++++++++++++++++++++++++++++++++
> include/linux/usb/otg-fsm.h | 13 ++++++
> 2 files changed, 97 insertions(+)
>
> diff --git a/drivers/usb/common/usb-otg-fsm.c
> b/drivers/usb/common/usb-otg-fsm.c
> index 61d538a..1a1b5f4 100644
> --- a/drivers/usb/common/usb-otg-fsm.c
> +++ b/drivers/usb/common/usb-otg-fsm.c
> @@ -78,6 +78,8 @@ static void otg_leave_state(struct otg_fsm *fsm, enum
> usb_otg_state old_state)
> 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);
> @@ -107,6 +109,8 @@ static void otg_leave_state(struct otg_fsm *fsm, enum
> usb_otg_state old_state)
> 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);
> @@ -120,6 +124,84 @@ static void otg_leave_state(struct otg_fsm *fsm, enum
> usb_otg_state old_state)
> }
> }
>
> +static void otg_hnp_polling_work(struct work_struct *work)
> +{
> + struct otg_fsm *fsm = container_of(to_delayed_work(work),
> + struct otg_fsm, hnp_polling_work);
> + struct usb_device *udev;
> + u8 host_req_flag;
> + enum usb_otg_state state = fsm->otg->state;
> + int retval;
> +
> + 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;
> + }
> +
> + /* 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;
> + }
If I plug usb thumb device, it will print above message, any ways to
hide it for non hnp-polling featured device?
Others are ok
Peter
> +
> + if (host_req_flag == 0) {
> + /* Continue HNP polling */
> + schedule_delayed_work(&fsm->hnp_polling_work,
> + msecs_to_jiffies(T_HOST_REQ_POLL));
> + return;
> + } else if (host_req_flag != HOST_REQUEST_FLAG) {
> + dev_err(&udev->dev, "host request flag %d is invalid\n",
> + host_req_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) {
> + dev_err(&udev->dev,
> + "can't enable HNP %d\n", retval);
> + return;
> + }
> + fsm->otg->host->b_hnp_enable = 1;
> + }
> +
> + fsm->a_bus_req = 0;
> + } else if (state == OTG_STATE_B_HOST) {
> + fsm->b_bus_req = 0;
> + }
> +
> + otg_statemachine(fsm);
> +}
> +
> +static void otg_start_hnp_polling(struct otg_fsm *fsm)
> +{
> + INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work);
> + schedule_delayed_work(&fsm->hnp_polling_work,
> + msecs_to_jiffies(T_HOST_REQ_POLL));
> +}
> +
> /* Called when entering a state */
> static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
> {
> @@ -169,6 +251,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum
> usb_otg_state new_state)
> otg_set_protocol(fsm, PROTO_HOST);
> usb_bus_start_enum(fsm->otg->host,
> fsm->otg->host->otg_port);
> + otg_start_hnp_polling(fsm);
> break;
> case OTG_STATE_A_IDLE:
> otg_drv_vbus(fsm, 0);
> @@ -203,6 +286,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum
> usb_otg_state new_state)
> */
> if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
> otg_add_timer(fsm, A_WAIT_ENUM);
> + otg_start_hnp_polling(fsm);
> break;
> case OTG_STATE_A_SUSPEND:
> otg_drv_vbus(fsm, 1);
> diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
> index f728f18..2bea252 100644
> --- a/include/linux/usb/otg-fsm.h
> +++ b/include/linux/usb/otg-fsm.h
> @@ -40,6 +40,18 @@
> #define PROTO_HOST (1)
> #define PROTO_GADGET (2)
>
> +#define OTG_STS_SELECTOR 0xF000 /* OTG status selector,
> according to
> + * OTG and EH 2.0 Chapter 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
> + */
> +
> +#define T_HOST_REQ_POLL (1500) /* 1500ms, HNP polling interval
> */
> +
> enum otg_fsm_timer {
> /* Standard OTG timers */
> A_WAIT_VRISE,
> @@ -119,6 +131,7 @@ struct otg_fsm {
> /* Current usb protocol used: 0:undefine; 1:host; 2:client */
> int protocol;
> struct mutex lock;
> + struct delayed_work hnp_polling_work;
> };
>
> struct otg_fsm_ops {
> --
> 1.7.9.5
>
--
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html