On Thu, Mar 12, 2015 at 10:30:23AM +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 <jun...@freescale.com>
> ---
>  drivers/usb/common/usb-otg-fsm.c |   93 
> ++++++++++++++++++++++++++++++++++++++
>  include/linux/usb/otg-fsm.h      |   14 ++++++
>  2 files changed, 107 insertions(+)
> 
> diff --git a/drivers/usb/common/usb-otg-fsm.c 
> b/drivers/usb/common/usb-otg-fsm.c
> index 61d538a..965b258 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,93 @@ 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(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 (host_req_flag == 0) {
> +             /* Continue HNP polling */
> +             mod_timer(&fsm->hnp_polling_timer,
> +                     jiffies + 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);

why isn't all of this...

> +}
> +
> +static void hnp_polling_timer_work(unsigned long arg)
> +{
> +     struct otg_fsm *fsm = (struct otg_fsm *)arg;
> +
> +     schedule_work(&fsm->hnp_polling_work);

here ? We would avoid a workstruct

> +}
> +
> +static void otg_start_hnp_polling(struct otg_fsm *fsm)
> +{
> +     INIT_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work);
> +     setup_timer(&fsm->hnp_polling_timer, hnp_polling_timer_work,
> +                                                     (unsigned long)fsm);
> +     mod_timer(&fsm->hnp_polling_timer,
> +                     jiffies + 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 +260,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 +295,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..2a6ee2e 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
> +                                      */

looks like this should be in ch9.h ?

-- 
balbi

Attachment: signature.asc
Description: Digital signature

Reply via email to