forked from len0rd/rockbox
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
This commit is contained in:
parent
9305c86f5b
commit
8181a0c905
29 changed files with 4585 additions and 72 deletions
|
@ -11156,3 +11156,73 @@
|
||||||
recording: ""
|
recording: ""
|
||||||
</voice>
|
</voice>
|
||||||
</phrase>
|
</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>
|
|
@ -99,6 +99,10 @@
|
||||||
#include "lcd-remote.h"
|
#include "lcd-remote.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_USBSTACK
|
||||||
|
#include "usbstack.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_USBOTG == USBOTG_ISP1362
|
#if CONFIG_USBOTG == USBOTG_ISP1362
|
||||||
#include "isp1362.h"
|
#include "isp1362.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -373,7 +377,10 @@ static void init(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
adc_init();
|
adc_init();
|
||||||
|
|
||||||
|
#ifdef HAVE_USBSTACK
|
||||||
|
usb_stack_init();
|
||||||
|
#endif
|
||||||
usb_init();
|
usb_init();
|
||||||
#if CONFIG_USBOTG == USBOTG_ISP1362
|
#if CONFIG_USBOTG == USBOTG_ISP1362
|
||||||
isp1362_init();
|
isp1362_init();
|
||||||
|
|
|
@ -42,6 +42,13 @@
|
||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_USBSTACK
|
||||||
|
#include "list.h"
|
||||||
|
#include "usbstack.h"
|
||||||
|
#include "statusbar.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/***********************************/
|
/***********************************/
|
||||||
/* TAGCACHE MENU */
|
/* TAGCACHE MENU */
|
||||||
#ifdef HAVE_TAGCACHE
|
#ifdef HAVE_TAGCACHE
|
||||||
|
@ -442,6 +449,82 @@ MAKE_MENU(voice_settings_menu, ID2P(LANG_VOICE), 0, Icon_Voice,
|
||||||
/* VOICE MENU */
|
/* 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 */
|
/* SETTINGS MENU */
|
||||||
static int language_browse(void)
|
static int language_browse(void)
|
||||||
|
@ -458,6 +541,10 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0,
|
||||||
&tagcache_menu,
|
&tagcache_menu,
|
||||||
#endif
|
#endif
|
||||||
&display_menu, &system_menu,
|
&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 */
|
/* SETTINGS MENU */
|
||||||
/***********************************/
|
/***********************************/
|
||||||
|
|
|
@ -98,6 +98,10 @@ struct system_status global_status;
|
||||||
#include "lcd-remote.h"
|
#include "lcd-remote.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_USBSTACK
|
||||||
|
#include "usbstack.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
long lasttime = 0;
|
long lasttime = 0;
|
||||||
|
|
||||||
/** NVRAM stuff, if the target doesnt have NVRAM it is saved in ROCKBOX_DIR /nvram.bin **/
|
/** 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();
|
read_color_theme_file();
|
||||||
#endif
|
#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
|
* reset all settings to their default value
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -748,6 +748,10 @@ struct user_settings
|
||||||
int list_accel_start_delay; /* ms before we start increaseing step size */
|
int list_accel_start_delay; /* ms before we start increaseing step size */
|
||||||
int list_accel_wait; /* ms between increases */
|
int list_accel_wait; /* ms between increases */
|
||||||
#endif
|
#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 **/
|
/** global variables **/
|
||||||
|
|
|
@ -47,6 +47,9 @@
|
||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_USBSTACK
|
||||||
|
#include "usbstack.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
|
#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
|
||||||
/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
|
/** 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,
|
3, "list_accel_wait", UNIT_SEC, 1, 10, 1,
|
||||||
scanaccel_formatter, scanaccel_getlang, NULL),
|
scanaccel_formatter, scanaccel_getlang, NULL),
|
||||||
#endif /* HAVE_SCROLLWHEEL */
|
#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);
|
const int nb_settings = sizeof(settings)/sizeof(*settings);
|
||||||
|
|
|
@ -101,6 +101,7 @@ drivers/dac.c
|
||||||
drivers/serial.c
|
drivers/serial.c
|
||||||
#endif /* SIMULATOR */
|
#endif /* SIMULATOR */
|
||||||
|
|
||||||
|
|
||||||
/* Storage */
|
/* Storage */
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
#ifdef HAVE_MMC
|
#ifdef HAVE_MMC
|
||||||
|
@ -221,6 +222,18 @@ drivers/audio/mas35xx.c
|
||||||
#endif /* defined(HAVE_*) */
|
#endif /* defined(HAVE_*) */
|
||||||
#endif /* SIMULATOR */
|
#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 */
|
/* USBOTG */
|
||||||
#if !defined(SIMULATOR)
|
#if !defined(SIMULATOR)
|
||||||
#if CONFIG_USBOTG == USBOTG_ISP1362
|
#if CONFIG_USBOTG == USBOTG_ISP1362
|
||||||
|
@ -230,7 +243,7 @@ drivers/isp1362.c
|
||||||
#if CONFIG_USBOTG == USBOTG_M5636
|
#if CONFIG_USBOTG == USBOTG_M5636
|
||||||
drivers/m5636.c
|
drivers/m5636.c
|
||||||
#elif CONFIG_USBOTG == USBOTG_ARC
|
#elif CONFIG_USBOTG == USBOTG_ARC
|
||||||
drivers/arcotg_udc.c
|
drivers/usb/arcotg_dcd.c
|
||||||
#endif /* CONFIG_USBOTG */
|
#endif /* CONFIG_USBOTG */
|
||||||
#endif /* !defined(BOOTLOADER) */
|
#endif /* !defined(BOOTLOADER) */
|
||||||
#endif /* !defined(SIMULATOR) */
|
#endif /* !defined(SIMULATOR) */
|
||||||
|
|
983
firmware/drivers/usb/arcotg_dcd.c
Normal file
983
firmware/drivers/usb/arcotg_dcd.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
173
firmware/drivers/usb/arcotg_dcd.h
Normal file
173
firmware/drivers/usb/arcotg_dcd.h
Normal file
|
@ -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_*/
|
|
@ -37,8 +37,6 @@
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
#define ETIMEDOUT 1
|
|
||||||
|
|
||||||
#define USB_MAX_ENDPOINTS 8
|
#define USB_MAX_ENDPOINTS 8
|
||||||
#define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2)
|
#define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2)
|
||||||
#define USB_MAX_CTRL_PAYLOAD 64
|
#define USB_MAX_CTRL_PAYLOAD 64
|
||||||
|
@ -99,7 +97,7 @@
|
||||||
#define USB_FRINDEX_MASKS (0x3fff)
|
#define USB_FRINDEX_MASKS (0x3fff)
|
||||||
|
|
||||||
/* USB CMD Register Bit Masks */
|
/* 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_CTRL_RESET (0x00000002)
|
||||||
#define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010)
|
#define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010)
|
||||||
#define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020)
|
#define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020)
|
||||||
|
|
|
@ -148,6 +148,8 @@
|
||||||
#define FIRMWARE_OFFSET_FILE_DATA 0x8
|
#define FIRMWARE_OFFSET_FILE_DATA 0x8
|
||||||
|
|
||||||
/* #define USB_IPODSTYLE */
|
/* #define USB_IPODSTYLE */
|
||||||
|
#define HAVE_USBSTACK
|
||||||
|
#define USBSTACK_CAPS CONTROLLER_DEVICE
|
||||||
|
|
||||||
/* USB On-the-go */
|
/* USB On-the-go */
|
||||||
#define CONFIG_USBOTG USBOTG_ARC
|
#define CONFIG_USBOTG USBOTG_ARC
|
||||||
|
|
710
firmware/export/linkedlist.h
Normal file
710
firmware/export/linkedlist.h
Normal file
|
@ -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_*/
|
762
firmware/export/usb_ch9.h
Normal file
762
firmware/export/usb_ch9.h
Normal file
|
@ -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_*/
|
55
firmware/export/usbstack.h
Normal file
55
firmware/export/usbstack.h
Normal file
|
@ -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_*/
|
|
@ -35,13 +35,20 @@ extern void clickwheel_int(void);
|
||||||
extern void microsd_int(void);
|
extern void microsd_int(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_USBSTACK
|
||||||
|
#include "usbstack/core.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void irq(void)
|
void irq(void)
|
||||||
{
|
{
|
||||||
if(CURRENT_CORE == CPU)
|
if(CURRENT_CORE == CPU)
|
||||||
{
|
{
|
||||||
if (CPU_INT_STAT & TIMER1_MASK)
|
if (CPU_INT_STAT & TIMER1_MASK) {
|
||||||
TIMER1();
|
TIMER1();
|
||||||
else if (CPU_INT_STAT & TIMER2_MASK)
|
#ifdef HAVE_USBSTACK
|
||||||
|
usb_stack_irq();
|
||||||
|
#endif
|
||||||
|
} else if (CPU_INT_STAT & TIMER2_MASK)
|
||||||
TIMER2();
|
TIMER2();
|
||||||
#if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */
|
#if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */
|
||||||
else if (CPU_HI_INT_STAT & GPIO_MASK)
|
else if (CPU_HI_INT_STAT & GPIO_MASK)
|
||||||
|
|
|
@ -22,71 +22,16 @@
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "cpu.h"
|
|
||||||
#include "kernel.h"
|
|
||||||
#include "thread.h"
|
|
||||||
#include "system.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 "usb.h"
|
||||||
#include "button.h"
|
|
||||||
#include "sprintf.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "hwcompat.h"
|
|
||||||
|
|
||||||
#include "usb-target.h"
|
|
||||||
#include "arcotg_udc.h"
|
#include "arcotg_udc.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_USBSTACK
|
||||||
|
#include "usbstack.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void usb_init_device(void)
|
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) \
|
#if defined(IPOD_COLOR) || defined(IPOD_4G) \
|
||||||
|| defined(IPOD_MINI) || defined(IPOD_MINI2G)
|
|| defined(IPOD_MINI) || defined(IPOD_MINI2G)
|
||||||
|
@ -98,6 +43,7 @@ void usb_init_device(void)
|
||||||
|
|
||||||
void usb_enable(bool on)
|
void usb_enable(bool on)
|
||||||
{
|
{
|
||||||
|
#ifndef HAVE_USBSTACK
|
||||||
/* This device specific code will eventually give way to proper USB
|
/* This device specific code will eventually give way to proper USB
|
||||||
handling, which should be the same for all PP502x targets. */
|
handling, which should be the same for all PP502x targets. */
|
||||||
if (on)
|
if (on)
|
||||||
|
@ -125,6 +71,7 @@ void usb_enable(bool on)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool usb_detect(void)
|
bool usb_detect(void)
|
||||||
|
@ -151,12 +98,13 @@ bool usb_detect(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
usbstatus1 = (UDC_OTGSC & 0x800) ? true : false;
|
usbstatus1 = (UDC_OTGSC & 0x800) ? true : false;
|
||||||
|
#ifdef HAVE_USBSTACK
|
||||||
if ((usbstatus1 == true) && (prev_usbstatus1 == false)) {
|
if ((usbstatus1 == true) && (prev_usbstatus1 == false)) {
|
||||||
dr_controller_run();
|
usb_stack_start();
|
||||||
} else if ((usbstatus1 == false) && (prev_usbstatus1 == true)) {
|
} else if ((usbstatus1 == false) && (prev_usbstatus1 == true)) {
|
||||||
dr_controller_stop();
|
usb_stack_stop();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
prev_usbstatus1 = usbstatus1;
|
prev_usbstatus1 = usbstatus1;
|
||||||
usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false;
|
usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false;
|
||||||
|
|
||||||
|
|
31
firmware/usbstack/config.h
Normal file
31
firmware/usbstack/config.h
Normal file
|
@ -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_*/
|
68
firmware/usbstack/controller.h
Normal file
68
firmware/usbstack/controller.h
Normal file
|
@ -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_*/
|
84
firmware/usbstack/core.h
Normal file
84
firmware/usbstack/core.h
Normal file
|
@ -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_*/
|
80
firmware/usbstack/core/config.c
Normal file
80
firmware/usbstack/core/config.c
Normal file
|
@ -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;
|
||||||
|
}
|
392
firmware/usbstack/core/core.c
Normal file
392
firmware/usbstack/core/core.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
186
firmware/usbstack/core/epsetup.c
Normal file
186
firmware/usbstack/core/epsetup.c
Normal file
|
@ -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;
|
||||||
|
}
|
125
firmware/usbstack/core/utils.c
Normal file
125
firmware/usbstack/core/utils.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
48
firmware/usbstack/device.h
Normal file
48
firmware/usbstack/device.h
Normal file
|
@ -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_*/
|
300
firmware/usbstack/drivers/device/usb_serial.c
Normal file
300
firmware/usbstack/drivers/device/usb_serial.c
Normal file
|
@ -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;
|
||||||
|
}
|
32
firmware/usbstack/drivers/device/usb_serial.h
Normal file
32
firmware/usbstack/drivers/device/usb_serial.h
Normal file
|
@ -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_*/
|
269
firmware/usbstack/drivers/device/usb_storage.c
Normal file
269
firmware/usbstack/drivers/device/usb_storage.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
31
firmware/usbstack/drivers/device/usb_storage.h
Normal file
31
firmware/usbstack/drivers/device/usb_storage.h
Normal file
|
@ -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_*/
|
31
firmware/usbstack/host.h
Normal file
31
firmware/usbstack/host.h
Normal file
|
@ -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_*/
|
Loading…
Add table
Add a link
Reference in a new issue