aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/Kconfig74
-rw-r--r--drivers/usb/gadget/Makefile7
-rw-r--r--drivers/usb/gadget/amd5536udc.c3454
-rw-r--r--drivers/usb/gadget/amd5536udc.h626
-rw-r--r--drivers/usb/gadget/at91_udc.c21
-rw-r--r--drivers/usb/gadget/dummy_hcd.c39
-rw-r--r--drivers/usb/gadget/ether.c12
-rw-r--r--drivers/usb/gadget/file_storage.c37
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c99
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h4
-rw-r--r--drivers/usb/gadget/gadget_chips.h35
-rw-r--r--drivers/usb/gadget/gmidi.c8
-rw-r--r--drivers/usb/gadget/goku_udc.c87
-rw-r--r--drivers/usb/gadget/goku_udc.h10
-rw-r--r--drivers/usb/gadget/inode.c8
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.c27
-rw-r--r--drivers/usb/gadget/m66592-udc.c1633
-rw-r--r--drivers/usb/gadget/m66592-udc.h575
-rw-r--r--drivers/usb/gadget/net2280.c99
-rw-r--r--drivers/usb/gadget/omap_udc.c108
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c473
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h48
-rw-r--r--drivers/usb/gadget/rndis.c164
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c2045
-rw-r--r--drivers/usb/gadget/s3c2410_udc.h110
-rw-r--r--drivers/usb/gadget/serial.c42
-rw-r--r--drivers/usb/gadget/zero.c9
27 files changed, 8834 insertions, 1020 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f771a7cae9e..767aed5b4be 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -42,6 +42,20 @@ config USB_GADGET
For more information, see <http://www.linux-usb.org/gadget> and
the kernel DocBook documentation for this API.
+config USB_GADGET_DEBUG
+ boolean "Debugging messages"
+ depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL
+ help
+ Many controller and gadget drivers will print some debugging
+ messages if you use this option to ask for those messages.
+
+ Avoid enabling these messages, even if you're actively
+ debugging such a driver. Many drivers will emit so many
+ messages that the driver timings are affected, which will
+ either create new failure modes or remove the one you're
+ trying to track down. Never enable these messages for a
+ production build.
+
config USB_GADGET_DEBUG_FILES
boolean "Debugging information files"
depends on USB_GADGET && PROC_FS
@@ -68,6 +82,27 @@ choice
Many controller drivers are platform-specific; these
often need board-specific hooks.
+config USB_GADGET_AMD5536UDC
+ boolean "AMD5536 UDC"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
+ help
+ The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+ It is a USB Highspeed DMA capable USB device controller. Beside ep0
+ it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ The UDC port supports OTG operation, and may be used as a host port
+ if it's not being used to implement peripheral or OTG roles.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "amd5536udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_AMD5536UDC
+ tristate
+ depends on USB_GADGET_AMD5536UDC
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
@@ -142,6 +177,24 @@ config USB_PXA2XX_SMALL
default y if USB_ETH
default y if USB_G_SERIAL
+config USB_GADGET_M66592
+ boolean "Renesas M66592 USB Peripheral Controller"
+ select USB_GADGET_DUALSPEED
+ help
+ M66592 is a discrete USB peripheral controller chip that
+ supports both full and high speed USB 2.0 data transfers.
+ It has seven configurable endpoints, and endpoint zero.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "m66592_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_M66592
+ tristate
+ depends on USB_GADGET_M66592
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
@@ -208,6 +261,27 @@ config USB_OTG
Select this only if your OMAP board has a Mini-AB connector.
+config USB_GADGET_S3C2410
+ boolean "S3C2410 USB Device Controller"
+ depends on ARCH_S3C2410
+ help
+ Samsung's S3C2410 is an ARM-4 processor with an integrated
+ full speed USB 1.1 device controller. It has 4 configurable
+ endpoints, as well as endpoint zero (for control transfers).
+
+ This driver has been tested on the S3C2410, S3C2412, and
+ S3C2440 processors.
+
+config USB_S3C2410
+ tristate
+ depends on USB_GADGET_S3C2410
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_S3C2410_DEBUG
+ boolean "S3C2410 udc debug messages"
+ depends on USB_GADGET_S3C2410
+
config USB_GADGET_AT91
boolean "AT91 USB Device Port"
depends on ARCH_AT91 && !ARCH_AT91SAM9RL
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 5db19396631..1bc0f03550c 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -1,14 +1,21 @@
#
# USB peripheral controller drivers
#
+ifeq ($(CONFIG_USB_GADGET_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
+obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
+obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
+obj-$(CONFIG_USB_M66592) += m66592-udc.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644
index 00000000000..714156ca8fe
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -0,0 +1,3454 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ */
+
+/* debug control */
+/* #define UDC_VERBOSE */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING "01.00.0206 - $Revision: #3 $"
+
+/* system */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+ unsigned long buf_len, gfp_t gfp_flags);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_pci_remove(struct pci_dev *pdev);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde 0 == do not touch RDE, do no start the RDE timer
+ * set_rde 1 == timer function will look whether FIFO has data
+ * set_rde 2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+ (unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+ ep0_string,
+ "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+ "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+ "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+ "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+ "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+ "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+ "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+ "true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+ DBG(dev, "------- Device registers -------\n");
+ DBG(dev, "dev config = %08x\n", readl(&dev->regs->cfg));
+ DBG(dev, "dev control = %08x\n", readl(&dev->regs->ctl));
+ DBG(dev, "dev status = %08x\n", readl(&dev->regs->sts));
+ DBG(dev, "\n");
+ DBG(dev, "dev int's = %08x\n", readl(&dev->regs->irqsts));
+ DBG(dev, "dev intmask = %08x\n", readl(&dev->regs->irqmsk));
+ DBG(dev, "\n");
+ DBG(dev, "dev ep int's = %08x\n", readl(&dev->regs->ep_irqsts));
+ DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+ DBG(dev, "\n");
+ DBG(dev, "USE DMA = %d\n", use_dma);
+ if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+ DBG(dev, "DMA mode = PPBNDU (packet per buffer "
+ "WITHOUT desc. update)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+ } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+ DBG(dev, "DMA mode = PPBDU (packet per buffer "
+ "WITH desc. update)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+ }
+ if (use_dma && use_dma_bufferfill_mode) {
+ DBG(dev, "DMA mode = BF (buffer fill mode)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+ }
+ if (!use_dma) {
+ dev_info(&dev->pdev->dev, "FIFO mode\n");
+ }
+ DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ /* mask all dev interrupts */
+ tmp = AMD_BIT(UDC_DEVINT_SVC) |
+ AMD_BIT(UDC_DEVINT_ENUM) |
+ AMD_BIT(UDC_DEVINT_US) |
+ AMD_BIT(UDC_DEVINT_UR) |
+ AMD_BIT(UDC_DEVINT_ES) |
+ AMD_BIT(UDC_DEVINT_SI) |
+ AMD_BIT(UDC_DEVINT_SOF)|
+ AMD_BIT(UDC_DEVINT_SC);
+ writel(tmp, &dev->regs->irqmsk);
+
+ /* mask all ep interrupts */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ /* enable ep0 irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+ & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "enable device interrupts for setup data\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->irqmsk);
+
+ /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_UR)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+ writel(tmp, &dev->regs->irqmsk);
+
+ return 0;
+}
+
+/* Calculates fifo start of endpoint based on preceeding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+ struct udc *dev;
+ u32 tmp;
+ int i;
+
+ if (!ep || !(ep->in))
+ return -EINVAL;
+
+ dev = ep->dev;
+ ep->txfifo = dev->txfifo;
+
+ /* traverse ep's */
+ for (i = 0; i < ep->num; i++) {
+ if (dev->ep[i].regs) {
+ /* read fifo size */
+ tmp = readl(&dev->ep[i].regs->bufin_framenum);
+ tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+ ep->txfifo += tmp;
+ }
+ }
+ return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+ if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+ DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+ cnak_pending |= 1 << (num);
+ ep->naking = 1;
+ } else
+ cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+ struct udc_ep *ep;
+ struct udc *dev;
+ u32 tmp;
+ unsigned long iflags;
+ u8 udc_csr_epix;
+
+ if (!usbep
+ || usbep->name == ep0_string
+ || !desc
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ dev = ep->dev;
+
+ DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&dev->lock, iflags);
+ ep->desc = desc;
+
+ ep->halted = 0;
+
+ /* set traffic type */
+ tmp = readl(&dev->ep[ep->num].regs->ctl);
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+ writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+ /* set max packet size */
+ tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+ ep->ep.maxpacket = desc->wMaxPacketSize;
+ writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+ /* IN ep */
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+ /* set buffer size (tx fifo entries) */
+ tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+ /* double buffering: fifo size = 2 x max packet size */
+ tmp = AMD_ADDBITS(
+ tmp,
+ desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
+ / UDC_DWORD_BYTES,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+ /* calc. tx fifo base addr */
+ udc_set_txfifo_addr(ep);
+
+ /* flush fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+ /* set max packet size UDC CSR */
+ tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+ UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+ if (use_dma && !ep->in) {
+ /* alloc and init BNA dummy request */
+ ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+ ep->bna_occurred = 0;
+ }
+
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_enabled = 1;
+ }
+
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* max packet */
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+ /* ep number */
+ tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+ /* ep direction */
+ tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+ /* ep type */
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+ /* ep config */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ /*
+ * clear NAK by writing CNAK
+ * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+ */
+ if (!use_dma || ep->in) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ tmp = desc->bEndpointAddress;
+ DBG(dev, "%s enabled\n", usbep->name);
+
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+ u32 tmp;
+
+ VDBG(ep->dev, "ep-%d reset\n", ep->num);
+ ep->desc = NULL;
+ ep->ep.ops = &udc_ep_ops;
+ INIT_LIST_HEAD(&ep->queue);
+
+ ep->ep.maxpacket = (u16) ~0;
+ /* set NAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 1;
+
+ /* disable interrupt */
+ tmp = readl(&regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp, &regs->ep_irqmsk);
+
+ if (ep->in) {
+ /* unset P and IN bit of potential former DMA */
+ tmp = readl(&ep->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+
+ tmp = readl(&ep->regs->sts);
+ tmp |= AMD_BIT(UDC_EPSTS_IN);
+ writel(tmp, &ep->regs->sts);
+
+ /* flush the fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ }
+ /* reset desc pointer */
+ writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+ struct udc_ep *ep = NULL;
+ unsigned long iflags;
+
+ if (!usbep)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (usbep->name == ep0_string || !ep->desc)
+ return -EINVAL;
+
+ DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+ empty_req_queue(ep);
+ ep_init(ep->dev->regs, ep);
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+ return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+ struct udc_request *req;
+ struct udc_data_dma *dma_desc;
+ struct udc_ep *ep;
+
+ if (!usbep)
+ return NULL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+
+ VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+ req = kzalloc(sizeof(struct udc_request), gfp);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_DONT_USE;
+ INIT_LIST_HEAD(&req->queue);
+
+ if (ep->dma) {
+ /* ep0 in requests are allocated from data pool here */
+ dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+ &req->td_phys);
+ if (!dma_desc) {
+ kfree(req);
+ return NULL;
+ }
+
+ VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+ "td_phys = %lx\n",
+ req, dma_desc,
+ (unsigned long)req->td_phys);
+ /* prevent from using desc. - set HOST BUSY */
+ dma_desc->status = AMD_ADDBITS(dma_desc->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+ req->td_data = dma_desc;
+ req->td_data_last = NULL;
+ req->chain_len = 1;
+ }
+
+ return &req->req;
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+
+ if (!usbep || !usbreq)
+ return;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ req = container_of(usbreq, struct udc_request, req);
+ VDBG(ep->dev, "free_req req=%p\n", req);
+ BUG_ON(!list_empty(&req->queue));
+ if (req->td_data) {
+ VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+ /* free dma chain if created */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+
+ pci_pool_free(ep->dev->data_requests, req->td_data,
+ req->td_phys);
+ }
+ kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+ if (req) {
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* set next pointer to itself */
+ req->td_data->next = req->td_phys;
+ /* set HOST BUSY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_DMA_DONE,
+ UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+ pr_debug("bna desc = %p, sts = %08x\n",
+ req->td_data, req->td_data->status);
+#endif
+ }
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+ struct udc_request *req = NULL;
+ struct usb_request *_req = NULL;
+
+ /* alloc the dummy request */
+ _req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+ if (_req) {
+ req = container_of(_req, struct udc_request, req);
+ ep->bna_dummy_req = req;
+ udc_init_bna_dummy(req);
+ }
+ return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+ u8 *req_buf;
+ u32 *buf;
+ int i, j;
+ unsigned bytes = 0;
+ unsigned remaining = 0;
+
+ if (!req || !ep)
+ return;
+
+ req_buf = req->buf + req->actual;
+ prefetch(req_buf);
+ remaining = req->length - req->actual;
+
+ buf = (u32 *) req_buf;
+
+ bytes = ep->ep.maxpacket;
+ if (bytes > remaining)
+ bytes = remaining;
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ writel(*(buf + i), ep->txfifo);
+ }
+
+ /* remaining bytes must be written by byte access */
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+ ep->txfifo);
+ }
+
+ /* dummy write confirm */
+ writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+ int i;
+
+ VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+ for (i = 0; i < dwords; i++) {
+ *(buf + i) = readl(dev->rxfifo);
+ }
+ return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+ int i, j;
+ u32 tmp;
+
+ VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+ }
+
+ /* remaining bytes must be read by byte access */
+ if (bytes % UDC_DWORD_BYTES) {
+ tmp = readl(dev->rxfifo);
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+ tmp = tmp >> UDC_BITS_PER_BYTE;
+ }
+ }
+
+ return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+ u8 *buf;
+ unsigned buf_space;
+ unsigned bytes = 0;
+ unsigned finished = 0;
+
+ /* received number bytes */
+ bytes = readl(&ep->regs->sts);
+ bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+ buf_space = req->req.length - req->req.actual;
+ buf = req->req.buf + req->req.actual;
+ if (bytes > buf_space) {
+ if ((buf_space % ep->ep.maxpacket) != 0) {
+ DBG(ep->dev,
+ "%s: rx %d bytes, rx-buf space = %d bytesn\n",
+ ep->ep.name, bytes, buf_space);
+ req->req.status = -EOVERFLOW;
+ }
+ bytes = buf_space;
+ }
+ req->req.actual += bytes;
+
+ /* last packet ? */
+ if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+ || ((req->req.actual == req->req.length) && !req->req.zero))
+ finished = 1;
+
+ /* read rx fifo bytes */
+ VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+ udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+ return finished;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+ int retval = 0;
+ u32 tmp;
+
+ VDBG(ep->dev, "prep_dma\n");
+ VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+ ep->num, req->td_data);
+
+ /* set buffer pointer */
+ req->td_data->bufptr = req->req.dma;
+
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+ /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+ if (use_dma_ppb) {
+
+ retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+ if (retval != 0) {
+ if (retval == -ENOMEM)
+ DBG(ep->dev, "Out of DMA memory\n");
+ return retval;
+ }
+ if (ep->in) {
+ if (req->req.length == ep->ep.maxpacket) {
+ /* write tx bytes */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+
+ }
+ }
+
+ }
+
+ if (ep->in) {
+ VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+ "maxpacket=%d ep%d\n",
+ use_dma_ppb, req->req.length,
+ ep->ep.maxpacket, ep->num);
+ /*
+ * if bytes < max packet then tx bytes must
+ * be written in packet per buffer mode
+ */
+ if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+ || ep->num == UDC_EP0OUT_IX
+ || ep->num == UDC_EP0IN_IX) {
+ /* write tx bytes */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ req->req.length,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* reset frame num */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ 0,
+ UDC_DMA_IN_STS_FRAMENUM);
+ }
+ /* set HOST BUSY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ } else {
+ VDBG(ep->dev, "OUT set host ready\n");
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ }
+
+ return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+ struct udc *dev;
+ unsigned halted;
+
+ VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+ dev = ep->dev;
+ /* unmap DMA */
+ if (req->dma_mapping) {
+ if (ep->in)
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_TODEVICE);
+ else
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 0;
+ req->req.dma = DMA_DONT_USE;
+ }
+
+ halted = ep->halted;
+ ep->halted = 1;
+
+ /* set new status if pending */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = sts;
+
+ /* remove from ep queue */
+ list_del_init(&req->queue);
+
+ VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+ &req->req, req->req.length, ep->ep.name, sts);
+
+ spin_unlock(&dev->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dev->lock);
+ ep->halted = halted;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+ int ret_val = 0;
+ struct udc_data_dma *td;
+ struct udc_data_dma *td_last = NULL;
+ unsigned int i;
+
+ DBG(dev, "free chain req = %p\n", req);
+
+ /* do not free first desc., will be done by free for request */
+ td_last = req->td_data;
+ td = phys_to_virt(td_last->next);
+
+ for (i = 1; i < req->chain_len; i++) {
+
+ pci_pool_free(dev->data_requests, td,
+ (dma_addr_t) td_last->next);
+ td_last = td;
+ td = phys_to_virt(td_last->next);
+ }
+
+ return ret_val;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+ struct udc_data_dma *td;
+
+ td = req->td_data;
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ td = phys_to_virt(td->next);
+ }
+
+ return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+ struct udc_data_dma *td;
+ u32 count;
+
+ td = req->td_data;
+ /* received number bytes */
+ count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ td = phys_to_virt(td->next);
+ /* received number bytes */
+ if (td) {
+ count += AMD_GETBITS(td->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ }
+ }
+
+ return count;
+
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+ struct udc_ep *ep,
+ struct udc_request *req,
+ unsigned long buf_len, gfp_t gfp_flags
+)
+{
+ unsigned long bytes = req->req.length;
+ unsigned int i;
+ dma_addr_t dma_addr;
+ struct udc_data_dma *td = NULL;
+ struct udc_data_dma *last = NULL;
+ unsigned long txbytes;
+ unsigned create_new_chain = 0;
+ unsigned len;
+
+ VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+ bytes, buf_len);
+ dma_addr = DMA_DONT_USE;
+
+ /* unset L bit in first desc for OUT */
+ if (!ep->in) {
+ req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+ }
+
+ /* alloc only new desc's if not already available */
+ len = req->req.length / ep->ep.maxpacket;
+ if (req->req.length % ep->ep.maxpacket) {
+ len++;
+ }
+
+ if (len > req->chain_len) {
+ /* shorter chain already allocated before */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+ req->chain_len = len;
+ create_new_chain = 1;
+ }
+
+ td = req->td_data;
+ /* gen. required number of descriptors and buffers */
+ for (i = buf_len; i < bytes; i += buf_len) {
+ /* create or determine next desc. */
+ if (create_new_chain) {
+
+ td = pci_pool_alloc(ep->dev->data_requests,
+ gfp_flags, &dma_addr);
+ if (!td)
+ return -ENOMEM;
+
+ td->status = 0;
+ } else if (i == buf_len) {
+ /* first td */
+ td = (struct udc_data_dma *) phys_to_virt(
+ req->td_data->next);
+ td->status = 0;
+ } else {
+ td = (struct udc_data_dma *) phys_to_virt(last->next);
+ td->status = 0;
+ }
+
+
+ if (td)
+ td->bufptr = req->req.dma + i; /* assign buffer */
+ else
+ break;
+
+ /* short packet ? */
+ if ((bytes - i) >= buf_len) {
+ txbytes = buf_len;
+ } else {
+ /* short packet */
+ txbytes = bytes - i;
+ }
+
+ /* link td and assign tx bytes */
+ if (i == buf_len) {
+ if (create_new_chain) {
+ req->td_data->next = dma_addr;
+ } else {
+ /* req->td_data->next = virt_to_phys(td); */
+ }
+ /* write tx bytes */
+ if (ep->in) {
+ /* first desc */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* second desc */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+ } else {
+ if (create_new_chain) {
+ last->next = dma_addr;
+ } else {
+ /* last->next = virt_to_phys(td); */
+ }
+ if (ep->in) {
+ /* write tx bytes */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+ }
+ last = td;
+ }
+ /* set last bit */
+ if (td) {
+ td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* last desc. points to itself */
+ req->td_data_last = td;
+ }
+
+ return 0;
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+ u32 tmp;
+
+ VDBG(dev, "udc_set_rde()\n");
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* set RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+ int retval = 0;
+ u8 open_rxfifo = 0;
+ unsigned long iflags;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc *dev;
+ u32 tmp;
+
+ /* check the inputs */
+ req = container_of(usbreq, struct udc_request, req);
+
+ if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+ || !list_empty(&req->queue))
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+
+ VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+ dev = ep->dev;
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* map dma (usually done before) */
+ if (ep->dma && usbreq->length != 0
+ && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+ VDBG(dev, "DMA map req %p\n", req);
+ if (ep->in)
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_TODEVICE);
+ else
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 1;
+ }
+
+ VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+ usbep->name, usbreq, usbreq->length,
+ req->td_data, usbreq->buf);
+
+ spin_lock_irqsave(&dev->lock, iflags);
+ usbreq->actual = 0;
+ usbreq->status = -EINPROGRESS;
+ req->dma_done = 0;
+
+ /* on empty queue just do first transfer */
+ if (list_empty(&ep->queue)) {
+ /* zlp */
+ if (usbreq->length == 0) {
+ /* IN zlp's are handled by hardware */
+ complete_req(ep, req, 0);
+ VDBG(dev, "%s: zlp\n", ep->ep.name);
+ /*
+ * if set_config or set_intf is waiting for ack by zlp
+ * then set CSR_DONE
+ */
+ if (dev->set_cfg_not_acked) {
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+ writel(tmp, &dev->regs->ctl);
+ dev->set_cfg_not_acked = 0;
+ }
+ /* setup command is ACK'ed now by zlp */
+ if (dev->waiting_zlp_ack_ep0in) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+ UDC_EP0IN_IX);
+ dev->waiting_zlp_ack_ep0in = 0;
+ }
+ goto finished;
+ }
+ if (ep->dma) {
+ retval = prep_dma(ep, req, gfp);
+ if (retval != 0)
+ goto finished;
+ /* write desc pointer to enable DMA */
+ if (ep->in) {
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+ }
+
+ /* disabled rx dma while descriptor update */
+ if (!ep->in) {
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* clear RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+ open_rxfifo = 1;
+
+ /*
+ * if BNA occurred then let BNA dummy desc.
+ * point to current desc.
+ */
+ if (ep->bna_occurred) {
+ VDBG(dev, "copy to BNA dummy desc.\n");
+ memcpy(ep->bna_dummy_req->td_data,
+ req->td_data,
+ sizeof(struct udc_data_dma));
+ }
+ }
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ if (ep->in) {
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
+ }
+
+ } else if (ep->dma) {
+
+ /*
+ * prep_dma not used for OUT ep's, this is not possible
+ * for PPB modes, because of chain creation reasons
+ */
+ if (ep->in) {
+ retval = prep_dma(ep, req, gfp);
+ if (retval != 0)
+ goto finished;
+ }
+ }
+ VDBG(dev, "list_add\n");
+ /* add request to ep queue */
+ if (req) {
+
+ list_add_tail(&req->queue, &ep->queue);
+
+ /* open rxfifo if out data queued */
+ if (open_rxfifo) {
+ /* enable DMA */
+ req->dma_going = 1;
+ udc_set_rde(dev);
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 1;
+ }
+ /* stop OUT naking */
+ if (!ep->in) {
+ if (!use_dma && udc_rxfifo_pending) {
+ DBG(dev, "udc_queue(): pending bytes in"
+ "rxfifo after nyet\n");
+ /*
+ * read pending bytes afer nyet:
+ * referring to isr
+ */
+ if (udc_rxfifo_read(ep, req)) {
+ /* finish */
+ complete_req(ep, req, 0);
+ }
+ udc_rxfifo_pending = 0;
+
+ }
+ }
+ }
+
+finished:
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+ struct udc_request *req;
+
+ ep->halted = 1;
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ complete_req(ep, req, -ESHUTDOWN);
+ }
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned halted;
+ unsigned long iflags;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+ && ep->num != UDC_EP0OUT_IX)))
+ return -EINVAL;
+
+ req = container_of(usbreq, struct udc_request, req);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ halted = ep->halted;
+ ep->halted = 1;
+ /* request in processing or next one */
+ if (ep->queue.next == &req->queue) {
+ if (ep->dma && req->dma_going) {
+ if (ep->in)
+ ep->cancel_transfer = 1;
+ else {
+ u32 tmp;
+ u32 dma_sts;
+ /* stop potential receive DMA */
+ tmp = readl(&udc->regs->ctl);
+ writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+ &udc->regs->ctl);
+ /*
+ * Cancel transfer later in ISR
+ * if descriptor was touched.
+ */
+ dma_sts = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_BS);
+ if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+ ep->cancel_transfer = 1;
+ else {
+ udc_init_bna_dummy(ep->req);
+ writel(ep->bna_dummy_req->td_phys,
+ &ep->regs->desptr);
+ }
+ writel(tmp, &udc->regs->ctl);
+ }
+ }
+ }
+ complete_req(ep, req, -ECONNRESET);
+ ep->halted = halted;
+
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+ return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ unsigned long iflags;
+ int retval = 0;
+
+ if (!usbep)
+ return -EINVAL;
+
+ pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&udc_stall_spinlock, iflags);
+ /* halt or clear halt */
+ if (halt) {
+ if (ep->num == 0)
+ ep->dev->stall_ep0in = 1;
+ else {
+ /*
+ * set STALL
+ * rxfifo empty not taken into acount
+ */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 1;
+
+ /* setup poll timer */
+ if (!timer_pending(&udc_pollstall_timer)) {
+ udc_pollstall_timer.expires = jiffies +
+ HZ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ if (!stop_pollstall_timer) {
+ DBG(ep->dev, "start polltimer\n");
+ add_timer(&udc_pollstall_timer);
+ }
+ }
+ }
+ } else {
+ /* ep is halted by set_halt() before */
+ if (ep->halted) {
+ tmp = readl(&ep->regs->ctl);
+ /* clear stall bit */
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+ spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+ return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+ .enable = udc_ep_enable,
+ .disable = udc_ep_disable,
+
+ .alloc_request = udc_alloc_request,
+ .free_request = udc_free_request,
+
+ .queue = udc_queue,
+ .dequeue = udc_dequeue,
+
+ .set_halt = udc_set_halt,
+ /* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+ return -EOPNOTSUPP;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+ struct udc *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct udc, gadget);
+ udc_remote_wakeup(dev);
+
+ return 0;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+ .wakeup = udc_wakeup,
+ .get_frame = udc_get_frame,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+ /* make gadget ep lists */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+
+ /* fifo config */
+ dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+ dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+ u32 tmp;
+
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* put into initial config */
+ udc_basic_init(dev);
+ /* link up all endpoints */
+ udc_setup_endpoints(dev);
+
+ /* program speed */
+ tmp = readl(&dev->regs->cfg);
+ if (use_fullspeed) {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ } else {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+ }
+ writel(tmp, &dev->regs->cfg);
+
+ return 0;
+}
+
+/* Inits UDC context */
+static void udc_basic_init(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "udc_basic_init()\n");
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop poll stall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+ /* disable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+ writel(tmp, &dev->regs->ctl);
+
+ /* enable dynamic CSR programming */
+ tmp = readl(&dev->regs->cfg);
+ tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+ /* set self powered */
+ tmp |= AMD_BIT(UDC_DEVCFG_SP);
+ /* set remote wakeupable */
+ tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+ writel(tmp, &dev->regs->cfg);
+
+ make_ep_lists(dev);
+
+ dev->data_ep_enabled = 0;
+ dev->data_ep_queued = 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ u32 reg;
+
+ DBG(dev, "udc_setup_endpoints()\n");
+
+ /* read enum speed */
+ tmp = readl(&dev->regs->sts);
+ tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+ if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+ dev->gadget.speed = USB_SPEED_HIGH;
+ } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+ dev->gadget.speed = USB_SPEED_FULL;
+ }
+
+ /* set basic ep parameters */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ ep = &dev->ep[tmp];
+ ep->dev = dev;
+ ep->ep.name = ep_string[tmp];
+ ep->num = tmp;
+ /* txfifo size is calculated at enable time */
+ ep->txfifo = dev->txfifo;
+
+ /* fifo size */
+ if (tmp < UDC_EPIN_NUM) {
+ ep->fifo_depth = UDC_TXFIFO_SIZE;
+ ep->in = 1;
+ } else {
+ ep->fifo_depth = UDC_RXFIFO_SIZE;
+ ep->in = 0;
+
+ }
+ ep->regs = &dev->ep_regs[tmp];
+ /*
+ * ep will be reset only if ep was not enabled before to avoid
+ * disabling ep interrupts when ENUM interrupt occurs but ep is
+ * not enabled by gadget driver
+ */
+ if (!ep->desc) {
+ ep_init(dev->regs, ep);
+ }
+
+ if (use_dma) {
+ /*
+ * ep->dma is not really used, just to indicate that
+ * DMA is active: remove this
+ * dma regs = dev control regs
+ */
+ ep->dma = &dev->regs->ctl;
+
+ /* nak OUT endpoints until enable - not for ep0 */
+ if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+ && tmp > UDC_EPIN_NUM) {
+ /* set NAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 1;
+
+ }
+ }
+ }
+ /* EP0 max packet */
+ if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+ UDC_FS_EP0OUT_MAX_PKT_SIZE;
+ } else if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+ }
+
+ /*
+ * with suspend bug workaround, ep0 params for gadget driver
+ * are set at gadget driver bind() call
+ */
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+ dev->ep[UDC_EP0IN_IX].halted = 0;
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+ /* init cfg/alt/int */
+ dev->cur_config = 0;
+ dev->cur_intf = 0;
+ dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+ dev_info(&dev->pdev->dev, "USB Connect\n");
+
+ dev->connected = 1;
+
+ /* put into initial config */
+ udc_basic_init(dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+ dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+ dev->connected = 0;
+
+ /* mask interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* REVISIT there doesn't seem to be a point to having this
+ * talk to a tasklet ... do it directly, we already hold
+ * the spinlock needed to process the disconnect.
+ */
+
+ tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+ struct udc *dev = (struct udc *)(*((struct udc **) par));
+ u32 tmp;
+
+ DBG(dev, "Tasklet disconnect\n");
+ spin_lock_irq(&dev->lock);
+
+ if (dev->driver) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* empty queues */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue(&dev->ep[tmp]);
+ }
+
+ }
+
+ /* disable ep0 */
+ ep_init(dev->regs,
+ &dev->ep[UDC_EP0IN_IX]);
+
+
+ if (!soft_reset_occured) {
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+ soft_reset_occured++;
+ }
+
+ /* re-enable dev interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+ /* back to full speed ? */
+ if (use_fullspeed) {
+ tmp = readl(&dev->regs->cfg);
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ writel(tmp, &dev->regs->cfg);
+ }
+
+ spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+ unsigned long flags;
+
+ DBG(dev, "Soft reset\n");
+ /*
+ * reset possible waiting interrupts, because int.
+ * status is lost after soft reset,
+ * ep int. status reset
+ */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+ /* device int. status reset */
+ writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+ spin_lock_irqsave(&udc_irq_spinlock, flags);
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ readl(&dev->regs->cfg);
+ spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+ u32 tmp;
+
+ spin_lock_irq(&udc_irq_spinlock);
+
+ if (set_rde > 0) {
+ /*
+ * open the fifo if fifo was filled on last timer call
+ * conditionally
+ */
+ if (set_rde > 1) {
+ /* set RDE to receive setup data */
+ tmp = readl(&udc->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &udc->regs->ctl);
+ set_rde = -1;
+ } else if (readl(&udc->regs->sts)
+ & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ /*
+ * if fifo empty setup polling, do not just
+ * open the fifo
+ */
+ udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ } else {
+ /*
+ * fifo contains data now, setup timer for opening
+ * the fifo when timer expires to be able to receive
+ * setup packets, when data packets gets queued by
+ * gadget layer then timer will forced to expire with
+ * set_rde=0 (RDE is set in udc_queue())
+ */
+ set_rde++;
+ /* debug: lhadmot_timer_start = 221070 */
+ udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+
+ } else
+ set_rde = -1; /* RDE was set by udc_queue() */
+ spin_unlock_irq(&udc_irq_spinlock);
+ if (stop_timer)
+ complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+ u32 tmp;
+ /* set stall as long not halted */
+ if (ep->halted == 1) {
+ tmp = readl(&ep->regs->ctl);
+ /* STALL cleared ? */
+ if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+ /*
+ * FIXME: MSC spec requires that stall remains
+ * even on receivng of CLEAR_FEATURE HALT. So
+ * we would set STALL again here to be compliant.
+ * But with current mass storage drivers this does
+ * not work (would produce endless host retries).
+ * So we clear halt on CLEAR_FEATURE.
+ *
+ DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);*/
+
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+ struct udc_ep *ep;
+ int halted = 0;
+
+ spin_lock_irq(&udc_stall_spinlock);
+ /*
+ * only one IN and OUT endpoints are handled
+ * IN poll stall
+ */
+ ep = &udc->ep[UDC_EPIN_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+ /* OUT poll stall */
+ ep = &udc->ep[UDC_EPOUT_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+
+ /* setup timer again when still halted */
+ if (!stop_pollstall_timer && halted) {
+ udc_pollstall_timer.expires = jiffies +
+ HZ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ add_timer(&udc_pollstall_timer);
+ }
+ spin_unlock_irq(&udc_stall_spinlock);
+
+ if (stop_pollstall_timer)
+ complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "activate_control_endpoints\n");
+
+ /* flush fifo */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* set ep0 directions */
+ dev->ep[UDC_EP0IN_IX].in = 1;
+ dev->ep[UDC_EP0OUT_IX].in = 0;
+
+ /* set buffer size (tx fifo entries) of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+ UDC_EPIN_BUFF_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+ /* set max packet size of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0_OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0 in UDC CSR */
+ tmp = readl(&dev->csr->ne[0]);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+ UDC_CSR_NE_MAX_PKT);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+ UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[0]);
+
+ if (use_dma) {
+ dev->ep[UDC_EP0OUT_IX].td->status |=
+ AMD_BIT(UDC_DMA_OUT_STS_L);
+ /* write dma desc address */
+ writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+ &dev->ep[UDC_EP0OUT_IX].regs->subptr);
+ writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop pollstall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+ /* enable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+ | AMD_BIT(UDC_DEVCTL_RDE)
+ | AMD_BIT(UDC_DEVCTL_TDE);
+ if (use_dma_bufferfill_mode) {
+ tmp |= AMD_BIT(UDC_DEVCTL_BF);
+ } else if (use_dma_ppb_du) {
+ tmp |= AMD_BIT(UDC_DEVCTL_DU);
+ }
+ writel(tmp, &dev->regs->ctl);
+ }
+
+ /* clear NAK by writing CNAK for EP0IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* clear NAK by writing CNAK for EP0OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+ activate_control_endpoints(dev);
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ return 0;
+}
+
+/* Called by gadget driver to register itself */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ int retval;
+ u32 tmp;
+
+ if (!driver || !driver->bind || !driver->setup
+ || driver->speed != USB_SPEED_HIGH)
+ return -EINVAL;
+ if (!dev)
+ return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
+
+ driver->driver.bus = NULL;
+ dev->driver = driver;
+ dev->gadget.dev.driver = &driver->driver;
+
+ retval = driver->bind(&dev->gadget);
+
+ /* Some gadget drivers use both ep0 directions.
+ * NOTE: to gadget driver, ep0 is just one endpoint...
+ */
+ dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+ dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+ if (retval) {
+ DBG(dev, "binding to %s returning %d\n",
+ driver->driver.name, retval);
+ dev->driver = NULL;
+ dev->gadget.dev.driver = NULL;
+ return retval;
+ }
+
+ /* get ready for ep0 traffic */
+ setup_ep0(dev);
+
+ /* clear SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+ usb_connect(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ int tmp;
+
+ /* empty queues and init hardware */
+ udc_basic_init(dev);
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue(&dev->ep[tmp]);
+ }
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+ spin_unlock(&dev->lock);
+ driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ /* init */
+ udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ unsigned long flags;
+ u32 tmp;
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver || !driver->unbind)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ udc_mask_unused_interrupts(dev);
+ shutdown(dev, driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ driver->unbind(&dev->gadget);
+ dev->driver = NULL;
+
+ /* set SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+
+ DBG(dev, "%s: unregistered\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+ u32 tmp;
+ u32 reg;
+
+ /* check epin's */
+ DBG(dev, "CNAK pending queue processing\n");
+ for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+ if (cnak_pending & (1 << tmp)) {
+ DBG(dev, "CNAK pending for ep%d\n", tmp);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+ }
+ }
+ /* ... and ep0out */
+ if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+ DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+ dev->ep[UDC_EP0OUT_IX].num);
+ }
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+ if (use_dma) {
+ /*
+ * only enable RXDMA when no data endpoint enabled
+ * or data is queued
+ */
+ if (!dev->data_ep_enabled || dev->data_ep_queued) {
+ udc_set_rde(dev);
+ } else {
+ /*
+ * setup timer for enabling RDE (to not enable
+ * RXFIFO DMA for data endpoints to early)
+ */
+ if (set_rde != 0 && !timer_pending(&udc_timer)) {
+ udc_timer.expires =
+ jiffies + HZ/UDC_RDE_TIMER_DIV;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+ }
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned int count;
+ struct udc_data_dma *td = NULL;
+ unsigned dma_done;
+
+ VDBG(dev, "ep%d irq\n", ep_ix);
+ ep = &dev->ep[ep_ix];
+
+ tmp = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ DBG(dev, "BNA ep%dout occured - DESPTR = %x \n",
+ ep->num, readl(&ep->regs->desptr));
+ /* clear BNA */
+ writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+ if (!ep->cancel_transfer)
+ ep->bna_occurred = 1;
+ else
+ ep->cancel_transfer = 0;
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+ }
+ /* HE event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+ dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num);
+
+ /* clear HE */
+ writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ if (!list_empty(&ep->queue)) {
+
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ } else {
+ req = NULL;
+ udc_rxfifo_pending = 1;
+ }
+ VDBG(dev, "req = %p\n", req);
+ /* fifo mode */
+ if (!use_dma) {
+
+ /* read fifo */
+ if (req && udc_rxfifo_read(ep, req)) {
+ ret_val = IRQ_HANDLED;
+
+ /* finish */
+ complete_req(ep, req, 0);
+ /* next request */
+ if (!list_empty(&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ } else
+ req = NULL;
+ }
+
+ /* DMA */
+ } else if (!ep->cancel_transfer && req != NULL) {
+ ret_val = IRQ_HANDLED;
+
+ /* check for DMA done */
+ if (!use_dma_ppb) {
+ dma_done = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_BS);
+ /* packet per buffer mode - rx bytes */
+ } else {
+ /*
+ * if BNA occurred then recover desc. from
+ * BNA dummy desc.
+ */
+ if (ep->bna_occurred) {
+ VDBG(dev, "Recover desc. from BNA dummy\n");
+ memcpy(req->td_data, ep->bna_dummy_req->td_data,
+ sizeof(struct udc_data_dma));
+ ep->bna_occurred = 0;
+ udc_init_bna_dummy(ep->req);
+ }
+ td = udc_get_last_dma_desc(req);
+ dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+ }
+ if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+ /* buffer fill mode - rx bytes */
+ if (!use_dma_ppb) {
+ /* received number bytes */
+ count = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ VDBG(dev, "rx bytes=%u\n", count);
+ /* packet per buffer mode - rx bytes */
+ } else {
+ VDBG(dev, "req->td_data=%p\n", req->td_data);
+ VDBG(dev, "last desc = %p\n", td);
+ /* received number bytes */
+ if (use_dma_ppb_du) {
+ /* every desc. counts bytes */
+ count = udc_get_ppbdu_rxbytes(req);
+ } else {
+ /* last desc. counts bytes */
+ count = AMD_GETBITS(td->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ if (!count && req->req.length
+ == UDC_DMA_MAXPACKET) {
+ /*
+ * on 64k packets the RXBYTES
+ * field is zero
+ */
+ count = UDC_DMA_MAXPACKET;
+ }
+ }
+ VDBG(dev, "last desc rx bytes=%u\n", count);
+ }
+
+ tmp = req->req.length - req->req.actual;
+ if (count > tmp) {
+ if ((tmp % ep->ep.maxpacket) != 0) {
+ DBG(dev, "%s: rx %db, space=%db\n",
+ ep->ep.name, count, tmp);
+ req->req.status = -EOVERFLOW;
+ }
+ count = tmp;
+ }
+ req->req.actual += count;
+ req->dma_going = 0;
+ /* complete request */
+ complete_req(ep, req, 0);
+
+ /* next request */
+ if (!list_empty(&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ /*
+ * DMA may be already started by udc_queue()
+ * called by gadget drivers completion
+ * routine. This happens when queue
+ * holds one request only.
+ */
+ if (req->dma_going == 0) {
+ /* next dma */
+ if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+ goto finished;
+ /* write desc pointer */
+ writel(req->td_phys,
+ &ep->regs->desptr);
+ req->dma_going = 1;
+ /* enable DMA */
+ udc_set_rde(dev);
+ }
+ } else {
+ /*
+ * implant BNA dummy descriptor to allow
+ * RXFIFO opening by RDE
+ */
+ if (ep->bna_dummy_req) {
+ /* write desc pointer */
+ writel(ep->bna_dummy_req->td_phys,
+ &ep->regs->desptr);
+ ep->bna_occurred = 0;
+ }
+
+ /*
+ * schedule timer for setting RDE if queue
+ * remains empty to allow ep0 packets pass
+ * through
+ */
+ if (set_rde != 0
+ && !timer_pending(&udc_timer)) {
+ udc_timer.expires =
+ jiffies
+ + HZ*UDC_RDE_TIMER_SECONDS;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 0;
+ }
+
+ } else {
+ /*
+ * RX DMA must be reenabled for each desc in PPBDU mode
+ * and must be enabled for PPBNDU mode in case of BNA
+ */
+ udc_set_rde(dev);
+ }
+
+ } else if (ep->cancel_transfer) {
+ ret_val = IRQ_HANDLED;
+ ep->cancel_transfer = 0;
+ }
+
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+ return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ u32 epsts;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc_data_dma *td;
+ unsigned dma_done;
+ unsigned len;
+
+ ep = &dev->ep[ep_ix];
+
+ epsts = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA ? */
+ if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+ dev_err(&dev->pdev->dev,
+ "BNA ep%din occured - DESPTR = %08lx \n",
+ ep->num,
+ (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear BNA */
+ writel(epsts, &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+ }
+ /* HE event ? */
+ if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+ dev_err(&dev->pdev->dev,
+ "HE ep%dn occured - DESPTR = %08lx \n",
+ ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear HE */
+ writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ /* DMA completion */
+ if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG(dev, "TDC set- completion\n");
+ ret_val = IRQ_HANDLED;
+ if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ if (req) {
+ /*
+ * length bytes transfered
+ * check dma done of last desc. in PPBDU mode
+ */
+ if (use_dma_ppb_du) {
+ td = udc_get_last_dma_desc(req);
+ if (td) {
+ dma_done =
+ AMD_GETBITS(td->status,
+ UDC_DMA_IN_STS_BS);
+ /* don't care DMA done */
+ req->req.actual =
+ req->req.length;
+ }
+ } else {
+ /* assume all bytes transferred */
+ req->req.actual = req->req.length;
+ }
+
+ if (req->req.actual == req->req.length) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ req->dma_going = 0;
+ /* further request available ? */
+ if (list_empty(&ep->queue)) {
+ /* disable interrupt */
+ tmp = readl(
+ &dev->regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp,
+ &dev->regs->ep_irqmsk);
+ }
+
+ }
+ }
+ }
+ ep->cancel_transfer = 0;
+
+ }
+ /*
+ * status reg has IN bit set and TDC not set (if TDC was handled,
+ * IN must not be handled (UDC defect) ?
+ */
+ if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+ && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+ ret_val = IRQ_HANDLED;
+ if (!list_empty(&ep->queue)) {
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ /* FIFO mode */
+ if (!use_dma) {
+ /* write fifo */
+ udc_txfifo_write(ep, &req->req);
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ /* DMA */
+ } else if (req && !req->dma_going) {
+ VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+ req, req->td_data);
+ if (req->td_data) {
+
+ req->dma_going = 1;
+
+ /*
+ * unset L bit of first desc.
+ * for chain
+ */
+ if (use_dma_ppb && req->req.length >
+ ep->ep.maxpacket) {
+ req->td_data->status &=
+ AMD_CLEAR_BIT(
+ UDC_DMA_IN_STS_L);
+ }
+
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(
+ req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+
+ /* set poll demand bit */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+ }
+ }
+
+ }
+ }
+ /* clear status bits */
+ writel(epsts, &ep->regs->sts);
+
+finished:
+ return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ int setup_supported;
+ u32 count;
+ int set = 0;
+ struct udc_ep *ep;
+ struct udc_ep *ep_tmp;
+
+ ep = &dev->ep[UDC_EP0OUT_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ /* check BNA and clear if set */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ VDBG(dev, "ep0: BNA set\n");
+ writel(AMD_BIT(UDC_EPSTS_BNA),
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ ep->bna_occurred = 1;
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ /* type of data: SETUP or DATA 0 bytes */
+ tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+ VDBG(dev, "data_typ = %x\n", tmp);
+
+ /* setup data */
+ if (tmp == UDC_EPSTS_OUT_SETUP) {
+ ret_val = IRQ_HANDLED;
+
+ ep->dev->stall_ep0in = 0;
+ dev->waiting_zlp_ack_ep0in = 0;
+
+ /* set NAK for EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 1;
+ /* get setup data */
+ if (use_dma) {
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR,
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ setup_data.data[0] =
+ dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+ setup_data.data[1] =
+ dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td_stp->status =
+ UDC_DMA_STP_STS_BS_HOST_READY;
+ } else {
+ /* read fifo */
+ udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+ }
+
+ /* determine direction of control data */
+ if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ set = 0;
+ } else {
+ dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+ /*
+ * implant BNA dummy descriptor to allow RXFIFO opening
+ * by RDE
+ */
+ if (ep->bna_dummy_req) {
+ /* write desc pointer */
+ writel(ep->bna_dummy_req->td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ ep->bna_occurred = 0;
+ }
+
+ set = 1;
+ dev->ep[UDC_EP0OUT_IX].naking = 1;
+ /*
+ * setup timer for enabling RDE (to not enable
+ * RXFIFO DMA for data to early)
+ */
+ set_rde = 1;
+ if (!timer_pending(&udc_timer)) {
+ udc_timer.expires = jiffies +
+ HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+
+ /*
+ * mass storage reset must be processed here because
+ * next packet may be a CLEAR_FEATURE HALT which would not
+ * clear the stall bit when no STALL handshake was received
+ * before (autostall can cause this)
+ */
+ if (setup_data.data[0] == UDC_MSCRES_DWORD0
+ && setup_data.data[1] == UDC_MSCRES_DWORD1) {
+ DBG(dev, "MSC Reset\n");
+ /*
+ * clear stall bits
+ * only one IN and OUT endpoints are handled
+ */
+ ep_tmp = &udc->ep[UDC_EPIN_IX];
+ udc_set_halt(&ep_tmp->ep, 0);
+ ep_tmp = &udc->ep[UDC_EPOUT_IX];
+ udc_set_halt(&ep_tmp->ep, 0);
+ }
+
+ /* call gadget with setup data received */
+ spin_unlock(&dev->lock);
+ setup_supported = dev->driver->setup(&dev->gadget,
+ &setup_data.request);
+ spin_lock(&dev->lock);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ /* ep0 in returns data (not zlp) on IN phase */
+ if (setup_supported >= 0 && setup_supported <
+ UDC_EP0IN_MAXPACKET) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* if unsupported request then stall */
+ } else if (setup_supported < 0) {
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ } else
+ dev->waiting_zlp_ack_ep0in = 1;
+
+
+ /* clear NAK by writing CNAK in EP0_OUT */
+ if (!set) {
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+ }
+
+ if (!use_dma) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR,
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ }
+
+ /* data packet 0 bytes */
+ } else if (tmp == UDC_EPSTS_OUT_DATA) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ /* get setup data: only 0 packet */
+ if (use_dma) {
+ /* no req if 0 packet, just reactivate */
+ if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+ VDBG(dev, "ZLP\n");
+
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td->status =
+ AMD_ADDBITS(
+ dev->ep[UDC_EP0OUT_IX].td->status,
+ UDC_DMA_OUT_STS_BS_HOST_READY,
+ UDC_DMA_OUT_STS_BS);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ ret_val = IRQ_HANDLED;
+
+ } else {
+ /* control write */
+ ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ /* re-program desc. pointer for possible ZLPs */
+ writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ }
+ } else {
+
+ /* received number bytes */
+ count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+ /* out data for fifo mode not working */
+ count = 0;
+
+ /* 0 packet or real data ? */
+ if (count != 0) {
+ ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ } else {
+ /* dummy read confirm */
+ readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+ ret_val = IRQ_HANDLED;
+ }
+ }
+ }
+
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+
+finished:
+ return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned len;
+
+ ep = &dev->ep[UDC_EP0IN_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+ /* DMA completion */
+ if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG(dev, "isr: TDC clear \n");
+ ret_val = IRQ_HANDLED;
+
+ /* clear TDC bit */
+ writel(AMD_BIT(UDC_EPSTS_TDC),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+
+ /* status reg has IN bit set ? */
+ } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+ ret_val = IRQ_HANDLED;
+
+ if (ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ if (dev->stall_ep0in) {
+ DBG(dev, "stall ep0in\n");
+ /* halt ep0in */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ } else {
+ if (!list_empty(&ep->queue)) {
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+
+ if (ep->dma) {
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(
+ req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+ /* set poll demand bit */
+ tmp =
+ readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp,
+ &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* all bytes will be transferred */
+ req->req.actual = req->req.length;
+
+ /* complete req */
+ complete_req(ep, req, 0);
+
+ } else {
+ /* write fifo */
+ udc_txfifo_write(ep, &req->req);
+
+ /* lengh bytes transfered */
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ }
+
+ }
+ }
+ ep->halted = 0;
+ dev->stall_ep0in = 0;
+ if (!ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ }
+
+ return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ u32 cfg;
+ struct udc_ep *ep;
+ u16 i;
+ u8 udc_csr_epix;
+
+ /* SET_CONFIG irq ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+ ret_val = IRQ_HANDLED;
+
+ /* read config value */
+ tmp = readl(&dev->regs->sts);
+ cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+ DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+ dev->cur_config = cfg;
+ dev->set_cfg_not_acked = 1;
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+ setup_data.request.wValue = dev->cur_config;
+
+ /* programm the NE registers */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep cfg */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+ UDC_CSR_NE_CFG);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+ spin_lock(&dev->lock);
+
+ } /* SET_INTERFACE ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+ ret_val = IRQ_HANDLED;
+
+ dev->set_cfg_not_acked = 1;
+ /* read interface and alt setting values */
+ tmp = readl(&dev->regs->sts);
+ dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+ dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+ setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+ setup_data.request.wValue = dev->cur_alt;
+ setup_data.request.wIndex = dev->cur_intf;
+
+ DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+ dev->cur_alt, dev->cur_intf);
+
+ /* programm the NE registers */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ /* UDC CSR reg */
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+ UDC_CSR_NE_INTF);
+ /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+ UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+ spin_lock(&dev->lock);
+
+ } /* USB reset */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+ DBG(dev, "USB Reset interrupt\n");
+ ret_val = IRQ_HANDLED;
+
+ /* allow soft reset when suspend occurs */
+ soft_reset_occured = 0;
+
+ dev->waiting_zlp_ack_ep0in = 0;
+ dev->set_cfg_not_acked = 0;
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* call gadget to resume and reset configs etc. */
+ spin_unlock(&dev->lock);
+ if (dev->sys_suspended && dev->driver->resume) {
+ dev->driver->resume(&dev->gadget);
+ dev->sys_suspended = 0;
+ }
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+ /* soft reset when rxfifo not empty */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+ && !soft_reset_after_usbreset_occured) {
+ udc_soft_reset(dev);
+ soft_reset_after_usbreset_occured++;
+ }
+
+ /*
+ * DMA reset to kill potential old DMA hw hang,
+ * POLL bit is already reset by ep_init() through
+ * disconnect()
+ */
+ DBG(dev, "DMA machine reset\n");
+ tmp = readl(&dev->regs->cfg);
+ writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+ writel(tmp, &dev->regs->cfg);
+
+ /* put into initial config */
+ udc_basic_init(dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ /* enable suspend interrupt */
+ tmp = readl(&dev->regs->irqmsk);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+ writel(tmp, &dev->regs->irqmsk);
+
+ } /* USB suspend */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+ DBG(dev, "USB Suspend interrupt\n");
+ ret_val = IRQ_HANDLED;
+ if (dev->driver->suspend) {
+ spin_unlock(&dev->lock);
+ dev->sys_suspended = 1;
+ dev->driver->suspend(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ } /* new speed ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+ DBG(dev, "ENUM interrupt\n");
+ ret_val = IRQ_HANDLED;
+ soft_reset_after_usbreset_occured = 0;
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+ /* link up all endpoints */
+ udc_setup_endpoints(dev);
+ if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+ "high");
+ } else if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+ "full");
+ }
+
+ /* init ep 0 */
+ activate_control_endpoints(dev);
+
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ }
+ /* session valid change interrupt */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+ DBG(dev, "USB SVC interrupt\n");
+ ret_val = IRQ_HANDLED;
+
+ /* check that session is not valid to detect disconnect */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+ /* disable suspend interrupt */
+ tmp = readl(&dev->regs->irqmsk);
+ tmp |= AMD_BIT(UDC_DEVINT_US);
+ writel(tmp, &dev->regs->irqmsk);
+ DBG(dev, "USB Disconnect (session valid low)\n");
+ /* cleanup on disconnect */
+ usb_disconnect(udc);
+ }
+
+ }
+
+ return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+ struct udc *dev = pdev;
+ u32 reg;
+ u16 i;
+ u32 ep_irq;
+ irqreturn_t ret_val = IRQ_NONE;
+
+ spin_lock(&dev->lock);
+
+ /* check for ep irq */
+ reg = readl(&dev->regs->ep_irqsts);
+ if (reg) {
+ if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+ ret_val |= udc_control_out_isr(dev);
+ if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+ ret_val |= udc_control_in_isr(dev);
+
+ /*
+ * data endpoint
+ * iterate ep's
+ */
+ for (i = 1; i < UDC_EP_NUM; i++) {
+ ep_irq = 1 << i;
+ if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+ continue;
+
+ /* clear irq status */
+ writel(ep_irq, &dev->regs->ep_irqsts);
+
+ /* irq for out ep ? */
+ if (i > UDC_EPIN_NUM)
+ ret_val |= udc_data_out_isr(dev, i);
+ else
+ ret_val |= udc_data_in_isr(dev, i);
+ }
+
+ }
+
+
+ /* check for dev irq */
+ reg = readl(&dev->regs->irqsts);
+ if (reg) {
+ /* clear irq */
+ writel(reg, &dev->regs->irqsts);
+ ret_val |= udc_dev_isr(dev, reg);
+ }
+
+
+ spin_unlock(&dev->lock);
+ return ret_val;
+}
+
+/* Tears down device */
+static void gadget_release(struct device *pdev)
+{
+ struct amd5536udc *dev = dev_get_drvdata(pdev);
+ kfree(dev);
+}
+
+/* Cleanup on device remove */
+static void udc_remove(struct udc *dev)
+{
+ /* remove timer */
+ stop_timer++;
+ if (timer_pending(&udc_timer))
+ wait_for_completion(&on_exit);
+ if (udc_timer.data)
+ del_timer_sync(&udc_timer);
+ /* remove pollstall timer */
+ stop_pollstall_timer++;
+ if (timer_pending(&udc_pollstall_timer))
+ wait_for_completion(&on_pollstall_exit);
+ if (udc_pollstall_timer.data)
+ del_timer_sync(&udc_pollstall_timer);
+ udc = NULL;
+}
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+ struct udc *dev;
+
+ dev = pci_get_drvdata(pdev);
+
+ /* gadget driver must not be registered */
+ BUG_ON(dev->driver != NULL);
+
+ /* dma pool cleanup */
+ if (dev->data_requests)
+ pci_pool_destroy(dev->data_requests);
+
+ if (dev->stp_requests) {
+ /* cleanup DMA desc's for ep0in */
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IX].td_stp,
+ dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IX].td,
+ dev->ep[UDC_EP0OUT_IX].td_phys);
+
+ pci_pool_destroy(dev->stp_requests);
+ }
+
+ /* reset controller */
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ if (dev->irq_registered)
+ free_irq(pdev->irq, dev);
+ if (dev->regs)
+ iounmap(dev->regs);
+ if (dev->mem_region)
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (dev->active)
+ pci_disable_device(pdev);
+
+ device_unregister(&dev->gadget.dev);
+ pci_set_drvdata(pdev, NULL);
+
+ udc_remove(dev);
+}
+
+/* create dma pools on init */
+static int init_dma_pools(struct udc *dev)
+{
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td_data;
+ int retval;
+
+ /* consistent DMA mode setting ? */
+ if (use_dma_ppb) {
+ use_dma_bufferfill_mode = 0;
+ } else {
+ use_dma_ppb_du = 0;
+ use_dma_bufferfill_mode = 1;
+ }
+
+ /* DMA setup */
+ dev->data_requests = dma_pool_create("data_requests", NULL,
+ sizeof(struct udc_data_dma), 0, 0);
+ if (!dev->data_requests) {
+ DBG(dev, "can't get request data pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+
+ /* EP0 in dma regs = dev control regs */
+ dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+ /* dma desc for setup data */
+ dev->stp_requests = dma_pool_create("setup requests", NULL,
+ sizeof(struct udc_stp_dma), 0, 0);
+ if (!dev->stp_requests) {
+ DBG(dev, "can't get stp request pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+ /* setup */
+ td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+ if (td_stp == NULL) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+ /* data: 0 packets !? */
+ td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IX].td_phys);
+ if (td_data == NULL) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep[UDC_EP0OUT_IX].td = td_data;
+ return 0;
+
+finished:
+ return retval;
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+ struct pci_dev *pdev,
+ const struct pci_device_id *id
+)
+{
+ struct udc *dev;
+ unsigned long resource;
+ unsigned long len;
+ int retval = 0;
+
+ /* one udc only */
+ if (udc) {
+ dev_dbg(&pdev->dev, "already probed\n");
+ return -EBUSY;
+ }
+
+ /* init */
+ dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+ if (!dev) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ memset(dev, 0, sizeof(struct udc));
+
+ /* pci setup */
+ if (pci_enable_device(pdev) < 0) {
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev->active = 1;
+
+ /* PCI resource allocation */
+ resource = pci_resource_start(pdev, 0);
+ len = pci_resource_len(pdev, 0);
+
+ if (!request_mem_region(resource, len, name)) {
+ dev_dbg(&pdev->dev, "pci device used already\n");
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->mem_region = 1;
+
+ dev->virt_addr = ioremap_nocache(resource, len);
+ if (dev->virt_addr == NULL) {
+ dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+ retval = -EFAULT;
+ goto finished;
+ }
+
+ if (!pdev->irq) {
+ dev_err(&dev->pdev->dev, "irq not set\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+
+ if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+ dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->irq_registered = 1;
+
+ pci_set_drvdata(pdev, dev);
+
+ /* chip revision */
+ dev->chiprev = 0;
+
+ pci_set_master(pdev);
+ pci_set_mwi(pdev);
+
+ /* chip rev for Hs AMD5536 */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
+ /* init dma pools */
+ if (use_dma) {
+ retval = init_dma_pools(dev);
+ if (retval != 0)
+ goto finished;
+ }
+
+ dev->phys_addr = resource;
+ dev->irq = pdev->irq;
+ dev->pdev = pdev;
+ dev->gadget.dev.parent = &pdev->dev;
+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ /* general probing */
+ if (udc_probe(dev) == 0)
+ return 0;
+
+finished:
+ if (dev)
+ udc_pci_remove(pdev);
+ return retval;
+}
+
+/* general probe */
+static int udc_probe(struct udc *dev)
+{
+ char tmp[128];
+ u32 reg;
+ int retval;
+
+ /* mark timer as not initialized */
+ udc_timer.data = 0;
+ udc_pollstall_timer.data = 0;
+
+ /* device struct setup */
+ spin_lock_init(&dev->lock);
+ dev->gadget.ops = &udc_ops;
+
+ strcpy(dev->gadget.dev.bus_id, "gadget");
+ dev->gadget.dev.release = gadget_release;
+ dev->gadget.name = name;
+ dev->gadget.name = name;
+ dev->gadget.is_dualspeed = 1;
+
+ /* udc csr registers base */
+ dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+ /* dev registers base */
+ dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+ /* ep registers base */
+ dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+ /* fifo's base */
+ dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+ dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+ /* init registers, interrupts, ... */
+ startup_registers(dev);
+
+ dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+ snprintf(tmp, sizeof tmp, "%d", dev->irq);
+ dev_info(&dev->pdev->dev,
+ "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+ tmp, dev->phys_addr, dev->chiprev,
+ (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+ strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+ if (dev->chiprev == UDC_HSA0_REV) {
+ dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev_info(&dev->pdev->dev,
+ "driver version: %s(for Geode5536 B1)\n", tmp);
+ udc = dev;
+
+ retval = device_register(&dev->gadget.dev);
+ if (retval)
+ goto finished;
+
+ /* timer init */
+ init_timer(&udc_timer);
+ udc_timer.function = udc_timer_function;
+ udc_timer.data = 1;
+ /* timer pollstall init */
+ init_timer(&udc_pollstall_timer);
+ udc_pollstall_timer.function = udc_pollstall_timer_function;
+ udc_pollstall_timer.data = 1;
+
+ /* set SD */
+ reg = readl(&dev->regs->ctl);
+ reg |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(reg, &dev->regs->ctl);
+
+ /* print dev register info */
+ print_regs(dev);
+
+ return 0;
+
+finished:
+ return retval;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+ unsigned long flags;
+ u32 tmp;
+
+ DBG(dev, "UDC initiates remote wakeup\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+ tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class_mask = 0xffffffff,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+ .name = (char *) name,
+ .id_table = pci_id,
+ .probe = udc_pci_probe,
+ .remove = udc_pci_remove,
+};
+
+/* Inits driver */
+static int __init init(void)
+{
+ return pci_register_driver(&udc_pci_driver);
+}
+module_init(init);
+
+/* Cleans driver */
+static void __exit cleanup(void)
+{
+ pci_unregister_driver(&udc_pci_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644
index 00000000000..4bbabbbfc93
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -0,0 +1,626 @@
+/*
+ * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef AMD5536UDC_H
+#define AMD5536UDC_H
+
+/* various constants */
+#define UDC_RDE_TIMER_SECONDS 1
+#define UDC_RDE_TIMER_DIV 10
+#define UDC_POLLSTALL_TIMER_USECONDS 500
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/*
+ * SETUP usb commands
+ * needed, because some SETUP's are handled in hw, but must be passed to
+ * gadget driver above
+ * SET_CONFIG
+ */
+#define UDC_SETCONFIG_DWORD0 0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK 0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS 16
+
+#define UDC_SETCONFIG_DWORD1 0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0 0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK 0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS 16
+
+#define UDC_SETINTF_DWORD1 0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK 0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS 0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0 0x0000ff21
+#define UDC_MSCRES_DWORD1 0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+#define UDC_CSR_ADDR 0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK 0x0000000f
+#define UDC_CSR_NE_NUM_OFS 0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK 0x00000010
+#define UDC_CSR_NE_DIR_OFS 4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK 0x00000060
+#define UDC_CSR_NE_TYPE_OFS 5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK 0x00000780
+#define UDC_CSR_NE_CFG_OFS 7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK 0x00007800
+#define UDC_CSR_NE_INTF_OFS 11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK 0x00078000
+#define UDC_CSR_NE_ALT_OFS 15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS 19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR 0x400
+
+#define UDC_DEVCFG_SOFTRESET 31
+#define UDC_DEVCFG_HNPSFEN 30
+#define UDC_DEVCFG_DMARST 29
+#define UDC_DEVCFG_SET_DESC 18
+#define UDC_DEVCFG_CSR_PRG 17
+#define UDC_DEVCFG_STATUS 7
+#define UDC_DEVCFG_DIR 6
+#define UDC_DEVCFG_PI 5
+#define UDC_DEVCFG_SS 4
+#define UDC_DEVCFG_SP 3
+#define UDC_DEVCFG_RWKP 2
+
+#define UDC_DEVCFG_SPD_MASK 0x3
+#define UDC_DEVCFG_SPD_OFS 0
+#define UDC_DEVCFG_SPD_HS 0x0
+#define UDC_DEVCFG_SPD_FS 0x1
+#define UDC_DEVCFG_SPD_LS 0x2
+/*#define UDC_DEVCFG_SPD_FS 0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR 0x404
+
+#define UDC_DEVCTL_THLEN_MASK 0xff000000
+#define UDC_DEVCTL_THLEN_OFS 24
+
+#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS 16
+
+#define UDC_DEVCTL_CSR_DONE 13
+#define UDC_DEVCTL_DEVNAK 12
+#define UDC_DEVCTL_SD 10
+#define UDC_DEVCTL_MODE 9
+#define UDC_DEVCTL_BREN 8
+#define UDC_DEVCTL_THE 7
+#define UDC_DEVCTL_BF 6
+#define UDC_DEVCTL_BE 5
+#define UDC_DEVCTL_DU 4
+#define UDC_DEVCTL_TDE 3
+#define UDC_DEVCTL_RDE 2
+#define UDC_DEVCTL_RES 0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR 0x408
+
+#define UDC_DEVSTS_TS_MASK 0xfffc0000
+#define UDC_DEVSTS_TS_OFS 18
+
+#define UDC_DEVSTS_SESSVLD 17
+#define UDC_DEVSTS_PHY_ERROR 16
+#define UDC_DEVSTS_RXFIFO_EMPTY 15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS 13
+#define UDC_DEVSTS_ENUM_SPEED_FULL 1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH 0
+
+#define UDC_DEVSTS_SUSP 12
+
+#define UDC_DEVSTS_ALT_MASK 0x00000f00
+#define UDC_DEVSTS_ALT_OFS 8
+
+#define UDC_DEVSTS_INTF_MASK 0x000000f0
+#define UDC_DEVSTS_INTF_OFS 4
+
+#define UDC_DEVSTS_CFG_MASK 0x0000000f
+#define UDC_DEVSTS_CFG_OFS 0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR 0x40c
+
+#define UDC_DEVINT_SVC 7
+#define UDC_DEVINT_ENUM 6
+#define UDC_DEVINT_SOF 5
+#define UDC_DEVINT_US 4
+#define UDC_DEVINT_UR 3
+#define UDC_DEVINT_ES 2
+#define UDC_DEVINT_SI 1
+#define UDC_DEVINT_SC 0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR 0x410
+
+#define UDC_DEVINT_MSK 0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR 0x414
+
+#define UDC_EPINT_OUT_MASK 0xffff0000
+#define UDC_EPINT_OUT_OFS 16
+#define UDC_EPINT_IN_MASK 0x0000ffff
+#define UDC_EPINT_IN_OFS 0
+
+#define UDC_EPINT_IN_EP0 0
+#define UDC_EPINT_IN_EP1 1
+#define UDC_EPINT_IN_EP2 2
+#define UDC_EPINT_IN_EP3 3
+#define UDC_EPINT_OUT_EP0 16
+#define UDC_EPINT_OUT_EP1 17
+#define UDC_EPINT_OUT_EP2 18
+#define UDC_EPINT_OUT_EP3 19
+
+#define UDC_EPINT_EP0_ENABLE_MSK 0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR 0x418
+
+#define UDC_EPINT_OUT_MSK_MASK 0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS 16
+#define UDC_EPINT_IN_MSK_MASK 0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS 0
+
+#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE 0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+#define UDC_EPREGS_ADDR 0x0
+#define UDC_EPIN_REGS_ADDR 0x0
+#define UDC_EPOUT_REGS_ADDR 0x200
+
+#define UDC_EPCTL_ADDR 0x0
+
+#define UDC_EPCTL_RRDY 9
+#define UDC_EPCTL_CNAK 8
+#define UDC_EPCTL_SNAK 7
+#define UDC_EPCTL_NAK 6
+
+#define UDC_EPCTL_ET_MASK 0x00000030
+#define UDC_EPCTL_ET_OFS 4
+#define UDC_EPCTL_ET_CONTROL 0
+#define UDC_EPCTL_ET_ISO 1
+#define UDC_EPCTL_ET_BULK 2
+#define UDC_EPCTL_ET_INTERRUPT 3
+
+#define UDC_EPCTL_P 3
+#define UDC_EPCTL_SN 2
+#define UDC_EPCTL_F 1
+#define UDC_EPCTL_S 0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR 0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS 11
+
+#define UDC_EPSTS_TDC 10
+#define UDC_EPSTS_HE 9
+#define UDC_EPSTS_BNA 7
+#define UDC_EPSTS_IN 6
+
+#define UDC_EPSTS_OUT_MASK 0x00000030
+#define UDC_EPSTS_OUT_OFS 4
+#define UDC_EPSTS_OUT_DATA 1
+#define UDC_EPSTS_OUT_DATA_CLEAR 0x10
+#define UDC_EPSTS_OUT_SETUP 2
+#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20
+#define UDC_EPSTS_OUT_CLEAR 0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR 0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS 0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE 32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE 32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT 2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE 256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE 32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE 32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS 0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS 16
+#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS 0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE 64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE 64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE 64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64
+
+/*
+ * Endpoint dma descriptors ------------------------------------------------
+ *
+ * Setup data, Status dword
+ */
+#define UDC_DMA_STP_STS_CFG_MASK 0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS 16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK 0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS 16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK 0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS 20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK 0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS 24
+#define UDC_DMA_STP_STS_RX_MASK 0x30000000
+#define UDC_DMA_STP_STS_RX_OFS 28
+#define UDC_DMA_STP_STS_BS_MASK 0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS 30
+#define UDC_DMA_STP_STS_BS_HOST_READY 0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY 1
+#define UDC_DMA_STP_STS_BS_DMA_DONE 2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY 3
+/* IN data, Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK 0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS 0
+#define UDC_DMA_IN_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS 0
+#define UDC_DMA_IN_STS_L 27
+#define UDC_DMA_IN_STS_TX_MASK 0x30000000
+#define UDC_DMA_IN_STS_TX_OFS 28
+#define UDC_DMA_IN_STS_BS_MASK 0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS 30
+#define UDC_DMA_IN_STS_BS_HOST_READY 0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY 1
+#define UDC_DMA_IN_STS_BS_DMA_DONE 2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY 3
+/* OUT data, Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK 0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS 0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS 0
+#define UDC_DMA_OUT_STS_L 27
+#define UDC_DMA_OUT_STS_RX_MASK 0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS 28
+#define UDC_DMA_OUT_STS_BS_MASK 0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS 30
+#define UDC_DMA_OUT_STS_BS_HOST_READY 0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY 1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE 2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY 3
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET 1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET 65536
+
+/* un-usable DMA address */
+#define DMA_DONT_USE (~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR 0x10
+#define UDC_EP_DESPTR_ADDR 0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR 0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM 32
+#define UDC_EPIN_NUM 16
+#define UDC_EPIN_NUM_USED 5
+#define UDC_EPOUT_NUM 16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM 9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS 12
+
+#define UDC_EP0OUT_IX 16
+#define UDC_EP0IN_IX 0
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR 0x800
+#define UDC_RXFIFO_SIZE 0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR 0xc00
+#define UDC_TXFIFO_SIZE 0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX 1
+#define UDC_EPIN_IX 2
+#define UDC_EPOUT_IX 18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES 4
+#define UDC_BITS_PER_BYTE_SHIFT 3
+#define UDC_BYTE_MASK 0xff
+#define UDC_BITS_PER_BYTE 8
+
+/*---------------------------------------------------------------------------*/
+/* UDC CSR's */
+struct udc_csrs {
+
+ /* sca - setup command address */
+ u32 sca;
+
+ /* ep ne's */
+ u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+ /* device configuration */
+ u32 cfg;
+
+ /* device control */
+ u32 ctl;
+
+ /* device status */
+ u32 sts;
+
+ /* device interrupt */
+ u32 irqsts;
+
+ /* device interrupt mask */
+ u32 irqmsk;
+
+ /* endpoint interrupt */
+ u32 ep_irqsts;
+
+ /* endpoint interrupt mask */
+ u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+ /* endpoint control */
+ u32 ctl;
+
+ /* endpoint status */
+ u32 sts;
+
+ /* endpoint buffer size in/ receive packet frame number out */
+ u32 bufin_framenum;
+
+ /* endpoint buffer size out/max packet size */
+ u32 bufout_maxpkt;
+
+ /* endpoint setup buffer pointer */
+ u32 subptr;
+
+ /* endpoint data descriptor pointer */
+ u32 desptr;
+
+ /* reserverd */
+ u32 reserved;
+
+ /* write/read confirmation */
+ u32 confirm;
+
+} __attribute__ ((packed));
+
+/* control data DMA desc */
+struct udc_stp_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* first setup word */
+ u32 data12;
+ /* second setup word */
+ u32 data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* buffer pointer */
+ u32 bufptr;
+ /* next descriptor pointer */
+ u32 next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+ /* embedded gadget ep */
+ struct usb_request req;
+
+ /* flags */
+ unsigned dma_going : 1,
+ dma_mapping : 1,
+ dma_done : 1;
+ /* phys. address */
+ dma_addr_t td_phys;
+ /* first dma desc. of chain */
+ struct udc_data_dma *td_data;
+ /* last dma desc. of chain */
+ struct udc_data_dma *td_data_last;
+ struct list_head queue;
+
+ /* chain length */
+ unsigned chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+ struct usb_ep ep;
+ struct udc_ep_regs __iomem *regs;
+ u32 __iomem *txfifo;
+ u32 __iomem *dma;
+ dma_addr_t td_phys;
+ dma_addr_t td_stp_dma;
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td;
+ /* temp request */
+ struct udc_request *req;
+ unsigned req_used;
+ unsigned req_completed;
+ /* dummy DMA desc for BNA dummy */
+ struct udc_request *bna_dummy_req;
+ unsigned bna_occurred;
+
+ /* NAK state */
+ unsigned naking;
+
+ struct udc *dev;
+
+ /* queue for requests */
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+ unsigned halted;
+ unsigned cancel_transfer;
+ unsigned num : 5,
+ fifo_depth : 14,
+ in : 1;
+};
+
+/* device struct */
+struct udc {
+ struct usb_gadget gadget;
+ spinlock_t lock; /* protects all state */
+ /* all endpoints */
+ struct udc_ep ep[UDC_EP_NUM];
+ struct usb_gadget_driver *driver;
+ /* operational flags */
+ unsigned active : 1,
+ stall_ep0in : 1,
+ waiting_zlp_ack_ep0in : 1,
+ set_cfg_not_acked : 1,
+ irq_registered : 1,
+ data_ep_enabled : 1,
+ data_ep_queued : 1,
+ mem_region : 1,
+ sys_suspended : 1,
+ connected;
+
+ u16 chiprev;
+
+ /* registers */
+ struct pci_dev *pdev;
+ struct udc_csrs __iomem *csr;
+ struct udc_regs __iomem *regs;
+ struct udc_ep_regs __iomem *ep_regs;
+ u32 __iomem *rxfifo;
+ u32 __iomem *txfifo;
+
+ /* DMA desc pools */
+ struct pci_pool *data_requests;
+ struct pci_pool *stp_requests;
+
+ /* device data */
+ unsigned long phys_addr;
+ void __iomem *virt_addr;
+ unsigned irq;
+
+ /* states */
+ u16 cur_config;
+ u16 cur_intf;
+ u16 cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+ u32 data[2];
+ struct usb_ctrlrequest request;
+};
+
+/*
+ *---------------------------------------------------------------------------
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ *
+ * set bitfield value in u32 u32Val
+ */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name) \
+ (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK)))) \
+ | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/*
+ * set bitfield value in zero-initialized u32 u32Val
+ * => bitfield bits in u32Val are all zero
+ */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name) \
+ ((u32Val) \
+ | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name) \
+ ((u32Val & ((u32) bitfield_stub_name##_MASK)) \
+ >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* debug macros ------------------------------------------------------------*/
+
+#define DBG(udc , args...) dev_dbg(&(udc)->pdev->dev, args)
+
+#ifdef UDC_VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(udc , args...) do {} while (0)
+#endif
+
+#endif /* #ifdef AMD5536UDC_H */
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index ba163f35bf2..63d7d656869 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -601,25 +601,6 @@ static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
-static void *at91_ep_alloc_buffer(
- struct usb_ep *_ep,
- unsigned bytes,
- dma_addr_t *dma,
- gfp_t gfp_flags)
-{
- *dma = ~0;
- return kmalloc(bytes, gfp_flags);
-}
-
-static void at91_ep_free_buffer(
- struct usb_ep *ep,
- void *buf,
- dma_addr_t dma,
- unsigned bytes)
-{
- kfree(buf);
-}
-
static int at91_ep_queue(struct usb_ep *_ep,
struct usb_request *_req, gfp_t gfp_flags)
{
@@ -788,8 +769,6 @@ static const struct usb_ep_ops at91_ep_ops = {
.disable = at91_ep_disable,
.alloc_request = at91_ep_alloc_request,
.free_request = at91_ep_free_request,
- .alloc_buffer = at91_ep_alloc_buffer,
- .free_buffer = at91_ep_free_buffer,
.queue = at91_ep_queue,
.dequeue = at91_ep_dequeue,
.set_halt = at91_ep_set_halt,
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index fcb5526cb08..f2fbdc7fe37 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -497,38 +497,6 @@ dummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
kfree (req);
}
-static void *
-dummy_alloc_buffer (
- struct usb_ep *_ep,
- unsigned bytes,
- dma_addr_t *dma,
- gfp_t mem_flags
-) {
- char *retval;
- struct dummy_ep *ep;
- struct dummy *dum;
-
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
-
- if (!dum->driver)
- return NULL;
- retval = kmalloc (bytes, mem_flags);
- *dma = (dma_addr_t) retval;
- return retval;
-}
-
-static void
-dummy_free_buffer (
- struct usb_ep *_ep,
- void *buf,
- dma_addr_t dma,
- unsigned bytes
-) {
- if (bytes)
- kfree (buf);
-}
-
static void
fifo_complete (struct usb_ep *ep, struct usb_request *req)
{
@@ -659,10 +627,6 @@ static const struct usb_ep_ops dummy_ep_ops = {
.alloc_request = dummy_alloc_request,
.free_request = dummy_free_request,
- .alloc_buffer = dummy_alloc_buffer,
- .free_buffer = dummy_free_buffer,
- /* map, unmap, ... eventually hook the "generic" dma calls */
-
.queue = dummy_queue,
.dequeue = dummy_dequeue,
@@ -1784,8 +1748,7 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
spin_lock_irq (&dum->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- dev_warn (&hcd->self.root_hub->dev, "HC isn't running!\n");
- rc = -ENODEV;
+ rc = -ESHUTDOWN;
} else {
dum->rh_state = DUMMY_RH_RUNNING;
set_link_state (dum);
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 325bf7cfb83..a3376739a81 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -277,7 +277,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
#define DEV_CONFIG_CDC
#endif
@@ -292,7 +292,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
-#ifdef CONFIG_USB_GADGET_SH
+#ifdef CONFIG_USB_GADGET_SUPERH
#define DEV_CONFIG_SUBSET
#endif
@@ -301,6 +301,14 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
+#ifdef CONFIG_USB_GADGET_M66592
+#define DEV_CONFIG_CDC
+#endif
+
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define DEV_CONFIG_CDC
+#endif
+
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index c6b6479fa4d..be7a1bd2823 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -686,7 +686,6 @@ struct fsg_dev {
int thread_wakeup_needed;
struct completion thread_notifier;
struct task_struct *thread_task;
- sigset_t thread_signal_mask;
int cmnd_size;
u8 cmnd[MAX_COMMAND_SIZE];
@@ -3277,8 +3276,7 @@ static void handle_exception(struct fsg_dev *fsg)
/* Clear the existing signals. Anything but SIGUSR1 is converted
* into a high-priority EXIT exception. */
for (;;) {
- sig = dequeue_signal_lock(current, &fsg->thread_signal_mask,
- &info);
+ sig = dequeue_signal_lock(current, &current->blocked, &info);
if (!sig)
break;
if (sig != SIGUSR1) {
@@ -3431,10 +3429,13 @@ static int fsg_main_thread(void *fsg_)
/* Allow the thread to be killed by a signal, but set the signal mask
* to block everything but INT, TERM, KILL, and USR1. */
- siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) |
- sigmask(SIGTERM) | sigmask(SIGKILL) |
- sigmask(SIGUSR1));
- sigprocmask(SIG_SETMASK, &fsg->thread_signal_mask, NULL);
+ allow_signal(SIGINT);
+ allow_signal(SIGTERM);
+ allow_signal(SIGKILL);
+ allow_signal(SIGUSR1);
+
+ /* Allow the thread to be frozen */
+ set_freezable();
/* Arrange for userspace references to be interpreted as kernel
* pointers. That way we can pass a kernel pointer to a routine
@@ -3735,19 +3736,12 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
}
/* Free the data buffers */
- for (i = 0; i < NUM_BUFFERS; ++i) {
- struct fsg_buffhd *bh = &fsg->buffhds[i];
-
- if (bh->buf)
- usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma,
- mod_data.buflen);
- }
+ for (i = 0; i < NUM_BUFFERS; ++i)
+ kfree(fsg->buffhds[i].buf);
/* Free the request and buffer for endpoint 0 */
if (req) {
- if (req->buf)
- usb_ep_free_buffer(fsg->ep0, req->buf,
- req->dma, EP0_BUFSIZE);
+ kfree(req->buf);
usb_ep_free_request(fsg->ep0, req);
}
@@ -3965,8 +3959,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
#endif
if (gadget->is_otg) {
- otg_desc.bmAttributes |= USB_OTG_HNP,
- config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ otg_desc.bmAttributes |= USB_OTG_HNP;
}
rc = -ENOMEM;
@@ -3975,8 +3968,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
if (!req)
goto out;
- req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE,
- &req->dma, GFP_KERNEL);
+ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
if (!req->buf)
goto out;
req->complete = ep0_complete;
@@ -3988,8 +3980,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Allocate for the bulk-in endpoint. We assume that
* the buffer will also work with the bulk-out (and
* interrupt-in) endpoint. */
- bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen,
- &bh->dma, GFP_KERNEL);
+ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
if (!bh->buf)
goto out;
bh->next = bh + 1;
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 3ca2b3159f0..10b2b33b869 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -228,7 +228,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
/* Config PHY interface */
portctrl = fsl_readl(&dr_regs->portsc1);
- portctrl &= ~(PORTSCX_PHY_TYPE_SEL & PORTSCX_PORT_WIDTH);
+ portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
switch (udc->phy_mode) {
case FSL_USB2_PHY_ULPI:
portctrl |= PORTSCX_PTS_ULPI;
@@ -601,39 +601,6 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
-/*------------------------------------------------------------------
- * Allocate an I/O buffer
-*---------------------------------------------------------------------*/
-static void *fsl_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, gfp_t gfp_flags)
-{
- struct fsl_ep *ep;
-
- if (!_ep)
- return NULL;
-
- ep = container_of(_ep, struct fsl_ep, ep);
-
- return dma_alloc_coherent(ep->udc->gadget.dev.parent,
- bytes, dma, gfp_flags);
-}
-
-/*------------------------------------------------------------------
- * frees an i/o buffer
-*---------------------------------------------------------------------*/
-static void fsl_free_buffer(struct usb_ep *_ep, void *buf,
- dma_addr_t dma, unsigned bytes)
-{
- struct fsl_ep *ep;
-
- if (!_ep)
- return;
-
- ep = container_of(_ep, struct fsl_ep, ep);
-
- dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma);
-}
-
/*-------------------------------------------------------------------------*/
static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
{
@@ -1047,9 +1014,6 @@ static struct usb_ep_ops fsl_ep_ops = {
.alloc_request = fsl_alloc_request,
.free_request = fsl_free_request,
- .alloc_buffer = fsl_alloc_buffer,
- .free_buffer = fsl_free_buffer,
-
.queue = fsl_ep_queue,
.dequeue = fsl_ep_dequeue,
@@ -2189,27 +2153,19 @@ static void fsl_udc_release(struct device *dev)
* init resource for globle controller
* Return the udc handle on success or NULL on failure
------------------------------------------------------------------*/
-static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
+static int __init struct_udc_setup(struct fsl_udc *udc,
+ struct platform_device *pdev)
{
- struct fsl_udc *udc;
struct fsl_usb2_platform_data *pdata;
size_t size;
- udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
- if (udc == NULL) {
- ERR("malloc udc failed\n");
- return NULL;
- }
-
pdata = pdev->dev.platform_data;
udc->phy_mode = pdata->phy_mode;
- /* max_ep_nr is bidirectional ep number, max_ep doubles the number */
- udc->max_ep = pdata->max_ep_nr * 2;
udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
if (!udc->eps) {
ERR("malloc fsl_ep failed\n");
- goto cleanup;
+ return -1;
}
/* initialized QHs, take care of alignment */
@@ -2225,7 +2181,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
if (!udc->ep_qh) {
ERR("malloc QHs for udc failed\n");
kfree(udc->eps);
- goto cleanup;
+ return -1;
}
udc->ep_qh_size = size;
@@ -2244,11 +2200,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
udc->remote_wakeup = 0; /* default to 0 on reset */
spin_lock_init(&udc->lock);
- return udc;
-
-cleanup:
- kfree(udc);
- return NULL;
+ return 0;
}
/*----------------------------------------------------------------
@@ -2287,35 +2239,37 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
}
/* Driver probe function
- * all intialize operations implemented here except enabling usb_intr reg
+ * all intialization operations implemented here except enabling usb_intr reg
+ * board setup should have been done in the platform code
*/
static int __init fsl_udc_probe(struct platform_device *pdev)
{
struct resource *res;
int ret = -ENODEV;
unsigned int i;
+ u32 dccparams;
if (strcmp(pdev->name, driver_name)) {
VDBG("Wrong device\n");
return -ENODEV;
}
- /* board setup should have been done in the platform code */
-
- /* Initialize the udc structure including QH member and other member */
- udc_controller = struct_udc_setup(pdev);
- if (!udc_controller) {
- VDBG("udc_controller is NULL \n");
+ udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
+ if (udc_controller == NULL) {
+ ERR("malloc udc failed\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
+ if (!res) {
+ kfree(udc_controller);
return -ENXIO;
+ }
if (!request_mem_region(res->start, res->end - res->start + 1,
driver_name)) {
ERR("request mem region for %s failed \n", pdev->name);
+ kfree(udc_controller);
return -EBUSY;
}
@@ -2328,13 +2282,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
usb_sys_regs = (struct usb_sys_interface *)
((u32)dr_regs + USB_DR_SYS_OFFSET);
+ /* Read Device Controller Capability Parameters register */
+ dccparams = fsl_readl(&dr_regs->dccparams);
+ if (!(dccparams & DCCPARAMS_DC)) {
+ ERR("This SOC doesn't support device role\n");
+ ret = -ENODEV;
+ goto err2;
+ }
+ /* Get max device endpoints */
+ /* DEN is bidirectional ep number, max_ep doubles the number */
+ udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
+
udc_controller->irq = platform_get_irq(pdev, 0);
if (!udc_controller->irq) {
ret = -ENODEV;
goto err2;
}
- ret = request_irq(udc_controller->irq, fsl_udc_irq, SA_SHIRQ,
+ ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
driver_name, udc_controller);
if (ret != 0) {
ERR("cannot request irq %d err %d \n",
@@ -2342,6 +2307,13 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
goto err2;
}
+ /* Initialize the udc structure including QH member and other member */
+ if (struct_udc_setup(udc_controller, pdev)) {
+ ERR("Can't initialize udc data structure\n");
+ ret = -ENOMEM;
+ goto err3;
+ }
+
/* initialize usb hw reg except for regs for EP,
* leave usbintr reg untouched */
dr_controller_setup(udc_controller);
@@ -2403,6 +2375,7 @@ err2:
iounmap(dr_regs);
err1:
release_mem_region(res->start, res->end - res->start + 1);
+ kfree(udc_controller);
return ret;
}
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index c6291e04650..832ab82b488 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -101,6 +101,10 @@ struct usb_sys_interface {
#define WAIT_FOR_OUT_STATUS 3
#define DATA_STATE_RECV 4
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_DC 0x00000080
+#define DCCPARAMS_DEN_MASK 0x0000001f
+
/* Frame Index Register Bit Masks */
#define USB_FRINDEX_MASKS 0x3fff
/* USB CMD Register Bit Masks */
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index d041b919e7b..f7f159c1002 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -8,6 +8,8 @@
* (And avoiding all runtime comparisons in typical one-choice configs!)
*
* NOTE: some of these controller drivers may not be available yet.
+ * Some are available on 2.4 kernels; several are available, but not
+ * yet pushed in the 2.6 mainline tree.
*/
#ifdef CONFIG_USB_GADGET_NET2280
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
@@ -15,6 +17,12 @@
#define gadget_is_net2280(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
+#else
+#define gadget_is_amd5536udc(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_DUMMY_HCD
#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name)
#else
@@ -33,12 +41,14 @@
#define gadget_is_goku(g) 0
#endif
+/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
#ifdef CONFIG_USB_GADGET_SUPERH
#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name)
#else
#define gadget_is_sh(g) 0
#endif
+/* not yet stable on 2.6 (would help "original Zaurus") */
#ifdef CONFIG_USB_GADGET_SA1100
#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name)
#else
@@ -51,6 +61,7 @@
#define gadget_is_lh7a40x(g) 0
#endif
+/* handhelds.org tree (?) */
#ifdef CONFIG_USB_GADGET_MQ11XX
#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
#else
@@ -63,22 +74,24 @@
#define gadget_is_omap(g) 0
#endif
+/* not yet ported 2.4 --> 2.6 */
#ifdef CONFIG_USB_GADGET_N9604
#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
#else
#define gadget_is_n9604(g) 0
#endif
+/* various unstable versions available */
#ifdef CONFIG_USB_GADGET_PXA27X
#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
#else
#define gadget_is_pxa27x(g) 0
#endif
-#ifdef CONFIG_USB_GADGET_HUSB2DEV
-#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name)
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name)
#else
-#define gadget_is_husb2dev(g) 0
+#define gadget_is_atmel_usba(g) 0
#endif
#ifdef CONFIG_USB_GADGET_S3C2410
@@ -93,6 +106,7 @@
#define gadget_is_at91(g) 0
#endif
+/* status unclear */
#ifdef CONFIG_USB_GADGET_IMX
#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name)
#else
@@ -106,6 +120,7 @@
#endif
/* Mentor high speed function controller */
+/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MUSBHSFC
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
#else
@@ -119,12 +134,20 @@
#define gadget_is_musbhdrc(g) 0
#endif
+/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MPC8272
#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
#else
#define gadget_is_mpc8272(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_M66592
+#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name)
+#else
+#define gadget_is_m66592(g) 0
+#endif
+
+
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
// ...
@@ -181,9 +204,13 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
- else if (gadget_is_husb2dev(gadget))
+ else if (gadget_is_atmel_usba(gadget))
return 0x18;
else if (gadget_is_fsl_usb2(gadget))
return 0x19;
+ else if (gadget_is_amd5536udc(gadget))
+ return 0x20;
+ else if (gadget_is_m66592(gadget))
+ return 0x21;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index d08a8d0e642..1c5aa49d743 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -1248,17 +1248,11 @@ autoconf_fail:
tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
/* preallocate control response and buffer */
- dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+ dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ);
if (!dev->req) {
err = -ENOMEM;
goto fail;
}
- dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ,
- &dev->req->dma, GFP_KERNEL);
- if (!dev->req->buf) {
- err = -ENOMEM;
- goto fail;
- }
dev->req->complete = gmidi_setup_complete;
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index ae931af05ce..349b8166f34 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -20,7 +20,6 @@
* - DMA works with ep1 (OUT transfers) and ep2 (IN transfers).
*/
-#undef DEBUG
// #define VERBOSE /* extra debug messages (success too) */
// #define USB_TRACE /* packet-level success messages */
@@ -296,51 +295,6 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
-/* allocating buffers this way eliminates dma mapping overhead, which
- * on some platforms will mean eliminating a per-io buffer copy. with
- * some kinds of system caches, further tweaks may still be needed.
- */
-static void *
-goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, gfp_t gfp_flags)
-{
- void *retval;
- struct goku_ep *ep;
-
- ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep)
- return NULL;
- *dma = DMA_ADDR_INVALID;
-
- if (ep->dma) {
- /* the main problem with this call is that it wastes memory
- * on typical 1/N page allocations: it allocates 1-N pages.
- */
-#warning Using dma_alloc_coherent even with buffers smaller than a page.
- retval = dma_alloc_coherent(&ep->dev->pdev->dev,
- bytes, dma, gfp_flags);
- } else
- retval = kmalloc(bytes, gfp_flags);
- return retval;
-}
-
-static void
-goku_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes)
-{
- /* free memory into the right allocator */
- if (dma != DMA_ADDR_INVALID) {
- struct goku_ep *ep;
-
- ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep)
- return;
- dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
- } else
- kfree (buf);
-}
-
-/*-------------------------------------------------------------------------*/
-
static void
done(struct goku_ep *ep, struct goku_request *req, int status)
{
@@ -485,7 +439,7 @@ top:
/* use ep1/ep2 double-buffering for OUT */
if (!(size & PACKET_ACTIVE))
size = readl(&regs->EPxSizeLB[ep->num]);
- if (!(size & PACKET_ACTIVE)) // "can't happen"
+ if (!(size & PACKET_ACTIVE)) /* "can't happen" */
break;
size &= DATASIZE; /* EPxSizeH == 0 */
@@ -1026,9 +980,6 @@ static struct usb_ep_ops goku_ep_ops = {
.alloc_request = goku_alloc_request,
.free_request = goku_free_request,
- .alloc_buffer = goku_alloc_buffer,
- .free_buffer = goku_free_buffer,
-
.queue = goku_queue,
.dequeue = goku_dequeue,
@@ -1140,17 +1091,17 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
is_usb_connected
? ((tmp & PW_PULLUP) ? "full speed" : "powered")
: "disconnected",
- ({char *tmp;
+ ({char *state;
switch(dev->ep0state){
- case EP0_DISCONNECT: tmp = "ep0_disconnect"; break;
- case EP0_IDLE: tmp = "ep0_idle"; break;
- case EP0_IN: tmp = "ep0_in"; break;
- case EP0_OUT: tmp = "ep0_out"; break;
- case EP0_STATUS: tmp = "ep0_status"; break;
- case EP0_STALL: tmp = "ep0_stall"; break;
- case EP0_SUSPEND: tmp = "ep0_suspend"; break;
- default: tmp = "ep0_?"; break;
- } tmp; })
+ case EP0_DISCONNECT: state = "ep0_disconnect"; break;
+ case EP0_IDLE: state = "ep0_idle"; break;
+ case EP0_IN: state = "ep0_in"; break;
+ case EP0_OUT: state = "ep0_out"; break;
+ case EP0_STATUS: state = "ep0_status"; break;
+ case EP0_STALL: state = "ep0_stall"; break;
+ case EP0_SUSPEND: state = "ep0_suspend"; break;
+ default: state = "ep0_?"; break;
+ } state; })
);
size -= t;
next += t;
@@ -1195,7 +1146,6 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
for (i = 0; i < 4; i++) {
struct goku_ep *ep = &dev->ep [i];
struct goku_request *req;
- int t;
if (i && !ep->desc)
continue;
@@ -1283,7 +1233,7 @@ done:
static void udc_reinit (struct goku_udc *dev)
{
static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" };
-
+
unsigned i;
INIT_LIST_HEAD (&dev->gadget.ep_list);
@@ -1827,14 +1777,13 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* alloc, and start init */
- dev = kmalloc (sizeof *dev, GFP_KERNEL);
+ dev = kzalloc (sizeof *dev, GFP_KERNEL);
if (dev == NULL){
pr_debug("enomem %s\n", pci_name(pdev));
retval = -ENOMEM;
goto done;
}
- memset(dev, 0, sizeof *dev);
spin_lock_init(&dev->lock);
dev->pdev = pdev;
dev->gadget.ops = &goku_ops;
@@ -1896,9 +1845,9 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* done */
the_controller = dev;
- device_register(&dev->gadget.dev);
-
- return 0;
+ retval = device_register(&dev->gadget.dev);
+ if (retval == 0)
+ return 0;
done:
if (dev)
@@ -1910,8 +1859,8 @@ done:
/*-------------------------------------------------------------------------*/
static struct pci_device_id pci_ids [] = { {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
- .class_mask = ~0,
+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class_mask = ~0,
.vendor = 0x102f, /* Toshiba */
.device = 0x0107, /* this UDC */
.subvendor = PCI_ANY_ID,
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index ea8c8e58cab..bc4eb1e0b50 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -41,8 +41,10 @@ struct goku_udc_regs {
#define INT_SYSERROR 0x40000
#define INT_PWRDETECT 0x80000
-#define INT_DEVWIDE (INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
-#define INT_EP0 (INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
+#define INT_DEVWIDE \
+ (INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
+#define INT_EP0 \
+ (INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
u32 dma_master;
#define MST_EOPB_DIS 0x0800
@@ -231,7 +233,7 @@ struct goku_request {
enum ep0state {
EP0_DISCONNECT, /* no host */
EP0_IDLE, /* between STATUS ack and SETUP report */
- EP0_IN, EP0_OUT, /* data stage */
+ EP0_IN, EP0_OUT, /* data stage */
EP0_STATUS, /* status stage */
EP0_STALL, /* data or status stages */
EP0_SUSPEND, /* usb suspend */
@@ -242,7 +244,7 @@ struct goku_udc {
struct usb_gadget gadget;
spinlock_t lock;
struct goku_ep ep[4];
- struct usb_gadget_driver *driver;
+ struct usb_gadget_driver *driver;
enum ep0state ep0state;
unsigned got_irq:1,
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 46d0e525274..e60745ffaf8 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -37,7 +37,7 @@
#include <linux/device.h>
#include <linux/moduleparam.h>
-#include <linux/usb_gadgetfs.h>
+#include <linux/usb/gadgetfs.h>
#include <linux/usb_gadget.h>
@@ -923,7 +923,7 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
struct dev_data *dev = ep->driver_data;
if (req->buf != dev->rbuf) {
- usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+ kfree(req->buf);
req->buf = dev->rbuf;
req->dma = DMA_ADDR_INVALID;
}
@@ -963,7 +963,7 @@ static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
return -EBUSY;
}
if (len > sizeof (dev->rbuf))
- req->buf = usb_ep_alloc_buffer (ep, len, &req->dma, GFP_ATOMIC);
+ req->buf = kmalloc(len, GFP_ATOMIC);
if (req->buf == 0) {
req->buf = dev->rbuf;
return -ENOMEM;
@@ -1505,7 +1505,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}
break;
-#ifndef CONFIG_USB_GADGETFS_PXA2XX
+#ifndef CONFIG_USB_GADGET_PXA2XX
/* PXA automagically handles this request too */
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != 0x80)
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index a0a73c08a34..e78c2ddc1f8 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -75,10 +75,6 @@ static int lh7a40x_ep_enable(struct usb_ep *ep,
static int lh7a40x_ep_disable(struct usb_ep *ep);
static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t);
static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *);
-static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *,
- gfp_t);
-static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t,
- unsigned);
static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t);
static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *);
static int lh7a40x_set_halt(struct usb_ep *ep, int);
@@ -104,9 +100,6 @@ static struct usb_ep_ops lh7a40x_ep_ops = {
.alloc_request = lh7a40x_alloc_request,
.free_request = lh7a40x_free_request,
- .alloc_buffer = lh7a40x_alloc_buffer,
- .free_buffer = lh7a40x_free_buffer,
-
.queue = lh7a40x_queue,
.dequeue = lh7a40x_dequeue,
@@ -1134,26 +1127,6 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req)
kfree(req);
}
-static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes,
- dma_addr_t * dma, gfp_t gfp_flags)
-{
- char *retval;
-
- DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags);
-
- retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM));
- if (retval)
- *dma = virt_to_bus(retval);
- return retval;
-}
-
-static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma,
- unsigned bytes)
-{
- DEBUG("%s, %p\n", __FUNCTION__, ep);
- kfree(buf);
-}
-
/** Queue one request
* Kickstart transfer if needed
* NOTE: Sets INDEX register
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
new file mode 100644
index 00000000000..700dda8a915
--- /dev/null
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -0,0 +1,1633 @@
+/*
+ * M66592 UDC (USB gadget)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+#include "m66592-udc.h"
+
+
+MODULE_DESCRIPTION("M66592 USB gadget driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+
+#define DRIVER_VERSION "29 May 2007"
+
+/* module parameters */
+static unsigned short clock = M66592_XTAL24;
+module_param(clock, ushort, 0644);
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+ "(default=16384)");
+
+static unsigned short vif = M66592_LDRV;
+module_param(vif, ushort, 0644);
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
+
+static unsigned short endian;
+module_param(endian, ushort, 0644);
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
+static unsigned short irq_sense = M66592_INTL;
+module_param(irq_sense, ushort, 0644);
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+ "(default=2)");
+
+static const char udc_name[] = "m66592_udc";
+static const char *m66592_ep_name[] = {
+ "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7"
+};
+
+static void disable_controller(struct m66592 *m66592);
+static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req);
+static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req);
+static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags);
+
+static void transfer_complete(struct m66592_ep *ep,
+ struct m66592_request *req, int status);
+
+/*-------------------------------------------------------------------------*/
+static inline u16 get_usb_speed(struct m66592 *m66592)
+{
+ return (m66592_read(m66592, M66592_DVSTCTR) & M66592_RHST);
+}
+
+static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
+ unsigned long reg)
+{
+ u16 tmp;
+
+ tmp = m66592_read(m66592, M66592_INTENB0);
+ m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
+ M66592_INTENB0);
+ m66592_bset(m66592, (1 << pipenum), reg);
+ m66592_write(m66592, tmp, M66592_INTENB0);
+}
+
+static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
+ unsigned long reg)
+{
+ u16 tmp;
+
+ tmp = m66592_read(m66592, M66592_INTENB0);
+ m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
+ M66592_INTENB0);
+ m66592_bclr(m66592, (1 << pipenum), reg);
+ m66592_write(m66592, tmp, M66592_INTENB0);
+}
+
+static void m66592_usb_connect(struct m66592 *m66592)
+{
+ m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
+ m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
+ M66592_INTENB0);
+ m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
+
+ m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
+}
+
+static void m66592_usb_disconnect(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
+{
+ m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
+ m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
+ M66592_INTENB0);
+ m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+
+ m66592->gadget.speed = USB_SPEED_UNKNOWN;
+ spin_unlock(&m66592->lock);
+ m66592->driver->disconnect(&m66592->gadget);
+ spin_lock(&m66592->lock);
+
+ disable_controller(m66592);
+ INIT_LIST_HEAD(&m66592->ep[0].queue);
+}
+
+static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
+{
+ u16 pid = 0;
+ unsigned long offset;
+
+ if (pipenum == 0)
+ pid = m66592_read(m66592, M66592_DCPCTR) & M66592_PID;
+ else if (pipenum < M66592_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ pid = m66592_read(m66592, offset) & M66592_PID;
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+
+ return pid;
+}
+
+static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
+ u16 pid)
+{
+ unsigned long offset;
+
+ if (pipenum == 0)
+ m66592_mdfy(m66592, pid, M66592_PID, M66592_DCPCTR);
+ else if (pipenum < M66592_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ m66592_mdfy(m66592, pid, M66592_PID, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+}
+
+static inline void pipe_start(struct m66592 *m66592, u16 pipenum)
+{
+ control_reg_set_pid(m66592, pipenum, M66592_PID_BUF);
+}
+
+static inline void pipe_stop(struct m66592 *m66592, u16 pipenum)
+{
+ control_reg_set_pid(m66592, pipenum, M66592_PID_NAK);
+}
+
+static inline void pipe_stall(struct m66592 *m66592, u16 pipenum)
+{
+ control_reg_set_pid(m66592, pipenum, M66592_PID_STALL);
+}
+
+static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum)
+{
+ u16 ret = 0;
+ unsigned long offset;
+
+ if (pipenum == 0)
+ ret = m66592_read(m66592, M66592_DCPCTR);
+ else if (pipenum < M66592_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ ret = m66592_read(m66592, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+
+ return ret;
+}
+
+static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum)
+{
+ unsigned long offset;
+
+ pipe_stop(m66592, pipenum);
+
+ if (pipenum == 0)
+ m66592_bset(m66592, M66592_SQCLR, M66592_DCPCTR);
+ else if (pipenum < M66592_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ m66592_bset(m66592, M66592_SQCLR, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum);
+}
+
+static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum)
+{
+ u16 tmp;
+ int size;
+
+ if (pipenum == 0) {
+ tmp = m66592_read(m66592, M66592_DCPCFG);
+ if ((tmp & M66592_CNTMD) != 0)
+ size = 256;
+ else {
+ tmp = m66592_read(m66592, M66592_DCPMAXP);
+ size = tmp & M66592_MAXP;
+ }
+ } else {
+ m66592_write(m66592, pipenum, M66592_PIPESEL);
+ tmp = m66592_read(m66592, M66592_PIPECFG);
+ if ((tmp & M66592_CNTMD) != 0) {
+ tmp = m66592_read(m66592, M66592_PIPEBUF);
+ size = ((tmp >> 10) + 1) * 64;
+ } else {
+ tmp = m66592_read(m66592, M66592_PIPEMAXP);
+ size = tmp & M66592_MXPS;
+ }
+ }
+
+ return size;
+}
+
+static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
+{
+ struct m66592_ep *ep = m66592->pipenum2ep[pipenum];
+
+ if (ep->use_dma)
+ return;
+
+ m66592_mdfy(m66592, pipenum, M66592_CURPIPE, ep->fifosel);
+
+ ndelay(450);
+
+ m66592_bset(m66592, M66592_MBW, ep->fifosel);
+}
+
+static int pipe_buffer_setting(struct m66592 *m66592,
+ struct m66592_pipe_info *info)
+{
+ u16 bufnum = 0, buf_bsize = 0;
+ u16 pipecfg = 0;
+
+ if (info->pipe == 0)
+ return -EINVAL;
+
+ m66592_write(m66592, info->pipe, M66592_PIPESEL);
+
+ if (info->dir_in)
+ pipecfg |= M66592_DIR;
+ pipecfg |= info->type;
+ pipecfg |= info->epnum;
+ switch (info->type) {
+ case M66592_INT:
+ bufnum = 4 + (info->pipe - M66592_BASE_PIPENUM_INT);
+ buf_bsize = 0;
+ break;
+ case M66592_BULK:
+ bufnum = m66592->bi_bufnum +
+ (info->pipe - M66592_BASE_PIPENUM_BULK) * 16;
+ m66592->bi_bufnum += 16;
+ buf_bsize = 7;
+ pipecfg |= M66592_DBLB;
+ if (!info->dir_in)
+ pipecfg |= M66592_SHTNAK;
+ break;
+ case M66592_ISO:
+ bufnum = m66592->bi_bufnum +
+ (info->pipe - M66592_BASE_PIPENUM_ISOC) * 16;
+ m66592->bi_bufnum += 16;
+ buf_bsize = 7;
+ break;
+ }
+ if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
+ printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
+ m66592->bi_bufnum);
+ return -ENOMEM;
+ }
+
+ m66592_write(m66592, pipecfg, M66592_PIPECFG);
+ m66592_write(m66592, (buf_bsize << 10) | (bufnum), M66592_PIPEBUF);
+ m66592_write(m66592, info->maxpacket, M66592_PIPEMAXP);
+ if (info->interval)
+ info->interval--;
+ m66592_write(m66592, info->interval, M66592_PIPEPERI);
+
+ return 0;
+}
+
+static void pipe_buffer_release(struct m66592 *m66592,
+ struct m66592_pipe_info *info)
+{
+ if (info->pipe == 0)
+ return;
+
+ switch (info->type) {
+ case M66592_BULK:
+ if (is_bulk_pipe(info->pipe))
+ m66592->bi_bufnum -= 16;
+ break;
+ case M66592_ISO:
+ if (is_isoc_pipe(info->pipe))
+ m66592->bi_bufnum -= 16;
+ break;
+ }
+
+ if (is_bulk_pipe(info->pipe)) {
+ m66592->bulk--;
+ } else if (is_interrupt_pipe(info->pipe))
+ m66592->interrupt--;
+ else if (is_isoc_pipe(info->pipe)) {
+ m66592->isochronous--;
+ if (info->type == M66592_BULK)
+ m66592->bulk--;
+ } else
+ printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
+ info->pipe);
+}
+
+static void pipe_initialize(struct m66592_ep *ep)
+{
+ struct m66592 *m66592 = ep->m66592;
+
+ m66592_mdfy(m66592, 0, M66592_CURPIPE, ep->fifosel);
+
+ m66592_write(m66592, M66592_ACLRM, ep->pipectr);
+ m66592_write(m66592, 0, ep->pipectr);
+ m66592_write(m66592, M66592_SQCLR, ep->pipectr);
+ if (ep->use_dma) {
+ m66592_mdfy(m66592, ep->pipenum, M66592_CURPIPE, ep->fifosel);
+
+ ndelay(450);
+
+ m66592_bset(m66592, M66592_MBW, ep->fifosel);
+ }
+}
+
+static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
+ const struct usb_endpoint_descriptor *desc,
+ u16 pipenum, int dma)
+{
+ if ((pipenum != 0) && dma) {
+ if (m66592->num_dma == 0) {
+ m66592->num_dma++;
+ ep->use_dma = 1;
+ ep->fifoaddr = M66592_D0FIFO;
+ ep->fifosel = M66592_D0FIFOSEL;
+ ep->fifoctr = M66592_D0FIFOCTR;
+ ep->fifotrn = M66592_D0FIFOTRN;
+ } else if (m66592->num_dma == 1) {
+ m66592->num_dma++;
+ ep->use_dma = 1;
+ ep->fifoaddr = M66592_D1FIFO;
+ ep->fifosel = M66592_D1FIFOSEL;
+ ep->fifoctr = M66592_D1FIFOCTR;
+ ep->fifotrn = M66592_D1FIFOTRN;
+ } else {
+ ep->use_dma = 0;
+ ep->fifoaddr = M66592_CFIFO;
+ ep->fifosel = M66592_CFIFOSEL;
+ ep->fifoctr = M66592_CFIFOCTR;
+ ep->fifotrn = 0;
+ }
+ } else {
+ ep->use_dma = 0;
+ ep->fifoaddr = M66592_CFIFO;
+ ep->fifosel = M66592_CFIFOSEL;
+ ep->fifoctr = M66592_CFIFOCTR;
+ ep->fifotrn = 0;
+ }
+
+ ep->pipectr = get_pipectr_addr(pipenum);
+ ep->pipenum = pipenum;
+ ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ m66592->pipenum2ep[pipenum] = ep;
+ m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
+ INIT_LIST_HEAD(&ep->queue);
+}
+
+static void m66592_ep_release(struct m66592_ep *ep)
+{
+ struct m66592 *m66592 = ep->m66592;
+ u16 pipenum = ep->pipenum;
+
+ if (pipenum == 0)
+ return;
+
+ if (ep->use_dma)
+ m66592->num_dma--;
+ ep->pipenum = 0;
+ ep->busy = 0;
+ ep->use_dma = 0;
+}
+
+static int alloc_pipe_config(struct m66592_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct m66592 *m66592 = ep->m66592;
+ struct m66592_pipe_info info;
+ int dma = 0;
+ int *counter;
+ int ret;
+
+ ep->desc = desc;
+
+ BUG_ON(ep->pipenum);
+
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (m66592->bulk >= M66592_MAX_NUM_BULK) {
+ if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
+ printk(KERN_ERR "bulk pipe is insufficient\n");
+ return -ENODEV;
+ } else {
+ info.pipe = M66592_BASE_PIPENUM_ISOC
+ + m66592->isochronous;
+ counter = &m66592->isochronous;
+ }
+ } else {
+ info.pipe = M66592_BASE_PIPENUM_BULK + m66592->bulk;
+ counter = &m66592->bulk;
+ }
+ info.type = M66592_BULK;
+ dma = 1;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ if (m66592->interrupt >= M66592_MAX_NUM_INT) {
+ printk(KERN_ERR "interrupt pipe is insufficient\n");
+ return -ENODEV;
+ }
+ info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt;
+ info.type = M66592_INT;
+ counter = &m66592->interrupt;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
+ printk(KERN_ERR "isochronous pipe is insufficient\n");
+ return -ENODEV;
+ }
+ info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous;
+ info.type = M66592_ISO;
+ counter = &m66592->isochronous;
+ break;
+ default:
+ printk(KERN_ERR "unexpect xfer type\n");
+ return -EINVAL;
+ }
+ ep->type = info.type;
+
+ info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ info.interval = desc->bInterval;
+ if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ info.dir_in = 1;
+ else
+ info.dir_in = 0;
+
+ ret = pipe_buffer_setting(m66592, &info);
+ if (ret < 0) {
+ printk(KERN_ERR "pipe_buffer_setting fail\n");
+ return ret;
+ }
+
+ (*counter)++;
+ if ((counter == &m66592->isochronous) && info.type == M66592_BULK)
+ m66592->bulk++;
+
+ m66592_ep_setting(m66592, ep, desc, info.pipe, dma);
+ pipe_initialize(ep);
+
+ return 0;
+}
+
+static int free_pipe_config(struct m66592_ep *ep)
+{
+ struct m66592 *m66592 = ep->m66592;
+ struct m66592_pipe_info info;
+
+ info.pipe = ep->pipenum;
+ info.type = ep->type;
+ pipe_buffer_release(m66592, &info);
+ m66592_ep_release(ep);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+static void pipe_irq_enable(struct m66592 *m66592, u16 pipenum)
+{
+ enable_irq_ready(m66592, pipenum);
+ enable_irq_nrdy(m66592, pipenum);
+}
+
+static void pipe_irq_disable(struct m66592 *m66592, u16 pipenum)
+{
+ disable_irq_ready(m66592, pipenum);
+ disable_irq_nrdy(m66592, pipenum);
+}
+
+/* if complete is true, gadget driver complete function is not call */
+static void control_end(struct m66592 *m66592, unsigned ccpl)
+{
+ m66592->ep[0].internal_ccpl = ccpl;
+ pipe_start(m66592, 0);
+ m66592_bset(m66592, M66592_CCPL, M66592_DCPCTR);
+}
+
+static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+ struct m66592 *m66592 = ep->m66592;
+
+ pipe_change(m66592, ep->pipenum);
+ m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
+ (M66592_ISEL | M66592_CURPIPE),
+ M66592_CFIFOSEL);
+ m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+ if (req->req.length == 0) {
+ m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+ pipe_start(m66592, 0);
+ transfer_complete(ep, req, 0);
+ } else {
+ m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS);
+ irq_ep0_write(ep, req);
+ }
+}
+
+static void start_packet_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+ struct m66592 *m66592 = ep->m66592;
+ u16 tmp;
+
+ pipe_change(m66592, ep->pipenum);
+ disable_irq_empty(m66592, ep->pipenum);
+ pipe_start(m66592, ep->pipenum);
+
+ tmp = m66592_read(m66592, ep->fifoctr);
+ if (unlikely((tmp & M66592_FRDY) == 0))
+ pipe_irq_enable(m66592, ep->pipenum);
+ else
+ irq_packet_write(ep, req);
+}
+
+static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
+{
+ struct m66592 *m66592 = ep->m66592;
+ u16 pipenum = ep->pipenum;
+
+ if (ep->pipenum == 0) {
+ m66592_mdfy(m66592, M66592_PIPE0,
+ (M66592_ISEL | M66592_CURPIPE),
+ M66592_CFIFOSEL);
+ m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+ pipe_start(m66592, pipenum);
+ pipe_irq_enable(m66592, pipenum);
+ } else {
+ if (ep->use_dma) {
+ m66592_bset(m66592, M66592_TRCLR, ep->fifosel);
+ pipe_change(m66592, pipenum);
+ m66592_bset(m66592, M66592_TRENB, ep->fifosel);
+ m66592_write(m66592,
+ (req->req.length + ep->ep.maxpacket - 1)
+ / ep->ep.maxpacket,
+ ep->fifotrn);
+ }
+ pipe_start(m66592, pipenum); /* trigger once */
+ pipe_irq_enable(m66592, pipenum);
+ }
+}
+
+static void start_packet(struct m66592_ep *ep, struct m66592_request *req)
+{
+ if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ start_packet_write(ep, req);
+ else
+ start_packet_read(ep, req);
+}
+
+static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
+{
+ u16 ctsq;
+
+ ctsq = m66592_read(ep->m66592, M66592_INTSTS0) & M66592_CTSQ;
+
+ switch (ctsq) {
+ case M66592_CS_RDDS:
+ start_ep0_write(ep, req);
+ break;
+ case M66592_CS_WRDS:
+ start_packet_read(ep, req);
+ break;
+
+ case M66592_CS_WRND:
+ control_end(ep->m66592, 0);
+ break;
+ default:
+ printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq);
+ break;
+ }
+}
+
+static void init_controller(struct m66592 *m66592)
+{
+ m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
+ M66592_PINCFG);
+ m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
+ m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
+
+ m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+
+ m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+
+ msleep(3);
+
+ m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+
+ msleep(1);
+
+ m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+
+ m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
+ m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
+ M66592_DMA0CFG);
+}
+
+static void disable_controller(struct m66592 *m66592)
+{
+ m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
+}
+
+static void m66592_start_xclock(struct m66592 *m66592)
+{
+ u16 tmp;
+
+ tmp = m66592_read(m66592, M66592_SYSCFG);
+ if (!(tmp & M66592_XCKE))
+ m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+}
+
+/*-------------------------------------------------------------------------*/
+static void transfer_complete(struct m66592_ep *ep,
+ struct m66592_request *req, int status)
+__releases(m66592->lock)
+__acquires(m66592->lock)
+{
+ int restart = 0;
+
+ if (unlikely(ep->pipenum == 0)) {
+ if (ep->internal_ccpl) {
+ ep->internal_ccpl = 0;
+ return;
+ }
+ }
+
+ list_del_init(&req->queue);
+ if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN)
+ req->req.status = -ESHUTDOWN;
+ else
+ req->req.status = status;
+
+ if (!list_empty(&ep->queue))
+ restart = 1;
+
+ spin_unlock(&ep->m66592->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&ep->m66592->lock);
+
+ if (restart) {
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ if (ep->desc)
+ start_packet(ep, req);
+ }
+}
+
+static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+ int i;
+ u16 tmp;
+ unsigned bufsize;
+ size_t size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct m66592 *m66592 = ep->m66592;
+
+ pipe_change(m66592, pipenum);
+ m66592_bset(m66592, M66592_ISEL, ep->fifosel);
+
+ i = 0;
+ do {
+ tmp = m66592_read(m66592, ep->fifoctr);
+ if (i++ > 100000) {
+ printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus"
+ "conflict. please power off this controller.");
+ return;
+ }
+ ndelay(1);
+ } while ((tmp & M66592_FRDY) == 0);
+
+ /* prepare parameters */
+ bufsize = get_buffer_size(m66592, pipenum);
+ buf = req->req.buf + req->req.actual;
+ size = min(bufsize, req->req.length - req->req.actual);
+
+ /* write fifo */
+ if (req->req.buf) {
+ if (size > 0)
+ m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
+ if ((size == 0) || ((size % ep->ep.maxpacket) != 0))
+ m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+ }
+
+ /* update parameters */
+ req->req.actual += size;
+
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ disable_irq_ready(m66592, pipenum);
+ disable_irq_empty(m66592, pipenum);
+ } else {
+ disable_irq_ready(m66592, pipenum);
+ enable_irq_empty(m66592, pipenum);
+ }
+ pipe_start(m66592, pipenum);
+}
+
+static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+ u16 tmp;
+ unsigned bufsize;
+ size_t size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct m66592 *m66592 = ep->m66592;
+
+ pipe_change(m66592, pipenum);
+ tmp = m66592_read(m66592, ep->fifoctr);
+ if (unlikely((tmp & M66592_FRDY) == 0)) {
+ pipe_stop(m66592, pipenum);
+ pipe_irq_disable(m66592, pipenum);
+ printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum);
+ return;
+ }
+
+ /* prepare parameters */
+ bufsize = get_buffer_size(m66592, pipenum);
+ buf = req->req.buf + req->req.actual;
+ size = min(bufsize, req->req.length - req->req.actual);
+
+ /* write fifo */
+ if (req->req.buf) {
+ m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
+ if ((size == 0)
+ || ((size % ep->ep.maxpacket) != 0)
+ || ((bufsize != ep->ep.maxpacket)
+ && (bufsize > size)))
+ m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+ }
+
+ /* update parameters */
+ req->req.actual += size;
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ disable_irq_ready(m66592, pipenum);
+ enable_irq_empty(m66592, pipenum);
+ } else {
+ disable_irq_empty(m66592, pipenum);
+ pipe_irq_enable(m66592, pipenum);
+ }
+}
+
+static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
+{
+ u16 tmp;
+ int rcv_len, bufsize, req_len;
+ int size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct m66592 *m66592 = ep->m66592;
+ int finish = 0;
+
+ pipe_change(m66592, pipenum);
+ tmp = m66592_read(m66592, ep->fifoctr);
+ if (unlikely((tmp & M66592_FRDY) == 0)) {
+ req->req.status = -EPIPE;
+ pipe_stop(m66592, pipenum);
+ pipe_irq_disable(m66592, pipenum);
+ printk(KERN_ERR "read fifo not ready");
+ return;
+ }
+
+ /* prepare parameters */
+ rcv_len = tmp & M66592_DTLN;
+ bufsize = get_buffer_size(m66592, pipenum);
+
+ buf = req->req.buf + req->req.actual;
+ req_len = req->req.length - req->req.actual;
+ if (rcv_len < bufsize)
+ size = min(rcv_len, req_len);
+ else
+ size = min(bufsize, req_len);
+
+ /* update parameters */
+ req->req.actual += size;
+
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ pipe_stop(m66592, pipenum);
+ pipe_irq_disable(m66592, pipenum);
+ finish = 1;
+ }
+
+ /* read fifo */
+ if (req->req.buf) {
+ if (size == 0)
+ m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+ else
+ m66592_read_fifo(m66592, ep->fifoaddr, buf, size);
+ }
+
+ if ((ep->pipenum != 0) && finish)
+ transfer_complete(ep, req, 0);
+}
+
+static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
+{
+ u16 check;
+ u16 pipenum;
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+
+ if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
+ m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
+ m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
+ M66592_CFIFOSEL);
+
+ ep = &m66592->ep[0];
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ irq_packet_read(ep, req);
+ } else {
+ for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if ((status & check) && (enb & check)) {
+ m66592_write(m66592, ~check, M66592_BRDYSTS);
+ ep = m66592->pipenum2ep[pipenum];
+ req = list_entry(ep->queue.next,
+ struct m66592_request, queue);
+ if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ irq_packet_write(ep, req);
+ else
+ irq_packet_read(ep, req);
+ }
+ }
+ }
+}
+
+static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb)
+{
+ u16 tmp;
+ u16 check;
+ u16 pipenum;
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+
+ if ((status & M66592_BEMP0) && (enb & M66592_BEMP0)) {
+ m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS);
+
+ ep = &m66592->ep[0];
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ irq_ep0_write(ep, req);
+ } else {
+ for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if ((status & check) && (enb & check)) {
+ m66592_write(m66592, ~check, M66592_BEMPSTS);
+ tmp = control_reg_get(m66592, pipenum);
+ if ((tmp & M66592_INBUFM) == 0) {
+ disable_irq_empty(m66592, pipenum);
+ pipe_irq_disable(m66592, pipenum);
+ pipe_stop(m66592, pipenum);
+ ep = m66592->pipenum2ep[pipenum];
+ req = list_entry(ep->queue.next,
+ struct m66592_request,
+ queue);
+ if (!list_empty(&ep->queue))
+ transfer_complete(ep, req, 0);
+ }
+ }
+ }
+ }
+}
+
+static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+__releases(m66592->lock)
+__acquires(m66592->lock)
+{
+ struct m66592_ep *ep;
+ u16 pid;
+ u16 status = 0;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ status = 1 << USB_DEVICE_SELF_POWERED;
+ break;
+ case USB_RECIP_INTERFACE:
+ status = 0;
+ break;
+ case USB_RECIP_ENDPOINT:
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ pid = control_reg_get_pid(m66592, ep->pipenum);
+ if (pid == M66592_PID_STALL)
+ status = 1 << USB_ENDPOINT_HALT;
+ else
+ status = 0;
+ break;
+ default:
+ pipe_stall(m66592, 0);
+ return; /* exit */
+ }
+
+ m66592->ep0_data = cpu_to_le16(status);
+ m66592->ep0_req->buf = &m66592->ep0_data;
+ m66592->ep0_req->length = 2;
+ /* AV: what happens if we get called again before that gets through? */
+ spin_unlock(&m66592->lock);
+ m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+ spin_lock(&m66592->lock);
+}
+
+static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ control_end(m66592, 1);
+ break;
+ case USB_RECIP_INTERFACE:
+ control_end(m66592, 1);
+ break;
+ case USB_RECIP_ENDPOINT: {
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ pipe_stop(m66592, ep->pipenum);
+ control_reg_sqclr(m66592, ep->pipenum);
+
+ control_end(m66592, 1);
+
+ req = list_entry(ep->queue.next,
+ struct m66592_request, queue);
+ if (ep->busy) {
+ ep->busy = 0;
+ if (list_empty(&ep->queue))
+ break;
+ start_packet(ep, req);
+ } else if (!list_empty(&ep->queue))
+ pipe_start(m66592, ep->pipenum);
+ }
+ break;
+ default:
+ pipe_stall(m66592, 0);
+ break;
+ }
+}
+
+static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ control_end(m66592, 1);
+ break;
+ case USB_RECIP_INTERFACE:
+ control_end(m66592, 1);
+ break;
+ case USB_RECIP_ENDPOINT: {
+ struct m66592_ep *ep;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ pipe_stall(m66592, ep->pipenum);
+
+ control_end(m66592, 1);
+ }
+ break;
+ default:
+ pipe_stall(m66592, 0);
+ break;
+ }
+}
+
+/* if return value is true, call class driver's setup() */
+static int setup_packet(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+ u16 *p = (u16 *)ctrl;
+ unsigned long offset = M66592_USBREQ;
+ int i, ret = 0;
+
+ /* read fifo */
+ m66592_write(m66592, ~M66592_VALID, M66592_INTSTS0);
+
+ for (i = 0; i < 4; i++)
+ p[i] = m66592_read(m66592, offset + i*2);
+
+ /* check request */
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ switch (ctrl->bRequest) {
+ case USB_REQ_GET_STATUS:
+ get_status(m66592, ctrl);
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ clear_feature(m66592, ctrl);
+ break;
+ case USB_REQ_SET_FEATURE:
+ set_feature(m66592, ctrl);
+ break;
+ default:
+ ret = 1;
+ break;
+ }
+ } else
+ ret = 1;
+ return ret;
+}
+
+static void m66592_update_usb_speed(struct m66592 *m66592)
+{
+ u16 speed = get_usb_speed(m66592);
+
+ switch (speed) {
+ case M66592_HSMODE:
+ m66592->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case M66592_FSMODE:
+ m66592->gadget.speed = USB_SPEED_FULL;
+ break;
+ default:
+ m66592->gadget.speed = USB_SPEED_UNKNOWN;
+ printk(KERN_ERR "USB speed unknown\n");
+ }
+}
+
+static void irq_device_state(struct m66592 *m66592)
+{
+ u16 dvsq;
+
+ dvsq = m66592_read(m66592, M66592_INTSTS0) & M66592_DVSQ;
+ m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0);
+
+ if (dvsq == M66592_DS_DFLT) { /* bus reset */
+ m66592->driver->disconnect(&m66592->gadget);
+ m66592_update_usb_speed(m66592);
+ }
+ if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
+ m66592_update_usb_speed(m66592);
+ if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS)
+ && m66592->gadget.speed == USB_SPEED_UNKNOWN)
+ m66592_update_usb_speed(m66592);
+
+ m66592->old_dvsq = dvsq;
+}
+
+static void irq_control_stage(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
+{
+ struct usb_ctrlrequest ctrl;
+ u16 ctsq;
+
+ ctsq = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ;
+ m66592_write(m66592, ~M66592_CTRT, M66592_INTSTS0);
+
+ switch (ctsq) {
+ case M66592_CS_IDST: {
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ ep = &m66592->ep[0];
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ transfer_complete(ep, req, 0);
+ }
+ break;
+
+ case M66592_CS_RDDS:
+ case M66592_CS_WRDS:
+ case M66592_CS_WRND:
+ if (setup_packet(m66592, &ctrl)) {
+ spin_unlock(&m66592->lock);
+ if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
+ pipe_stall(m66592, 0);
+ spin_lock(&m66592->lock);
+ }
+ break;
+ case M66592_CS_RDSS:
+ case M66592_CS_WRSS:
+ control_end(m66592, 0);
+ break;
+ default:
+ printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
+ break;
+ }
+}
+
+static irqreturn_t m66592_irq(int irq, void *_m66592)
+{
+ struct m66592 *m66592 = _m66592;
+ u16 intsts0;
+ u16 intenb0;
+ u16 brdysts, nrdysts, bempsts;
+ u16 brdyenb, nrdyenb, bempenb;
+ u16 savepipe;
+ u16 mask0;
+
+ spin_lock(&m66592->lock);
+
+ intsts0 = m66592_read(m66592, M66592_INTSTS0);
+ intenb0 = m66592_read(m66592, M66592_INTENB0);
+
+ savepipe = m66592_read(m66592, M66592_CFIFOSEL);
+
+ mask0 = intsts0 & intenb0;
+ if (mask0) {
+ brdysts = m66592_read(m66592, M66592_BRDYSTS);
+ nrdysts = m66592_read(m66592, M66592_NRDYSTS);
+ bempsts = m66592_read(m66592, M66592_BEMPSTS);
+ brdyenb = m66592_read(m66592, M66592_BRDYENB);
+ nrdyenb = m66592_read(m66592, M66592_NRDYENB);
+ bempenb = m66592_read(m66592, M66592_BEMPENB);
+
+ if (mask0 & M66592_VBINT) {
+ m66592_write(m66592, 0xffff & ~M66592_VBINT,
+ M66592_INTSTS0);
+ m66592_start_xclock(m66592);
+
+ /* start vbus sampling */
+ m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
+ & M66592_VBSTS;
+ m66592->scount = M66592_MAX_SAMPLING;
+
+ mod_timer(&m66592->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ if (intsts0 & M66592_DVSQ)
+ irq_device_state(m66592);
+
+ if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE)
+ && (brdysts & brdyenb)) {
+ irq_pipe_ready(m66592, brdysts, brdyenb);
+ }
+ if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE)
+ && (bempsts & bempenb)) {
+ irq_pipe_empty(m66592, bempsts, bempenb);
+ }
+
+ if (intsts0 & M66592_CTRT)
+ irq_control_stage(m66592);
+ }
+
+ m66592_write(m66592, savepipe, M66592_CFIFOSEL);
+
+ spin_unlock(&m66592->lock);
+ return IRQ_HANDLED;
+}
+
+static void m66592_timer(unsigned long _m66592)
+{
+ struct m66592 *m66592 = (struct m66592 *)_m66592;
+ unsigned long flags;
+ u16 tmp;
+
+ spin_lock_irqsave(&m66592->lock, flags);
+ tmp = m66592_read(m66592, M66592_SYSCFG);
+ if (!(tmp & M66592_RCKE)) {
+ m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+ udelay(10);
+ m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+ }
+ if (m66592->scount > 0) {
+ tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS;
+ if (tmp == m66592->old_vbus) {
+ m66592->scount--;
+ if (m66592->scount == 0) {
+ if (tmp == M66592_VBSTS)
+ m66592_usb_connect(m66592);
+ else
+ m66592_usb_disconnect(m66592);
+ } else {
+ mod_timer(&m66592->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ } else {
+ m66592->scount = M66592_MAX_SAMPLING;
+ m66592->old_vbus = tmp;
+ mod_timer(&m66592->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ }
+ spin_unlock_irqrestore(&m66592->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+static int m66592_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct m66592_ep *ep;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ return alloc_pipe_config(ep, desc);
+}
+
+static int m66592_disable(struct usb_ep *_ep)
+{
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ BUG_ON(!ep);
+
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+ transfer_complete(ep, req, -ECONNRESET);
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+ }
+
+ pipe_irq_disable(ep->m66592, ep->pipenum);
+ return free_pipe_config(ep);
+}
+
+static struct usb_request *m66592_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct m66592_request *req;
+
+ req = kzalloc(sizeof(struct m66592_request), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void m66592_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct m66592_request *req;
+
+ req = container_of(_req, struct m66592_request, req);
+ kfree(req);
+}
+
+static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ unsigned long flags;
+ int request = 0;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ req = container_of(_req, struct m66592_request, req);
+
+ if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+
+ if (list_empty(&ep->queue))
+ request = 1;
+
+ list_add_tail(&req->queue, &ep->queue);
+ req->req.actual = 0;
+ req->req.status = -EINPROGRESS;
+
+ if (ep->desc == 0) /* control */
+ start_ep0(ep, req);
+ else {
+ if (request && !ep->busy)
+ start_packet(ep, req);
+ }
+
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+
+ return 0;
+}
+
+static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ req = container_of(_req, struct m66592_request, req);
+
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+ if (!list_empty(&ep->queue))
+ transfer_complete(ep, req, -ECONNRESET);
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+
+ return 0;
+}
+
+static int m66592_set_halt(struct usb_ep *_ep, int value)
+{
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ unsigned long flags;
+ int ret = 0;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+ if (!list_empty(&ep->queue)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ if (value) {
+ ep->busy = 1;
+ pipe_stall(ep->m66592, ep->pipenum);
+ } else {
+ ep->busy = 0;
+ pipe_stop(ep->m66592, ep->pipenum);
+ }
+
+out:
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+ return ret;
+}
+
+static void m66592_fifo_flush(struct usb_ep *_ep)
+{
+ struct m66592_ep *ep;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+ if (list_empty(&ep->queue) && !ep->busy) {
+ pipe_stop(ep->m66592, ep->pipenum);
+ m66592_bclr(ep->m66592, M66592_BCLR, ep->fifoctr);
+ }
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+}
+
+static struct usb_ep_ops m66592_ep_ops = {
+ .enable = m66592_enable,
+ .disable = m66592_disable,
+
+ .alloc_request = m66592_alloc_request,
+ .free_request = m66592_free_request,
+
+ .queue = m66592_queue,
+ .dequeue = m66592_dequeue,
+
+ .set_halt = m66592_set_halt,
+ .fifo_flush = m66592_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+static struct m66592 *the_controller;
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct m66592 *m66592 = the_controller;
+ int retval;
+
+ if (!driver
+ || driver->speed != USB_SPEED_HIGH
+ || !driver->bind
+ || !driver->setup)
+ return -EINVAL;
+ if (!m66592)
+ return -ENODEV;
+ if (m66592->driver)
+ return -EBUSY;
+
+ /* hook up the driver */
+ driver->driver.bus = NULL;
+ m66592->driver = driver;
+ m66592->gadget.dev.driver = &driver->driver;
+
+ retval = device_add(&m66592->gadget.dev);
+ if (retval) {
+ printk(KERN_ERR "device_add error (%d)\n", retval);
+ goto error;
+ }
+
+ retval = driver->bind (&m66592->gadget);
+ if (retval) {
+ printk(KERN_ERR "bind to driver error (%d)\n", retval);
+ device_del(&m66592->gadget.dev);
+ goto error;
+ }
+
+ m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
+ if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
+ m66592_start_xclock(m66592);
+ /* start vbus sampling */
+ m66592->old_vbus = m66592_read(m66592,
+ M66592_INTSTS0) & M66592_VBSTS;
+ m66592->scount = M66592_MAX_SAMPLING;
+ mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50));
+ }
+
+ return 0;
+
+error:
+ m66592->driver = NULL;
+ m66592->gadget.dev.driver = NULL;
+
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct m66592 *m66592 = the_controller;
+ unsigned long flags;
+
+ if (driver != m66592->driver || !driver->unbind)
+ return -EINVAL;
+
+ spin_lock_irqsave(&m66592->lock, flags);
+ if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
+ m66592_usb_disconnect(m66592);
+ spin_unlock_irqrestore(&m66592->lock, flags);
+
+ m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
+
+ driver->unbind(&m66592->gadget);
+
+ init_controller(m66592);
+ disable_controller(m66592);
+
+ device_del(&m66592->gadget.dev);
+ m66592->driver = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+static int m66592_get_frame(struct usb_gadget *_gadget)
+{
+ struct m66592 *m66592 = gadget_to_m66592(_gadget);
+ return m66592_read(m66592, M66592_FRMNUM) & 0x03FF;
+}
+
+static struct usb_gadget_ops m66592_gadget_ops = {
+ .get_frame = m66592_get_frame,
+};
+
+static int __exit m66592_remove(struct platform_device *pdev)
+{
+ struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
+
+ del_timer_sync(&m66592->timer);
+ iounmap(m66592->reg);
+ free_irq(platform_get_irq(pdev, 0), m66592);
+ m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+ kfree(m66592);
+ return 0;
+}
+
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+
+static int __init m66592_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int irq;
+ void __iomem *reg = NULL;
+ struct m66592 *m66592 = NULL;
+ int ret = 0;
+ int i;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ (char *)udc_name);
+ if (!res) {
+ ret = -ENODEV;
+ printk(KERN_ERR "platform_get_resource_byname error.\n");
+ goto clean_up;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = -ENODEV;
+ printk(KERN_ERR "platform_get_irq error.\n");
+ goto clean_up;
+ }
+
+ reg = ioremap(res->start, resource_len(res));
+ if (reg == NULL) {
+ ret = -ENOMEM;
+ printk(KERN_ERR "ioremap error.\n");
+ goto clean_up;
+ }
+
+ /* initialize ucd */
+ m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
+ if (m66592 == NULL) {
+ printk(KERN_ERR "kzalloc error\n");
+ goto clean_up;
+ }
+
+ spin_lock_init(&m66592->lock);
+ dev_set_drvdata(&pdev->dev, m66592);
+
+ m66592->gadget.ops = &m66592_gadget_ops;
+ device_initialize(&m66592->gadget.dev);
+ strcpy(m66592->gadget.dev.bus_id, "gadget");
+ m66592->gadget.is_dualspeed = 1;
+ m66592->gadget.dev.parent = &pdev->dev;
+ m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
+ m66592->gadget.dev.release = pdev->dev.release;
+ m66592->gadget.name = udc_name;
+
+ init_timer(&m66592->timer);
+ m66592->timer.function = m66592_timer;
+ m66592->timer.data = (unsigned long)m66592;
+ m66592->reg = reg;
+
+ m66592->bi_bufnum = M66592_BASE_BUFNUM;
+
+ ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
+ udc_name, m66592);
+ if (ret < 0) {
+ printk(KERN_ERR "request_irq error (%d)\n", ret);
+ goto clean_up;
+ }
+
+ INIT_LIST_HEAD(&m66592->gadget.ep_list);
+ m66592->gadget.ep0 = &m66592->ep[0].ep;
+ INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list);
+ for (i = 0; i < M66592_MAX_NUM_PIPE; i++) {
+ struct m66592_ep *ep = &m66592->ep[i];
+
+ if (i != 0) {
+ INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
+ list_add_tail(&m66592->ep[i].ep.ep_list,
+ &m66592->gadget.ep_list);
+ }
+ ep->m66592 = m66592;
+ INIT_LIST_HEAD(&ep->queue);
+ ep->ep.name = m66592_ep_name[i];
+ ep->ep.ops = &m66592_ep_ops;
+ ep->ep.maxpacket = 512;
+ }
+ m66592->ep[0].ep.maxpacket = 64;
+ m66592->ep[0].pipenum = 0;
+ m66592->ep[0].fifoaddr = M66592_CFIFO;
+ m66592->ep[0].fifosel = M66592_CFIFOSEL;
+ m66592->ep[0].fifoctr = M66592_CFIFOCTR;
+ m66592->ep[0].fifotrn = 0;
+ m66592->ep[0].pipectr = get_pipectr_addr(0);
+ m66592->pipenum2ep[0] = &m66592->ep[0];
+ m66592->epaddr2ep[0] = &m66592->ep[0];
+
+ the_controller = m66592;
+
+ m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
+ if (m66592->ep0_req == NULL)
+ goto clean_up2;
+ m66592->ep0_req->complete = nop_completion;
+
+ init_controller(m66592);
+
+ dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
+ return 0;
+
+clean_up2:
+ free_irq(irq, m66592);
+clean_up:
+ if (m66592) {
+ if (m66592->ep0_req)
+ m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+ kfree(m66592);
+ }
+ if (reg)
+ iounmap(reg);
+
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+static struct platform_driver m66592_driver = {
+ .remove = __exit_p(m66592_remove),
+ .driver = {
+ .name = (char *) udc_name,
+ },
+};
+
+static int __init m66592_udc_init(void)
+{
+ return platform_driver_probe(&m66592_driver, m66592_probe);
+}
+module_init(m66592_udc_init);
+
+static void __exit m66592_udc_cleanup(void)
+{
+ platform_driver_unregister(&m66592_driver);
+}
+module_exit(m66592_udc_cleanup);
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
new file mode 100644
index 00000000000..bfa0c645f22
--- /dev/null
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -0,0 +1,575 @@
+/*
+ * M66592 UDC (USB gadget)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __M66592_UDC_H__
+#define __M66592_UDC_H__
+
+#define M66592_SYSCFG 0x00
+#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
+#define M66592_XTAL48 0x8000 /* 48MHz */
+#define M66592_XTAL24 0x4000 /* 24MHz */
+#define M66592_XTAL12 0x0000 /* 12MHz */
+#define M66592_XCKE 0x2000 /* b13: External clock enable */
+#define M66592_RCKE 0x1000 /* b12: Register clock enable */
+#define M66592_PLLC 0x0800 /* b11: PLL control */
+#define M66592_SCKE 0x0400 /* b10: USB clock enable */
+#define M66592_ATCKM 0x0100 /* b8: Automatic clock supply */
+#define M66592_HSE 0x0080 /* b7: Hi-speed enable */
+#define M66592_DCFM 0x0040 /* b6: Controller function select */
+#define M66592_DMRPD 0x0020 /* b5: D- pull down control */
+#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */
+#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */
+#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */
+#define M66592_USBE 0x0001 /* b0: USB module operation enable */
+
+#define M66592_SYSSTS 0x02
+#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */
+#define M66592_SE1 0x0003 /* SE1 */
+#define M66592_KSTS 0x0002 /* K State */
+#define M66592_JSTS 0x0001 /* J State */
+#define M66592_SE0 0x0000 /* SE0 */
+
+#define M66592_DVSTCTR 0x04
+#define M66592_WKUP 0x0100 /* b8: Remote wakeup */
+#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */
+#define M66592_USBRST 0x0040 /* b6: USB reset enable */
+#define M66592_RESUME 0x0020 /* b5: Resume enable */
+#define M66592_UACT 0x0010 /* b4: USB bus enable */
+#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */
+#define M66592_HSMODE 0x0003 /* Hi-Speed mode */
+#define M66592_FSMODE 0x0002 /* Full-Speed mode */
+#define M66592_HSPROC 0x0001 /* HS handshake is processing */
+
+#define M66592_TESTMODE 0x06
+#define M66592_UTST 0x000F /* b4-0: Test select */
+#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */
+#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
+#define M66592_H_TST_K 0x000A /* HOST TEST K */
+#define M66592_H_TST_J 0x0009 /* HOST TEST J */
+#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */
+#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */
+#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
+#define M66592_P_TST_K 0x0002 /* PERI TEST K */
+#define M66592_P_TST_J 0x0001 /* PERI TEST J */
+#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+
+#define M66592_PINCFG 0x0A
+#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
+#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
+
+#define M66592_DMA0CFG 0x0C
+#define M66592_DMA1CFG 0x0E
+#define M66592_DREQA 0x4000 /* b14: Dreq active select */
+#define M66592_BURST 0x2000 /* b13: Burst mode */
+#define M66592_DACKA 0x0400 /* b10: Dack active select */
+#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */
+#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
+#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
+#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
+#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
+#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */
+#define M66592_DENDA 0x0040 /* b6: Dend active select */
+#define M66592_PKTM 0x0020 /* b5: Packet mode */
+#define M66592_DENDE 0x0010 /* b4: Dend enable */
+#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
+
+#define M66592_CFIFO 0x10
+#define M66592_D0FIFO 0x14
+#define M66592_D1FIFO 0x18
+
+#define M66592_CFIFOSEL 0x1E
+#define M66592_D0FIFOSEL 0x24
+#define M66592_D1FIFOSEL 0x2A
+#define M66592_RCNT 0x8000 /* b15: Read count mode */
+#define M66592_REW 0x4000 /* b14: Buffer rewind */
+#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
+#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
+#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */
+#define M66592_MBW_8 0x0000 /* 8bit */
+#define M66592_MBW_16 0x0400 /* 16bit */
+#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
+#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
+#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */
+#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */
+#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */
+
+#define M66592_CFIFOCTR 0x20
+#define M66592_D0FIFOCTR 0x26
+#define M66592_D1FIFOCTR 0x2c
+#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */
+#define M66592_BCLR 0x4000 /* b14: Buffer clear */
+#define M66592_FRDY 0x2000 /* b13: FIFO ready */
+#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */
+
+#define M66592_CFIFOSIE 0x22
+#define M66592_TGL 0x8000 /* b15: Buffer toggle */
+#define M66592_SCLR 0x4000 /* b14: Buffer clear */
+#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */
+
+#define M66592_D0FIFOTRN 0x28
+#define M66592_D1FIFOTRN 0x2E
+#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */
+
+#define M66592_INTENB0 0x30
+#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */
+#define M66592_RSME 0x4000 /* b14: Resume interrupt */
+#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */
+#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */
+#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition irq */
+#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */
+#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */
+#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */
+#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */
+#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */
+#define M66592_WDST 0x0008 /* b3: Control write data stage completed irq */
+#define M66592_RDST 0x0004 /* b2: Control read data stage completed irq */
+#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */
+#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */
+
+#define M66592_INTENB1 0x32
+#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */
+#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */
+#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
+#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */
+#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */
+#define M66592_INTL 0x0002 /* b1: Interrupt sense select */
+#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */
+
+#define M66592_BRDYENB 0x36
+#define M66592_BRDYSTS 0x46
+#define M66592_BRDY7 0x0080 /* b7: PIPE7 */
+#define M66592_BRDY6 0x0040 /* b6: PIPE6 */
+#define M66592_BRDY5 0x0020 /* b5: PIPE5 */
+#define M66592_BRDY4 0x0010 /* b4: PIPE4 */
+#define M66592_BRDY3 0x0008 /* b3: PIPE3 */
+#define M66592_BRDY2 0x0004 /* b2: PIPE2 */
+#define M66592_BRDY1 0x0002 /* b1: PIPE1 */
+#define M66592_BRDY0 0x0001 /* b1: PIPE0 */
+
+#define M66592_NRDYENB 0x38
+#define M66592_NRDYSTS 0x48
+#define M66592_NRDY7 0x0080 /* b7: PIPE7 */
+#define M66592_NRDY6 0x0040 /* b6: PIPE6 */
+#define M66592_NRDY5 0x0020 /* b5: PIPE5 */
+#define M66592_NRDY4 0x0010 /* b4: PIPE4 */
+#define M66592_NRDY3 0x0008 /* b3: PIPE3 */
+#define M66592_NRDY2 0x0004 /* b2: PIPE2 */
+#define M66592_NRDY1 0x0002 /* b1: PIPE1 */
+#define M66592_NRDY0 0x0001 /* b1: PIPE0 */
+
+#define M66592_BEMPENB 0x3A
+#define M66592_BEMPSTS 0x4A
+#define M66592_BEMP7 0x0080 /* b7: PIPE7 */
+#define M66592_BEMP6 0x0040 /* b6: PIPE6 */
+#define M66592_BEMP5 0x0020 /* b5: PIPE5 */
+#define M66592_BEMP4 0x0010 /* b4: PIPE4 */
+#define M66592_BEMP3 0x0008 /* b3: PIPE3 */
+#define M66592_BEMP2 0x0004 /* b2: PIPE2 */
+#define M66592_BEMP1 0x0002 /* b1: PIPE1 */
+#define M66592_BEMP0 0x0001 /* b0: PIPE0 */
+
+#define M66592_SOFCFG 0x3C
+#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */
+#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */
+#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
+#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */
+
+#define M66592_INTSTS0 0x40
+#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */
+#define M66592_RESM 0x4000 /* b14: Resume interrupt */
+#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define M66592_DVST 0x1000 /* b12: Device state transition */
+#define M66592_CTRT 0x0800 /* b11: Control stage transition */
+#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define M66592_VBSTS 0x0080 /* b7: VBUS input port */
+#define M66592_DVSQ 0x0070 /* b6-4: Device state */
+#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */
+#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */
+#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */
+#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */
+#define M66592_DS_SUSP 0x0040 /* Suspend */
+#define M66592_DS_CNFG 0x0030 /* Configured */
+#define M66592_DS_ADDS 0x0020 /* Address */
+#define M66592_DS_DFLT 0x0010 /* Default */
+#define M66592_DS_POWR 0x0000 /* Powered */
+#define M66592_DVSQS 0x0030 /* b5-4: Device state */
+#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */
+#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */
+#define M66592_CS_SQER 0x0006 /* Sequence error */
+#define M66592_CS_WRND 0x0005 /* Control write nodata status */
+#define M66592_CS_WRSS 0x0004 /* Control write status stage */
+#define M66592_CS_WRDS 0x0003 /* Control write data stage */
+#define M66592_CS_RDSS 0x0002 /* Control read status stage */
+#define M66592_CS_RDDS 0x0001 /* Control read data stage */
+#define M66592_CS_IDST 0x0000 /* Idle or setup stage */
+
+#define M66592_INTSTS1 0x42
+#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */
+#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */
+#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */
+#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */
+
+#define M66592_FRMNUM 0x4C
+#define M66592_OVRN 0x8000 /* b15: Overrun error */
+#define M66592_CRCE 0x4000 /* b14: Received data error */
+#define M66592_SOFRM 0x0800 /* b11: SOF output mode */
+#define M66592_FRNM 0x07FF /* b10-0: Frame number */
+
+#define M66592_UFRMNUM 0x4E
+#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */
+
+#define M66592_RECOVER 0x50
+#define M66592_STSRECOV 0x0700 /* Status recovery */
+#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */
+#define M66592_STSR_DEFAULT 0x0100 /* Default state */
+#define M66592_STSR_ADDRESS 0x0200 /* Address state */
+#define M66592_STSR_CONFIG 0x0300 /* Configured state */
+#define M66592_USBADDR 0x007F /* b6-0: USB address */
+
+#define M66592_USBREQ 0x54
+#define M66592_bRequest 0xFF00 /* b15-8: bRequest */
+#define M66592_GET_STATUS 0x0000
+#define M66592_CLEAR_FEATURE 0x0100
+#define M66592_ReqRESERVED 0x0200
+#define M66592_SET_FEATURE 0x0300
+#define M66592_ReqRESERVED1 0x0400
+#define M66592_SET_ADDRESS 0x0500
+#define M66592_GET_DESCRIPTOR 0x0600
+#define M66592_SET_DESCRIPTOR 0x0700
+#define M66592_GET_CONFIGURATION 0x0800
+#define M66592_SET_CONFIGURATION 0x0900
+#define M66592_GET_INTERFACE 0x0A00
+#define M66592_SET_INTERFACE 0x0B00
+#define M66592_SYNCH_FRAME 0x0C00
+#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */
+#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data direction */
+#define M66592_HOST_TO_DEVICE 0x0000
+#define M66592_DEVICE_TO_HOST 0x0080
+#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */
+#define M66592_STANDARD 0x0000
+#define M66592_CLASS 0x0020
+#define M66592_VENDOR 0x0040
+#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */
+#define M66592_DEVICE 0x0000
+#define M66592_INTERFACE 0x0001
+#define M66592_ENDPOINT 0x0002
+
+#define M66592_USBVAL 0x56
+#define M66592_wValue 0xFFFF /* b15-0: wValue */
+/* Standard Feature Selector */
+#define M66592_ENDPOINT_HALT 0x0000
+#define M66592_DEVICE_REMOTE_WAKEUP 0x0001
+#define M66592_TEST_MODE 0x0002
+/* Descriptor Types */
+#define M66592_DT_TYPE 0xFF00
+#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8)
+#define M66592_DT_DEVICE 0x01
+#define M66592_DT_CONFIGURATION 0x02
+#define M66592_DT_STRING 0x03
+#define M66592_DT_INTERFACE 0x04
+#define M66592_DT_ENDPOINT 0x05
+#define M66592_DT_DEVICE_QUALIFIER 0x06
+#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07
+#define M66592_DT_INTERFACE_POWER 0x08
+#define M66592_DT_INDEX 0x00FF
+#define M66592_CONF_NUM 0x00FF
+#define M66592_ALT_SET 0x00FF
+
+#define M66592_USBINDEX 0x58
+#define M66592_wIndex 0xFFFF /* b15-0: wIndex */
+#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode */
+#define M66592_TEST_J 0x0100 /* Test_J */
+#define M66592_TEST_K 0x0200 /* Test_K */
+#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */
+#define M66592_TEST_PACKET 0x0400 /* Test_Packet */
+#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */
+#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */
+#define M66592_TEST_Reserved 0x4000 /* Reserved */
+#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific tests */
+#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */
+#define M66592_EP_DIR_IN 0x0080
+#define M66592_EP_DIR_OUT 0x0000
+
+#define M66592_USBLENG 0x5A
+#define M66592_wLength 0xFFFF /* b15-0: wLength */
+
+#define M66592_DCPCFG 0x5C
+#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */
+#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */
+
+#define M66592_DCPMAXP 0x5E
+#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */
+#define M66592_DEVICE_0 0x0000 /* Device address 0 */
+#define M66592_DEVICE_1 0x4000 /* Device address 1 */
+#define M66592_DEVICE_2 0x8000 /* Device address 2 */
+#define M66592_DEVICE_3 0xC000 /* Device address 3 */
+#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of ep0 */
+
+#define M66592_DCPCTR 0x60
+#define M66592_BSTS 0x8000 /* b15: Buffer status */
+#define M66592_SUREQ 0x4000 /* b14: Send USB request */
+#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define M66592_CCPL 0x0004 /* b2: control transfer complete */
+#define M66592_PID 0x0003 /* b1-0: Response PID */
+#define M66592_PID_STALL 0x0002 /* STALL */
+#define M66592_PID_BUF 0x0001 /* BUF */
+#define M66592_PID_NAK 0x0000 /* NAK */
+
+#define M66592_PIPESEL 0x64
+#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */
+#define M66592_PIPE0 0x0000 /* PIPE 0 */
+#define M66592_PIPE1 0x0001 /* PIPE 1 */
+#define M66592_PIPE2 0x0002 /* PIPE 2 */
+#define M66592_PIPE3 0x0003 /* PIPE 3 */
+#define M66592_PIPE4 0x0004 /* PIPE 4 */
+#define M66592_PIPE5 0x0005 /* PIPE 5 */
+#define M66592_PIPE6 0x0006 /* PIPE 6 */
+#define M66592_PIPE7 0x0007 /* PIPE 7 */
+
+#define M66592_PIPECFG 0x66
+#define M66592_TYP 0xC000 /* b15-14: Transfer type */
+#define M66592_ISO 0xC000 /* Isochronous */
+#define M66592_INT 0x8000 /* Interrupt */
+#define M66592_BULK 0x4000 /* Bulk */
+#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode */
+#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */
+#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */
+#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */
+#define M66592_DIR 0x0010 /* b4: Transfer direction select */
+#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */
+#define M66592_DIR_P_IN 0x0010 /* PERI IN */
+#define M66592_DIR_H_IN 0x0000 /* HOST IN */
+#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */
+#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */
+#define M66592_EP1 0x0001
+#define M66592_EP2 0x0002
+#define M66592_EP3 0x0003
+#define M66592_EP4 0x0004
+#define M66592_EP5 0x0005
+#define M66592_EP6 0x0006
+#define M66592_EP7 0x0007
+#define M66592_EP8 0x0008
+#define M66592_EP9 0x0009
+#define M66592_EP10 0x000A
+#define M66592_EP11 0x000B
+#define M66592_EP12 0x000C
+#define M66592_EP13 0x000D
+#define M66592_EP14 0x000E
+#define M66592_EP15 0x000F
+
+#define M66592_PIPEBUF 0x68
+#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
+#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10)
+#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */
+
+#define M66592_PIPEMAXP 0x6A
+#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */
+
+#define M66592_PIPEPERI 0x6C
+#define M66592_IFIS 0x1000 /* b12: ISO in-buffer flush mode */
+#define M66592_IITV 0x0007 /* b2-0: ISO interval */
+
+#define M66592_PIPE1CTR 0x70
+#define M66592_PIPE2CTR 0x72
+#define M66592_PIPE3CTR 0x74
+#define M66592_PIPE4CTR 0x76
+#define M66592_PIPE5CTR 0x78
+#define M66592_PIPE6CTR 0x7A
+#define M66592_PIPE7CTR 0x7C
+#define M66592_BSTS 0x8000 /* b15: Buffer status */
+#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (PIPE 1-5) */
+#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define M66592_PID 0x0003 /* b1-0: Response PID */
+
+#define M66592_INVALID_REG 0x7E
+
+
+#define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2)
+
+#define M66592_MAX_SAMPLING 10
+
+#define M66592_MAX_NUM_PIPE 8
+#define M66592_MAX_NUM_BULK 3
+#define M66592_MAX_NUM_ISOC 2
+#define M66592_MAX_NUM_INT 2
+
+#define M66592_BASE_PIPENUM_BULK 3
+#define M66592_BASE_PIPENUM_ISOC 1
+#define M66592_BASE_PIPENUM_INT 6
+
+#define M66592_BASE_BUFNUM 6
+#define M66592_MAX_BUFNUM 0x4F
+
+struct m66592_pipe_info {
+ u16 pipe;
+ u16 epnum;
+ u16 maxpacket;
+ u16 type;
+ u16 interval;
+ u16 dir_in;
+};
+
+struct m66592_request {
+ struct usb_request req;
+ struct list_head queue;
+};
+
+struct m66592_ep {
+ struct usb_ep ep;
+ struct m66592 *m66592;
+
+ struct list_head queue;
+ unsigned busy:1;
+ unsigned internal_ccpl:1; /* use only control */
+
+ /* this member can able to after m66592_enable */
+ unsigned use_dma:1;
+ u16 pipenum;
+ u16 type;
+ const struct usb_endpoint_descriptor *desc;
+ /* register address */
+ unsigned long fifoaddr;
+ unsigned long fifosel;
+ unsigned long fifoctr;
+ unsigned long fifotrn;
+ unsigned long pipectr;
+};
+
+struct m66592 {
+ spinlock_t lock;
+ void __iomem *reg;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+
+ struct m66592_ep ep[M66592_MAX_NUM_PIPE];
+ struct m66592_ep *pipenum2ep[M66592_MAX_NUM_PIPE];
+ struct m66592_ep *epaddr2ep[16];
+
+ struct usb_request *ep0_req; /* for internal request */
+ u16 ep0_data; /* for internal request */
+
+ struct timer_list timer;
+
+ u16 old_vbus;
+ int scount;
+
+ int old_dvsq;
+
+ /* pipe config */
+ int bulk;
+ int interrupt;
+ int isochronous;
+ int num_dma;
+ int bi_bufnum; /* bulk and isochronous's bufnum */
+};
+
+#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
+#define m66592_to_gadget(m66592) (&m66592->gadget)
+
+#define is_bulk_pipe(pipenum) \
+ ((pipenum >= M66592_BASE_PIPENUM_BULK) && \
+ (pipenum < (M66592_BASE_PIPENUM_BULK + M66592_MAX_NUM_BULK)))
+#define is_interrupt_pipe(pipenum) \
+ ((pipenum >= M66592_BASE_PIPENUM_INT) && \
+ (pipenum < (M66592_BASE_PIPENUM_INT + M66592_MAX_NUM_INT)))
+#define is_isoc_pipe(pipenum) \
+ ((pipenum >= M66592_BASE_PIPENUM_ISOC) && \
+ (pipenum < (M66592_BASE_PIPENUM_ISOC + M66592_MAX_NUM_ISOC)))
+
+#define enable_irq_ready(m66592, pipenum) \
+ enable_pipe_irq(m66592, pipenum, M66592_BRDYENB)
+#define disable_irq_ready(m66592, pipenum) \
+ disable_pipe_irq(m66592, pipenum, M66592_BRDYENB)
+#define enable_irq_empty(m66592, pipenum) \
+ enable_pipe_irq(m66592, pipenum, M66592_BEMPENB)
+#define disable_irq_empty(m66592, pipenum) \
+ disable_pipe_irq(m66592, pipenum, M66592_BEMPENB)
+#define enable_irq_nrdy(m66592, pipenum) \
+ enable_pipe_irq(m66592, pipenum, M66592_NRDYENB)
+#define disable_irq_nrdy(m66592, pipenum) \
+ disable_pipe_irq(m66592, pipenum, M66592_NRDYENB)
+
+/*-------------------------------------------------------------------------*/
+static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
+{
+ return inw((unsigned long)m66592->reg + offset);
+}
+
+static inline void m66592_read_fifo(struct m66592 *m66592,
+ unsigned long offset,
+ void *buf, unsigned long len)
+{
+ unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+
+ len = (len + 1) / 2;
+ insw(fifoaddr, buf, len);
+}
+
+static inline void m66592_write(struct m66592 *m66592, u16 val,
+ unsigned long offset)
+{
+ outw(val, (unsigned long)m66592->reg + offset);
+}
+
+static inline void m66592_write_fifo(struct m66592 *m66592,
+ unsigned long offset,
+ void *buf, unsigned long len)
+{
+ unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+ unsigned long odd = len & 0x0001;
+
+ len = len / 2;
+ outsw(fifoaddr, buf, len);
+ if (odd) {
+ unsigned char *p = buf + len*2;
+ outb(*p, fifoaddr);
+ }
+}
+
+static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
+ unsigned long offset)
+{
+ u16 tmp;
+ tmp = m66592_read(m66592, offset);
+ tmp = tmp & (~pat);
+ tmp = tmp | val;
+ m66592_write(m66592, tmp, offset);
+}
+
+#define m66592_bclr(m66592, val, offset) \
+ m66592_mdfy(m66592, 0, val, offset)
+#define m66592_bset(m66592, val, offset) \
+ m66592_mdfy(m66592, val, 0, offset)
+
+#endif /* ifndef __M66592_UDC_H__ */
+
+
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index d975ecf18e0..c3d364ecd4f 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -450,100 +450,6 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
-/*
- * dma-coherent memory allocation (for dma-capable endpoints)
- *
- * NOTE: the dma_*_coherent() API calls suck. Most implementations are
- * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
- * respect to calls with irqs disabled: alloc is safe, free is not.
- * We currently work around (b), but not (a).
- */
-
-static void *
-net2280_alloc_buffer (
- struct usb_ep *_ep,
- unsigned bytes,
- dma_addr_t *dma,
- gfp_t gfp_flags
-)
-{
- void *retval;
- struct net2280_ep *ep;
-
- ep = container_of (_ep, struct net2280_ep, ep);
- if (!_ep)
- return NULL;
- *dma = DMA_ADDR_INVALID;
-
- if (ep->dma)
- retval = dma_alloc_coherent(&ep->dev->pdev->dev,
- bytes, dma, gfp_flags);
- else
- retval = kmalloc(bytes, gfp_flags);
- return retval;
-}
-
-static DEFINE_SPINLOCK(buflock);
-static LIST_HEAD(buffers);
-
-struct free_record {
- struct list_head list;
- struct device *dev;
- unsigned bytes;
- dma_addr_t dma;
-};
-
-static void do_free(unsigned long ignored)
-{
- spin_lock_irq(&buflock);
- while (!list_empty(&buffers)) {
- struct free_record *buf;
-
- buf = list_entry(buffers.next, struct free_record, list);
- list_del(&buf->list);
- spin_unlock_irq(&buflock);
-
- dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
-
- spin_lock_irq(&buflock);
- }
- spin_unlock_irq(&buflock);
-}
-
-static DECLARE_TASKLET(deferred_free, do_free, 0);
-
-static void
-net2280_free_buffer (
- struct usb_ep *_ep,
- void *address,
- dma_addr_t dma,
- unsigned bytes
-) {
- /* free memory into the right allocator */
- if (dma != DMA_ADDR_INVALID) {
- struct net2280_ep *ep;
- struct free_record *buf = address;
- unsigned long flags;
-
- ep = container_of(_ep, struct net2280_ep, ep);
- if (!_ep)
- return;
-
- ep = container_of (_ep, struct net2280_ep, ep);
- buf->dev = &ep->dev->pdev->dev;
- buf->bytes = bytes;
- buf->dma = dma;
-
- spin_lock_irqsave(&buflock, flags);
- list_add_tail(&buf->list, &buffers);
- tasklet_schedule(&deferred_free);
- spin_unlock_irqrestore(&buflock, flags);
- } else
- kfree (address);
-}
-
-/*-------------------------------------------------------------------------*/
-
/* load a packet into the fifo we use for usb IN transfers.
* works for all endpoints.
*
@@ -1392,9 +1298,6 @@ static const struct usb_ep_ops net2280_ep_ops = {
.alloc_request = net2280_alloc_request,
.free_request = net2280_free_request,
- .alloc_buffer = net2280_alloc_buffer,
- .free_buffer = net2280_free_buffer,
-
.queue = net2280_queue,
.dequeue = net2280_dequeue,
@@ -2964,7 +2867,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
, &dev->pci->pcimstctl);
/* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */
pci_set_master (pdev);
- pci_set_mwi (pdev);
+ pci_try_set_mwi (pdev);
/* ... also flushes any posted pci writes */
dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index c4975a6cf77..9b0f0925ddd 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -296,111 +296,6 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
-/*
- * dma-coherent memory allocation (for dma-capable endpoints)
- *
- * NOTE: the dma_*_coherent() API calls suck. Most implementations are
- * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
- * respect to calls with irqs disabled: alloc is safe, free is not.
- * We currently work around (b), but not (a).
- */
-
-static void *
-omap_alloc_buffer(
- struct usb_ep *_ep,
- unsigned bytes,
- dma_addr_t *dma,
- gfp_t gfp_flags
-)
-{
- void *retval;
- struct omap_ep *ep;
-
- if (!_ep)
- return NULL;
-
- ep = container_of(_ep, struct omap_ep, ep);
- if (use_dma && ep->has_dma) {
- static int warned;
- if (!warned && bytes < PAGE_SIZE) {
- dev_warn(ep->udc->gadget.dev.parent,
- "using dma_alloc_coherent for "
- "small allocations wastes memory\n");
- warned++;
- }
- return dma_alloc_coherent(ep->udc->gadget.dev.parent,
- bytes, dma, gfp_flags);
- }
-
- retval = kmalloc(bytes, gfp_flags);
- if (retval)
- *dma = virt_to_phys(retval);
- return retval;
-}
-
-static DEFINE_SPINLOCK(buflock);
-static LIST_HEAD(buffers);
-
-struct free_record {
- struct list_head list;
- struct device *dev;
- unsigned bytes;
- dma_addr_t dma;
-};
-
-static void do_free(unsigned long ignored)
-{
- spin_lock_irq(&buflock);
- while (!list_empty(&buffers)) {
- struct free_record *buf;
-
- buf = list_entry(buffers.next, struct free_record, list);
- list_del(&buf->list);
- spin_unlock_irq(&buflock);
-
- dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
-
- spin_lock_irq(&buflock);
- }
- spin_unlock_irq(&buflock);
-}
-
-static DECLARE_TASKLET(deferred_free, do_free, 0);
-
-static void omap_free_buffer(
- struct usb_ep *_ep,
- void *buf,
- dma_addr_t dma,
- unsigned bytes
-)
-{
- if (!_ep) {
- WARN_ON(1);
- return;
- }
-
- /* free memory into the right allocator */
- if (dma != DMA_ADDR_INVALID) {
- struct omap_ep *ep;
- struct free_record *rec = buf;
- unsigned long flags;
-
- ep = container_of(_ep, struct omap_ep, ep);
-
- rec->dev = ep->udc->gadget.dev.parent;
- rec->bytes = bytes;
- rec->dma = dma;
-
- spin_lock_irqsave(&buflock, flags);
- list_add_tail(&rec->list, &buffers);
- tasklet_schedule(&deferred_free);
- spin_unlock_irqrestore(&buflock, flags);
- } else
- kfree(buf);
-}
-
-/*-------------------------------------------------------------------------*/
-
static void
done(struct omap_ep *ep, struct omap_req *req, int status)
{
@@ -1271,9 +1166,6 @@ static struct usb_ep_ops omap_ep_ops = {
.alloc_request = omap_alloc_request,
.free_request = omap_free_request,
- .alloc_buffer = omap_alloc_buffer,
- .free_buffer = omap_free_buffer,
-
.queue = omap_ep_queue,
.dequeue = omap_ep_dequeue,
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 84392e835d5..63b9521c132 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -24,9 +24,9 @@
*
*/
-#undef DEBUG
// #define VERBOSE DBG_VERBOSE
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -46,19 +46,17 @@
#include <asm/byteorder.h>
#include <asm/dma.h>
+#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/unaligned.h>
#include <asm/hardware.h>
-#ifdef CONFIG_ARCH_PXA
-#include <asm/arch/pxa-regs.h>
-#endif
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
-#include <asm/arch/udc.h>
+#include <asm/mach/udc_pxa2xx.h>
/*
@@ -76,9 +74,17 @@
* it constrains the sorts of USB configuration change events that work.
* The errata for these chips are misleading; some "fixed" bugs from
* pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
+ *
+ * Note that the UDC hardware supports DMA (except on IXP) but that's
+ * not used here. IN-DMA (to host) is simple enough, when the data is
+ * suitably aligned (16 bytes) ... the network stack doesn't do that,
+ * other software can. OUT-DMA is buggy in most chip versions, as well
+ * as poorly designed (data toggle not automatic). So this driver won't
+ * bother using DMA. (Mostly-working IN-DMA support was available in
+ * kernels before 2.6.23, but was never enabled or well tested.)
*/
-#define DRIVER_VERSION "4-May-2005"
+#define DRIVER_VERSION "30-June-2007"
#define DRIVER_DESC "PXA 25x USB Device Controller driver"
@@ -87,12 +93,9 @@ static const char driver_name [] = "pxa2xx_udc";
static const char ep0name [] = "ep0";
-// #define USE_DMA
-// #define USE_OUT_DMA
// #define DISABLE_TEST_MODE
#ifdef CONFIG_ARCH_IXP4XX
-#undef USE_DMA
/* cpu-specific register addresses are compiled in to this code */
#ifdef CONFIG_ARCH_PXA
@@ -104,25 +107,6 @@ static const char ep0name [] = "ep0";
#include "pxa2xx_udc.h"
-#ifdef USE_DMA
-static int use_dma = 1;
-module_param(use_dma, bool, 0);
-MODULE_PARM_DESC (use_dma, "true to use dma");
-
-static void dma_nodesc_handler (int dmach, void *_ep);
-static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req);
-
-#ifdef USE_OUT_DMA
-#define DMASTR " (dma support)"
-#else
-#define DMASTR " (dma in)"
-#endif
-
-#else /* !USE_DMA */
-#define DMASTR " (pio only)"
-#undef USE_OUT_DMA
-#endif
-
#ifdef CONFIG_USB_PXA2XX_SMALL
#define SIZE_STR " (small)"
#else
@@ -155,7 +139,7 @@ static int is_vbus_present(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_vbus)
- return udc_gpio_get(mach->gpio_vbus);
+ return gpio_get_value(mach->gpio_vbus);
if (mach->udc_is_connected)
return mach->udc_is_connected();
return 1;
@@ -167,7 +151,7 @@ static void pullup_off(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- udc_gpio_set(mach->gpio_pullup, 0);
+ gpio_set_value(mach->gpio_pullup, 0);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
@@ -177,7 +161,7 @@ static void pullup_on(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- udc_gpio_set(mach->gpio_pullup, 1);
+ gpio_set_value(mach->gpio_pullup, 1);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
@@ -281,9 +265,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
}
ep->desc = desc;
- ep->dma = -1;
ep->stopped = 0;
- ep->pio_irqs = ep->dma_irqs = 0;
+ ep->pio_irqs = 0;
ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
/* flush fifo (mostly for OUT buffers) */
@@ -291,30 +274,6 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
/* ... reset halt state too, if we could ... */
-#ifdef USE_DMA
- /* for (some) bulk and ISO endpoints, try to get a DMA channel and
- * bind it to the endpoint. otherwise use PIO.
- */
- switch (ep->bmAttributes) {
- case USB_ENDPOINT_XFER_ISOC:
- if (le16_to_cpu(desc->wMaxPacketSize) % 32)
- break;
- // fall through
- case USB_ENDPOINT_XFER_BULK:
- if (!use_dma || !ep->reg_drcmr)
- break;
- ep->dma = pxa_request_dma ((char *)_ep->name,
- (le16_to_cpu (desc->wMaxPacketSize) > 64)
- ? DMA_PRIO_MEDIUM /* some iso */
- : DMA_PRIO_LOW,
- dma_nodesc_handler, ep);
- if (ep->dma >= 0) {
- *ep->reg_drcmr = DRCMR_MAPVLD | ep->dma;
- DMSG("%s using dma%d\n", _ep->name, ep->dma);
- }
- }
-#endif
-
DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);
return 0;
}
@@ -334,14 +293,6 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
nuke (ep, -ESHUTDOWN);
-#ifdef USE_DMA
- if (ep->dma >= 0) {
- *ep->reg_drcmr = 0;
- pxa_free_dma (ep->dma);
- ep->dma = -1;
- }
-#endif
-
/* flush fifo (mostly for IN buffers) */
pxa2xx_ep_fifo_flush (_ep);
@@ -390,35 +341,6 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
-
-/* PXA cache needs flushing with DMA I/O (it's dma-incoherent), but there's
- * no device-affinity and the heap works perfectly well for i/o buffers.
- * It wastes much less memory than dma_alloc_coherent() would, and even
- * prevents cacheline (32 bytes wide) sharing problems.
- */
-static void *
-pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, gfp_t gfp_flags)
-{
- char *retval;
-
- retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM));
- if (retval)
-#ifdef USE_DMA
- *dma = virt_to_bus (retval);
-#else
- *dma = (dma_addr_t)~0;
-#endif
- return retval;
-}
-
-static void
-pxa2xx_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma,
- unsigned bytes)
-{
- kfree (buf);
-}
-
/*-------------------------------------------------------------------------*/
/*
@@ -518,18 +440,8 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
/* requests complete when all IN data is in the FIFO */
if (is_last) {
done (ep, req, 0);
- if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) {
+ if (list_empty(&ep->queue))
pio_irq_disable (ep->bEndpointAddress);
-#ifdef USE_DMA
- /* unaligned data and zlps couldn't use dma */
- if (unlikely(!list_empty(&ep->queue))) {
- req = list_entry(ep->queue.next,
- struct pxa2xx_request, queue);
- kick_dma(ep,req);
- return 0;
- }
-#endif
- }
return 1;
}
@@ -728,182 +640,6 @@ read_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
return 0;
}
-#ifdef USE_DMA
-
-#define MAX_IN_DMA ((DCMD_LENGTH + 1) - BULK_FIFO_SIZE)
-
-static void
-start_dma_nodesc(struct pxa2xx_ep *ep, struct pxa2xx_request *req, int is_in)
-{
- u32 dcmd = req->req.length;
- u32 buf = req->req.dma;
- u32 fifo = io_v2p ((u32)ep->reg_uddr);
-
- /* caller guarantees there's a packet or more remaining
- * - IN may end with a short packet (TSP set separately),
- * - OUT is always full length
- */
- buf += req->req.actual;
- dcmd -= req->req.actual;
- ep->dma_fixup = 0;
-
- /* no-descriptor mode can be simple for bulk-in, iso-in, iso-out */
- DCSR(ep->dma) = DCSR_NODESC;
- if (is_in) {
- DSADR(ep->dma) = buf;
- DTADR(ep->dma) = fifo;
- if (dcmd > MAX_IN_DMA)
- dcmd = MAX_IN_DMA;
- else
- ep->dma_fixup = (dcmd % ep->ep.maxpacket) != 0;
- dcmd |= DCMD_BURST32 | DCMD_WIDTH1
- | DCMD_FLOWTRG | DCMD_INCSRCADDR;
- } else {
-#ifdef USE_OUT_DMA
- DSADR(ep->dma) = fifo;
- DTADR(ep->dma) = buf;
- if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC)
- dcmd = ep->ep.maxpacket;
- dcmd |= DCMD_BURST32 | DCMD_WIDTH1
- | DCMD_FLOWSRC | DCMD_INCTRGADDR;
-#endif
- }
- DCMD(ep->dma) = dcmd;
- DCSR(ep->dma) = DCSR_RUN | DCSR_NODESC
- | (unlikely(is_in)
- ? DCSR_STOPIRQEN /* use dma_nodesc_handler() */
- : 0); /* use handle_ep() */
-}
-
-static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req)
-{
- int is_in = ep->bEndpointAddress & USB_DIR_IN;
-
- if (is_in) {
- /* unaligned tx buffers and zlps only work with PIO */
- if ((req->req.dma & 0x0f) != 0
- || unlikely((req->req.length - req->req.actual)
- == 0)) {
- pio_irq_enable(ep->bEndpointAddress);
- if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0)
- (void) write_fifo(ep, req);
- } else {
- start_dma_nodesc(ep, req, USB_DIR_IN);
- }
- } else {
- if ((req->req.length - req->req.actual) < ep->ep.maxpacket) {
- DMSG("%s short dma read...\n", ep->ep.name);
- /* we're always set up for pio out */
- read_fifo (ep, req);
- } else {
- *ep->reg_udccs = UDCCS_BO_DME
- | (*ep->reg_udccs & UDCCS_BO_FST);
- start_dma_nodesc(ep, req, USB_DIR_OUT);
- }
- }
-}
-
-static void cancel_dma(struct pxa2xx_ep *ep)
-{
- struct pxa2xx_request *req;
- u32 tmp;
-
- if (DCSR(ep->dma) == 0 || list_empty(&ep->queue))
- return;
-
- DCSR(ep->dma) = 0;
- while ((DCSR(ep->dma) & DCSR_STOPSTATE) == 0)
- cpu_relax();
-
- req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
- tmp = DCMD(ep->dma) & DCMD_LENGTH;
- req->req.actual = req->req.length - (tmp & DCMD_LENGTH);
-
- /* the last tx packet may be incomplete, so flush the fifo.
- * FIXME correct req.actual if we can
- */
- if (ep->bEndpointAddress & USB_DIR_IN)
- *ep->reg_udccs = UDCCS_BI_FTF;
-}
-
-/* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */
-static void dma_nodesc_handler(int dmach, void *_ep)
-{
- struct pxa2xx_ep *ep = _ep;
- struct pxa2xx_request *req;
- u32 tmp, completed;
-
- local_irq_disable();
-
- req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
-
- ep->dma_irqs++;
- ep->dev->stats.irqs++;
- HEX_DISPLAY(ep->dev->stats.irqs);
-
- /* ack/clear */
- tmp = DCSR(ep->dma);
- DCSR(ep->dma) = tmp;
- if ((tmp & DCSR_STOPSTATE) == 0
- || (DDADR(ep->dma) & DDADR_STOP) != 0) {
- DBG(DBG_VERBOSE, "%s, dcsr %08x ddadr %08x\n",
- ep->ep.name, DCSR(ep->dma), DDADR(ep->dma));
- goto done;
- }
- DCSR(ep->dma) = 0; /* clear DCSR_STOPSTATE */
-
- /* update transfer status */
- completed = tmp & DCSR_BUSERR;
- if (ep->bEndpointAddress & USB_DIR_IN)
- tmp = DSADR(ep->dma);
- else
- tmp = DTADR(ep->dma);
- req->req.actual = tmp - req->req.dma;
-
- /* FIXME seems we sometimes see partial transfers... */
-
- if (unlikely(completed != 0))
- req->req.status = -EIO;
- else if (req->req.actual) {
- /* these registers have zeroes in low bits; they miscount
- * some (end-of-transfer) short packets: tx 14 as tx 12
- */
- if (ep->dma_fixup)
- req->req.actual = min(req->req.actual + 3,
- req->req.length);
-
- tmp = (req->req.length - req->req.actual);
- completed = (tmp == 0);
- if (completed && (ep->bEndpointAddress & USB_DIR_IN)) {
-
- /* maybe validate final short packet ... */
- if ((req->req.actual % ep->ep.maxpacket) != 0)
- *ep->reg_udccs = UDCCS_BI_TSP/*|UDCCS_BI_TPC*/;
-
- /* ... or zlp, using pio fallback */
- else if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK
- && req->req.zero) {
- DMSG("%s zlp terminate ...\n", ep->ep.name);
- completed = 0;
- }
- }
- }
-
- if (likely(completed)) {
- done(ep, req, 0);
-
- /* maybe re-activate after completion */
- if (ep->stopped || list_empty(&ep->queue))
- goto done;
- req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
- }
- kick_dma(ep, req);
-done:
- local_irq_enable();
-}
-
-#endif
-
/*-------------------------------------------------------------------------*/
static int
@@ -942,19 +678,8 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
(ep->desc->wMaxPacketSize)))
return -EMSGSIZE;
-#ifdef USE_DMA
- // FIXME caller may already have done the dma mapping
- if (ep->dma >= 0) {
- _req->dma = dma_map_single(dev->dev,
- _req->buf, _req->length,
- ((ep->bEndpointAddress & USB_DIR_IN) != 0)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- }
-#endif
-
DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
- _ep->name, _req, _req->length, _req->buf);
+ _ep->name, _req, _req->length, _req->buf);
local_irq_save(flags);
@@ -1002,11 +727,6 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
local_irq_restore (flags);
return -EL2HLT;
}
-#ifdef USE_DMA
- /* either start dma or prime pio pump */
- } else if (ep->dma >= 0) {
- kick_dma(ep, req);
-#endif
/* can the FIFO can satisfy the request immediately? */
} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
@@ -1017,7 +737,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req = NULL;
}
- if (likely (req && ep->desc) && ep->dma < 0)
+ if (likely (req && ep->desc))
pio_irq_enable(ep->bEndpointAddress);
}
@@ -1038,10 +758,6 @@ static void nuke(struct pxa2xx_ep *ep, int status)
struct pxa2xx_request *req;
/* called with irqs blocked */
-#ifdef USE_DMA
- if (ep->dma >= 0 && !ep->stopped)
- cancel_dma(ep);
-#endif
while (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next,
struct pxa2xx_request,
@@ -1076,19 +792,7 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
return -EINVAL;
}
-#ifdef USE_DMA
- if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {
- cancel_dma(ep);
- done(ep, req, -ECONNRESET);
- /* restart i/o */
- if (!list_empty(&ep->queue)) {
- req = list_entry(ep->queue.next,
- struct pxa2xx_request, queue);
- kick_dma(ep, req);
- }
- } else
-#endif
- done(ep, req, -ECONNRESET);
+ done(ep, req, -ECONNRESET);
local_irq_restore(flags);
return 0;
@@ -1203,9 +907,6 @@ static struct usb_ep_ops pxa2xx_ep_ops = {
.alloc_request = pxa2xx_ep_alloc_request,
.free_request = pxa2xx_ep_free_request,
- .alloc_buffer = pxa2xx_ep_alloc_buffer,
- .free_buffer = pxa2xx_ep_free_buffer,
-
.queue = pxa2xx_ep_queue,
.dequeue = pxa2xx_ep_dequeue,
@@ -1325,7 +1026,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
/* basic device status */
t = scnprintf(next, size, DRIVER_DESC "\n"
"%s version: %s\nGadget driver: %s\nHost %s\n\n",
- driver_name, DRIVER_VERSION SIZE_STR DMASTR,
+ driver_name, DRIVER_VERSION SIZE_STR "(pio)",
dev->driver ? dev->driver->driver.name : "(none)",
is_vbus_present() ? "full speed" : "disconnected");
size -= t;
@@ -1390,7 +1091,6 @@ udc_proc_read(char *page, char **start, off_t off, int count,
for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
struct pxa2xx_ep *ep = &dev->ep [i];
struct pxa2xx_request *req;
- int t;
if (i != 0) {
const struct usb_endpoint_descriptor *d;
@@ -1400,10 +1100,9 @@ udc_proc_read(char *page, char **start, off_t off, int count,
continue;
tmp = *dev->ep [i].reg_udccs;
t = scnprintf(next, size,
- "%s max %d %s udccs %02x irqs %lu/%lu\n",
+ "%s max %d %s udccs %02x irqs %lu\n",
ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
- (ep->dma >= 0) ? "dma" : "pio", tmp,
- ep->pio_irqs, ep->dma_irqs);
+ "pio", tmp, ep->pio_irqs);
/* TODO translate all five groups of udccs bits! */
} else /* ep0 should only have one transfer queued */
@@ -1423,19 +1122,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
continue;
}
list_for_each_entry(req, &ep->queue, queue) {
-#ifdef USE_DMA
- if (ep->dma >= 0 && req->queue.prev == &ep->queue)
- t = scnprintf(next, size,
- "\treq %p len %d/%d "
- "buf %p (dma%d dcmd %08x)\n",
- &req->req, req->req.actual,
- req->req.length, req->req.buf,
- ep->dma, DCMD(ep->dma)
- // low 13 bits == bytes-to-go
- );
- else
-#endif
- t = scnprintf(next, size,
+ t = scnprintf(next, size,
"\treq %p len %d/%d buf %p\n",
&req->req, req->req.actual,
req->req.length, req->req.buf);
@@ -1488,7 +1175,6 @@ static void udc_disable(struct pxa2xx_udc *dev)
ep0_idle (dev);
dev->gadget.speed = USB_SPEED_UNKNOWN;
- LED_CONNECTED_OFF;
}
@@ -1514,7 +1200,7 @@ static void udc_reinit(struct pxa2xx_udc *dev)
ep->desc = NULL;
ep->stopped = 0;
INIT_LIST_HEAD (&ep->queue);
- ep->pio_irqs = ep->dma_irqs = 0;
+ ep->pio_irqs = 0;
}
/* the rest was statically initialized, and is read-only */
@@ -1666,7 +1352,6 @@ stop_activity(struct pxa2xx_udc *dev, struct usb_gadget_driver *driver)
del_timer_sync(&dev->timer);
/* report disconnect; the driver is already quiesced */
- LED_CONNECTED_OFF;
if (driver)
driver->disconnect(&dev->gadget);
@@ -1715,16 +1400,13 @@ lubbock_vbus_irq(int irq, void *_dev)
int vbus;
dev->stats.irqs++;
- HEX_DISPLAY(dev->stats.irqs);
switch (irq) {
case LUBBOCK_USB_IRQ:
- LED_CONNECTED_ON;
vbus = 1;
disable_irq(LUBBOCK_USB_IRQ);
enable_irq(LUBBOCK_USB_DISC_IRQ);
break;
case LUBBOCK_USB_DISC_IRQ:
- LED_CONNECTED_OFF;
vbus = 0;
disable_irq(LUBBOCK_USB_DISC_IRQ);
enable_irq(LUBBOCK_USB_IRQ);
@@ -1742,7 +1424,7 @@ lubbock_vbus_irq(int irq, void *_dev)
static irqreturn_t udc_vbus_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
- int vbus = udc_gpio_get(dev->mach->gpio_vbus);
+ int vbus = gpio_get_value(dev->mach->gpio_vbus);
pxa2xx_udc_vbus_session(&dev->gadget, vbus);
return IRQ_HANDLED;
@@ -2040,18 +1722,6 @@ static void handle_ep(struct pxa2xx_ep *ep)
/* fifos can hold packets, ready for reading... */
if (likely(req)) {
-#ifdef USE_OUT_DMA
-// TODO didn't yet debug out-dma. this approach assumes
-// the worst about short packets and RPC; it might be better.
-
- if (likely(ep->dma >= 0)) {
- if (!(udccs & UDCCS_BO_RSP)) {
- *ep->reg_udccs = UDCCS_BO_RPC;
- ep->dma_irqs++;
- return;
- }
- }
-#endif
completed = read_fifo(ep, req);
} else
pio_irq_disable (ep->bEndpointAddress);
@@ -2074,7 +1744,6 @@ pxa2xx_udc_irq(int irq, void *_dev)
int handled;
dev->stats.irqs++;
- HEX_DISPLAY(dev->stats.irqs);
do {
u32 udccr = UDCCR;
@@ -2125,7 +1794,6 @@ pxa2xx_udc_irq(int irq, void *_dev)
} else {
DBG(DBG_VERBOSE, "USB reset end\n");
dev->gadget.speed = USB_SPEED_FULL;
- LED_CONNECTED_ON;
memset(&dev->stats, 0, sizeof dev->stats);
/* driver and endpoints are still reset */
}
@@ -2217,7 +1885,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS1,
.reg_uddr = &UDDR1,
- drcmr (25)
},
.ep[2] = {
.ep = {
@@ -2232,7 +1899,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS2,
.reg_ubcr = &UBCR2,
.reg_uddr = &UDDR2,
- drcmr (26)
},
#ifndef CONFIG_USB_PXA2XX_SMALL
.ep[3] = {
@@ -2247,7 +1913,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS3,
.reg_uddr = &UDDR3,
- drcmr (27)
},
.ep[4] = {
.ep = {
@@ -2262,7 +1927,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS4,
.reg_ubcr = &UBCR4,
.reg_uddr = &UDDR4,
- drcmr (28)
},
.ep[5] = {
.ep = {
@@ -2291,7 +1955,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS6,
.reg_uddr = &UDDR6,
- drcmr (30)
},
.ep[7] = {
.ep = {
@@ -2306,7 +1969,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS7,
.reg_ubcr = &UBCR7,
.reg_uddr = &UDDR7,
- drcmr (31)
},
.ep[8] = {
.ep = {
@@ -2320,7 +1982,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS8,
.reg_uddr = &UDDR8,
- drcmr (32)
},
.ep[9] = {
.ep = {
@@ -2335,7 +1996,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS9,
.reg_ubcr = &UBCR9,
.reg_uddr = &UDDR9,
- drcmr (33)
},
.ep[10] = {
.ep = {
@@ -2364,7 +2024,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS11,
.reg_uddr = &UDDR11,
- drcmr (35)
},
.ep[12] = {
.ep = {
@@ -2379,7 +2038,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS12,
.reg_ubcr = &UBCR12,
.reg_uddr = &UDDR12,
- drcmr (36)
},
.ep[13] = {
.ep = {
@@ -2393,7 +2051,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS13,
.reg_uddr = &UDDR13,
- drcmr (37)
},
.ep[14] = {
.ep = {
@@ -2408,7 +2065,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS14,
.reg_ubcr = &UBCR14,
.reg_uddr = &UDDR14,
- drcmr (38)
},
.ep[15] = {
.ep = {
@@ -2466,7 +2122,7 @@ static struct pxa2xx_udc memory = {
static int __init pxa2xx_udc_probe(struct platform_device *pdev)
{
struct pxa2xx_udc *dev = &memory;
- int retval, out_dma = 1, vbus_irq, irq;
+ int retval, vbus_irq, irq;
u32 chiprev;
/* insist on Intel/ARM/XScale */
@@ -2489,7 +2145,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
case PXA250_B2: case PXA210_B2:
case PXA250_B1: case PXA210_B1:
case PXA250_B0: case PXA210_B0:
- out_dma = 0;
+ /* OUT-DMA is broken ... */
/* fall through */
case PXA250_C0: case PXA210_C0:
break;
@@ -2498,11 +2154,9 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
case IXP425_B0:
case IXP465_AD:
dev->has_cfr = 1;
- out_dma = 0;
break;
#endif
default:
- out_dma = 0;
printk(KERN_ERR "%s: unrecognized processor: %08x\n",
driver_name, chiprev);
/* iop3xx, ixp4xx, ... */
@@ -2513,36 +2167,41 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (irq < 0)
return -ENODEV;
- pr_debug("%s: IRQ %d%s%s%s\n", driver_name, irq,
+ pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,
dev->has_cfr ? "" : " (!cfr)",
- out_dma ? "" : " (broken dma-out)",
- SIZE_STR DMASTR
+ SIZE_STR "(pio)"
);
-#ifdef USE_DMA
-#ifndef USE_OUT_DMA
- out_dma = 0;
-#endif
- /* pxa 250 erratum 130 prevents using OUT dma (fixed C0) */
- if (!out_dma) {
- DMSG("disabled OUT dma\n");
- dev->ep[ 2].reg_drcmr = dev->ep[ 4].reg_drcmr = 0;
- dev->ep[ 7].reg_drcmr = dev->ep[ 9].reg_drcmr = 0;
- dev->ep[12].reg_drcmr = dev->ep[14].reg_drcmr = 0;
- }
-#endif
-
/* other non-static parts of init */
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
+
if (dev->mach->gpio_vbus) {
- udc_gpio_init_vbus(dev->mach->gpio_vbus);
- vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus);
+ if ((retval = gpio_request(dev->mach->gpio_vbus,
+ "pxa2xx_udc GPIO VBUS"))) {
+ dev_dbg(&pdev->dev,
+ "can't get vbus gpio %d, err: %d\n",
+ dev->mach->gpio_vbus, retval);
+ return -EBUSY;
+ }
+ gpio_direction_input(dev->mach->gpio_vbus);
+ vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);
set_irq_type(vbus_irq, IRQT_BOTHEDGE);
} else
vbus_irq = 0;
- if (dev->mach->gpio_pullup)
- udc_gpio_init_pullup(dev->mach->gpio_pullup);
+
+ if (dev->mach->gpio_pullup) {
+ if ((retval = gpio_request(dev->mach->gpio_pullup,
+ "pca2xx_udc GPIO PULLUP"))) {
+ dev_dbg(&pdev->dev,
+ "can't get pullup gpio %d, err: %d\n",
+ dev->mach->gpio_pullup, retval);
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
+ return -EBUSY;
+ }
+ gpio_direction_output(dev->mach->gpio_pullup, 0);
+ }
init_timer(&dev->timer);
dev->timer.function = udc_watchdog;
@@ -2566,6 +2225,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %d, err %d\n",
driver_name, irq, retval);
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
dev->got_irq = 1;
@@ -2581,6 +2244,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
driver_name, LUBBOCK_USB_DISC_IRQ, retval);
lubbock_fail0:
free_irq(irq, dev);
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
retval = request_irq(LUBBOCK_USB_IRQ,
@@ -2593,11 +2260,6 @@ lubbock_fail0:
free_irq(LUBBOCK_USB_DISC_IRQ, dev);
goto lubbock_fail0;
}
-#ifdef DEBUG
- /* with U-Boot (but not BLOB), hex is off by default */
- HEX_DISPLAY(dev->stats.irqs);
- LUB_DISC_BLNK_LED &= 0xff;
-#endif
} else
#endif
if (vbus_irq) {
@@ -2608,6 +2270,10 @@ lubbock_fail0:
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, vbus_irq, retval);
free_irq(irq, dev);
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
}
@@ -2641,8 +2307,13 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
free_irq(LUBBOCK_USB_IRQ, dev);
}
#endif
- if (dev->mach->gpio_vbus)
- free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
+ if (dev->mach->gpio_vbus) {
+ free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
+ gpio_free(dev->mach->gpio_vbus);
+ }
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+
platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 773e549aff3..0e5d0e6fb0e 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -54,8 +54,6 @@ struct pxa2xx_ep {
const struct usb_endpoint_descriptor *desc;
struct list_head queue;
unsigned long pio_irqs;
- unsigned long dma_irqs;
- short dma;
unsigned short fifo_size;
u8 bEndpointAddress;
@@ -63,7 +61,7 @@ struct pxa2xx_ep {
unsigned stopped : 1;
unsigned dma_fixup : 1;
-
+
/* UDCCS = UDC Control/Status for this EP
* UBCR = UDC Byte Count Remaining (contents of OUT fifo)
* UDDR = UDC Endpoint Data Register (the fifo)
@@ -72,12 +70,6 @@ struct pxa2xx_ep {
volatile u32 *reg_udccs;
volatile u32 *reg_ubcr;
volatile u32 *reg_uddr;
-#ifdef USE_DMA
- volatile u32 *reg_drcmr;
-#define drcmr(n) .reg_drcmr = & DRCMR ## n ,
-#else
-#define drcmr(n)
-#endif
};
struct pxa2xx_request {
@@ -85,7 +77,7 @@ struct pxa2xx_request {
struct list_head queue;
};
-enum ep0_state {
+enum ep0_state {
EP0_IDLE,
EP0_IN_DATA_PHASE,
EP0_OUT_DATA_PHASE,
@@ -108,7 +100,6 @@ struct udc_stats {
#ifdef CONFIG_USB_PXA2XX_SMALL
/* when memory's tight, SMALL config saves code+data. */
-#undef USE_DMA
#define PXA_UDC_NUM_ENDPOINTS 3
#endif
@@ -144,37 +135,8 @@ struct pxa2xx_udc {
#ifdef CONFIG_ARCH_LUBBOCK
#include <asm/arch/lubbock.h>
/* lubbock can also report usb connect/disconnect irqs */
-
-#ifdef DEBUG
-#define HEX_DISPLAY(n) if (machine_is_lubbock()) { LUB_HEXLED = (n); }
#endif
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/* LEDs are only for debug */
-#ifndef HEX_DISPLAY
-#define HEX_DISPLAY(n) do {} while(0)
-#endif
-
-#ifdef DEBUG
-#include <asm/leds.h>
-
-#define LED_CONNECTED_ON leds_event(led_green_on)
-#define LED_CONNECTED_OFF do { \
- leds_event(led_green_off); \
- HEX_DISPLAY(0); \
- } while(0)
-#endif
-
-#ifndef LED_CONNECTED_ON
-#define LED_CONNECTED_ON do {} while(0)
-#define LED_CONNECTED_OFF do {} while(0)
-#endif
-
-/*-------------------------------------------------------------------------*/
-
static struct pxa2xx_udc *the_controller;
/*-------------------------------------------------------------------------*/
@@ -204,7 +166,7 @@ static const char *state_name[] = {
# define UDC_DEBUG DBG_NORMAL
#endif
-static void __attribute__ ((__unused__))
+static void __maybe_unused
dump_udccr(const char *label)
{
u32 udccr = UDCCR;
@@ -220,7 +182,7 @@ dump_udccr(const char *label)
(udccr & UDCCR_UDE) ? " ude" : "");
}
-static void __attribute__ ((__unused__))
+static void __maybe_unused
dump_udccs0(const char *label)
{
u32 udccs0 = UDCCS0;
@@ -237,7 +199,7 @@ dump_udccs0(const char *label)
(udccs0 & UDCCS0_OPR) ? " opr" : "");
}
-static void __attribute__ ((__unused__))
+static void __maybe_unused
dump_state(struct pxa2xx_udc *dev)
{
u32 tmp;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 708657c8913..db1b2bfcee4 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -53,7 +53,7 @@
*/
#if 0
-#define DEBUG(str,args...) do { \
+#define DBG(str,args...) do { \
if (rndis_debug) \
printk(KERN_DEBUG str , ## args ); \
} while (0)
@@ -65,7 +65,7 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
#else
#define rndis_debug 0
-#define DEBUG(str,args...) do{}while(0)
+#define DBG(str,args...) do{}while(0)
#endif
#define RNDIS_MAX_CONFIGS 1
@@ -183,9 +183,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
if (!resp) return -ENOMEM;
if (buf_len && rndis_debug > 1) {
- DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
+ DBG("query OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
- DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+ DBG("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpu(get_unaligned((__le32 *)
&buf[i])),
le32_to_cpu(get_unaligned((__le32 *)
@@ -207,7 +207,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
- DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
+ DBG("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
length = sizeof (oid_supported_list);
count = length / sizeof (u32);
for (i = 0; i < count; i++)
@@ -217,7 +217,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_HARDWARE_STATUS:
- DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
/* Bogus question!
* Hardware must be ready to receive high level protocols.
* BTW:
@@ -230,14 +230,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
- DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
- DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
/* one medium, one transport... (maybe you do it better) */
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
@@ -245,7 +245,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MAXIMUM_FRAME_SIZE:
- DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -256,7 +256,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_LINK_SPEED:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
+ DBG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].media_state
== NDIS_MEDIA_STATE_DISCONNECTED)
*outbuf = __constant_cpu_to_le32 (0);
@@ -268,7 +268,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_TRANSMIT_BLOCK_SIZE:
- DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -278,7 +278,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RECEIVE_BLOCK_SIZE:
- DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -288,7 +288,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_VENDOR_ID:
- DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].vendorID);
retval = 0;
@@ -296,7 +296,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_VENDOR_DESCRIPTION:
- DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
memcpy (outbuf,
rndis_per_dev_params [configNr].vendorDescr, length);
@@ -304,7 +304,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
- DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
/* Created as LE */
*outbuf = rndis_driver_version;
retval = 0;
@@ -312,14 +312,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
- DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
+ DBG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
retval = 0;
break;
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
- DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
retval = 0;
break;
@@ -327,14 +327,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MEDIA_CONNECT_STATUS:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.media_state);
retval = 0;
break;
case OID_GEN_PHYSICAL_MEDIUM:
- DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
+ DBG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@@ -344,7 +344,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
* versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
*/
case OID_GEN_MAC_OPTIONS: /* from WinME */
- DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32(
NDIS_MAC_OPTION_RECEIVE_SERIALIZED
| NDIS_MAC_OPTION_FULL_DUPLEX);
@@ -356,7 +356,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_XMIT_OK:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
+ DBG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->tx_packets -
@@ -369,7 +369,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_OK:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->rx_packets -
@@ -382,7 +382,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_XMIT_ERROR:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_errors);
@@ -393,7 +393,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_ERROR:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_errors);
@@ -403,7 +403,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_NO_BUFFER:
- DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_dropped);
@@ -413,7 +413,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
#ifdef RNDIS_OPTIONAL_STATS
case OID_GEN_DIRECTED_BYTES_XMIT:
- DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
/*
* Aunt Tilly's size of shoes
* minus antarctica count of penguins
@@ -433,7 +433,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_DIRECTED_FRAMES_XMIT:
- DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
/* dito */
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
@@ -449,7 +449,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_BYTES_XMIT:
- DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast*1234);
@@ -458,7 +458,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_FRAMES_XMIT:
- DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
@@ -467,7 +467,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_BYTES_XMIT:
- DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42*255);
@@ -476,7 +476,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_FRAMES_XMIT:
- DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42);
@@ -485,19 +485,19 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_DIRECTED_BYTES_RCV:
- DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
- DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
- DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast * 1111);
@@ -506,7 +506,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
- DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
@@ -515,7 +515,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_BYTES_RCV:
- DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42*255);
@@ -524,7 +524,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
- DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42);
@@ -533,7 +533,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_RCV_CRC_ERROR:
- DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_crc_errors);
@@ -542,7 +542,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
- DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
+ DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@@ -552,7 +552,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_PERMANENT_ADDRESS:
- DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
@@ -564,7 +564,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_CURRENT_ADDRESS:
- DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
@@ -576,7 +576,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_MULTICAST_LIST:
- DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32 (0xE0000000);
retval = 0;
@@ -584,21 +584,21 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
- DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32 (1);
retval = 0;
break;
case OID_802_3_MAC_OPTIONS:
- DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
break;
/* ieee802.3 statistics OIDs (table 4-4) */
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
- DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
+ DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_frame_errors);
@@ -608,51 +608,51 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
- DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
- DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
#ifdef RNDIS_OPTIONAL_STATS
case OID_802_3_XMIT_DEFERRED:
- DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_MAX_COLLISIONS:
- DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_RCV_OVERRUN:
- DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
+ DBG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_UNDERRUN:
- DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
- DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_TIMES_CRS_LOST:
- DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_LATE_COLLISIONS:
- DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
/* TODO */
break;
#endif /* RNDIS_OPTIONAL_STATS */
@@ -660,7 +660,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
#ifdef RNDIS_PM
/* power management OIDs (table 4-5) */
case OID_PNP_CAPABILITIES:
- DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
+ DBG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
/* for now, no wakeup capabilities */
length = sizeof (struct NDIS_PNP_CAPABILITIES);
@@ -668,7 +668,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
retval = 0;
break;
case OID_PNP_QUERY_POWER:
- DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
+ DBG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
le32_to_cpu(get_unaligned((__le32 *)buf)) - 1);
/* only suspend is a real power state, and
* it can't be entered by OID_PNP_SET_POWER...
@@ -705,9 +705,9 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
return -ENOMEM;
if (buf_len && rndis_debug > 1) {
- DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
+ DBG("set OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
- DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+ DBG("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpu(get_unaligned((__le32 *)
&buf[i])),
le32_to_cpu(get_unaligned((__le32 *)
@@ -731,7 +731,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
*/
*params->filter = (u16) le32_to_cpu(get_unaligned(
(__le32 *)buf));
- DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
+ DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__FUNCTION__, *params->filter);
/* this call has a significant side effect: it's
@@ -756,7 +756,7 @@ update_linkstate:
case OID_802_3_MULTICAST_LIST:
/* I think we can ignore this */
- DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
retval = 0;
break;
#if 0
@@ -764,7 +764,7 @@ update_linkstate:
{
struct rndis_config_parameter *param;
param = (struct rndis_config_parameter *) buf;
- DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
+ DBG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
__FUNCTION__,
min(cpu_to_le32(param->ParameterNameLength),80),
buf + param->ParameterNameOffset);
@@ -781,7 +781,7 @@ update_linkstate:
* FIXME ... then things go batty; Windows wedges itself.
*/
i = le32_to_cpu(get_unaligned((__le32 *)buf));
- DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
+ DBG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
switch (i) {
case NdisDeviceStateD0:
*params->filter = params->saved_filter;
@@ -858,7 +858,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
rndis_query_cmplt_type *resp;
rndis_resp_t *r;
- // DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
+ // DBG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
/*
@@ -911,15 +911,15 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
BufOffset = le32_to_cpu (buf->InformationBufferOffset);
#ifdef VERBOSE
- DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
- DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
- DEBUG("%s: InfoBuffer: ", __FUNCTION__);
+ DBG("%s: Length: %d\n", __FUNCTION__, BufLength);
+ DBG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
+ DBG("%s: InfoBuffer: ", __FUNCTION__);
for (i = 0; i < BufLength; i++) {
- DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
+ DBG("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
}
- DEBUG ("\n");
+ DBG("\n");
#endif
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
@@ -1082,14 +1082,14 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
/* For USB: responses may take up to 10 seconds */
switch (MsgType) {
case REMOTE_NDIS_INITIALIZE_MSG:
- DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
+ DBG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
__FUNCTION__ );
params->state = RNDIS_INITIALIZED;
return rndis_init_response (configNr,
(rndis_init_msg_type *) buf);
case REMOTE_NDIS_HALT_MSG:
- DEBUG("%s: REMOTE_NDIS_HALT_MSG\n",
+ DBG("%s: REMOTE_NDIS_HALT_MSG\n",
__FUNCTION__ );
params->state = RNDIS_UNINITIALIZED;
if (params->dev) {
@@ -1107,7 +1107,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
(rndis_set_msg_type *) buf);
case REMOTE_NDIS_RESET_MSG:
- DEBUG("%s: REMOTE_NDIS_RESET_MSG\n",
+ DBG("%s: REMOTE_NDIS_RESET_MSG\n",
__FUNCTION__ );
return rndis_reset_response (configNr,
(rndis_reset_msg_type *) buf);
@@ -1115,7 +1115,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
case REMOTE_NDIS_KEEPALIVE_MSG:
/* For USB: host does this every 5 seconds */
if (rndis_debug > 1)
- DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
+ DBG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
__FUNCTION__ );
return rndis_keepalive_response (configNr,
(rndis_keepalive_msg_type *)
@@ -1132,7 +1132,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
{
unsigned i;
for (i = 0; i < MsgLength; i += 16) {
- DEBUG ("%03d: "
+ DBG("%03d: "
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
@@ -1163,18 +1163,18 @@ int rndis_register (int (* rndis_control_ack) (struct net_device *))
if (!rndis_per_dev_params [i].used) {
rndis_per_dev_params [i].used = 1;
rndis_per_dev_params [i].ack = rndis_control_ack;
- DEBUG("%s: configNr = %d\n", __FUNCTION__, i);
+ DBG("%s: configNr = %d\n", __FUNCTION__, i);
return i;
}
}
- DEBUG("failed\n");
+ DBG("failed\n");
return -1;
}
void rndis_deregister (int configNr)
{
- DEBUG("%s: \n", __FUNCTION__ );
+ DBG("%s: \n", __FUNCTION__ );
if (configNr >= RNDIS_MAX_CONFIGS) return;
rndis_per_dev_params [configNr].used = 0;
@@ -1186,7 +1186,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
struct net_device_stats *stats,
u16 *cdc_filter)
{
- DEBUG("%s:\n", __FUNCTION__ );
+ DBG("%s:\n", __FUNCTION__ );
if (!dev || !stats) return -1;
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
@@ -1199,7 +1199,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
{
- DEBUG("%s:\n", __FUNCTION__ );
+ DBG("%s:\n", __FUNCTION__ );
if (!vendorDescr) return -1;
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
@@ -1211,7 +1211,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
{
- DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
+ DBG("%s: %u %u\n", __FUNCTION__, medium, speed);
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
rndis_per_dev_params [configNr].medium = medium;
@@ -1390,7 +1390,7 @@ static int rndis_proc_write (struct file *file, const char __user *buffer,
break;
default:
if (fl_speed) p->speed = speed;
- else DEBUG ("%c is not valid\n", c);
+ else DBG("%c is not valid\n", c);
break;
}
@@ -1419,12 +1419,12 @@ int __devinit rndis_init (void)
if (!(rndis_connect_state [i]
= create_proc_entry (name, 0660, NULL)))
{
- DEBUG ("%s :remove entries", __FUNCTION__);
+ DBG("%s :remove entries", __FUNCTION__);
while (i) {
sprintf (name, NAME_TEMPLATE, --i);
remove_proc_entry (name, NULL);
}
- DEBUG ("\n");
+ DBG("\n");
return -EIO;
}
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
new file mode 100644
index 00000000000..0be80c635c4
--- /dev/null
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -0,0 +1,2045 @@
+/*
+ * linux/drivers/usb/gadget/s3c2410_udc.c
+ *
+ * Samsung S3C24xx series on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard
+ * Additional cleanups by Ben Dooks <ben-linux@fluff.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/clk.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <linux/usb.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-udc.h>
+#include <asm/arch/udc.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c2410_udc.h"
+
+#define DRIVER_DESC "S3C2410 USB Device Controller Gadget"
+#define DRIVER_VERSION "29 Apr 2007"
+#define DRIVER_AUTHOR "Herbert Pötzl <herbert@13thfloor.at>, " \
+ "Arnaud Patard <arnaud.patard@rtp-net.org>"
+
+static const char gadget_name[] = "s3c2410_udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+static struct s3c2410_udc *the_controller;
+static struct clk *udc_clock;
+static struct clk *usb_bus_clock;
+static void __iomem *base_addr;
+static u64 rsrc_start;
+static u64 rsrc_len;
+static struct dentry *s3c2410_udc_debugfs_root;
+
+static inline u32 udc_read(u32 reg)
+{
+ return readb(base_addr + reg);
+}
+
+static inline void udc_write(u32 value, u32 reg)
+{
+ writeb(value, base_addr + reg);
+}
+
+static inline void udc_writeb(void __iomem *base, u32 value, u32 reg)
+{
+ writeb(value, base + reg);
+}
+
+static struct s3c2410_udc_mach_info *udc_info;
+
+/*************************** DEBUG FUNCTION ***************************/
+#define DEBUG_NORMAL 1
+#define DEBUG_VERBOSE 2
+
+#ifdef CONFIG_USB_S3C2410_DEBUG
+#define USB_S3C2410_DEBUG_LEVEL 0
+
+static uint32_t s3c2410_ticks = 0;
+
+static int dprintk(int level, const char *fmt, ...)
+{
+ static char printk_buf[1024];
+ static long prevticks;
+ static int invocation;
+ va_list args;
+ int len;
+
+ if (level > USB_S3C2410_DEBUG_LEVEL)
+ return 0;
+
+ if (s3c2410_ticks != prevticks) {
+ prevticks = s3c2410_ticks;
+ invocation = 0;
+ }
+
+ len = scnprintf(printk_buf,
+ sizeof(printk_buf), "%1lu.%02d USB: ",
+ prevticks, invocation++);
+
+ va_start(args, fmt);
+ len = vscnprintf(printk_buf+len,
+ sizeof(printk_buf)-len, fmt, args);
+ va_end(args);
+
+ return printk(KERN_DEBUG "%s", printk_buf);
+}
+#else
+static int dprintk(int level, const char *fmt, ...)
+{
+ return 0;
+}
+#endif
+static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
+{
+ u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
+ u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;
+ u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2;
+ u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2;
+
+ addr_reg = udc_read(S3C2410_UDC_FUNC_ADDR_REG);
+ pwr_reg = udc_read(S3C2410_UDC_PWR_REG);
+ ep_int_reg = udc_read(S3C2410_UDC_EP_INT_REG);
+ usb_int_reg = udc_read(S3C2410_UDC_USB_INT_REG);
+ ep_int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+ usb_int_en_reg = udc_read(S3C2410_UDC_USB_INT_EN_REG);
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+ ep0_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ udc_write(1, S3C2410_UDC_INDEX_REG);
+ ep1_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ ep1_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG);
+ ep1_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ ep1_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG);
+ udc_write(2, S3C2410_UDC_INDEX_REG);
+ ep2_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ ep2_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG);
+ ep2_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ ep2_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG);
+
+ seq_printf(m, "FUNC_ADDR_REG : 0x%04X\n"
+ "PWR_REG : 0x%04X\n"
+ "EP_INT_REG : 0x%04X\n"
+ "USB_INT_REG : 0x%04X\n"
+ "EP_INT_EN_REG : 0x%04X\n"
+ "USB_INT_EN_REG : 0x%04X\n"
+ "EP0_CSR : 0x%04X\n"
+ "EP1_I_CSR1 : 0x%04X\n"
+ "EP1_I_CSR2 : 0x%04X\n"
+ "EP1_O_CSR1 : 0x%04X\n"
+ "EP1_O_CSR2 : 0x%04X\n"
+ "EP2_I_CSR1 : 0x%04X\n"
+ "EP2_I_CSR2 : 0x%04X\n"
+ "EP2_O_CSR1 : 0x%04X\n"
+ "EP2_O_CSR2 : 0x%04X\n",
+ addr_reg,pwr_reg,ep_int_reg,usb_int_reg,
+ ep_int_en_reg, usb_int_en_reg, ep0_csr,
+ ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2,
+ ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2
+ );
+
+ return 0;
+}
+
+static int s3c2410_udc_debugfs_fops_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, s3c2410_udc_debugfs_seq_show, NULL);
+}
+
+static const struct file_operations s3c2410_udc_debugfs_fops = {
+ .open = s3c2410_udc_debugfs_fops_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+/* io macros */
+
+static inline void s3c2410_udc_clear_ep0_opr(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, S3C2410_UDC_EP0_CSR_SOPKTRDY,
+ S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_clear_ep0_sst(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ writeb(0x00, base + S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_clear_ep0_se(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, S3C2410_UDC_EP0_CSR_SSE, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_ipr(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, S3C2410_UDC_EP0_CSR_IPKRDY, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG);
+}
+
+inline void s3c2410_udc_set_ep0_ss(void __iomem *b)
+{
+ udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+
+ udc_writeb(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY
+ | S3C2410_UDC_EP0_CSR_DE),
+ S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
+ | S3C2410_UDC_EP0_CSR_SSE),
+ S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, (S3C2410_UDC_EP0_CSR_IPKRDY
+ | S3C2410_UDC_EP0_CSR_DE),
+ S3C2410_UDC_EP0_CSR_REG);
+}
+
+/*------------------------- I/O ----------------------------------*/
+
+/*
+ * s3c2410_udc_done
+ */
+static void s3c2410_udc_done(struct s3c2410_ep *ep,
+ struct s3c2410_request *req, int status)
+{
+ unsigned halted = ep->halted;
+
+ list_del_init(&req->queue);
+
+ if (likely (req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ ep->halted = 1;
+ req->req.complete(&ep->ep, &req->req);
+ ep->halted = halted;
+}
+
+static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
+ struct s3c2410_ep *ep, int status)
+{
+ /* Sanity check */
+ if (&ep->queue == NULL)
+ return;
+
+ while (!list_empty (&ep->queue)) {
+ struct s3c2410_request *req;
+ req = list_entry (ep->queue.next, struct s3c2410_request,
+ queue);
+ s3c2410_udc_done(ep, req, status);
+ }
+}
+
+static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
+{
+ unsigned i;
+
+ /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
+ * fifos, and pending transactions mustn't be continued in any case.
+ */
+
+ for (i = 1; i < S3C2410_ENDPOINTS; i++)
+ s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
+}
+
+static inline int s3c2410_udc_fifo_count_out(void)
+{
+ int tmp;
+
+ tmp = udc_read(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;
+ tmp |= udc_read(S3C2410_UDC_OUT_FIFO_CNT1_REG);
+ return tmp;
+}
+
+/*
+ * s3c2410_udc_write_packet
+ */
+static inline int s3c2410_udc_write_packet(int fifo,
+ struct s3c2410_request *req,
+ unsigned max)
+{
+ unsigned len = min(req->req.length - req->req.actual, max);
+ u8 *buf = req->req.buf + req->req.actual;
+
+ prefetch(buf);
+
+ dprintk(DEBUG_VERBOSE, "%s %d %d %d %d\n", __func__,
+ req->req.actual, req->req.length, len, req->req.actual + len);
+
+ req->req.actual += len;
+
+ udelay(5);
+ writesb(base_addr + fifo, buf, len);
+ return len;
+}
+
+/*
+ * s3c2410_udc_write_fifo
+ *
+ * return: 0 = still running, 1 = completed, negative = errno
+ */
+static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep,
+ struct s3c2410_request *req)
+{
+ unsigned count;
+ int is_last;
+ u32 idx;
+ int fifo_reg;
+ u32 ep_csr;
+
+ idx = ep->bEndpointAddress & 0x7F;
+ switch (idx) {
+ default:
+ idx = 0;
+ case 0:
+ fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
+ break;
+ case 1:
+ fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
+ break;
+ case 2:
+ fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
+ break;
+ case 3:
+ fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
+ break;
+ case 4:
+ fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
+ break;
+ }
+
+ count = s3c2410_udc_write_packet(fifo_reg, req, ep->ep.maxpacket);
+
+ /* last packet is often short (sometimes a zlp) */
+ if (count != ep->ep.maxpacket)
+ is_last = 1;
+ else if (req->req.length != req->req.actual || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 2;
+
+ /* Only ep0 debug messages are interesting */
+ if (idx == 0)
+ dprintk(DEBUG_NORMAL,
+ "Written ep%d %d.%d of %d b [last %d,z %d]\n",
+ idx, count, req->req.actual, req->req.length,
+ is_last, req->req.zero);
+
+ if (is_last) {
+ /* The order is important. It prevents sending 2 packets
+ * at the same time */
+
+ if (idx == 0) {
+ /* Reset signal => no need to say 'data sent' */
+ if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+ & S3C2410_UDC_USBINT_RESET))
+ s3c2410_udc_set_ep0_de_in(base_addr);
+ ep->dev->ep0state=EP0_IDLE;
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY,
+ S3C2410_UDC_IN_CSR1_REG);
+ }
+
+ s3c2410_udc_done(ep, req, 0);
+ is_last = 1;
+ } else {
+ if (idx == 0) {
+ /* Reset signal => no need to say 'data sent' */
+ if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+ & S3C2410_UDC_USBINT_RESET))
+ s3c2410_udc_set_ep0_ipr(base_addr);
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY,
+ S3C2410_UDC_IN_CSR1_REG);
+ }
+ }
+
+ return is_last;
+}
+
+static inline int s3c2410_udc_read_packet(int fifo, u8 *buf,
+ struct s3c2410_request *req, unsigned avail)
+{
+ unsigned len;
+
+ len = min(req->req.length - req->req.actual, avail);
+ req->req.actual += len;
+
+ readsb(fifo + base_addr, buf, len);
+ return len;
+}
+
+/*
+ * return: 0 = still running, 1 = queue empty, negative = errno
+ */
+static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep,
+ struct s3c2410_request *req)
+{
+ u8 *buf;
+ u32 ep_csr;
+ unsigned bufferspace;
+ int is_last=1;
+ unsigned avail;
+ int fifo_count = 0;
+ u32 idx;
+ int fifo_reg;
+
+ idx = ep->bEndpointAddress & 0x7F;
+
+ switch (idx) {
+ default:
+ idx = 0;
+ case 0:
+ fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
+ break;
+ case 1:
+ fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
+ break;
+ case 2:
+ fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
+ break;
+ case 3:
+ fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
+ break;
+ case 4:
+ fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
+ break;
+ }
+
+ if (!req->req.length)
+ return 1;
+
+ buf = req->req.buf + req->req.actual;
+ bufferspace = req->req.length - req->req.actual;
+ if (!bufferspace) {
+ dprintk(DEBUG_NORMAL, "%s: buffer full!\n", __func__);
+ return -1;
+ }
+
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+
+ fifo_count = s3c2410_udc_fifo_count_out();
+ dprintk(DEBUG_NORMAL, "%s fifo count : %d\n", __func__, fifo_count);
+
+ if (fifo_count > ep->ep.maxpacket)
+ avail = ep->ep.maxpacket;
+ else
+ avail = fifo_count;
+
+ fifo_count = s3c2410_udc_read_packet(fifo_reg, buf, req, avail);
+
+ /* checking this with ep0 is not accurate as we already
+ * read a control request
+ **/
+ if (idx != 0 && fifo_count < ep->ep.maxpacket) {
+ is_last = 1;
+ /* overflowed this request? flush extra data */
+ if (fifo_count != avail)
+ req->req.status = -EOVERFLOW;
+ } else {
+ is_last = (req->req.length <= req->req.actual) ? 1 : 0;
+ }
+
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ fifo_count = s3c2410_udc_fifo_count_out();
+
+ /* Only ep0 debug messages are interesting */
+ if (idx == 0)
+ dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n",
+ __func__, fifo_count,is_last);
+
+ if (is_last) {
+ if (idx == 0) {
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ ep->dev->ep0state = EP0_IDLE;
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY,
+ S3C2410_UDC_OUT_CSR1_REG);
+ }
+
+ s3c2410_udc_done(ep, req, 0);
+ } else {
+ if (idx == 0) {
+ s3c2410_udc_clear_ep0_opr(base_addr);
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY,
+ S3C2410_UDC_OUT_CSR1_REG);
+ }
+ }
+
+ return is_last;
+}
+
+static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq)
+{
+ unsigned char *outbuf = (unsigned char*)crq;
+ int bytes_read = 0;
+
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+
+ bytes_read = s3c2410_udc_fifo_count_out();
+
+ dprintk(DEBUG_NORMAL, "%s: fifo_count=%d\n", __func__, bytes_read);
+
+ if (bytes_read > sizeof(struct usb_ctrlrequest))
+ bytes_read = sizeof(struct usb_ctrlrequest);
+
+ readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read);
+
+ dprintk(DEBUG_VERBOSE, "%s: len=%d %02x:%02x {%x,%x,%x}\n", __func__,
+ bytes_read, crq->bRequest, crq->bRequestType,
+ crq->wValue, crq->wIndex, crq->wLength);
+
+ return bytes_read;
+}
+
+static int s3c2410_udc_get_status(struct s3c2410_udc *dev,
+ struct usb_ctrlrequest *crq)
+{
+ u16 status = 0;
+ u8 ep_num = crq->wIndex & 0x7F;
+ u8 is_in = crq->wIndex & USB_DIR_IN;
+
+ switch (crq->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_INTERFACE:
+ break;
+
+ case USB_RECIP_DEVICE:
+ status = dev->devstatus;
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ if (ep_num > 4 || crq->wLength > 2)
+ return 1;
+
+ if (ep_num == 0) {
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+ status = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ status = status & S3C2410_UDC_EP0_CSR_SENDSTL;
+ } else {
+ udc_write(ep_num, S3C2410_UDC_INDEX_REG);
+ if (is_in) {
+ status = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ status = status & S3C2410_UDC_ICSR1_SENDSTL;
+ } else {
+ status = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+ status = status & S3C2410_UDC_OCSR1_SENDSTL;
+ }
+ }
+
+ status = status ? 1 : 0;
+ break;
+
+ default:
+ return 1;
+ }
+
+ /* Seems to be needed to get it working. ouch :( */
+ udelay(5);
+ udc_write(status & 0xFF, S3C2410_UDC_EP0_FIFO_REG);
+ udc_write(status >> 8, S3C2410_UDC_EP0_FIFO_REG);
+ s3c2410_udc_set_ep0_de_in(base_addr);
+
+ return 0;
+}
+/*------------------------- usb state machine -------------------------------*/
+static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value);
+
+static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
+ struct s3c2410_ep *ep,
+ struct usb_ctrlrequest *crq,
+ u32 ep0csr)
+{
+ int len, ret, tmp;
+
+ /* start control request? */
+ if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY))
+ return;
+
+ s3c2410_udc_nuke(dev, ep, -EPROTO);
+
+ len = s3c2410_udc_read_fifo_crq(crq);
+ if (len != sizeof(*crq)) {
+ dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR"
+ " wanted %d bytes got %d. Stalling out...\n",
+ sizeof(*crq), len);
+ s3c2410_udc_set_ep0_ss(base_addr);
+ return;
+ }
+
+ dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n",
+ crq->bRequest, crq->bRequestType, crq->wLength);
+
+ /* cope with automagic for some standard requests. */
+ dev->req_std = (crq->bRequestType & USB_TYPE_MASK)
+ == USB_TYPE_STANDARD;
+ dev->req_config = 0;
+ dev->req_pending = 1;
+
+ switch (crq->bRequest) {
+ case USB_REQ_SET_CONFIGURATION:
+ dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");
+
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ dev->req_config = 1;
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ }
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
+
+ if (crq->bRequestType == USB_RECIP_INTERFACE) {
+ dev->req_config = 1;
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ }
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");
+
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ tmp = crq->wValue & 0x7F;
+ dev->address = tmp;
+ udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE),
+ S3C2410_UDC_FUNC_ADDR_REG);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ return;
+ }
+ break;
+
+ case USB_REQ_GET_STATUS:
+ dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");
+ s3c2410_udc_clear_ep0_opr(base_addr);
+
+ if (dev->req_std) {
+ if (!s3c2410_udc_get_status(dev, crq)) {
+ return;
+ }
+ }
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ s3c2410_udc_clear_ep0_opr(base_addr);
+
+ if (crq->bRequestType != USB_RECIP_ENDPOINT)
+ break;
+
+ if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
+ break;
+
+ s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ return;
+
+ case USB_REQ_SET_FEATURE:
+ s3c2410_udc_clear_ep0_opr(base_addr);
+
+ if (crq->bRequestType != USB_RECIP_ENDPOINT)
+ break;
+
+ if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
+ break;
+
+ s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ return;
+
+ default:
+ s3c2410_udc_clear_ep0_opr(base_addr);
+ break;
+ }
+
+ if (crq->bRequestType & USB_DIR_IN)
+ dev->ep0state = EP0_IN_DATA_PHASE;
+ else
+ dev->ep0state = EP0_OUT_DATA_PHASE;
+
+ ret = dev->driver->setup(&dev->gadget, crq);
+ if (ret < 0) {
+ if (dev->req_config) {
+ dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n",
+ crq->bRequest, ret);
+ return;
+ }
+
+ if (ret == -EOPNOTSUPP)
+ dprintk(DEBUG_NORMAL, "Operation not supported\n");
+ else
+ dprintk(DEBUG_NORMAL,
+ "dev->driver->setup failed. (%d)\n", ret);
+
+ udelay(5);
+ s3c2410_udc_set_ep0_ss(base_addr);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ dev->ep0state = EP0_IDLE;
+ /* deferred i/o == no response yet */
+ } else if (dev->req_pending) {
+ dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n");
+ dev->req_pending=0;
+ }
+
+ dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]);
+}
+
+static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev)
+{
+ u32 ep0csr;
+ struct s3c2410_ep *ep = &dev->ep[0];
+ struct s3c2410_request *req;
+ struct usb_ctrlrequest crq;
+
+ if (list_empty(&ep->queue))
+ req = NULL;
+ else
+ req = list_entry(ep->queue.next, struct s3c2410_request, queue);
+
+ /* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to
+ * S3C2410_UDC_EP0_CSR_REG when index is zero */
+
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+ ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+
+ dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n",
+ ep0csr, ep0states[dev->ep0state]);
+
+ /* clear stall status */
+ if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
+ s3c2410_udc_nuke(dev, ep, -EPIPE);
+ dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");
+ s3c2410_udc_clear_ep0_sst(base_addr);
+ dev->ep0state = EP0_IDLE;
+ return;
+ }
+
+ /* clear setup end */
+ if (ep0csr & S3C2410_UDC_EP0_CSR_SE) {
+ dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n");
+ s3c2410_udc_nuke(dev, ep, 0);
+ s3c2410_udc_clear_ep0_se(base_addr);
+ dev->ep0state = EP0_IDLE;
+ }
+
+ switch (dev->ep0state) {
+ case EP0_IDLE:
+ s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
+ break;
+
+ case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */
+ dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
+ if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) {
+ s3c2410_udc_write_fifo(ep, req);
+ }
+ break;
+
+ case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */
+ dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
+ if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) {
+ s3c2410_udc_read_fifo(ep,req);
+ }
+ break;
+
+ case EP0_END_XFER:
+ dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n");
+ dev->ep0state = EP0_IDLE;
+ break;
+
+ case EP0_STALL:
+ dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n");
+ dev->ep0state = EP0_IDLE;
+ break;
+ }
+}
+
+/*
+ * handle_ep - Manage I/O endpoints
+ */
+
+static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+{
+ struct s3c2410_request *req;
+ int is_in = ep->bEndpointAddress & USB_DIR_IN;
+ u32 ep_csr1;
+ u32 idx;
+
+ if (likely (!list_empty(&ep->queue)))
+ req = list_entry(ep->queue.next,
+ struct s3c2410_request, queue);
+ else
+ req = NULL;
+
+ idx = ep->bEndpointAddress & 0x7F;
+
+ if (is_in) {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n",
+ idx, ep_csr1, req ? 1 : 0);
+
+ if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) {
+ dprintk(DEBUG_VERBOSE, "st\n");
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr1 & ~S3C2410_UDC_ICSR1_SENTSTL,
+ S3C2410_UDC_IN_CSR1_REG);
+ return;
+ }
+
+ if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) {
+ s3c2410_udc_write_fifo(ep,req);
+ }
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+ dprintk(DEBUG_VERBOSE, "ep%01d rd csr:%02x\n", idx, ep_csr1);
+
+ if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr1 & ~S3C2410_UDC_OCSR1_SENTSTL,
+ S3C2410_UDC_OUT_CSR1_REG);
+ return;
+ }
+
+ if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
+ s3c2410_udc_read_fifo(ep,req);
+ }
+ }
+}
+
+#include <asm/arch/regs-irq.h>
+
+/*
+ * s3c2410_udc_irq - interrupt handler
+ */
+static irqreturn_t s3c2410_udc_irq(int irq, void *_dev)
+{
+ struct s3c2410_udc *dev = _dev;
+ int usb_status;
+ int usbd_status;
+ int pwr_reg;
+ int ep0csr;
+ int i;
+ u32 idx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* Driver connected ? */
+ if (!dev->driver) {
+ /* Clear interrupts */
+ udc_write(udc_read(S3C2410_UDC_USB_INT_REG),
+ S3C2410_UDC_USB_INT_REG);
+ udc_write(udc_read(S3C2410_UDC_EP_INT_REG),
+ S3C2410_UDC_EP_INT_REG);
+ }
+
+ /* Save index */
+ idx = udc_read(S3C2410_UDC_INDEX_REG);
+
+ /* Read status registers */
+ usb_status = udc_read(S3C2410_UDC_USB_INT_REG);
+ usbd_status = udc_read(S3C2410_UDC_EP_INT_REG);
+ pwr_reg = udc_read(S3C2410_UDC_PWR_REG);
+
+ udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+
+ dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n",
+ usb_status, usbd_status, pwr_reg, ep0csr);
+
+ /*
+ * Now, handle interrupts. There's two types :
+ * - Reset, Resume, Suspend coming -> usb_int_reg
+ * - EP -> ep_int_reg
+ */
+
+ /* RESET */
+ if (usb_status & S3C2410_UDC_USBINT_RESET) {
+ /* two kind of reset :
+ * - reset start -> pwr reg = 8
+ * - reset end -> pwr reg = 0
+ **/
+ dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n",
+ ep0csr, pwr_reg);
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+ udc_write(0x00, S3C2410_UDC_INDEX_REG);
+ udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3,
+ S3C2410_UDC_MAXP_REG);
+ dev->address = 0;
+
+ dev->ep0state = EP0_IDLE;
+ dev->gadget.speed = USB_SPEED_FULL;
+
+ /* clear interrupt */
+ udc_write(S3C2410_UDC_USBINT_RESET,
+ S3C2410_UDC_USB_INT_REG);
+
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ /* RESUME */
+ if (usb_status & S3C2410_UDC_USBINT_RESUME) {
+ dprintk(DEBUG_NORMAL, "USB resume\n");
+
+ /* clear interrupt */
+ udc_write(S3C2410_UDC_USBINT_RESUME,
+ S3C2410_UDC_USB_INT_REG);
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ && dev->driver
+ && dev->driver->resume)
+ dev->driver->resume(&dev->gadget);
+ }
+
+ /* SUSPEND */
+ if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {
+ dprintk(DEBUG_NORMAL, "USB suspend\n");
+
+ /* clear interrupt */
+ udc_write(S3C2410_UDC_USBINT_SUSPEND,
+ S3C2410_UDC_USB_INT_REG);
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ && dev->driver
+ && dev->driver->suspend)
+ dev->driver->suspend(&dev->gadget);
+
+ dev->ep0state = EP0_IDLE;
+ }
+
+ /* EP */
+ /* control traffic */
+ /* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready
+ * generate an interrupt
+ */
+ if (usbd_status & S3C2410_UDC_INT_EP0) {
+ dprintk(DEBUG_VERBOSE, "USB ep0 irq\n");
+ /* Clear the interrupt bit by setting it to 1 */
+ udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
+ s3c2410_udc_handle_ep0(dev);
+ }
+
+ /* endpoint data transfers */
+ for (i = 1; i < S3C2410_ENDPOINTS; i++) {
+ u32 tmp = 1 << i;
+ if (usbd_status & tmp) {
+ dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i);
+
+ /* Clear the interrupt bit by setting it to 1 */
+ udc_write(tmp, S3C2410_UDC_EP_INT_REG);
+ s3c2410_udc_handle_ep(&dev->ep[i]);
+ }
+ }
+
+ dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq);
+
+ /* Restore old index */
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return IRQ_HANDLED;
+}
+/*------------------------- s3c2410_ep_ops ----------------------------------*/
+
+static inline struct s3c2410_ep *to_s3c2410_ep(struct usb_ep *ep)
+{
+ return container_of(ep, struct s3c2410_ep, ep);
+}
+
+static inline struct s3c2410_udc *to_s3c2410_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct s3c2410_udc, gadget);
+}
+
+static inline struct s3c2410_request *to_s3c2410_req(struct usb_request *req)
+{
+ return container_of(req, struct s3c2410_request, req);
+}
+
+/*
+ * s3c2410_udc_ep_enable
+ */
+static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct s3c2410_udc *dev;
+ struct s3c2410_ep *ep;
+ u32 max, tmp;
+ unsigned long flags;
+ u32 csr1,csr2;
+ u32 int_en_reg;
+
+ ep = to_s3c2410_ep(_ep);
+
+ if (!_ep || !desc || ep->desc
+ || _ep->name == ep0name
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+
+ dev = ep->dev;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+
+ local_irq_save (flags);
+ _ep->maxpacket = max & 0x7ff;
+ ep->desc = desc;
+ ep->halted = 0;
+ ep->bEndpointAddress = desc->bEndpointAddress;
+
+ /* set max packet */
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(max >> 3, S3C2410_UDC_MAXP_REG);
+
+ /* set type, direction, address; reset fifo counters */
+ if (desc->bEndpointAddress & USB_DIR_IN) {
+ csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT;
+ csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN;
+
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr1, S3C2410_UDC_IN_CSR1_REG);
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr2, S3C2410_UDC_IN_CSR2_REG);
+ } else {
+ /* don't flush in fifo or it will cause endpoint interrupt */
+ csr1 = S3C2410_UDC_ICSR1_CLRDT;
+ csr2 = S3C2410_UDC_ICSR2_DMAIEN;
+
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr1, S3C2410_UDC_IN_CSR1_REG);
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr2, S3C2410_UDC_IN_CSR2_REG);
+
+ csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT;
+ csr2 = S3C2410_UDC_OCSR2_DMAIEN;
+
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr1, S3C2410_UDC_OUT_CSR1_REG);
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr2, S3C2410_UDC_OUT_CSR2_REG);
+ }
+
+ /* enable irqs */
+ int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+ udc_write(int_en_reg | (1 << ep->num), S3C2410_UDC_EP_INT_EN_REG);
+
+ /* print some debug message */
+ tmp = desc->bEndpointAddress;
+ dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
+ _ep->name,ep->num, tmp,
+ desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max);
+
+ local_irq_restore (flags);
+ s3c2410_udc_set_halt(_ep, 0);
+
+ return 0;
+}
+
+/*
+ * s3c2410_udc_ep_disable
+ */
+static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
+{
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ unsigned long flags;
+ u32 int_en_reg;
+
+ if (!_ep || !ep->desc) {
+ dprintk(DEBUG_NORMAL, "%s not enabled\n",
+ _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+
+ dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
+
+ ep->desc = NULL;
+ ep->halted = 1;
+
+ s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);
+
+ /* disable irqs */
+ int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+ udc_write(int_en_reg & ~(1<<ep->num), S3C2410_UDC_EP_INT_EN_REG);
+
+ local_irq_restore(flags);
+
+ dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name);
+
+ return 0;
+}
+
+/*
+ * s3c2410_udc_alloc_request
+ */
+static struct usb_request *
+s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags)
+{
+ struct s3c2410_request *req;
+
+ dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags);
+
+ if (!_ep)
+ return NULL;
+
+ req = kzalloc (sizeof(struct s3c2410_request), mem_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD (&req->queue);
+ return &req->req;
+}
+
+/*
+ * s3c2410_udc_free_request
+ */
+static void
+s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ struct s3c2410_request *req = to_s3c2410_req(_req);
+
+ dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
+
+ if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+ return;
+
+ WARN_ON (!list_empty (&req->queue));
+ kfree(req);
+}
+
+/*
+ * s3c2410_udc_queue
+ */
+static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct s3c2410_request *req = to_s3c2410_req(_req);
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ struct s3c2410_udc *dev;
+ u32 ep_csr = 0;
+ int fifo_count = 0;
+ unsigned long flags;
+
+ if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__);
+ return -EINVAL;
+ }
+
+ dev = ep->dev;
+ if (unlikely (!dev->driver
+ || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+ return -ESHUTDOWN;
+ }
+
+ local_irq_save (flags);
+
+ if (unlikely(!_req || !_req->complete
+ || !_req->buf || !list_empty(&req->queue))) {
+ if (!_req)
+ dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__);
+ else {
+ dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n",
+ __func__, !_req->complete,!_req->buf,
+ !list_empty(&req->queue));
+ }
+
+ local_irq_restore(flags);
+ return -EINVAL;
+ }
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n",
+ __func__, ep->bEndpointAddress, _req->length);
+
+ if (ep->bEndpointAddress) {
+ udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG);
+
+ ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN)
+ ? S3C2410_UDC_IN_CSR1_REG
+ : S3C2410_UDC_OUT_CSR1_REG);
+ fifo_count = s3c2410_udc_fifo_count_out();
+ } else {
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ fifo_count = s3c2410_udc_fifo_count_out();
+ }
+
+ /* kickstart this i/o queue? */
+ if (list_empty(&ep->queue) && !ep->halted) {
+ if (ep->bEndpointAddress == 0 /* ep0 */) {
+ switch (dev->ep0state) {
+ case EP0_IN_DATA_PHASE:
+ if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY)
+ && s3c2410_udc_write_fifo(ep,
+ req)) {
+ dev->ep0state = EP0_IDLE;
+ req = NULL;
+ }
+ break;
+
+ case EP0_OUT_DATA_PHASE:
+ if ((!_req->length)
+ || ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
+ && s3c2410_udc_read_fifo(ep,
+ req))) {
+ dev->ep0state = EP0_IDLE;
+ req = NULL;
+ }
+ break;
+
+ default:
+ local_irq_restore(flags);
+ return -EL2HLT;
+ }
+ } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
+ && (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY))
+ && s3c2410_udc_write_fifo(ep, req)) {
+ req = NULL;
+ } else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
+ && fifo_count
+ && s3c2410_udc_read_fifo(ep, req)) {
+ req = NULL;
+ }
+ }
+
+ /* pio or dma irq handler advances the queue. */
+ if (likely (req != 0))
+ list_add_tail(&req->queue, &ep->queue);
+
+ local_irq_restore(flags);
+
+ dprintk(DEBUG_VERBOSE, "%s ok\n", __func__);
+ return 0;
+}
+
+/*
+ * s3c2410_udc_dequeue
+ */
+static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ struct s3c2410_udc *udc;
+ int retval = -EINVAL;
+ unsigned long flags;
+ struct s3c2410_request *req = NULL;
+
+ dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
+
+ if (!the_controller->driver)
+ return -ESHUTDOWN;
+
+ if (!_ep || !_req)
+ return retval;
+
+ udc = to_s3c2410_udc(ep->gadget);
+
+ local_irq_save (flags);
+
+ list_for_each_entry (req, &ep->queue, queue) {
+ if (&req->req == _req) {
+ list_del_init (&req->queue);
+ _req->status = -ECONNRESET;
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval == 0) {
+ dprintk(DEBUG_VERBOSE,
+ "dequeued req %p from %s, len %d buf %p\n",
+ req, _ep->name, _req->length, _req->buf);
+
+ s3c2410_udc_done(ep, req, -ECONNRESET);
+ }
+
+ local_irq_restore (flags);
+ return retval;
+}
+
+/*
+ * s3c2410_udc_set_halt
+ */
+static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value)
+{
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ u32 ep_csr = 0;
+ unsigned long flags;
+ u32 idx;
+
+ if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__);
+ return -EINVAL;
+ }
+
+ local_irq_save (flags);
+
+ idx = ep->bEndpointAddress & 0x7F;
+
+ if (idx == 0) {
+ s3c2410_udc_set_ep0_ss(base_addr);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN)
+ ? S3C2410_UDC_IN_CSR1_REG
+ : S3C2410_UDC_OUT_CSR1_REG);
+
+ if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+ if (value)
+ udc_write(ep_csr | S3C2410_UDC_ICSR1_SENDSTL,
+ S3C2410_UDC_IN_CSR1_REG);
+ else {
+ ep_csr &= ~S3C2410_UDC_ICSR1_SENDSTL;
+ udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG);
+ ep_csr |= S3C2410_UDC_ICSR1_CLRDT;
+ udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG);
+ }
+ } else {
+ if (value)
+ udc_write(ep_csr | S3C2410_UDC_OCSR1_SENDSTL,
+ S3C2410_UDC_OUT_CSR1_REG);
+ else {
+ ep_csr &= ~S3C2410_UDC_OCSR1_SENDSTL;
+ udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG);
+ ep_csr |= S3C2410_UDC_OCSR1_CLRDT;
+ udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG);
+ }
+ }
+ }
+
+ ep->halted = value ? 1 : 0;
+ local_irq_restore (flags);
+
+ return 0;
+}
+
+static const struct usb_ep_ops s3c2410_ep_ops = {
+ .enable = s3c2410_udc_ep_enable,
+ .disable = s3c2410_udc_ep_disable,
+
+ .alloc_request = s3c2410_udc_alloc_request,
+ .free_request = s3c2410_udc_free_request,
+
+ .queue = s3c2410_udc_queue,
+ .dequeue = s3c2410_udc_dequeue,
+
+ .set_halt = s3c2410_udc_set_halt,
+};
+
+/*------------------------- usb_gadget_ops ----------------------------------*/
+
+/*
+ * s3c2410_udc_get_frame
+ */
+static int s3c2410_udc_get_frame(struct usb_gadget *_gadget)
+{
+ int tmp;
+
+ dprintk(DEBUG_VERBOSE, "%s()\n", __func__);
+
+ tmp = udc_read(S3C2410_UDC_FRAME_NUM2_REG) << 8;
+ tmp |= udc_read(S3C2410_UDC_FRAME_NUM1_REG);
+ return tmp;
+}
+
+/*
+ * s3c2410_udc_wakeup
+ */
+static int s3c2410_udc_wakeup(struct usb_gadget *_gadget)
+{
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+ return 0;
+}
+
+/*
+ * s3c2410_udc_set_selfpowered
+ */
+static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value)
+{
+ struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ if (value)
+ udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
+ else
+ udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+ return 0;
+}
+
+static void s3c2410_udc_disable(struct s3c2410_udc *dev);
+static void s3c2410_udc_enable(struct s3c2410_udc *dev);
+
+static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on)
+{
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ if (udc_info && udc_info->udc_command) {
+ if (is_on)
+ s3c2410_udc_enable(udc);
+ else {
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+ if (udc->driver && udc->driver->disconnect)
+ udc->driver->disconnect(&udc->gadget);
+
+ }
+ s3c2410_udc_disable(udc);
+ }
+ }
+ else
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int s3c2410_udc_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ udc->vbus = (is_active != 0);
+ s3c2410_udc_set_pullup(udc, is_active);
+ return 0;
+}
+
+static int s3c2410_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ s3c2410_udc_set_pullup(udc, is_on ? 0 : 1);
+ return 0;
+}
+
+static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
+{
+ struct s3c2410_udc *dev = _dev;
+ unsigned int value;
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+ value = s3c2410_gpio_getpin(udc_info->vbus_pin);
+
+ if (udc_info->vbus_pin_inverted)
+ value = !value;
+
+ if (value != dev->vbus)
+ s3c2410_udc_vbus_session(&dev->gadget, value);
+
+ return IRQ_HANDLED;
+}
+
+static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
+{
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ if (udc_info && udc_info->vbus_draw) {
+ udc_info->vbus_draw(ma);
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+static const struct usb_gadget_ops s3c2410_ops = {
+ .get_frame = s3c2410_udc_get_frame,
+ .wakeup = s3c2410_udc_wakeup,
+ .set_selfpowered = s3c2410_udc_set_selfpowered,
+ .pullup = s3c2410_udc_pullup,
+ .vbus_session = s3c2410_udc_vbus_session,
+ .vbus_draw = s3c2410_vbus_draw,
+};
+
+/*------------------------- gadget driver handling---------------------------*/
+/*
+ * s3c2410_udc_disable
+ */
+static void s3c2410_udc_disable(struct s3c2410_udc *dev)
+{
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ /* Disable all interrupts */
+ udc_write(0x00, S3C2410_UDC_USB_INT_EN_REG);
+ udc_write(0x00, S3C2410_UDC_EP_INT_EN_REG);
+
+ /* Clear the interrupt registers */
+ udc_write(S3C2410_UDC_USBINT_RESET
+ | S3C2410_UDC_USBINT_RESUME
+ | S3C2410_UDC_USBINT_SUSPEND,
+ S3C2410_UDC_USB_INT_REG);
+
+ udc_write(0x1F, S3C2410_UDC_EP_INT_REG);
+
+ /* Good bye, cruel world */
+ if (udc_info && udc_info->udc_command)
+ udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+
+ /* Set speed to unknown */
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+/*
+ * s3c2410_udc_reinit
+ */
+static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
+{
+ u32 i;
+
+ /* device/ep0 records init */
+ INIT_LIST_HEAD (&dev->gadget.ep_list);
+ INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+ dev->ep0state = EP0_IDLE;
+
+ for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+ struct s3c2410_ep *ep = &dev->ep[i];
+
+ if (i != 0)
+ list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+
+ ep->dev = dev;
+ ep->desc = NULL;
+ ep->halted = 0;
+ INIT_LIST_HEAD (&ep->queue);
+ }
+}
+
+/*
+ * s3c2410_udc_enable
+ */
+static void s3c2410_udc_enable(struct s3c2410_udc *dev)
+{
+ int i;
+
+ dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n");
+
+ /* dev->gadget.speed = USB_SPEED_UNKNOWN; */
+ dev->gadget.speed = USB_SPEED_FULL;
+
+ /* Set MAXP for all endpoints */
+ for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+ udc_write(i, S3C2410_UDC_INDEX_REG);
+ udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3,
+ S3C2410_UDC_MAXP_REG);
+ }
+
+ /* Set default power state */
+ udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG);
+
+ /* Enable reset and suspend interrupt interrupts */
+ udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND,
+ S3C2410_UDC_USB_INT_EN_REG);
+
+ /* Enable ep0 interrupt */
+ udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);
+
+ /* time to say "hello, world" */
+ if (udc_info && udc_info->udc_command)
+ udc_info->udc_command(S3C2410_UDC_P_ENABLE);
+}
+
+/*
+ * usb_gadget_register_driver
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct s3c2410_udc *udc = the_controller;
+ int retval;
+
+ dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n",
+ driver->driver.name);
+
+ /* Sanity checks */
+ if (!udc)
+ return -ENODEV;
+
+ if (udc->driver)
+ return -EBUSY;
+
+ if (!driver->bind || !driver->setup
+ || driver->speed != USB_SPEED_FULL) {
+ printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
+ driver->bind, driver->setup, driver->speed);
+ return -EINVAL;
+ }
+#if defined(MODULE)
+ if (!driver->unbind) {
+ printk(KERN_ERR "Invalid driver: no unbind method\n");
+ return -EINVAL;
+ }
+#endif
+
+ /* Hook the driver */
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+
+ /* Bind the driver */
+ if ((retval = device_add(&udc->gadget.dev)) != 0) {
+ printk(KERN_ERR "Error in device_add() : %d\n",retval);
+ goto register_error;
+ }
+
+ dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",
+ driver->driver.name);
+
+ if ((retval = driver->bind (&udc->gadget)) != 0) {
+ device_del(&udc->gadget.dev);
+ goto register_error;
+ }
+
+ /* Enable udc */
+ s3c2410_udc_enable(udc);
+
+ return 0;
+
+register_error:
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return retval;
+}
+
+/*
+ * usb_gadget_unregister_driver
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct s3c2410_udc *udc = the_controller;
+
+ if (!udc)
+ return -ENODEV;
+
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n",
+ driver->driver.name);
+
+ if (driver->disconnect)
+ driver->disconnect(&udc->gadget);
+
+ device_del(&udc->gadget.dev);
+ udc->driver = NULL;
+
+ /* Disable udc */
+ s3c2410_udc_disable(udc);
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static struct s3c2410_udc memory = {
+ .gadget = {
+ .ops = &s3c2410_ops,
+ .ep0 = &memory.ep[0].ep,
+ .name = gadget_name,
+ .dev = {
+ .bus_id = "gadget",
+ },
+ },
+
+ /* control endpoint */
+ .ep[0] = {
+ .num = 0,
+ .ep = {
+ .name = ep0name,
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP0_FIFO_SIZE,
+ },
+ .dev = &memory,
+ },
+
+ /* first group of endpoints */
+ .ep[1] = {
+ .num = 1,
+ .ep = {
+ .name = "ep1-bulk",
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+ .fifo_size = EP_FIFO_SIZE,
+ .bEndpointAddress = 1,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .ep[2] = {
+ .num = 2,
+ .ep = {
+ .name = "ep2-bulk",
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+ .fifo_size = EP_FIFO_SIZE,
+ .bEndpointAddress = 2,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .ep[3] = {
+ .num = 3,
+ .ep = {
+ .name = "ep3-bulk",
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+ .fifo_size = EP_FIFO_SIZE,
+ .bEndpointAddress = 3,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .ep[4] = {
+ .num = 4,
+ .ep = {
+ .name = "ep4-bulk",
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+ .fifo_size = EP_FIFO_SIZE,
+ .bEndpointAddress = 4,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ }
+
+};
+
+/*
+ * probe - binds to the platform device
+ */
+static int s3c2410_udc_probe(struct platform_device *pdev)
+{
+ struct s3c2410_udc *udc = &memory;
+ struct device *dev = &pdev->dev;
+ int retval;
+ unsigned int irq;
+
+ dev_dbg(dev, "%s()\n", __func__);
+
+ usb_bus_clock = clk_get(NULL, "usb-bus-gadget");
+ if (IS_ERR(usb_bus_clock)) {
+ dev_err(dev, "failed to get usb bus clock source\n");
+ return PTR_ERR(usb_bus_clock);
+ }
+
+ clk_enable(usb_bus_clock);
+
+ udc_clock = clk_get(NULL, "usb-device");
+ if (IS_ERR(udc_clock)) {
+ dev_err(dev, "failed to get udc clock source\n");
+ return PTR_ERR(udc_clock);
+ }
+
+ clk_enable(udc_clock);
+
+ mdelay(10);
+
+ dev_dbg(dev, "got and enabled clocks\n");
+
+ if (strncmp(pdev->name, "s3c2440", 7) == 0) {
+ dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n");
+ memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE;
+ memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE;
+ memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE;
+ memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
+ }
+
+ spin_lock_init (&udc->lock);
+ udc_info = pdev->dev.platform_data;
+
+ rsrc_start = S3C2410_PA_USBDEV;
+ rsrc_len = S3C24XX_SZ_USBDEV;
+
+ if (!request_mem_region(rsrc_start, rsrc_len, gadget_name))
+ return -EBUSY;
+
+ base_addr = ioremap(rsrc_start, rsrc_len);
+ if (!base_addr) {
+ retval = -ENOMEM;
+ goto err_mem;
+ }
+
+ device_initialize(&udc->gadget.dev);
+ udc->gadget.dev.parent = &pdev->dev;
+ udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ the_controller = udc;
+ platform_set_drvdata(pdev, udc);
+
+ s3c2410_udc_disable(udc);
+ s3c2410_udc_reinit(udc);
+
+ /* irq setup after old hardware state is cleaned up */
+ retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
+ IRQF_DISABLED, gadget_name, udc);
+
+ if (retval != 0) {
+ dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval);
+ retval = -EBUSY;
+ goto err_map;
+ }
+
+ dev_dbg(dev, "got irq %i\n", IRQ_USBD);
+
+ if (udc_info && udc_info->vbus_pin > 0) {
+ irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+ retval = request_irq(irq, s3c2410_udc_vbus_irq,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING
+ | IRQF_TRIGGER_FALLING,
+ gadget_name, udc);
+
+ if (retval != 0) {
+ dev_err(dev, "can't get vbus irq %i, err %d\n",
+ irq, retval);
+ retval = -EBUSY;
+ goto err_int;
+ }
+
+ dev_dbg(dev, "got irq %i\n", irq);
+ } else {
+ udc->vbus = 1;
+ }
+
+ if (s3c2410_udc_debugfs_root) {
+ udc->regs_info = debugfs_create_file("registers", S_IRUGO,
+ s3c2410_udc_debugfs_root,
+ udc, &s3c2410_udc_debugfs_fops);
+ if (IS_ERR(udc->regs_info)) {
+ dev_warn(dev, "debugfs file creation failed %ld\n",
+ PTR_ERR(udc->regs_info));
+ udc->regs_info = NULL;
+ }
+ }
+
+ dev_dbg(dev, "probe ok\n");
+
+ return 0;
+
+err_int:
+ free_irq(IRQ_USBD, udc);
+err_map:
+ iounmap(base_addr);
+err_mem:
+ release_mem_region(rsrc_start, rsrc_len);
+
+ return retval;
+}
+
+/*
+ * s3c2410_udc_remove
+ */
+static int s3c2410_udc_remove(struct platform_device *pdev)
+{
+ struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+ unsigned int irq;
+
+ dev_dbg(&pdev->dev, "%s()\n", __func__);
+ if (udc->driver)
+ return -EBUSY;
+
+ debugfs_remove(udc->regs_info);
+
+ if (udc_info && udc_info->vbus_pin > 0) {
+ irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+ free_irq(irq, udc);
+ }
+
+ free_irq(IRQ_USBD, udc);
+
+ iounmap(base_addr);
+ release_mem_region(rsrc_start, rsrc_len);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (!IS_ERR(udc_clock) && udc_clock != NULL) {
+ clk_disable(udc_clock);
+ clk_put(udc_clock);
+ udc_clock = NULL;
+ }
+
+ if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) {
+ clk_disable(usb_bus_clock);
+ clk_put(usb_bus_clock);
+ usb_bus_clock = NULL;
+ }
+
+ dev_dbg(&pdev->dev, "%s: remove ok\n", __func__);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ if (udc_info && udc_info->udc_command)
+ udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+
+ return 0;
+}
+
+static int s3c2410_udc_resume(struct platform_device *pdev)
+{
+ if (udc_info && udc_info->udc_command)
+ udc_info->udc_command(S3C2410_UDC_P_ENABLE);
+
+ return 0;
+}
+#else
+#define s3c2410_udc_suspend NULL
+#define s3c2410_udc_resume NULL
+#endif
+
+static struct platform_driver udc_driver_2410 = {
+ .driver = {
+ .name = "s3c2410-usbgadget",
+ .owner = THIS_MODULE,
+ },
+ .probe = s3c2410_udc_probe,
+ .remove = s3c2410_udc_remove,
+ .suspend = s3c2410_udc_suspend,
+ .resume = s3c2410_udc_resume,
+};
+
+static struct platform_driver udc_driver_2440 = {
+ .driver = {
+ .name = "s3c2440-usbgadget",
+ .owner = THIS_MODULE,
+ },
+ .probe = s3c2410_udc_probe,
+ .remove = s3c2410_udc_remove,
+ .suspend = s3c2410_udc_suspend,
+ .resume = s3c2410_udc_resume,
+};
+
+static int __init udc_init(void)
+{
+ int retval;
+
+ dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
+
+ s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
+ if (IS_ERR(s3c2410_udc_debugfs_root)) {
+ printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
+ gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
+ s3c2410_udc_debugfs_root = NULL;
+ }
+
+ retval = platform_driver_register(&udc_driver_2410);
+ if (retval)
+ goto err;
+
+ retval = platform_driver_register(&udc_driver_2440);
+ if (retval)
+ goto err;
+
+ return 0;
+
+err:
+ debugfs_remove(s3c2410_udc_debugfs_root);
+ return retval;
+}
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver_2410);
+ platform_driver_unregister(&udc_driver_2440);
+ debugfs_remove(s3c2410_udc_debugfs_root);
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+module_init(udc_init);
+module_exit(udc_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h
new file mode 100644
index 00000000000..9e0bece4f24
--- /dev/null
+++ b/drivers/usb/gadget/s3c2410_udc.h
@@ -0,0 +1,110 @@
+/*
+ * linux/drivers/usb/gadget/s3c2410_udc.h
+ * Samsung on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard
+ * Additional cleanups by Ben Dooks <ben-linux@fluff.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _S3C2410_UDC_H
+#define _S3C2410_UDC_H
+
+struct s3c2410_ep {
+ struct list_head queue;
+ unsigned long last_io; /* jiffies timestamp */
+ struct usb_gadget *gadget;
+ struct s3c2410_udc *dev;
+ const struct usb_endpoint_descriptor *desc;
+ struct usb_ep ep;
+ u8 num;
+
+ unsigned short fifo_size;
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+
+ unsigned halted : 1;
+ unsigned already_seen : 1;
+ unsigned setup_stage : 1;
+};
+
+
+/* Warning : ep0 has a fifo of 16 bytes */
+/* Don't try to set 32 or 64 */
+/* also testusb 14 fails wit 16 but is */
+/* fine with 8 */
+#define EP0_FIFO_SIZE 8
+#define EP_FIFO_SIZE 64
+#define DEFAULT_POWER_STATE 0x00
+
+#define S3C2440_EP_FIFO_SIZE 128
+
+static const char ep0name [] = "ep0";
+
+static const char *const ep_name[] = {
+ ep0name, /* everyone has ep0 */
+ /* s3c2410 four bidirectional bulk endpoints */
+ "ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk",
+};
+
+#define S3C2410_ENDPOINTS ARRAY_SIZE(ep_name)
+
+struct s3c2410_request {
+ struct list_head queue; /* ep's requests */
+ struct usb_request req;
+};
+
+enum ep0_state {
+ EP0_IDLE,
+ EP0_IN_DATA_PHASE,
+ EP0_OUT_DATA_PHASE,
+ EP0_END_XFER,
+ EP0_STALL,
+};
+
+static const char *ep0states[]= {
+ "EP0_IDLE",
+ "EP0_IN_DATA_PHASE",
+ "EP0_OUT_DATA_PHASE",
+ "EP0_END_XFER",
+ "EP0_STALL",
+};
+
+struct s3c2410_udc {
+ spinlock_t lock;
+
+ struct s3c2410_ep ep[S3C2410_ENDPOINTS];
+ int address;
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct s3c2410_request fifo_req;
+ u8 fifo_buf[EP_FIFO_SIZE];
+ u16 devstatus;
+
+ u32 port_status;
+ int ep0state;
+
+ unsigned got_irq : 1;
+
+ unsigned req_std : 1;
+ unsigned req_config : 1;
+ unsigned req_pending : 1;
+ u8 vbus;
+ struct dentry *regs_info;
+};
+
+#endif
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f847c3414be..9cd98e73dc1 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/mutex.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -258,7 +259,7 @@ static const char *EP_IN_NAME;
static const char *EP_OUT_NAME;
static const char *EP_NOTIFY_NAME;
-static struct semaphore gs_open_close_sem[GS_NUM_PORTS];
+static struct mutex gs_open_close_lock[GS_NUM_PORTS];
static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
@@ -595,7 +596,7 @@ static int __init gs_module_init(void)
tty_set_operations(gs_tty_driver, &gs_tty_ops);
for (i=0; i < GS_NUM_PORTS; i++)
- sema_init(&gs_open_close_sem[i], 1);
+ mutex_init(&gs_open_close_lock[i]);
retval = tty_register_driver(gs_tty_driver);
if (retval) {
@@ -635,7 +636,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
struct gs_port *port;
struct gs_dev *dev;
struct gs_buf *buf;
- struct semaphore *sem;
+ struct mutex *mtx;
int ret;
port_num = tty->index;
@@ -656,10 +657,10 @@ static int gs_open(struct tty_struct *tty, struct file *file)
return -ENODEV;
}
- sem = &gs_open_close_sem[port_num];
- if (down_interruptible(sem)) {
+ mtx = &gs_open_close_lock[port_num];
+ if (mutex_lock_interruptible(mtx)) {
printk(KERN_ERR
- "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+ "gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
port_num, tty, file);
return -ERESTARTSYS;
}
@@ -754,12 +755,12 @@ static int gs_open(struct tty_struct *tty, struct file *file)
exit_unlock_port:
spin_unlock_irqrestore(&port->port_lock, flags);
- up(sem);
+ mutex_unlock(mtx);
return ret;
exit_unlock_dev:
spin_unlock_irqrestore(&dev->dev_lock, flags);
- up(sem);
+ mutex_unlock(mtx);
return ret;
}
@@ -781,7 +782,7 @@ exit_unlock_dev:
static void gs_close(struct tty_struct *tty, struct file *file)
{
struct gs_port *port = tty->driver_data;
- struct semaphore *sem;
+ struct mutex *mtx;
if (port == NULL) {
printk(KERN_ERR "gs_close: NULL port pointer\n");
@@ -790,8 +791,8 @@ static void gs_close(struct tty_struct *tty, struct file *file)
gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
- sem = &gs_open_close_sem[port->port_num];
- down(sem);
+ mtx = &gs_open_close_lock[port->port_num];
+ mutex_lock(mtx);
spin_lock_irq(&port->port_lock);
@@ -846,7 +847,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
exit:
spin_unlock_irq(&port->port_lock);
- up(sem);
+ mutex_unlock(mtx);
}
/*
@@ -1427,7 +1428,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL);
+ gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
@@ -1435,7 +1436,6 @@ static int __init gs_bind(struct usb_gadget *gadget)
init_utsname()->sysname, init_utsname()->release,
gadget->name);
- memset(dev, 0, sizeof(struct gs_dev));
dev->dev_gadget = gadget;
spin_lock_init(&dev->dev_lock);
INIT_LIST_HEAD(&dev->dev_req_list);
@@ -2215,7 +2215,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
*
* Free the buffer and all associated memory.
*/
-void gs_buf_free(struct gs_buf *gb)
+static void gs_buf_free(struct gs_buf *gb)
{
if (gb) {
kfree(gb->buf_buf);
@@ -2228,7 +2228,7 @@ void gs_buf_free(struct gs_buf *gb)
*
* Clear out all data in the circular buffer.
*/
-void gs_buf_clear(struct gs_buf *gb)
+static void gs_buf_clear(struct gs_buf *gb)
{
if (gb != NULL)
gb->buf_get = gb->buf_put;
@@ -2241,7 +2241,7 @@ void gs_buf_clear(struct gs_buf *gb)
* Return the number of bytes of data available in the circular
* buffer.
*/
-unsigned int gs_buf_data_avail(struct gs_buf *gb)
+static unsigned int gs_buf_data_avail(struct gs_buf *gb)
{
if (gb != NULL)
return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
@@ -2255,7 +2255,7 @@ unsigned int gs_buf_data_avail(struct gs_buf *gb)
* Return the number of bytes of space available in the circular
* buffer.
*/
-unsigned int gs_buf_space_avail(struct gs_buf *gb)
+static unsigned int gs_buf_space_avail(struct gs_buf *gb)
{
if (gb != NULL)
return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
@@ -2271,7 +2271,8 @@ unsigned int gs_buf_space_avail(struct gs_buf *gb)
*
* Return the number of bytes copied.
*/
-unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
+static unsigned int
+gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
{
unsigned int len;
@@ -2309,7 +2310,8 @@ unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
*
* Return the number of bytes copied.
*/
-unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
+static unsigned int
+gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
{
unsigned int len;
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 7078374d0b7..a2e6e3fc8c8 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -481,8 +481,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
req = usb_ep_alloc_request (ep, GFP_ATOMIC);
if (req) {
req->length = length;
- req->buf = usb_ep_alloc_buffer (ep, length,
- &req->dma, GFP_ATOMIC);
+ req->buf = kmalloc(length, GFP_ATOMIC);
if (!req->buf) {
usb_ep_free_request (ep, req);
req = NULL;
@@ -493,8 +492,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
{
- if (req->buf)
- usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+ kfree(req->buf);
usb_ep_free_request (ep, req);
}
@@ -1199,8 +1197,7 @@ autoconf_fail:
dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
if (!dev->req)
goto enomem;
- dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
- &dev->req->dma, GFP_KERNEL);
+ dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
if (!dev->req->buf)
goto enomem;