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