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 <jun.li@xxxxxxxxxxxxx> > > > --- > > > 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html