diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c562613ccd1a..a1f7c2b4b000 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -371,121 +371,66 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } -static int dwc3_ep0_handle_feature(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl, int set) +static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state, + int set) { - struct dwc3_ep *dep; - u32 recip; - u32 wValue; - u32 wIndex; - u32 reg; - int ret; - enum usb_device_state state; + u32 reg; - wValue = le16_to_cpu(ctrl->wValue); - wIndex = le16_to_cpu(ctrl->wIndex); - recip = ctrl->bRequestType & USB_RECIP_MASK; - state = dwc->gadget.state; + if (state != USB_STATE_CONFIGURED) + return -EINVAL; + if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && + (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) + return -EINVAL; - switch (recip) { - case USB_RECIP_DEVICE: + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (set) + reg |= DWC3_DCTL_INITU1ENA; + else + reg &= ~DWC3_DCTL_INITU1ENA; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); - switch (wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - break; - /* - * 9.4.1 says only only for SS, in AddressState only for - * default control pipe - */ - case USB_DEVICE_U1_ENABLE: - if (state != USB_STATE_CONFIGURED) - return -EINVAL; - if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && - (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) - return -EINVAL; + return 0; +} - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - if (set) - reg |= DWC3_DCTL_INITU1ENA; - else - reg &= ~DWC3_DCTL_INITU1ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - break; +static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state, + int set) +{ + u32 reg; - case USB_DEVICE_U2_ENABLE: - if (state != USB_STATE_CONFIGURED) - return -EINVAL; - if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && - (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) - return -EINVAL; - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - if (set) - reg |= DWC3_DCTL_INITU2ENA; - else - reg &= ~DWC3_DCTL_INITU2ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - break; + if (state != USB_STATE_CONFIGURED) + return -EINVAL; + if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && + (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) + return -EINVAL; - case USB_DEVICE_LTM_ENABLE: - return -EINVAL; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (set) + reg |= DWC3_DCTL_INITU2ENA; + else + reg &= ~DWC3_DCTL_INITU2ENA; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); - case USB_DEVICE_TEST_MODE: - if ((wIndex & 0xff) != 0) - return -EINVAL; - if (!set) - return -EINVAL; + return 0; +} - switch (wIndex >> 8) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: - dwc->test_mode_nr = wIndex >> 8; - dwc->test_mode = true; - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } +static int dwc3_ep0_handle_test(struct dwc3 *dwc, enum usb_device_state state, + u32 wIndex, int set) +{ + if ((wIndex & 0xff) != 0) + return -EINVAL; + if (!set) + return -EINVAL; + + switch (wIndex >> 8) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + case TEST_FORCE_EN: + dwc->test_mode_nr = wIndex >> 8; + dwc->test_mode = true; break; - - case USB_RECIP_INTERFACE: - switch (wValue) { - case USB_INTRF_FUNC_SUSPEND: - if (wIndex & USB_INTRF_FUNC_SUSPEND_LP) - /* XXX enable Low power suspend */ - ; - if (wIndex & USB_INTRF_FUNC_SUSPEND_RW) - /* XXX enable remote wakeup */ - ; - break; - default: - return -EINVAL; - } - break; - - case USB_RECIP_ENDPOINT: - switch (wValue) { - case USB_ENDPOINT_HALT: - dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); - if (!dep) - return -EINVAL; - if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) - break; - ret = __dwc3_gadget_ep_set_halt(dep, set, true); - if (ret) - return -EINVAL; - break; - default: - return -EINVAL; - } - break; - default: return -EINVAL; } @@ -493,6 +438,132 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, return 0; } +static int dwc3_ep0_handle_device(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl, int set) +{ + enum usb_device_state state; + u32 wValue; + u32 wIndex; + int ret = 0; + + wValue = le16_to_cpu(ctrl->wValue); + wIndex = le16_to_cpu(ctrl->wIndex); + state = dwc->gadget.state; + + switch (wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + break; + /* + * 9.4.1 says only only for SS, in AddressState only for + * default control pipe + */ + case USB_DEVICE_U1_ENABLE: + ret = dwc3_ep0_handle_u1(dwc, state, set); + break; + case USB_DEVICE_U2_ENABLE: + ret = dwc3_ep0_handle_u2(dwc, state, set); + break; + case USB_DEVICE_LTM_ENABLE: + ret = -EINVAL; + break; + case USB_DEVICE_TEST_MODE: + ret = dwc3_ep0_handle_test(dwc, state, wIndex, set); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int dwc3_ep0_handle_intf(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl, int set) +{ + enum usb_device_state state; + u32 wValue; + u32 wIndex; + int ret = 0; + + wValue = le16_to_cpu(ctrl->wValue); + wIndex = le16_to_cpu(ctrl->wIndex); + state = dwc->gadget.state; + + switch (wValue) { + case USB_INTRF_FUNC_SUSPEND: + if (wIndex & USB_INTRF_FUNC_SUSPEND_LP) + /* XXX enable Low power suspend */ + ; + if (wIndex & USB_INTRF_FUNC_SUSPEND_RW) + /* XXX enable remote wakeup */ + ; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl, int set) +{ + struct dwc3_ep *dep; + enum usb_device_state state; + u32 wValue; + u32 wIndex; + int ret; + + wValue = le16_to_cpu(ctrl->wValue); + wIndex = le16_to_cpu(ctrl->wIndex); + state = dwc->gadget.state; + + switch (wValue) { + case USB_ENDPOINT_HALT: + dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); + if (!dep) + return -EINVAL; + + if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) + break; + + ret = __dwc3_gadget_ep_set_halt(dep, set, true); + if (ret) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dwc3_ep0_handle_feature(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl, int set) +{ + u32 recip; + int ret; + enum usb_device_state state; + + recip = ctrl->bRequestType & USB_RECIP_MASK; + state = dwc->gadget.state; + + switch (recip) { + case USB_RECIP_DEVICE: + ret = dwc3_ep0_handle_device(dwc, ctrl, set); + break; + case USB_RECIP_INTERFACE: + ret = dwc3_ep0_handle_intf(dwc, ctrl, set); + break; + case USB_RECIP_ENDPOINT: + ret = dwc3_ep0_handle_endpoint(dwc, ctrl, set); + break; + default: + ret = -EINVAL; + } + + return ret; +} + static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { enum usb_device_state state = dwc->gadget.state;