On Thu, Mar 12, 2015 at 11:06:28AM -0500, Felipe Balbi wrote:
> 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 <[email protected]>
> > ---
> >  drivers/usb/common/usb-otg-fsm.c |   93 
> > ++++++++++++++++++++++++++++++++++++++
> >  include/linux/usb/otg-fsm.h      |   14 ++++++
> >  2 files changed, 107 insertions(+)
> > 
> > +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...
> 

In all cases go to otg_statemachine(fsm) and then return? If the host request
is not set, there should be no any state transitions for HNP polling.

Li Jun
> > +}
> > +
> > +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
> 

I will use schedule_delayed_work to avoid a workstruct for timer.

Li Jun
> > +}
> > +
> > +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 ?
> 

ok, I will move OTG_STS_SELECTOR to ch9.h

Li Jun
> -- 
> balbi


--
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