diff mbox

[U-Boot,1/3] Add Atmel USBA UDC

Message ID 1297527588-21530-1-git-send-email-korgull@home.nl
State Rejected
Delegated to: Reinhard Meyer
Headers show

Commit Message

Marcel Janssen Feb. 12, 2011, 4:19 p.m. UTC
From: Marcel <korgull@home.nl>

Signed-off-by: Marcel <korgull@home.nl>

Added Atmel USBA UDC to Makefile

Signed-off-by: Marcel <korgull@home.nl>
---
 drivers/usb/gadget/Makefile         |    1 +
 drivers/usb/gadget/atmel_usba_udc.c | 1586 +++++++++++++++++++++++++++++++++++
 include/usb/atmel_usba_udc.h        |  469 +++++++++++
 3 files changed, 2056 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/gadget/atmel_usba_udc.c
 create mode 100644 include/usb/atmel_usba_udc.h

Comments

Wolfgang Denk Feb. 12, 2011, 7:09 p.m. UTC | #1
Dear Marcel Janssen,

In message <1297527588-21530-1-git-send-email-korgull@home.nl> you wrote:
> From: Marcel <korgull@home.nl>
> 
> Signed-off-by: Marcel <korgull@home.nl>
> 
> Added Atmel USBA UDC to Makefile
> 
> Signed-off-by: Marcel <korgull@home.nl>
> ---
>  drivers/usb/gadget/Makefile         |    1 +
>  drivers/usb/gadget/atmel_usba_udc.c | 1586 +++++++++++++++++++++++++++++++++++
>  include/usb/atmel_usba_udc.h        |  469 +++++++++++
>  3 files changed, 2056 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/usb/gadget/atmel_usba_udc.c
>  create mode 100644 include/usb/atmel_usba_udc.h

Will you please stop posting random patch series without any
additional information???

Remo wrote already yesterday:
| 
| How does this patch relate to the patch you posted yesterday?
| That one modified a Makefile as well, while this one does not?!
| If you make a new version of a patch, please add the proper version
| info and changelog to the newer patch as described here:
| http://www.denx.de/wiki/view/U-Boot/Patches#Sending_updated_patch_versions

But you ignore all advice and post one patch seires after the other,
without markign these by some version number, without adding any
change log so we can see what might have been changed.

You are supposed to follow the rules.

And before reposting, please make sure to run your patchjes through
checkpatch and fix all the errors:

[U-Boot] [PATCH 1/4] Add Atmel USBA UDC
total: 323 errors, 117 warnings, 2055 lines checked
[U-Boot] [PATCH 2/4] Add Atmel USBA UDC
        OK, 7 lines checked
[U-Boot] [PATCH 3/4] add USB DFU driver
total: 247 errors, 91 warnings, 1713 lines checked
[U-Boot] [PATCH 4/4] add icnova sam9g45 board
total: 105 errors, 37 warnings, 1077 lines checked
[U-Boot] [PATCH 1/3] Add Atmel USBA UDC
total: 323 errors, 117 warnings, 2062 lines checked
[U-Boot] [PATCH 2/3] add USB DFU driver
total: 247 errors, 91 warnings, 1713 lines checked
[U-Boot] [PATCH 3/3] add icnova sam9g45 board
total: 105 errors, 37 warnings, 1087 lines checked

Please consider ALL you patches rejected.

Best regards,

Wolfgang Denk
diff mbox

Patch

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 0846233..024844d 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -29,6 +29,7 @@  LIB	:= $(obj)libusb_gadget.o
 ifdef CONFIG_USB_ETHER
 COBJS-y += ether.o epautoconf.o config.o usbstring.o
 COBJS-$(CONFIG_USB_GADGET_AT91) += at91_udc.o
+COBJS-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o
 else
 # Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE
 ifdef CONFIG_USB_DEVICE
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644
index 0000000..ff9c469
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -0,0 +1,1586 @@ 
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ * Copyright (C) 2011 Marcel Janssen
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/atmel_usba_udc.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <mach/board.h>
+*/
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/errno.h>
+#include <linux/list.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/mtd/compat.h>
+#include <linux/porting-compat.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/io.h>
+
+#include <usb/atmel_usba_udc.h>
+
+#define __iomem
+
+#define memcpy_toio(a,b,c)        memcpy((a),(b),(c))
+#define memcpy_fromio(a,b,c)      memcpy((a),(b),(c))
+#define REQ_COUNT 8
+#define MAX_REQ (REQ_COUNT-1)
+
+static struct usba_udc the_udc;
+
+#define true 1
+#define false 0
+
+static const char driver_name[] = "atmel_usba_udc";
+static const char ep0name[] = "ep0";
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+	unsigned int transaction_len;
+
+	transaction_len = req->req.length - req->req.actual;
+	req->last_transaction = 1;
+	if (transaction_len > ep->ep.maxpacket) {
+		transaction_len = ep->ep.maxpacket;
+		req->last_transaction = 0;
+	} else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+		req->last_transaction = 0;
+
+	debug("%s: submit_transaction, req %p (length %d)%s\n",
+		ep->ep.name, req, transaction_len,
+		req->last_transaction ? ", done" : "");
+	
+	memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+	//__raw_writesb(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	req->req.actual += transaction_len;	
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+
+	req->req.actual = 0;
+	req->submitted = 1;
+
+	debug("%s : submit_request: req %p (length %d)\n",
+				ep->ep.name, req, req->req.length);
+	next_fifo_transaction(ep, req);
+	if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+	} else {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		}
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+	struct usba_request *req;
+	
+
+	if (list_empty(&ep->queue)) {
+		usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+		return;
+	}
+	req = list_entry(ep->queue.next, struct usba_request, queue);
+	if (!req->submitted)
+		submit_request(ep, req);
+	debug("%s : submit_next_request: req %p (length %d)\n",
+				ep->ep.name, req, req->req.length);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+	debug("Send USBA status\n");
+        ep->state = STATUS_STAGE_IN;
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+	struct usba_udc *udc = ep->udc;
+	struct usba_request *req;
+	unsigned long status;
+	unsigned int bytecount, nr_busy;
+	int is_complete = 0;
+	 
+	status = usba_ep_readl(ep, STA);
+	nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+	debug("receive data: nr_busy=%u\n", nr_busy);
+	
+	while (nr_busy > 0) {
+		if (list_empty(&ep->queue)) {
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			break;
+		}
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+		bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+		if (status & (1 << 31))
+			is_complete = 1;
+		if (req->req.actual + bytecount >= req->req.length) {
+			is_complete = 1;
+			bytecount = req->req.length - req->req.actual;
+		}
+
+		memcpy_fromio(req->req.buf + req->req.actual,
+				ep->fifo, bytecount);
+		req->req.actual += bytecount;
+
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+		
+		if (is_complete) {
+			debug("%s: request done\n", ep->ep.name);
+			req->req.status = 0;
+			list_del_init(&req->queue);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			req->req.complete(&ep->ep, &req->req);
+			debug("request->complete done\n");
+		}
+
+		status = usba_ep_readl(ep, STA);
+		nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+		debug("nr_busy = %d\n", nr_busy);
+		if (is_complete && ep_is_control(ep)) {
+			send_status(udc, ep);
+			break;
+		}
+		debug("rcv : bytecount=%d actual=%d\n", req->req.actual);
+	}
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+	
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+
+	debug("%s: req %p complete: status %d, actual %u\n",
+		ep->ep.name, req, req->req.status, req->req.actual);
+	
+	req->req.complete(&ep->ep, &req->req);
+	debug("request complete finished\n");
+}
+
+/*
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+	struct usba_request *req, *tmp_req;
+        debug("Request complete list\n");
+	list_for_each_entry_safe(req, tmp_req, list, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, status);
+	}
+}
+*/
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct usba_ep *ep;//to_usba_ep(_ep);
+	struct usba_udc *udc;
+	unsigned long ept_cfg, maxpacket; //regvalue;
+	unsigned int nr_trans;
+	//int i;
+	
+	ep = container_of(_ep, struct  usba_ep, ep);
+	udc = ep->udc;
+	
+        debug("Endpoint enable ep %d\n",ep->index);
+	maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+	
+	if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+			|| ep->index == 0
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| maxpacket == 0
+			|| maxpacket > ep->fifo_size) {
+		debug("ep_enable: Invalid argument");
+		return -EINVAL;
+	}
+
+	ep->is_isoc = 0;
+	ep->is_in = 0;
+
+/*	if( (ep->index == 1) || (ep->index == 2) || (ep->index == 3) )
+  
+{
+	  i = ep->index;
+	  // DMA stop channel command
+	  __raw_writel(0x00, AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMACONTROL);
+	  // Disable endpoint
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + 0x100 + (0x20*i) + UDPHS_EPTCTLDIS);
+	  __raw_writel( (regvalue | 0XFFFFFFFF), AT91SAM9G45_BASE_UDPHS + 0x100 + (0x20*i) + UDPHS_EPTCTLDIS);
+	  // Reset endpoint config
+	  __raw_writel(0x00, AT91SAM9G45_BASE_UDPHS + 0x100 + (0x20*i) + UDPHS_EPTCFG);
+	  // Reset DMA channel (Buff count and Control field)
+	  __raw_writel(0x02, AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMACONTROL);
+	  // DMA stop channel command
+	  __raw_writel(0x00, AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMACONTROL);
+	  // Clear DMA channel status (read the register for clear it)
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMASTATUS);
+	  __raw_writel(regvalue, AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMASTATUS);
+}
+*/	
+	if (maxpacket <= 8)
+		ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+	else
+		/* LSB is bit 1, not 0 */
+		ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+	
+	debug("%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+			ep->ep.name, ept_cfg, maxpacket);
+	
+	if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+		ep->is_in = 1;
+		ept_cfg |= USBA_EPT_DIR_IN;
+		debug("%s: is IN endpoint\n",ep->ep.name);
+	}
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+		debug("%s: is CTRL endpoint\n",ep->ep.name);
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		debug("%s: is ISOC endpoint\n",ep->ep.name);
+		if (!ep->can_isoc) {
+			return -EINVAL;
+		}
+
+		/*
+		 * Bits 11:12 specify number of _additional_
+		 * transactions per microframe.
+		 */
+		nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+		if (nr_trans > 3)
+			return -EINVAL;
+
+		ep->is_isoc = 1;
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+		/*
+		 * Do triple-buffering on high-bandwidth iso endpoints.
+		 */
+		if (nr_trans > 1 && ep->nr_banks == 3)
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+		else
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);//USBA_BK_NUMBER_ONE USBA_BK_NUMBER_DOUBLE);
+		ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+	        debug("%s: is BULK endpoint\n",ep->ep.name);
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);//USBA_BK_NUMBER_DOUBLE);
+		break;
+	case USB_ENDPOINT_XFER_INT:
+	        debug("%s: is INT endpoint\n",ep->ep.name);
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);//USBA_BK_NUMBER_DOUBLE);
+		break;
+	}
+
+
+	if (ep->desc) {
+	        debug("ep%d already enabled\n", ep->index);
+		return -EBUSY;
+	}
+
+	ep->desc = desc;
+	ep->ep.maxpacket = maxpacket;
+
+	usba_ep_writel(ep, CFG, ept_cfg);
+	debug("ep%d CFG = 0x%lx\n", ep->index, ept_cfg);
+	usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+        debug("ep%d not using DMA\n", ep->index);
+	usba_writel(udc, INT_ENB, (usba_readl(udc, INT_ENB)
+					| USBA_BF(EPT_INT, 1 << ep->index)));
+
+
+	debug("EPT_CFG%d after init: %#08lx\n", ep->index,
+			(unsigned long)usba_ep_readl(ep, CFG));
+	debug("INT_ENB after init: %#08lx\n",
+			(unsigned long)usba_readl(udc, INT_ENB));
+	debug("INT_STA after init: %#08lx\n",
+			(unsigned long)usba_readl(udc, INT_STA));
+	debug("EPT_CTL_ENB%d after init: %#08lx\n", ep->index,
+			(unsigned long)usba_ep_readl(ep, CTL_ENB));
+	debug("EPT_CTL_DIS%d after init: %#08lx\n", ep->index,
+			(unsigned long)usba_ep_readl(ep, CTL_DIS));
+	debug("EPT_CTL%d after init: %#08lx\n", ep->index,
+			(unsigned long)usba_ep_readl(ep, CTL));
+	debug("EPT_STA%d after init: %#08lx\n", ep->index,
+			(unsigned long)usba_ep_readl(ep, STA));
+	return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+	struct usba_ep *ep;//to_usba_ep(_ep);
+	struct usba_udc *udc;
+	//LIST_HEAD(req_list);
+	
+	ep = container_of(_ep, struct usba_ep, ep);
+	udc = ep->udc;
+	
+        
+	if (ep == &ep->udc->ep[0])
+		return -EINVAL;
+	
+	debug("Endpoint disable ep %d\n",ep->index);
+	//if (!ep->desc) {
+	//	/* REVISIT because this driver disables endpoints in
+	//	 * reset_all_endpoints() before calling disconnect(),
+	//	 * most gadget drivers would trigger this non-error ...
+	//	 */
+	//	debug("ep%d unknown speed\n",ep->index);
+	//	if (udc->gadget.speed != USB_SPEED_UNKNOWN)
+	//	return -EINVAL;
+	//}
+	ep->desc = NULL;
+
+	//list_splice_init(&ep->queue, &req_list);
+
+	usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+	usba_writel(udc, INT_ENB,
+			usba_readl(udc, INT_ENB)
+			& ~USBA_BF(EPT_INT, 1 << ep->index));
+
+	//request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+	return 0;
+}
+
+#define REQ_COUNT 8
+#define MAX_REQ (REQ_COUNT-1)
+static struct usba_request req_pool[REQ_COUNT];
+
+static void init_requests(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_REQ; i++) {
+		req_pool[i].in_use=0;
+	}
+}
+
+static void free_request(struct usba_request* ptr)
+{
+	if (ptr < &req_pool[0] && ptr > &req_pool[REQ_COUNT]){
+		debug("%s: ptr 0x%p does not specify valid req\n", \
+			__func__, ptr);
+		if (!(ptr->in_use))
+			debug("%s: ptr not marked as \"in_use\"\n", __func__);
+
+		hang();
+	}
+	ptr->in_use=0;
+}
+
+static struct usba_request* alloc_request(void)
+{
+	int i;
+	struct usba_request* ptr=NULL;
+
+	for (i = 0; i < MAX_REQ; i++) {
+		if (!req_pool[i].in_use) {
+			ptr=&req_pool[i];
+			req_pool[i].in_use=1;
+			DBG("alloc_req: request[%d]\n",i);
+			break;
+		}
+	}
+	if (!ptr)
+		DBG("panic: no more free req buffers\n");
+	return ptr;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct usba_request *req;
+
+	req = alloc_request();
+
+	if (!req)
+	{
+	        debug("ALLOC REQUEST FAILLED : %s\n",_ep->name);
+		return NULL;
+	}
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+static void usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_request *req;
+
+	debug("FREE request for %s\n",_ep->name);
+	req = container_of(_req, struct usba_request, req);
+
+	free_request(req);
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, 
+	      struct usb_request *_req, 
+	      gfp_t gfp_flags)
+{
+	struct usba_request *req = to_usba_req(_req);
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	int ret;
+        
+	debug("%s: queue req %p, len %u\n",
+			ep->ep.name, req, _req->length);
+	      
+	if (!_req || !_req->complete
+			|| !_req->buf || !list_empty(&req->queue)) {
+	  
+		debug("invalid request\n");
+		if(!_req) debug("NO REQUEST\n");
+		if(!_req->complete) debug("NO REQUEST COMPLETE\n");
+		if(!_req->buf) debug("NO REQUEST BUF : did you initialize the gadget well ?\n");
+		if(!list_empty(&req->queue)) debug("NO LIST EMPTY\n");
+		return -EINVAL;
+	}
+
+	if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {
+		DBG("invalid ep\n");
+		return -EINVAL;
+	}
+	
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+			return -ESHUTDOWN;
+	
+	req->submitted = 0;
+	req->last_transaction = 0;
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* May have received a reset since last time we checked */
+	ret = -ESHUTDOWN;
+
+	if (ep->desc) {
+		list_add_tail(&req->queue, &ep->queue);
+
+		if ((!ep_is_control(ep) && ep->is_in) ||
+			(ep_is_control(ep)
+				&& (ep->state == DATA_STAGE_IN
+					|| ep->state == STATUS_STAGE_IN)))
+			{
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		        debug("WE TRANSMITTED DATA ep= %s\n", ep->ep.name);
+			}
+		else
+			{  
+		        debug("WE RECEIVED OUT DATA ep= %s\n", ep->ep.name);
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+			//usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_ep *ep = container_of(_ep, struct usba_ep, ep);//to_usba_ep(_ep);
+	struct usba_request *req = container_of(_req, struct usba_request, req);//to_usba_req(_req);
+
+	debug("ep_dequeue: %s, req %p\n",
+			ep->ep.name, req);
+	
+	if (!_ep || ep->ep.name == ep0name) {
+		DBG("invalid dequeue request\n");
+		if(!_ep) debug("NO ENDPOINT\n");
+		if(ep->ep.name == ep0name) debug("Cannot dequeue on ep0\n");
+		return -EINVAL;
+	}
+	/*
+	 * Errors should stop the queue from advancing until the
+	 * completion function returns.
+	 */
+	//list_del_init(&req->queue);
+	
+        /* make sure it's actually queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+	request_complete(ep, req, -ECONNRESET);
+
+	/* Process the next request if any */
+	submit_next_request(ep);
+
+	return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct usba_ep *ep = container_of(_ep, struct usba_ep, ep);//to_usba_ep(_ep);
+	int ret = 0;
+        
+	debug("Endpoint halt\n");
+	
+	if (!ep->desc) {
+		debug("Attempted to halt uninitialized ep %s\n",
+				ep->ep.name);
+		return -ENODEV;
+	}
+	if (ep->is_isoc) {
+		debug("Attempted to halt isochronous ep %s\n",
+				ep->ep.name);
+		return -ENOTTY;
+	}
+
+	/*
+	 * We can't halt IN endpoints while there are still data to be
+	 * transferred
+	 */
+	if (!list_empty(&ep->queue)
+			|| ((value && ep->is_in && (usba_ep_readl(ep, STA)
+					& USBA_BF(BUSY_BANKS, -1L))))) {
+		ret = -EAGAIN;
+	} else {
+		if (value)
+			usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+		else
+			usba_ep_writel(ep, CLR_STA,
+					USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+		usba_ep_readl(ep, STA);
+	}
+
+	return ret;
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+	.enable		= usba_ep_enable,
+	.disable	= usba_ep_disable,
+	.alloc_request	= usba_ep_alloc_request,
+	.free_request	= usba_ep_free_request,
+	.queue		= usba_ep_queue,
+	.dequeue	= usba_ep_dequeue,
+	.set_halt	= usba_ep_set_halt,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+
+	return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	u32 ctrl;
+	int ret = -EINVAL;
+	debug("UDC wakeup\n");
+
+	if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+		ctrl = usba_readl(udc, CTRL);
+		usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+        
+	debug("UDC set selfpowered\n");
+	
+	if (is_selfpowered)
+		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+	else
+		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+	.get_frame		= usba_udc_get_frame,
+	.wakeup			= usba_udc_wakeup,
+	.set_selfpowered	= usba_udc_set_selfpowered,
+};
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = __constant_cpu_to_le16(64),
+	/* FIXME: I have no idea what to put here */
+	.bInterval = 1,
+};
+
+static struct usba_udc the_udc = {
+	.regs = (unsigned *) AT91SAM9G45_BASE_UDPHS, 
+	.fifo = (unsigned *) AT91SAM9G45_UDPHS_FIFO,
+	.gadget = {
+		.ops	= &usba_udc_ops,
+		.ep0	= &the_udc.ep[0].ep,
+		//.ep_list	= LIST_HEAD_INIT(the_udc.gadget.ep_list),
+		.is_dualspeed = 1,
+		.name	= driver_name,
+	},
+	
+	.ep[0] = {
+		.ep = {
+			.name	= ep0name,
+			.ops	= &usba_ep_ops,
+			.maxpacket	= 64,
+		},
+		.udc		= &the_udc,
+		.is_pingpong	= 0,
+		.int_mask	= 1 << 0,
+		.fifo_size	= 64,
+		.nr_banks	= 1,
+		.can_dma        = 0,
+		.can_isoc       = 0,
+	},
+	.ep[1] = {
+		.ep = {
+			.name	= "ep1",
+			.ops	= &usba_ep_ops,
+			.maxpacket	= 1024,
+		},
+		.udc		= &the_udc,
+		.is_pingpong	= 0,
+		.int_mask	= 1 << 1,
+		.fifo_size	= 1024,
+		.nr_banks	= 1,
+		.can_dma        = 0,
+		.can_isoc       = 0,
+	},
+	.ep[2] = {
+		.ep = {
+			.name	= "ep2",
+			.ops	= &usba_ep_ops,
+			.maxpacket	= 1024,
+		},
+		.udc		= &the_udc,
+		.is_pingpong	= 0,
+		.int_mask	= 1 << 2,
+		.fifo_size	= 1024,
+		.nr_banks	= 1,
+		.can_dma        = 0,
+		.can_isoc       = 0,
+	},
+	.ep[3] = {
+		.ep = {
+			.name	= "ep3",
+			.ops	= &usba_ep_ops,
+			.maxpacket	= 1024,
+		},
+		.udc		= &the_udc,
+		.is_pingpong	= 0,
+		.int_mask	= 1 << 3,
+		.fifo_size	= 1024,
+		.nr_banks	= 1,
+		.can_dma        = 0,
+		.can_isoc       = 0,		
+	},
+	.ep[4] = {
+		.ep = {
+			.name	= "ep4",
+			.ops	= &usba_ep_ops,
+			.maxpacket	= 1024,
+		},
+		.udc		= &the_udc,
+		.is_pingpong	= 0,
+		.int_mask	= 1 << 4,
+		.fifo_size	= 1024,
+		.nr_banks	= 1,
+		.can_dma        = 0,
+		.can_isoc       = 0,
+	},
+	.ep[5] = {
+		.ep = {
+			.name	= "ep5",
+			.ops	= &usba_ep_ops,
+			.maxpacket	= 1024,
+		},
+		.udc		= &the_udc,
+		.is_pingpong	= 0,
+		.int_mask	= 1 << 5,
+		.fifo_size	= 1024,
+		.nr_banks	= 1,
+		.can_dma        = 0,
+		.can_isoc       = 0,
+	},
+	.ep[6] = {
+		.ep = {
+			.name	= "ep6",
+			.ops	= &usba_ep_ops,
+			.maxpacket	= 1024,
+		},
+		.udc		= &the_udc,
+		.is_pingpong	= 0,
+		.int_mask	= 1 << 6,
+		.fifo_size	= 1024,
+		.nr_banks	= 1,
+		.can_dma        = 0,
+		.can_isoc       = 0,
+	},
+	
+};
+
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+
+	struct usba_ep *ep;
+	struct usba_request *req, *tmp_req;
+        debug("USBA : reset all endpoints\n");
+	usba_writel(udc, EPT_RST, ~0UL);
+
+	ep = container_of(udc->gadget.ep0, struct usba_ep, ep);//to_usba_ep(udc->gadget.ep0);
+	list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, -ECONNRESET);
+	}
+
+	 //NOTE:  normally, the next call to the gadget driver is in
+	 // charge of disabling endpoints... usually disconnect().
+	 // The exception would be entering a high speed test mode.
+	 //
+	 // FIXME remove this code ... and retest thoroughly.
+	 //
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+		if (ep->desc) {
+			usba_ep_disable(&ep->ep);
+		}
+	}
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+	struct usba_ep *ep;
+        debug("get EP by Address\n");
+	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+		return container_of(udc->gadget.ep0, struct usba_ep, ep);//to_usba_ep(udc->gadget.ep0);
+
+	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+		u8 bEndpointAddress;
+
+		if (!ep->desc)
+			continue;
+		bEndpointAddress = ep->desc->bEndpointAddress;
+		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+			continue;
+		if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+				== (wIndex & USB_ENDPOINT_NUMBER_MASK))
+			return ep;
+	}
+
+	return NULL;
+}
+
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+        debug("Set protocol stall\n");
+	usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+	ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+	 debug("IS STALLED\n");
+	if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+		return 1;
+	return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+	u32 regval;
+	debug("USBA : set address %d\n", addr);
+	regval = usba_readl(udc, CTRL);
+	regval = USBA_BFINS(DEV_ADDR, addr, regval);
+	usba_writel(udc, CTRL, regval);
+}
+
+/* Avoid overly long expressions */
+static inline char feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+		return true;
+	return false;
+}
+
+static inline char feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+		return true;
+	return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+		struct usb_ctrlrequest *crq)
+{
+	int retval = 0;
+
+	debug("USBA : EP0 setup\n");
+	switch (crq->bRequest) {
+	case USB_REQ_GET_STATUS: {
+		u16 status;
+		debug("USBA : USB_REQ_GET_STATUS\n");
+		if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+			status = cpu_to_le16(udc->devstatus);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+			status =  cpu_to_le16(0);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+			struct usba_ep *target;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			status = 0;
+			if (is_stalled(udc, target))
+				status |= cpu_to_le16(1);
+		} else{
+			debug("Delegate : USB_REQ_GET_STATUS\n");
+			goto delegate;
+		}
+		/* Write directly to the FIFO. No queueing is done. */
+		if (crq->wLength != cpu_to_le16(sizeof(status)))
+			goto stall;
+		ep->state = DATA_STAGE_IN;
+		debug("Writing to FIFO\n");
+		__raw_writew(status, ep->fifo);
+		usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+		break;
+	}
+
+	case USB_REQ_CLEAR_FEATURE: {
+		debug("USBA : USB_REQ_CLEAR_FEATURE\n");
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_remote_wakeup(crq))
+				udc->devstatus
+					&= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+			else
+				/* Can't CLEAR_FEATURE TEST_MODE */
+				goto stall;
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != cpu_to_le16(0)
+					|| !feature_is_ep_halt(crq))
+				goto stall;
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+			if (target->index != 0)
+				usba_ep_writel(target, CLR_STA,
+						USBA_TOGGLE_CLR);
+		} else {
+			goto delegate;
+		}
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_FEATURE: {
+	        debug("USBA :  USB_REQ_SET_FEATURE\n");
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_remote_wakeup(crq)) {
+				udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+			} else {
+				goto stall;
+			}	
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength !=cpu_to_le16(0)
+					|| !feature_is_ep_halt(crq))
+				goto stall;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+		} else
+			goto delegate;
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_ADDRESS:
+	        debug("USBA :  USB_REQ_SET_ADDRESS\n");
+		if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+			goto delegate;
+
+		set_address(udc, le16_to_cpu(crq->wValue));
+		send_status(udc, ep);
+		ep->state = STATUS_STAGE_ADDR;
+		break;
+
+	default:
+delegate:
+
+                debug("deligate SETUP Type = %4x %4x %4x\n",		
+			crq->bRequest,
+			crq->wValue,
+		        crq->wIndex);
+
+		retval = udc->driver->setup(&udc->gadget, crq);
+	}
+
+
+	return retval;
+
+stall:
+        debug("udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+		"halting endpoint...\n",
+		ep->ep.name, crq->bRequestType, crq->bRequest,
+		le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+		le16_to_cpu(crq->wLength));
+	set_protocol_stall(udc, ep);
+	return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+restart:
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	debug("%s [%d]: s/%08x c/%08x\n",
+			ep->ep.name, ep->state, epstatus, epctrl);
+	
+	req = NULL;
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+	if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		debug("usba_control_irq : USBA_TX_PK_RDY\n");
+		if (req->submitted)
+			next_fifo_transaction(ep, req);
+		else
+			submit_request(ep, req);
+
+		if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+		}
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+		debug("usba_control_irq : USBA_TX_COMPLETE\n");
+		usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+		switch (ep->state) {
+		case DATA_STAGE_IN:
+		        debug("USBA : DATA Stage in\n");
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = STATUS_STAGE_OUT;
+			break;
+		case STATUS_STAGE_ADDR:
+		        debug("USBA : Status stage addr\n");
+			/* Activate our new address */
+			usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+						| USBA_FADDR_EN));
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_IN:
+		        debug("USBA : Status stage in\n");
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+				submit_next_request(ep);
+			}
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_TEST:
+			debug("USBA : test mode not supported\n");
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		default:
+			debug("udc: %s: TXRDY: Invalid endpoint state %d, "
+				"halting endpoint...\n",
+				ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+	        debug("USBA : USBA_RX_BK_RDY\n");
+		switch (ep->state) {
+		case STATUS_STAGE_OUT:
+			debug("%s : USBA :STATUS_STAGE_OUT\n",ep->ep.name);
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+			if (req) {
+				list_del_init(&req->queue);
+				debug("%s : USBA :call request complete\n",ep->ep.name);
+				request_complete(ep, req, 0);
+			}
+			ep->state = WAIT_FOR_SETUP;
+			break;
+
+		case DATA_STAGE_OUT: 
+		        debug("%s : DATA STAGE OUT\n",ep->ep.name);
+			receive_data(ep);
+			break;
+
+		default:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			debug("udc: %s: RXRDY: Invalid endpoint state %d, "
+				"halting endpoint...\n",
+				ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if (epstatus & USBA_RX_SETUP) {
+	  debug("USBA : USBA_RX_SETUP\n");
+		union {
+			struct usb_ctrlrequest crq;
+			unsigned long data[2];
+		} crq;
+		unsigned int pkt_len;
+		int ret;
+
+		if (ep->state != WAIT_FOR_SETUP) {
+			/*
+			 * Didn't expect a SETUP packet at this
+			 * point. Clean up any pending requests (which
+			 * may be successful).
+			 */
+			int status = -EPROTO;
+
+			/*
+			 * RXRDY and TXCOMP are dropped when SETUP
+			 * packets arrive.  Just pretend we received
+			 * the status packet.
+			 */
+			if (ep->state == STATUS_STAGE_OUT
+					|| ep->state == STATUS_STAGE_IN) {
+			        debug("DROPPING DATA %s\n", ep->ep.name);
+				usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+				status = 0;
+			}
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, status);
+			}
+		}
+
+		pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+		debug("Packet length: %u\n", pkt_len);
+		if (pkt_len != sizeof(crq)) {
+			debug("udc: Invalid packet length %u "
+				"(expected %zu)\n", pkt_len, sizeof(crq));
+			set_protocol_stall(udc, ep);
+			return;
+		}
+		
+		debug("Copying ctrl request from 0x%p:\n", ep->fifo);
+		memcpy_fromio(crq.data, ep->fifo, sizeof(crq));
+
+		/* Free up one bank in the FIFO so that we can
+		 * generate or receive a reply right away. */
+		usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+		/* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+			ep->state, crq.crq.bRequestType,
+			crq.crq.bRequest); */
+
+		if (crq.crq.bRequestType & USB_DIR_IN) {
+			/*
+			 * The USB 2.0 spec states that "if wLength is
+			 * zero, there is no data transfer phase."
+			 * However, testusb #14 seems to actually
+			 * expect a data phase even if wLength = 0...
+			 */
+			ep->state = DATA_STAGE_IN;
+		} else {
+			if (crq.crq.wLength != cpu_to_le16(0))
+				ep->state = DATA_STAGE_OUT;
+			else
+				ep->state = STATUS_STAGE_IN;
+		}
+
+		ret = -1;
+		if (ep->index == 0)
+			ret = handle_ep0_setup(udc, ep, &crq.crq);
+		else {
+		        debug("driver setup %d %d\n",crq.crq.wIndex,crq.crq.wValue); 
+			ret = udc->driver->setup(&udc->gadget, &crq.crq);
+		  
+		}
+
+		if (ret < 0) {
+			/* Let the host know that we failed */
+			set_protocol_stall(udc, ep);
+		}
+	}
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+        
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	//debug("%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+	
+	while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		debug("%s: TX PK ready\n", ep->ep.name);
+	  
+		if (list_empty(&ep->queue)) {
+			debug("ep_irq: queue empty\n");
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			return;
+		}
+
+		req = list_entry(ep->queue.next, struct usba_request, queue);
+
+		if (req->submitted)
+		{
+		    debug("TX next trans %s\n", ep->ep.name);
+		    next_fifo_transaction(ep, req);
+		}
+		else
+		{
+		    debug("TX submit %s\n", ep->ep.name);
+		    submit_request(ep, req);
+		}
+		if (req->last_transaction) {
+		        debug("last transaction %s\n", ep->ep.name);
+			list_del_init(&req->queue);
+			submit_next_request(ep);
+			request_complete(ep, req, 0);
+		}
+
+		epstatus = usba_ep_readl(ep, STA);
+		epctrl = usba_ep_readl(ep, CTL);
+	}
+	debug("%s status = %lx\n", ep->ep.name, epstatus);
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+	        debug("%s RX data ready\n", ep->ep.name);
+		receive_data(ep);
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+	}
+}
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct usba_udc *udc = &the_udc;
+	u32 status;
+	u32 ep_status;
+  
+	status = usba_readl(udc, INT_STA);
+	debug("irq, status=%#08x\n", status);
+	
+	if (status & USBA_DET_SUSPEND) {
+	        debug("USBA : USBA_DET_SUSPEND\n");
+		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver && udc->driver->suspend) {
+			udc->driver->suspend(&udc->gadget);
+		}
+	}
+        	
+        if (status & USBA_WAKE_UP) {
+	        debug("USBA : USBA_WAKE_UP\n");
+		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+	}
+
+	if (status & USBA_END_OF_RESUME) {
+	        debug("USBA : USBA_END_OF_RESUME\n");
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver && udc->driver->resume) {
+			udc->driver->resume(&udc->gadget);
+		}
+	}
+	
+	ep_status = USBA_BFEXT(EPT_INT, status);
+	if (ep_status) {
+		int i;
+
+		for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+			if (ep_status & (1 << i)) {
+				if (ep_is_control(&udc->ep[i]))
+				{
+					debug("EP %d = control\n",i);
+					usba_control_irq(udc, &udc->ep[i]);
+				}
+				else
+				{
+					debug("EP = %d\n",i);
+					usba_ep_irq(udc, &udc->ep[i]);
+				}
+			}
+	}
+
+	if (status & USBA_END_OF_RESET) {
+		struct usba_ep *ep0;
+                debug("USBA : USBA_END_OF_RESET\n");
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+		reset_all_endpoints(udc);
+
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver->disconnect) {
+			udc->gadget.speed = USB_SPEED_UNKNOWN;
+			udc->driver->disconnect(&udc->gadget);
+		}
+		
+
+		if (status & USBA_HIGH_SPEED) {
+		        debug("USBA : High speed\n");
+			udc->gadget.speed = USB_SPEED_HIGH;
+		} else {
+		        debug("USBA : Full speed\n");
+			udc->gadget.speed = USB_SPEED_FULL;
+		}
+                
+		ep0 = &udc->ep[0];
+		ep0->desc = &usba_ep0_desc;
+		ep0->state = WAIT_FOR_SETUP;
+		usba_ep_writel(ep0, CFG,
+				(USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+		usba_ep_writel(ep0, CTL_ENB,
+				USBA_EPT_ENABLE | USBA_RX_SETUP);
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+				| USBA_BF(EPT_INT, 1)
+				| USBA_DET_SUSPEND
+				| USBA_END_OF_RESUME));
+
+		/*
+		 * Unclear why we hit this irregularly, e.g. in usbtest,
+		 * but it's clearly harmless...
+		*/ 
+		if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+		{
+			ERR("ODD: EP0 configuration is invalid!\n");
+			debug("ERROR : ep0 config invalid\n");
+		  
+		}
+		debug("USBA : USBA_END_OF_RESET - finished\n");
+		
+	}
+        
+	return IRQ_HANDLED;
+}
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+        struct usba_udc *udc = &the_udc;
+
+	if (!driver)
+		return -ENODEV;
+	if (driver != udc->driver || !driver->unbind)
+		return -EINVAL;
+
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	reset_all_endpoints(udc);
+
+	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+
+	if (udc->driver->disconnect)
+		udc->driver->disconnect(&udc->gadget);
+
+	driver->unbind(&udc->gadget);
+	udc->driver = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &the_udc;
+	int		retval = -1;
+
+        debug("USBA : registering driver\n");
+
+	/*if (!driver
+			|| driver->speed < USB_SPEED_FULL
+			|| !driver->bind
+			|| !driver->setup) {
+		DBG("bad parameter.\n");
+		return -EINVAL;
+	}*/
+
+	if (udc->driver) {
+		debug("UDC already has a gadget driver\n");
+		return -EBUSY;
+	}
+		
+	udc->driver = driver;
+
+	if (udc->driver)
+	{
+	   retval = driver->bind(&udc->gadget);
+	}
+
+	if (retval) {
+		debug("driver->bind() returned %d\n", retval);
+		udc->driver = NULL;
+		return retval;
+	}
+        
+        debug("Enabling controller\n");
+        usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+	usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+	// todo: anyway allow registering the driver, maybe a later
+	// 	bringup may succeed. postpone pullup the eth_init?
+	//
+
+	//check vbus
+	//value = at91_get_gpio_value(udc->board.vbus_pin);
+        debug("USBA register finished\n");
+	return 0;
+}
+
+/* reinit == restore inital software state */
+static void udc_reinit(struct usba_udc *udc)
+{
+	u32 i;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+	for (i = 0; i < USBA_NR_ENDPOINTS; i++) {
+		struct usba_ep *ep = &udc->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+		ep->desc = NULL;
+		ep->stopped = 0;
+		ep->fifo_bank = 0;
+		ep->ep.maxpacket = ep->maxpacket;
+		ep->ep_regs = (void __iomem *) udc->regs + USBA_EPT_BASE(i);
+		// initialiser une queue par endpoint
+		INIT_LIST_HEAD(&ep->queue);
+	}
+}
+
+int usba_udc_probe(struct platform_data *pdata)
+{
+	//struct usba_platform_data *pdata = pdev->dev.platform_data;
+	//struct resource *regs, *fifo;
+	//struct clk *pclk, *hclk;
+	struct usba_udc *udc;
+	//struct usba_request *req;
+	int  i;
+	// needed to disable DMA
+	at91_pmc_t *pmc	= (at91_pmc_t *)AT91_PMC_BASE;
+	u32 regvalue;//, regvalue2;
+	
+	udc = &the_udc;
+	udc->regs = (unsigned *) AT91SAM9G45_BASE_UDPHS; 
+	udc->fifo = (unsigned *) AT91SAM9G45_UDPHS_FIFO;
+
+	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+	
+        debug("USBA : Probing USB controller\n");
+	//at91_pmc_t *pmc	= (at91_pmc_t *)AT91_PMC_BASE;
+	writel(readl(&pmc->pcer) | (1 << AT91SAM9G45_ID_UDPHS), &pmc->pcer);
+	writel(readl(&pmc->uckr) | AT91_PMC_UPLLEN | AT91_PMC_BIASEN, &pmc->uckr);
+
+	debug("USBA : Enable controller\n");
+	usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+	usba_writel(udc, INT_ENB, USBA_END_OF_RESET);	
+
+	init_requests();
+	udc_reinit(udc);
+
+	the_udc.gadget.ep0 = &udc->ep[0].ep;
+
+	udc->ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+	udc->ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+	udc->ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+	udc->ep[0].ep.ops = &usba_ep_ops;
+	udc->ep[0].ep.name = the_udc.ep[0].ep.name;
+	udc->ep[0].ep.maxpacket =  64;//the_udc.ep[0].ep.maxpacket;
+	udc->ep[0].udc = &the_udc;
+	udc->ep[0].fifo_size = 64;//the_udc.ep[0].fifo_size;
+	udc->ep[0].nr_banks = the_udc.ep[0].nr_banks;
+	udc->ep[0].index = 0;
+	udc->ep[0].is_pingpong = 0;
+	udc->ep[0].can_isoc = 0;//the_udc.ep[0].can_isoc;
+	udc->ep[0].can_dma = 0;//the_udc.ep[0].can_dma;
+	
+	for (i = 1; i < USBA_NR_ENDPOINTS; i++) {
+		struct usba_ep *ep = &udc->ep[i];
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);//udc->ep[0].fifo + udc->ep[0].fifo_size + ((i-1) * 0x10000);//0x10000);//USBA_FIFO_BASE(i);
+		ep->ep.ops = &usba_ep_ops;
+		ep->ep.name = the_udc.ep[i].ep.name;
+		ep->ep.maxpacket = 1024;
+		ep->udc = &the_udc;
+		//INIT_LIST_HEAD(&ep->queue);
+		ep->fifo_size = 1024;
+		ep->index = i;
+		if( (i == 1) || (i==2) )
+		{
+		ep->nr_banks = 1;//the_udc.ep[i].nr_banks;
+		ep->is_pingpong = 0;
+		}
+		else
+		{
+		ep->nr_banks = 1;//the_udc.ep[i].nr_banks;
+		ep->is_pingpong = 0;
+		}  
+		ep->can_isoc = 0;//the_udc.ep[i].can_isoc;
+                ep->can_dma = 0;//the_udc.ep[i].can_dma;
+
+		//list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	}
+
+
+	/* we don't use DMA : this is from the g45 spec 
+	 * 
+	 * // Reset IP UDPHS
+	   AT91C_BASE_UDPHS->UDPHS_CTRL &= ~AT91C_UDPHS_EN_UDPHS;
+	   AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_EN_UDPHS;
+	   // With OR without DMA !!!
+	   for( i=1; i<=((AT91C_BASE_UDPHS->UDPHS_IPFEATURES &
+	   AT91C_UDPHS_DMA_CHANNEL_NBR)>>4); i++ ) {
+	   // RESET endpoint canal DMA:
+	   // DMA stop channel command
+	   AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0;
+	   // STOP command
+	   // Disable endpoint
+	   AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLDIS |= 0XFFFFFFFF;
+	   // Reset endpoint config
+	   AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLCFG = 0;
+	   // Reset DMA channel (Buff count and Control field)
+	   AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0x02;
+	  // NON STOP command
+	  // Reset DMA channel 0 (STOP)
+	  AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0;
+	  // STOP command
+	  // Clear DMA channel status (read the register for clear it)
+	  AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMASTATUS =
+	  AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMASTATUS;
+	  }
+	*/
+
+	// This code disables DMA
+	// Reset IP UDPHS
+	regvalue = usba_readl(udc, CTRL);
+	usba_writel(udc, CTRL, (regvalue & ~ AT91C_UDPHS_EN_UDPHS));
+	usba_writel(udc, CTRL, (regvalue | AT91C_UDPHS_EN_UDPHS));
+    
+	regvalue = usba_readl(udc, CTRL);
+	debug("UDPHS_CTRL after reset 0x%lx\n",regvalue);
+	for( i=1; i<=(((AT91SAM9G45_BASE_UDPHS + UDPHS_IPFEATURES) &
+	   AT91C_UDPHS_DMA_CHANNEL_NBR)>>4); i++ ) {
+	  debug("UDPHS ep %d disable DMA\n",i);
+	  
+	  // DMA stop channel command
+	  __raw_writel(0x00, AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMACONTROL);
+	  // Disable endpoint
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + 0x100 + (0x20*i) + UDPHS_EPTCTLDIS);
+	  __raw_writel( (regvalue | 0XFFFFFFFF), AT91SAM9G45_BASE_UDPHS + 0x100 + (0x20*i) + UDPHS_EPTCTLDIS);
+	  // Reset endpoint config
+	  __raw_writel(0x00, AT91SAM9G45_BASE_UDPHS + 0x100 + (0x20*i) + UDPHS_EPTCFG);
+	  // Reset DMA channel (Buff count and Control field)
+	  __raw_writel(0x02, AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMACONTROL);
+	  // DMA stop channel command
+	  __raw_writel(0x00, AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMACONTROL);
+	  // Clear DMA channel status (read the register for clear it)
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMASTATUS);
+	  __raw_writel(regvalue, AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMASTATUS);
+	  
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMACONTROL);
+	  debug("UDPHS_DMACONTROL = 0x%lx\n", regvalue);
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + 0x100 + (0x20*i) + UDPHS_EPTCTLDIS);
+	  debug("UDPHS_EPTCTLDIS = 0x%lx\n", regvalue);
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + 0x100 + (0x20*i) + UDPHS_EPTCFG);
+	  debug("UDPHS_EPTCFG = 0x%lx\n", regvalue);
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + (UDPHS_DMA+ 0x10*i) + UDPHS_DMASTATUS);
+	  debug("UDPHS_DMASTATUS = 0x%lx\n", regvalue);
+	  regvalue = readl(AT91SAM9G45_BASE_UDPHS + 0xF0);
+	  debug("UDPHS_IPNAME1 = 0x%lx\n", regvalue);	
+	}
+	
+	debug("USBA : Probing finished\n");
+	return 0;
+
+}
+
+MODULE_DESCRIPTION("Atmel usba udc driver");
+MODULE_AUTHOR("Marcel Janssen");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:atmel_usba_udc");
+
diff --git a/include/usb/atmel_usba_udc.h b/include/usb/atmel_usba_udc.h
new file mode 100644
index 0000000..1664c89
--- /dev/null
+++ b/include/usb/atmel_usba_udc.h
@@ -0,0 +1,469 @@ 
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/list.h>
+
+#define __iomem
+
+/* USB register offsets */
+#define USBA_CTRL				0x0000
+#define USBA_FNUM				0x0004
+#define USBA_INT_ENB				0x0010
+#define USBA_INT_STA				0x0014
+#define USBA_INT_CLR				0x0018
+#define USBA_EPT_RST				0x001c
+#define USBA_TST				0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG				0x0000
+#define USBA_EPT_CTL_ENB			0x0004
+#define USBA_EPT_CTL_DIS			0x0008
+#define USBA_EPT_CTL				0x000c
+#define USBA_EPT_SET_STA			0x0014
+#define USBA_EPT_CLR_STA			0x0018
+#define USBA_EPT_STA				0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC			0x0000
+#define USBA_DMA_ADDRESS			0x0004
+#define USBA_DMA_CONTROL			0x0008
+#define USBA_DMA_STATUS				0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET			0
+#define USBA_DEV_ADDR_SIZE			7
+#define USBA_FADDR_EN				(1 <<  7)
+#define USBA_EN_USBA				(1 <<  8)
+#define USBA_DETACH				(1 <<  9)
+#define USBA_REMOTE_WAKE_UP			(1 << 10)
+#define USBA_PULLD_DIS				(1 << 11)
+
+#if defined(CONFIG_AVR32)
+#define USBA_ENABLE_MASK			USBA_EN_USBA
+#define USBA_DISABLE_MASK			0
+#elif defined(CONFIG_ARCH_AT91)
+#define USBA_ENABLE_MASK			(USBA_EN_USBA | USBA_PULLD_DIS)
+#define USBA_DISABLE_MASK			USBA_DETACH
+#endif /* CONFIG_ARCH_AT91 */
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET		0
+#define USBA_MICRO_FRAME_NUM_SIZE		3
+#define USBA_FRAME_NUMBER_OFFSET		3
+#define USBA_FRAME_NUMBER_SIZE			11
+#define USBA_FRAME_NUM_ERROR			(1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED				(1 <<  0)
+#define USBA_DET_SUSPEND			(1 <<  1)
+#define USBA_MICRO_SOF				(1 <<  2)
+#define USBA_SOF				(1 <<  3)
+#define USBA_END_OF_RESET			(1 <<  4)
+#define USBA_WAKE_UP				(1 <<  5)
+#define USBA_END_OF_RESUME			(1 <<  6)
+#define USBA_UPSTREAM_RESUME			(1 <<  7)
+#define USBA_EPT_INT_OFFSET			8
+#define USBA_EPT_INT_SIZE			16
+#define USBA_DMA_INT_OFFSET			24
+#define USBA_DMA_INT_SIZE			8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET				0
+#define USBA_RST_SIZE				16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET			0
+#define USBA_SPEED_CFG_SIZE			2
+#define USBA_TST_J_MODE				(1 <<  2)
+#define USBA_TST_K_MODE				(1 <<  3)
+#define USBA_TST_PKT_MODE			(1 <<  4)
+#define USBA_OPMODE2				(1 <<  5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET			0
+#define USBA_EPT_SIZE_SIZE			3
+#define USBA_EPT_DIR_IN				(1 <<  3)
+#define USBA_EPT_TYPE_OFFSET			4
+#define USBA_EPT_TYPE_SIZE			2
+#define USBA_BK_NUMBER_OFFSET			6
+#define USBA_BK_NUMBER_SIZE			2
+#define USBA_NB_TRANS_OFFSET			8
+#define USBA_NB_TRANS_SIZE			2
+#define USBA_EPT_MAPPED				(1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE				(1 <<  0)
+#define USBA_AUTO_VALID				(1 <<  1)
+#define USBA_INTDIS_DMA				(1 <<  3)
+#define USBA_NYET_DIS				(1 <<  4)
+#define USBA_DATAX_RX				(1 <<  6)
+#define USBA_MDATA_RX				(1 <<  7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE			(1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL			(1 <<  5)
+#define USBA_TOGGLE_CLR				(1 <<  6)
+#define USBA_TOGGLE_SEQ_OFFSET			6
+#define USBA_TOGGLE_SEQ_SIZE			2
+#define USBA_ERR_OVFLW				(1 <<  8)
+#define USBA_RX_BK_RDY				(1 <<  9)
+#define USBA_KILL_BANK				(1 <<  9)
+#define USBA_TX_COMPLETE			(1 << 10)
+#define USBA_TX_PK_RDY				(1 << 11)
+#define USBA_ISO_ERR_TRANS			(1 << 11)
+#define USBA_RX_SETUP				(1 << 12)
+#define USBA_ISO_ERR_FLOW			(1 << 12)
+#define USBA_STALL_SENT				(1 << 13)
+#define USBA_ISO_ERR_CRC			(1 << 13)
+#define USBA_ISO_ERR_NBTRANS			(1 << 13)
+#define USBA_NAK_IN				(1 << 14)
+#define USBA_ISO_ERR_FLUSH			(1 << 14)
+#define USBA_NAK_OUT				(1 << 15)
+#define USBA_CURRENT_BANK_OFFSET		16
+#define USBA_CURRENT_BANK_SIZE			2
+#define USBA_BUSY_BANKS_OFFSET			18
+#define USBA_BUSY_BANKS_SIZE			2
+#define USBA_BYTE_COUNT_OFFSET			20
+#define USBA_BYTE_COUNT_SIZE			11
+#define USBA_SHORT_PACKET			(1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN				(1 <<  0)
+#define USBA_DMA_LINK				(1 <<  1)
+#define USBA_DMA_END_TR_EN			(1 <<  2)
+#define USBA_DMA_END_BUF_EN			(1 <<  3)
+#define USBA_DMA_END_TR_IE			(1 <<  4)
+#define USBA_DMA_END_BUF_IE			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_IE			(1 <<  6)
+#define USBA_DMA_BURST_LOCK			(1 <<  7)
+#define USBA_DMA_BUF_LEN_OFFSET			16
+#define USBA_DMA_BUF_LEN_SIZE			16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE			(1 <<  1)
+#define USBA_DMA_END_TR_ST			(1 <<  4)
+#define USBA_DMA_END_BUF_ST			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_ST			(1 <<  6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL			0
+#define USBA_SPEED_CFG_FORCE_HIGH		2
+#define USBA_SPEED_CFG_FORCE_FULL		3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8				0
+#define USBA_EPT_SIZE_16			1
+#define USBA_EPT_SIZE_32			2
+#define USBA_EPT_SIZE_64			3
+#define USBA_EPT_SIZE_128			4
+#define USBA_EPT_SIZE_256			5
+#define USBA_EPT_SIZE_512			6
+#define USBA_EPT_SIZE_1024			7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL			0
+#define USBA_EPT_TYPE_ISO			1
+#define USBA_EPT_TYPE_BULK			2
+#define USBA_EPT_TYPE_INT			3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO			0
+#define USBA_BK_NUMBER_ONE			1
+#define USBA_BK_NUMBER_DOUBLE			2
+#define USBA_BK_NUMBER_TRIPLE			3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value)					\
+	(((value) & ((1 << USBA_##name##_SIZE) - 1))		\
+	 << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value)					\
+	(((value) >> USBA_##name##_OFFSET)			\
+	 & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old)				\
+	(((old) & ~(((1 << USBA_##name##_SIZE) - 1)		\
+		    << USBA_##name##_OFFSET))			\
+	 | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg)					\
+	__raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value)				\
+	__raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg)					\
+	__raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg)					\
+	__raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x)	(0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x)	(0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x)	((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS	7
+
+#define EP0_FIFO_SIZE		64
+#define EP0_EPT_SIZE		USBA_EPT_SIZE_64
+#define EP0_NR_BANKS		1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID	0
+#define CTRL_IOMEM_ID	1
+
+#define DBG_ERR		0x0001	/* report all error returns */
+#define DBG_HW		0x0002	/* debug hardware initialization */
+#define DBG_GADGET	0x0004	/* calls to/from gadget driver */
+#define DBG_INT		0x0008	/* interrupts */
+#define DBG_BUS		0x0010	/* report changes in bus state */
+#define DBG_QUEUE	0x0020  /* debug request queue processing */
+#define DBG_FIFO	0x0040  /* debug FIFO contents */
+#define DBG_DMA		0x0080  /* debug DMA handling */
+#define DBG_REQ		0x0100	/* print out queued request length */
+#define DBG_ALL		0xffff
+#define DBG_NONE	0x0000
+
+#define DEBUG_LEVEL	(DBG_ERR)
+
+enum usba_ctrl_state {
+	WAIT_FOR_SETUP,
+	DATA_STAGE_IN,
+	DATA_STAGE_OUT,
+	STATUS_STAGE_IN,
+	STATUS_STAGE_OUT,
+	STATUS_STAGE_ADDR,
+	STATUS_STAGE_TEST,
+};
+/*
+  EP_STATE_IDLE,
+  EP_STATE_SETUP,
+  EP_STATE_IN_DATA,
+  EP_STATE_OUT_DATA,
+  EP_STATE_SET_ADDR_STATUS,
+  EP_STATE_RX_STATUS,
+  EP_STATE_TX_STATUS,
+  EP_STATE_HALT,
+*/
+
+/*struct usba_dma_desc {
+	dma_addr_t next;
+	dma_addr_t addr;
+	u32 ctrl;
+};
+*/
+
+struct usba_ep {
+        int				state;
+	struct usb_ep			ep;
+	struct list_head		queue;
+	struct usba_udc			*udc;
+	void __iomem			*fifo;
+	//void __iomem			*creg;
+	void __iomem			*dma_regs;
+	void __iomem			*ep_regs;
+
+	unsigned			maxpacket:16;
+	u8				int_mask;
+	unsigned			is_pingpong:1;
+	u8				index;
+	u16				fifo_size;
+	u8				nr_banks;
+	unsigned			stopped:1;
+	unsigned int			can_dma:1;
+	unsigned int			can_isoc:1;
+	unsigned			is_in:1;
+	unsigned			is_isoc:1;
+	unsigned			fifo_bank:1;
+
+	const struct usb_endpoint_descriptor
+					*desc;
+};
+
+/*struct usba_ep {
+	int					state;
+	//void __iomem				*ep_regs;
+	void __iomem				*dma_regs;
+	void __iomem				*fifo;
+	struct usb_ep				ep;
+	struct usba_udc				*udc;
+
+	struct list_head			queue;
+	const struct usb_endpoint_descriptor	*desc;
+
+	u16					fifo_size;
+	u8					nr_banks;
+	u8					index;
+	unsigned int				can_dma:1;
+	unsigned int				can_isoc:1;
+	unsigned int				is_isoc:1;
+	unsigned int				is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	u32					last_dma_status;
+	struct dentry				*debugfs_dir;
+	struct dentry				*debugfs_queue;
+	struct dentry				*debugfs_dma_status;
+	struct dentry				*debugfs_state;
+#endif
+};
+*/
+
+struct usba_request {
+	struct usb_request		req;
+	struct list_head		queue;
+	unsigned int			last_transaction:1;
+	unsigned int			submitted:1;
+	//u32				ctrl;
+	unsigned 			in_use;
+};
+
+/*struct usba_request {
+	struct usb_request			req;
+	struct list_head			queue;
+
+	u32					ctrl;
+
+	unsigned int				submitted:1;
+	unsigned int				last_transaction:1;
+	unsigned int				using_dma:1;
+	unsigned int				mapped:1;
+};
+*/
+
+/* USB Device */
+struct usba_udc_data {
+	u8	vbus_pin;		/* high == host powering us */
+	u8	pullup_pin;		/* high == D+ pulled up */
+};
+
+struct platform_data {
+	struct usba_udc_data	board;
+	unsigned 		udc_clk;
+	/*struct	clk	*fclk;*/
+};
+
+/*
+ * driver is non-SMP, and just blocks IRQs whenever it needs
+ * access protection for chip registers or driver state
+ */
+
+struct usba_udc {
+
+	void __iomem *regs;
+	void __iomem *fifo;
+	//void __iomem *udp_baseaddr;
+	struct usb_gadget 		gadget;
+	struct usba_ep			ep[USBA_NR_ENDPOINTS];
+	struct usb_gadget_driver 	*driver;
+	//struct platform_device 		*pdev;
+	struct usba_udc_data		board;
+	unsigned			vbus:1;
+	//unsigned			enabled:1;
+	int irq;
+	int vbus_pin;
+	struct clk *pclk;
+	struct clk *hclk;
+
+	u16 devstatus;
+	int vbus_prev;
+
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+	return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct usba_udc, gadget);
+}
+
+int usba_udc_probe(struct platform_data *pdata);//struct platform_device *pdev);
+
+#define ep_is_control(ep)	((ep)->index == 0)
+#define ep_is_idle(ep)		((ep)->state == EP_STATE_IDLE)
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)		printf("udc: " stuff)
+#else
+#define DBG(stuff...)		do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#define VDBG(x...)	printf(x)
+//VDBG(x...) printf(__FUNCTION__ , x)
+#else
+#define VDBG(stuff...)	do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+#    define PACKET		VDBG
+#else
+#    define PACKET(stuff...)	do{}while(0)
+#endif
+
+#define ERR(stuff...)		printf("ERR udc: " stuff)
+#define WARN(stuff...)		printf("WARNING udc: " stuff)
+#define INFO(stuff...)		printf("INFO udc: " stuff)
+
+/* following defines come form At91Bootstrap. 
+ * They're needed for disabling DMA for the USB device controller 
+ */
+#define UDPHS_CTRL                   ( 0) 		// UDPHS Control Register
+#define AT91C_UDPHS_EN_UDPHS         (0x1 <<  8) 	// (UDPHS) UDPHS Enable
+#define UDPHS_IPFEATURES (248)    			// UDPHS Features Register
+#define AT91C_UDPHS_DMA_CHANNEL_NBR (0x7 <<  4) 	// (UDPHS) Number of DMA Channels
+#define UDPHS_DMACONTROL            ( 8) 		// UDPHS DMA Channel Control Register
+#define UDPHS_EPT       	    (256) 		// UDPHS Endpoint struct
+#define AT91C_BASE_UDPHS_EPT_0    (0xFFF78100) // (UDPHS_EPT_0) Base Address
+#define UDPHS_EPTCTLDIS 	    ( 8) 		// UDPHS Endpoint Control Disable Register
+#define UDPHS_EPTCFG    	    ( 0) 		// UDPHS Endpoint Config Register
+#define UDPHS_EPTCTL    	    (12) 		// UDPHS Endpoint Control Register
+#define UDPHS_DMA       	    (768) 		// UDPHS DMA channel struct (not use [0])  
+#define AT91C_BASE_UDPHS_DMA_1    (0xFFF78310)
+#define AT91C_BASE_UDPHS_DMA_1    (0xFFF78310) 	// (UDPHS_DMA_1) Base Address
+#define AT91C_BASE_UDPHS_DMA_2    (0xFFF78320) 	// (UDPHS_DMA_2) Base Address
+#define AT91C_BASE_UDPHS_DMA_3    (0xFFF78330) 	// (UDPHS_DMA_3) Base Address
+#define AT91C_BASE_UDPHS_DMA_4    (0xFFF78340) 	// (UDPHS_DMA_4) Base Address
+#define AT91C_BASE_UDPHS_DMA_5    (0xFFF78350) 	// (UDPHS_DMA_5) Base Address
+#define AT91C_BASE_UDPHS_DMA_6    (0xFFF78360) 	// (UDPHS_DMA_6) Base Address
+#define UDPHS_DMASTATUS (12) 			// UDPHS DMA Channel Status Register
+#define AT91C_BASE_UDPHS_EPTFIFO  (0x00600000) // (UDPHS_EPTFIFO) Base Address
+// ========== Register definition for UDPHS_EPTFIFO peripheral ==========
+#define AT91C_UDPHS_EPTFIFO_READEPT3 (0x00630000) // (UDPHS_EPTFIFO) FIFO Endpoint Data Register 3
+#define AT91C_UDPHS_EPTFIFO_READEPT5 (0x00650000) // (UDPHS_EPTFIFO) FIFO Endpoint Data Register 5
+#define AT91C_UDPHS_EPTFIFO_READEPT1 (0x00610000) // (UDPHS_EPTFIFO) FIFO Endpoint Data Register 1
+#define AT91C_UDPHS_EPTFIFO_READEPT0 (0x00600000) // (UDPHS_EPTFIFO) FIFO Endpoint Data Register 0
+#define AT91C_UDPHS_EPTFIFO_READEPT6 (0x00660000) // (UDPHS_EPTFIFO) FIFO Endpoint Data Register 6
+#define AT91C_UDPHS_EPTFIFO_READEPT2 (0x00620000) // (UDPHS_EPTFIFO) FIFO Endpoint Data Register 2
+#define AT91C_UDPHS_EPTFIFO_READEPT4 (0x00640000) // (UDPHS_EPTFIFO) FIFO Endpoint Data Register 4
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */