diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-05 15:15:38 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-05 15:15:38 -0700 |
commit | 933141509cefd64102a943d61d154c5c53bad889 (patch) | |
tree | d36112785cb0742ab3b6d6c91cfd4777978b3220 /drivers/usb/dwc3/ep0.c | |
parent | 94ff447cf275170042a7a05b972b6da8b94754ca (diff) | |
parent | 6f17f74b3d8345663f5fcfd834145685110075bd (diff) |
Merge tag 'dwc3-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
usb: dwc3: patches for v3.6 merge window
lots of changes for the dwc3 driver which will make
the driver a lot more stable and some changes which
are just cosmetic.
The bulk of changes is related to mis-defined macros
which were never used before, some fixes to error path
which e.g. prevent the driver from initiating two
transfer on ep0out in case of stall, some fixes to
request dequeueing and the End Transfer Command.
We have some changes to U1/U2 handling where we were
enabling those transtions at the wrong spot (though
we haven't seen a problem from that as of today).
A few patches will make it easier to add support for
newer releases of the core by adding definitions for
new registers and changing the code to act accordingly
when certain revisions are detected.
There's also the usual comestic changes to make the
driver easier to maintain and make it easier for new-
comers to understand the driver. Also one patch fixing
a double inclusion of a header.
Diffstat (limited to 'drivers/usb/dwc3/ep0.c')
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 146 |
1 files changed, 92 insertions, 54 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9e8a3dce69fd..9b94886b66e5 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -54,7 +54,9 @@ #include "gadget.h" #include "io.h" -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum); +static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); +static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, + struct dwc3_ep *dep, struct dwc3_request *req); static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) { @@ -111,7 +113,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, } dep->flags |= DWC3_EP_BUSY; - dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, + dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, dep->number); dwc->ep0_next_event = DWC3_EP0_COMPLETE; @@ -150,16 +152,15 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, return 0; } - ret = dwc3_ep0_start_trans(dwc, direction, - req->request.dma, req->request.length, - DWC3_TRBCTL_CONTROL_DATA); + __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req); + dep->flags &= ~(DWC3_EP_PENDING_REQUEST | DWC3_EP0_DIR_IN); } else if (dwc->delayed_status) { dwc->delayed_status = false; if (dwc->ep0state == EP0_STATUS_PHASE) - dwc3_ep0_do_control_status(dwc, 1); + __dwc3_ep0_do_control_status(dwc, dwc->eps[1]); else dev_dbg(dwc->dev, "too early for delayed status\n"); } @@ -224,6 +225,16 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) dwc3_ep0_out_start(dwc); } +int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) +{ + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; + + dwc3_ep0_stall_and_restart(dwc); + + return 0; +} + void dwc3_ep0_out_start(struct dwc3 *dwc) { int ret; @@ -463,6 +474,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { u32 cfg; int ret; + u32 reg; dwc->start_config_issued = false; cfg = le16_to_cpu(ctrl->wValue); @@ -477,6 +489,14 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { dwc->dev_state = DWC3_CONFIGURED_STATE; + /* + * Enable transition to U1/U2 state when + * nothing is pending from application. + */ + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc->resize_fifos = true; dev_dbg(dwc->dev, "resize fifos flag SET\n"); } @@ -514,8 +534,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) dwc->u1sel = timing.u1sel; dwc->u1pel = timing.u1pel; - dwc->u2sel = timing.u2sel; - dwc->u2pel = timing.u2pel; + dwc->u2sel = le16_to_cpu(timing.u2sel); + dwc->u2pel = le16_to_cpu(timing.u2pel); reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (reg & DWC3_DCTL_INITU2ENA) @@ -640,11 +660,11 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { struct usb_ctrlrequest *ctrl = dwc->ctrl_req; - int ret; + int ret = -EINVAL; u32 len; if (!dwc->gadget_driver) - goto err; + goto out; len = le16_to_cpu(ctrl->wLength); if (!len) { @@ -665,11 +685,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, if (ret == USB_GADGET_DELAYED_STATUS) dwc->delayed_status = true; - if (ret >= 0) - return; - -err: - dwc3_ep0_stall_and_restart(dwc); +out: + if (ret < 0) + dwc3_ep0_stall_and_restart(dwc); } static void dwc3_ep0_complete_data(struct dwc3 *dwc, @@ -723,7 +741,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, } } -static void dwc3_ep0_complete_req(struct dwc3 *dwc, +static void dwc3_ep0_complete_status(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { struct dwc3_request *r; @@ -745,6 +763,7 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc, dev_dbg(dwc->dev, "Invalid Test #%d\n", dwc->test_mode_nr); dwc3_ep0_stall_and_restart(dwc); + return; } } @@ -758,7 +777,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; dep->flags &= ~DWC3_EP_BUSY; - dep->res_trans_idx = 0; + dep->resource_index = 0; dwc->setup_packet_pending = false; switch (dwc->ep0state) { @@ -774,7 +793,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, case EP0_STATUS_PHASE: dev_vdbg(dwc->dev, "Status Phase\n"); - dwc3_ep0_complete_req(dwc, event); + dwc3_ep0_complete_status(dwc, event); break; default: WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state); @@ -787,68 +806,81 @@ static void dwc3_ep0_do_control_setup(struct dwc3 *dwc, dwc3_ep0_out_start(dwc); } -static void dwc3_ep0_do_control_data(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) +static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, + struct dwc3_ep *dep, struct dwc3_request *req) { - struct dwc3_ep *dep; - struct dwc3_request *req; int ret; - dep = dwc->eps[0]; - - if (list_empty(&dep->request_list)) { - dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); - dep->flags |= DWC3_EP_PENDING_REQUEST; - - if (event->endpoint_number) - dep->flags |= DWC3_EP0_DIR_IN; - return; - } - - req = next_request(&dep->request_list); - req->direction = !!event->endpoint_number; + req->direction = !!dep->number; if (req->request.length == 0) { - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, + ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ctrl_req_addr, 0, DWC3_TRBCTL_CONTROL_DATA); - } else if ((req->request.length % dep->endpoint.maxpacket) - && (event->endpoint_number == 0)) { + } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) + && (dep->number == 0)) { + u32 transfer_size; + ret = usb_gadget_map_request(&dwc->gadget, &req->request, - event->endpoint_number); + dep->number); if (ret) { dev_dbg(dwc->dev, "failed to map request\n"); return; } - WARN_ON(req->request.length > dep->endpoint.maxpacket); + WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE); + + transfer_size = roundup(req->request.length, + (u32) dep->endpoint.maxpacket); dwc->ep0_bounced = true; /* - * REVISIT in case request length is bigger than EP0 - * wMaxPacketSize, we will need two chained TRBs to handle - * the transfer. + * REVISIT in case request length is bigger than + * DWC3_EP0_BOUNCE_SIZE we will need two chained + * TRBs to handle the transfer. */ - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, - dwc->ep0_bounce_addr, dep->endpoint.maxpacket, + ret = dwc3_ep0_start_trans(dwc, dep->number, + dwc->ep0_bounce_addr, transfer_size, DWC3_TRBCTL_CONTROL_DATA); } else { ret = usb_gadget_map_request(&dwc->gadget, &req->request, - event->endpoint_number); + dep->number); if (ret) { dev_dbg(dwc->dev, "failed to map request\n"); return; } - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, - req->request.dma, req->request.length, - DWC3_TRBCTL_CONTROL_DATA); + ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma, + req->request.length, DWC3_TRBCTL_CONTROL_DATA); } WARN_ON(ret < 0); } +static void dwc3_ep0_do_control_data(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) +{ + struct dwc3_ep *dep; + struct dwc3_request *req; + + dep = dwc->eps[0]; + + if (list_empty(&dep->request_list)) { + dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); + dep->flags |= DWC3_EP_PENDING_REQUEST; + + if (event->endpoint_number) + dep->flags |= DWC3_EP0_DIR_IN; + return; + } + + req = next_request(&dep->request_list); + dep = dwc->eps[event->endpoint_number]; + + __dwc3_ep0_do_control_data(dwc, dep, req); +} + static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; @@ -861,10 +893,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) dwc->ctrl_req_addr, 0, type); } -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum) +static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) { - struct dwc3_ep *dep = dwc->eps[epnum]; - if (dwc->resize_fifos) { dev_dbg(dwc->dev, "starting to resize fifos\n"); dwc3_gadget_resize_tx_fifos(dwc); @@ -874,13 +904,21 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum) WARN_ON(dwc3_ep0_start_control_status(dep)); } +static void dwc3_ep0_do_control_status(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) +{ + struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; + + __dwc3_ep0_do_control_status(dwc, dep); +} + static void dwc3_ep0_xfernotready(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { dwc->setup_packet_pending = true; /* - * This part is very tricky: If we has just handled + * This part is very tricky: If we have just handled * XferNotReady(Setup) and we're now expecting a * XferComplete but, instead, we receive another * XferNotReady(Setup), we should STALL and restart @@ -974,7 +1012,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, return; } - dwc3_ep0_do_control_status(dwc, event->endpoint_number); + dwc3_ep0_do_control_status(dwc, event); } } |