Index: apps/settings.c
===================================================================
--- apps/settings.c (revision 14379)
+++ apps/settings.c (working copy)
@@ -98,6 +98,10 @@
#include "lcd-remote.h"
#endif
+#ifdef USE_USBSTACK
+#include "usbstack.h"
+#endif
+
long lasttime = 0;
/** NVRAM stuff, if the target doesnt have NVRAM it is saved in ROCKBOX_DIR /nvram.bin **/
@@ -874,7 +878,16 @@
if (global_settings.colors_file)
read_color_theme_file();
#endif
-
+
+#ifdef USE_USBSTACK
+ usb_controller_select(global_settings.usb_stack_mode);
+ usb_device_driver_bind("serial");
+#if 0
+ if (global_settings.usb_device_driver != NULL) {
+ usb_device_driver_bind(global_settings.usb_device_driver);
+ }
+#endif
+#endif
}
Index: apps/lang/english.lang
===================================================================
--- apps/lang/english.lang (revision 14379)
+++ apps/lang/english.lang (working copy)
@@ -11037,3 +11037,87 @@
*: "Only when viewing all types"
+
+ id: LANG_USBSTACK
+ desc: in settings_menu
+ user:
+
+ *: "USB Stack"
+
+
+ *: "USB Stack"
+
+
+ *: "USB Stack"
+
+
+
+ id: LANG_USBSTACK_MODE
+ desc: in usbstack settings
+ user:
+
+ *: "USB Stack Mode"
+
+
+ *: "USB Stack Mode"
+
+
+ *: "USB Stack Mode"
+
+
+
+ id: LANG_USBSTACK_AUTOMATIC
+ desc: in usbstack settings
+ user:
+
+ *: "Automatic"
+
+
+ *: "Automatic"
+
+
+ *: "Automatic"
+
+
+
+ id: LANG_USBSTACK_DEVICE
+ desc: in usbstack settings
+ user:
+
+ *: "Device"
+
+
+ *: "Device"
+
+
+ *: "Device"
+
+
+
+ id: LANG_USBSTACK_HOST
+ desc: in usbstack settings
+ user:
+
+ *: "Host"
+
+
+ *: "Host"
+
+
+ *: "Host"
+
+
+
+ id: LANG_USBSTACK_DEVICE_DRIVER
+ desc: in usbstack settings
+ user:
+
+ *: "Device Driver"
+
+
+ *: "Device Driver"
+
+
+ *: "Device Driver"
+
+
Index: apps/settings.h
===================================================================
--- apps/settings.h (revision 14379)
+++ apps/settings.h (working copy)
@@ -745,6 +745,10 @@
int list_accel_start_delay; /* ms before we start increaseing step size */
int list_accel_wait; /* ms between increases */
#endif
+#ifdef USE_USBSTACK
+ int usb_stack_mode; /* automatic, device or host */
+ unsigned char usb_device_driver[MAX_FILENAME+1]; /* name of usb device driver to use */
+#endif
};
/** global variables **/
Index: apps/menus/settings_menu.c
===================================================================
--- apps/menus/settings_menu.c (revision 14379)
+++ apps/menus/settings_menu.c (working copy)
@@ -442,7 +442,19 @@
/* VOICE MENU */
/***********************************/
+#ifdef USE_USBSTACK
/***********************************/
+/* USB STACK MENU */
+MENUITEM_SETTING(usbstack_mode, &global_settings.usb_stack_mode, NULL);
+MENUITEM_SETTING(usb_device_driver, &global_settings.usb_device_driver, NULL);
+
+MAKE_MENU(usbstack_menu, ID2P(LANG_USBSTACK), 0, Icon_NOICON,
+ &usbstack_mode, &usb_device_driver);
+/* USB STACK MENU */
+/***********************************/
+#endif
+
+/***********************************/
/* SETTINGS MENU */
static int language_browse(void)
{
@@ -458,6 +470,11 @@
&tagcache_menu,
#endif
&display_menu, &system_menu,
- &bookmark_settings_menu, &browse_langs, &voice_settings_menu );
+ &bookmark_settings_menu, &browse_langs, &voice_settings_menu
+
+#ifdef USE_USBSTACK
+ , &usbstack_menu
+#endif
+ );
/* SETTINGS MENU */
/***********************************/
Index: apps/settings_list.c
===================================================================
--- apps/settings_list.c (revision 14379)
+++ apps/settings_list.c (working copy)
@@ -47,6 +47,9 @@
#include "radio.h"
#endif
+#ifdef USE_USBSTACK
+#include "usbstack.h"
+#endif
#define NVRAM(bytes) (bytes<
#include
#include "inttypes.h"
+#include "linkedlist.h"
typedef int (*_isfunc_type)(void);
@@ -85,6 +86,12 @@
#define F_CHOICE_SETTING 0x100
#define F_CHOICETALKS 0x200 /* uses .talks in the above struct for the talks */
/* and cfg_vals for the strings to display */
+
+struct linkedlist_setting {
+ struct list_head list;
+};
+#define F_LINKEDLIST_SETTING 0x120
+
/* these use the _isfunc_type type for the function */
/* typedef int (*_isfunc_type)(void); */
#define F_MIN_ISFUNC 0x100000 /* min(above) is function pointer to above type */
@@ -120,6 +127,7 @@
struct filename_setting *filename_setting; /* use F_FILENAME */
struct int_setting *int_setting; /* use F_INT_SETTING */
struct choice_setting *choice_setting; /* F_CHOICE_SETTING */
+ struct linkedlist_setting *linkedlist_setting; /* F_LINKEDLIST_SETTING */
};
};
Index: apps/main.c
===================================================================
--- apps/main.c (revision 14379)
+++ apps/main.c (working copy)
@@ -72,6 +72,10 @@
#include "scrobbler.h"
#include "icon.h"
+#if defined(USE_USBSTACK)
+#include "usbstack.h"
+#endif
+
#if (CONFIG_CODEC == SWCODEC)
#include "playback.h"
#include "pcmbuf.h"
@@ -373,8 +377,12 @@
#endif
adc_init();
-
+
+#if defined(USE_USBSTACK)
+ usb_stack_init();
+#endif
usb_init();
+
#if CONFIG_USBOTG == USBOTG_ISP1362
isp1362_init();
#elif CONFIG_USBOTG == USBOTG_M5636
Index: firmware/export/linkedlist.h
===================================================================
--- firmware/export/linkedlist.h (revision 0)
+++ firmware/export/linkedlist.h (revision 0)
@@ -0,0 +1,355 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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: /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 /* 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_*/
Index: firmware/export/config.h
===================================================================
--- firmware/export/config.h (revision 14379)
+++ firmware/export/config.h (working copy)
@@ -320,7 +320,7 @@
#define ICODE_ATTR __attribute__ ((section(".icode")))
#define ICONST_ATTR __attribute__ ((section(".irodata")))
#define IDATA_ATTR __attribute__ ((section(".idata")))
-#define IBSS_ATTR __attribute__ ((section(".ibss")))
+#define IBSS_ATTR
#define USE_IRAM
#if CONFIG_CPU != SH7034
#define IRAM_STEAL
Index: firmware/export/arcotg_udc.h
===================================================================
--- firmware/export/arcotg_udc.h (revision 14379)
+++ firmware/export/arcotg_udc.h (working copy)
@@ -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
@@ -66,6 +64,7 @@
#define UDC_FRINDEX (*(volatile unsigned int *)(USB_BASE+0x14c)) /* Frame Index Register */
#define UDC_DEVICEADDR (*(volatile unsigned int *)(USB_BASE+0x154)) /* Device Address */
#define UDC_ENDPOINTLISTADDR (*(volatile unsigned int *)(USB_BASE+0x158)) /* Endpoint List Address Register */
+#define UDC_ASYNCTTSTS (*(volatile unsigned int *)(USB_BASE+0x15c))
#define UDC_BURSTSIZE (*(volatile unsigned int *)(USB_BASE+0x160)) /* Master Interface Data Burst Size Register */
#define UDC_TXFILLTUNING (*(volatile unsigned int *)(USB_BASE+0x164)) /* Transmit FIFO Tuning Controls Register */
#define UDC_ULPIVIEW (*(volatile unsigned int *)(USB_BASE+0x170))
Index: firmware/export/usbstack.h
===================================================================
--- firmware/export/usbstack.h (revision 0)
+++ firmware/export/usbstack.h (revision 0)
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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
+
+#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 {
+ AUTOMATIC = 0, /* only used for autodetection, do not use in controllers */
+ DEVICE,
+ HOST,
+};
+
+/*
+ * stack routines
+ */
+void usb_stack_init(void);
+void usb_stack_shutdown(void);
+void usb_stack_start(void);
+void usb_stack_stop(void);
+void usb_stack_irq(void);
+void usb_stack_work(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_*/
Index: firmware/export/usb_ch9.h
===================================================================
--- firmware/export/usb_ch9.h (revision 0)
+++ firmware/export/usb_ch9.h (revision 0)
@@ -0,0 +1,218 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * Based on code from the Linux Kernel
+ * available at http://www.kernel.org
+ * Original file: /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
+
+/*
+ * 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)
+
+/**
+ * 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_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 */
+
+/*
+ * Endpoints
+ */
+#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.
+ */
+};
+
+#endif /*_CH9_H_*/
Index: firmware/export/config-e200.h
===================================================================
--- firmware/export/config-e200.h (revision 14379)
+++ firmware/export/config-e200.h (working copy)
@@ -151,6 +151,8 @@
/* USB On-the-go */
#define CONFIG_USBOTG USBOTG_ARC
+#define USE_USBSTACK
+#define USBSTACK_CAPS (CONTROLLER_DEVICE)
/* Virtual LED (icon) */
#define CONFIG_LED LED_VIRTUAL
Index: firmware/usbstack/host.h
===================================================================
--- firmware/usbstack/host.h (revision 0)
+++ firmware/usbstack/host.h (revision 0)
@@ -0,0 +1,32 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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 */
+ struct list_head list;
+};
+
+#endif /*_USBSTACK_HOST_H_*/
Index: firmware/usbstack/device.h
===================================================================
--- firmware/usbstack/device.h (revision 0)
+++ firmware/usbstack/device.h (revision 0)
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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* data; /* used to store controller specific ops struct */
+ struct list_head list;
+};
+
+int usb_device_driver_register(struct usb_device_driver* driver);
+int usb_device_driver_unregister(struct usb_device_driver* driver);
+
+#endif /*_USBSTACK_DEVICE_H_*/
Index: firmware/usbstack/core/utils.c
===================================================================
--- firmware/usbstack/core/utils.c (revision 0)
+++ firmware/usbstack/core/utils.c (revision 0)
@@ -0,0 +1,121 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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 "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;
+ }
+ 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);
+ }
+}
Index: firmware/usbstack/core/core.c
===================================================================
--- firmware/usbstack/core/core.c (revision 0)
+++ firmware/usbstack/core/core.c (revision 0)
@@ -0,0 +1,438 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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
+#include
+#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"
+
+static 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) {
+
+ 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 linked lists */
+ INIT_LIST_HEAD(&usbcore.device_drivers.list);
+ INIT_LIST_HEAD(&usbcore.host_drivers.list);
+
+ /* init controllers */
+#if (USBSTACK_CAPS & CONTROLLER_DEVICE)
+ usb_dcd_init();
+#endif
+
+#if (USBSTACK_CAPS & CONTROLLER_HOST)
+ usb_hcd_init();
+#endif
+
+
+ /* idea: all drivers should be something like rockbox plugins... rockbox usb drivers.
+ * the app code scans for usb drivers and register them automaticly in the stack.
+ * We only need one *.c file for a driver and we dont need any *.h files with one
+ * method in it: usb__driver_init(void);
+ */
+
+ /* init drivers */
+ usb_serial_driver_init();
+ usb_storage_driver_init();
+}
+
+/**
+ * Shutdown usb stack.
+ */
+void usb_stack_shutdown(void) {
+
+ struct list_head* pos;
+
+ /* free current used device driver */
+ if (usbcore.active_controller->device_driver != NULL) {
+
+ /* call unbind if supported */
+ if (usbcore.active_controller->device_driver->unbind != NULL) {
+ usbcore.active_controller->device_driver->unbind();
+ }
+ usbcore.active_controller->device_driver = NULL;
+ }
+
+ /* stop stack */
+ usb_stack_stop();
+
+ /* delete linked lists */
+ list_for_each(pos, &usbcore.device_drivers.list) {
+ list_del(pos);
+ }
+ list_for_each(pos, &usbcore.host_drivers.list) {
+ list_del(pos);
+ }
+
+ /* shutdown controllers */
+#if (USBSTACK_CAPS & CONTROLLER_DEVICE)
+ usb_dcd_shutdown();
+#endif
+
+#if (USBSTACK_CAPS & CONTROLLER_HOST)
+ usb_hcd_shutdown();
+#endif
+
+}
+
+/**
+ * Start processing of usb stack. This function init
+ * active usb controller.
+ */
+void usb_stack_start(void) {
+
+ /* are we allready running? */
+ if (usbcore.running) {
+ return;
+ }
+
+ if (usbcore.active_controller == NULL) {
+ return;
+ }
+
+ /* forward to 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 */
+ if (usbcore.active_controller->type == DEVICE) {
+ if (usbcore.active_controller->device_driver == NULL && usbcore.device_driver != NULL) {
+ /* bind driver */
+ 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 AUTOMATIC:
+ /* we want autodetection, so shutdown current controller */
+ if (usbcore.active_controller != NULL) {
+ usbcore.active_controller->shutdown();
+ usbcore.active_controller = NULL;
+ }
+ return;
+ break;
+ 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) {
+ usbcore.active_controller->shutdown();
+ }
+
+ /* set and init new controller */
+ usbcore.active_controller = new;
+ 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) {
+
+ if (driver == NULL) {
+ return EINVAL;
+ }
+
+ /* add to linked list */
+ logf("usb_stack: register usb driver");
+ list_add(&driver->list, &usbcore.device_drivers.list);
+ update_driver_names(device_driver_names);
+
+ return 0;
+}
+
+/**
+ * Unregister an usb device driver.
+ *
+ * @param driver to unregister
+ * @return 0 or defined error code.
+ */
+int usb_device_driver_unregister(struct usb_device_driver* driver) {
+
+ if (driver == NULL) {
+ return EINVAL;
+ }
+
+ /* delete from linked list */
+ list_del(&driver->list);
+ update_driver_names(device_driver_names);
+
+ return 0;
+}
+
+int usb_device_driver_bind(const char* name) {
+
+ struct list_head *pos = NULL;
+ 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);
+ list_for_each(pos, &usbcore.device_drivers.list) {
+ tmp = list_entry(pos, struct usb_device_driver, list);
+ if (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 pos = 0;
+ unsigned char terminator = ',';
+ struct usb_device_driver* dd = NULL;
+
+ /* reset buffer, iterate through linked lists and add to char array */
+ memset(result, 0, USB_STACK_MAX_SETTINGS_NAME);
+
+ list_for_each_entry(dd, &usbcore.device_drivers.list, list) {
+ int 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);
+}
Index: firmware/usbstack/controller.h
===================================================================
--- firmware/usbstack/controller.h (revision 0)
+++ firmware/usbstack/controller.h (revision 0)
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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;
+ int (*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_dcd_controller_ops {
+ /* endpoint management */
+ int (*enable)(struct usb_ep* ep, const struct usb_endpoint_descriptor *desc);
+ int (*disable)(struct usb_ep* ep);
+ int (*set_halt)(struct usb_ep* ep, bool hald);
+
+ /* request management*/
+ struct usb_request* (*alloc_request)(struct usb_ep* ep);
+ void (*free_request)(struct usb_ep* ep, struct usb_request* req);
+
+ /* transmitting */
+ int (*queue)(struct usb_ep* ep, struct usb_request* req);
+ int (*dequeue)(struct usb_ep* ep, struct usb_request* req);
+};
+
+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_*/
Index: firmware/usbstack/config.h
===================================================================
--- firmware/usbstack/config.h (revision 0)
+++ firmware/usbstack/config.h (revision 0)
@@ -0,0 +1,26 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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_CONFIG_H_
+#define _USBSTACK_CONFIG_H_
+
+#define CONTROLLER_DEVICE (1 << 0)
+#define CONTROLLER_HOST (1 << 1)
+
+#endif /*_USBSTACK_CONFIG_H_*/
Index: firmware/usbstack/drivers/device/usb_storage.h
===================================================================
--- firmware/usbstack/drivers/device/usb_storage.h (revision 0)
+++ firmware/usbstack/drivers/device/usb_storage.h (revision 0)
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * Based on code from the Linux Kernel
+ *
+ * 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 _USB_STORAGE_H_
+#define _USB_STORAGE_H_
+
+#include "usbstack/core.h"
+
+/* register storage driver in usb stack */
+void usb_storage_driver_init(void);
+
+/* functions used for usb_device_driver */
+void usb_storage_driver_bind(void* controller_ops);
+void usb_storage_driver_unbind(void);
+int usb_storage_driver_request(struct usb_ctrlrequest* req);
+
+#endif /*USB_STORAGE_H_*/
Index: firmware/usbstack/drivers/device/usb_serial.c
===================================================================
--- firmware/usbstack/drivers/device/usb_serial.c (revision 0)
+++ firmware/usbstack/drivers/device/usb_serial.c (revision 0)
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define GS_NUM_CONFIGS 1
+#define GS_NO_CONFIG_ID 0
+#define GS_BULK_CONFIG_ID 1
+#define GS_ACM_CONFIG_ID 2
+
+static struct usb_dcd_controller_ops* ops;
+static struct usb_request req;
+
+struct usb_device_driver usb_serial_driver = {
+ "serial",
+ usb_serial_driver_bind,
+ 0,
+ usb_serial_driver_request,
+ 0,
+ 0,
+ 0,
+ {0,0}
+};
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures.
+ */
+#define GS_VENDOR_ID 0x0525 /* NetChip */
+#define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */
+
+/* usb descriptors */
+
+#define GS_MANUFACTURER_STR_ID 1
+#define GS_PRODUCT_STR_ID 2
+#define GS_SERIAL_STR_ID 3
+#define GS_BULK_CONFIG_STR_ID 4
+#define GS_ACM_CONFIG_STR_ID 5
+#define GS_CONTROL_STR_ID 6
+#define GS_DATA_STR_ID 7
+
+static struct usb_device_descriptor gs_device_desc = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .idVendor = GS_VENDOR_ID,
+ .idProduct = GS_PRODUCT_ID,
+ .iManufacturer = GS_MANUFACTURER_STR_ID,
+ .iProduct = GS_PRODUCT_STR_ID,
+ .iSerialNumber = GS_SERIAL_STR_ID,
+ .bNumConfigurations = GS_NUM_CONFIGS,
+};
+
+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;
+}
+
+int usb_serial_driver_request(struct usb_ctrlrequest* request) {
+
+ int ret = -EOPNOTSUPP;
+ logf("usb serial: request");
+
+ if ((request->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ switch (request->bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+
+ switch (request->wValue >> 8) {
+ case USB_DT_DEVICE:
+ ret = MIN(request->wLength, (uint16_t)sizeof(struct usb_device_descriptor));
+ req.buf = &gs_device_desc;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (ret > 0) {
+ req.length = ret;
+ logf("queuing response");
+ ret = ops->queue(NULL,
+ &req);
+ }
+
+ return ret;
+}
Index: firmware/usbstack/drivers/device/usb_serial.h
===================================================================
--- firmware/usbstack/drivers/device/usb_serial.h (revision 0)
+++ firmware/usbstack/drivers/device/usb_serial.h (revision 0)
@@ -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 _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);
+
+#endif /*_SERIAL_H_*/
Index: firmware/usbstack/drivers/device/usb_storage.c
===================================================================
--- firmware/usbstack/drivers/device/usb_storage.c (revision 0)
+++ firmware/usbstack/drivers/device/usb_storage.c (revision 0)
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * Based on code from the Linux Kernel
+ *
+ * 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 "system.h"
+#include "thread.h"
+#include "usb.h"
+
+/*-------------------------------------------------------------------------*/
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures. */
+#define DRIVER_VENDOR_ID 0x0525 // NetChip
+#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget
+
+#define STRING_MANUFACTURER 1
+#define STRING_PRODUCT 2
+#define STRING_SERIAL 3
+#define STRING_CONFIG 4
+#define STRING_INTERFACE 5
+
+/* usb descriptors */
+static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = 0x0200,
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+
+ /* The next three values can be overridden by module parameters */
+ .idVendor = DRIVER_VENDOR_ID,
+ .idProduct = DRIVER_PRODUCT_ID,
+ .bcdDevice = 0xffff,
+
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .iSerialNumber = STRING_SERIAL,
+ .bNumConfigurations = 1,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* pointer to operations supported by device controller */
+static struct usb_dcd_controller_ops* ops;
+
+/* descripes our device driver */
+struct usb_device_driver usb_storage_driver = {
+ "storage",
+ usb_storage_driver_bind,
+ usb_storage_driver_unbind,
+ usb_storage_driver_request,
+ 0,
+ 0,
+ 0,
+ {0,0}
+};
+
+/*-------------------------------------------------------------------------*/
+
+#define USB_STORAGE 1
+
+static long storage_stack [(DEFAULT_STACK_SIZE)/sizeof(long)];
+static const char storage_thread_name[] = "usb storage";
+static struct mutex storage_mtx;
+static struct event_queue storage_queue;
+struct thread_entry* rb_thread;
+
+static void storage_thread(void) __attribute__((noreturn));
+
+/*-------------------------------------------------------------------------*/
+
+void usb_storage_driver_init(void) {
+
+ logf("usb storage: register");
+ usb_device_driver_register(&usb_storage_driver);
+}
+
+void usb_storage_driver_bind(void* controller_ops) {
+
+ logf("usb storage: bind");
+ ops = controller_ops;
+
+ logf("usb storage: creating thread");
+ queue_init(&storage_queue, true);
+ rb_thread = create_thread(storage_thread, storage_stack, sizeof(storage_stack),
+ storage_thread_name IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU, false));
+}
+
+void usb_storage_driver_unbind(void) {
+
+ logf("usb storage: unbinding");
+ logf("usb storage: destroying thread");
+ remove_thread(rb_thread);
+ queue_delete(&storage_queue);
+}
+
+int usb_storage_driver_request(struct usb_ctrlrequest* req) {
+
+}
+
+/* thread we use to manage handling of scsi commands */
+static void storage_thread(void) {
+
+ struct event ev;
+ bool idle_notified = false;
+
+ while (1) {
+ queue_wait_w_tmo(&storage_queue, &ev, HZ);
+
+ switch (ev.id) {
+ case USB_STORAGE:
+ break;
+
+ case SYS_USB_CONNECTED:
+ usb_acknowledge(SYS_USB_CONNECTED_ACK);
+ /* Wait until the USB cable is extracted again */
+ usb_wait_for_disconnect(&storage_queue);
+ break;
+ }
+ }
+}
+
Index: firmware/usbstack/core.h
===================================================================
--- firmware/usbstack/core.h (revision 0)
+++ firmware/usbstack/core.h (revision 0)
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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 "usbstack.h"
+
+/*
+ * stack datatypes
+ */
+struct usb_ep {
+ const char* name;
+ uint8_t type;
+ uint32_t size;
+ struct list_head list;
+};
+
+struct usb_request {
+ void *buf;
+ unsigned length;
+};
+
+#include "usbstack/controller.h"
+#include "usbstack/device.h"
+#include "usbstack/host.h"
+
+/*
+ * 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 lists */
+ struct usb_host_driver host_drivers;
+ struct usb_device_driver device_drivers;
+ enum usb_controller_type mode;
+ bool running;
+};
+
+/* only used for debug */
+void into_usb_ctrlrequest(struct usb_ctrlrequest* request);
+
+#endif /*_USBSTACK_CORE_H_*/
Index: firmware/SOURCES
===================================================================
--- firmware/SOURCES (revision 14379)
+++ firmware/SOURCES (working copy)
@@ -223,6 +223,12 @@
/* USBOTG */
#if !defined(SIMULATOR)
+#if defined(USE_USBSTACK)
+usbstack/core/core.c
+usbstack/core/utils.c
+usbstack/drivers/device/usb_serial.c
+usbstack/drivers/device/usb_storage.c
+#endif
#if CONFIG_USBOTG == USBOTG_ISP1362
drivers/isp1362.c
#endif
@@ -230,7 +236,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) */
Index: firmware/target/arm/usb-fw-pp502x.c
===================================================================
--- firmware/target/arm/usb-fw-pp502x.c (revision 14379)
+++ firmware/target/arm/usb-fw-pp502x.c (working copy)
@@ -8,6 +8,7 @@
* $Id$
*
* Copyright (C) 2002 by Linus Nielsen Feltzing
+ * Copyright (C) 2007 by Christian Gmeiner
*
* iPod driver based on code from the ipodlinux project - http://ipodlinux.org
* Adapted for Rockbox in January 2006
@@ -21,32 +22,18 @@
* KIND, either express or implied.
*
****************************************************************************/
-#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 "usbstack/core.h"
#include "arcotg_udc.h"
-void usb_init_device(void)
-{
- int r0;
- outl(inl(0x70000084) | 0x200, 0x70000084);
+void usb_init_device(void) {
+ logf("usb_init_device");
+
+ outl(inl(0x70000084) | 0x200, 0x70000084);
outl(inl(0x7000002C) | 0x3000000, 0x7000002C);
DEV_EN |= DEV_USB;
@@ -55,90 +42,42 @@
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);
- }
+ /* enable interrupts */
+#if defined(SANSA_E200)
+ GPIOB_INT_EN &= ~(1 << 4);
- UDC_USBCMD |= USB_CMD_CTRL_RESET;
- while((UDC_USBCMD & USB_CMD_CTRL_RESET) != 0);
-
- r0 = UDC_PORTSC1;
+ GPIOB_OUTPUT_EN &= ~(1 << 4);
+ GPIOB_ENABLE |= (1 << 4);
+ GPIOB_INT_LEV = (GPIOB_INT_LEV & ~(1 << 4)) |
+ (~GPIOB_INPUT_VAL & (1 << 4));
- /* 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);
+ /* enable gpio interrupt in cpu */
+ CPU_INT_EN = HI_MASK;
+ CPU_HI_INT_EN = GPIO0_MASK;
- udelay(0x186A0);
-
- dr_controller_setup();
-
-#if defined(IPOD_COLOR) || defined(IPOD_4G) \
- || defined(IPOD_MINI) || defined(IPOD_MINI2G)
- /* GPIO C bit 1 is firewire detect */
- GPIOC_ENABLE |= 0x02;
- GPIOC_OUTPUT_EN &= ~0x02;
+ /* ack interrupt */
+ GPIOB_INT_CLR = (1 << 4);
+ /* enable gpiob interupt */
+ GPIOB_INT_EN |= (1 << 4);
#endif
}
-void usb_enable(bool on)
-{
- /* This device specific code will eventually give way to proper USB
- handling, which should be the same for all PP502x targets. */
- if (on)
- {
-#if defined(IPOD_ARCH) || defined(IRIVER_H10) || defined (IRIVER_H10_5GB)
- /* For the H10 and iPod, we can only do one thing with USB mode - reboot
- into the flash-based disk-mode. This does not return. */
+void usb_enable(bool on) {
-#if defined(IRIVER_H10) || defined (IRIVER_H10_5GB)
- if(button_status()==BUTTON_RIGHT)
-#endif
- {
- ata_sleepnow(); /* Immediately spindown the disk. */
- sleep(HZ*2);
-
-#ifdef IPOD_ARCH /* The following code is based on ipodlinux */
-#if CONFIG_CPU == PP5020
- memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
-#elif CONFIG_CPU == PP5022
- memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
-#endif
-#endif
-
- system_reboot(); /* Reboot */
- }
-#endif
+ if (on) {
+ logf("enabling usb");
+ usb_stack_start();
+ } else {
+ logf("disabling usb");
+ usb_stack_stop();
}
}
-bool usb_detect(void)
-{
- static bool prev_usbstatus1 = false;
- bool usbstatus1,usbstatus2;
+bool usb_detect(void) {
-#if defined(IPOD_COLOR) || defined(IPOD_4G) \
- || defined(IPOD_MINI) || defined(IPOD_MINI2G)
- /* GPIO C bit 1 is firewire detect */
- if (!(GPIOC_INPUT_VAL & 0x02))
- return true;
-#endif
-
+ bool connected = false;
+
/* UDC_ID should have the bit format:
[31:24] = 0x0
[23:16] = 0x22 (Revision number)
@@ -150,19 +89,29 @@
return false;
}
- usbstatus1 = (UDC_OTGSC & 0x800) ? true : false;
- if ((usbstatus1 == true) && (prev_usbstatus1 == false)) {
- dr_controller_run();
- } else if ((usbstatus1 == false) && (prev_usbstatus1 == true)) {
- dr_controller_stop();
+ connected = (UDC_OTGSC & 0x800) ? true : false;
+
+ if (connected == false) {
+ //logf("con2: %d", (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false);
+ usb_stack_stop();
+ return false;
}
+
+ /* do we want autodetection? */
+ if (usb_stack_get_mode() == AUTOMATIC) {
- prev_usbstatus1 = usbstatus1;
- usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false;
-
- if (usbstatus1 && usbstatus2) {
- return true;
- } else {
- return false;
+ logf("automatic mode");
+ UDC_OTGSC |= 0x5F000000;
+ if ((UDC_OTGSC & 0x100) == 0) {
+ usb_controller_select(HOST);
+ } else {
+ usb_controller_select(DEVICE);
+ }
}
+
+ /* TODO correct place? */
+ usb_stack_start();
+
+ return true;
}
+
Index: firmware/target/arm/system-pp502x.c
===================================================================
--- firmware/target/arm/system-pp502x.c (revision 14379)
+++ firmware/target/arm/system-pp502x.c (working copy)
@@ -20,6 +20,10 @@
#include "thread.h"
#include "i2s.h"
+#if defined(USE_USBSTACK)
+#include "usbstack.h"
+#endif
+
#if NUM_CORES > 1
struct mutex boostctrl_mtx NOCACHEBSS_ATTR;
#endif
@@ -53,13 +57,15 @@
else if (CPU_HI_INT_STAT & GPIO0_MASK) {
if (GPIOA_INT_STAT & 0x80)
microsd_int();
+ if (GPIOB_INT_STAT & 0x10)
+ usb_stack_irq();
}
else if (CPU_HI_INT_STAT & GPIO1_MASK) {
if (GPIOF_INT_STAT & 0xff)
button_int();
if (GPIOH_INT_STAT & 0xc0)
clickwheel_int();
- }
+ }
#endif
} else {
if (COP_INT_STAT & TIMER1_MASK)
Index: firmware/drivers/usb/arcotg_dcd.h
===================================================================
--- firmware/drivers/usb/arcotg_dcd.h (revision 0)
+++ firmware/drivers/usb/arcotg_dcd.h (revision 0)
@@ -0,0 +1,128 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: arcotg_udc.h 12340 2007-02-16 22:13:21Z barrywardell $
+ *
+ * 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 "system.h"
+#include "arcotg_udc.h"
+
+#define USB_MAX_ENDPOINTS 8
+#define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2)
+
+/* 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)
+
+/* Endpoint Transfer Descriptor data struct */
+struct etd {
+ 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 buff_ptr0; /* Buffer pointer Page 0 */
+ uint32_t buff_ptr1; /* Buffer pointer Page 1 */
+ uint32_t buff_ptr2; /* Buffer pointer Page 2 */
+ uint32_t buff_ptr3; /* Buffer pointer Page 3 */
+ uint32_t buff_ptr4; /* Buffer pointer Page 4 */
+ uint32_t res; /* make it an even 8 words */
+} __attribute((packed));
+
+/* Endpoint Queue Head*/
+struct eqh {
+ 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 etd dtd_ovrl; /* Transfer descriptor */
+ uint32_t setup_buffer[2]; /* Setup data 8 bytes */
+ uint32_t res2[4]; /* pad out to 64 bytes */
+} __attribute((packed));
+
+
+struct arcotg_udc {
+ struct mutex lock;
+ struct usb_ctrlrequest local_setup_buff;
+ enum usb_device_state usb_state;
+ enum usb_device_state resume_state;
+ bool stopped;
+};
+
+/* usb controller ops */
+int usb_arcotg_queue(struct usb_ep* ep, struct usb_request* req);
+
+/* usb_controller functions */
+int 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);
+
+/* 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);
+
+/* dcd fcuntions */
+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 etd* td, void* buffer, uint32_t todo);
+static void ep0Stall(void);
+
+#endif /*_ARCOTG_DCD_H_*/
Index: firmware/drivers/usb/arcotg_dcd.c
===================================================================
--- firmware/drivers/usb/arcotg_dcd.c (revision 0)
+++ firmware/drivers/usb/arcotg_dcd.c (revision 0)
@@ -0,0 +1,584 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $
+ *
+ * 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
+#include "usbstack/core.h"
+#include "arcotg_dcd.h"
+
+static void info_usb_register(void) {
+
+ logf("-reg dump-");
+
+ logf("USBCMD 0x%08x", UDC_USBCMD);
+ logf("USBSTS 0x%08x", UDC_USBSTS);
+ logf("USBINTR 0x%08x", UDC_USBINTR);
+ logf("FRINDEX 0x%08x", UDC_FRINDEX);
+ logf("DEVICEADDR 0x%08x", UDC_DEVICEADDR);
+ logf("ENDPOINTLISTADDR 0x%08x", UDC_ENDPOINTLISTADDR);
+ logf("ASYNCTTSTS 0x%08x", UDC_ASYNCTTSTS);
+ logf("PORTSC1 0x%08x", UDC_PORTSC1);
+ logf("OTGSC 0x%08x", UDC_OTGSC);
+ logf("USBMODE 0x%08x", UDC_USBMODE);
+ logf("ENDPTSETUPSTAT 0x%08x", UDC_ENDPTSETUPSTAT);
+ logf("ENDPTPRIME 0x%08x", UDC_ENDPTPRIME);
+ logf("ENDPTCOMPLETE 0x%08x", UDC_ENDPTCOMPLETE);
+ logf("ENDPTCTRL0 0x%08x", UDC_ENDPTCTRL0);
+
+ logf("-end dump-");
+}
+
+/* description of our device driver operations */
+struct usb_dcd_controller_ops arotg_dcd_opt = {
+ .enable = NULL,
+ .disable = NULL,
+ .set_halt = NULL,
+ .alloc_request = NULL,
+ .free_request = NULL,
+ .queue = usb_arcotg_queue,
+ .dequeue = NULL,
+};
+
+/* description of our usb controller driver */
+struct usb_controller arcotg_dcd = {
+ .name = "arcotg_dcd",
+ .type = DEVICE,
+ .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_opt,
+};
+
+/* USEC timer */
+#define PRIME_TIMER 100000
+#define TRANSFER_TIMER 1000000
+#define RESET_TIMER 5000000
+
+struct timer {
+ unsigned long s;
+ unsigned long e;
+};
+
+/* Maybe put this in a more global place */
+static void timer_set(struct timer * timer, unsigned long val) {
+ timer->s = USEC_TIMER;
+ timer->e = timer->s + val + 1;
+}
+
+static 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);
+ }
+}
+
+static void usleep(unsigned long t) {
+ struct timer timer;
+
+ timer_set(&timer, t);
+ while (!timer_expired(&timer));
+}
+
+static struct arcotg_udc udc_controller;
+
+/* device structes used to `communicate` with the device controler */
+struct eqh qh[USB_MAX_PIPES] __attribute((aligned (1 << 11))) __attribute__ ((section(".ibss")));
+struct etd td[1] __attribute((aligned (32))) __attribute__ ((section(".ibss"))); /* only for testing */
+
+/* shared memory used by rockbox and dcd to exchange data */
+#define BUFFER_SIZE 4096
+unsigned char buffer[BUFFER_SIZE] __attribute((aligned (1 << 12))) __attribute__ ((section(".ibss")));
+
+
+void usb_dcd_init(void) {
+
+ logf("arcotg_dcd: registering us");
+ /* register us in the usb stack */
+ usb_controller_register(&arcotg_dcd);
+}
+
+void usb_dcd_shutdown(void) {
+ logf("arcotg_dcd: shutdown");
+}
+
+/*
+ * arotg controller functions
+ */
+
+void usb_arcotg_dcd_start(void) {
+
+ logf("arcotg_dcd: start");
+
+ /* enable interrupt sources */
+ UDC_USBINTR = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN |
+ USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN |
+ USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+ /* clear stopped bit */
+ udc_controller.stopped = false;
+
+ /* set controller to Run */
+ UDC_USBCMD |= USB_CMD_RUN_STOP;
+}
+
+void usb_arcotg_dcd_stop(void) {
+
+ logf("arcotg_dcd: stop");
+
+ /* disable all interrupts */
+ UDC_USBINTR = 0;
+
+ /* set stopped bit */
+ udc_controller.stopped = true;
+
+ /* set controller to Stop */
+ UDC_USBCMD &= ~USB_CMD_RUN_STOP;
+}
+
+int usb_arcotg_dcd_init(void) {
+
+ struct timer t;
+ logf("arcotg_dcd: init");
+
+ /* setup data structues */
+ memset(&udc_controller, 0, sizeof(struct arcotg_udc));
+ spinlock_init(&udc_controller.lock);
+
+ /* stop usb controller */
+ UDC_USBCMD &= ~USB_CMD_RUN_STOP;
+
+ usleep(500000);
+
+ timer_set(&t, RESET_TIMER);
+
+ /* reset */
+ UDC_USBCMD |= USB_CMD_CTRL_RESET;
+ while (UDC_USBCMD & USB_CMD_CTRL_RESET) {
+ if (timer_expired(&t)) {
+ logf("%s: TIMEOUT", __FUNCTION__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* set the controller as device mode */
+ UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE;
+
+ /* init queue heads for ep0 */
+ 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);
+
+ /* set address of queue heads */
+ UDC_ENDPOINTLISTADDR = (uint32_t)qh;
+ logf("qhaddr: 0x%x", (unsigned int)qh);
+
+ return 0;
+}
+
+void usb_arcotg_dcd_shutdown(void) {
+
+ logf("arcotg_dcd: shutdown");
+}
+
+/**
+ * Main interrupt dispatcher.
+ */
+void usb_arcotg_dcd_irq(void) {
+
+ unsigned int irq_src = 0;
+
+ if (udc_controller.stopped == true) {
+ return;
+ }
+
+ //spinlock_lock(&udc_controller.lock);
+
+ /* read source of irq */
+ irq_src = UDC_USBSTS & UDC_USBINTR;
+
+ /* ack interrupt */
+ GPIOB_INT_CLR = (1 << 4);
+
+ /* hmmm...is this right? seems to work though */
+ GPIOB_INT_LEV = (GPIOB_INT_LEV & ~(1 << 4)) |
+ (~GPIOB_INPUT_VAL & (1 << 4));
+
+ /* TODO */
+ if (irq_src == 0x0) {
+ logf("BAD IRQ");
+ //spinlock_unlock(&udc_controller.lock);
+ return;
+ }
+
+ /* clear notification bits */
+ UDC_USBSTS &= irq_src;
+ logf("irq_src [0x%08x]", irq_src);
+
+ /* check if we need to wake up from suspend */
+ if (!(irq_src & USB_STS_SUSPEND) && udc_controller.resume_state) {
+ resume_int();
+ }
+
+ /* USB Interrupt */
+ if (irq_src & 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(&udc_controller.local_setup_buff, (uint8_t *) &qh[0].setup_buffer, 8);
+ setup_received_int(&udc_controller.local_setup_buff);
+ }
+
+ if (UDC_ENDPTCOMPLETE != 0) {
+ logf("!!!!!!!!!!!!");
+ logf("yes");
+ }
+ }
+
+ if (irq_src & USB_STS_PORT_CHANGE) {
+ port_change_int();
+ }
+
+ if (irq_src & USB_STS_SUSPEND) {
+ suspend_int();
+ }
+
+ if (irq_src & USB_STS_RESET) {
+ reset_int();
+ }
+
+ if (irq_src & USB_STS_ERR) {
+ logf("!!! error !!!");
+ }
+
+ if (irq_src & USB_STS_SYS_ERR) {
+ logf("!!! sys error !!!");
+ }
+
+ //spinlock_unlock(&udc_controller.lock);
+}
+
+/*
+ * arcotg controller ops
+ */
+int usb_arcotg_queue(struct usb_ep* ep, struct usb_request* req) {
+
+ /* hardcoded to ep0 */
+ struct etd* p_Td = &td[0];
+ struct eqh* p_Qh = &qh[0];
+ const unsigned int mask = 1 << 16;
+ struct timer t;
+
+ int todo, done = 0;
+ int size = req->length;
+ const char * ptr = req->buf;
+
+ do {
+ todo = MIN(req->length, BUFFER_SIZE);
+ logf("try tp send %d byte", todo);
+
+ memcpy(buffer, ptr, todo);
+ td_init(p_Td, buffer, todo);
+
+ /* execute td */
+ p_Qh->dtd_ovrl.next_dtd = (uint32_t)p_Td;
+ p_Qh->dtd_ovrl.dtd_token &= ~0xc0;
+
+ logf("priming...");
+ timer_set(&t, PRIME_TIMER);
+ UDC_ENDPTPRIME |= mask;
+
+ while (UDC_ENDPTPRIME & mask) {
+ if (timer_expired(&t)) {
+ logf("%s: TIMEOUT", __FUNCTION__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ if ((UDC_ENDPTSTAT & mask) == 0) {
+ return -EHWCRITICAL;
+ }
+
+ info_usb_register();
+
+ size -= todo;
+ ptr += todo;
+ done += todo;
+
+ } while (size > 0);
+
+ return 0;
+}
+
+/*
+ * Interrupt handlers
+ */
+
+static void setup_received_int(struct usb_ctrlrequest* request) {
+
+ 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);
+
+ /* we only handle standard requests */
+ if ((request->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+
+ /* what shall we do? */
+ switch (request->bRequest) {
+ case USB_REQ_GET_STATUS:
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ /* set recived address */
+ break;
+ }
+ }
+
+ if (handled == 0) {
+ logf("pass it to driver...");
+ /* pass it to device driver */
+ 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);
+ }
+ }
+
+ /* was the request handeled? */
+ if (handled < 0) {
+ /* stall */
+ ep0Stall();
+ }
+}
+
+static void port_change_int(void) {
+
+ logf("port_change_int");
+#if 0
+ uint32_t speed;
+
+ if (udc_controller.bus_reset) {
+ udc_controller.bus_reset = false;
+ }
+
+ /* bus resetting is finished */
+ if (!(UDC_PORTSC1 & PORTSCX_PORT_RESET)) {
+ /* Get the speed */
+ speed = (UDC_PORTSC1 & PORTSCX_PORT_SPEED_MASK);
+ switch (speed) {
+ case PORTSCX_PORT_SPEED_HIGH:
+ udc_controller.gadget.speed = USB_SPEED_HIGH;
+ break;
+ case PORTSCX_PORT_SPEED_FULL:
+ udc_controller.gadget.speed = USB_SPEED_FULL;
+ break;
+ case PORTSCX_PORT_SPEED_LOW:
+ udc_controller.gadget.speed = USB_SPEED_LOW;
+ break;
+ default:
+ udc_controller.gadget.speed = USB_SPEED_UNKNOWN;
+ break;
+ }
+ }
+
+ logf("arcotg: new speed %d", udc_controller.gadget.speed);
+
+ /* update USB state */
+ if (!udc_controller.resume_state) {
+ udc_controller.usb_state = USB_STATE_DEFAULT;
+ }
+#endif
+}
+
+static void reset_int(void) {
+
+ struct timer t;
+ logf("reset_int");
+
+ /* clear usb state */
+ udc_controller.usb_state = USB_STATE_DEFAULT;
+
+ timer_set(&t, RESET_TIMER);
+
+ /* clear all the setup token semaphores */
+ UDC_ENDPTSETUPSTAT = UDC_ENDPTSETUPSTAT;
+
+ /* clear all the endpoint complete status bits */
+ UDC_ENDPTCOMPLETE = UDC_ENDPTCOMPLETE;
+
+ /* prime and flush pending transfers */
+ while (UDC_ENDPTPRIME) {
+ if (timer_expired(&t)) {
+ logf("%s->%s: TIMEOUT", __FUNCTION__, "prime");
+ return;
+ }
+ }
+
+ /* write 1s to the Flush register */
+ UDC_ENDPTFLUSH = ~0;
+
+ if ((UDC_PORTSC1 & (1 << 8)) == 0) {
+ logf("%s->%s: TIMEOUT", __FUNCTION__, "flush");
+ return;
+ }
+
+ UDC_USBSTS = (1 << 6);
+
+ while ((UDC_USBSTS & (1 << 2)) == 0) { /* wait for port change */
+ if (timer_expired(&t)) {
+ logf("%s->%s: TIMEOUT", __FUNCTION__, "port");
+ return;
+ }
+ }
+
+ UDC_USBSTS = (1 << 2);
+
+ if (UDC_PORTSC1 & PORTSCX_PORT_RESET) {
+ logf("arcotg: Bus RESET");
+ /* Bus is reseting */
+ } else {
+ logf("arcotg: Controller reset");
+ udc_controller.usb_state = USB_STATE_ATTACHED;
+ }
+}
+
+static void suspend_int(void) {
+
+ logf("suspend_int");
+ udc_controller.resume_state = udc_controller.usb_state;
+ udc_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");
+ udc_controller.usb_state = udc_controller.resume_state;
+ udc_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();
+ }
+}
+
+/*
+ * Lifecycle
+ */
+
+/**
+ * Used to initialise queue head for one endpoint.
+ */
+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 eqh *p_QH = &qh[2 * ep_num + dir];
+ uint32_t tmp = 0;
+ memset(p_QH, 0, sizeof(*p_QH));
+
+ /* 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 */
+ p_QH->endpt_cap = tmp;
+
+ /* write the next dTD Terminate bit fild to 1 */
+ p_QH->dtd_ovrl.next_dtd = 1;
+
+ /* write the Active bit in the status field to 0 */
+ p_QH->dtd_ovrl.dtd_token &= ~STATUS_ACTIVE;
+
+ /* write the Hald bit in the status field to 0 */
+ p_QH->dtd_ovrl.dtd_token &= ~STATUS_HALTED;
+}
+
+static void td_init(struct etd* 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(td)); /* 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->buff_ptr0 = (uint32_t)buffer;
+ td->buff_ptr1 = 0;
+ td->buff_ptr2 = 0;
+ td->buff_ptr3 = 0;
+ td->buff_ptr4 = 0;
+}
+
+static void ep0Stall(void) {
+
+ logf("stalling ep0");
+ UDC_ENDPTCTRL0 |= (EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL);
+}