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(+) > > 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
signature.asc
Description: Digital signature
