[PATCH 96/133] [Jaunty SRU] ARM.imx51 Freescale:ENGR00112509 : [MX37] failed to test our MSC driver with USBCV 1.3.
Brad Figg
brad.figg at canonical.com
Thu Jul 9 16:49:26 UTC 2009
1. pass msc class driver test with usbcv.
2. set_bulk_out_req_length should set 512, not 31.
3. fixed the missing ACK issue.
4. remove the compile warning.
Signed-off-by: Albert Chen <r65187 at freescale.com>
Signed-off-by: Brad Figg <brad.figg at canonical.com>
---
drivers/usb/gadget/arcotg_udc.c | 218 +++++++++++++++++++++++--------------
drivers/usb/gadget/arcotg_udc.h | 3 +-
drivers/usb/gadget/file_storage.c | 2 +
3 files changed, 139 insertions(+), 84 deletions(-)
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index afd9ad2..2d3f89b 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -89,6 +89,8 @@ fsl_ep0_desc = {
};
static const size_t g_iram_size = IRAM_TD_PPH_SIZE;
+typedef int (*dev_sus)(struct device *dev, pm_message_t state);
+typedef int (*dev_res) (struct device *dev);
static int udc_suspend(struct fsl_udc *udc);
static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state);
static int fsl_udc_resume(struct platform_device *pdev);
@@ -379,9 +381,11 @@ static void dr_controller_run(struct fsl_udc *udc)
udc->stopped = 0;
/* Set controller to Run */
- temp = fsl_readl(&dr_regs->usbcmd);
- temp |= USB_CMD_RUN_STOP;
- fsl_writel(temp, &dr_regs->usbcmd);
+ if (udc->driver) {
+ temp = fsl_readl(&dr_regs->usbcmd);
+ temp |= USB_CMD_RUN_STOP;
+ fsl_writel(temp, &dr_regs->usbcmd);
+ }
return;
}
@@ -922,8 +926,8 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
int is_iso = 0;
/* catch various bogus parameters */
- if (!_req || !req->req.complete || !req->req.buf
- || !list_empty(&req->queue)) {
+ if (!_req || !req->req.buf || (ep_index(ep)
+ && !list_empty(&req->queue))) {
VDBG("%s, bad params\n", __func__);
return -EINVAL;
}
@@ -978,10 +982,6 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return -ENOMEM;
}
- /* Update ep0 state */
- if ((ep_index(ep) == 0))
- udc->ep0_state = DATA_STATE_XMIT;
-
/* irq handler advances the queue */
if (req != NULL)
list_add_tail(&req->queue, &ep->queue);
@@ -1111,7 +1111,6 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
spin_unlock_irqrestore(&ep->udc->lock, flags);
if (ep_index(ep) == 0) {
- udc->ep0_state = WAIT_FOR_SETUP;
udc->ep0_dir = 0;
}
out:
@@ -1323,7 +1322,6 @@ static void ep0stall(struct fsl_udc *udc)
tmp = fsl_readl(&dr_regs->endptctrl[0]);
tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
fsl_writel(tmp, &dr_regs->endptctrl[0]);
- udc->ep0_state = WAIT_FOR_SETUP;
udc->ep0_dir = 0;
}
@@ -1340,24 +1338,12 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
udc->ep0_dir = USB_DIR_OUT;
ep = &udc->eps[0];
- udc->ep0_state = WAIT_FOR_OUT_STATUS;
req->ep = ep;
req->req.length = 0;
req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->req.complete = NULL;
- req->dtd_count = 0;
-
- if (fsl_req_to_dtd(req) == 0)
- status = fsl_queue_td(ep, req);
- else
- return -ENOMEM;
-
- if (status)
- ERR("Can't queue ep0 status request \n");
- list_add_tail(&req->queue, &ep->queue);
+ status = fsl_ep_queue(&ep->ep, &req->req, GFP_ATOMIC);
return status;
}
@@ -1423,32 +1409,24 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
}
udc->ep0_dir = USB_DIR_IN;
- /* Borrow the per device status_req */
- req = udc->status_req;
+ /* Borrow the per device data_req */
+ /* status_req had been used to prime status */
+ req = udc->data_req;
/* Fill in the reqest structure */
*((u16 *) req->req.buf) = cpu_to_le16(tmp);
req->ep = ep;
req->req.length = 2;
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->req.complete = NULL;
- req->dtd_count = 0;
-
- /* prime the data phase */
- if ((fsl_req_to_dtd(req) == 0))
- status = fsl_queue_td(ep, req);
- else /* no mem */
- goto stall;
+ status = fsl_ep_queue(&ep->ep, &req->req, GFP_ATOMIC);
if (status) {
+ udc_reset_ep_queue(udc, 0);
ERR("Can't respond to getstatus request \n");
goto stall;
}
- list_add_tail(&req->queue, &ep->queue);
- udc->ep0_state = DATA_STATE_XMIT;
return;
stall:
ep0stall(udc);
+
}
static void setup_received_irq(struct fsl_udc *udc,
@@ -1460,6 +1438,15 @@ static void setup_received_irq(struct fsl_udc *udc,
udc_reset_ep_queue(udc, 0);
+ if (wLength) {
+ int dir;
+ dir = EP_DIR_IN;
+ if (setup->bRequestType & USB_DIR_IN) {
+ dir = EP_DIR_OUT;
+ }
+ if (ep0_prime_status(udc, dir))
+ ep0stall(udc);
+ }
/* We process some stardard setup requests here */
switch (setup->bRequest) {
case USB_REQ_GET_STATUS:
@@ -1550,11 +1537,11 @@ static void setup_received_irq(struct fsl_udc *udc,
? USB_DIR_IN : USB_DIR_OUT;
spin_unlock(&udc->lock);
if (udc->driver->setup(&udc->gadget,
- &udc->local_setup_buff) < 0)
+ &udc->local_setup_buff) < 0) {
+ /* cancel status phase */
+ udc_reset_ep_queue(udc, 0);
ep0stall(udc);
- spin_lock(&udc->lock);
- udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
- ? DATA_STATE_XMIT : DATA_STATE_RECV;
+ }
} else {
/* No data phase, IN status from gadget */
udc->ep0_dir = USB_DIR_IN;
@@ -1562,9 +1549,8 @@ static void setup_received_irq(struct fsl_udc *udc,
if (udc->driver->setup(&udc->gadget,
&udc->local_setup_buff) < 0)
ep0stall(udc);
- spin_lock(&udc->lock);
- udc->ep0_state = WAIT_FOR_OUT_STATUS;
}
+ spin_lock(&udc->lock);
}
/* Process request for Data or Status phase of ep0
@@ -1580,28 +1566,6 @@ static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,
}
done(ep0, req, 0);
-
- switch (udc->ep0_state) {
- case DATA_STATE_XMIT:
- /* receive status phase */
- if (ep0_prime_status(udc, EP_DIR_OUT))
- ep0stall(udc);
- break;
- case DATA_STATE_RECV:
- /* send status phase */
- if (ep0_prime_status(udc, EP_DIR_IN))
- ep0stall(udc);
- break;
- case WAIT_FOR_OUT_STATUS:
- udc->ep0_state = WAIT_FOR_SETUP;
- break;
- case WAIT_FOR_SETUP:
- ERR("Unexpect ep0 packets \n");
- break;
- default:
- ep0stall(udc);
- break;
- }
}
/* Tripwire mechanism to ensure a setup packet payload is extracted without
@@ -1820,7 +1784,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
/* If the ep is configured */
if (curr_ep->name == NULL) {
- WARN("Invalid EP?");
+ INFO("Invalid EP?");
continue;
}
@@ -1900,6 +1864,21 @@ static void suspend_irq(struct fsl_udc *udc)
udc->driver->suspend(&udc->gadget);
}
+#ifdef CONFIG_USB_GADGET_WAKE_UP
+/* Process Wake up interrupt */
+static void wake_up_irq(struct fsl_udc *udc)
+{
+ u32 irq_src;
+
+ pr_debug("%s\n", __func__);
+
+ /* disable wake up irq */
+ irq_src = fsl_readl(&dr_regs->usbctrl);
+ irq_src &= ~USB_CTRL_OTG_WUIE;
+ fsl_writel(irq_src, &dr_regs->usbctrl);
+}
+#endif
+
static void bus_resume(struct fsl_udc *udc)
{
udc->usb_state = udc->resume_state;
@@ -1928,7 +1907,6 @@ static int reset_queues(struct fsl_udc *udc)
static void reset_irq(struct fsl_udc *udc)
{
u32 temp;
- unsigned long timeout;
/* Clear the device address */
temp = fsl_readl(&dr_regs->deviceaddr);
@@ -1939,7 +1917,6 @@ static void reset_irq(struct fsl_udc *udc)
/* Clear usb state */
udc->resume_state = 0;
udc->ep0_dir = 0;
- udc->ep0_state = WAIT_FOR_SETUP;
udc->remote_wakeup = 0; /* default to 0 on reset */
udc->gadget.b_hnp_enable = 0;
udc->gadget.a_hnp_support = 0;
@@ -1991,6 +1968,25 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
irqreturn_t status = IRQ_NONE;
unsigned long flags;
+#ifdef CONFIG_USB_GADGET_WAKE_UP
+ spin_lock_irqsave(&udc->lock, flags);
+ /* check USBCTRL register to see if wake up irq */
+ irq_src = fsl_readl(&dr_regs->usbctrl);
+ if (irq_src & USB_CTRL_OTG_WUIR) {
+ wake_up_irq(udc);
+ irq_src = fsl_readl(&dr_regs->usbsts) &
+ fsl_readl(&dr_regs->usbintr);
+ if (irq_src)
+ udc->stopped = 0;
+ else
+ status = IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ if (status == IRQ_HANDLED)
+ return IRQ_HANDLED;
+#endif
+
/* Disable ISR for OTG host mode */
if (udc->stopped)
return IRQ_NONE;
@@ -2101,8 +2097,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
printk(KERN_INFO "Suspend udc for OTG auto detect\n");
/* export udc suspend/resume call to OTG */
- udc_controller->gadget.dev.driver->suspend = fsl_udc_suspend;
- udc_controller->gadget.dev.driver->resume = fsl_udc_resume;
+ udc_controller->gadget.dev.driver->suspend = (dev_sus)fsl_udc_suspend;
+ udc_controller->gadget.dev.driver->resume = (dev_res)fsl_udc_resume;
/* connect to bus through transceiver */
if (udc_controller->transceiver) {
@@ -2120,7 +2116,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
/* Enable DR IRQ reg and Set usbcmd reg Run bit */
dr_controller_run(udc_controller);
udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
udc_controller->ep0_dir = 0;
}
printk(KERN_INFO "%s: bind to driver %s \n",
@@ -2153,7 +2148,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
/* in fact, no needed */
udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
udc_controller->ep0_dir = 0;
/* stand operation */
@@ -2509,6 +2503,11 @@ static int __init struct_udc_setup(struct fsl_udc *udc,
/* allocate a small amount of memory to get valid address */
udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf);
+ /* Initialize ep0 data request structure */
+ udc->data_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
+ struct fsl_req, req);
+ udc->data_req->req.buf = kmalloc(8, GFP_KERNEL);
+ udc->data_req->req.dma = virt_to_phys(udc->data_req->req.buf);
udc->resume_state = USB_STATE_NOTATTACHED;
udc->usb_state = USB_STATE_POWERED;
@@ -2606,11 +2605,17 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
goto err1a;
}
#endif
- dr_regs = ioremap(res->start, resource_size(res));
- if (!dr_regs) {
- ret = -ENOMEM;
- goto err1;
+ if ((pdata->port_enables & FSL_USB2_DONT_REMAP) == 0) {
+ dr_regs = ioremap(res->start, resource_size(res));
+ if (!dr_regs) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+ udc_controller->dr_remapped = !0;
+ } else {
+ dr_regs = (void *)res->start;
+ dev_warn(&pdev->dev, "does not remap its address space\n");
}
pdata->regs = (void *)dr_regs;
/*
@@ -2739,7 +2744,8 @@ err2:
if (pdata->platform_uninit)
pdata->platform_uninit(pdata);
err2a:
- iounmap(dr_regs);
+ if (udc_controller->dr_remapped)
+ iounmap((u8 __iomem *)dr_regs);
err1:
if (!udc_controller->transceiver)
release_mem_region(res->start, resource_size(res));
@@ -2769,6 +2775,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
/* Free allocated memory */
kfree(udc_controller->status_req->req.buf);
kfree(udc_controller->status_req);
+ kfree(udc_controller->data_req->req.buf);
+ kfree(udc_controller->data_req);
kfree(udc_controller->eps);
#ifdef POSTPONE_FREE_LAST_DTD
if (last_free_td != NULL)
@@ -2777,7 +2785,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
#endif
dma_pool_destroy(udc_controller->td_pool);
free_irq(udc_controller->irq, udc_controller);
- iounmap(dr_regs);
+ if (udc_controller->dr_remapped)
+ iounmap((u8 __iomem *)dr_regs);
#ifndef CONFIG_USB_OTG
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2823,12 +2832,12 @@ static int udc_suspend(struct fsl_udc *udc)
return 0;
}
- printk(KERN_INFO "USB Gadget suspended\n");
-
/* stop the controller */
usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
fsl_writel(usbcmd, &dr_regs->usbcmd);
+ printk(KERN_INFO "USB Gadget suspended\n");
+
udc->stopped = 1;
return 0;
}
@@ -2839,6 +2848,35 @@ static int udc_suspend(struct fsl_udc *udc)
-----------------------------------------------------------------*/
static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
{
+ unsigned int port_status, temp;
+
+ if ((udc_controller->usb_state > USB_STATE_POWERED) &&
+ (udc_controller->usb_state < USB_STATE_SUSPENDED))
+ return -EBUSY;
+
+#ifdef CONFIG_USB_GADGET_WAKE_UP
+ temp = fsl_readl(&dr_regs->usbctrl);
+ /* if usb wake up irq is disabled, enable it */
+ if (!(temp & USB_CTRL_OTG_WUIE)) {
+ temp |= USB_CTRL_OTG_WUIE;
+ fsl_writel(temp, &dr_regs->usbctrl);
+ }
+#else
+ temp = fsl_readl(&dr_regs->usbctrl);
+ /* if usb wake up irq is enabled, disable it */
+ if (temp & USB_CTRL_OTG_WUIE) {
+ temp &= ~USB_CTRL_OTG_WUIE;
+ fsl_writel(temp, &dr_regs->usbctrl);
+ }
+#endif
+
+ /* close UBS PHY clock if PHCD is 0 */
+ port_status = fsl_readl(&dr_regs->portsc1);
+ if (!(port_status & PORTSCX_PHY_LOW_POWER_SPD)) {
+ port_status |= PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(port_status, &dr_regs->portsc1);
+ }
+
return udc_suspend(udc_controller);
}
@@ -2863,11 +2901,27 @@ static int fsl_udc_resume(struct platform_device *pdev)
/* Enable DR irq reg and set controller Run */
if (udc_controller->stopped) {
+ u32 temp;
+
+#ifdef CONFIG_USB_GADGET_WAKE_UP
+ /* disable wake up irq */
+ temp = fsl_readl(&dr_regs->usbctrl);
+ temp &= ~UCTRL_OWIE;
+ fsl_writel(temp, &dr_regs->usbctrl);
+#endif
+
+ /* Enable PHY clock if it's disabled */
+ temp = fsl_readl(&dr_regs->portsc1);
+ if (temp & PORTSCX_PHY_LOW_POWER_SPD) {
+ temp &= ~PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(temp, &dr_regs->portsc1);
+ mdelay(1);
+ }
+
dr_controller_setup(udc_controller);
dr_controller_run(udc_controller);
}
udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
udc_controller->ep0_dir = 0;
printk(KERN_INFO "USB Gadget resumed\n");
diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h
index 447aef8..b966f32 100644
--- a/drivers/usb/gadget/arcotg_udc.h
+++ b/drivers/usb/gadget/arcotg_udc.h
@@ -566,6 +566,7 @@ struct fsl_udc {
struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
struct fsl_req *status_req; /* ep0 status request */
+ struct fsl_req *data_req; /* ep0 data request */
struct dma_pool *td_pool; /* dma pool for DTD */
enum fsl_usb2_phy_modes phy_mode;
@@ -578,7 +579,6 @@ struct fsl_udc {
u32 resume_state; /* USB state to resume */
u32 usb_state; /* USB current state */
u32 usb_next_state; /* USB next state */
- u32 ep0_state; /* Endpoint zero state */
u32 ep0_dir; /* Endpoint zero direction: can be
USB_DIR_IN or USB_DIR_OUT */
u32 usb_sof_count; /* SOF count */
@@ -634,7 +634,6 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
#endif
#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
-#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index d77ad4a..2529b1f 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -712,8 +712,10 @@ static void set_bulk_out_req_length(struct fsg_dev *fsg,
if (rem > 0)
length += fsg->bulk_out_maxpacket - rem;
bh->outreq->length = length;
+#if 0
if (bh->bulk_out_intended_length == 31)
bh->outreq->length = 31;
+#endif
}
static struct fsg_dev *the_fsg;
--
1.6.0.4
More information about the kernel-team
mailing list