Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 14229) +++ apps/lang/english.lang (working copy) @@ -11004,3 +11004,73 @@ *: "Demos" + + 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" + + \ No newline at end of file Index: apps/settings.c =================================================================== --- apps/settings.c (revision 14229) +++ 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 **/ @@ -867,7 +871,10 @@ if (global_settings.colors_file) read_color_theme_file(); #endif - + +#ifdef USE_USBSTACK + usb_controller_select(global_settings.usb_stack_mode); +#endif } Index: apps/settings.h =================================================================== --- apps/settings.h (revision 14229) +++ apps/settings.h (working copy) @@ -743,6 +743,9 @@ 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 */ +#endif }; /** global variables **/ Index: apps/menus/settings_menu.c =================================================================== --- apps/menus/settings_menu.c (revision 14229) +++ apps/menus/settings_menu.c (working copy) @@ -442,7 +442,18 @@ /* VOICE MENU */ /***********************************/ +#ifdef USE_USBSTACK /***********************************/ +/* USB STACK MENU */ +MENUITEM_SETTING(usbstack_mode, &global_settings.usb_stack_mode, NULL); + +MAKE_MENU(usbstack_menu, ID2P(LANG_USBSTACK), 0, Icon_file_view_menu, + &usbstack_mode); +/* USB STACK MENU */ +/***********************************/ +#endif + +/***********************************/ /* SETTINGS MENU */ static int language_browse(void) { @@ -458,6 +469,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 14229) +++ 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< ) \___| < | \_\ ( <_> > < < + * 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_ + +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 14229) +++ firmware/export/config.h (working copy) @@ -334,7 +334,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/usbstack.h =================================================================== --- firmware/export/usbstack.h (revision 0) +++ firmware/export/usbstack.h (revision 0) @@ -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. + * + ****************************************************************************/ + +#ifndef _USBSTACK_H_ +#define _USBSTACK_H_ + +#include "linkedlist.h" +#include "logf.h" + +/* + * error codes + */ +#define ENOFREESLOT 1 +#define ENOCONTROLLERACTIVE 2 +#define EWRONGCONTROLLERTYPE 3 + +/* + * 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); + +/* + * usb controller + */ + +enum usb_controller_type { + AUTOMATIC = 0, /* only used for autodetection, do not use in drivers or controllers*/ + DEVICE, + HOST, +}; + +struct usb_driver; + +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); + struct usb_driver* driver; +}; + +int usb_controller_register(struct usb_controller* ctrl); +int usb_controller_unregister(struct usb_controller* ctrl); +void usb_controller_select(int type); + +/* + * usb driver (host or device) + */ +struct usb_driver { + const char* name; + enum usb_controller_type type; + void (*bind)(void); + void (*unbind)(void); + void* data; /* used to store controller specific ops struct */ + struct list_head list; +}; + +int usb_driver_register(struct usb_driver* driver); +int usb_driver_unregister(struct usb_driver* driver); +int usb_driver_bind(struct usb_driver* driver); +void usb_driver_unbind(struct usb_driver* driver); + +/* + * dcd - device controller driver + */ +void usb_dcd_init(void); +void usb_dcd_shutdown(void); + +struct usb_dcd_controller_ops { + /* endpoint management */ + /* transfer */ + /* reciving */ +}; + +/* + * hcd - host controller driver + */ +void usb_hcd_init(void); +void usb_hcd_shutdown(void); + +struct usb_hcd_controller_ops { + /* TODO */ +}; + +/* + * 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; + struct usb_driver host_drivers; + struct usb_driver device_drivers; + enum usb_controller_type mode; +}; + +/* use a global variable to make usb_core accessable in other places */ +struct usb_core usbcore; + +#endif /*_USBSTACK_H_*/ Index: firmware/export/config-e200.h =================================================================== --- firmware/export/config-e200.h (revision 14229) +++ firmware/export/config-e200.h (working copy) @@ -145,6 +145,7 @@ /* USB On-the-go */ #define CONFIG_USBOTG USBOTG_ARC +#define USE_USBSTACK /* define this if the unit can be powered or charged via USB */ #define HAVE_USB_POWER Index: firmware/export/config-ipodvideo.h =================================================================== --- firmware/export/config-ipodvideo.h (revision 14229) +++ firmware/export/config-ipodvideo.h (working copy) @@ -38,6 +38,8 @@ /* define this if you would like tagcache to build on this target */ #define HAVE_TAGCACHE +#define USE_USBSTACK + /* LCD dimensions */ #define LCD_WIDTH 320 #define LCD_HEIGHT 240 Index: firmware/export/usbstack/dummy_driver.h =================================================================== --- firmware/export/usbstack/dummy_driver.h (revision 0) +++ firmware/export/usbstack/dummy_driver.h (revision 0) @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * 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 _DUMMY_DRIVER_H_ +#define _DUMMY_DRIVER_H_ + +void usb_dummy_init(void); + +#endif /*_DUMMY_DRIVER_H_*/ Index: firmware/usbstack/core/core.c =================================================================== --- firmware/usbstack/core/core.c (revision 0) +++ firmware/usbstack/core/core.c (revision 0) @@ -0,0 +1,299 @@ +/*************************************************************************** + * __________ __ ___. + * 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" + +/** + * Initialize usb stack. + */ +void usb_stack_init(void) { + + /* init datastructures */ + usbcore.controller[0] = NULL; + usbcore.controller[1] = NULL; + usbcore.active_controller = NULL; + + /* init linked lists */ + INIT_LIST_HEAD(&usbcore.device_drivers.list); + INIT_LIST_HEAD(&usbcore.host_drivers.list); + + /* 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__init(void); + */ +} + +/** + * Shutdown usb stack. + */ +void usb_stack_shutdown(void) { + + /* free current used driver */ + if (usbcore.active_controller->driver != NULL) { + + /* call unbind if supported */ + if (usbcore.active_controller->driver->unbind != NULL) { + usbcore.active_controller->driver->unbind(); + } + usbcore.active_controller->driver = NULL; + } + + /* stop stack */ + usb_stack_stop(); + + /* TODO delete linked lists */ +} + +/** + * Start processing of usb stack. This function init + * active usb controller. + */ +void usb_stack_start(void) { + + /* forward to controller */ + if (usbcore.active_controller != NULL && usbcore.active_controller->start != NULL) { + usbcore.active_controller->start(); + } +} + +/** + * Stop processing of usb stack. This function shutsdown + * active usb controller. + */ +void usb_stack_stop(void) { + + /* forward to controller */ + if (usbcore.active_controller != NULL && usbcore.active_controller->stop != NULL) { + usbcore.active_controller->stop(); + } +} + +/** + * 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; +} + +/** + * 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_driver_register(struct usb_driver* driver) { + + if (driver == NULL) { + return EINVAL; + } + + logf("usb_stack: register usb driver"); + logf(" -> name: %s", driver->name); + logf(" -> type: %d", driver->type); + + /* add it to linked list */ + switch (driver->type) { + case DEVICE: + list_add(&driver->list, &usbcore.device_drivers.list); + break; + case HOST: + list_add(&driver->list, &usbcore.host_drivers.list); + break; + default: + return EINVAL; + } + + return 0; +} + +int usb_driver_unregister(struct usb_driver* driver) { + + if (driver == NULL) { + return EINVAL; + } + + /* delete from linked list */ + list_del(&driver->list); + + return 0; +} + +int usb_driver_bind(struct usb_driver* driver) { + + if (driver == NULL) { + return EINVAL; + } + + /* look if there is an usb controller loaded */ + if (usbcore.active_controller == NULL) { + return ENOCONTROLLERACTIVE; + } + + /* we need to have an active dcd controller */ + if (usbcore.active_controller->type != DEVICE) { + return EWRONGCONTROLLERTYPE; + } + + /* bind driver to controller */ + usbcore.active_controller->driver = driver; + + /* init dirver */ + driver->bind(); + + return 0; +} + +void usb_driver_unbind(struct usb_driver* driver) { + (void)driver; +} Index: firmware/SOURCES =================================================================== --- firmware/SOURCES (revision 14229) +++ firmware/SOURCES (working copy) @@ -226,6 +226,10 @@ /* USBOTG */ #if !defined(SIMULATOR) +#if defined(USE_USBSTACK) +usbstack/core/core.c +usbstack/drivers/dummy.c +#endif #if CONFIG_USBOTG == USBOTG_ISP1362 drivers/isp1362.c #endif @@ -233,7 +237,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 14229) +++ 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,16 @@ * 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.h" #include "arcotg_udc.h" -void usb_init_device(void) -{ - int r0; - outl(inl(0x70000084) | 0x200, 0x70000084); +void usb_init_device(void) { + outl(inl(0x70000084) | 0x200, 0x70000084); outl(inl(0x7000002C) | 0x3000000, 0x7000002C); DEV_EN |= DEV_USB; @@ -56,89 +41,32 @@ DEV_INIT |= INIT_USB; while ((inl(0x70000028) & 0x80) == 0); + /* reset port */ 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); - } - + /* reset device */ 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) - /* GPIO C bit 1 is firewire detect */ - GPIOC_ENABLE |= 0x02; - GPIOC_OUTPUT_EN &= ~0x02; -#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 +78,24 @@ 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) { + return false; } + + /* do we want autodetection? */ + if (usbcore.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); + } } + + return true; } + Index: firmware/target/arm/system-pp502x.c =================================================================== --- firmware/target/arm/system-pp502x.c (revision 14229) +++ 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 @@ -39,8 +43,12 @@ { if(CURRENT_CORE == CPU) { - if (CPU_INT_STAT & TIMER1_MASK) + if (CPU_INT_STAT & TIMER1_MASK) { TIMER1(); +#if defined(USE_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 */ Index: firmware/drivers/arcotg_udc.c =================================================================== --- firmware/drivers/arcotg_udc.c (revision 14229) +++ firmware/drivers/arcotg_udc.c (working copy) @@ -1,135 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 by Barry Wardell - * - * 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 "arcotg_udc.h" -#include "logf.h" - -static int timeout; - -/* @qh_addr is the aligned virt addr of ep QH addr - * it is used to set endpointlistaddr Reg */ -/* was static int dr_controller_setup(void *qh_addr) */ -int dr_controller_setup(void) -{ -#if 0 - struct arc_usb_config *config; - - config = udc_controller->config; - - /* before here, make sure usb_slave_regs has been initialized */ - if (!qh_addr) - return -EINVAL; -#endif - - /* Stop and reset the usb controller */ - UDC_USBCMD &= ~USB_CMD_RUN_STOP; - - UDC_USBCMD |= USB_CMD_CTRL_RESET; - - /* Wait for reset to complete */ - timeout = 10000000; - while ((UDC_USBCMD & USB_CMD_CTRL_RESET) && - --timeout) { - continue; - } - if (timeout == 0) { - logf("%s: TIMEOUT", __FUNCTION__); - return -ETIMEDOUT; - } - - /* Set the controller as device mode and disable setup lockout */ - UDC_USBMODE |= (USB_MODE_CTRL_MODE_DEVICE | USB_MODE_SETUP_LOCK_OFF); - - /* Clear the setup status */ - UDC_USBSTS = 0; -#if 0 - UDC_ENDPOINTLISTADDR = (unsigned int)qh_addr & USB_EP_LIST_ADDRESS_MASK; - - VDBG("qh_addr=0x%x epla_reg=0x%8x", qh_addr, UOG_ASYNCLISTADDR); -#endif - UDC_PORTSC1 = (UDC_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_UTMI; -#if 0 - if (config->set_vbus_power) - config->set_vbus_power(0); -#endif - - return 0; -} - -/* just Enable DR irq reg and Set Dr controller Run */ -/* was static void dr_controller_run(struct arcotg_udc *udc) */ -void dr_controller_run(void) -{ - /*Enable DR irq reg */ - 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; -#if 0 - /* Clear stopped bit */ - udc->stopped = 0; -#endif - /* Set the controller as device mode */ - UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; - - /* Set controller to Run */ - UDC_USBCMD |= USB_CMD_RUN_STOP; - - return; -} - -/* just Enable DR irq reg and Set Dr controller Run */ -/* was static void dr_controller_stop(struct arcotg_udc *udc) */ -void dr_controller_stop(void) -{ -#if 0 - /* if we're in OTG mode, and the Host is currently using the port, - * stop now and don't rip the controller out from under the - * ehci driver - */ - if (udc->gadget.is_otg) { - if (!(UDC_OTGSC & OTGSC_STS_USB_ID)) { - logf("Leaving early"); - return; - } - } -#endif - - /* disable all INTR */ - UDC_USBINTR = 0; -#if 0 - /* Set stopped bit */ - udc->stopped = 1; -#endif - /* Set controller to Stop */ - UDC_USBCMD &= ~USB_CMD_RUN_STOP; -} 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,152 @@ +/*************************************************************************** + * __________ __ ___. + * 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.h" +#include "arcotg_dcd.h" + +/* 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, +}; + +static unsigned int timeout; +static struct arcotg_udc udc_controller; + +void usb_dcd_init() { + + logf("arcotg_dcd: registering us"); + + /* register us in the usb stack */ + usb_controller_register(&arcotg_dcd); +} + +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 the controller as device mode */ + UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; + + /* 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) { + + logf("arcotg_dcd: init"); + + /* do some mysical stuff */ + outl(inl(0x70000028) &~0x4000, 0x70000028); + outl(inl(0x70000028) | 0x2, 0x70000028); + + /* setup data structues */ + memset(&udc_controller, 0, sizeof(struct arcotg_udc)); + spinlock_init(&udc_controller.lock); + + /* stop and reset the usb controller */ + UDC_USBCMD &= ~USB_CMD_RUN_STOP; + UDC_USBCMD |= USB_CMD_CTRL_RESET; + + /* wait for reset to complete */ + timeout = 10000000; + while ((UDC_USBCMD & USB_CMD_CTRL_RESET) && -timeout) { + continue; + } + + if (timeout == 0) { + logf("%s: TIMEOUT", __FUNCTION__); + return -ETIMEDOUT; + } + + /* set the controller as device mode */ + UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; + + return 0; +} + +void usb_arcotg_dcd_shutdown(void) { + + logf("arcotg_dcd: shutdown"); +} + +void usb_arcotg_dcd_irq(void) { + + unsigned int irq_src = 0; + + spinlock_lock(&udc_controller.lock); + + /* read source of irq */ + irq_src = UDC_USBSTS & UDC_USBINTR; + + /* TODO */ + if (irq_src == 0x0) { + spinlock_unlock(&udc_controller.lock); + return; + } + + /* clear notification bits */ + UDC_USBSTS &= irq_src; + logf("irq_src [0x%08x]", irq_src); + + spinlock_unlock(&udc_controller.lock); +} Index: firmware/drivers/usb/ehcid.c =================================================================== --- firmware/drivers/usb/ehcid.c (revision 0) +++ firmware/drivers/usb/ehcid.c (revision 0) @@ -0,0 +1,34 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +