Usb Stack: only setup packet handling, and not enabled by default as there is a lot to do.
* settings code is not fully ready -> changing device driver has no effect
* clean ups
* check copyriths
* find a way to detect IN transfers
* support for full and highspeed
* ...




git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14470 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index adc3041..2503fa5 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -11156,3 +11156,73 @@
     recording: ""
   </voice>
 </phrase>
+<phrase>
+  id: LANG_USBSTACK
+  desc: in settings_menu
+  user:
+  <source>
+    *: "USB Stack"
+  </source>
+  <dest>
+    *: "USB Stack"
+  </dest>
+  <voice>
+    *: "USB Stack"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_USBSTACK_MODE
+  desc: in usbstack settings
+  user:
+  <source>
+    *: "USB Stack Mode"
+  </source>
+  <dest>
+    *: "USB Stack Mode"
+  </dest>
+  <voice>
+    *: "USB Stack Mode"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_USBSTACK_DEVICE
+  desc: in usbstack settings
+  user:
+  <source>
+    *: "Device"
+  </source>
+  <dest>
+    *: "Device"
+  </dest>
+  <voice>
+    *: "Device"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_USBSTACK_HOST
+  desc: in usbstack settings
+  user:
+  <source>
+    *: "Host"
+  </source>
+  <dest>
+    *: "Host"
+  </dest>
+  <voice>
+    *: "Host"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_USBSTACK_DEVICE_DRIVER
+  desc: in usbstack settings
+  user:
+  <source>
+    *: "Device Driver"
+  </source>
+  <dest>
+    *: "Device Driver"
+  </dest>
+  <voice>
+    *: "Device Driver"
+  </voice>
+</phrase>
\ No newline at end of file
diff --git a/apps/main.c b/apps/main.c
index df25084..54787d6 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -99,6 +99,10 @@
 #include "lcd-remote.h"
 #endif
 
+#ifdef HAVE_USBSTACK
+#include "usbstack.h"
+#endif
+
 #if CONFIG_USBOTG == USBOTG_ISP1362
 #include "isp1362.h"
 #endif
@@ -373,7 +377,10 @@
 #endif
 
     adc_init();
-    
+
+#ifdef HAVE_USBSTACK
+    usb_stack_init();
+#endif
     usb_init();
 #if CONFIG_USBOTG == USBOTG_ISP1362
     isp1362_init();
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index 0399498..5c97ac2 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -42,6 +42,13 @@
 #include "radio.h"
 #endif
 
+#ifdef HAVE_USBSTACK
+#include "list.h"
+#include "usbstack.h"
+#include "statusbar.h"
+#include "misc.h"
+#endif
+
 /***********************************/
 /*    TAGCACHE MENU                */
 #ifdef HAVE_TAGCACHE
@@ -442,6 +449,82 @@
 /*    VOICE MENU                   */
 /***********************************/
 
+#ifdef HAVE_USBSTACK
+/***********************************/
+/*    USB STACK MENU               */
+char drivers[16][32];
+static char* usb_menu_getname(int item, void * data, char *buffer)
+{
+    (void)data; (void)buffer;
+    return drivers[item];
+}
+int usbdriver_menuitem(void)
+{
+    struct gui_synclist lists;
+    int action, count = 0;
+    char *s = device_driver_names, *e;
+    do {
+        e = strchr(s, ',');
+        if (e)
+        {
+            strncpy(drivers[count++], s, e-s);
+            s = e+1;
+        }
+    } while (e && count < 16);
+    if (count < 16)
+        strcpy(drivers[count++], s);
+    for (action=0; action<count; action++)
+    {
+        if (!strcmp(drivers[action], 
+                   global_settings.usb_stack_device_driver))
+            break;
+    }
+    
+    gui_synclist_init(&lists, usb_menu_getname, drivers, false, 1);
+    gui_synclist_set_title(&lists, str(LANG_USBSTACK_DEVICE_DRIVER), NOICON);
+    gui_synclist_set_icon_callback(&lists, NULL);
+    gui_synclist_set_nb_items(&lists, count);
+    gui_synclist_select_item(&lists, action==count?0:action);
+    gui_synclist_draw(&lists);
+
+    while(1)
+    {
+        gui_syncstatusbar_draw(&statusbars, true);
+        action = get_action(CONTEXT_STD, HZ/5); 
+        if (gui_synclist_do_button(&lists, action, LIST_WRAP_UNLESS_HELD))
+            continue;
+        if (action == ACTION_STD_CANCEL)
+        {
+            // setting was canceled
+            break;
+        }
+        else if (action == ACTION_STD_OK)
+        {
+            // setting was accepted... save
+            strcpy(global_settings.usb_stack_device_driver, 
+                  drivers[gui_synclist_get_sel_pos(&lists)]);
+            break;
+        }
+        else if (action == ACTION_REDRAW)
+            gui_synclist_draw(&lists);
+        else if(default_event_handler(action) == SYS_USB_CONNECTED)
+            return true;
+    }
+    return false;
+}
+
+MENUITEM_SETTING(usbstack_mode, &global_settings.usb_stack_mode, NULL);
+MENUITEM_FUNCTION(usbdriver, 0, ID2P(LANG_USBSTACK_DEVICE_DRIVER),
+                  usbdriver_menuitem, 0,  NULL, Icon_NOICON);
+
+MAKE_MENU(usbstack_menu, ID2P(LANG_USBSTACK), 0, Icon_NOICON,
+                &usbstack_mode, &usbdriver);
+/*    USB STACK MENU               */
+/***********************************/
+#endif
+
+/***********************************/
+
 /***********************************/
 /*    SETTINGS MENU                */
 static int language_browse(void)
@@ -458,6 +541,10 @@
           &tagcache_menu,
 #endif
           &display_menu, &system_menu,
-          &bookmark_settings_menu, &browse_langs, &voice_settings_menu );
+          &bookmark_settings_menu, &browse_langs, &voice_settings_menu
+#ifdef HAVE_USBSTACK
+          , &usbstack_menu
+#endif
+          );
 /*    SETTINGS MENU                */
 /***********************************/
diff --git a/apps/settings.c b/apps/settings.c
index cd1c252..c7c8772 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -98,6 +98,10 @@
 #include "lcd-remote.h"
 #endif
 
+#ifdef HAVE_USBSTACK
+#include "usbstack.h"
+#endif
+
 long lasttime = 0;
 
 /** NVRAM stuff, if the target doesnt have NVRAM it is saved in ROCKBOX_DIR /nvram.bin **/
@@ -875,11 +879,13 @@
         read_color_theme_file();
 #endif
     
+#ifdef HAVE_USBSTACK
+    usb_controller_select(global_settings.usb_stack_mode);
+    usb_device_driver_bind(global_settings.usb_stack_device_driver);
+#endif    
 }
 
 
-
-
 /*
  * reset all settings to their default value
  */
diff --git a/apps/settings.h b/apps/settings.h
index 987709c..c4cb917 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -748,6 +748,10 @@
     int list_accel_start_delay; /* ms before we start increaseing step size */
     int list_accel_wait; /* ms between increases */
 #endif
+#ifdef HAVE_USBSTACK
+    int usb_stack_mode;	/* device or host */
+    unsigned char usb_stack_device_driver[32]; /* usb device driver to load */
+#endif
 };
 
 /** global variables **/
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 16c3222..1218dbf 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -47,6 +47,9 @@
 #include "radio.h"
 #endif
 
+#ifdef HAVE_USBSTACK
+#include "usbstack.h"
+#endif
 
 #define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
 /** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
@@ -1260,6 +1263,14 @@
                 3, "list_accel_wait", UNIT_SEC, 1, 10, 1, 
                 scanaccel_formatter, scanaccel_getlang, NULL),
 #endif /* HAVE_SCROLLWHEEL */
+#ifdef HAVE_USBSTACK
+    CHOICE_SETTING(0, usb_stack_mode, LANG_USBSTACK_MODE, 0, "usb mode",
+                 "device,host",
+                 usb_controller_select,
+                 2, ID2P(LANG_USBSTACK_DEVICE), ID2P(LANG_USBSTACK_HOST)),
+    FILENAME_SETTING(0, usb_stack_device_driver, "usb device driver",
+                 "storage", NULL, NULL, 32),                 
+#endif /* HAVE_USBSTACK */               
 };
 
 const int nb_settings = sizeof(settings)/sizeof(*settings);
diff --git a/firmware/SOURCES b/firmware/SOURCES
index cd628fb..c704bee 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -101,6 +101,7 @@
 drivers/serial.c
 #endif /* SIMULATOR */
 
+
 /* Storage */
 #ifndef SIMULATOR
 #ifdef HAVE_MMC
@@ -221,6 +222,18 @@
 #endif /* defined(HAVE_*) */
 #endif /* SIMULATOR */
 
+/* USB Stack */
+#if !defined(SIMULATOR)
+#ifdef HAVE_USBSTACK
+usbstack/core/core.c
+usbstack/core/epsetup.c
+usbstack/core/utils.c
+usbstack/core/config.c
+usbstack/drivers/device/usb_serial.c
+usbstack/drivers/device/usb_storage.c
+#endif
+#endif
+
 /* USBOTG */
 #if !defined(SIMULATOR)
 #if CONFIG_USBOTG == USBOTG_ISP1362
@@ -230,7 +243,7 @@
 #if CONFIG_USBOTG == USBOTG_M5636
 drivers/m5636.c
 #elif CONFIG_USBOTG == USBOTG_ARC
-drivers/arcotg_udc.c
+drivers/usb/arcotg_dcd.c
 #endif /* CONFIG_USBOTG */
 #endif /* !defined(BOOTLOADER) */
 #endif /* !defined(SIMULATOR) */
diff --git a/firmware/drivers/usb/arcotg_dcd.c b/firmware/drivers/usb/arcotg_dcd.c
new file mode 100644
index 0000000..982fdfb
--- /dev/null
+++ b/firmware/drivers/usb/arcotg_dcd.c
@@ -0,0 +1,983 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * Based on code from the Linux Target Image Builder from Freescale
+ * available at http://www.bitshrine.org/ and
+ * http://www.bitshrine.org/gpp/linux-2.6.16-mx31-usb-2.patch
+ * Adapted for Rockbox in January 2007
+ * Original file: drivers/usb/gadget/arcotg_udc.c
+ *
+ * USB Device Controller Driver
+ * Driver for ARC OTG USB module in the i.MX31 platform, etc.
+ *
+ * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Based on mpc-udc.h
+ * Author: Li Yang (leoli@freescale.com)
+ *         Jiang Bo (Tanya.jiang@freescale.com)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <string.h>
+#include "arcotg_dcd.h"
+
+/*-------------------------------------------------------------------------*/
+
+static struct arcotg_dcd dcd_controller;
+struct usb_response res;
+
+/* datastructes to controll transfers */
+struct dtd dev_td[USB_MAX_PIPES] IBSS_ATTR;
+struct dqh dev_qh[USB_MAX_PIPES] __attribute((aligned (1 << 11))) IBSS_ATTR;
+
+/* shared memory used by rockbox and dcd to exchange data */
+#define BUFFER_SIZE 512
+unsigned char buffer[BUFFER_SIZE] IBSS_ATTR;
+
+/*-------------------------------------------------------------------------*/
+
+/* description of our device driver operations */
+struct usb_dcd_controller_ops arotg_dcd_ops = {
+    .enable          = usb_arcotg_dcd_enable,
+    .disable         = NULL,
+    .set_halt        = usb_arcotg_dcd_set_halt,
+    .send            = usb_arcotg_dcd_send,
+    .receive         = usb_arcotg_dcd_receive,
+    .ep0             = &dcd_controller.endpoints[0],
+};
+
+/* description of our usb controller driver */
+struct usb_controller arcotg_dcd = {
+    .name            = "arcotg_dcd",
+    .type            = DEVICE,
+    .speed           = USB_SPEED_UNKNOWN,
+    .init            = usb_arcotg_dcd_init,
+    .shutdown        = usb_arcotg_dcd_shutdown,
+    .irq             = usb_arcotg_dcd_irq,
+    .start           = usb_arcotg_dcd_start,
+    .stop            = usb_arcotg_dcd_stop,
+    .controller_ops  = (void*)&arotg_dcd_ops,
+};
+
+static struct usb_response response;
+
+/*-------------------------------------------------------------------------*/
+
+/* TODO hmmm */
+
+struct timer {
+  unsigned long s;
+  unsigned long e;
+};
+
+void
+timer_set(struct timer * timer, unsigned long val)
+{
+  timer->s = USEC_TIMER;
+  timer->e = timer->s + val + 1;
+}
+
+int
+timer_expired(struct timer * timer)
+{
+  unsigned long val = USEC_TIMER;
+
+  if (timer->e > timer->s) {
+    return !(val >= timer->s && val <= timer->e);
+  } else {
+    return (val > timer->e && val < timer->s);
+  }
+}
+
+#define MAX_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+
+#define ERROR_TIMEOUT  (-3)
+#define ERROR_UNKNOWN  (-7)
+
+#define PRIME_TIMER    100000
+#define TRANSFER_TIMER 1000000
+#define RESET_TIMER    5000000
+#define SETUP_TIMER    200000
+
+/*-------------------------------------------------------------------------*/
+
+/* gets called by usb_stack_init() to register 
+ * this arcotg device conrtollder driver in the 
+ * stack. */
+void usb_dcd_init(void) {
+    usb_controller_register(&arcotg_dcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+void usb_arcotg_dcd_init(void) {
+
+    struct timer t;
+    int i, ep_num = 0;
+
+    logf("arcotg_dcd: init");
+    memset(&dcd_controller, 0, sizeof(struct arcotg_dcd));
+
+    /* setup list of aviable endpoints */
+    INIT_LIST_HEAD(&arcotg_dcd.endpoints.list);
+
+    for (i = 0; i < USB_MAX_PIPES; i++) {
+
+        dcd_controller.endpoints[i].pipe_num = i;
+
+        if (i % 2 == 0) {
+            dcd_controller.endpoints[i].ep_num = ep_num;
+        } else {
+            dcd_controller.endpoints[i].ep_num = ep_num;
+            ep_num++;
+        }
+
+        logf("pipe %d -> ep %d %s", dcd_controller.endpoints[i].pipe_num, dcd_controller.endpoints[i].ep_num, dcd_controller.endpoints[i].name);
+
+        if (ep_name[i] != NULL) {
+            memcpy(&dcd_controller.endpoints[i].name, ep_name[i], sizeof(dcd_controller.endpoints[i].name));
+
+            if (i != 0) {
+                /* add to list of configurable endpoints */
+                list_add_tail(&dcd_controller.endpoints[i].list, &arcotg_dcd.endpoints.list);
+            }
+        }
+    }
+
+    /* ep0 is special */
+    arcotg_dcd.ep0 = &dcd_controller.endpoints[0];
+    arcotg_dcd.ep0->maxpacket = USB_MAX_CTRL_PAYLOAD;
+
+    /* stop */
+    UDC_USBCMD &= ~USB_CMD_RUN;
+
+    udelay(50000);
+    timer_set(&t, RESET_TIMER);
+
+    /* reset */
+    UDC_USBCMD |= USB_CMD_CTRL_RESET;
+
+    while ((UDC_USBCMD & USB_CMD_CTRL_RESET)) {
+        if (timer_expired(&t)) {
+            logf("TIMEOUT->init");
+        }
+    }
+
+    /* put controller in device mode */
+    UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE;
+
+    /* init queue heads */    
+    qh_init(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD, 0, 0);
+    qh_init(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD, 0, 0);    
+
+    UDC_ENDPOINTLISTADDR = (unsigned int)dev_qh;
+}
+
+void usb_arcotg_dcd_shutdown(void) {
+
+}
+
+void usb_arcotg_dcd_start(void) {
+
+    logf("start");
+
+    if (arcotg_dcd.device_driver != NULL) {
+    	logf("YEEEEEEESSSSSSS");
+    } else {
+    	logf("NOOOOOO");
+    }
+    
+    /* clear stopped bit */
+    dcd_controller.stopped = false;   
+
+    UDC_USBCMD |= USB_CMD_RUN;
+}
+
+void usb_arcotg_dcd_stop(void) {
+
+    logf("stop");
+
+    /* set stopped bit */
+    dcd_controller.stopped = true;
+
+    UDC_USBCMD &= ~USB_CMD_RUN;
+}
+
+void usb_arcotg_dcd_irq(void) {
+
+    int i;
+
+    if (dcd_controller.stopped == true) {
+        return;
+    }
+
+    /* check if we need to wake up from suspend */
+    if (!(UDC_USBSTS & USB_STS_SUSPEND) && dcd_controller.resume_state) {
+        resume_int();
+    }
+
+    /* USB Interrupt */
+    if (UDC_USBSTS & USB_STS_INT) {
+
+        /* setup packet, we only support ep0 as control ep */
+        if (UDC_ENDPTSETUPSTAT & EP_SETUP_STATUS_EP0) {
+            /* copy data from queue head to local buffer */
+            memcpy(&dcd_controller.local_setup_buff, (uint8_t *) &dev_qh[0].setup_buffer, 8);
+            /* ack setup packet*/
+            UDC_ENDPTSETUPSTAT = UDC_ENDPTSETUPSTAT;
+            setup_received_int(&dcd_controller.local_setup_buff);
+        }
+
+        if (UDC_ENDPTCOMPLETE) {
+        	UDC_ENDPTCOMPLETE = UDC_ENDPTCOMPLETE;
+        }
+    }
+    
+    if (UDC_USBSTS & USB_STS_PORT_CHANGE) {
+        port_change_int();
+    }
+
+    if (UDC_USBSTS & USB_STS_SUSPEND) {
+        suspend_int();
+    }
+
+    if (UDC_USBSTS & USB_STS_RESET) {
+        reset_int();
+    }
+
+    if (UDC_USBSTS & USB_STS_ERR) {
+        logf("!!! error !!!");
+    }
+
+    if (UDC_USBSTS & USB_STS_SYS_ERR) {
+        logf("!!! sys error !!!");
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+/* interrupt handlers */
+
+static void setup_received_int(struct usb_ctrlrequest* request) {
+
+    int error = 0;
+    uint8_t address = 0;
+    int handled = 0;    /* set to zero if we do not handle the message, */
+                        /* and should pass it to the driver */	
+
+    logf("setup_int");
+    into_usb_ctrlrequest(request);
+
+    /* handle all requests we support */
+    switch (request->bRequestType & USB_TYPE_MASK) {
+    case USB_TYPE_STANDARD:
+
+        switch (request->bRequest) {
+        case USB_REQ_SET_ADDRESS:
+
+            /* store address as we need to ack before setting it */
+            address = (uint8_t)request->wValue;
+
+            handled = 1;
+            break;
+
+        case USB_REQ_GET_STATUS:
+
+            logf("sending status..");
+            response.buf = &dcd_controller.usb_state;
+            response.length = 2;
+
+            handled = usb_arcotg_dcd_send(NULL, &response);
+            break;
+        }
+
+        case USB_REQ_CLEAR_FEATURE:
+        case USB_REQ_SET_FEATURE:
+            /* we only support set/clear feature for endpoint */
+            if (request->bRequestType == USB_RECIP_ENDPOINT) {
+                int dir = (request->wIndex & 0x0080) ? EP_DIR_IN : EP_DIR_OUT;
+                int num = (request->wIndex & 0x000f);
+                struct usb_ep *ep;
+
+                if (request->wValue != 0 || request->wLength != 0 || (num * 2 + dir) > USB_MAX_PIPES) {
+                    break;
+                }
+                ep = &dcd_controller.endpoints[num * 2 + dir];
+
+                if (request->bRequest == USB_REQ_SET_FEATURE) {
+                    logf("SET_FEATURE doing set_halt");
+                    handled = usb_arcotg_dcd_set_halt(ep, 1);
+                } else {
+                    logf("CLEAR_FEATURE doing clear_halt");
+                    handled = usb_arcotg_dcd_set_halt(ep, 0);
+                }
+
+                if (handled == 0) {
+                	handled = 1; /* dont pass it to driver */
+                }
+            }
+#if 0            
+            if (rc == 0) {
+                /* send status only if _arcotg_ep_set_halt success */
+                if (ep0_prime_status(udc, EP_DIR_IN))
+                    Ep0Stall(udc);
+            }		
+#endif		
+            break;
+    }
+
+    /* if dcd can not handle reqeust, ask driver */
+    if (handled == 0) {
+        if (arcotg_dcd.device_driver != NULL && arcotg_dcd.device_driver->request != NULL) {
+            handled = arcotg_dcd.device_driver->request(request);
+            logf("result from driver %d", handled);
+        }
+    }
+
+    if (handled <= 0) {
+        error = handled;
+    }
+
+    /* ack transfer */
+    usb_ack(request, error);
+
+    if (address != 0) {
+        logf("setting address to %d", address);
+        UDC_DEVICEADDR = address << 25;
+    }
+}
+
+static void port_change_int(void) {
+
+    //logf("port_change_int");
+    uint32_t tmp;
+    enum usb_device_speed speed = USB_SPEED_UNKNOWN; 
+
+    /* bus resetting is finished */
+    if (!(UDC_PORTSC1 & PORTSCX_PORT_RESET)) {
+        /* Get the speed */
+        tmp = (UDC_PORTSC1 & PORTSCX_PORT_SPEED_MASK);
+        switch (tmp) {
+        case PORTSCX_PORT_SPEED_HIGH:
+            speed = USB_SPEED_HIGH;
+            break;
+        case PORTSCX_PORT_SPEED_FULL:
+            speed = USB_SPEED_FULL;
+            break;
+        case PORTSCX_PORT_SPEED_LOW:
+            speed = USB_SPEED_LOW;
+            break;
+        default:
+            speed = USB_SPEED_UNKNOWN;
+            break;
+        }
+    }
+
+    /* update speed */
+    arcotg_dcd.speed = speed;
+    
+    /* update USB state */
+    if (!dcd_controller.resume_state) {
+        dcd_controller.usb_state = USB_STATE_DEFAULT;
+    }
+
+    /* inform device driver */
+    if (arcotg_dcd.device_driver != NULL && arcotg_dcd.device_driver->speed != NULL) {
+        arcotg_dcd.device_driver->speed(speed);
+    }
+}
+
+static void suspend_int(void) {
+
+    //logf("suspend_int");
+    dcd_controller.resume_state = dcd_controller.usb_state;
+    dcd_controller.usb_state = USB_STATE_SUSPENDED;
+
+    /* report suspend to the driver */
+    if (arcotg_dcd.device_driver != NULL && arcotg_dcd.device_driver->suspend != NULL) {
+        arcotg_dcd.device_driver->suspend();
+    }
+}
+
+static void resume_int(void) {
+
+    //logf("resume_int");
+    dcd_controller.usb_state = dcd_controller.resume_state;
+    dcd_controller.resume_state = USB_STATE_NOTATTACHED;
+
+    /* report resume to the driver */
+    if (arcotg_dcd.device_driver != NULL && arcotg_dcd.device_driver->resume != NULL) {
+        arcotg_dcd.device_driver->resume();
+    }
+}
+
+static void reset_int(void) {
+
+    //logf("reset_int");
+    struct timer t;
+
+    timer_set(&t, RESET_TIMER);
+
+    UDC_ENDPTSETUPSTAT = UDC_ENDPTSETUPSTAT;
+    UDC_ENDPTCOMPLETE  = UDC_ENDPTCOMPLETE;
+
+    while (UDC_ENDPTPRIME) { /* prime and flush pending transfers */
+        if (timer_expired(&t)) {
+            logf("TIMEOUT->p&f");
+        }
+    }
+
+    UDC_ENDPTFLUSH = ~0;
+
+    if ((UDC_PORTSC1 & (1 << 8)) == 0) {
+        logf("TIMEOUT->port");
+    }
+
+    UDC_USBSTS = (1 << 6);
+
+    while ((UDC_USBSTS & (1 << 2)) == 0) { /* wait for port change */
+        if (timer_expired(&t)) {
+        logf("TIMEOUT->portchange");
+        }
+    }
+
+    UDC_USBSTS = (1 << 2);
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* usb controller ops */
+
+int usb_arcotg_dcd_enable(struct usb_ep* ep) {
+
+    unsigned short max = 0;
+    unsigned char mult = 0, zlt = 0;
+    int retval = 0;
+    char *val = NULL;	/* for debug */
+
+    /* catch bogus parameter */
+    if (!ep) {
+        return -EINVAL;
+    }
+
+    logf("ahhh %d", ep->desc->wMaxPacketSize);
+    max = ep->desc->wMaxPacketSize;
+    retval = -EINVAL;
+
+    /* check the max package size validate for this endpoint */
+    /* Refer to USB2.0 spec table 9-13,
+     */
+    switch (ep->desc->bmAttributes & 0x03) {
+    case USB_ENDPOINT_XFER_BULK:
+        zlt = 1;
+        break;
+
+    case USB_ENDPOINT_XFER_INT:
+        zlt = 1;
+    break;
+
+    case USB_ENDPOINT_XFER_ISOC:
+        break;
+
+    case USB_ENDPOINT_XFER_CONTROL:
+        break;
+    }
+
+#if 0
+    switch (ep->desc->bmAttributes & 0x03) {
+	case USB_ENDPOINT_XFER_BULK:
+		if (strstr(ep->ep.name, "-iso") || strstr(ep->ep.name, "-int")) {
+			goto en_done;
+		}
+		mult = 0;
+		zlt = 1;
+		
+		switch (arcotg_dcd.speed) {
+		case USB_SPEED_HIGH:
+			if ((max == 128) || (max == 256) || (max == 512)) {
+				break;
+			}
+		default:
+			switch (max) {
+			case 4:
+			case 8:
+			case 16:
+			case 32:
+			case 64:
+				break;
+			default:
+	+			case USB_SPEED_LOW:
+	+				goto en_done;
+	+			}
+	+		}
+	+		break;
+	+	case USB_ENDPOINT_XFER_INT:
+	+		if (strstr(ep->ep.name, "-iso"))	/* bulk is ok */
+	+			goto en_done;
+	+		mult = 0;
+	+		zlt = 1;
+	+		switch (udc->gadget.speed) {
+	+		case USB_SPEED_HIGH:
+	+			if (max <= 1024)
+	+				break;
+	+		case USB_SPEED_FULL:
+	+			if (max <= 64)
+	+				break;
+	+		default:
+	+			if (max <= 8)
+	+				break;
+	+			goto en_done;
+	+		}
+	+		break;
+	+	case USB_ENDPOINT_XFER_ISOC:
+	+		if (strstr(ep->ep.name, "-bulk") || strstr(ep->ep.name, "-int"))
+	+			goto en_done;
+	+		mult = (unsigned char)
+	+		    (1 + ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 0x03));
+	+		zlt = 0;
+	+		switch (udc->gadget.speed) {
+	+		case USB_SPEED_HIGH:
+	+			if (max <= 1024)
+	+				break;
+	+		case USB_SPEED_FULL:
+	+			if (max <= 1023)
+	+				break;
+	+		default:
+	+			goto en_done;
+	+		}
+	+		break;
+	+	case USB_ENDPOINT_XFER_CONTROL:
+	+		if (strstr(ep->ep.name, "-iso") || strstr(ep->ep.name, "-int"))
+	+			goto en_done;
+	+		mult = 0;
+	+		zlt = 1;
+	+		switch (udc->gadget.speed) {
+	+		case USB_SPEED_HIGH:
+	+		case USB_SPEED_FULL:
+	+			switch (max) {
+	+			case 1:
+	+			case 2:
+	+			case 4:
+	+			case 8:
+	+			case 16:
+	+			case 32:
+	+			case 64:
+	+				break;
+	+			default:
+	+				goto en_done;
+	+			}
+	+		case USB_SPEED_LOW:
+	+			switch (max) {
+	+			case 1:
+	+			case 2:
+	+			case 4:
+	+			case 8:
+	+				break;
+	+			default:
+	+				goto en_done;
+	+			}
+	+		default:
+	+			goto en_done;
+	+		}
+	+		break;
+	+
+	+	default:
+	+		goto en_done;
+	+	}
+#endif
+
+    /* here initialize variable of ep */
+    ep->maxpacket = max;
+
+    /* hardware special operation */
+
+    /* Init EPx Queue Head (Ep Capabilites field in QH
+     * according to max, zlt, mult) */
+    qh_init(ep->ep_num,
+            (ep->desc->bEndpointAddress & USB_DIR_IN) ? USB_RECV : USB_SEND, 
+            (unsigned char) (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK),
+            max, zlt, mult);
+
+    /* Init endpoint x at here */
+    ep_setup(ep->ep_num, 
+            (unsigned char)((ep->desc->bEndpointAddress & USB_DIR_IN) ? USB_RECV : USB_SEND),
+            (unsigned char)(ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK));
+
+    /* Now HW will be NAKing transfers to that EP,
+     * until a buffer is queued to it. */
+
+    retval = 0;
+    switch (ep->desc->bmAttributes & 0x03) {
+    case USB_ENDPOINT_XFER_BULK:
+        val = "bulk";
+        break;
+    case USB_ENDPOINT_XFER_ISOC:
+        val = "iso";
+        break;
+    case USB_ENDPOINT_XFER_INT:
+        val = "intr";
+        break;
+    default:
+        val = "ctrl";
+        break;
+    }
+
+    logf("ep num %d", (int)ep->ep_num);
+
+    logf("enabled %s (ep%d%s-%s)", ep->name,
+         ep->desc->bEndpointAddress & 0x0f,
+        (ep->desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", val);
+    logf(" maxpacket %d", max);
+
+    return retval;
+}
+
+int usb_arcotg_dcd_set_halt(struct usb_ep* ep, bool halt) {
+
+    int status = -EOPNOTSUPP; /* operation not supported */
+    unsigned char dir = 0;
+    unsigned int tmp_epctrl = 0;
+
+    if (!ep) {
+        status = -EINVAL;
+        goto out;
+    }
+
+    if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+        status = -EOPNOTSUPP;
+        goto out;
+    }
+
+    status = 0;
+    dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+
+    tmp_epctrl = UDC_ENDPTCTRL(ep->ep_num);
+
+    if (halt) {
+        /* set the stall bit */
+        if (dir) {
+            tmp_epctrl |= EPCTRL_TX_EP_STALL;
+        } else {
+            tmp_epctrl |= EPCTRL_RX_EP_STALL;
+        }
+    } else {
+        /* clear the stall bit and reset data toggle */
+        if (dir) {
+            tmp_epctrl &= ~EPCTRL_TX_EP_STALL;
+            tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+        } else {
+            tmp_epctrl &= ~EPCTRL_RX_EP_STALL;
+            tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+        }
+    }
+    UDC_ENDPTCTRL(ep->ep_num) = tmp_epctrl;
+
+out:
+    logf(" %s %s halt rc=%d", ep->name, halt ? "set" : "clear", status);
+    return status;
+}
+
+int usb_arcotg_dcd_send(struct usb_ep* ep, struct usb_response* res) {
+
+    char* ptr;
+    int todo, error, size, done = 0;
+    int index = 1; /* use as default ep0 tx qh and td */
+    struct dtd* td;
+    struct dqh* qh;
+    unsigned int mask;
+
+    if (res == NULL) {
+        logf("invalid input");
+        return -EINVAL;
+    }
+
+    if (ep != NULL) {
+        index = ep->pipe_num;
+    }
+
+    logf("buff: %x", res->buf);
+    logf("len: %d", res->length);
+
+    ptr = res->buf;
+    size = res->length;
+
+    td = &dev_td[index];
+    qh = &dev_qh[index];
+    mask = 1 << (15 + index);
+    logf("sending mask: %x", mask);
+
+    do {
+        /* calculate how much to copy and send */
+        todo = MIN(size, BUFFER_SIZE);
+
+        /* copy data to shared memory area */
+        memcpy(buffer, ptr, todo);
+
+        /* init transfer descriptor */
+        td_init(td, buffer, todo);
+
+        /* start transfer*/
+        error = td_enqueue(td, qh, mask);
+
+        if (error == 0) {
+            /* waiting for finished transfer */
+            error = td_wait(td, mask);
+        }
+
+        if (error) {
+            done = error;
+            break;
+        }
+
+        size -= todo;
+        ptr  += todo;
+        done += todo;
+
+    } while (size > 0);
+
+    logf("usb_send done %d",done);
+    return done;
+}
+
+int usb_arcotg_dcd_receive(struct usb_ep* ep, struct usb_response* res) {
+
+    char* ptr;
+    int todo, error, size, done = 0;
+    int index = 0; /* use as default ep0 rx qh and td */
+    struct dtd* td;
+    struct dqh* qh;
+    unsigned int mask;
+
+    if (res == NULL) {
+        logf("invalid input");
+        return -EINVAL;
+    }
+
+    if (ep != NULL) {
+        index = ep->pipe_num;
+    }
+
+    ptr = res->buf;
+    size = res->length;
+
+    td = &dev_td[index];
+    qh = &dev_qh[index];
+    mask = 1 << index;
+
+    do {
+        /* calculate how much to receive in one step */
+        todo = MIN(size, BUFFER_SIZE);
+
+        /* init transfer descritpor */
+        td_init(td, buffer, size);
+
+        /* start transfer */
+        error = td_enqueue(td, qh, mask);
+
+        if (error == 0) {
+            /* wait until transfer is finished */
+            error = td_wait(td, mask);
+        }
+
+        if (error) {
+            done = error;
+            break;
+        }
+
+        /* copy receive data to buffer */
+        memcpy(ptr, buffer, todo);
+
+        size -= todo;
+        ptr  += todo;
+        done += todo;
+
+    } while (size > 0);
+
+    logf("usb_recive done %d",done);
+    return done;
+}
+
+/*-------------------------------------------------------------------------*/
+/* lifecylce */
+
+static void qh_init(unsigned char ep_num, unsigned char dir, unsigned char ep_type,
+                    unsigned int max_pkt_len, unsigned int zlt, unsigned char mult) {
+
+    struct dqh *qh = &dev_qh[2 * ep_num + dir];   
+    uint32_t tmp = 0;
+    memset(qh, 0, sizeof(struct dqh));
+
+    /* set the Endpoint Capabilites Reg of QH */
+    switch (ep_type) {
+    case USB_ENDPOINT_XFER_CONTROL:
+        /* Interrupt On Setup (IOS). for control ep  */
+        tmp = (max_pkt_len << LENGTH_BIT_POS) | INTERRUPT_ON_COMPLETE;
+        break;
+    case USB_ENDPOINT_XFER_ISOC:
+        tmp = (max_pkt_len << LENGTH_BIT_POS) | (mult << EP_QUEUE_HEAD_MULT_POS);
+        break;
+    case USB_ENDPOINT_XFER_BULK:
+    case USB_ENDPOINT_XFER_INT:
+        tmp = max_pkt_len << LENGTH_BIT_POS;
+        if (zlt) {
+            tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+        }
+        break;
+    default:
+        logf("error ep type is %d", ep_type);
+            return;
+    }
+
+    /* see 32.14.4.1 Queue Head Initialization */
+
+    /* write the wMaxPacketSize field as required by the USB Chapter9 or application specific portocol */
+    qh->endpt_cap = tmp;
+
+    /* write the next dTD Terminate bit fild to 1 */
+    qh->dtd_ovrl.next_dtd = 1;
+
+    /* write the Active bit in the status field to 0 */
+    qh->dtd_ovrl.dtd_token &= ~STATUS_ACTIVE;
+
+    /* write the Hald bit in the status field to 0 */
+    qh->dtd_ovrl.dtd_token &= ~STATUS_HALTED;
+
+    logf("qh: init %d", (2 * ep_num + dir));
+}
+
+static void td_init(struct dtd* td, void* buffer, uint32_t todo) {
+
+    /* see 32.14.5.2 Building a Transfer Descriptor */
+
+    /* init first 7 dwords with 0 */
+    memset(td, 0, sizeof(struct dtd)); /* set set all to 0 */
+
+    /* set terminate bit to 1*/
+    td->next_dtd = 1;
+
+    /* fill in total bytes with transfer size */
+    td->dtd_token = (todo << 16);
+
+    /* set interrupt on compilte if desierd */
+    td->dtd_token |= INTERRUPT_ON_COMPLETE;
+
+    /* initialize the status field with the active bit set to 1 and all remaining status bits to 0 */
+    td->dtd_token |= STATUS_ACTIVE;
+
+    td->buf_ptr0 = (uint32_t)buffer;
+}
+
+static void ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type) {
+
+    unsigned int tmp_epctrl = 0;
+    struct timer t;
+
+    tmp_epctrl = UDC_ENDPTCTRL(ep_num);
+    if (dir) {
+        if (ep_num) {
+            tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+        }
+        logf("tx enablde");
+        tmp_epctrl |= EPCTRL_TX_ENABLE;
+        tmp_epctrl |= ((unsigned int)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT);
+    } else {
+        if (ep_num) {
+            tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+        }
+        logf("rx enablde");
+        tmp_epctrl |= EPCTRL_RX_ENABLE;
+        tmp_epctrl |= ((unsigned int)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT);
+    }
+
+    UDC_ENDPTCTRL(ep_num) = tmp_epctrl;
+    
+    /* wait for the write reg to finish */
+
+    timer_set(&t, SETUP_TIMER);    
+    while (!(UDC_ENDPTCTRL(ep_num) & (tmp_epctrl & (EPCTRL_TX_ENABLE | EPCTRL_RX_ENABLE)))) {
+        if (timer_expired(&t)) {
+        	logf("TIMEOUT: enable ep");
+            return;
+        }    	
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+/* helpers for sending/receiving */
+
+static int td_enqueue(struct dtd* td, struct dqh* qh, unsigned int mask) {
+
+    struct timer t;
+
+    qh->dtd_ovrl.next_dtd   = (unsigned int)td;
+    qh->dtd_ovrl.dtd_token &= ~0xc0;
+
+    timer_set(&t, PRIME_TIMER);
+    UDC_ENDPTPRIME |= mask;
+
+    while ((UDC_ENDPTPRIME & mask)) {
+        if (timer_expired(&t)) {
+            logf("timeout->prime");
+        }
+    }
+
+    if ((UDC_ENDPTSTAT & mask) == 0) {
+        logf("Endptstat 0x%x", UDC_ENDPTSTAT);
+        logf("HW_ERROR");
+    }
+
+    return 0;
+}
+
+static int td_wait(struct dtd* td, unsigned int mask) {
+
+    struct timer t;
+    timer_set(&t, TRANSFER_TIMER);
+
+    for (;;) {
+        if ((UDC_ENDPTCOMPLETE & mask) != 0) {
+            UDC_ENDPTCOMPLETE |= mask;
+        }
+
+        if ((td->dtd_token & (1 << 7)) == 0) {
+            return 0;
+        }
+
+        if (timer_expired(&t)) {
+            return ERROR_TIMEOUT;
+        }
+    }
+}
+
+static int usb_ack(struct usb_ctrlrequest * s, int error) {
+
+    if (error) {
+        logf("STALLing ep0");
+        UDC_ENDPTCTRL0 |= 1 << 16; /* stall */
+        return 0;
+    }
+
+    res.buf = NULL;
+    res.length = 0;
+
+    if (s->bRequestType & 0x80) {
+        logf("ack in");
+        return usb_arcotg_dcd_receive(NULL, &res);
+    } else {
+        logf("ack out");
+        return usb_arcotg_dcd_send(NULL, &res);
+    }
+}
diff --git a/firmware/drivers/usb/arcotg_dcd.h b/firmware/drivers/usb/arcotg_dcd.h
new file mode 100644
index 0000000..127ee43
--- /dev/null
+++ b/firmware/drivers/usb/arcotg_dcd.h
@@ -0,0 +1,173 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * Based on code from the Linux Target Image Builder from Freescale
+ * available at http://www.bitshrine.org/ and
+ * http://www.bitshrine.org/gpp/linux-2.6.16-mx31-usb-2.patch
+ * Adapted for Rockbox in January 2007
+ * Original file: drivers/usb/gadget/arcotg_udc.c
+ *
+ * USB Device Controller Driver
+ * Driver for ARC OTG USB module in the i.MX31 platform, etc.
+ *
+ * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Based on mpc-udc.h
+ * Author: Li Yang (leoli@freescale.com)
+ *         Jiang Bo (Tanya.jiang@freescale.com)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _ARCOTG_DCD_H_
+#define _ARCOTG_DCD_H_
+
+#include "usbstack/core.h"
+#include "arcotg_udc.h"
+
+/*-------------------------------------------------------------------------*/
+
+#define ep_is_in(EP)    (((EP)->desc->bEndpointAddress & USB_DIR_IN)==USB_DIR_IN)
+
+#define EP_DIR_IN	1
+#define EP_DIR_OUT	0
+
+/*-------------------------------------------------------------------------*/
+
+/* pipe direction macro from device view */
+#define USB_RECV    (0) /* OUT EP */
+#define USB_SEND    (1) /* IN EP */
+
+/* Shared Bit Masks for Endpoint Queue Head and Endpoint Transfer Descriptor */
+#define  TERMINATE                              (1 << 0)
+#define  STATUS_ACTIVE                          (1 << 7)
+#define  STATUS_HALTED                          (1 << 6)
+#define  STATUS_DATA_BUFF_ERR                   (1 << 5)
+#define  STATUS_TRANSACTION_ERR                 (1 << 4)
+#define  INTERRUPT_ON_COMPLETE                  (1 << 15)
+#define  LENGTH_BIT_POS                         (16)
+#define  ADDRESS_MASK                           (0xFFFFFFE0)
+#define  ERROR_MASK                             (DTD_STATUS_HALTED | \
+                                                DTD_STATUS_DATA_BUFF_ERR | \
+                                                DTD_STATUS_TRANSACTION_ERR)
+
+#define  RESERVED_FIELDS                        ((1 << 0) | (1 << 2) | (1 << 4) | \
+                                                (1 << 8) | (1 << 9) | (1 << 12)| \
+                                                (1 << 13)| (1 << 14)| (1 << 31))
+
+/* Endpoint Queue Head Bit Masks */
+#define  EP_QUEUE_HEAD_MULT_POS               (30)
+#define  EP_QUEUE_HEAD_ZLT_SEL                (0x20000000)
+#define  EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info)   (((ep_info)>>16)&0x07ff)
+#define  EP_QUEUE_HEAD_MULTO                  (0x00000C00)
+#define  EP_QUEUE_CURRENT_OFFSET_MASK         (0x00000FFF)
+#define  EP_QUEUE_FRINDEX_MASK                (0x000007FF)
+#define  EP_MAX_LENGTH_TRANSFER               (0x4000)
+
+/*-------------------------------------------------------------------------*/
+
+/* ep name is important, it should obey the convention of ep_match() */
+/* even numbered EPs are OUT or setup, odd are IN/INTERRUPT */
+static const char* ep_name[] = {
+    "ep0-control", NULL, /* everyone has ep0 */
+     /* 7 configurable endpoints */
+    "ep1out",
+    "ep1in",
+    "ep2out",
+    "ep2in",
+    "ep3out",
+    "ep3in",
+    "ep4out",
+    "ep4in",
+    "ep5out",
+    "ep5in",
+    "ep6out",
+    "ep6in",
+    "ep7out",
+    "ep7in"
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Endpoint Transfer Descriptor data struct */
+struct dtd {
+    uint32_t next_dtd;       /* Next TD pointer(31-5), T(0) set indicate invalid */
+    uint32_t dtd_token;      /* Total bytes (30-16), IOC (15), MultO(11-10), STS (7-0)  */
+    uint32_t buf_ptr0;       /* Buffer pointer Page 0 */
+    uint32_t buf_ptr1;       /* Buffer pointer Page 1 */
+    uint32_t buf_ptr2;       /* Buffer pointer Page 2 */
+    uint32_t buf_ptr3;       /* Buffer pointer Page 3 */
+    uint32_t buf_ptr4;       /* Buffer pointer Page 4 */
+    uint32_t res;            /* make it an even 8 words */
+} __attribute((packed));
+
+/* Endpoint Queue Head*/
+struct dqh {
+    uint32_t endpt_cap;          /* Mult(31-30) , Zlt(29) , Max Pkt len
+                                  * and IOS(15) */
+    uint32_t cur_dtd;            /* Current dTD Pointer(31-5) */
+    struct dtd dtd_ovrl;         /* Transfer descriptor */
+    uint32_t setup_buffer[2];    /* Setup data 8 bytes */
+    uint32_t res2[4];            /* pad out to 64 bytes */
+} __attribute((packed));
+
+#define RESPONSE_SIZE 30
+
+/* our controller struct */
+struct arcotg_dcd {
+    struct usb_ctrlrequest local_setup_buff;
+    struct usb_ep endpoints[USB_MAX_PIPES];
+    struct usb_response response[RESPONSE_SIZE];
+    enum usb_device_state usb_state;
+    enum usb_device_state resume_state;
+    bool stopped;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* usb_controller functions */
+void usb_arcotg_dcd_init(void);
+void usb_arcotg_dcd_shutdown(void);
+void usb_arcotg_dcd_irq(void);
+void usb_arcotg_dcd_start(void);
+void usb_arcotg_dcd_stop(void);
+
+/* usb controller ops */
+int usb_arcotg_dcd_enable(struct usb_ep* ep);
+int usb_arcotg_dcd_disable(struct usb_ep* ep);
+int usb_arcotg_dcd_set_halt(struct usb_ep* ep, bool halt);
+int usb_arcotg_dcd_send(struct usb_ep* ep, struct usb_response* request);
+int usb_arcotg_dcd_receive(struct usb_ep* ep, struct usb_response* res);
+
+/* interrupt handlers */
+static void setup_received_int(struct usb_ctrlrequest* request);
+static void port_change_int(void);
+static void reset_int(void);
+static void suspend_int(void);
+static void resume_int(void);
+
+/* life cycle */
+static void qh_init(unsigned char ep_num, unsigned char dir, unsigned char ep_type,
+                    unsigned int max_pkt_len, unsigned int zlt, unsigned char mult);
+static void td_init(struct dtd* td, void* buffer, uint32_t todo);
+static void ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type);
+
+/* helpers for tx/rx */
+static int td_enqueue(struct dtd* td, struct dqh* qh, unsigned int mask);
+static int td_wait(struct dtd* td, unsigned int mask);
+static int usb_ack(struct usb_ctrlrequest * s, int error);
+
+#endif /*_ARCOTG_DCD_H_*/
diff --git a/firmware/export/arcotg_udc.h b/firmware/export/arcotg_udc.h
index e3bf93a..e016321 100644
--- a/firmware/export/arcotg_udc.h
+++ b/firmware/export/arcotg_udc.h
@@ -37,8 +37,6 @@
 
 #include "cpu.h"
 
-#define ETIMEDOUT               1
-
 #define USB_MAX_ENDPOINTS       8
 #define USB_MAX_PIPES           (USB_MAX_ENDPOINTS*2)
 #define USB_MAX_CTRL_PAYLOAD    64
@@ -99,7 +97,7 @@
 #define  USB_FRINDEX_MASKS                      (0x3fff)
 
 /* USB CMD  Register Bit Masks */
-#define  USB_CMD_RUN_STOP                       (0x00000001)
+#define  USB_CMD_RUN                            (0x00000001)
 #define  USB_CMD_CTRL_RESET                     (0x00000002)
 #define  USB_CMD_PERIODIC_SCHEDULE_EN           (0x00000010)
 #define  USB_CMD_ASYNC_SCHEDULE_EN              (0x00000020)
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h
index 5a23b27..453faf5 100644
--- a/firmware/export/config-e200.h
+++ b/firmware/export/config-e200.h
@@ -148,6 +148,8 @@
 #define FIRMWARE_OFFSET_FILE_DATA   0x8
 
 /* #define USB_IPODSTYLE */
+#define HAVE_USBSTACK
+#define USBSTACK_CAPS CONTROLLER_DEVICE
 
 /* USB On-the-go */
 #define CONFIG_USBOTG USBOTG_ARC
diff --git a/firmware/export/linkedlist.h b/firmware/export/linkedlist.h
new file mode 100644
index 0000000..299c2f2
--- /dev/null
+++ b/firmware/export/linkedlist.h
@@ -0,0 +1,710 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: adc.h 13174 2007-04-15 23:35:56Z amiconn $
+ *
+ * Copyright (C) by Linux Kernel Developers
+ *
+ * Original source can be found in linux kernel: <kernel>/include/list.h
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _LINKED_LIST_H_
+#define _LINKED_LIST_H_
+
+#include <stddef.h> /* used for offsetof */
+
+static inline void prefetch(const void *x) { (void)x; }
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+/* TODO move this macro? */
+/* more about this macro: http://www.kroah.com/log/linux/container_of.html */
+#define container_of(ptr, type, member) ({ \
+                const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+                (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+struct list_head {
+    struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+    struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+    list->next = list;
+    list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+                              struct list_head *prev,
+                              struct list_head *next)
+{
+    next->prev = new;
+    new->next = next;
+    new->prev = prev;
+    prev->next = new;
+}
+
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+    __list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+    __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+    next->prev = prev;
+    prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+    entry->next = LIST_POISON1;
+    entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+                                struct list_head *new)
+{
+    new->next = old->next;
+    new->next->prev = new;
+    new->prev = old->prev;
+    new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+                                     struct list_head *new)
+{
+    list_replace(old, new);
+    INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+    INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+    __list_del(list->prev, list->next);
+    list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+                                  struct list_head *head)
+{
+    __list_del(list->prev, list->next);
+    list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+                               const struct list_head *head)
+{
+    return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+    return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+                                 struct list_head *head)
+{
+    struct list_head *first = list->next;
+    struct list_head *last = list->prev;
+    struct list_head *at = head->next;
+
+    first->prev = head;
+    head->next = first;
+
+    last->next = at;
+    at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+    if (!list_empty(list)) {
+        __list_splice(list, head);
+    }
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+                                    struct list_head *head)
+{
+    if (!list_empty(list)) {
+        __list_splice(list, head);
+        INIT_LIST_HEAD(list);
+    }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:        the &struct list_head pointer.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+    container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos:        the &struct list_head to use as a loop cursor.
+ * @head:       the head for your list.
+ */
+#define list_for_each(pos, head) \
+    for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+        pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+    for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+    for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+        pos = pos->prev)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)                  \
+    for (pos = list_entry((head)->next, typeof(*pos), member);  \
+        prefetch(pos->member.next), &pos->member != (head);     \
+        pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)          \
+    for (pos = list_entry((head)->prev, typeof(*pos), member);  \
+        prefetch(pos->member.prev), &pos->member != (head);     \
+        pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos:        the type * to use as a start point
+ * @head:       the head of the list
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+    ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member)             \
+    for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
+        prefetch(pos->member.next), &pos->member != (head);         \
+        pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member)             \
+    for (; prefetch(pos->member.next), &pos->member != (head);  \
+        pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#endif /*_LINKED_LIST_H_*/
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: adc.h 13174 2007-04-15 23:35:56Z amiconn $
+ *
+ * Copyright (C) by Linux Kernel Developers
+ *
+ * Original source can be found in linux kernel: <kernel>/include/list.h
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _LINKED_LIST_H_
+#define _LINKED_LIST_H_
+
+#include <stddef.h> /* used for offsetof */
+
+static inline void prefetch(const void *x) { (void)x; }
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+/* TODO move this macro? */
+/* more about this macro: http://www.kroah.com/log/linux/container_of.html */
+#define container_of(ptr, type, member) ({ \
+                const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+                (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+struct list_head {
+    struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+    struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+    list->next = list;
+    list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+                              struct list_head *prev,
+                              struct list_head *next)
+{
+    next->prev = new;
+    new->next = next;
+    new->prev = prev;
+    prev->next = new;
+}
+
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+    __list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+    __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+    next->prev = prev;
+    prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+    entry->next = LIST_POISON1;
+    entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+                                struct list_head *new)
+{
+    new->next = old->next;
+    new->next->prev = new;
+    new->prev = old->prev;
+    new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+                                     struct list_head *new)
+{
+    list_replace(old, new);
+    INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+    INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+    __list_del(list->prev, list->next);
+    list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+                                  struct list_head *head)
+{
+    __list_del(list->prev, list->next);
+    list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+                               const struct list_head *head)
+{
+    return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+    return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+                                 struct list_head *head)
+{
+    struct list_head *first = list->next;
+    struct list_head *last = list->prev;
+    struct list_head *at = head->next;
+
+    first->prev = head;
+    head->next = first;
+
+    last->next = at;
+    at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+    if (!list_empty(list)) {
+        __list_splice(list, head);
+    }
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+                                    struct list_head *head)
+{
+    if (!list_empty(list)) {
+        __list_splice(list, head);
+        INIT_LIST_HEAD(list);
+    }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:        the &struct list_head pointer.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+    container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos:        the &struct list_head to use as a loop cursor.
+ * @head:       the head for your list.
+ */
+#define list_for_each(pos, head) \
+    for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+        pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+    for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+    for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+        pos = pos->prev)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)                  \
+    for (pos = list_entry((head)->next, typeof(*pos), member);  \
+        prefetch(pos->member.next), &pos->member != (head);     \
+        pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)          \
+    for (pos = list_entry((head)->prev, typeof(*pos), member);  \
+        prefetch(pos->member.prev), &pos->member != (head);     \
+        pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos:        the type * to use as a start point
+ * @head:       the head of the list
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+    ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member)             \
+    for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
+        prefetch(pos->member.next), &pos->member != (head);         \
+        pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member)             \
+    for (; prefetch(pos->member.next), &pos->member != (head);  \
+        pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#endif /*_LINKED_LIST_H_*/
diff --git a/firmware/export/usb_ch9.h b/firmware/export/usb_ch9.h
new file mode 100644
index 0000000..5784ff3
--- /dev/null
+++ b/firmware/export/usb_ch9.h
@@ -0,0 +1,762 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) by Linux Kernel Developers
+ *
+ * Based on code from the Linux Kernel
+ * available at http://www.kernel.org
+ * Original file: <kernel>/include/linux/usb/ch9.h
+ * 
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _CH9_H_
+#define _CH9_H_
+
+#include <inttypes.h>
+
+/*
+ * USB directions
+ *
+ * This bit flag is used in endpoint descriptors' bEndpointAddress field.
+ * It's also one of three fields in control requests bRequestType.
+ */
+#define USB_DIR_OUT         0        /* to device */
+#define USB_DIR_IN          0x80     /* to host */
+
+/*
+ * USB types, the second of three bRequestType fields
+ */
+#define USB_TYPE_MASK           (0x03 << 5)
+#define USB_TYPE_STANDARD       (0x00 << 5)
+#define USB_TYPE_CLASS          (0x01 << 5)
+#define USB_TYPE_VENDOR         (0x02 << 5)
+#define USB_TYPE_RESERVED       (0x03 << 5)
+
+/*
+ * USB recipients, the third of three bRequestType fields
+ */
+#define USB_RECIP_MASK          0x1f
+#define USB_RECIP_DEVICE        0x00
+#define USB_RECIP_INTERFACE     0x01
+#define USB_RECIP_ENDPOINT      0x02
+#define USB_RECIP_OTHER         0x03
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * struct usb_ctrlrequest - SETUP data for a USB device control request
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field (le16 byte order)
+ * @wIndex: matches the USB wIndex field (le16 byte order)
+ * @wLength: matches the USB wLength field (le16 byte order)
+ */
+struct usb_ctrlrequest {
+    uint8_t bRequestType;
+    uint8_t bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+} __attribute__ ((packed));
+
+/*
+ * Standard requests, for the bRequest field of a SETUP packet.
+ *
+ * These are qualified by the bRequestType field, so that for example
+ * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
+ * by a GET_STATUS request.
+ */
+#define USB_REQ_GET_STATUS          0x00
+#define USB_REQ_CLEAR_FEATURE       0x01
+#define USB_REQ_SET_FEATURE         0x03
+#define USB_REQ_SET_ADDRESS         0x05
+#define USB_REQ_GET_DESCRIPTOR      0x06
+#define USB_REQ_SET_DESCRIPTOR      0x07
+#define USB_REQ_GET_CONFIGURATION   0x08
+#define USB_REQ_SET_CONFIGURATION   0x09
+#define USB_REQ_GET_INTERFACE       0x0A
+#define USB_REQ_SET_INTERFACE       0x0B
+#define USB_REQ_SYNCH_FRAME         0x0C
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
+ * (rarely) accepted by SET_DESCRIPTOR.
+ *
+ * Note that all multi-byte values here are encoded in little endian
+ * byte order "on the wire".  But when exposed through Linux-USB APIs,
+ * they've been converted to cpu byte order.
+ */
+
+/*
+ * Descriptor types ... USB 2.0 spec table 9.5
+ */
+#define USB_DT_DEVICE                   0x01
+#define USB_DT_CONFIG                   0x02
+#define USB_DT_STRING                   0x03
+#define USB_DT_INTERFACE                0x04
+#define USB_DT_ENDPOINT                 0x05
+#define USB_DT_DEVICE_QUALIFIER		    0x06
+#define USB_DT_OTHER_SPEED_CONFIG	    0x07
+#define USB_DT_INTERFACE_POWER		    0x08
+/* these are from a minor usb 2.0 revision (ECN) */
+#define USB_DT_OTG                      0x09
+#define USB_DT_DEBUG                    0x0a
+#define USB_DT_INTERFACE_ASSOCIATION    0x0b
+/* these are from the Wireless USB spec */
+#define USB_DT_SECURITY                 0x0c
+#define USB_DT_KEY                      0x0d
+#define USB_DT_ENCRYPTION_TYPE          0x0e
+#define USB_DT_BOS                      0x0f
+#define USB_DT_DEVICE_CAPABILITY        0x10
+#define USB_DT_WIRELESS_ENDPOINT_COMP   0x11
+#define USB_DT_WIRE_ADAPTER             0x21
+#define USB_DT_RPIPE                    0x22
+
+/* Conventional codes for class-specific descriptors.  The convention is
+ * defined in the USB "Common Class" Spec (3.11).  Individual class specs
+ * are authoritative for their usage, not the "common class" writeup.
+ */
+#define USB_DT_CS_DEVICE        (USB_TYPE_CLASS | USB_DT_DEVICE)
+#define USB_DT_CS_CONFIG        (USB_TYPE_CLASS | USB_DT_CONFIG)
+#define USB_DT_CS_STRING        (USB_TYPE_CLASS | USB_DT_STRING)
+#define USB_DT_CS_INTERFACE     (USB_TYPE_CLASS | USB_DT_INTERFACE)
+#define USB_DT_CS_ENDPOINT      (USB_TYPE_CLASS | USB_DT_ENDPOINT)
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE: Device descriptor */
+struct usb_device_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+    uint16_t bcdUSB;
+    uint8_t  bDeviceClass;
+    uint8_t  bDeviceSubClass;
+    uint8_t  bDeviceProtocol;
+    uint8_t  bMaxPacketSize0;
+    uint16_t idVendor;
+    uint16_t idProduct;
+    uint16_t bcdDevice;
+    uint8_t  iManufacturer;
+    uint8_t  iProduct;
+    uint8_t  iSerialNumber;
+    uint8_t  bNumConfigurations;
+} __attribute__ ((packed));
+
+#define USB_DT_DEVICE_SIZE    18
+
+/*
+ * Device and/or Interface Class codes
+ * as found in bDeviceClass or bInterfaceClass
+ * and defined by www.usb.org documents
+ */
+#define USB_CLASS_PER_INTERFACE          0 /* for DeviceClass */
+#define USB_CLASS_AUDIO                  1
+#define USB_CLASS_COMM                   2
+#define USB_CLASS_HID                    3
+#define USB_CLASS_PHYSICAL               5
+#define USB_CLASS_STILL_IMAGE            6
+#define USB_CLASS_PRINTER                7
+#define USB_CLASS_MASS_STORAGE           8
+#define USB_CLASS_HUB                    9
+#define USB_CLASS_CDC_DATA               0x0a
+#define USB_CLASS_CSCID                  0x0b /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC            0x0d /* content security */
+#define USB_CLASS_VIDEO                  0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER    0xe0
+#define USB_CLASS_MISC                   0xef
+#define USB_CLASS_APP_SPEC               0xfe
+#define USB_CLASS_VENDOR_SPEC            0xff
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_CONFIG: Configuration descriptor information.
+ *
+ * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
+ * descriptor type is different.  Highspeed-capable devices can look
+ * different depending on what speed they're currently running.  Only
+ * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
+ * descriptors.
+ */
+struct usb_config_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+    uint16_t wTotalLength;
+    uint8_t  bNumInterfaces;
+    uint8_t  bConfigurationValue;
+    uint8_t  iConfiguration;
+    uint8_t  bmAttributes;
+    uint8_t  bMaxPower;
+} __attribute__ ((packed));
+
+#define USB_DT_CONFIG_SIZE    9
+
+/* from config descriptor bmAttributes */
+#define USB_CONFIG_ATT_ONE          (1 << 7) /* must be set */
+#define USB_CONFIG_ATT_SELFPOWER    (1 << 6) /* self powered */
+#define USB_CONFIG_ATT_WAKEUP       (1 << 5) /* can wakeup */
+#define USB_CONFIG_ATT_BATTERY      (1 << 4) /* battery powered */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_STRING: String descriptor */
+struct usb_string_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint16_t wData[1]; /* UTF-16LE encoded */
+} __attribute__ ((packed));
+
+/* note that "string" zero is special, it holds language codes that
+ * the device supports, not Unicode characters.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE: Interface descriptor */
+struct usb_interface_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint8_t  bInterfaceNumber;
+    uint8_t  bAlternateSetting;
+    uint8_t  bNumEndpoints;
+    uint8_t  bInterfaceClass;
+    uint8_t  bInterfaceSubClass;
+    uint8_t  bInterfaceProtocol;
+    uint8_t  iInterface;
+} __attribute__ ((packed));
+
+#define USB_DT_INTERFACE_SIZE    9
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENDPOINT: Endpoint descriptor */
+struct usb_endpoint_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint8_t  bEndpointAddress;
+    uint8_t  bmAttributes;
+    uint16_t wMaxPacketSize;
+    uint8_t  bInterval;
+
+	/* NOTE:  these two are _only_ in audio endpoints. */
+	/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
+    //uint8_t  bRefresh;
+    //uint8_t  bSynchAddress;
+} __attribute__ ((packed));
+
+#define USB_DT_ENDPOINT_SIZE        7
+#define USB_DT_ENDPOINT_AUDIO_SIZE  9	/* Audio extension */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
+struct usb_qualifier_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint16_t bcdUSB;
+    uint8_t  bDeviceClass;
+    uint8_t  bDeviceSubClass;
+    uint8_t  bDeviceProtocol;
+    uint8_t  bMaxPacketSize0;
+    uint8_t  bNumConfigurations;
+    uint8_t  bRESERVED;
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_OTG (from OTG 1.0a supplement) */
+struct usb_otg_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint8_t  bmAttributes;	/* support for HNP, SRP, etc */
+} __attribute__ ((packed));
+
+/* from usb_otg_descriptor.bmAttributes */
+#define USB_OTG_SRP    (1 << 0)
+#define USB_OTG_HNP    (1 << 1) /* swap host/device roles */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
+struct usb_debug_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+	/* bulk endpoints with 8 byte maxpacket */
+    uint8_t  bDebugInEndpoint;
+    uint8_t  bDebugOutEndpoint;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_XFERTYPE_MASK  0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL   0
+#define USB_ENDPOINT_XFER_ISOC      1
+#define USB_ENDPOINT_XFER_BULK      2
+#define USB_ENDPOINT_XFER_INT       3
+
+enum usb_device_speed {
+	USB_SPEED_UNKNOWN = 0,          /* enumerating */
+	USB_SPEED_LOW, USB_SPEED_FULL,  /* usb 1.1 */
+	USB_SPEED_HIGH,                 /* usb 2.0 */
+	USB_SPEED_VARIABLE,             /* wireless (usb 2.5) */
+};
+
+enum usb_device_state {
+	/* NOTATTACHED isn't in the USB spec, and this state acts
+	 * the same as ATTACHED ... but it's clearer this way.
+	 */
+	USB_STATE_NOTATTACHED = 0,
+
+	/* chapter 9 and authentication (wireless) device states */
+	USB_STATE_ATTACHED,
+	USB_STATE_POWERED,			/* wired */
+	USB_STATE_UNAUTHENTICATED,		/* auth */
+	USB_STATE_RECONNECTING,			/* auth */
+	USB_STATE_DEFAULT,			/* limited function */
+	USB_STATE_ADDRESS,
+	USB_STATE_CONFIGURED,			/* most functions */
+
+	USB_STATE_SUSPENDED
+
+	/* NOTE:  there are actually four different SUSPENDED
+	 * states, returning to POWERED, DEFAULT, ADDRESS, or
+	 * CONFIGURED respectively when SOF tokens flow again.
+	 */
+};
+
+/* All standard descriptors have these 2 fields at the beginning */
+struct usb_descriptor_header {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+} __attribute__ ((packed));
+
+/**
+ * struct usb_string - wraps a C string and its USB id
+ * @id:the (nonzero) ID for this string
+ * @s:the string, in UTF-8 encoding
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap a string
+ * together with its ID.
+ */
+struct usb_string {
+    uint8_t id;
+    const char* s;
+};
+
+/**
+ * struct usb_gadget_strings - a set of USB strings in a given language
+ * @language:identifies the strings' language (0x0409 for en-us)
+ * @strings:array of strings with their ids
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap all the
+ * strings for a given language.
+ */
+struct usb_gadget_strings {
+    uint16_t language;	/* 0x0409 for en-us */
+    struct usb_string* strings;
+};
+
+#endif /*_CH9_H_*/
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) by Linux Kernel Developers
+ *
+ * Based on code from the Linux Kernel
+ * available at http://www.kernel.org
+ * Original file: <kernel>/include/linux/usb/ch9.h
+ * 
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _CH9_H_
+#define _CH9_H_
+
+#include <inttypes.h>
+
+/*
+ * USB directions
+ *
+ * This bit flag is used in endpoint descriptors' bEndpointAddress field.
+ * It's also one of three fields in control requests bRequestType.
+ */
+#define USB_DIR_OUT         0        /* to device */
+#define USB_DIR_IN          0x80     /* to host */
+
+/*
+ * USB types, the second of three bRequestType fields
+ */
+#define USB_TYPE_MASK           (0x03 << 5)
+#define USB_TYPE_STANDARD       (0x00 << 5)
+#define USB_TYPE_CLASS          (0x01 << 5)
+#define USB_TYPE_VENDOR         (0x02 << 5)
+#define USB_TYPE_RESERVED       (0x03 << 5)
+
+/*
+ * USB recipients, the third of three bRequestType fields
+ */
+#define USB_RECIP_MASK          0x1f
+#define USB_RECIP_DEVICE        0x00
+#define USB_RECIP_INTERFACE     0x01
+#define USB_RECIP_ENDPOINT      0x02
+#define USB_RECIP_OTHER         0x03
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * struct usb_ctrlrequest - SETUP data for a USB device control request
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field (le16 byte order)
+ * @wIndex: matches the USB wIndex field (le16 byte order)
+ * @wLength: matches the USB wLength field (le16 byte order)
+ */
+struct usb_ctrlrequest {
+    uint8_t bRequestType;
+    uint8_t bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+} __attribute__ ((packed));
+
+/*
+ * Standard requests, for the bRequest field of a SETUP packet.
+ *
+ * These are qualified by the bRequestType field, so that for example
+ * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
+ * by a GET_STATUS request.
+ */
+#define USB_REQ_GET_STATUS          0x00
+#define USB_REQ_CLEAR_FEATURE       0x01
+#define USB_REQ_SET_FEATURE         0x03
+#define USB_REQ_SET_ADDRESS         0x05
+#define USB_REQ_GET_DESCRIPTOR      0x06
+#define USB_REQ_SET_DESCRIPTOR      0x07
+#define USB_REQ_GET_CONFIGURATION   0x08
+#define USB_REQ_SET_CONFIGURATION   0x09
+#define USB_REQ_GET_INTERFACE       0x0A
+#define USB_REQ_SET_INTERFACE       0x0B
+#define USB_REQ_SYNCH_FRAME         0x0C
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
+ * (rarely) accepted by SET_DESCRIPTOR.
+ *
+ * Note that all multi-byte values here are encoded in little endian
+ * byte order "on the wire".  But when exposed through Linux-USB APIs,
+ * they've been converted to cpu byte order.
+ */
+
+/*
+ * Descriptor types ... USB 2.0 spec table 9.5
+ */
+#define USB_DT_DEVICE                   0x01
+#define USB_DT_CONFIG                   0x02
+#define USB_DT_STRING                   0x03
+#define USB_DT_INTERFACE                0x04
+#define USB_DT_ENDPOINT                 0x05
+#define USB_DT_DEVICE_QUALIFIER		    0x06
+#define USB_DT_OTHER_SPEED_CONFIG	    0x07
+#define USB_DT_INTERFACE_POWER		    0x08
+/* these are from a minor usb 2.0 revision (ECN) */
+#define USB_DT_OTG                      0x09
+#define USB_DT_DEBUG                    0x0a
+#define USB_DT_INTERFACE_ASSOCIATION    0x0b
+/* these are from the Wireless USB spec */
+#define USB_DT_SECURITY                 0x0c
+#define USB_DT_KEY                      0x0d
+#define USB_DT_ENCRYPTION_TYPE          0x0e
+#define USB_DT_BOS                      0x0f
+#define USB_DT_DEVICE_CAPABILITY        0x10
+#define USB_DT_WIRELESS_ENDPOINT_COMP   0x11
+#define USB_DT_WIRE_ADAPTER             0x21
+#define USB_DT_RPIPE                    0x22
+
+/* Conventional codes for class-specific descriptors.  The convention is
+ * defined in the USB "Common Class" Spec (3.11).  Individual class specs
+ * are authoritative for their usage, not the "common class" writeup.
+ */
+#define USB_DT_CS_DEVICE        (USB_TYPE_CLASS | USB_DT_DEVICE)
+#define USB_DT_CS_CONFIG        (USB_TYPE_CLASS | USB_DT_CONFIG)
+#define USB_DT_CS_STRING        (USB_TYPE_CLASS | USB_DT_STRING)
+#define USB_DT_CS_INTERFACE     (USB_TYPE_CLASS | USB_DT_INTERFACE)
+#define USB_DT_CS_ENDPOINT      (USB_TYPE_CLASS | USB_DT_ENDPOINT)
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE: Device descriptor */
+struct usb_device_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+    uint16_t bcdUSB;
+    uint8_t  bDeviceClass;
+    uint8_t  bDeviceSubClass;
+    uint8_t  bDeviceProtocol;
+    uint8_t  bMaxPacketSize0;
+    uint16_t idVendor;
+    uint16_t idProduct;
+    uint16_t bcdDevice;
+    uint8_t  iManufacturer;
+    uint8_t  iProduct;
+    uint8_t  iSerialNumber;
+    uint8_t  bNumConfigurations;
+} __attribute__ ((packed));
+
+#define USB_DT_DEVICE_SIZE    18
+
+/*
+ * Device and/or Interface Class codes
+ * as found in bDeviceClass or bInterfaceClass
+ * and defined by www.usb.org documents
+ */
+#define USB_CLASS_PER_INTERFACE          0 /* for DeviceClass */
+#define USB_CLASS_AUDIO                  1
+#define USB_CLASS_COMM                   2
+#define USB_CLASS_HID                    3
+#define USB_CLASS_PHYSICAL               5
+#define USB_CLASS_STILL_IMAGE            6
+#define USB_CLASS_PRINTER                7
+#define USB_CLASS_MASS_STORAGE           8
+#define USB_CLASS_HUB                    9
+#define USB_CLASS_CDC_DATA               0x0a
+#define USB_CLASS_CSCID                  0x0b /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC            0x0d /* content security */
+#define USB_CLASS_VIDEO                  0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER    0xe0
+#define USB_CLASS_MISC                   0xef
+#define USB_CLASS_APP_SPEC               0xfe
+#define USB_CLASS_VENDOR_SPEC            0xff
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_CONFIG: Configuration descriptor information.
+ *
+ * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
+ * descriptor type is different.  Highspeed-capable devices can look
+ * different depending on what speed they're currently running.  Only
+ * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
+ * descriptors.
+ */
+struct usb_config_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+    uint16_t wTotalLength;
+    uint8_t  bNumInterfaces;
+    uint8_t  bConfigurationValue;
+    uint8_t  iConfiguration;
+    uint8_t  bmAttributes;
+    uint8_t  bMaxPower;
+} __attribute__ ((packed));
+
+#define USB_DT_CONFIG_SIZE    9
+
+/* from config descriptor bmAttributes */
+#define USB_CONFIG_ATT_ONE          (1 << 7) /* must be set */
+#define USB_CONFIG_ATT_SELFPOWER    (1 << 6) /* self powered */
+#define USB_CONFIG_ATT_WAKEUP       (1 << 5) /* can wakeup */
+#define USB_CONFIG_ATT_BATTERY      (1 << 4) /* battery powered */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_STRING: String descriptor */
+struct usb_string_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint16_t wData[1]; /* UTF-16LE encoded */
+} __attribute__ ((packed));
+
+/* note that "string" zero is special, it holds language codes that
+ * the device supports, not Unicode characters.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE: Interface descriptor */
+struct usb_interface_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint8_t  bInterfaceNumber;
+    uint8_t  bAlternateSetting;
+    uint8_t  bNumEndpoints;
+    uint8_t  bInterfaceClass;
+    uint8_t  bInterfaceSubClass;
+    uint8_t  bInterfaceProtocol;
+    uint8_t  iInterface;
+} __attribute__ ((packed));
+
+#define USB_DT_INTERFACE_SIZE    9
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENDPOINT: Endpoint descriptor */
+struct usb_endpoint_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint8_t  bEndpointAddress;
+    uint8_t  bmAttributes;
+    uint16_t wMaxPacketSize;
+    uint8_t  bInterval;
+
+	/* NOTE:  these two are _only_ in audio endpoints. */
+	/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
+    //uint8_t  bRefresh;
+    //uint8_t  bSynchAddress;
+} __attribute__ ((packed));
+
+#define USB_DT_ENDPOINT_SIZE        7
+#define USB_DT_ENDPOINT_AUDIO_SIZE  9	/* Audio extension */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
+struct usb_qualifier_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint16_t bcdUSB;
+    uint8_t  bDeviceClass;
+    uint8_t  bDeviceSubClass;
+    uint8_t  bDeviceProtocol;
+    uint8_t  bMaxPacketSize0;
+    uint8_t  bNumConfigurations;
+    uint8_t  bRESERVED;
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_OTG (from OTG 1.0a supplement) */
+struct usb_otg_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+    uint8_t  bmAttributes;	/* support for HNP, SRP, etc */
+} __attribute__ ((packed));
+
+/* from usb_otg_descriptor.bmAttributes */
+#define USB_OTG_SRP    (1 << 0)
+#define USB_OTG_HNP    (1 << 1) /* swap host/device roles */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
+struct usb_debug_descriptor {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+
+	/* bulk endpoints with 8 byte maxpacket */
+    uint8_t  bDebugInEndpoint;
+    uint8_t  bDebugOutEndpoint;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_XFERTYPE_MASK  0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL   0
+#define USB_ENDPOINT_XFER_ISOC      1
+#define USB_ENDPOINT_XFER_BULK      2
+#define USB_ENDPOINT_XFER_INT       3
+
+enum usb_device_speed {
+	USB_SPEED_UNKNOWN = 0,          /* enumerating */
+	USB_SPEED_LOW, USB_SPEED_FULL,  /* usb 1.1 */
+	USB_SPEED_HIGH,                 /* usb 2.0 */
+	USB_SPEED_VARIABLE,             /* wireless (usb 2.5) */
+};
+
+enum usb_device_state {
+	/* NOTATTACHED isn't in the USB spec, and this state acts
+	 * the same as ATTACHED ... but it's clearer this way.
+	 */
+	USB_STATE_NOTATTACHED = 0,
+
+	/* chapter 9 and authentication (wireless) device states */
+	USB_STATE_ATTACHED,
+	USB_STATE_POWERED,			/* wired */
+	USB_STATE_UNAUTHENTICATED,		/* auth */
+	USB_STATE_RECONNECTING,			/* auth */
+	USB_STATE_DEFAULT,			/* limited function */
+	USB_STATE_ADDRESS,
+	USB_STATE_CONFIGURED,			/* most functions */
+
+	USB_STATE_SUSPENDED
+
+	/* NOTE:  there are actually four different SUSPENDED
+	 * states, returning to POWERED, DEFAULT, ADDRESS, or
+	 * CONFIGURED respectively when SOF tokens flow again.
+	 */
+};
+
+/* All standard descriptors have these 2 fields at the beginning */
+struct usb_descriptor_header {
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+} __attribute__ ((packed));
+
+/**
+ * struct usb_string - wraps a C string and its USB id
+ * @id:the (nonzero) ID for this string
+ * @s:the string, in UTF-8 encoding
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap a string
+ * together with its ID.
+ */
+struct usb_string {
+    uint8_t id;
+    const char* s;
+};
+
+/**
+ * struct usb_gadget_strings - a set of USB strings in a given language
+ * @language:identifies the strings' language (0x0409 for en-us)
+ * @strings:array of strings with their ids
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap all the
+ * strings for a given language.
+ */
+struct usb_gadget_strings {
+    uint16_t language;	/* 0x0409 for en-us */
+    struct usb_string* strings;
+};
+
+#endif /*_CH9_H_*/
diff --git a/firmware/export/usbstack.h b/firmware/export/usbstack.h
new file mode 100644
index 0000000..9142b1b
--- /dev/null
+++ b/firmware/export/usbstack.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _USBSTACK_H_
+#define _USBSTACK_H_
+
+#include <errno.h>
+
+#define USB_STACK_MAX_SETTINGS_NAME	32*10		/* should be enough for > 10 driver names */
+
+/*
+ * error codes
+ */
+#define ENOFREESLOT             1
+#define EWRONGCONTROLLERTYPE    2
+#define ENODRIVERFOUND          3
+#define EHWCRITICAL				4
+
+enum usb_controller_type {
+    DEVICE = 0,
+    HOST,
+};
+
+/*
+ * stack routines
+ */
+void usb_stack_init(void);
+void usb_stack_start(void);
+void usb_stack_stop(void);
+
+void usb_controller_select(int type);
+int usb_stack_get_mode(void);
+int usb_device_driver_bind(const char* name);
+void ubs_device_driver_unbind(void);
+
+/* used by apps settings code */
+unsigned char device_driver_names[USB_STACK_MAX_SETTINGS_NAME];
+
+#endif /*_USBSTACK_H_*/
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c
index 98ee78b..a282564 100644
--- a/firmware/target/arm/system-pp502x.c
+++ b/firmware/target/arm/system-pp502x.c
@@ -35,13 +35,20 @@
 extern void microsd_int(void);
 #endif
 
+#ifdef HAVE_USBSTACK
+#include "usbstack/core.h"
+#endif
+
 void irq(void)
 {
     if(CURRENT_CORE == CPU)
     {
-        if (CPU_INT_STAT & TIMER1_MASK)
+        if (CPU_INT_STAT & TIMER1_MASK) {
             TIMER1();
-        else if (CPU_INT_STAT & TIMER2_MASK)
+#ifdef HAVE_USBSTACK
+            usb_stack_irq();
+#endif
+        } else if (CPU_INT_STAT & TIMER2_MASK)
             TIMER2();
 #if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */
         else if (CPU_HI_INT_STAT & GPIO_MASK)
diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c
index 92e3dee..f687782 100644
--- a/firmware/target/arm/usb-fw-pp502x.c
+++ b/firmware/target/arm/usb-fw-pp502x.c
@@ -22,71 +22,16 @@
  *
  ****************************************************************************/
 #include "config.h"
-#include "cpu.h"
-#include "kernel.h"
-#include "thread.h"
 #include "system.h"
-#include "debug.h"
-#include "ata.h"
-#include "fat.h"
-#include "disk.h"
-#include "panic.h"
-#include "lcd.h"
-#include "adc.h"
 #include "usb.h"
-#include "button.h"
-#include "sprintf.h"
-#include "string.h"
-#include "hwcompat.h"
-
-#include "usb-target.h"
 #include "arcotg_udc.h"
 
+#ifdef HAVE_USBSTACK
+#include "usbstack.h"
+#endif
+
 void usb_init_device(void)
 {
-    int r0;
-    outl(inl(0x70000084) | 0x200, 0x70000084);
-
-    outl(inl(0x7000002C) | 0x3000000, 0x7000002C);
-    DEV_EN |= DEV_USB;
-
-    DEV_RS |= DEV_USB; /* reset usb start */
-    DEV_RS &=~DEV_USB;/* reset usb end */
-
-    DEV_INIT |= INIT_USB;
-    while ((inl(0x70000028) & 0x80) == 0);
-
-    UDC_PORTSC1 |= PORTSCX_PORT_RESET;
-    while ((UDC_PORTSC1 & PORTSCX_PORT_RESET) != 0);
-
-    UDC_OTGSC |= 0x5F000000;
-    if( (UDC_OTGSC & 0x100) == 0) {
-        UDC_USBMODE &=~ USB_MODE_CTRL_MODE_HOST;
-        UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE;
-        outl(inl(0x70000028) | 0x4000, 0x70000028);
-        outl(inl(0x70000028) | 0x2, 0x70000028);
-    } else {
-        UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE;
-        outl(inl(0x70000028) &~0x4000, 0x70000028);
-        outl(inl(0x70000028) | 0x2, 0x70000028);
-    }
-    
-    
-    UDC_USBCMD |= USB_CMD_CTRL_RESET;
-    while((UDC_USBCMD & USB_CMD_CTRL_RESET) != 0);
-    
-    r0 = UDC_PORTSC1;
-
-    /* Note from IPL source (referring to next 5 lines of code: 
-       THIS NEEDS TO BE CHANGED ONCE THERE IS KERNEL USB */
-    DEV_INIT |= INIT_USB;
-    DEV_EN |= DEV_USB;
-    while ((inl(0x70000028) & 0x80) == 0);
-    outl(inl(0x70000028) | 0x2, 0x70000028);
-
-    udelay(0x186A0);
-
-    dr_controller_setup();
 
 #if defined(IPOD_COLOR) || defined(IPOD_4G) \
  || defined(IPOD_MINI)  || defined(IPOD_MINI2G)
@@ -98,6 +43,7 @@
 
 void usb_enable(bool on)
 {
+#ifndef HAVE_USBSTACK
     /* This device specific code will eventually give way to proper USB
        handling, which should be the same for all PP502x targets. */
     if (on)
@@ -125,6 +71,7 @@
         }
 #endif
     }
+#endif
 }
 
 bool usb_detect(void)
@@ -151,12 +98,13 @@
     }
 
     usbstatus1 = (UDC_OTGSC & 0x800) ? true : false;
+#ifdef HAVE_USBSTACK
     if ((usbstatus1 == true) && (prev_usbstatus1 == false)) {
-        dr_controller_run();
+        usb_stack_start();
     } else if ((usbstatus1 == false) && (prev_usbstatus1 == true)) {
-        dr_controller_stop();
+    	usb_stack_stop();
     }
-
+#endif
     prev_usbstatus1 = usbstatus1;
     usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false;
 
diff --git a/firmware/usbstack/config.h b/firmware/usbstack/config.h
new file mode 100644
index 0000000..95b00da
--- /dev/null
+++ b/firmware/usbstack/config.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _USBSTACK_CONFIG_H_
+#define _USBSTACK_CONFIG_H_
+
+/* default: use no controller */
+#ifndef USBSTACK_CAPS
+#define USBSTACK_CAPS 0
+#endif
+
+#define CONTROLLER_DEVICE	 (1 << 0)
+#define CONTROLLER_HOST      (1 << 1)
+
+#endif /*_USBSTACK_CONFIG_H_*/
diff --git a/firmware/usbstack/controller.h b/firmware/usbstack/controller.h
new file mode 100644
index 0000000..8e99cf6
--- /dev/null
+++ b/firmware/usbstack/controller.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _USBSTACK_CONTROLLER_H_
+#define _USBSTACK_CONTROLLER_H_
+
+struct usb_controller {
+    const char* name;
+    enum usb_controller_type type;
+    enum usb_device_speed speed;
+    void (*init)(void);
+    void (*shutdown)(void);
+    void (*irq)(void);
+    void (*start)(void);
+    void (*stop)(void);
+    void* controller_ops;
+    struct usb_device_driver* device_driver;
+    struct usb_host_driver* host_driver;
+    struct usb_ep* ep0;
+    struct usb_ep endpoints;
+};
+
+struct usb_dcd_controller_ops {
+    /* endpoint management */
+    int (*enable)(struct usb_ep* ep);
+    int (*disable)(struct usb_ep* ep);
+    int (*set_halt)(struct usb_ep* ep, bool hald);
+    
+    /* transmitting */
+    int (*send)(struct usb_ep* ep, struct usb_response* req);
+    int (*receive)(struct usb_ep* ep, struct usb_response* res);
+    
+    /* ep0 */
+    struct usb_ep* ep0;
+};
+
+int usb_controller_register(struct usb_controller* ctrl);
+int usb_controller_unregister(struct usb_controller* ctrl);
+
+/*
+ * dcd - device controller driver
+ */
+void usb_dcd_init(void);
+void usb_dcd_shutdown(void);
+
+/*
+ * hcd - host controller driver
+ */
+void usb_hcd_init(void);
+void usb_hcd_shutdown(void);
+
+#endif /*_USBSTACK_CONTROLLER_H_*/
diff --git a/firmware/usbstack/core.h b/firmware/usbstack/core.h
new file mode 100644
index 0000000..7bda293
--- /dev/null
+++ b/firmware/usbstack/core.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _USBSTACK_CORE_H_
+#define _USBSTACK_CORE_H_
+
+#include "linkedlist.h"
+#include "usb_ch9.h"
+#include "logf.h"
+#include "system.h"
+
+#include "usbstack.h"
+
+/*
+ * stack datatypes
+ */
+struct usb_response {
+    void* buf;
+    uint32_t length;
+};
+
+struct usb_ep {
+    const char name[15];
+    uint8_t type;
+    uint32_t ep_num;	/* which endpoint? */
+    uint32_t pipe_num;  /* which pipe? */
+    uint32_t maxpacket;
+    bool claimed;
+
+    struct usb_endpoint_descriptor *desc;
+    struct list_head list;
+};
+
+#include "usbstack/controller.h"
+#include "usbstack/device.h"
+#include "usbstack/host.h"
+
+#define NUM_DRIVERS 3
+
+/*
+ * usb core
+ */
+struct usb_core {
+    /* we can have maximum two controllers (one device, one host) */
+    struct usb_controller* controller[2];
+    struct usb_controller* active_controller;
+    /* device driver used by stack */
+    struct usb_device_driver* device_driver;
+    /* for each type of driver use own array */
+    struct usb_host_driver* host_drivers[NUM_DRIVERS];
+    struct usb_device_driver* device_drivers[NUM_DRIVERS];
+    enum usb_controller_type mode;
+    bool running;
+};
+
+void usb_stack_irq(void);
+void usb_stack_work(void);
+
+/* endpoint configuration */
+void usb_ep_autoconfig_reset(void);
+struct usb_ep* usb_ep_autoconfig(struct usb_endpoint_descriptor* desc);
+
+/* only used for debug */
+void into_usb_ctrlrequest(struct usb_ctrlrequest* request);
+
+extern struct usb_core usbcore;
+
+#endif /*_USBSTACK_CORE_H_*/
diff --git a/firmware/usbstack/core/config.c b/firmware/usbstack/core/config.c
new file mode 100644
index 0000000..a05a508
--- /dev/null
+++ b/firmware/usbstack/core/config.c
@@ -0,0 +1,80 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * Based on linux/drivers/usb/gadget/config.c
+ *   Copyright (C) 2003 David Brownell
+ * 
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <string.h>
+#include "usbstack/core.h"
+
+static int usb_descriptor_fillbuf(void* buf, unsigned buflen, struct usb_descriptor_header** src) {
+	
+	uint8_t* dest = buf;
+
+	if (!src) {
+		return -EINVAL;
+	}
+
+	/* fill buffer from src[] until null descriptor ptr */
+	for (; 0 != *src; src++) {
+		unsigned len = (*src)->bLength;
+
+		logf("len: %d", len);
+		
+		if (len > buflen)
+			return -EINVAL;
+		memcpy(dest, *src, len);
+		buflen -= len;
+		dest += len;
+	}
+	return dest - (uint8_t *)buf;
+}
+
+int usb_stack_configdesc(const struct usb_config_descriptor* config, void* buf, unsigned length, struct usb_descriptor_header** desc) {
+	
+    struct usb_config_descriptor* cp = buf;
+	int len;
+
+	if (length < USB_DT_CONFIG_SIZE || !desc) {
+		return -EINVAL;
+	}
+	
+	/* config descriptor first */
+	*cp = *config; 
+
+	/* then interface/endpoint/class/vendor/... */
+	len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (uint8_t*)buf, length - USB_DT_CONFIG_SIZE, desc);
+	
+	if (len < 0) {
+		return len;
+	}
+	
+	len += USB_DT_CONFIG_SIZE;
+	if (len > 0xffff) {
+		return -EINVAL;
+	}
+
+	/* patch up the config descriptor */
+	cp->bLength = USB_DT_CONFIG_SIZE;
+	cp->bDescriptorType = USB_DT_CONFIG;
+	cp->wTotalLength = len;
+	cp->bmAttributes |= USB_CONFIG_ATT_ONE;
+	
+	return len;
+}
diff --git a/firmware/usbstack/core/core.c b/firmware/usbstack/core/core.c
new file mode 100644
index 0000000..61b7f83
--- /dev/null
+++ b/firmware/usbstack/core/core.c
@@ -0,0 +1,392 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include "usbstack.h"
+
+#include "config.h"
+
+#include "usbstack/core.h"
+#include "usbstack/config.h"
+#include "usbstack/controller.h"
+#include "usbstack/drivers/device/usb_serial.h"
+#include "usbstack/drivers/device/usb_storage.h"
+
+struct usb_core usbcore;
+
+/* private used functions */
+static void update_driver_names(unsigned char* result);
+static void bind_device_driver(struct usb_device_driver* driver);
+
+/**
+ * Initialize usb stack.
+ */
+void usb_stack_init(void) {
+
+    int i;	
+	logf("usb_stack_init");
+	
+    /* init datastructures */
+    usbcore.controller[0] = NULL;
+    usbcore.controller[1] = NULL;
+    usbcore.active_controller = NULL;
+    usbcore.device_driver = NULL;
+    usbcore.running = false;
+    
+    memset(&device_driver_names, 0, USB_STACK_MAX_SETTINGS_NAME);
+    
+    /* init arrays */
+    for (i = 0; i < NUM_DRIVERS; i++) {
+    	usbcore.device_drivers[i] = NULL;
+    	usbcore.host_drivers[i] = NULL;
+    }
+    
+    /* init controllers */
+#if (USBSTACK_CAPS & CONTROLLER_DEVICE)
+    usb_dcd_init();
+#endif
+
+#if (USBSTACK_CAPS & CONTROLLER_HOST)
+    usb_hcd_init();
+#endif
+
+    /* init drivers */
+    usb_serial_driver_init();
+    usb_storage_driver_init();
+}
+
+/**
+ * Start processing of usb stack. This function init
+ * active usb controller.
+ */
+void usb_stack_start(void) {
+
+	/* are we allready running? */
+	if (usbcore.running) {
+		logf("allready running!");
+		return;
+	}
+	
+	if (usbcore.active_controller == NULL) {
+		logf("no active controller!");
+		return;
+	}
+	
+    /* forward to controller */
+	logf("starting controller");
+    usbcore.active_controller->start();
+    usbcore.running = true;
+    
+    /* look if started controller is a device controller
+     * and if it has a device driver bind to it */
+    logf("check for auto bind");
+    if (usbcore.active_controller->type == DEVICE) {
+        if (usbcore.active_controller->device_driver == NULL && usbcore.device_driver != NULL) {
+            /* bind driver */
+        	logf("binding...");
+            bind_device_driver(usbcore.device_driver);
+        }
+    }
+}
+
+/**
+ * Stop processing of usb stack. This function shutsdown
+ * active usb controller.
+ */
+void usb_stack_stop(void) {
+
+	/* are we allready stopped? */
+	if (usbcore.running == false) {
+		return;
+	}
+	
+    /* forward to controller */
+    usbcore.active_controller->stop();    
+    usbcore.running = false;
+}
+
+/**
+ * Gets called by upper layers to indicate that there is
+ * an interrupt waiting for the controller.
+ */
+void usb_stack_irq(void) {
+
+    /* simply notify usb controller */
+    if (usbcore.active_controller != NULL && usbcore.active_controller->irq != NULL) {
+        usbcore.active_controller->irq();
+    }
+}
+
+/**
+ * If a host device controller is loaded, we need to have a function
+ * to call for maintanence. We need to check if a new device has connected,
+ * find suitable drivers for new devices.
+ */
+void usb_stack_work(void) {
+    /* TODO will be used with host device controllers 
+     * and needs to be called in a loop (thread) */
+}
+
+/**
+ * Register an usb controller in the stack. The stack can
+ * only have two controllers registered at one time.
+ * One device host controller and one host device controller.
+ * 
+ * @param ctrl pointer to controller to register.
+ * @return 0 on success else a defined error code. 
+ */
+int usb_controller_register(struct usb_controller* ctrl) {
+
+    if (ctrl == NULL) {
+        return EINVAL;
+    }
+
+    logf("usb_stack: register usb ctrl");
+    logf("  -> name: %s", ctrl->name);
+    logf("  -> type: %d", ctrl->type);
+
+    switch (ctrl->type) {
+    case DEVICE:
+        if (usbcore.controller[0] == NULL) {
+            usbcore.controller[0] = ctrl;
+            return 0;
+        }
+        break;
+    case HOST:
+        if (usbcore.controller[1] == NULL) {
+            usbcore.controller[1] = ctrl;
+            return 0;
+        }
+        break;
+    default:
+        return EINVAL;
+    }
+
+    return ENOFREESLOT;
+}
+
+/**
+ * Unregister an usb controller from the stack.
+ * 
+ * @param ctrl pointer to controller to unregister.
+ * @return 0 on success else a defined error code. 
+ */
+int usb_controller_unregister(struct usb_controller* ctrl) {
+
+    if (ctrl == NULL) {
+        return EINVAL;
+    }
+
+    switch (ctrl->type) {
+    case DEVICE:
+        if (usbcore.controller[0] == ctrl) {
+            usbcore.controller[0] = NULL;
+            return 0;
+        }
+        break;
+    case HOST:
+        if (usbcore.controller[1] == ctrl) {
+            usbcore.controller[1] = NULL;
+            return 0;
+        }
+        break;
+    default:
+        return EINVAL;
+    }
+
+    return 0; /* never reached */
+}
+
+/**
+ * Select an usb controller and active it.
+ * 
+ * @param type of controller to activate.
+ */
+void usb_controller_select(int type) {
+	
+    struct usb_controller* new = NULL;
+
+    /* check if a controller of the wanted type is already loaded */
+    if (usbcore.active_controller != NULL && (int)usbcore.active_controller->type == type) {
+    	logf("controller already set");
+    	return;
+    }
+
+	logf("usb_controller_select");
+	logf("  -> type: %d", type);    
+
+	usbcore.mode = type;
+	
+    switch (type) {
+    case DEVICE:
+        new = usbcore.controller[0];
+        break;
+    case HOST:
+        new = usbcore.controller[1];
+        break;
+    }
+
+    /* if there is only one controller, stop here */
+    if (new == NULL) {
+    	logf("no suitable cntrl found");
+        return;
+    }
+
+    /* shutdown current used controller */
+    if (usbcore.active_controller != NULL) {
+    	logf("shuting down old one");
+        usbcore.active_controller->shutdown();
+    }
+
+    /* set and init new controller */
+    usbcore.active_controller = new;
+    logf("init controller");
+    usbcore.active_controller->init();   
+}
+
+int usb_stack_get_mode(void) {
+    return usbcore.mode;
+}
+
+/**
+ * Register an usb device driver.
+ * 
+ * @param driver pointer to an usb_device_driver struct.
+ * @return 0 on success, else a defined error code.
+ */
+int usb_device_driver_register(struct usb_device_driver* driver) {
+
+    int i;
+    
+    if (driver == NULL) {
+        return EINVAL;
+    }
+
+    /* add to linked list */
+    logf("usb_stack: register usb driver");
+    for (i = 0; i < NUM_DRIVERS; i++) {
+        if (usbcore.device_drivers[i] == NULL) {
+        	usbcore.device_drivers[i] = driver;
+        	update_driver_names(device_driver_names);
+        	return 0;
+        }
+    }
+
+    update_driver_names(device_driver_names);
+    
+    return 0;
+}
+
+int usb_device_driver_bind(const char* name) {
+
+	int i;
+	struct usb_device_driver *tmp = NULL;
+	struct usb_device_driver *driver = NULL;
+	
+    if (name == NULL) {
+        return EINVAL;
+    }
+	
+    /* look for driver */
+    logf("looking for driver %s", name);
+    for (i = 0; i < NUM_DRIVERS; i++) {
+    	tmp = usbcore.device_drivers[i];
+    	if (tmp != NULL && strcmp(name, tmp->name) == 0) {
+    		driver = tmp;
+    	}
+    }
+ 
+    if (driver == NULL) {
+ 	    logf("no driver found");
+ 	    return ENODRIVERFOUND;
+    } 
+    
+	/* look if there is an usb controller loaded */
+    if (usbcore.active_controller == NULL) {
+    	/* safe choosen driver and set it when controller starts */
+    	usbcore.device_driver = driver;
+        
+    } else {
+    
+        /* we need to have an active dcd controller */
+        if (usbcore.active_controller->type != DEVICE) {
+    	    logf("wrong type");
+            return EWRONGCONTROLLERTYPE;
+        }
+    
+        /* bind driver to controller */
+        bind_device_driver(driver);
+    }
+    
+    return 0;
+}
+
+void usb_device_driver_unbind(void) {
+
+	logf("usb_device_driver_unbind");
+	if (usbcore.active_controller->device_driver != NULL) {
+		usbcore.active_controller->device_driver->unbind();
+		usbcore.active_controller->device_driver = NULL;
+	}
+	
+	usbcore.device_driver = NULL;
+}
+
+static void update_driver_names(unsigned char* result) {
+
+	int i;
+    int pos = 0;
+	unsigned char terminator = ',';
+    struct usb_device_driver* dd = NULL;
+    
+    /* reset buffer, iterate through drivers and add to char array */
+    memset(result, 0, USB_STACK_MAX_SETTINGS_NAME);
+    for (i = 0; i < NUM_DRIVERS; i++) {
+    	int len;
+        dd = usbcore.device_drivers[i];
+        
+        if (dd !=  NULL) {
+        	len = strlen(dd->name);
+        	if (pos > 0) {
+        		memcpy(result + pos, &terminator, 1);
+        		pos++;
+        	}
+        	memcpy(result + pos, dd->name, len);
+        	pos += len;
+        }
+    }
+}
+
+static void bind_device_driver(struct usb_device_driver* driver) {
+	
+    /* look if there is an old driver */
+    if (usbcore.active_controller->device_driver != NULL) {
+        usbcore.active_controller->device_driver->unbind();
+    }
+	
+    /* bind driver to controller */
+    usbcore.active_controller->device_driver = driver;
+    
+    /* init dirver */
+    driver->bind(usbcore.active_controller->controller_ops);    
+}
+
+
diff --git a/firmware/usbstack/core/epsetup.c b/firmware/usbstack/core/epsetup.c
new file mode 100644
index 0000000..6ae54fb
--- /dev/null
+++ b/firmware/usbstack/core/epsetup.c
@@ -0,0 +1,186 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <string.h>
+#include <ctype.h>
+#include "usbstack/core.h"
+
+/**
+ * 
+ * Naming Convention for Endpoint Names
+ * 
+ *	- ep1, ep2, ... address is fixed, not direction or type
+ *	- ep1in, ep2out, ... address and direction are fixed, not type
+ *	- ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
+ *	- ep1in-bulk, ep2out-iso, ... all three are fixed
+ *	- ep-* ... no functionality restrictions
+ *
+ * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
+ *
+ */
+static int ep_matches(struct usb_ep* ep, struct usb_endpoint_descriptor* desc);
+
+void usb_ep_autoconfig_reset(void) {
+
+    struct usb_ep* ep = NULL;
+    if (usbcore.active_controller == NULL) {
+        return;
+    }
+	
+    logf("resetting endpoints");
+    list_for_each_entry(ep, &usbcore.active_controller->endpoints.list, list) {
+    	logf("reset %s", ep->name);
+        ep->claimed = false;
+    }
+}
+
+/**
+ * Find a suitable endpoint for the requested endpoint descriptor.
+ * @param desc usb descritpro to use for seraching.
+ * @return NULL or a valid endpoint.
+ */
+struct usb_ep* usb_ep_autoconfig(struct usb_endpoint_descriptor* desc) {
+
+	struct usb_ep* ep = NULL;
+    if (usbcore.active_controller == NULL) {
+    	logf("active controller NULL");
+        return NULL;
+    }
+        
+    list_for_each_entry(ep, &usbcore.active_controller->endpoints.list, list) {
+        if (ep_matches (ep, desc)) {
+            return ep;
+        }
+    }
+    
+    return NULL;
+}
+
+static int ep_matches(struct usb_ep* ep, struct usb_endpoint_descriptor* desc) {
+	
+    uint8_t     type;
+	const char* tmp;
+	uint16_t    max;
+
+	/* endpoint already claimed? */
+	if (ep->claimed) {
+		logf("!! claimed !!");
+        return 0;
+    }
+
+    /* only support ep0 for portable CONTROL traffic */
+    type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+    if (type == USB_ENDPOINT_XFER_CONTROL) {
+    	logf("type == control");
+        return 0;
+    }
+
+    /* some other naming convention */
+    if (ep->name[0] != 'e') {
+    	logf("wrong name");
+        return 0;
+    }
+    
+    /* type-restriction:  "-iso", "-bulk", or "-int".
+     * direction-restriction:  "in", "out".
+     */
+    if (ep->name[2] != '-' ) {
+        tmp = strrchr (ep->name, '-');
+        if (tmp) {
+            switch (type) {
+            case USB_ENDPOINT_XFER_INT:
+                /* bulk endpoints handle interrupt transfers,
+                 * except the toggle-quirky iso-synch kind
+                 */
+                if (tmp[2] == 's') { // == "-iso"
+                    return 0;
+                }
+				break;
+	        case USB_ENDPOINT_XFER_BULK:
+	            if (tmp[1] != 'b') { // != "-bulk"
+	                return 0;
+	            }
+	            break;
+	        case USB_ENDPOINT_XFER_ISOC:
+	            if (tmp[2] != 's') { // != "-iso"
+	                return 0;
+	            }
+	        }
+        } else {
+            tmp = ep->name + strlen (ep->name);
+	    }
+
+        /* direction-restriction:  "..in-..", "out-.." */
+        tmp--;
+        if (!isdigit(*tmp)) {
+            if (desc->bEndpointAddress & USB_DIR_IN) {
+                if ('n' != *tmp) {
+                    return 0;
+			    }
+            } else {
+                if ('t' != *tmp) {
+                    return 0;
+                }
+            }
+        }
+    }
+
+
+    /* endpoint maxpacket size is an input parameter, except for bulk
+     * where it's an output parameter representing the full speed limit.
+     * the usb spec fixes high speed bulk maxpacket at 512 bytes.
+     */
+    max = 0x7ff & desc->wMaxPacketSize;
+    
+    switch (type) {
+    case USB_ENDPOINT_XFER_INT:
+        /* INT:  limit 64 bytes full speed, 1024 high speed */
+    	if ((usbcore.active_controller->speed != USB_SPEED_HIGH) && (max > 64)) {
+            return 0;
+        }
+		/* FALLTHROUGH */
+
+	case USB_ENDPOINT_XFER_ISOC:
+        if ((usbcore.active_controller->speed != USB_SPEED_HIGH) && (max > 1023)) {
+            return 0;
+        }
+		break;
+	}
+
+	/* MATCH!! */
+
+	/* report address */
+    desc->bEndpointAddress |= ep->ep_num;
+
+    /* report (variable) full speed bulk maxpacket */
+    if (type == USB_ENDPOINT_XFER_BULK) {
+    	int size = max;
+
+        /* min() doesn't work on bitfields with gcc-3.5 */
+        if (size > 64) {
+            size = 64;
+	    }
+        desc->wMaxPacketSize = size;
+    }
+
+    /* save desc in endpoint */
+    ep->desc = desc;
+    
+    return 1;
+}
diff --git a/firmware/usbstack/core/utils.c b/firmware/usbstack/core/utils.c
new file mode 100644
index 0000000..2fb2695
--- /dev/null
+++ b/firmware/usbstack/core/utils.c
@@ -0,0 +1,125 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <string.h>
+#include "usbstack/core.h"
+
+void into_usb_ctrlrequest(struct usb_ctrlrequest* request) {
+
+	char* type = "";
+	char* req = "";
+	char* extra = 0;
+	
+	logf("-usb request-");
+    /* check if packet is okay */
+	if (request->bRequestType == 0 &&
+        request->bRequest == 0 &&
+        request->wValue == 0 &&
+        request->wIndex == 0 &&
+        request->wLength == 0) {
+        logf(" -> INVALID <-");
+        return;
+	}	
+	
+    switch (request->bRequestType & USB_TYPE_MASK) {
+	case USB_TYPE_STANDARD:
+		type = "standard";
+		
+        switch (request->bRequest) {
+        case USB_REQ_GET_STATUS:
+        	req  = "get status";
+            break;
+        case USB_REQ_CLEAR_FEATURE:
+        	req = "clear feature";
+            break;
+        case USB_REQ_SET_FEATURE:
+        	req = "set feature";
+            break;
+        case USB_REQ_SET_ADDRESS:
+        	req = "set address";
+            break;
+        case USB_REQ_GET_DESCRIPTOR:
+        	req = "get descriptor";
+        	
+    		switch (request->wValue >> 8) {
+    		case USB_DT_DEVICE:
+    			extra = "get device descriptor";
+    			break;
+    		case USB_DT_DEVICE_QUALIFIER:
+    			extra = "get device qualifier";
+    			break;
+    		case USB_DT_OTHER_SPEED_CONFIG:
+    			extra = "get other-speed config descriptor";
+    		case USB_DT_CONFIG:
+    			extra = "get configuration descriptor";
+    			break;
+    		case USB_DT_STRING:
+    			extra = "get string descriptor";
+    			break;
+    		case USB_DT_DEBUG:
+    			extra = "debug";
+    			break;
+    		}
+    		break;        	
+        	
+            break;
+        case USB_REQ_SET_DESCRIPTOR:
+        	req = "set descriptor";
+            break;
+        case USB_REQ_GET_CONFIGURATION:
+        	req = "get configuration";
+            break;
+        case USB_REQ_SET_CONFIGURATION:
+        	req = "set configuration";
+            break;
+        case USB_REQ_GET_INTERFACE:
+        	req = "get interface";
+            break;
+        case USB_REQ_SET_INTERFACE:
+        	req = "set interface";
+            break;
+        case USB_REQ_SYNCH_FRAME:
+        	req = "sync frame";
+            break;
+        default:
+        	req = "unkown";
+        	break;
+        }
+
+        break;
+    case USB_TYPE_CLASS:
+    	type = "class";
+        break;
+
+    case USB_TYPE_VENDOR:
+    	type = "vendor";
+        break;
+    }
+        
+    logf(" -b 0x%x", request->bRequestType);
+    logf(" -b 0x%x", request->bRequest);
+    logf(" -b 0x%x", request->wValue);
+    logf(" -b 0x%x", request->wIndex);
+    logf(" -b 0x%x", request->wLength);
+    logf(" -> t: %s", type);
+    logf(" -> r: %s", req);
+    if (extra != 0) {
+    	logf(" -> e: %s", extra);
+    }
+}
diff --git a/firmware/usbstack/device.h b/firmware/usbstack/device.h
new file mode 100644
index 0000000..5b385d8
--- /dev/null
+++ b/firmware/usbstack/device.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _USBSTACK_DEVICE_H_
+#define _USBSTACK_DEVICE_H_
+
+/*
+ * usb device driver
+ */
+struct usb_device_driver {
+    const char* name;
+    void (*bind)(void* controller_ops);
+    void (*unbind)(void);
+    int (*request)(struct usb_ctrlrequest* req);
+    void (*suspend)(void);
+    void (*resume)(void);
+    void (*speed)(enum usb_device_speed speed);
+    struct usb_descriptors* descriptors;
+    void* data; /* used to store controller specific ops struct */
+};
+
+int usb_device_driver_register(struct usb_device_driver* driver);
+
+/* forward declaration */
+struct usb_config_descriptor;
+struct usb_descriptor_header;
+
+int usb_stack_configdesc(const struct usb_config_descriptor* config,
+						void* buf, unsigned length,
+						struct usb_descriptor_header** desc);
+
+#endif /*_USBSTACK_DEVICE_H_*/
diff --git a/firmware/usbstack/drivers/device/usb_serial.c b/firmware/usbstack/drivers/device/usb_serial.c
new file mode 100644
index 0000000..fe1e52f
--- /dev/null
+++ b/firmware/usbstack/drivers/device/usb_serial.c
@@ -0,0 +1,300 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "usb_serial.h"
+#include <string.h>
+
+static struct usb_dcd_controller_ops* ops;
+
+struct usb_device_driver usb_serial_driver = {
+    .name =         "serial",
+    .bind =         usb_serial_driver_bind,
+    .unbind =       NULL,
+    .request =      usb_serial_driver_request,
+    .suspend =      NULL,
+    .resume =       NULL,
+    .speed =        usb_serial_driver_speed,
+};
+
+/*-------------------------------------------------------------------------*/
+/* usb descriptors */
+
+/* TODO: implement strings */
+#define GS_MANUFACTURER_STR_ID  0
+#define GS_PRODUCT_STR_ID       0
+#define GS_SERIAL_STR_ID        0
+#define GS_BULK_CONFIG_STR_ID   0
+#define GS_DATA_STR_ID          0
+
+#define GS_BULK_CONFIG_ID       1
+
+static struct usb_device_descriptor serial_device_desc = {
+    .bLength =              USB_DT_DEVICE_SIZE,
+    .bDescriptorType =      USB_DT_DEVICE,
+    .bcdUSB =               0x0200,
+    .bDeviceClass =         USB_CLASS_COMM,
+    .bDeviceSubClass =      0,
+    .bDeviceProtocol =      0,
+    .idVendor =             0x0525,
+    .idProduct =            0xa4a6,
+    .iManufacturer =        GS_MANUFACTURER_STR_ID,
+    .iProduct =             GS_PRODUCT_STR_ID,
+    .iSerialNumber =        GS_SERIAL_STR_ID,
+    .bNumConfigurations =   1,
+};
+
+static struct usb_config_descriptor serial_bulk_config_desc = {
+    .bLength =              USB_DT_CONFIG_SIZE,
+    .bDescriptorType =      USB_DT_CONFIG,
+
+    .bNumInterfaces =       1,
+    .bConfigurationValue =  GS_BULK_CONFIG_ID,
+    .iConfiguration =       GS_BULK_CONFIG_STR_ID,
+    .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+    .bMaxPower =            1,
+};
+
+static struct usb_interface_descriptor serial_bulk_interface_desc = {
+    .bLength =              USB_DT_INTERFACE_SIZE,
+    .bDescriptorType =      USB_DT_INTERFACE,
+    .bInterfaceNumber =     0,
+    .bNumEndpoints =        2,
+    .bInterfaceClass =      USB_CLASS_CDC_DATA,
+    .bInterfaceSubClass =   0,
+    .bInterfaceProtocol =   0,
+    .iInterface =           GS_DATA_STR_ID,
+};
+
+static struct usb_endpoint_descriptor serial_fullspeed_in_desc = {
+    .bLength =              USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType =      USB_DT_ENDPOINT,
+    .bEndpointAddress =     USB_DIR_IN,
+    .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize =       8,
+};
+
+static struct usb_endpoint_descriptor serial_fullspeed_out_desc = {
+    .bLength =              USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType =      USB_DT_ENDPOINT,
+    .bEndpointAddress =     USB_DIR_OUT,
+    .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize =       8,
+};
+
+static struct usb_debug_descriptor serial_debug_desc = {
+    .bLength =              sizeof(struct usb_debug_descriptor),
+    .bDescriptorType =      USB_DT_DEBUG,
+};
+
+static struct usb_qualifier_descriptor serial_qualifier_desc = {
+    .bLength =             sizeof(struct usb_qualifier_descriptor),
+    .bDescriptorType =     USB_DT_DEVICE_QUALIFIER,
+    .bcdUSB =              0x0200,
+    .bDeviceClass =        USB_CLASS_COMM,
+    .bNumConfigurations =  1,
+};
+
+struct usb_descriptor_header *serial_bulk_fullspeed_function[] = {
+    (struct usb_descriptor_header *) &serial_bulk_interface_desc,
+    (struct usb_descriptor_header *) &serial_fullspeed_in_desc,
+    (struct usb_descriptor_header *) &serial_fullspeed_out_desc,
+    NULL,
+};
+
+#define BUFFER_SIZE 100
+uint8_t buf[BUFFER_SIZE];
+
+struct usb_response res;
+
+/* helper functions */
+static int config_buf(uint8_t *buf, uint8_t type, unsigned index);
+static int set_config(int config);
+
+
+struct device {
+	struct usb_ep* in;
+	struct usb_ep* out;
+	uint32_t used_config;
+};
+
+static struct device dev;
+
+/*-------------------------------------------------------------------------*/
+
+void usb_serial_driver_init(void) {
+
+    logf("usb serial: register");
+    usb_device_driver_register(&usb_serial_driver);
+}
+
+/*-------------------------------------------------------------------------*/
+
+void usb_serial_driver_bind(void* controler_ops) {
+
+    logf("usb serial: bind");
+    ops = controler_ops;
+    
+    /* serach and asign endpoints */
+    usb_ep_autoconfig_reset();
+
+    dev.in = usb_ep_autoconfig(&serial_fullspeed_in_desc);
+	if (!dev.in) {
+		goto autoconf_fail;
+	}
+	dev.in->claimed = true;
+	logf("usb serial: in: %s", dev.in->name);
+	
+	dev.out = usb_ep_autoconfig(&serial_fullspeed_out_desc);
+	if (!dev.out) {
+		goto autoconf_fail;
+	}
+	dev.out->claimed = true;
+	logf("usb serial: out: %s", dev.out->name);
+
+	/* update device decsriptor */
+	serial_device_desc.bMaxPacketSize0 = ops->ep0->maxpacket;
+	
+	/* update qualifie descriptor */
+	serial_qualifier_desc.bMaxPacketSize0 = ops->ep0->maxpacket;
+	
+	/* update debug descriptor */
+	serial_debug_desc.bDebugInEndpoint = dev.in->ep_num;
+	serial_debug_desc.bDebugOutEndpoint = dev.out->ep_num;
+		
+	return;
+	
+autoconf_fail:
+	logf("failed to find endpoiunts");
+}
+
+int usb_serial_driver_request(struct usb_ctrlrequest* request) {
+
+    int ret = -EOPNOTSUPP;
+    logf("usb serial: request");
+
+    res.length = 0;
+    res.buf = NULL;
+    
+    switch (request->bRequestType & USB_TYPE_MASK) {
+    case USB_TYPE_STANDARD:
+
+        switch (request->bRequest) {
+        case USB_REQ_GET_DESCRIPTOR:
+
+            switch (request->wValue >> 8) {
+            case USB_DT_DEVICE:
+                logf("usb serial: sending device desc");
+                ret = MIN(sizeof(struct usb_device_descriptor), request->wLength);
+                res.buf = &serial_device_desc;
+                break;
+
+            case USB_DT_DEVICE_QUALIFIER:
+            	logf("usb serial: sending qualifier dec");
+                ret = MIN(sizeof(struct usb_qualifier_descriptor), request->wLength);
+                res.buf = &serial_qualifier_desc;            	
+                
+            case USB_DT_CONFIG:
+                logf("usb serial: sending config desc");
+                
+    			ret = config_buf(buf, request->wValue >> 8, request->wValue & 0xff);
+    			if (ret >= 0) {
+    				logf("%d, vs %d", request->wLength, ret);
+    				ret = MIN(request->wLength, (uint16_t)ret);
+    			}
+                res.buf = buf;
+                break;
+                
+            case USB_DT_DEBUG:
+            	logf("usb serial: sending debug desc");
+            	ret = MIN(sizeof(struct usb_debug_descriptor), request->wLength);
+            	res.buf = &serial_debug_desc;
+            	break;
+            }
+            break;
+
+        case USB_REQ_SET_CONFIGURATION:
+            logf("usb serial: set configuration %d", request->wValue);
+            ret = set_config(request->wValue);
+            break;
+            
+        case USB_REQ_GET_CONFIGURATION:
+        	logf("usb serial: get configuration");
+            ret = 1;
+            res.buf = &dev.used_config;
+            break;
+        }
+    }
+
+    if (ret >= 0) {
+        res.length = ret;
+        ret = ops->send(NULL, &res);
+    }
+    
+    return ret;
+}
+
+void usb_serial_driver_speed(enum usb_device_speed speed) {
+
+    switch (speed) {
+    case USB_SPEED_LOW:
+    case USB_SPEED_FULL:
+    	logf("usb serial: using fullspeed");
+    	break;
+    case USB_SPEED_HIGH:
+    	logf("usb serial: using highspeed");
+    	break;
+    default:
+    	logf("speed: hmm");
+    	break;
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+/* helper functions */
+
+static int config_buf(uint8_t *buf, uint8_t type, unsigned index) {
+    
+	int len;
+
+	/* TODO check index*/
+	
+	len = usb_stack_configdesc(&serial_bulk_config_desc, buf, BUFFER_SIZE, serial_bulk_fullspeed_function);
+	if (len < 0) {
+		return len;
+	}
+	((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+	return len;
+}
+
+static int set_config(int config) {
+
+	/* TODO check config*/
+    
+    /* enable endpoints */
+    logf("setup %s", dev.in->name);
+    ops->enable(dev.in);
+    logf("setup %s", dev.out->name);
+    ops->enable(dev.out);
+    
+	/* store config */
+	logf("using config %d", config);
+	dev.used_config = config;
+		
+    return 0;
+}
diff --git a/firmware/usbstack/drivers/device/usb_serial.h b/firmware/usbstack/drivers/device/usb_serial.h
new file mode 100644
index 0000000..808eaa1
--- /dev/null
+++ b/firmware/usbstack/drivers/device/usb_serial.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _SERIAL_H_
+#define _SERIAL_H_
+
+#include "usbstack/core.h"
+
+/* register serial driver in usb stack */
+void usb_serial_driver_init(void);
+
+void usb_serial_driver_bind(void* controller_ops);
+int usb_serial_driver_request(struct usb_ctrlrequest* req);
+void usb_serial_driver_speed(enum usb_device_speed speed);
+
+#endif /*_SERIAL_H_*/
diff --git a/firmware/usbstack/drivers/device/usb_storage.c b/firmware/usbstack/drivers/device/usb_storage.c
new file mode 100644
index 0000000..0cb1f10
--- /dev/null
+++ b/firmware/usbstack/drivers/device/usb_storage.c
@@ -0,0 +1,269 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "usb_storage.h"
+#include <string.h>
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_dcd_controller_ops* ops;
+
+struct usb_device_driver usb_storage_driver = {
+    .name =         "storage",
+    .bind =         usb_storage_driver_bind,
+    .unbind =       NULL,
+    .request =      usb_storage_driver_request,
+    .suspend =      NULL,
+    .resume =       NULL,
+    .speed =        NULL,
+};
+
+struct device {
+    struct usb_ep* in;
+    struct usb_ep* out;
+    struct usb_ep* intr;
+};
+
+static struct device dev;
+
+/*-------------------------------------------------------------------------*/
+
+#define PROTO_BULK 0x50    // Bulk only
+#define SUBCL_SCSI 0x06    // Transparent SCSI
+
+/* Bulk-only class specific requests */
+#define USB_BULK_RESET_REQUEST          0xff
+#define USB_BULK_GET_MAX_LUN_REQUEST    0xfe
+
+/*-------------------------------------------------------------------------*/
+/* usb descriptors */
+
+static struct usb_device_descriptor storage_device_desc = {
+    .bLength =              USB_DT_DEVICE_SIZE,
+    .bDescriptorType =      USB_DT_DEVICE,
+    .bcdUSB =               0x0200,
+    .bDeviceClass =         0,
+    .bDeviceSubClass =      0,
+    .bDeviceProtocol =      0,
+    .bMaxPacketSize0 =      64,
+    .idVendor =             0xffff,
+    .idProduct =            0x0001,
+    .iManufacturer =        0,
+    .iProduct =             0,
+    .iSerialNumber =        0,
+    .bNumConfigurations =   1,
+};
+
+static struct usb_config_descriptor storage_config_desc = {
+    .bLength =              USB_DT_CONFIG_SIZE,
+    .bDescriptorType =      USB_DT_CONFIG,
+
+    .bNumInterfaces =       1,
+    .bConfigurationValue =  1,
+    .iConfiguration =       0,
+    .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+    .bMaxPower =            1,
+};
+
+static struct usb_interface_descriptor storage_interface_desc = {
+    .bLength =              USB_DT_INTERFACE_SIZE,
+    .bDescriptorType =      USB_DT_INTERFACE,
+    .bInterfaceNumber =     0,
+    .bNumEndpoints =        3,
+    .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
+    .bInterfaceSubClass =   SUBCL_SCSI,
+    .bInterfaceProtocol =   PROTO_BULK,
+    .iInterface =           0,
+};
+
+/* endpoint I -> bulk in */
+static struct usb_endpoint_descriptor storage_bulk_in_desc = {
+    .bLength =              USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType =      USB_DT_ENDPOINT,
+    .bEndpointAddress =     USB_DIR_IN,
+    .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize =       512,
+};
+
+/* endpoint II -> bulk out */
+static struct usb_endpoint_descriptor storage_bulk_out_desc = {
+    .bLength =              USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType =      USB_DT_ENDPOINT,
+    .bEndpointAddress =     USB_DIR_OUT,
+    .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize =       512,
+};
+
+struct usb_descriptor_header *storage_fullspeed_function[] = {
+    (struct usb_descriptor_header *) &storage_interface_desc,
+    (struct usb_descriptor_header *) &storage_bulk_in_desc,
+    (struct usb_descriptor_header *) &storage_bulk_out_desc,
+    NULL,
+};
+
+#define BUFFER_SIZE 100
+uint8_t buf[BUFFER_SIZE];
+
+struct usb_response res;
+
+/* helper functions */
+static int config_buf(uint8_t *buf, uint8_t type, unsigned index);
+static int set_config(int config);
+
+/*-------------------------------------------------------------------------*/
+
+void usb_storage_driver_init(void) {
+
+    logf("usb storage: register");
+    usb_device_driver_register(&usb_storage_driver);
+}
+
+/*-------------------------------------------------------------------------*/
+/* device driver ops */
+
+void usb_storage_driver_bind(void* controler_ops) {
+
+    ops = controler_ops;
+    
+    /* serach and asign endpoints */
+    usb_ep_autoconfig_reset();
+    
+    dev.in = usb_ep_autoconfig(&storage_bulk_in_desc);
+	if (!dev.in) {
+		goto autoconf_fail;
+	}
+	dev.in->claimed = true;
+	logf("usb storage: in: %s", dev.in->name);
+	
+	dev.out = usb_ep_autoconfig(&storage_bulk_out_desc);
+	if (!dev.out) {
+		goto autoconf_fail;
+	}
+	dev.out->claimed = true;
+	logf("usb storage: out: %s", dev.out->name);
+	
+	return;
+	
+autoconf_fail:
+	logf("failed to find endpoints");
+}
+
+int usb_storage_driver_request(struct usb_ctrlrequest* request) {
+
+    int ret = -EOPNOTSUPP;
+    logf("usb storage: request");
+
+    res.length = 0;
+    res.buf = NULL;
+    
+    switch (request->bRequestType & USB_TYPE_MASK) {
+    case USB_TYPE_STANDARD:
+
+        switch (request->bRequest) {
+        case USB_REQ_GET_DESCRIPTOR:
+
+            switch (request->wValue >> 8) {
+            case USB_DT_DEVICE:
+                logf("usb storage: sending device desc");
+                ret = MIN(sizeof(struct usb_device_descriptor), request->wLength);
+                res.buf = &storage_device_desc;
+                break;
+
+            case USB_DT_CONFIG:
+                logf("usb storage: sending config desc");
+                
+    			ret = config_buf(buf, request->wValue >> 8, request->wValue & 0xff);
+    			if (ret >= 0) {
+    				logf("%d, vs %d", request->wLength, ret);
+    				ret = MIN(request->wLength, (uint16_t)ret);
+    			}
+                res.buf = buf;
+                break;
+            }
+            break;
+
+        case USB_REQ_SET_CONFIGURATION:
+            logf("usb storage: set configuration %d", request->wValue);
+            ret = set_config(request->wValue);
+            break;
+            
+        case USB_REQ_SET_INTERFACE:
+            logf("usb storage: set interface");
+            ret = 0;
+            break;
+        }
+        
+    case USB_TYPE_CLASS:
+    	
+    	switch (request->bRequest) {
+    	case USB_BULK_RESET_REQUEST:
+    		logf("usb storage: bulk reset");
+    		break;
+    		
+    	case USB_BULK_GET_MAX_LUN_REQUEST:
+    		logf("usb storage: get max lun");
+    		/* we support no LUNs (Logical Unit Number) */
+    		buf[0] = 0;
+    		ret = 1;
+    		break;
+    	}
+    	break;
+    }
+
+    if (ret >= 0) {
+        res.length = ret;
+        ret = ops->send(NULL, &res);
+    }
+    
+    return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+/* S/GET CONFIGURATION helpers */
+
+static int config_buf(uint8_t *buf, uint8_t type, unsigned index) {
+    
+	int len;
+
+	/* only one configuration */
+	if (index != 0) {
+		return -EINVAL;
+	}
+	
+	len = usb_stack_configdesc(&storage_config_desc, buf, BUFFER_SIZE, storage_fullspeed_function);
+	if (len < 0) {
+		return len;
+	}
+	((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+	return len;
+}
+
+static int set_config(int config) {
+
+    /* enable endpoints */
+    logf("setup %s", dev.in->name);
+    ops->enable(dev.in);
+    logf("setup %s", dev.out->name);
+    ops->enable(dev.out);
+    
+    /* setup buffers */
+    
+    return 0;
+}
+
diff --git a/firmware/usbstack/drivers/device/usb_storage.h b/firmware/usbstack/drivers/device/usb_storage.h
new file mode 100644
index 0000000..9494aa7
--- /dev/null
+++ b/firmware/usbstack/drivers/device/usb_storage.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _STORGAGE_H_
+#define _STORGAGE_H_
+
+#include "usbstack/core.h"
+
+/* register serial driver in usb stack */
+void usb_storage_driver_init(void);
+
+void usb_storage_driver_bind(void* controller_ops);
+int usb_storage_driver_request(struct usb_ctrlrequest* req);
+
+#endif /*_STORGAGE_H_*/
diff --git a/firmware/usbstack/host.h b/firmware/usbstack/host.h
new file mode 100644
index 0000000..cb2f550
--- /dev/null
+++ b/firmware/usbstack/host.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _USBSTACK_HOST_H_
+#define _USBSTACK_HOST_H_
+
+/*
+ * usb host driver
+ */
+struct usb_host_driver {
+    const char* name;
+    void* data;			/* used to store controller specific ops struct */
+};
+
+#endif /*_USBSTACK_HOST_H_*/