summaryrefslogtreecommitdiff
path: root/drivers/usb/musb/ux500_dma.c
diff options
context:
space:
mode:
authorBenn Pörscke <benn.porscke@stericsson.com>2011-12-16 15:04:55 +0100
committerBenn Pörscke <benn.porscke@stericsson.com>2011-12-16 15:04:55 +0100
commit93f379e6cfadfded0d262192ca69d1abc096d90e (patch)
tree43f180e31ee26ee94f7d2dd559132c30c6476b4d /drivers/usb/musb/ux500_dma.c
parent77955e37bd395f789900b8e180991ad67cabd899 (diff)
Change-Id: I2fcf46d1fc4b0cd4c61e5be3654c43b80db86015
Diffstat (limited to 'drivers/usb/musb/ux500_dma.c')
-rw-r--r--drivers/usb/musb/ux500_dma.c57
1 files changed, 48 insertions, 9 deletions
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index d6a606ef839..fc0d3a04859 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -32,6 +32,11 @@
#include <linux/pfn.h>
#include <mach/usb.h>
#include "musb_core.h"
+#undef DBG
+#undef WARNING
+#undef INFO
+#include <linux/usb/composite.h>
+#define Ux500_USB_DMA_MIN_TRANSFER_SIZE 512
struct ux500_dma_channel {
struct dma_channel channel;
@@ -258,13 +263,44 @@ static void ux500_dma_channel_release(struct dma_channel *channel)
static int ux500_dma_is_compatible(struct dma_channel *channel,
u16 maxpacket, void *buf, u32 length)
{
- if ((maxpacket & 0x3) ||
- ((int)buf & 0x3) ||
- (length < 512) ||
- (length & 0x3))
- return false;
- else
- return true;
+ struct ux500_dma_channel *ux500_channel = channel->private_data;
+ struct musb_hw_ep *hw_ep = ux500_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
+ struct usb_descriptor_header **descriptors;
+ struct usb_function *f;
+ struct usb_gadget *gadget = &musb->g;
+ struct usb_composite_dev *cdev = get_gadget_data(gadget);
+
+ if (length < Ux500_USB_DMA_MIN_TRANSFER_SIZE)
+ return 0;
+
+ list_for_each_entry(f, &cdev->config->functions, list) {
+ if (!strcmp(f->name, "cdc_ethernet") ||
+ !strcmp(f->name, "rndis") ||
+ !strcmp(f->name, "phonet") ||
+ !strcmp(f->name, "adb")) {
+ if (gadget->speed == USB_SPEED_HIGH)
+ descriptors = f->hs_descriptors;
+ else
+ descriptors = f->descriptors;
+
+ for (; *descriptors; ++descriptors) {
+ struct usb_endpoint_descriptor *ep;
+
+ if ((*descriptors)->bDescriptorType !=
+ USB_DT_ENDPOINT)
+ continue;
+
+ ep = (struct usb_endpoint_descriptor *)
+ *descriptors;
+ if (ep->bEndpointAddress ==
+ ux500_channel->hw_ep->epnum)
+ return 0;
+ }
+ }
+ }
+
+ return 1;
}
/**
@@ -282,12 +318,15 @@ static int ux500_dma_channel_program(struct dma_channel *channel,
dma_addr_t dma_addr, u32 len)
{
int ret;
+ struct ux500_dma_channel *ux500_dma_channel = channel->private_data;
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
- if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len))
- return false;
+ if (len < Ux500_USB_DMA_MIN_TRANSFER_SIZE)
+ return 0;
+ if (!ux500_dma_channel->is_tx && len < packet_sz)
+ return 0;
channel->status = MUSB_DMA_STATUS_BUSY;
channel->actual_len = 0;