On Wed, Mar 18, 2015 at 03:04:31PM +0800, Li Jun wrote:
> On Wed, Mar 18, 2015 at 01:36:13PM +0800, Peter Chen wrote:
> > 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
> > > +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
> > 
> 
> This is known to me, I plan to enhance this in my next step, for this 
> patchset,
> which can be prevented by change of something like below:
> 
> diff --git a/drivers/usb/common/usb-otg-fsm.c 
> b/drivers/usb/common/usb-otg-fsm.c
> index 1a1b5f4..20906f6 100644
> --- a/drivers/usb/common/usb-otg-fsm.c
> +++ b/drivers/usb/common/usb-otg-fsm.c
> @@ -197,9 +197,30 @@ static void otg_hnp_polling_work(struct work_struct 
> *work)
> 
> 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,
> +       struct usb_device *udev;
> +       struct usb_otg_descriptor *desc = NULL;
> +
> +       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;
> +       }
> +
> +       if (__usb_get_extra_descriptor(udev->rawdescriptors[0],
> +               le16_to_cpu(udev->config[0].desc.wTotalLength),
> +                       USB_DT_OTG, (void **) &desc) == 0) {
> +               if (desc->bmAttributes & USB_OTG_HNP) {
> +                       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));

Currently, you can use way, when we have bcdOTG introduced, you can
change to bcdOTG, meanwhile, even for v2.0 otg driver, hnp polling
is not a must, so you may change the message level to dev_dbg for
that message.

> +               } else {
> +                       dev_info(&udev->dev, "OTG device w/o HNP capable\n");
> +               }
> +       } else {
> +               dev_info(&udev->dev, "Non-OTG device\n");
> +       }

The above two info messages are not needed.

Peter

> }
> 
> Idea is to check if the connected device is a HNP capable OTG(even 
> V2.0)device,
> maybe the better way is to use some flag which can be set while enumeration
> of OTG device(again existing bus->b_hnp_enable is not accurate for this 
> purpose),
> 
> Li Jun
> 
> > >  
> > > +
> > > + 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

-- 

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

Reply via email to