diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/tegra_udc.c | 34 | ||||
-rw-r--r-- | drivers/usb/gadget/tegra_udc.h | 4 |
2 files changed, 32 insertions, 6 deletions
diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c index 47e2e97984a4..db5b72856e8e 100644 --- a/drivers/usb/gadget/tegra_udc.c +++ b/drivers/usb/gadget/tegra_udc.c @@ -129,8 +129,9 @@ static void done(struct tegra_ep *ep, struct tegra_req *req, int status) { struct tegra_udc *udc = NULL; unsigned char stopped = ep->stopped; - struct ep_td_struct *curr_td, *next_td; + struct ep_td_struct *curr_td, *next_td = 0; int j; + int count; BUG_ON(!(in_irq() || irqs_disabled())); udc = (struct tegra_udc *)ep->udc; /* Removed the req from tegra_ep->queue */ @@ -143,12 +144,19 @@ static void done(struct tegra_ep *ep, struct tegra_req *req, int status) status = req->req.status; /* Free dtd for the request */ - next_td = req->head; - for (j = 0; j < req->dtd_count; j++) { + count = 0; + if (ep->last_td) { + next_td = ep->last_td; + count = ep->last_dtd_count; + } + ep->last_td = req->head; + ep->last_dtd_count = req->dtd_count; + + for (j = 0; j < count; j++) { curr_td = next_td; - if (j != req->dtd_count - 1) + if (j != count - 1) { next_td = curr_td->next_td_virt; - + } dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); } @@ -568,6 +576,8 @@ static int tegra_ep_enable(struct usb_ep *_ep, ep->ep.maxpacket = max; ep->desc = desc; ep->stopped = 0; + ep->last_td = 0; + ep->last_dtd_count = 0; /* Controller related setup * Init EPx Queue Head (Ep Capabilites field in QH @@ -610,6 +620,8 @@ static int tegra_ep_disable(struct usb_ep *_ep) unsigned long flags = 0; u32 epctrl; int ep_num; + struct ep_td_struct *curr_td, *next_td; + int j; ep = container_of(_ep, struct tegra_ep, ep); if (!_ep || !ep->desc) { @@ -638,6 +650,18 @@ static int tegra_ep_disable(struct usb_ep *_ep) ep->desc = NULL; ep->stopped = 1; + if (ep->last_td) { + next_td = ep->last_td; + for (j = 0; j < ep->last_dtd_count; j++) { + curr_td = next_td; + dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); + if (j != ep->last_dtd_count - 1) { + next_td = curr_td->next_td_virt; + } + } + } + ep->last_td =0; + ep->last_dtd_count = 0; spin_unlock_irqrestore(&udc->lock, flags); VDBG("disabled %s OK", _ep->name); diff --git a/drivers/usb/gadget/tegra_udc.h b/drivers/usb/gadget/tegra_udc.h index e94543fd98e3..50e2a3193648 100644 --- a/drivers/usb/gadget/tegra_udc.h +++ b/drivers/usb/gadget/tegra_udc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 NVIDIA Corporation + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * Description: * High-speed USB device controller driver. @@ -390,6 +390,8 @@ struct tegra_ep { struct ep_queue_head *qh; const struct usb_endpoint_descriptor *desc; struct usb_gadget *gadget; + struct ep_td_struct *last_td; + int last_dtd_count; char name[14]; unsigned stopped:1; |