New USB stack
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15758 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
2e2cbfe4ac
commit
b4e5123e5d
|
@ -99,10 +99,6 @@
|
|||
#include "lcd-remote.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
#include "usbstack.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_USBOTG == USBOTG_ISP1362
|
||||
#include "isp1362.h"
|
||||
#endif
|
||||
|
@ -389,9 +385,6 @@ static void init(void)
|
|||
|
||||
adc_init();
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
usb_stack_init();
|
||||
#endif
|
||||
usb_init();
|
||||
#if CONFIG_USBOTG == USBOTG_ISP1362
|
||||
isp1362_init();
|
||||
|
|
|
@ -42,13 +42,6 @@
|
|||
#include "radio.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
#include "list.h"
|
||||
#include "usbstack.h"
|
||||
#include "statusbar.h"
|
||||
#include "misc.h"
|
||||
#endif
|
||||
|
||||
/***********************************/
|
||||
/* TAGCACHE MENU */
|
||||
#ifdef HAVE_TAGCACHE
|
||||
|
@ -453,88 +446,6 @@ MAKE_MENU(voice_settings_menu, ID2P(LANG_VOICE), 0, Icon_Voice,
|
|||
/* VOICE MENU */
|
||||
/***********************************/
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
/***********************************/
|
||||
/* USB STACK MENU */
|
||||
char drivers[16][32];
|
||||
static char* usb_menu_getname(int item, void * data, char *buffer)
|
||||
{
|
||||
(void)data; (void)buffer;
|
||||
return drivers[item];
|
||||
}
|
||||
int usbdriver_menuitem(void)
|
||||
{
|
||||
struct gui_synclist lists;
|
||||
int action, count = 0;
|
||||
char *s = device_driver_names, *e;
|
||||
do {
|
||||
e = strchr(s, ',');
|
||||
if (e)
|
||||
{
|
||||
strncpy(drivers[count++], s, e-s);
|
||||
s = e+1;
|
||||
}
|
||||
} while (e && count < 16);
|
||||
if (count < 16)
|
||||
strcpy(drivers[count++], s);
|
||||
for (action=0; action<count; action++)
|
||||
{
|
||||
if (!strcmp(drivers[action],
|
||||
global_settings.usb_stack_device_driver))
|
||||
break;
|
||||
}
|
||||
|
||||
gui_synclist_init(&lists, usb_menu_getname, drivers, false, 1);
|
||||
gui_synclist_set_title(&lists, str(LANG_USBSTACK_DEVICE_DRIVER), NOICON);
|
||||
gui_synclist_set_icon_callback(&lists, NULL);
|
||||
gui_synclist_set_nb_items(&lists, count);
|
||||
gui_synclist_select_item(&lists, action==count?0:action);
|
||||
gui_synclist_draw(&lists);
|
||||
|
||||
while(1)
|
||||
{
|
||||
gui_syncstatusbar_draw(&statusbars, true);
|
||||
action = get_action(CONTEXT_STD, HZ/5);
|
||||
if (gui_synclist_do_button(&lists, &action, LIST_WRAP_UNLESS_HELD))
|
||||
continue;
|
||||
if (action == ACTION_STD_CANCEL)
|
||||
{
|
||||
/* setting was canceled */
|
||||
break;
|
||||
}
|
||||
else if (action == ACTION_STD_OK)
|
||||
{
|
||||
/* setting was accepted... save */
|
||||
strcpy(global_settings.usb_stack_device_driver,
|
||||
drivers[gui_synclist_get_sel_pos(&lists)]);
|
||||
|
||||
/* switch device driver */
|
||||
usb_device_driver_bind(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;
|
||||
}
|
||||
|
||||
#if USBSTACK_CAPS == (CONTROLLER_DEVICE|CONTROLLER_HOST)
|
||||
MENUITEM_SETTING(usbstack_mode, &global_settings.usb_stack_mode, NULL);
|
||||
#endif
|
||||
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,
|
||||
#if USBSTACK_CAPS == (CONTROLLER_DEVICE|CONTROLLER_HOST)
|
||||
&usbstack_mode,
|
||||
#endif
|
||||
&usbdriver);
|
||||
/* USB STACK MENU */
|
||||
/***********************************/
|
||||
#endif
|
||||
|
||||
/***********************************/
|
||||
|
||||
/***********************************/
|
||||
|
@ -554,9 +465,6 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0,
|
|||
#endif
|
||||
&display_menu, &system_menu,
|
||||
&bookmark_settings_menu, &browse_langs, &voice_settings_menu
|
||||
#ifdef HAVE_USBSTACK
|
||||
, &usbstack_menu
|
||||
#endif
|
||||
);
|
||||
/* SETTINGS MENU */
|
||||
/***********************************/
|
||||
|
|
|
@ -97,10 +97,6 @@ struct system_status global_status;
|
|||
#include "lcd-remote.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
#include "usbstack.h"
|
||||
#endif
|
||||
|
||||
long lasttime = 0;
|
||||
|
||||
/** NVRAM stuff, if the target doesnt have NVRAM it is saved in ROCKBOX_DIR /nvram.bin **/
|
||||
|
@ -879,18 +875,6 @@ void settings_apply(void)
|
|||
read_color_theme_file();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
|
||||
#if USBSTACK_CAPS == (CONTROLLER_DEVICE|CONTROLLER_HOST)
|
||||
usb_controller_select(global_settings.usb_stack_mode);
|
||||
#elif USBSTACK_CAPS == (CONTROLLER_DEVICE)
|
||||
usb_controller_select(DEVICE);
|
||||
#elif USBSTACK_CAPS == (CONTROLLER_HOST)
|
||||
usb_controller_select(HOST);
|
||||
#endif
|
||||
|
||||
usb_device_driver_bind(global_settings.usb_stack_device_driver);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -47,10 +47,6 @@
|
|||
#include "radio.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
#include "usbstack.h"
|
||||
#endif
|
||||
|
||||
#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
|
||||
/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
|
||||
and you may need to update it if you edit this file */
|
||||
|
@ -1270,14 +1266,6 @@ const struct settings_list settings[] = {
|
|||
3, "list_accel_wait", UNIT_SEC, 1, 10, 1,
|
||||
scanaccel_formatter, scanaccel_getlang, NULL),
|
||||
#endif /* HAVE_SCROLLWHEEL */
|
||||
#ifdef HAVE_USBSTACK
|
||||
CHOICE_SETTING(0, usb_stack_mode, LANG_USBSTACK_MODE, 0, "usb mode",
|
||||
"device,host",
|
||||
usb_controller_select,
|
||||
2, ID2P(LANG_USBSTACK_DEVICE), ID2P(LANG_USBSTACK_HOST)),
|
||||
FILENAME_SETTING(0, usb_stack_device_driver, "usb device driver",
|
||||
"storage", NULL, NULL, 32),
|
||||
#endif /* HAVE_USBSTACK */
|
||||
};
|
||||
|
||||
const int nb_settings = sizeof(settings)/sizeof(*settings);
|
||||
|
|
|
@ -17,9 +17,7 @@ drivers/usb/*.[ch]
|
|||
export/*.h
|
||||
include/*.h
|
||||
include/sys/*.h
|
||||
usbstack/*.h
|
||||
usbstack/core/*.c
|
||||
usbstack/drivers/device/*.[ch]
|
||||
usbstack/*.[ch]
|
||||
target/arm/*.[chS]
|
||||
target/arm/archos/av300/*.[chS]
|
||||
target/arm/imx31/gigabeat-s/*.[chS]
|
||||
|
|
|
@ -227,32 +227,14 @@ drivers/audio/mas35xx.c
|
|||
/* 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
|
||||
usbstack/usb_core.c
|
||||
usbstack/usb_storage.c
|
||||
usbstack/usb_benchmark.c
|
||||
#ifdef CPU_PP502x
|
||||
target/arm/usb-drv-pp502x.c
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* USBOTG */
|
||||
#if !defined(SIMULATOR)
|
||||
#if CONFIG_USBOTG == USBOTG_ISP1362
|
||||
drivers/isp1362.c
|
||||
#endif
|
||||
#if defined(SANSA_E200) || defined(SANSA_C200) || !defined(BOOTLOADER)
|
||||
#if CONFIG_USBOTG == USBOTG_M5636
|
||||
drivers/m5636.c
|
||||
#elif CONFIG_USBOTG == USBOTG_ARC
|
||||
#ifdef HAVE_USBSTACK
|
||||
drivers/usb/arcotg_dcd.c
|
||||
#else
|
||||
drivers/usb/arcotg_udc.c
|
||||
#endif
|
||||
#endif /* CONFIG_USBOTG */
|
||||
#endif /* !defined(BOOTLOADER) */
|
||||
#endif /* !defined(SIMULATOR) */
|
||||
|
||||
/* Other Random Hardware */
|
||||
#ifdef HAVE_TSC2100
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,179 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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,
|
||||
struct usb_endpoint_descriptor* desc);
|
||||
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 dtd_complete(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_*/
|
|
@ -1,136 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 by Barry Wardell
|
||||
*
|
||||
* Based on code from the Linux Target Image Builder from Freescale
|
||||
* available at http://www.bitshrine.org/ and
|
||||
* http://www.bitshrine.org/gpp/linux-2.6.16-mx31-usb-2.patch
|
||||
* Adapted for Rockbox in January 2007
|
||||
* Original file: drivers/usb/gadget/arcotg_udc.c
|
||||
*
|
||||
* USB Device Controller Driver
|
||||
* Driver for ARC OTG USB module in the i.MX31 platform, etc.
|
||||
*
|
||||
* Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* Based on mpc-udc.h
|
||||
* Author: Li Yang (leoli@freescale.com)
|
||||
* Jiang Bo (Tanya.jiang@freescale.com)
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "arcotg_udc.h"
|
||||
#include "logf.h"
|
||||
#include "errno.h"
|
||||
|
||||
static int timeout;
|
||||
|
||||
/* @qh_addr is the aligned virt addr of ep QH addr
|
||||
* it is used to set endpointlistaddr Reg */
|
||||
/* was static int dr_controller_setup(void *qh_addr) */
|
||||
int dr_controller_setup(void)
|
||||
{
|
||||
#if 0
|
||||
struct arc_usb_config *config;
|
||||
|
||||
config = udc_controller->config;
|
||||
|
||||
/* before here, make sure usb_slave_regs has been initialized */
|
||||
if (!qh_addr)
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
/* Stop and reset the usb controller */
|
||||
UDC_USBCMD &= ~USB_CMD_RUN;
|
||||
|
||||
UDC_USBCMD |= USB_CMD_CTRL_RESET;
|
||||
|
||||
/* Wait for reset to complete */
|
||||
timeout = 10000000;
|
||||
while ((UDC_USBCMD & USB_CMD_CTRL_RESET) &&
|
||||
--timeout) {
|
||||
continue;
|
||||
}
|
||||
if (timeout == 0) {
|
||||
logf("%s: TIMEOUT", __FUNCTION__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Set the controller as device mode and disable setup lockout */
|
||||
UDC_USBMODE |= (USB_MODE_CTRL_MODE_DEVICE | USB_MODE_SETUP_LOCK_OFF);
|
||||
|
||||
/* Clear the setup status */
|
||||
UDC_USBSTS = 0;
|
||||
#if 0
|
||||
UDC_ENDPOINTLISTADDR = (unsigned int)qh_addr & USB_EP_LIST_ADDRESS_MASK;
|
||||
|
||||
VDBG("qh_addr=0x%x epla_reg=0x%8x", qh_addr, UOG_ASYNCLISTADDR);
|
||||
#endif
|
||||
UDC_PORTSC1 = (UDC_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_UTMI;
|
||||
#if 0
|
||||
if (config->set_vbus_power)
|
||||
config->set_vbus_power(0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* just Enable DR irq reg and Set Dr controller Run */
|
||||
/* was static void dr_controller_run(struct arcotg_udc *udc) */
|
||||
void dr_controller_run(void)
|
||||
{
|
||||
/*Enable DR irq reg */
|
||||
UDC_USBINTR = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN |
|
||||
USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN |
|
||||
USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
|
||||
#if 0
|
||||
/* Clear stopped bit */
|
||||
udc->stopped = 0;
|
||||
#endif
|
||||
/* Set the controller as device mode */
|
||||
UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE;
|
||||
|
||||
/* Set controller to Run */
|
||||
UDC_USBCMD |= USB_CMD_RUN;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* just Enable DR irq reg and Set Dr controller Run */
|
||||
/* was static void dr_controller_stop(struct arcotg_udc *udc) */
|
||||
void dr_controller_stop(void)
|
||||
{
|
||||
#if 0
|
||||
/* if we're in OTG mode, and the Host is currently using the port,
|
||||
* stop now and don't rip the controller out from under the
|
||||
* ehci driver
|
||||
*/
|
||||
if (udc->gadget.is_otg) {
|
||||
if (!(UDC_OTGSC & OTGSC_STS_USB_ID)) {
|
||||
logf("Leaving early");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* disable all INTR */
|
||||
UDC_USBINTR = 0;
|
||||
#if 0
|
||||
/* Set stopped bit */
|
||||
udc->stopped = 1;
|
||||
#endif
|
||||
/* Set controller to Stop */
|
||||
UDC_USBCMD &= ~USB_CMD_RUN;
|
||||
}
|
|
@ -1,318 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 by Barry Wardell
|
||||
*
|
||||
* ARC OTG USB device driver based on code from the Linux Target Image Builder
|
||||
* from Freescale - 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.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Freescale USB device/endpoint management registers
|
||||
*/
|
||||
#ifndef __ARCOTG_UDC_H
|
||||
#define __ARCOTG_UDC_H
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define USB_MAX_ENDPOINTS 8
|
||||
#define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2)
|
||||
#define USB_MAX_CTRL_PAYLOAD 64
|
||||
|
||||
/* USB DR device mode registers (Little Endian) */
|
||||
/* Identification registers */
|
||||
#define UDC_ID (*(volatile unsigned int *)(USB_BASE+0x000))
|
||||
#define UDC_HWGENERAL (*(volatile unsigned int *)(USB_BASE+0x004))
|
||||
#define UDC_HWHOST (*(volatile unsigned int *)(USB_BASE+0x008))
|
||||
#define UDC_HWTXBUF (*(volatile unsigned int *)(USB_BASE+0x010))
|
||||
#define UDC_HWRXBUF (*(volatile unsigned int *)(USB_BASE+0x014))
|
||||
|
||||
/* Capability registers */
|
||||
#define UDC_CAPLENGTH (*(volatile unsigned char *)(USB_BASE+0x100)) /* Capability Register Length */
|
||||
#define UDC_HCIVERSION (*(volatile unsigned short *)(USB_BASE+0x102)) /* Host Controller Interface Version */
|
||||
#define UDC_HCSPARAMS (*(volatile unsigned int *)(USB_BASE+0x104)) /* Host Controller Structual Parameters */
|
||||
#define UDC_HCCPARAMS (*(volatile unsigned int *)(USB_BASE+0x108)) /* Host Controller Capability Parameters */
|
||||
#define UDC_DCIVERSION (*(volatile unsigned short *)(USB_BASE+0x120)) /* Device Controller Interface Version */
|
||||
#define UDC_DCCPARAMS (*(volatile unsigned int *)(USB_BASE+0x124)) /* Device Controller Capability Parameters */
|
||||
|
||||
/* Operation registers */
|
||||
#define UDC_USBCMD (*(volatile unsigned int *)(USB_BASE+0x140)) /* USB Command Register */
|
||||
#define UDC_USBSTS (*(volatile unsigned int *)(USB_BASE+0x144)) /* USB Status Register */
|
||||
#define UDC_USBINTR (*(volatile unsigned int *)(USB_BASE+0x148)) /* USB Interrupt Enable Register */
|
||||
#define UDC_FRINDEX (*(volatile unsigned int *)(USB_BASE+0x14c)) /* Frame Index Register */
|
||||
#define UDC_DEVICEADDR (*(volatile unsigned int *)(USB_BASE+0x154)) /* Device Address */
|
||||
#define UDC_ENDPOINTLISTADDR (*(volatile unsigned int *)(USB_BASE+0x158)) /* Endpoint List Address Register */
|
||||
#define UDC_BURSTSIZE (*(volatile unsigned int *)(USB_BASE+0x160)) /* Master Interface Data Burst Size Register */
|
||||
#define UDC_TXFILLTUNING (*(volatile unsigned int *)(USB_BASE+0x164)) /* Transmit FIFO Tuning Controls Register */
|
||||
#define UDC_ULPIVIEW (*(volatile unsigned int *)(USB_BASE+0x170))
|
||||
#define UDC_CFGFLAG (*(volatile unsigned int *)(USB_BASE+0x180)) /* Configure Flag Register */
|
||||
#define UDC_PORTSC1 (*(volatile unsigned int *)(USB_BASE+0x184)) /* Port 1 Status and Control Register */
|
||||
#define UDC_OTGSC (*(volatile unsigned int *)(USB_BASE+0x1a4)) /* On-The-Go Status and Control */
|
||||
#define UDC_USBMODE (*(volatile unsigned int *)(USB_BASE+0x1a8)) /* USB Mode Register */
|
||||
#define UDC_ENDPTSETUPSTAT (*(volatile unsigned int *)(USB_BASE+0x1ac)) /* Endpoint Setup Status Register */
|
||||
#define UDC_ENDPTPRIME (*(volatile unsigned int *)(USB_BASE+0x1b0)) /* Endpoint Initialization Register */
|
||||
#define UDC_ENDPTFLUSH (*(volatile unsigned int *)(USB_BASE+0x1b4)) /* Endpoint Flush Register */
|
||||
#define UDC_ENDPTSTAT (*(volatile unsigned int *)(USB_BASE+0x1b8)) /* Endpoint Status Register */
|
||||
#define UDC_ENDPTCOMPLETE (*(volatile unsigned int *)(USB_BASE+0x1bc)) /* Endpoint Complete Register */
|
||||
#define UDC_ENDPTCTRL0 (*(volatile unsigned int *)(USB_BASE+0x1c0)) /* Endpoint 0 Control Register */
|
||||
#define UDC_ENDPTCTRL1 (*(volatile unsigned int *)(USB_BASE+0x1c4)) /* Endpoint 1 Control Register */
|
||||
#define UDC_ENDPTCTRL2 (*(volatile unsigned int *)(USB_BASE+0x1c8)) /* Endpoint 2 Control Register */
|
||||
#define UDC_ENDPTCTRL3 (*(volatile unsigned int *)(USB_BASE+0x1cc)) /* Endpoint 3 Control Register */
|
||||
#define UDC_ENDPTCTRL4 (*(volatile unsigned int *)(USB_BASE+0x1d0)) /* Endpoint 4 Control Register */
|
||||
#define UDC_ENDPTCTRL5 (*(volatile unsigned int *)(USB_BASE+0x1d4)) /* Endpoint 5 Control Register */
|
||||
#define UDC_ENDPTCTRL6 (*(volatile unsigned int *)(USB_BASE+0x1d8)) /* Endpoint 6 Control Register */
|
||||
#define UDC_ENDPTCTRL7 (*(volatile unsigned int *)(USB_BASE+0x1dc)) /* Endpoint 7 Control Register */
|
||||
#define UDC_ENDPTCTRL(x) (*(volatile unsigned int *)(USB_BASE+0x1c0+4*(x))) /* Endpoint X Control Register */
|
||||
|
||||
/* ep0 transfer state */
|
||||
#define WAIT_FOR_SETUP 0
|
||||
#define DATA_STATE_XMIT 1
|
||||
#define DATA_STATE_NEED_ZLP 2
|
||||
#define WAIT_FOR_OUT_STATUS 3
|
||||
#define DATA_STATE_RECV 4
|
||||
|
||||
/* Frame Index Register Bit Masks */
|
||||
#define USB_FRINDEX_MASKS (0x3fff)
|
||||
|
||||
/* USB CMD Register Bit Masks */
|
||||
#define USB_CMD_RUN (0x00000001)
|
||||
#define USB_CMD_CTRL_RESET (0x00000002)
|
||||
#define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010)
|
||||
#define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020)
|
||||
#define USB_CMD_INT_AA_DOORBELL (0x00000040)
|
||||
#define USB_CMD_ASP (0x00000300)
|
||||
#define USB_CMD_ASYNC_SCH_PARK_EN (0x00000800)
|
||||
#define USB_CMD_SUTW (0x00002000)
|
||||
#define USB_CMD_ATDTW (0x00004000)
|
||||
#define USB_CMD_ITC (0x00FF0000)
|
||||
|
||||
/* bit 15,3,2 are frame list size */
|
||||
#define USB_CMD_FRAME_SIZE_1024 (0x00000000)
|
||||
#define USB_CMD_FRAME_SIZE_512 (0x00000004)
|
||||
#define USB_CMD_FRAME_SIZE_256 (0x00000008)
|
||||
#define USB_CMD_FRAME_SIZE_128 (0x0000000C)
|
||||
#define USB_CMD_FRAME_SIZE_64 (0x00008000)
|
||||
#define USB_CMD_FRAME_SIZE_32 (0x00008004)
|
||||
#define USB_CMD_FRAME_SIZE_16 (0x00008008)
|
||||
#define USB_CMD_FRAME_SIZE_8 (0x0000800C)
|
||||
|
||||
/* bit 9-8 are async schedule park mode count */
|
||||
#define USB_CMD_ASP_00 (0x00000000)
|
||||
#define USB_CMD_ASP_01 (0x00000100)
|
||||
#define USB_CMD_ASP_10 (0x00000200)
|
||||
#define USB_CMD_ASP_11 (0x00000300)
|
||||
#define USB_CMD_ASP_BIT_POS (8)
|
||||
|
||||
/* bit 23-16 are interrupt threshold control */
|
||||
#define USB_CMD_ITC_NO_THRESHOLD (0x00000000)
|
||||
#define USB_CMD_ITC_1_MICRO_FRM (0x00010000)
|
||||
#define USB_CMD_ITC_2_MICRO_FRM (0x00020000)
|
||||
#define USB_CMD_ITC_4_MICRO_FRM (0x00040000)
|
||||
#define USB_CMD_ITC_8_MICRO_FRM (0x00080000)
|
||||
#define USB_CMD_ITC_16_MICRO_FRM (0x00100000)
|
||||
#define USB_CMD_ITC_32_MICRO_FRM (0x00200000)
|
||||
#define USB_CMD_ITC_64_MICRO_FRM (0x00400000)
|
||||
#define USB_CMD_ITC_BIT_POS (16)
|
||||
|
||||
/* USB STS Register Bit Masks */
|
||||
#define USB_STS_INT (0x00000001)
|
||||
#define USB_STS_ERR (0x00000002)
|
||||
#define USB_STS_PORT_CHANGE (0x00000004)
|
||||
#define USB_STS_FRM_LST_ROLL (0x00000008)
|
||||
#define USB_STS_SYS_ERR (0x00000010)
|
||||
#define USB_STS_IAA (0x00000020)
|
||||
#define USB_STS_RESET (0x00000040)
|
||||
#define USB_STS_SOF (0x00000080)
|
||||
#define USB_STS_SUSPEND (0x00000100)
|
||||
#define USB_STS_HC_HALTED (0x00001000)
|
||||
#define USB_STS_RCL (0x00002000)
|
||||
#define USB_STS_PERIODIC_SCHEDULE (0x00004000)
|
||||
#define USB_STS_ASYNC_SCHEDULE (0x00008000)
|
||||
|
||||
/* USB INTR Register Bit Masks */
|
||||
#define USB_INTR_INT_EN (0x00000001)
|
||||
#define USB_INTR_ERR_INT_EN (0x00000002)
|
||||
#define USB_INTR_PTC_DETECT_EN (0x00000004)
|
||||
#define USB_INTR_FRM_LST_ROLL_EN (0x00000008)
|
||||
#define USB_INTR_SYS_ERR_EN (0x00000010)
|
||||
#define USB_INTR_ASYN_ADV_EN (0x00000020)
|
||||
#define USB_INTR_RESET_EN (0x00000040)
|
||||
#define USB_INTR_SOF_EN (0x00000080)
|
||||
#define USB_INTR_DEVICE_SUSPEND (0x00000100)
|
||||
|
||||
/* Device Address bit masks */
|
||||
#define USB_DEVICE_ADDRESS_MASK (0xFE000000)
|
||||
#define USB_DEVICE_ADDRESS_BIT_POS (25)
|
||||
|
||||
/* endpoint list address bit masks */
|
||||
#define USB_EP_LIST_ADDRESS_MASK (0xfffff800)
|
||||
|
||||
/* PORTSCX Register Bit Masks */
|
||||
#define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001)
|
||||
#define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002)
|
||||
#define PORTSCX_PORT_ENABLE (0x00000004)
|
||||
#define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008)
|
||||
#define PORTSCX_OVER_CURRENT_ACT (0x00000010)
|
||||
#define PORTSCX_OVER_CURRENT_CHG (0x00000020)
|
||||
#define PORTSCX_PORT_FORCE_RESUME (0x00000040)
|
||||
#define PORTSCX_PORT_SUSPEND (0x00000080)
|
||||
#define PORTSCX_PORT_RESET (0x00000100)
|
||||
#define PORTSCX_LINE_STATUS_BITS (0x00000C00)
|
||||
#define PORTSCX_PORT_POWER (0x00001000)
|
||||
#define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000)
|
||||
#define PORTSCX_PORT_TEST_CTRL (0x000F0000)
|
||||
#define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000)
|
||||
#define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000)
|
||||
#define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000)
|
||||
#define PORTSCX_PHY_LOW_POWER_SPD (0x00800000)
|
||||
#define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000)
|
||||
#define PORTSCX_PORT_SPEED_MASK (0x0C000000)
|
||||
#define PORTSCX_PORT_WIDTH (0x10000000)
|
||||
#define PORTSCX_PHY_TYPE_SEL (0xC0000000)
|
||||
|
||||
/* bit 11-10 are line status */
|
||||
#define PORTSCX_LINE_STATUS_SE0 (0x00000000)
|
||||
#define PORTSCX_LINE_STATUS_JSTATE (0x00000400)
|
||||
#define PORTSCX_LINE_STATUS_KSTATE (0x00000800)
|
||||
#define PORTSCX_LINE_STATUS_UNDEF (0x00000C00)
|
||||
#define PORTSCX_LINE_STATUS_BIT_POS (10)
|
||||
|
||||
/* bit 15-14 are port indicator control */
|
||||
#define PORTSCX_PIC_OFF (0x00000000)
|
||||
#define PORTSCX_PIC_AMBER (0x00004000)
|
||||
#define PORTSCX_PIC_GREEN (0x00008000)
|
||||
#define PORTSCX_PIC_UNDEF (0x0000C000)
|
||||
#define PORTSCX_PIC_BIT_POS (14)
|
||||
|
||||
/* bit 19-16 are port test control */
|
||||
#define PORTSCX_PTC_DISABLE (0x00000000)
|
||||
#define PORTSCX_PTC_JSTATE (0x00010000)
|
||||
#define PORTSCX_PTC_KSTATE (0x00020000)
|
||||
#define PORTSCX_PTC_SEQNAK (0x00030000)
|
||||
#define PORTSCX_PTC_PACKET (0x00040000)
|
||||
#define PORTSCX_PTC_FORCE_EN (0x00050000)
|
||||
#define PORTSCX_PTC_BIT_POS (16)
|
||||
|
||||
/* bit 27-26 are port speed */
|
||||
#define PORTSCX_PORT_SPEED_FULL (0x00000000)
|
||||
#define PORTSCX_PORT_SPEED_LOW (0x04000000)
|
||||
#define PORTSCX_PORT_SPEED_HIGH (0x08000000)
|
||||
#define PORTSCX_PORT_SPEED_UNDEF (0x0C000000)
|
||||
#define PORTSCX_SPEED_BIT_POS (26)
|
||||
|
||||
/* bit 28 is parallel transceiver width for UTMI interface */
|
||||
#define PORTSCX_PTW (0x10000000)
|
||||
#define PORTSCX_PTW_8BIT (0x00000000)
|
||||
#define PORTSCX_PTW_16BIT (0x10000000)
|
||||
|
||||
/* bit 31-30 are port transceiver select */
|
||||
#define PORTSCX_PTS_UTMI (0x00000000)
|
||||
#define PORTSCX_PTS_ULPI (0x80000000)
|
||||
#define PORTSCX_PTS_FSLS (0xC0000000)
|
||||
#define PORTSCX_PTS_BIT_POS (30)
|
||||
|
||||
/* USB MODE Register Bit Masks */
|
||||
#define USB_MODE_CTRL_MODE_IDLE (0x00000000)
|
||||
#define USB_MODE_CTRL_MODE_DEVICE (0x00000002)
|
||||
#define USB_MODE_CTRL_MODE_HOST (0x00000003)
|
||||
#define USB_MODE_CTRL_MODE_RSV (0x00000001)
|
||||
#define USB_MODE_SETUP_LOCK_OFF (0x00000008)
|
||||
#define USB_MODE_STREAM_DISABLE (0x00000010)
|
||||
|
||||
/* Endpoint Flush Register */
|
||||
#define EPFLUSH_TX_OFFSET (0x00010000)
|
||||
#define EPFLUSH_RX_OFFSET (0x00000000)
|
||||
|
||||
/* Endpoint Setup Status bit masks */
|
||||
#define EP_SETUP_STATUS_MASK (0x0000003F)
|
||||
#define EP_SETUP_STATUS_EP0 (0x00000001)
|
||||
|
||||
/* ENDPOINTCTRLx Register Bit Masks */
|
||||
#define EPCTRL_TX_ENABLE (0x00800000)
|
||||
#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */
|
||||
#define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */
|
||||
#define EPCTRL_TX_TYPE (0x000C0000)
|
||||
#define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */
|
||||
#define EPCTRL_TX_EP_STALL (0x00010000)
|
||||
#define EPCTRL_RX_ENABLE (0x00000080)
|
||||
#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */
|
||||
#define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */
|
||||
#define EPCTRL_RX_TYPE (0x0000000C)
|
||||
#define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */
|
||||
#define EPCTRL_RX_EP_STALL (0x00000001)
|
||||
|
||||
/* bit 19-18 and 3-2 are endpoint type */
|
||||
#define EPCTRL_EP_TYPE_CONTROL (0)
|
||||
#define EPCTRL_EP_TYPE_ISO (1)
|
||||
#define EPCTRL_EP_TYPE_BULK (2)
|
||||
#define EPCTRL_EP_TYPE_INTERRUPT (3)
|
||||
#define EPCTRL_TX_EP_TYPE_SHIFT (18)
|
||||
#define EPCTRL_RX_EP_TYPE_SHIFT (2)
|
||||
|
||||
/* SNOOPn Register Bit Masks */
|
||||
#define SNOOP_ADDRESS_MASK (0xFFFFF000)
|
||||
#define SNOOP_SIZE_ZERO (0x00) /* snooping disable */
|
||||
#define SNOOP_SIZE_4KB (0x0B) /* 4KB snoop size */
|
||||
#define SNOOP_SIZE_8KB (0x0C)
|
||||
#define SNOOP_SIZE_16KB (0x0D)
|
||||
#define SNOOP_SIZE_32KB (0x0E)
|
||||
#define SNOOP_SIZE_64KB (0x0F)
|
||||
#define SNOOP_SIZE_128KB (0x10)
|
||||
#define SNOOP_SIZE_256KB (0x11)
|
||||
#define SNOOP_SIZE_512KB (0x12)
|
||||
#define SNOOP_SIZE_1MB (0x13)
|
||||
#define SNOOP_SIZE_2MB (0x14)
|
||||
#define SNOOP_SIZE_4MB (0x15)
|
||||
#define SNOOP_SIZE_8MB (0x16)
|
||||
#define SNOOP_SIZE_16MB (0x17)
|
||||
#define SNOOP_SIZE_32MB (0x18)
|
||||
#define SNOOP_SIZE_64MB (0x19)
|
||||
#define SNOOP_SIZE_128MB (0x1A)
|
||||
#define SNOOP_SIZE_256MB (0x1B)
|
||||
#define SNOOP_SIZE_512MB (0x1C)
|
||||
#define SNOOP_SIZE_1GB (0x1D)
|
||||
#define SNOOP_SIZE_2GB (0x1E) /* 2GB snoop size */
|
||||
|
||||
/* pri_ctrl Register Bit Masks */
|
||||
#define PRI_CTRL_PRI_LVL1 (0x0000000C)
|
||||
#define PRI_CTRL_PRI_LVL0 (0x00000003)
|
||||
|
||||
/* si_ctrl Register Bit Masks */
|
||||
#define SI_CTRL_ERR_DISABLE (0x00000010)
|
||||
#define SI_CTRL_IDRC_DISABLE (0x00000008)
|
||||
#define SI_CTRL_RD_SAFE_EN (0x00000004)
|
||||
#define SI_CTRL_RD_PREFETCH_DISABLE (0x00000002)
|
||||
#define SI_CTRL_RD_PREFEFETCH_VAL (0x00000001)
|
||||
|
||||
/* control Register Bit Masks */
|
||||
#define USB_CTRL_IOENB (0x00000004)
|
||||
#define USB_CTRL_ULPI_INT0EN (0x00000001)
|
||||
|
||||
/* Externally used functions */
|
||||
int dr_controller_setup(void);
|
||||
void dr_controller_run(void);
|
||||
void dr_controller_stop(void);
|
||||
|
||||
#endif /* __ARCOTG_UDC_H */
|
|
@ -162,10 +162,10 @@
|
|||
/* USB On-the-go */
|
||||
#define CONFIG_USBOTG USBOTG_ARC
|
||||
|
||||
/* enable these for the experimental usb stack
|
||||
/* enable these for the experimental usb stack */
|
||||
#define HAVE_USBSTACK
|
||||
#define USBSTACK_CAPS CONTROLLER_DEVICE
|
||||
*/
|
||||
#define USB_VENDOR_ID 0x0781
|
||||
#define USB_PRODUCT_ID 0x7450
|
||||
|
||||
/* Virtual LED (icon) */
|
||||
#define CONFIG_LED LED_VIRTUAL
|
||||
|
|
|
@ -157,11 +157,10 @@
|
|||
/* USB On-the-go */
|
||||
#define CONFIG_USBOTG USBOTG_ARC
|
||||
|
||||
/* enable these for the experimental usb stack
|
||||
/* enable these for the experimental usb stack */
|
||||
#define HAVE_USBSTACK
|
||||
#define USBSTACK_CAPS CONTROLLER_DEVICE
|
||||
*/
|
||||
|
||||
#define USB_VENDOR_ID 0x0781
|
||||
#define USB_PRODUCT_ID 0x7421
|
||||
|
||||
/* Virtual LED (icon) */
|
||||
#define CONFIG_LED LED_VIRTUAL
|
||||
|
|
|
@ -152,10 +152,10 @@
|
|||
/* USB On-the-go */
|
||||
#define CONFIG_USBOTG USBOTG_ARC
|
||||
|
||||
/* enable these for the experimental usb stack
|
||||
/* enable these for the experimental usb stack */
|
||||
#define HAVE_USBSTACK
|
||||
#define USBSTACK_CAPS CONTROLLER_DEVICE
|
||||
*/
|
||||
#define USB_VENDOR_ID 0x0B70
|
||||
#define USB_PRODUCT_ID 0x00BA
|
||||
|
||||
/* Virtual LED (icon) */
|
||||
#define CONFIG_LED LED_VIRTUAL
|
||||
|
|
|
@ -135,10 +135,10 @@
|
|||
/* USB On-the-go */
|
||||
#define CONFIG_USBOTG USBOTG_ARC
|
||||
|
||||
/* enable these for the experimental usb stack
|
||||
/* enable these for the experimental usb stack */
|
||||
#define HAVE_USBSTACK
|
||||
#define USBSTACK_CAPS CONTROLLER_DEVICE
|
||||
*/
|
||||
#define USB_VENDOR_ID 0x0B70
|
||||
#define USB_PRODUCT_ID 0x00BA
|
||||
|
||||
/* Virtual LED (icon) */
|
||||
#define CONFIG_LED LED_VIRTUAL
|
||||
|
|
|
@ -1,355 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* 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_*/
|
|
@ -92,8 +92,8 @@
|
|||
#define TIMER2_IRQ 1
|
||||
#define MAILBOX_IRQ 4
|
||||
#define IIS_IRQ 10
|
||||
#define USB_IRQ 20
|
||||
#define IDE_IRQ 23
|
||||
#define USB_IRQ 24
|
||||
#define FIREWIRE_IRQ 25
|
||||
#define HI_IRQ 30
|
||||
#define GPIO0_IRQ (32+0) /* Ports A..D */
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
#define USBPOWER_BUTTON BUTTON_MENU
|
||||
#define USBPOWER_BTN_IGNORE BUTTON_BACK
|
||||
#elif CONFIG_KEYPAD == IRIVER_H10_PAD
|
||||
#define USBPOWER_BUTTON BUTTON_NONE
|
||||
#define USBPOWER_BUTTON BUTTON_RIGHT
|
||||
#define USBPOWER_BTN_IGNORE BUTTON_POWER
|
||||
#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
|
||||
(CONFIG_KEYPAD == SANSA_C200_PAD)
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2007 by Christian Gmeiner
|
||||
* Copyright (C) 2007 by Björn Stenberg
|
||||
*
|
||||
* 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.
|
||||
|
@ -16,18 +16,40 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef USB_CORE_H
|
||||
#define USB_CORE_H
|
||||
|
||||
#ifndef _SERIAL_H_
|
||||
#define _SERIAL_H_
|
||||
#include "usb_ch9.h"
|
||||
|
||||
#include "usbstack/core.h"
|
||||
#if defined(CPU_PP)
|
||||
#define USB_IRAM_ORIGIN ((unsigned char *)0x4000c000)
|
||||
#define USB_IRAM_SIZE ((size_t)0xc000)
|
||||
#endif
|
||||
|
||||
/* register serial driver in usb stack */
|
||||
void usb_serial_driver_init(void);
|
||||
/* endpoints */
|
||||
enum {
|
||||
EP_CONTROL = 0,
|
||||
EP_RX,
|
||||
EP_TX,
|
||||
NUM_ENDPOINTS
|
||||
};
|
||||
|
||||
int usb_serial_driver_bind(void* controller_ops);
|
||||
void usb_serial_driver_unbind(void);
|
||||
int usb_serial_driver_request(struct usb_ctrlrequest* req);
|
||||
void usb_serial_driver_speed(enum usb_device_speed speed);
|
||||
/* queue events */
|
||||
#define USB_TRANSFER_COMPLETE 1
|
||||
|
||||
struct queue_msg {
|
||||
int endpoint;
|
||||
int length;
|
||||
void* data;
|
||||
};
|
||||
|
||||
extern int usb_max_pkt_size;
|
||||
|
||||
void usb_core_init(void);
|
||||
void usb_core_exit(void);
|
||||
void usb_core_control_request(struct usb_ctrlrequest* req);
|
||||
void usb_core_transfer_complete(int endpoint, bool in);
|
||||
void usb_core_bus_reset(void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /*_SERIAL_H_*/
|
|
@ -5,9 +5,9 @@
|
|||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2007 by Christian Gmeiner
|
||||
* Copyright (C) 2007 by Björn Stenberg
|
||||
*
|
||||
* 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.
|
||||
|
@ -16,18 +16,20 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef ARCOTG_DRV_H
|
||||
#define ARCOTG_DRV_H
|
||||
#include "usb_ch9.h"
|
||||
#include "kernel.h"
|
||||
|
||||
#ifndef _STORGAGE_H_
|
||||
#define _STORGAGE_H_
|
||||
void usb_drv_init(void);
|
||||
void usb_drv_exit(void);
|
||||
void usb_drv_int(void);
|
||||
void usb_drv_stall(int endpoint, bool stall);
|
||||
void usb_drv_send(int endpoint, void* ptr, int length);
|
||||
void usb_drv_recv(int endpoint, void* ptr, int length);
|
||||
void usb_drv_ack(struct usb_ctrlrequest* req);
|
||||
void usb_drv_set_address(int address);
|
||||
void usb_drv_reset_endpoint(int endpoint, bool send);
|
||||
void usb_drv_wait(int endpoint, bool send);
|
||||
|
||||
#include "usbstack/core.h"
|
||||
|
||||
/* register storage driver in usb stack */
|
||||
void usb_storage_driver_init(void);
|
||||
|
||||
int usb_storage_driver_bind(void* controller_ops);
|
||||
void usb_storage_driver_unbind(void);
|
||||
int usb_storage_driver_request(struct usb_ctrlrequest* req);
|
||||
void usb_storage_driver_speed(enum usb_device_speed speed);
|
||||
|
||||
#endif /*_STORGAGE_H_*/
|
||||
#endif
|
|
@ -1,63 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 */
|
||||
|
||||
/* usb stack configuration */
|
||||
#ifndef USBSTACK_CAPS
|
||||
#define USBSTACK_CAPS 0 /* default: use no controller */
|
||||
#endif
|
||||
|
||||
#define CONTROLLER_DEVICE (1 << 0)
|
||||
#define CONTROLLER_HOST (1 << 1)
|
||||
|
||||
/*
|
||||
* 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_*/
|
|
@ -21,6 +21,9 @@
|
|||
#include "i2s.h"
|
||||
#include "i2c-pp.h"
|
||||
#include "as3514.h"
|
||||
#ifdef HAVE_USBSTACK
|
||||
#include "usb_drv.h"
|
||||
#endif
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
extern void TIMER1(void);
|
||||
|
@ -33,19 +36,12 @@ extern void button_int(void);
|
|||
extern void clickwheel_int(void);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
#include "usbstack/core.h"
|
||||
#endif
|
||||
|
||||
void irq(void)
|
||||
{
|
||||
if(CURRENT_CORE == CPU)
|
||||
{
|
||||
if (CPU_INT_STAT & TIMER1_MASK) {
|
||||
TIMER1();
|
||||
#ifdef HAVE_USBSTACK
|
||||
usb_stack_irq();
|
||||
#endif
|
||||
} else if (CPU_INT_STAT & TIMER2_MASK)
|
||||
TIMER2();
|
||||
#if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */
|
||||
|
@ -70,6 +66,11 @@ void irq(void)
|
|||
if (GPIOL_INT_STAT & 0x08)
|
||||
microsd_int();
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_USBSTACK
|
||||
else if (CPU_INT_STAT & USB_MASK) {
|
||||
usb_drv_int();
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (COP_INT_STAT & TIMER2_MASK)
|
||||
|
|
|
@ -0,0 +1,624 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id: $
|
||||
*
|
||||
* Driver for ARC USBOTG Device Controller
|
||||
*
|
||||
* Copyright (C) 2007 by Björn Stenberg
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "string.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "usb_core.h"
|
||||
//#define LOGF_ENABLE
|
||||
#include "logf.h"
|
||||
|
||||
/* USB device mode registers (Little Endian) */
|
||||
|
||||
#define REG_ID (*(volatile unsigned int *)(USB_BASE+0x000))
|
||||
#define REG_HWGENERAL (*(volatile unsigned int *)(USB_BASE+0x004))
|
||||
#define REG_CAPLENGTH (*(volatile unsigned char*)(USB_BASE+0x100))
|
||||
#define REG_DCIVERSION (*(volatile unsigned int *)(USB_BASE+0x120))
|
||||
#define REG_DCCPARAMS (*(volatile unsigned int *)(USB_BASE+0x124))
|
||||
#define REG_USBCMD (*(volatile unsigned int *)(USB_BASE+0x140))
|
||||
#define REG_USBSTS (*(volatile unsigned int *)(USB_BASE+0x144))
|
||||
#define REG_USBINTR (*(volatile unsigned int *)(USB_BASE+0x148))
|
||||
#define REG_FRINDEX (*(volatile unsigned int *)(USB_BASE+0x14c))
|
||||
#define REG_DEVICEADDR (*(volatile unsigned int *)(USB_BASE+0x154))
|
||||
#define REG_ENDPOINTLISTADDR (*(volatile unsigned int *)(USB_BASE+0x158))
|
||||
#define REG_BURSTSIZE (*(volatile unsigned int *)(USB_BASE+0x160))
|
||||
#define REG_CONFIGFLAG (*(volatile unsigned int *)(USB_BASE+0x180))
|
||||
#define REG_PORTSC1 (*(volatile unsigned int *)(USB_BASE+0x184))
|
||||
#define REG_OTGSC (*(volatile unsigned int *)(USB_BASE+0x1a4))
|
||||
#define REG_USBMODE (*(volatile unsigned int *)(USB_BASE+0x1a8))
|
||||
#define REG_ENDPTSETUPSTAT (*(volatile unsigned int *)(USB_BASE+0x1ac))
|
||||
#define REG_ENDPTPRIME (*(volatile unsigned int *)(USB_BASE+0x1b0))
|
||||
#define REG_ENDPTFLUSH (*(volatile unsigned int *)(USB_BASE+0x1b4))
|
||||
#define REG_ENDPTSTATUS (*(volatile unsigned int *)(USB_BASE+0x1b8))
|
||||
#define REG_ENDPTCOMPLETE (*(volatile unsigned int *)(USB_BASE+0x1bc))
|
||||
#define REG_ENDPTCTRL0 (*(volatile unsigned int *)(USB_BASE+0x1c0))
|
||||
#define REG_ENDPTCTRL1 (*(volatile unsigned int *)(USB_BASE+0x1c4))
|
||||
#define REG_ENDPTCTRL2 (*(volatile unsigned int *)(USB_BASE+0x1c8))
|
||||
#define REG_ENDPTCTRL(_x_) (*(volatile unsigned int *)(USB_BASE+0x1c0+4*(_x_)))
|
||||
|
||||
/* Frame Index Register Bit Masks */
|
||||
#define USB_FRINDEX_MASKS (0x3fff)
|
||||
|
||||
/* USB CMD Register Bit Masks */
|
||||
#define USBCMD_RUN (0x00000001)
|
||||
#define USBCMD_CTRL_RESET (0x00000002)
|
||||
#define USBCMD_PERIODIC_SCHEDULE_EN (0x00000010)
|
||||
#define USBCMD_ASYNC_SCHEDULE_EN (0x00000020)
|
||||
#define USBCMD_INT_AA_DOORBELL (0x00000040)
|
||||
#define USBCMD_ASP (0x00000300)
|
||||
#define USBCMD_ASYNC_SCH_PARK_EN (0x00000800)
|
||||
#define USBCMD_SUTW (0x00002000)
|
||||
#define USBCMD_ATDTW (0x00004000)
|
||||
#define USBCMD_ITC (0x00FF0000)
|
||||
|
||||
/* bit 15,3,2 are frame list size */
|
||||
#define USBCMD_FRAME_SIZE_1024 (0x00000000)
|
||||
#define USBCMD_FRAME_SIZE_512 (0x00000004)
|
||||
#define USBCMD_FRAME_SIZE_256 (0x00000008)
|
||||
#define USBCMD_FRAME_SIZE_128 (0x0000000C)
|
||||
#define USBCMD_FRAME_SIZE_64 (0x00008000)
|
||||
#define USBCMD_FRAME_SIZE_32 (0x00008004)
|
||||
#define USBCMD_FRAME_SIZE_16 (0x00008008)
|
||||
#define USBCMD_FRAME_SIZE_8 (0x0000800C)
|
||||
|
||||
/* bit 9-8 are async schedule park mode count */
|
||||
#define USBCMD_ASP_00 (0x00000000)
|
||||
#define USBCMD_ASP_01 (0x00000100)
|
||||
#define USBCMD_ASP_10 (0x00000200)
|
||||
#define USBCMD_ASP_11 (0x00000300)
|
||||
#define USBCMD_ASP_BIT_POS (8)
|
||||
|
||||
/* bit 23-16 are interrupt threshold control */
|
||||
#define USBCMD_ITC_NO_THRESHOLD (0x00000000)
|
||||
#define USBCMD_ITC_1_MICRO_FRM (0x00010000)
|
||||
#define USBCMD_ITC_2_MICRO_FRM (0x00020000)
|
||||
#define USBCMD_ITC_4_MICRO_FRM (0x00040000)
|
||||
#define USBCMD_ITC_8_MICRO_FRM (0x00080000)
|
||||
#define USBCMD_ITC_16_MICRO_FRM (0x00100000)
|
||||
#define USBCMD_ITC_32_MICRO_FRM (0x00200000)
|
||||
#define USBCMD_ITC_64_MICRO_FRM (0x00400000)
|
||||
#define USBCMD_ITC_BIT_POS (16)
|
||||
|
||||
/* USB STS Register Bit Masks */
|
||||
#define USBSTS_INT (0x00000001)
|
||||
#define USBSTS_ERR (0x00000002)
|
||||
#define USBSTS_PORT_CHANGE (0x00000004)
|
||||
#define USBSTS_FRM_LST_ROLL (0x00000008)
|
||||
#define USBSTS_SYS_ERR (0x00000010) /* not used */
|
||||
#define USBSTS_IAA (0x00000020)
|
||||
#define USBSTS_RESET (0x00000040)
|
||||
#define USBSTS_SOF (0x00000080)
|
||||
#define USBSTS_SUSPEND (0x00000100)
|
||||
#define USBSTS_HC_HALTED (0x00001000)
|
||||
#define USBSTS_RCL (0x00002000)
|
||||
#define USBSTS_PERIODIC_SCHEDULE (0x00004000)
|
||||
#define USBSTS_ASYNC_SCHEDULE (0x00008000)
|
||||
|
||||
/* USB INTR Register Bit Masks */
|
||||
#define USBINTR_INT_EN (0x00000001)
|
||||
#define USBINTR_ERR_INT_EN (0x00000002)
|
||||
#define USBINTR_PTC_DETECT_EN (0x00000004)
|
||||
#define USBINTR_FRM_LST_ROLL_EN (0x00000008)
|
||||
#define USBINTR_SYS_ERR_EN (0x00000010)
|
||||
#define USBINTR_ASYN_ADV_EN (0x00000020)
|
||||
#define USBINTR_RESET_EN (0x00000040)
|
||||
#define USBINTR_SOF_EN (0x00000080)
|
||||
#define USBINTR_DEVICE_SUSPEND (0x00000100)
|
||||
|
||||
/* Device Address bit masks */
|
||||
#define USBDEVICEADDRESS_MASK (0xFE000000)
|
||||
#define USBDEVICEADDRESS_BIT_POS (25)
|
||||
|
||||
/* endpoint list address bit masks */
|
||||
#define USB_EP_LIST_ADDRESS_MASK (0xfffff800)
|
||||
|
||||
/* PORTSCX Register Bit Masks */
|
||||
#define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001)
|
||||
#define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002)
|
||||
#define PORTSCX_PORT_ENABLE (0x00000004)
|
||||
#define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008)
|
||||
#define PORTSCX_OVER_CURRENT_ACT (0x00000010)
|
||||
#define PORTSCX_OVER_CURRENT_CHG (0x00000020)
|
||||
#define PORTSCX_PORT_FORCE_RESUME (0x00000040)
|
||||
#define PORTSCX_PORT_SUSPEND (0x00000080)
|
||||
#define PORTSCX_PORT_RESET (0x00000100)
|
||||
#define PORTSCX_LINE_STATUS_BITS (0x00000C00)
|
||||
#define PORTSCX_PORT_POWER (0x00001000)
|
||||
#define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000)
|
||||
#define PORTSCX_PORT_TEST_CTRL (0x000F0000)
|
||||
#define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000)
|
||||
#define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000)
|
||||
#define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000)
|
||||
#define PORTSCX_PHY_LOW_POWER_SPD (0x00800000)
|
||||
#define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000)
|
||||
#define PORTSCX_PORT_SPEED_MASK (0x0C000000)
|
||||
#define PORTSCX_PORT_WIDTH (0x10000000)
|
||||
#define PORTSCX_PHY_TYPE_SEL (0xC0000000)
|
||||
|
||||
/* bit 11-10 are line status */
|
||||
#define PORTSCX_LINE_STATUS_SE0 (0x00000000)
|
||||
#define PORTSCX_LINE_STATUS_JSTATE (0x00000400)
|
||||
#define PORTSCX_LINE_STATUS_KSTATE (0x00000800)
|
||||
#define PORTSCX_LINE_STATUS_UNDEF (0x00000C00)
|
||||
#define PORTSCX_LINE_STATUS_BIT_POS (10)
|
||||
|
||||
/* bit 15-14 are port indicator control */
|
||||
#define PORTSCX_PIC_OFF (0x00000000)
|
||||
#define PORTSCX_PIC_AMBER (0x00004000)
|
||||
#define PORTSCX_PIC_GREEN (0x00008000)
|
||||
#define PORTSCX_PIC_UNDEF (0x0000C000)
|
||||
#define PORTSCX_PIC_BIT_POS (14)
|
||||
|
||||
/* bit 19-16 are port test control */
|
||||
#define PORTSCX_PTC_DISABLE (0x00000000)
|
||||
#define PORTSCX_PTC_JSTATE (0x00010000)
|
||||
#define PORTSCX_PTC_KSTATE (0x00020000)
|
||||
#define PORTSCX_PTC_SEQNAK (0x00030000)
|
||||
#define PORTSCX_PTC_PACKET (0x00040000)
|
||||
#define PORTSCX_PTC_FORCE_EN (0x00050000)
|
||||
#define PORTSCX_PTC_BIT_POS (16)
|
||||
|
||||
/* bit 27-26 are port speed */
|
||||
#define PORTSCX_PORT_SPEED_FULL (0x00000000)
|
||||
#define PORTSCX_PORT_SPEED_LOW (0x04000000)
|
||||
#define PORTSCX_PORT_SPEED_HIGH (0x08000000)
|
||||
#define PORTSCX_PORT_SPEED_UNDEF (0x0C000000)
|
||||
#define PORTSCX_SPEED_BIT_POS (26)
|
||||
|
||||
/* bit 28 is parallel transceiver width for UTMI interface */
|
||||
#define PORTSCX_PTW (0x10000000)
|
||||
#define PORTSCX_PTW_8BIT (0x00000000)
|
||||
#define PORTSCX_PTW_16BIT (0x10000000)
|
||||
|
||||
/* bit 31-30 are port transceiver select */
|
||||
#define PORTSCX_PTS_UTMI (0x00000000)
|
||||
#define PORTSCX_PTS_ULPI (0x80000000)
|
||||
#define PORTSCX_PTS_FSLS (0xC0000000)
|
||||
#define PORTSCX_PTS_BIT_POS (30)
|
||||
|
||||
/* USB MODE Register Bit Masks */
|
||||
#define USBMODE_CTRL_MODE_IDLE (0x00000000)
|
||||
#define USBMODE_CTRL_MODE_DEVICE (0x00000002)
|
||||
#define USBMODE_CTRL_MODE_HOST (0x00000003)
|
||||
#define USBMODE_CTRL_MODE_RSV (0x00000001)
|
||||
#define USBMODE_SETUP_LOCK_OFF (0x00000008)
|
||||
#define USBMODE_STREAM_DISABLE (0x00000010)
|
||||
|
||||
/* Endpoint Flush Register */
|
||||
#define EPFLUSH_TX_OFFSET (0x00010000)
|
||||
#define EPFLUSH_RX_OFFSET (0x00000000)
|
||||
|
||||
/* Endpoint Setup Status bit masks */
|
||||
#define EPSETUP_STATUS_MASK (0x0000003F)
|
||||
#define EPSETUP_STATUS_EP0 (0x00000001)
|
||||
|
||||
/* ENDPOINTCTRLx Register Bit Masks */
|
||||
#define EPCTRL_TX_ENABLE (0x00800000)
|
||||
#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */
|
||||
#define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */
|
||||
#define EPCTRL_TX_TYPE (0x000C0000)
|
||||
#define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */
|
||||
#define EPCTRL_TX_EP_STALL (0x00010000)
|
||||
#define EPCTRL_RX_ENABLE (0x00000080)
|
||||
#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */
|
||||
#define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */
|
||||
#define EPCTRL_RX_TYPE (0x0000000C)
|
||||
#define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */
|
||||
#define EPCTRL_RX_EP_STALL (0x00000001)
|
||||
|
||||
/* bit 19-18 and 3-2 are endpoint type */
|
||||
#define EPCTRL_EP_TYPE_CONTROL (0)
|
||||
#define EPCTRL_EP_TYPE_ISO (1)
|
||||
#define EPCTRL_EP_TYPE_BULK (2)
|
||||
#define EPCTRL_EP_TYPE_INTERRUPT (3)
|
||||
#define EPCTRL_TX_EP_TYPE_SHIFT (18)
|
||||
#define EPCTRL_RX_EP_TYPE_SHIFT (2)
|
||||
|
||||
/* pri_ctrl Register Bit Masks */
|
||||
#define PRI_CTRL_PRI_LVL1 (0x0000000C)
|
||||
#define PRI_CTRL_PRI_LVL0 (0x00000003)
|
||||
|
||||
/* si_ctrl Register Bit Masks */
|
||||
#define SI_CTRL_ERR_DISABLE (0x00000010)
|
||||
#define SI_CTRL_IDRC_DISABLE (0x00000008)
|
||||
#define SI_CTRL_RD_SAFE_EN (0x00000004)
|
||||
#define SI_CTRL_RD_PREFETCH_DISABLE (0x00000002)
|
||||
#define SI_CTRL_RD_PREFEFETCH_VAL (0x00000001)
|
||||
|
||||
/* control Register Bit Masks */
|
||||
#define USB_CTRL_IOENB (0x00000004)
|
||||
#define USB_CTRL_ULPI_INT0EN (0x00000001)
|
||||
|
||||
#define QH_MULT_POS (30)
|
||||
#define QH_ZLT_SEL (0x20000000)
|
||||
#define QH_MAX_PKT_LEN_POS (16)
|
||||
#define QH_IOS (0x00008000)
|
||||
#define QH_NEXT_TERMINATE (0x00000001)
|
||||
#define QH_IOC (0x00008000)
|
||||
#define QH_MULTO (0x00000C00)
|
||||
#define QH_STATUS_HALT (0x00000040)
|
||||
#define QH_STATUS_ACTIVE (0x00000080)
|
||||
#define EP_QUEUE_CURRENT_OFFSET_MASK (0x00000FFF)
|
||||
#define EP_QUEUE_HEAD_NEXT_POINTER_MASK (0xFFFFFFE0)
|
||||
#define EP_QUEUE_FRINDEX_MASK (0x000007FF)
|
||||
#define EP_MAX_LENGTH_TRANSFER (0x4000)
|
||||
|
||||
#define DTD_NEXT_TERMINATE (0x00000001)
|
||||
#define DTD_IOC (0x00008000)
|
||||
#define DTD_STATUS_ACTIVE (0x00000080)
|
||||
#define DTD_STATUS_HALTED (0x00000040)
|
||||
#define DTD_STATUS_DATA_BUFF_ERR (0x00000020)
|
||||
#define DTD_STATUS_TRANSACTION_ERR (0x00000008)
|
||||
#define DTD_RESERVED_FIELDS (0x80007300)
|
||||
#define DTD_ADDR_MASK (0xFFFFFFE0)
|
||||
#define DTD_PACKET_SIZE (0x7FFF0000)
|
||||
#define DTD_LENGTH_BIT_POS (16)
|
||||
#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \
|
||||
DTD_STATUS_DATA_BUFF_ERR | \
|
||||
DTD_STATUS_TRANSACTION_ERR)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */
|
||||
struct transfer_descriptor {
|
||||
unsigned int next_td_ptr; /* Next TD pointer(31-5), T(0) set
|
||||
indicate invalid */
|
||||
unsigned int size_ioc_sts; /* Total bytes (30-16), IOC (15),
|
||||
MultO(11-10), STS (7-0) */
|
||||
unsigned int buff_ptr0; /* Buffer pointer Page 0 */
|
||||
unsigned int buff_ptr1; /* Buffer pointer Page 1 */
|
||||
unsigned int buff_ptr2; /* Buffer pointer Page 2 */
|
||||
unsigned int buff_ptr3; /* Buffer pointer Page 3 */
|
||||
unsigned int buff_ptr4; /* Buffer pointer Page 4 */
|
||||
unsigned int reserved;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static struct transfer_descriptor _td_array[NUM_ENDPOINTS*2] __attribute((aligned (32)));
|
||||
static struct transfer_descriptor* td_array;
|
||||
|
||||
/* manual: 32.13.1 Endpoint Queue Head (dQH) */
|
||||
struct queue_head {
|
||||
unsigned int max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len
|
||||
and IOS(15) */
|
||||
unsigned int curr_dtd_ptr; /* Current dTD Pointer(31-5) */
|
||||
struct transfer_descriptor dtd; /* dTD overlay */
|
||||
unsigned int setup_buffer[2]; /* Setup data 8 bytes */
|
||||
unsigned int reserved[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
static struct queue_head _qh_array[NUM_ENDPOINTS*2] __attribute((aligned (2048)));
|
||||
static struct queue_head* qh_array;
|
||||
|
||||
|
||||
static const unsigned int pipe2mask[NUM_ENDPOINTS*2] = {
|
||||
0x01, 0x010000,
|
||||
0x02, 0x020000,
|
||||
0x04, 0x040000,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static void transfer_completed(void);
|
||||
static void prime_transfer(int endpoint, void* ptr, int len, bool send);
|
||||
static void bus_reset(void);
|
||||
static void init_queue_heads(void);
|
||||
static void init_endpoints(void);
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* manual: 32.14.1 Device Controller Initialization */
|
||||
void usb_drv_init(void)
|
||||
{
|
||||
REG_USBCMD &= ~USBCMD_RUN;
|
||||
udelay(50000);
|
||||
REG_USBCMD |= USBCMD_CTRL_RESET;
|
||||
while (REG_USBCMD & USBCMD_CTRL_RESET);
|
||||
|
||||
REG_USBMODE = USBMODE_CTRL_MODE_DEVICE;
|
||||
|
||||
td_array = (struct transfer_descriptor*)UNCACHED_ADDR(&_td_array);
|
||||
qh_array = (struct queue_head*)UNCACHED_ADDR(&_qh_array);
|
||||
init_queue_heads();
|
||||
memset(td_array, 0, sizeof _td_array);
|
||||
|
||||
REG_ENDPOINTLISTADDR = (unsigned int)qh_array;
|
||||
REG_DEVICEADDR = 0;
|
||||
|
||||
/* enable USB interrupts */
|
||||
REG_USBINTR =
|
||||
USBINTR_INT_EN |
|
||||
USBINTR_ERR_INT_EN |
|
||||
USBINTR_PTC_DETECT_EN |
|
||||
USBINTR_RESET_EN |
|
||||
USBINTR_SYS_ERR_EN;
|
||||
|
||||
/* enable USB IRQ in CPU */
|
||||
CPU_INT_EN |= USB_MASK;
|
||||
|
||||
/* go go go */
|
||||
REG_USBCMD |= USBCMD_RUN;
|
||||
|
||||
logf("usb_drv_init() finished");
|
||||
logf("usb id %x", REG_ID);
|
||||
logf("usb dciversion %x", REG_DCIVERSION);
|
||||
logf("usb dccparams %x", REG_DCCPARAMS);
|
||||
|
||||
/* now a bus reset will occur. see bus_reset() */
|
||||
}
|
||||
|
||||
void usb_drv_exit(void)
|
||||
{
|
||||
/* disable interrupts */
|
||||
REG_USBINTR = 0;
|
||||
|
||||
/* stop usb controller */
|
||||
REG_USBCMD &= ~USBCMD_RUN;
|
||||
}
|
||||
|
||||
void usb_drv_int(void)
|
||||
{
|
||||
unsigned int status = REG_USBSTS;
|
||||
|
||||
#if 0
|
||||
if (status & USBSTS_INT) logf("int: usb ioc");
|
||||
if (status & USBSTS_ERR) logf("int: usb err");
|
||||
if (status & USBSTS_PORT_CHANGE) logf("int: portchange");
|
||||
if (status & USBSTS_RESET) logf("int: reset");
|
||||
if (status & USBSTS_SYS_ERR) logf("int: syserr");
|
||||
#endif
|
||||
|
||||
/* usb transaction interrupt */
|
||||
if (status & USBSTS_INT) {
|
||||
REG_USBSTS |= USBSTS_INT;
|
||||
|
||||
/* a control packet? */
|
||||
if (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0) {
|
||||
/* copy setup data from packet */
|
||||
unsigned int tmp[2];
|
||||
tmp[0] = qh_array[0].setup_buffer[0];
|
||||
tmp[1] = qh_array[0].setup_buffer[1];
|
||||
|
||||
/* acknowledge packet recieved */
|
||||
REG_ENDPTSETUPSTAT |= EPSETUP_STATUS_EP0;
|
||||
|
||||
usb_core_control_request((struct usb_ctrlrequest*)tmp);
|
||||
}
|
||||
|
||||
if (REG_ENDPTCOMPLETE)
|
||||
transfer_completed();
|
||||
}
|
||||
|
||||
/* error interrupt */
|
||||
if (status & USBSTS_ERR) {
|
||||
REG_USBSTS |= USBSTS_ERR;
|
||||
logf("usb error int");
|
||||
}
|
||||
|
||||
/* reset interrupt */
|
||||
if (status & USBSTS_RESET) {
|
||||
REG_USBSTS |= USBSTS_RESET;
|
||||
bus_reset();
|
||||
usb_core_bus_reset(); /* tell mom */
|
||||
}
|
||||
|
||||
/* port change */
|
||||
if (status & USBSTS_PORT_CHANGE) {
|
||||
REG_USBSTS |= USBSTS_PORT_CHANGE;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_drv_stall(int endpoint, bool stall)
|
||||
{
|
||||
logf("%sstall %d", stall?"":"un", endpoint);
|
||||
|
||||
if (stall) {
|
||||
REG_ENDPTCTRL(endpoint) |= EPCTRL_RX_EP_STALL;
|
||||
REG_ENDPTCTRL(endpoint) |= EPCTRL_TX_EP_STALL;
|
||||
}
|
||||
else {
|
||||
REG_ENDPTCTRL(endpoint) &= ~EPCTRL_RX_EP_STALL;
|
||||
REG_ENDPTCTRL(endpoint) &= ~EPCTRL_TX_EP_STALL;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_drv_send(int endpoint, void* ptr, int length)
|
||||
{
|
||||
prime_transfer(endpoint, ptr, length, true);
|
||||
}
|
||||
|
||||
void usb_drv_recv(int endpoint, void* ptr, int length)
|
||||
{
|
||||
//logf("usbrecv(%x, %d)", ptr, length);
|
||||
prime_transfer(endpoint, ptr, length, false);
|
||||
}
|
||||
|
||||
void usb_drv_wait(int endpoint, bool send)
|
||||
{
|
||||
int pipe = endpoint * 2 + (send ? 1 : 0);
|
||||
struct queue_head* qh = &qh_array[pipe];
|
||||
|
||||
while (qh->dtd.size_ioc_sts & QH_STATUS_ACTIVE) {
|
||||
if (REG_USBSTS & USBSTS_RESET)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void usb_drv_set_address(int address)
|
||||
{
|
||||
REG_DEVICEADDR = address << USBDEVICEADDRESS_BIT_POS;
|
||||
init_endpoints();
|
||||
}
|
||||
|
||||
void usb_drv_reset_endpoint(int endpoint, bool send)
|
||||
{
|
||||
int pipe = endpoint * 2 + (send ? 1 : 0);
|
||||
unsigned int mask = pipe2mask[pipe];
|
||||
REG_ENDPTFLUSH = mask;
|
||||
while (REG_ENDPTFLUSH & mask);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* manual: 32.14.5.2 */
|
||||
static void prime_transfer(int endpoint, void* ptr, int len, bool send)
|
||||
{
|
||||
int timeout;
|
||||
int pipe = endpoint * 2 + (send ? 1 : 0);
|
||||
unsigned int mask = pipe2mask[pipe];
|
||||
struct transfer_descriptor* td = &td_array[pipe];
|
||||
struct queue_head* qh = &qh_array[pipe];
|
||||
|
||||
if (send && endpoint > EP_CONTROL) {
|
||||
logf("usb: sent %d bytes", len);
|
||||
}
|
||||
|
||||
memset(td, 0, sizeof(struct transfer_descriptor));
|
||||
td->next_td_ptr = DTD_NEXT_TERMINATE;
|
||||
td->size_ioc_sts = (len << DTD_LENGTH_BIT_POS) |
|
||||
DTD_STATUS_ACTIVE | DTD_IOC;
|
||||
td->buff_ptr0 = (unsigned int)ptr;
|
||||
td->buff_ptr1 = (unsigned int)ptr + 0x1000;
|
||||
td->buff_ptr2 = (unsigned int)ptr + 0x2000;
|
||||
td->buff_ptr3 = (unsigned int)ptr + 0x3000;
|
||||
td->buff_ptr4 = (unsigned int)ptr + 0x4000;
|
||||
td->reserved = len;
|
||||
qh->dtd.next_td_ptr = (unsigned int)td;
|
||||
qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE);
|
||||
|
||||
REG_ENDPTPRIME |= mask;
|
||||
|
||||
timeout = 10000;
|
||||
while ((REG_ENDPTPRIME & mask) && --timeout) {
|
||||
if (REG_USBSTS & USBSTS_RESET)
|
||||
break;
|
||||
}
|
||||
if (!timeout) {
|
||||
logf("prime timeout");
|
||||
}
|
||||
|
||||
if (!(REG_ENDPTSTATUS & mask)) {
|
||||
logf("no prime! %d %d %x", endpoint, pipe, qh->dtd.size_ioc_sts & 0xff );
|
||||
}
|
||||
|
||||
if (send) {
|
||||
/* wait for transfer to finish */
|
||||
timeout = 100000;
|
||||
while ((td->size_ioc_sts & DTD_STATUS_ACTIVE) && --timeout) {
|
||||
if (REG_ENDPTCOMPLETE & mask)
|
||||
REG_ENDPTCOMPLETE |= mask;
|
||||
|
||||
if (REG_USBSTS & USBSTS_RESET)
|
||||
return;
|
||||
}
|
||||
if (!timeout) {
|
||||
logf("td never finished");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_completed(void)
|
||||
{
|
||||
int i;
|
||||
unsigned int mask = REG_ENDPTCOMPLETE;
|
||||
REG_ENDPTCOMPLETE |= mask;
|
||||
|
||||
//logf("usb comp %x", mask);
|
||||
|
||||
for (i=0; i<NUM_ENDPOINTS; i++) {
|
||||
int x;
|
||||
for (x=0; x<2; x++) {
|
||||
int pipe = i * 2 + x;
|
||||
if (mask & pipe2mask[pipe])
|
||||
usb_core_transfer_complete(i, x ? true : false);
|
||||
|
||||
if ((mask & pipe2mask[pipe]) &&
|
||||
(td_array[pipe].size_ioc_sts & DTD_ERROR_MASK)) {
|
||||
logf("pipe %d err %x", pipe, td_array[pipe].size_ioc_sts & DTD_ERROR_MASK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* manual: 32.14.2.1 Bus Reset */
|
||||
static void bus_reset(void)
|
||||
{
|
||||
int i;
|
||||
logf("usb bus_reset");
|
||||
|
||||
REG_DEVICEADDR = 0;
|
||||
REG_ENDPTSETUPSTAT = REG_ENDPTSETUPSTAT;
|
||||
REG_ENDPTCOMPLETE = REG_ENDPTCOMPLETE;
|
||||
|
||||
for (i=0; i<100; i++) {
|
||||
if (!REG_ENDPTPRIME)
|
||||
break;
|
||||
|
||||
if (REG_USBSTS & USBSTS_RESET) {
|
||||
logf("usb: double reset");
|
||||
return;
|
||||
}
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
if (REG_ENDPTPRIME) {
|
||||
logf("usb: short reset timeout");
|
||||
}
|
||||
|
||||
REG_ENDPTFLUSH = ~0;
|
||||
//while (REG_ENDPTFLUSH);
|
||||
|
||||
if (!(REG_PORTSC1 & PORTSCX_PORT_RESET)) {
|
||||
logf("usb: slow reset!");
|
||||
}
|
||||
}
|
||||
|
||||
/* manual: 32.14.4.1 Queue Head Initialization */
|
||||
static void init_queue_heads(void)
|
||||
{
|
||||
memset(qh_array, 0, sizeof _qh_array);
|
||||
|
||||
/*** control ***/
|
||||
qh_array[EP_CONTROL].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS | QH_IOS;
|
||||
qh_array[EP_CONTROL].dtd.next_td_ptr = QH_NEXT_TERMINATE;
|
||||
qh_array[EP_CONTROL+1].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS;
|
||||
qh_array[EP_CONTROL+1].dtd.next_td_ptr = QH_NEXT_TERMINATE;
|
||||
|
||||
/*** bulk ***/
|
||||
qh_array[EP_RX*2].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS;
|
||||
qh_array[EP_RX*2].dtd.next_td_ptr = QH_NEXT_TERMINATE;
|
||||
qh_array[EP_TX*2+1].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS;
|
||||
qh_array[EP_TX*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE;
|
||||
}
|
||||
|
||||
static void init_endpoints(void)
|
||||
{
|
||||
/* bulk */
|
||||
REG_ENDPTCTRL(EP_RX) =
|
||||
EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE |
|
||||
(EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT) |
|
||||
(EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT);
|
||||
|
||||
REG_ENDPTCTRL(EP_TX) =
|
||||
EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE |
|
||||
(EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT) |
|
||||
(EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT);
|
||||
}
|
|
@ -27,15 +27,13 @@
|
|||
#include "button.h"
|
||||
#include "ata.h"
|
||||
#include "string.h"
|
||||
#include "arcotg_udc.h"
|
||||
|
||||
#ifdef HAVE_USBSTACK
|
||||
#include "usbstack.h"
|
||||
#include "usb_core.h"
|
||||
#endif
|
||||
|
||||
void usb_init_device(void)
|
||||
{
|
||||
int r0;
|
||||
/* enable usb module */
|
||||
GPO32_ENABLE |= 0x200;
|
||||
|
||||
outl(inl(0x7000002C) | 0x3000000, 0x7000002C);
|
||||
|
@ -46,41 +44,9 @@ void usb_init_device(void)
|
|||
|
||||
DEV_INIT2 |= 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_INIT2 |= INIT_USB;
|
||||
DEV_EN |= DEV_USB;
|
||||
while ((inl(0x70000028) & 0x80) == 0);
|
||||
outl(inl(0x70000028) | 0x2, 0x70000028);
|
||||
|
||||
udelay(0x186A0);
|
||||
|
||||
#ifndef HAVE_USBSTACK
|
||||
dr_controller_setup();
|
||||
#endif
|
||||
|
||||
#if defined(IPOD_COLOR) || defined(IPOD_4G) \
|
||||
|| defined(IPOD_MINI) || defined(IPOD_MINI2G)
|
||||
/* GPIO C bit 1 is firewire detect */
|
||||
|
@ -92,9 +58,10 @@ void usb_init_device(void)
|
|||
void usb_enable(bool on)
|
||||
{
|
||||
#ifdef HAVE_USBSTACK
|
||||
if (!on) {
|
||||
usb_stack_stop();
|
||||
}
|
||||
if (on)
|
||||
usb_core_init();
|
||||
else
|
||||
usb_core_exit();
|
||||
#else
|
||||
/* This device specific code will eventually give way to proper USB
|
||||
handling, which should be the same for all PP502x targets. */
|
||||
|
@ -131,11 +98,6 @@ void usb_enable(bool on)
|
|||
|
||||
int usb_detect(void)
|
||||
{
|
||||
static int countdown = 0;
|
||||
static int status = USB_EXTRACTED;
|
||||
static bool prev_usbstatus1 = false;
|
||||
bool usbstatus1, usbstatus2;
|
||||
|
||||
#if defined(IPOD_COLOR) || defined(IPOD_4G) \
|
||||
|| defined(IPOD_MINI) || defined(IPOD_MINI2G)
|
||||
/* GPIO C bit 1 is firewire detect */
|
||||
|
@ -143,75 +105,19 @@ int usb_detect(void)
|
|||
return USB_INSERTED;
|
||||
#endif
|
||||
|
||||
if (countdown > 0)
|
||||
{
|
||||
countdown--;
|
||||
|
||||
usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false;
|
||||
if ((countdown == 0) || usbstatus2)
|
||||
{
|
||||
countdown = 0;
|
||||
status = usbstatus2 ? USB_INSERTED : USB_POWERED;
|
||||
#ifndef HAVE_USBSTACK
|
||||
dr_controller_stop();
|
||||
#endif
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* UDC_ID should have the bit format:
|
||||
[31:24] = 0x0
|
||||
[23:16] = 0x22 (Revision number)
|
||||
[15:14] = 0x3 (Reserved)
|
||||
[13:8] = 0x3a (NID - 1's compliment of ID)
|
||||
[7:6] = 0x0 (Reserved)
|
||||
[5:0] = 0x05 (ID) */
|
||||
if (UDC_ID != 0x22FA05) {
|
||||
/* This should never occur - do we even need to test? */
|
||||
return USB_EXTRACTED;
|
||||
}
|
||||
|
||||
usbstatus1 = (UDC_OTGSC & 0x800) ? true : false;
|
||||
|
||||
if (usbstatus1 == prev_usbstatus1)
|
||||
{
|
||||
/* Nothing has changed, so just return previous status */
|
||||
return status;
|
||||
}
|
||||
prev_usbstatus1 = usbstatus1;
|
||||
|
||||
if (!usbstatus1)
|
||||
{ /* We have just been disconnected */
|
||||
status = USB_EXTRACTED;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* We now know that we have just been connected to either a charger
|
||||
or a computer */
|
||||
|
||||
if((button_status() & ~USBPOWER_BTN_IGNORE) == USBPOWER_BUTTON)
|
||||
{
|
||||
/* The user wants to charge, so it doesn't matter what we are
|
||||
connected to. */
|
||||
|
||||
status = USB_POWERED;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Run the USB controller for long enough to detect if we're connected
|
||||
to a computer, then stop it again. */
|
||||
|
||||
#ifndef HAVE_USBSTACK
|
||||
dr_controller_run();
|
||||
#else
|
||||
usb_stack_start();
|
||||
#if defined(SANSA_C200)
|
||||
/* GPIO H bit 1 is usb detect */
|
||||
if (GPIOH_INPUT_VAL & 0x02)
|
||||
return USB_INSERTED;
|
||||
#elif defined(SANSA_E200)
|
||||
/* GPIO B bit 4 is usb detect */
|
||||
if (GPIOB_INPUT_VAL & 0x10)
|
||||
return USB_INSERTED;
|
||||
#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
|
||||
/* GPIO L bit 2 is usb detect */
|
||||
if (GPIOL_INPUT_VAL & 0x4)
|
||||
return USB_INSERTED;
|
||||
#endif
|
||||
|
||||
/* Wait for 50 ticks (500ms) before deciding there is no computer
|
||||
attached. The required value varied a lot between different users
|
||||
when this feature was being tested. */
|
||||
|
||||
countdown = 50;
|
||||
|
||||
return status;
|
||||
return USB_EXTRACTED;
|
||||
}
|
||||
|
|
|
@ -87,9 +87,11 @@ static void usb_slave_mode(bool on)
|
|||
else
|
||||
{
|
||||
DEBUGF("Leaving USB slave mode\n");
|
||||
|
||||
|
||||
#ifndef HAVE_USBSTACK
|
||||
/* Let the ISDx00 settle */
|
||||
sleep(HZ*1);
|
||||
#endif
|
||||
|
||||
usb_enable(false);
|
||||
|
||||
|
@ -402,7 +404,7 @@ bool usb_charging_enabled(void)
|
|||
/* TODO: implement it for other targets... */
|
||||
#endif
|
||||
|
||||
logf("usb_charging_enabled: %s\n", rc ? "true" : "false" );
|
||||
logf("usb charging %s", rc ? "enabled" : "disabled" );
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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_CONTROLLER_H_
|
||||
#define _USBSTACK_CONTROLLER_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;
|
||||
};
|
||||
|
||||
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, struct usb_endpoint_descriptor* desc);
|
||||
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_*/
|
|
@ -1,64 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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_CORE_H_
|
||||
#define _USBSTACK_CORE_H_
|
||||
|
||||
#include "linkedlist.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "logf.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "usbstack.h"
|
||||
|
||||
#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_*/
|
|
@ -1,82 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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;
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,402 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 "config.h"
|
||||
|
||||
#include "usbstack.h"
|
||||
#include "usbstack/core.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)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* 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 */
|
||||
ret = driver->bind(usbcore.active_controller->controller_ops);
|
||||
|
||||
if (ret != 0) {
|
||||
logf("binding of %s failed", driver->name);
|
||||
usbcore.active_controller->device_driver = NULL;
|
||||
usbcore.device_driver = NULL;
|
||||
}
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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!! */
|
||||
|
||||
/* set address of used ep in desc */
|
||||
desc->bEndpointAddress |= ep->ep_num;
|
||||
ep->desc = desc;
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 by Christian Gmeiner
|
||||
*
|
||||
* Based on linux/drivers/usb/gadget/usbstring.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"
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
int usb_stack_get_string(struct usb_string* strings, int id, uint8_t* buf)
|
||||
{
|
||||
struct usb_string* tmp;
|
||||
char* sp, *dp;
|
||||
int len;
|
||||
|
||||
/* if id is 0, then we need to send back all supported
|
||||
* languages. In our case we only support one
|
||||
* language: en-us (0x0409) */
|
||||
if (id == 0) {
|
||||
buf [0] = 4;
|
||||
buf [1] = USB_DT_STRING;
|
||||
buf [2] = (uint8_t) 0x0409;
|
||||
buf [3] = (uint8_t) (0x0409 >> 8);
|
||||
return 4;
|
||||
}
|
||||
|
||||
/* look for string */
|
||||
for (tmp = strings; tmp && tmp->s; tmp++) {
|
||||
if (tmp->id == id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* did we found it? */
|
||||
if (!tmp || !tmp->s) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = MIN ((size_t) 126, strlen (tmp->s));
|
||||
memset(buf + 2, 0, 2 * len);
|
||||
|
||||
/* convert to utf-16le */
|
||||
sp = (char*)tmp->s;
|
||||
dp = (char*)&buf[2];
|
||||
|
||||
while (*sp) {
|
||||
*dp++ = *sp++;
|
||||
*dp++ = 0;
|
||||
}
|
||||
|
||||
/* write len and tag */
|
||||
buf [0] = (len + 1) * 2;
|
||||
buf [1] = USB_DT_STRING;
|
||||
|
||||
return buf[0];
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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_DEVICE_H_
|
||||
#define _USBSTACK_DEVICE_H_
|
||||
|
||||
/*
|
||||
* usb device driver
|
||||
*/
|
||||
struct usb_device_driver {
|
||||
const char* name;
|
||||
int (*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);
|
||||
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_*/
|
|
@ -1,358 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 "usb_serial.h"
|
||||
#include "usbstack/utils.h"
|
||||
|
||||
static struct usb_dcd_controller_ops* ops;
|
||||
|
||||
struct usb_device_driver usb_serial_driver = {
|
||||
.name = "serial",
|
||||
.bind = usb_serial_driver_bind,
|
||||
.unbind = usb_serial_driver_unbind,
|
||||
.request = usb_serial_driver_request,
|
||||
.suspend = NULL,
|
||||
.resume = NULL,
|
||||
.speed = usb_serial_driver_speed,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* usb descriptors */
|
||||
|
||||
#define MANUFACTURER_STR_ID 1
|
||||
#define PRODUCT_STR_ID 2
|
||||
#define SERIAL_STR_ID 3
|
||||
#define BULK_CONFIG_STR_ID 4
|
||||
#define DATA_STR_ID 5
|
||||
|
||||
/* static strings, in UTF-8 */
|
||||
static struct usb_string strings[] = {
|
||||
{ MANUFACTURER_STR_ID, "RockBox" },
|
||||
{ PRODUCT_STR_ID, "RockBox Serial Driver" },
|
||||
{ SERIAL_STR_ID, "0" },
|
||||
{ BULK_CONFIG_STR_ID, "Serial Bulk" },
|
||||
{ DATA_STR_ID, "Serial Data" },
|
||||
};
|
||||
|
||||
#define 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 = MANUFACTURER_STR_ID,
|
||||
.iProduct = PRODUCT_STR_ID,
|
||||
.iSerialNumber = 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 = BULK_CONFIG_ID,
|
||||
.iConfiguration = 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 = DATA_STR_ID,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor serial_fs_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_fs_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_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &serial_bulk_interface_desc,
|
||||
(struct usb_descriptor_header *) &serial_fs_in_desc,
|
||||
(struct usb_descriptor_header *) &serial_fs_out_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* USB 2.0 */
|
||||
static struct usb_endpoint_descriptor serial_hs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 512,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor serial_hs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 512,
|
||||
};
|
||||
|
||||
struct usb_descriptor_header *serial_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &serial_bulk_interface_desc,
|
||||
(struct usb_descriptor_header *) &serial_hs_in_desc,
|
||||
(struct usb_descriptor_header *) &serial_hs_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;
|
||||
struct usb_descriptor_header** descriptors;
|
||||
};
|
||||
|
||||
static struct device dev;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
void usb_serial_driver_init(void)
|
||||
{
|
||||
logf("usb serial: register");
|
||||
usb_device_driver_register(&usb_serial_driver);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
int 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_fs_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_fs_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;
|
||||
|
||||
/* update hs descriptors as we asume that endpoints
|
||||
are the same for fs and hs */
|
||||
serial_hs_in_desc.bEndpointAddress = serial_fs_in_desc.bEndpointAddress;
|
||||
serial_hs_out_desc.bEndpointAddress = serial_fs_out_desc.bEndpointAddress;
|
||||
|
||||
return 0;
|
||||
|
||||
autoconf_fail:
|
||||
logf("failed to find endpoints");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void usb_serial_driver_unbind(void) {
|
||||
|
||||
/* disable endpoints... */
|
||||
}
|
||||
|
||||
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;
|
||||
break;
|
||||
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
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;
|
||||
|
||||
case USB_DT_STRING:
|
||||
logf("usb serial: sending string desc");
|
||||
ret = usb_stack_get_string(strings, request->wValue & 0xff,
|
||||
buf);
|
||||
ret = MIN(ret, request->wLength);
|
||||
res.buf = buf;
|
||||
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_HIGH:
|
||||
logf("usb serial: using highspeed");
|
||||
dev.descriptors = serial_hs_function;
|
||||
break;
|
||||
default:
|
||||
logf("usb serial: using fullspeed");
|
||||
dev.descriptors = serial_fs_function;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* helper functions */
|
||||
|
||||
static int config_buf(uint8_t *buf, uint8_t type, unsigned index)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* TODO check index*/
|
||||
(void)index;
|
||||
|
||||
len = usb_stack_configdesc(&serial_bulk_config_desc, buf, BUFFER_SIZE,
|
||||
dev.descriptors);
|
||||
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, (struct usb_endpoint_descriptor*)dev.descriptors[1]);
|
||||
logf("setup %s", dev.out->name);
|
||||
ops->enable(dev.out, (struct usb_endpoint_descriptor*)dev.descriptors[2]);
|
||||
|
||||
/* store config */
|
||||
logf("using config %d", config);
|
||||
dev.used_config = config;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,387 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 "usb_storage.h"
|
||||
#include "usbstack/utils.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_dcd_controller_ops* ops;
|
||||
|
||||
struct usb_device_driver usb_storage_driver = {
|
||||
.name = "storage",
|
||||
.bind = usb_storage_driver_bind,
|
||||
.unbind = usb_storage_driver_unbind,
|
||||
.request = usb_storage_driver_request,
|
||||
.suspend = NULL,
|
||||
.resume = NULL,
|
||||
.speed = usb_storage_driver_speed,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#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 */
|
||||
|
||||
#define MANUFACTURER_STR_ID 1
|
||||
#define PRODUCT_STR_ID 2
|
||||
#define SERIAL_STR_ID 3
|
||||
#define CONFIG_STR_ID 4
|
||||
#define DATA_STR_ID 5
|
||||
|
||||
/* static strings, in UTF-8 */
|
||||
static struct usb_string strings[] = {
|
||||
{ MANUFACTURER_STR_ID, "RockBox" },
|
||||
{ PRODUCT_STR_ID, "RockBox Storage Driver" },
|
||||
{ SERIAL_STR_ID, "0" },
|
||||
{ CONFIG_STR_ID, "Storage Bulk" },
|
||||
{ DATA_STR_ID, "Storage Data" },
|
||||
};
|
||||
|
||||
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,
|
||||
.idVendor = 0xffff,
|
||||
.idProduct = 0x0001,
|
||||
.iManufacturer = MANUFACTURER_STR_ID,
|
||||
.iProduct = PRODUCT_STR_ID,
|
||||
.iSerialNumber = SERIAL_STR_ID,
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
static struct usb_config_descriptor storage_config_desc = {
|
||||
.bLength = USB_DT_CONFIG_SIZE,
|
||||
.bDescriptorType = USB_DT_CONFIG,
|
||||
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = CONFIG_STR_ID,
|
||||
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
|
||||
.bMaxPower = 250, /* 500mA in 2mA units */
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor storage_interface_desc = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
|
||||
.bInterfaceSubClass = SUBCL_SCSI,
|
||||
.bInterfaceProtocol = PROTO_BULK,
|
||||
.iInterface = DATA_STR_ID,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor storage_fs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 64,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor storage_fs_bulk_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 64,
|
||||
};
|
||||
|
||||
static struct usb_qualifier_descriptor storage_qualifier_desc = {
|
||||
.bLength = sizeof(struct usb_qualifier_descriptor),
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = 0,
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
struct usb_descriptor_header *storage_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &storage_interface_desc,
|
||||
(struct usb_descriptor_header *) &storage_fs_bulk_in_desc,
|
||||
(struct usb_descriptor_header *) &storage_fs_bulk_out_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* USB 2.0 */
|
||||
static struct usb_endpoint_descriptor storage_hs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 512,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor storage_hs_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_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &storage_interface_desc,
|
||||
(struct usb_descriptor_header *) &storage_hs_bulk_in_desc,
|
||||
(struct usb_descriptor_header *) &storage_hs_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);
|
||||
static int set_interface_alt_setting(int interface_alt_setting);
|
||||
|
||||
struct device {
|
||||
struct usb_ep* in;
|
||||
struct usb_ep* out;
|
||||
struct usb_ep* intr;
|
||||
uint32_t used_config;
|
||||
uint32_t used_interface_alt_setting;
|
||||
struct usb_descriptor_header** descriptors;
|
||||
};
|
||||
|
||||
static struct device dev;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
void usb_storage_driver_init(void)
|
||||
{
|
||||
logf("usb storage: register");
|
||||
usb_device_driver_register(&usb_storage_driver);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* device driver ops */
|
||||
|
||||
int usb_storage_driver_bind(void* controler_ops)
|
||||
{
|
||||
ops = controler_ops;
|
||||
|
||||
/* serach and asign endpoints */
|
||||
usb_ep_autoconfig_reset();
|
||||
|
||||
dev.in = usb_ep_autoconfig(&storage_fs_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_fs_bulk_out_desc);
|
||||
if (!dev.out) {
|
||||
goto autoconf_fail;
|
||||
}
|
||||
dev.out->claimed = true;
|
||||
logf("usb storage: out: %s", dev.out->name);
|
||||
|
||||
/* update device decsriptor */
|
||||
storage_device_desc.bMaxPacketSize0 = ops->ep0->maxpacket;
|
||||
|
||||
/* update hs descriptors as we asume that endpoints
|
||||
are the same for fs and hs */
|
||||
storage_hs_bulk_in_desc.bEndpointAddress =
|
||||
storage_fs_bulk_in_desc.bEndpointAddress;
|
||||
storage_hs_bulk_out_desc.bEndpointAddress =
|
||||
storage_fs_bulk_out_desc.bEndpointAddress;
|
||||
|
||||
return 0;
|
||||
|
||||
autoconf_fail:
|
||||
logf("failed to find endpoints");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void usb_storage_driver_unbind(void)
|
||||
{
|
||||
|
||||
/* disable 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_DEVICE_QUALIFIER:
|
||||
logf("usb storage: sending qualifier dec");
|
||||
ret = MIN(sizeof(struct usb_qualifier_descriptor),
|
||||
request->wLength);
|
||||
res.buf = &storage_qualifier_desc;
|
||||
break;
|
||||
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
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;
|
||||
|
||||
case USB_DT_STRING:
|
||||
logf("usb storage: sending string desc");
|
||||
ret = usb_stack_get_string(strings, request->wValue & 0xff,
|
||||
buf);
|
||||
ret = MIN(ret, request->wLength);
|
||||
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_GET_CONFIGURATION:
|
||||
logf("usb storage: get configuration");
|
||||
ret = 1;
|
||||
res.buf = &dev.used_config;
|
||||
break;
|
||||
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
logf("usb storage: get interface");
|
||||
ret = 1;
|
||||
res.buf = &dev.used_interface_alt_setting;
|
||||
break;
|
||||
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
logf("usb storage: set interface");
|
||||
ret = set_interface_alt_setting(request->wValue);
|
||||
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;
|
||||
}
|
||||
|
||||
void usb_storage_driver_speed(enum usb_device_speed speed)
|
||||
{
|
||||
switch (speed) {
|
||||
case USB_SPEED_HIGH:
|
||||
logf("usb storage: using highspeed");
|
||||
dev.descriptors = storage_hs_function;
|
||||
break;
|
||||
default:
|
||||
logf("usb storage: using fullspeed");
|
||||
dev.descriptors = storage_fs_function;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* S/GET CONFIGURATION helpers */
|
||||
|
||||
static int config_buf(uint8_t *buf, uint8_t type, unsigned index)
|
||||
{
|
||||
int len;
|
||||
|
||||
(void)index;
|
||||
|
||||
len = usb_stack_configdesc(&storage_config_desc, buf, BUFFER_SIZE,
|
||||
dev.descriptors);
|
||||
logf("result %d", len);
|
||||
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, (struct usb_endpoint_descriptor*)dev.descriptors[1]);
|
||||
logf("setup %s", dev.out->name);
|
||||
ops->enable(dev.out, (struct usb_endpoint_descriptor*)dev.descriptors[2]);
|
||||
|
||||
dev.used_config = config;
|
||||
|
||||
/* setup buffers */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_interface_alt_setting(int interface_alt_setting)
|
||||
{
|
||||
dev.used_interface_alt_setting = interface_alt_setting;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2007 by Björn Stenberg
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "usb_core.h"
|
||||
#include "usb_drv.h"
|
||||
//#define LOGF_ENABLE
|
||||
#include "logf.h"
|
||||
|
||||
static int current_length;
|
||||
|
||||
static unsigned char _input_buffer[16384];
|
||||
static unsigned char* input_buffer = USB_IRAM_ORIGIN + 1024;
|
||||
|
||||
static void ack_control(struct usb_ctrlrequest* req);
|
||||
|
||||
static enum {
|
||||
IDLE,
|
||||
SENDING,
|
||||
RECEIVING
|
||||
} state = IDLE;
|
||||
|
||||
|
||||
void usb_benchmark_init(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<128; i++)
|
||||
input_buffer[i] = i;
|
||||
}
|
||||
|
||||
void usb_benchmark_control_request(struct usb_ctrlrequest* req)
|
||||
{
|
||||
int todo;
|
||||
//usb_max_pkt_size = sizeof _input_buffer;
|
||||
usb_max_pkt_size = 64;
|
||||
|
||||
switch (req->bRequest) {
|
||||
case 1: /* read */
|
||||
ack_control(req);
|
||||
current_length = req->wValue * req->wIndex;
|
||||
logf("bench: read %d", current_length);
|
||||
todo = MIN(usb_max_pkt_size, current_length);
|
||||
state = SENDING;
|
||||
usb_drv_reset_endpoint(EP_TX, true);
|
||||
usb_drv_send(EP_TX, &input_buffer, todo);
|
||||
current_length -= todo;
|
||||
break;
|
||||
|
||||
case 2: /* write */
|
||||
ack_control(req);
|
||||
current_length = req->wValue * req->wIndex;
|
||||
logf("bench: write %d", current_length);
|
||||
state = RECEIVING;
|
||||
usb_drv_reset_endpoint(EP_RX, false);
|
||||
usb_drv_recv(EP_RX, &input_buffer, sizeof _input_buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_benchmark_transfer_complete(int endpoint, bool in)
|
||||
{
|
||||
(void)in;
|
||||
|
||||
/* see what remains to transfer */
|
||||
if (current_length == 0) {
|
||||
logf("we're done");
|
||||
state = IDLE;
|
||||
return; /* we're done */
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case SENDING: {
|
||||
int todo = MIN(usb_max_pkt_size, current_length);
|
||||
if (endpoint == EP_RX) {
|
||||
logf("unexpected ep_rx");
|
||||
break;
|
||||
}
|
||||
|
||||
logf("bench: %d more tx", current_length);
|
||||
usb_drv_send(EP_TX, &input_buffer, todo);
|
||||
current_length -= todo;
|
||||
input_buffer[0]++;
|
||||
break;
|
||||
}
|
||||
|
||||
case RECEIVING:
|
||||
if (endpoint == EP_TX) {
|
||||
logf("unexpected ep_tx");
|
||||
break;
|
||||
}
|
||||
|
||||
/* re-prime endpoint */
|
||||
usb_drv_recv(EP_RX, &input_buffer, sizeof _input_buffer);
|
||||
input_buffer[0]++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void ack_control(struct usb_ctrlrequest* req)
|
||||
{
|
||||
if (req->bRequestType & 0x80)
|
||||
usb_drv_recv(EP_CONTROL, NULL, 0);
|
||||
else
|
||||
usb_drv_send(EP_CONTROL, NULL, 0);
|
||||
}
|
|
@ -5,9 +5,9 @@
|
|||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2007 by Peter D'Hoye
|
||||
* Copyright (C) 2007 by Björn Stenberg
|
||||
*
|
||||
* 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.
|
||||
|
@ -16,10 +16,11 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef USB_BENCHMARK_H
|
||||
#define USB_BENCHMARK_H
|
||||
|
||||
#ifndef _USBSTACK_UTILS_H_
|
||||
#define _USBSTACK_UTILS_H_
|
||||
void usb_benchmark_init(void);
|
||||
void usb_benchmark_control_request(struct usb_ctrlrequest* req);
|
||||
void usb_benchmark_transfer_complete(int endpoint, bool in);
|
||||
|
||||
int usb_stack_get_string(struct usb_string* strings, int id, uint8_t* buf);
|
||||
|
||||
#endif /*_USBSTACK_UTILS_H_*/
|
||||
#endif
|
|
@ -0,0 +1,537 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2007 by Björn Stenberg
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "thread.h"
|
||||
#include "kernel.h"
|
||||
#include "string.h"
|
||||
//#define LOGF_ENABLE
|
||||
#include "logf.h"
|
||||
|
||||
//#define USB_STORAGE
|
||||
//#define USB_BENCHMARK
|
||||
#define USB_CHARGING_ONLY
|
||||
|
||||
#include "usb_ch9.h"
|
||||
#include "usb_drv.h"
|
||||
#include "usb_core.h"
|
||||
|
||||
#if defined(USB_STORAGE)
|
||||
#include "usb_storage.h"
|
||||
#elif defined(USB_BENCHMARK)
|
||||
#include "usb_benchmark.h"
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* USB protocol descriptors: */
|
||||
|
||||
#define USB_SC_SCSI 0x06 /* Transparent */
|
||||
#define USB_PROT_BULK 0x50 /* bulk only */
|
||||
|
||||
int usb_max_pkt_size = 512;
|
||||
|
||||
static const struct usb_device_descriptor device_descriptor = {
|
||||
.bLength = sizeof(struct usb_device_descriptor),
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = 0x0200, /* USB version 2.0 */
|
||||
.bDeviceClass = USB_CLASS_PER_INTERFACE,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
.bMaxPacketSize0 = 64,
|
||||
.idVendor = USB_VENDOR_ID,
|
||||
.idProduct = USB_PRODUCT_ID,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = 1,
|
||||
.iProduct = 2,
|
||||
.iSerialNumber = 0,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
|
||||
static const struct {
|
||||
struct usb_config_descriptor config_descriptor;
|
||||
struct usb_interface_descriptor interface_descriptor;
|
||||
struct usb_endpoint_descriptor ep1_hs_in_descriptor;
|
||||
struct usb_endpoint_descriptor ep1_hs_out_descriptor;
|
||||
} config_data =
|
||||
{
|
||||
{
|
||||
.bLength = sizeof(struct usb_config_descriptor),
|
||||
.bDescriptorType = USB_DT_CONFIG,
|
||||
.wTotalLength = sizeof config_data,
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 0,
|
||||
.bmAttributes = USB_CONFIG_ATT_ONE,
|
||||
.bMaxPower = 250, /* 500mA in 2mA units */
|
||||
},
|
||||
|
||||
#ifdef USB_CHARGING_ONLY
|
||||
/* dummy interface for charging-only */
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 4
|
||||
},
|
||||
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_TX | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 0
|
||||
},
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_RX | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 0
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USB_STORAGE
|
||||
/* storage interface */
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
|
||||
.bInterfaceSubClass = USB_SC_SCSI,
|
||||
.bInterfaceProtocol = USB_PROT_BULK,
|
||||
.iInterface = 0
|
||||
},
|
||||
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_TX | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 512,
|
||||
.bInterval = 0
|
||||
},
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_RX | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 512,
|
||||
.bInterval = 0
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USB_SERIAL
|
||||
/* serial interface */
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 0
|
||||
},
|
||||
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_TX | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 512,
|
||||
.bInterval = 0
|
||||
},
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_RX | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 512,
|
||||
.bInterval = 0
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USB_BENCHMARK
|
||||
/* bulk test interface */
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceSubClass = 255,
|
||||
.bInterfaceProtocol = 255,
|
||||
.iInterface = 3
|
||||
},
|
||||
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_RX | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
// .wMaxPacketSize = 64,
|
||||
.wMaxPacketSize = 512,
|
||||
.bInterval = 0
|
||||
},
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_TX | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
// .wMaxPacketSize = 64,
|
||||
.wMaxPacketSize = 512,
|
||||
.bInterval = 0
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct usb_qualifier_descriptor qualifier_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_qualifier_descriptor),
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = 0,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
.bMaxPacketSize0 = 64,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
|
||||
/* full speed = 12 Mbit */
|
||||
static const struct usb_endpoint_descriptor ep1_fs_in_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 1 | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
static const struct usb_endpoint_descriptor ep1_fs_out_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 1 | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
static const struct usb_endpoint_descriptor* ep_descriptors[4] =
|
||||
{
|
||||
&config_data.ep1_hs_in_descriptor,
|
||||
&config_data.ep1_hs_out_descriptor,
|
||||
&ep1_fs_in_descriptor,
|
||||
&ep1_fs_out_descriptor
|
||||
};
|
||||
|
||||
/* this is stringid #0: languages supported */
|
||||
static const struct usb_string_descriptor lang_descriptor =
|
||||
{
|
||||
sizeof(struct usb_string_descriptor),
|
||||
USB_DT_STRING,
|
||||
{0x0409} /* LANGID US English */
|
||||
};
|
||||
|
||||
/* this is stringid #1 and up: the actual strings */
|
||||
static const struct {
|
||||
unsigned char size;
|
||||
unsigned char type;
|
||||
unsigned short string[32];
|
||||
} usb_strings[] =
|
||||
{
|
||||
{
|
||||
16,
|
||||
USB_DT_STRING,
|
||||
{'R','o','c','k','b','o','x'}
|
||||
},
|
||||
{
|
||||
42,
|
||||
USB_DT_STRING,
|
||||
{'D','i','g','i','t','a','l',' ','a','u','d','i','o',' ','p','l','a','y','e','r'}
|
||||
},
|
||||
{
|
||||
40,
|
||||
USB_DT_STRING,
|
||||
{'B','u','l','k',' ','t','e','s','t',' ','i','n','t','e','r','f','a','c','e'}
|
||||
},
|
||||
{
|
||||
28,
|
||||
USB_DT_STRING,
|
||||
{'C','h','a','r','g','i','n','g',' ','o','n','l','y'}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static int usb_address = 0;
|
||||
static bool initialized = false;
|
||||
static struct event_queue usbcore_queue;
|
||||
|
||||
#ifdef USB_STORAGE
|
||||
static const char usbcore_thread_name[] = "usb_core";
|
||||
static struct thread_entry* usbcore_thread;
|
||||
static long usbcore_stack[DEFAULT_STACK_SIZE];
|
||||
static void usb_core_thread(void);
|
||||
#endif
|
||||
|
||||
static void ack_control(struct usb_ctrlrequest* req);
|
||||
|
||||
void usb_core_init(void)
|
||||
{
|
||||
queue_init(&usbcore_queue, false);
|
||||
usb_drv_init();
|
||||
#ifdef USB_STORAGE
|
||||
usb_storage_init();
|
||||
usbcore_thread =
|
||||
create_thread(usb_core_thread, usbcore_stack, sizeof(usbcore_stack), 0,
|
||||
usbcore_thread_name
|
||||
IF_PRIO(, PRIORITY_SYSTEM)
|
||||
IF_COP(, CPU));
|
||||
#endif
|
||||
|
||||
#ifdef USB_BENCHMARK
|
||||
usb_benchmark_init();
|
||||
#endif
|
||||
initialized = true;
|
||||
logf("usb_core_init() finished");
|
||||
}
|
||||
|
||||
void usb_core_exit(void)
|
||||
{
|
||||
if (initialized) {
|
||||
usb_drv_exit();
|
||||
queue_delete(&usbcore_queue);
|
||||
#ifdef USB_STORAGE
|
||||
remove_thread(usbcore_thread);
|
||||
#endif
|
||||
}
|
||||
logf("usb_core_exit() finished");
|
||||
}
|
||||
|
||||
#ifdef USB_STORAGE
|
||||
void usb_core_thread(void)
|
||||
{
|
||||
while (1) {
|
||||
struct queue_event ev;
|
||||
|
||||
queue_wait(&usbcore_queue, &ev);
|
||||
|
||||
usb_storage_transfer_complete(ev.id, ev.data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* called by usb_drv_int() */
|
||||
void usb_core_control_request(struct usb_ctrlrequest* req)
|
||||
{
|
||||
/* note: interrupt context */
|
||||
|
||||
#ifdef USB_BENCHMARK
|
||||
if ((req->bRequestType & 0x60) == USB_TYPE_VENDOR) {
|
||||
usb_benchmark_control_request(req);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
logf("usb_core: SET_CONFIG");
|
||||
#ifdef USB_STORAGE
|
||||
usb_storage_control_request(req);
|
||||
#endif
|
||||
ack_control(req);
|
||||
break;
|
||||
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
logf("usb_core: SET_INTERFACE");
|
||||
ack_control(req);
|
||||
break;
|
||||
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
logf("usb_core: CLEAR_FEATURE");
|
||||
if (req->wValue)
|
||||
usb_drv_stall(req->wIndex, true);
|
||||
else
|
||||
usb_drv_stall(req->wIndex, false);
|
||||
ack_control(req);
|
||||
break;
|
||||
|
||||
case USB_REQ_SET_ADDRESS:
|
||||
usb_address = req->wValue;
|
||||
logf("usb_core: SET_ADR %d", usb_address);
|
||||
ack_control(req);
|
||||
usb_drv_set_address(usb_address);
|
||||
break;
|
||||
|
||||
case USB_REQ_GET_STATUS: {
|
||||
static char tmp[2] = {0,0};
|
||||
tmp[0] = 0;
|
||||
tmp[1] = 0;
|
||||
logf("usb_core: GET_STATUS");
|
||||
usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&tmp), 2);
|
||||
ack_control(req);
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_REQ_GET_DESCRIPTOR: {
|
||||
int index = req->wValue & 0xff;
|
||||
int length = req->wLength;
|
||||
int size;
|
||||
const void* ptr = NULL;
|
||||
logf("usb_core: GET_DESC %d", req->wValue >> 8);
|
||||
|
||||
switch (req->wValue >> 8) { /* type */
|
||||
case USB_DT_DEVICE:
|
||||
ptr = &device_descriptor;
|
||||
size = sizeof device_descriptor;
|
||||
break;
|
||||
|
||||
case USB_DT_CONFIG:
|
||||
ptr = &config_data;
|
||||
size = sizeof config_data;
|
||||
break;
|
||||
|
||||
case USB_DT_STRING:
|
||||
switch (index) {
|
||||
case 0: /* lang descriptor */
|
||||
ptr = &lang_descriptor;
|
||||
size = sizeof lang_descriptor;
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((unsigned)index <= (sizeof(usb_strings)/sizeof(usb_strings[0]))) {
|
||||
index -= 1;
|
||||
ptr = &usb_strings[index];
|
||||
size = usb_strings[index].size;
|
||||
}
|
||||
else {
|
||||
logf("bad string id %d", index);
|
||||
usb_drv_stall(EP_CONTROL, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_INTERFACE:
|
||||
ptr = &config_data.interface_descriptor;
|
||||
size = sizeof config_data.interface_descriptor;
|
||||
break;
|
||||
|
||||
case USB_DT_ENDPOINT:
|
||||
if (index <= NUM_ENDPOINTS) {
|
||||
ptr = &ep_descriptors[index];
|
||||
size = sizeof ep_descriptors[index];
|
||||
}
|
||||
else {
|
||||
logf("bad endpoint %d", index);
|
||||
usb_drv_stall(EP_CONTROL, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_DEVICE_QUALIFIER:
|
||||
ptr = &qualifier_descriptor;
|
||||
size = sizeof qualifier_descriptor;
|
||||
break;
|
||||
|
||||
/*
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
ptr = &other_speed_descriptor;
|
||||
size = sizeof other_speed_descriptor;
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
logf("bad desc %d", req->wValue >> 8);
|
||||
usb_drv_stall(EP_CONTROL, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
length = MIN(size, length);
|
||||
usb_drv_send(EP_CONTROL, (void*)UNCACHED_ADDR(ptr), length);
|
||||
}
|
||||
ack_control(req);
|
||||
break;
|
||||
} /* USB_REQ_GET_DESCRIPTOR */
|
||||
|
||||
default:
|
||||
#ifdef USB_STORAGE
|
||||
/* does usb_storage know this request? */
|
||||
if (!usb_storage_control_request(req))
|
||||
#endif
|
||||
{
|
||||
/* nope. flag error */
|
||||
logf("usb bad req %d", req->bRequest);
|
||||
usb_drv_stall(EP_CONTROL, true);
|
||||
ack_control(req);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* called by usb_drv_int() */
|
||||
void usb_core_bus_reset(void)
|
||||
{
|
||||
usb_address = 0;
|
||||
}
|
||||
|
||||
/* called by usb_drv_transfer_completed() */
|
||||
void usb_core_transfer_complete(int endpoint, bool in)
|
||||
{
|
||||
#ifdef USB_CHARGING_ONLY
|
||||
(void)in;
|
||||
#endif
|
||||
|
||||
switch (endpoint) {
|
||||
case EP_CONTROL:
|
||||
/* already handled */
|
||||
break;
|
||||
|
||||
case EP_RX:
|
||||
case EP_TX:
|
||||
#if defined(USB_BENCHMARK)
|
||||
usb_benchmark_transfer_complete(endpoint, in);
|
||||
#elif defined(USB_STORAGE)
|
||||
queue_post(&usbcore_queue, endpoint);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ack_control(struct usb_ctrlrequest* req)
|
||||
{
|
||||
if (req->bRequestType & 0x80)
|
||||
usb_drv_recv(EP_CONTROL, NULL, 0);
|
||||
else
|
||||
usb_drv_send(EP_CONTROL, NULL, 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,331 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2007 by Björn Stenberg
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "usb_core.h"
|
||||
#include "usb_drv.h"
|
||||
//#define LOGF_ENABLE
|
||||
#include "logf.h"
|
||||
#include "ata.h"
|
||||
#include "hotswap.h"
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
/* bulk-only class specific requests */
|
||||
#define USB_BULK_RESET_REQUEST 0xff
|
||||
#define USB_BULK_GET_MAX_LUN 0xfe
|
||||
|
||||
#define DIRECT_ACCESS_DEVICE 0x00 /* disks */
|
||||
#define DEVICE_REMOVABLE 0x80
|
||||
|
||||
#define CBW_SIGNATURE 0x43425355
|
||||
#define CSW_SIGNATURE 0x53425355
|
||||
|
||||
#define SCSI_TEST_UNIT_READY 0x00
|
||||
#define SCSI_INQUIRY 0x12
|
||||
#define SCSI_MODE_SENSE 0x1a
|
||||
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SCSI_READ_CAPACITY 0x25
|
||||
#define SCSI_READ_10 0x28
|
||||
#define SCSI_WRITE_10 0x2a
|
||||
|
||||
#define SCSI_STATUS_GOOD 0x00
|
||||
#define SCSI_STATUS_CHECK_CONDITION 0x02
|
||||
|
||||
|
||||
struct inquiry_data {
|
||||
unsigned char DeviceType;
|
||||
unsigned char DeviceTypeModifier;
|
||||
unsigned char Versions;
|
||||
unsigned char Format;
|
||||
unsigned char AdditionalLength;
|
||||
unsigned char Reserved[2];
|
||||
unsigned char Capability;
|
||||
unsigned char VendorId[8];
|
||||
unsigned char ProductId[16];
|
||||
unsigned char ProductRevisionLevel[4];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct command_block_wrapper {
|
||||
unsigned int signature;
|
||||
unsigned int tag;
|
||||
unsigned int data_transfer_length;
|
||||
unsigned char flags;
|
||||
unsigned char lun;
|
||||
unsigned char command_length;
|
||||
unsigned char command_block[16];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct command_status_wrapper {
|
||||
unsigned int signature;
|
||||
unsigned int tag;
|
||||
unsigned int data_residue;
|
||||
unsigned char status;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct capacity {
|
||||
unsigned int block_count;
|
||||
unsigned int block_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* the ARC USB controller can at most buffer 16KB unaligned data */
|
||||
static unsigned char _transfer_buffer[16384];
|
||||
static unsigned char* transfer_buffer;
|
||||
static struct inquiry_data _inquiry;
|
||||
static struct inquiry_data* inquiry;
|
||||
static struct capacity _capacity_data;
|
||||
static struct capacity* capacity_data;
|
||||
|
||||
//static unsigned char partial_sector[SECTOR_SIZE];
|
||||
|
||||
static struct {
|
||||
unsigned int sector;
|
||||
unsigned int offset; /* if partial sector */
|
||||
unsigned int count;
|
||||
unsigned int tag;
|
||||
} current_cmd;
|
||||
|
||||
void handle_scsi(struct command_block_wrapper* cbw);
|
||||
void send_csw(unsigned int tag, int status);
|
||||
static void identify2inquiry(void);
|
||||
|
||||
static enum {
|
||||
IDLE,
|
||||
SENDING,
|
||||
RECEIVING
|
||||
} state = IDLE;
|
||||
|
||||
/* called by usb_code_init() */
|
||||
void usb_storage_init(void)
|
||||
{
|
||||
inquiry = (void*)UNCACHED_ADDR(&_inquiry);
|
||||
transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer);
|
||||
capacity_data = (void*)UNCACHED_ADDR(&_capacity_data);
|
||||
identify2inquiry();
|
||||
}
|
||||
|
||||
/* called by usb_core_transfer_complete() */
|
||||
void usb_storage_transfer_complete(int endpoint)
|
||||
{
|
||||
struct command_block_wrapper* cbw = (void*)transfer_buffer;
|
||||
|
||||
switch (endpoint) {
|
||||
case EP_RX:
|
||||
//logf("ums: %d bytes in", length);
|
||||
switch (state) {
|
||||
case IDLE:
|
||||
handle_scsi(cbw);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* re-prime endpoint */
|
||||
usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer);
|
||||
break;
|
||||
|
||||
case EP_TX:
|
||||
//logf("ums: %d bytes out", length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* called by usb_core_control_request() */
|
||||
bool usb_storage_control_request(struct usb_ctrlrequest* req)
|
||||
{
|
||||
/* note: interrupt context */
|
||||
|
||||
bool handled = false;
|
||||
|
||||
switch (req->bRequest) {
|
||||
case USB_BULK_GET_MAX_LUN: {
|
||||
static char maxlun = 0;
|
||||
logf("ums: getmaxlun");
|
||||
usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&maxlun), 1);
|
||||
usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_BULK_RESET_REQUEST:
|
||||
logf("ums: bulk reset");
|
||||
usb_drv_reset_endpoint(EP_RX, false);
|
||||
usb_drv_reset_endpoint(EP_TX, true);
|
||||
usb_drv_send(EP_CONTROL, NULL, 0); /* ack */
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
logf("ums: set config");
|
||||
/* prime rx endpoint */
|
||||
usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void handle_scsi(struct command_block_wrapper* cbw)
|
||||
{
|
||||
/* USB Mass Storage assumes LBA capability.
|
||||
TODO: support 48-bit LBA */
|
||||
|
||||
unsigned int length = cbw->data_transfer_length;
|
||||
|
||||
switch (cbw->command_block[0]) {
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
logf("scsi test_unit_ready");
|
||||
send_csw(cbw->tag, SCSI_STATUS_GOOD);
|
||||
break;
|
||||
|
||||
case SCSI_INQUIRY:
|
||||
logf("scsi inquiry");
|
||||
length = MIN(length, cbw->command_block[4]);
|
||||
usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length));
|
||||
send_csw(cbw->tag, SCSI_STATUS_GOOD);
|
||||
break;
|
||||
|
||||
case SCSI_MODE_SENSE: {
|
||||
static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
logf("scsi mode_sense");
|
||||
usb_drv_send(EP_TX, UNCACHED_ADDR(&sense_data),
|
||||
MIN(sizeof sense_data, length));
|
||||
send_csw(cbw->tag, SCSI_STATUS_GOOD);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCSI_ALLOW_MEDIUM_REMOVAL:
|
||||
logf("scsi allow_medium_removal");
|
||||
send_csw(cbw->tag, SCSI_STATUS_GOOD);
|
||||
break;
|
||||
|
||||
case SCSI_READ_CAPACITY: {
|
||||
logf("scsi read_capacity");
|
||||
#ifdef HAVE_FLASH_STORAGE
|
||||
tCardInfo* cinfo = card_get_info(0);
|
||||
capacity_data->block_count = htobe32(cinfo->numblocks);
|
||||
capacity_data->block_size = htobe32(cinfo->blocksize);
|
||||
#else
|
||||
unsigned short* identify = ata_get_identify();
|
||||
capacity_data->block_count = htobe32(identify[60] << 16 | identify[61]);
|
||||
capacity_data->block_size = htobe32(SECTOR_SIZE);
|
||||
#endif
|
||||
usb_drv_send(EP_TX, capacity_data,
|
||||
MIN(sizeof _capacity_data, length));
|
||||
send_csw(cbw->tag, SCSI_STATUS_GOOD);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCSI_READ_10:
|
||||
current_cmd.sector =
|
||||
cbw->command_block[2] << 24 |
|
||||
cbw->command_block[3] << 16 |
|
||||
cbw->command_block[4] << 8 |
|
||||
cbw->command_block[5] ;
|
||||
current_cmd.count =
|
||||
cbw->command_block[7] << 16 |
|
||||
cbw->command_block[8];
|
||||
current_cmd.offset = 0;
|
||||
current_cmd.tag = cbw->tag;
|
||||
|
||||
logf("scsi read %d %d", current_cmd.sector, current_cmd.count);
|
||||
|
||||
/* too much? */
|
||||
if (current_cmd.count > (sizeof _transfer_buffer / SECTOR_SIZE)) {
|
||||
send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION);
|
||||
break;
|
||||
}
|
||||
|
||||
ata_read_sectors(IF_MV2(0,) current_cmd.sector, current_cmd.count,
|
||||
&transfer_buffer);
|
||||
state = SENDING;
|
||||
usb_drv_send(EP_TX, transfer_buffer,
|
||||
MIN(current_cmd.count * SECTOR_SIZE, length));
|
||||
break;
|
||||
|
||||
case SCSI_WRITE_10:
|
||||
logf("scsi write10");
|
||||
break;
|
||||
|
||||
default:
|
||||
logf("scsi unknown cmd %x", cbw->command_block[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void send_csw(unsigned int tag, int status)
|
||||
{
|
||||
static struct command_status_wrapper _csw;
|
||||
struct command_status_wrapper* csw = UNCACHED_ADDR(&_csw);
|
||||
csw->signature = CSW_SIGNATURE;
|
||||
csw->tag = tag;
|
||||
csw->data_residue = 0;
|
||||
csw->status = status;
|
||||
|
||||
//logf("csw %x %x", csw->tag, csw->signature);
|
||||
usb_drv_send(EP_TX, csw, sizeof _csw);
|
||||
}
|
||||
|
||||
/* convert ATA IDENTIFY to SCSI INQUIRY */
|
||||
static void identify2inquiry(void)
|
||||
{
|
||||
unsigned int i;
|
||||
#ifdef HAVE_FLASH_STORAGE
|
||||
for (i=0; i<8; i++)
|
||||
inquiry->VendorId[i] = i + 'A';
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
inquiry->ProductId[i] = i + 'm';
|
||||
#else
|
||||
unsigned short* dest;
|
||||
unsigned short* src;
|
||||
unsigned short* identify = ata_get_identify();
|
||||
memset(inquiry, 0, sizeof _inquiry);
|
||||
|
||||
if (identify[82] & 4)
|
||||
inquiry->DeviceTypeModifier = DEVICE_REMOVABLE;
|
||||
|
||||
/* ATA only has a 'model' field, so we copy the
|
||||
first 8 bytes to 'vendor' and the rest to 'product' */
|
||||
src = (unsigned short*)&identify[27];
|
||||
dest = (unsigned short*)&inquiry->VendorId;
|
||||
for (i=0;i<4;i++)
|
||||
dest[i] = src[i];
|
||||
|
||||
src = (unsigned short*)&identify[27+8];
|
||||
dest = (unsigned short*)&inquiry->ProductId;
|
||||
for (i=0;i<8;i++)
|
||||
dest[i] = src[i];
|
||||
|
||||
src = (unsigned short*)&identify[23];
|
||||
dest = (unsigned short*)&inquiry->ProductRevisionLevel;
|
||||
for (i=0;i<2;i++)
|
||||
dest[i] = src[i];
|
||||
#endif
|
||||
|
||||
inquiry->DeviceType = DIRECT_ACCESS_DEVICE;
|
||||
inquiry->AdditionalLength = 0x1f;
|
||||
inquiry->Versions = 3; /* ANSI SCSI level 2 */
|
||||
inquiry->Format = 3; /* ANSI SCSI level 2 INQUIRY format */
|
||||
}
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2007 by Christian Gmeiner
|
||||
* Copyright (C) 2007 by Björn Stenberg
|
||||
*
|
||||
* 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.
|
||||
|
@ -16,16 +16,15 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef USB_STORAGE_H
|
||||
#define USB_STORAGE_H
|
||||
|
||||
#ifndef _USBSTACK_HOST_H_
|
||||
#define _USBSTACK_HOST_H_
|
||||
#include "usb_ch9.h"
|
||||
|
||||
/*
|
||||
* usb host driver
|
||||
*/
|
||||
struct usb_host_driver {
|
||||
const char* name;
|
||||
void* data; /* used to store controller specific ops struct */
|
||||
};
|
||||
void usb_storage_init(void);
|
||||
void usb_storage_transfer(void* data);
|
||||
void usb_storage_transfer_complete(int endpoint);
|
||||
bool usb_storage_control_request(struct usb_ctrlrequest* req);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /*_USBSTACK_HOST_H_*/
|
|
@ -87,6 +87,9 @@ wavtrim: wavtrim.c
|
|||
voicefont: voicefont.c
|
||||
$(SILENT)$(CC) -g $+ -o $@
|
||||
|
||||
usb_benchmark: usb_benchmark.c
|
||||
$(SILENT)$(CC) -g -lusb $+ -o $@
|
||||
|
||||
clean:
|
||||
@echo "Cleaning tools"
|
||||
$(SILENT)rm -f $(CLEANALL) $(shell for f in $(CLEANALL) ; do echo $$f.exe $$f.o $$f.obj ; done) *.ajf *~
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
LPCUSB, an USB device driver for LPC microcontrollers
|
||||
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
Simple benchmarking application.
|
||||
|
||||
It talks with the 'custom' device application on the LPC214x through
|
||||
libusb.
|
||||
|
||||
2007-11-01: Some minor modifications by <bjorn@haxx.se>
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
// types
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
typedef unsigned int U32;
|
||||
typedef unsigned char U8;
|
||||
|
||||
#define MAX_TIME 3000
|
||||
|
||||
static unsigned char abData[16384];
|
||||
|
||||
// USB device specific definitions
|
||||
#define VENDOR_ID 0x0781
|
||||
#define PRODUCT_ID 0x7450
|
||||
|
||||
#define BM_REQUEST_TYPE (2<<5)
|
||||
#define BULK_IN_EP 0x82
|
||||
#define BULK_OUT_EP 0x05
|
||||
|
||||
// this structure should match with the expectations of the 'custom' device!
|
||||
typedef struct {
|
||||
U32 dwAddress;
|
||||
U32 dwLength;
|
||||
} TMemoryCmd;
|
||||
|
||||
|
||||
static struct usb_device * find_device(int iVendor, int iProduct)
|
||||
{
|
||||
struct usb_bus *usb_bus;
|
||||
struct usb_device *dev;
|
||||
|
||||
for (usb_bus = usb_get_busses(); usb_bus; usb_bus = usb_bus->next) {
|
||||
for (dev = usb_bus->devices; dev; dev = dev->next) {
|
||||
if ((dev->descriptor.idVendor == iVendor) &&
|
||||
(dev->descriptor.idProduct == iProduct)) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct timeb start;
|
||||
|
||||
static void starttimer(void)
|
||||
{
|
||||
ftime(&start);
|
||||
}
|
||||
|
||||
static int stoptimer(void)
|
||||
{
|
||||
struct timeb now;
|
||||
|
||||
ftime(&now);
|
||||
return 1000 * (now.time - start.time) + now.millitm - start.millitm;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const int blocksize[] = { 128, 512 };
|
||||
struct usb_device *dev;
|
||||
struct usb_dev_handle *hdl;
|
||||
int i, j;
|
||||
U32 dwBlockSize, dwChunk, dwBytes;
|
||||
TMemoryCmd MemCmd;
|
||||
int iTimer;
|
||||
|
||||
usb_init();
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
|
||||
for (i=0; i<sizeof abData/4; i++)
|
||||
((unsigned int*)abData)[i] = i;
|
||||
|
||||
dev = find_device(VENDOR_ID, PRODUCT_ID);
|
||||
if (dev == NULL) {
|
||||
fprintf(stderr, "device not found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdl = usb_open(dev);
|
||||
|
||||
i = usb_set_configuration(hdl, 1);
|
||||
if (i < 0) {
|
||||
fprintf(stderr, "usb_set_configuration failed\n");
|
||||
}
|
||||
|
||||
i = usb_claim_interface(hdl, 0);
|
||||
if (i < 0) {
|
||||
fprintf(stderr, "usb_claim_interface failed %d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// read some data
|
||||
for (j = 0; j < 1; j++) {
|
||||
dwBlockSize = blocksize[j];
|
||||
fprintf(stderr, "Testing blocksize %5d\n", dwBlockSize);
|
||||
|
||||
#if 1
|
||||
fprintf(stderr, "* write:");
|
||||
// send a vendor request for a write
|
||||
MemCmd.dwAddress = 0;
|
||||
MemCmd.dwLength = 20 * 1024;
|
||||
i = usb_control_msg(hdl, BM_REQUEST_TYPE, 0x02, 20, 1024, NULL, 0, 1000);
|
||||
if (i < 0) {
|
||||
fprintf(stderr, "usb_control_msg failed %d\n", i);
|
||||
break;
|
||||
}
|
||||
dwBytes = 0;
|
||||
starttimer();
|
||||
while (MemCmd.dwLength > 0) {
|
||||
dwChunk = MIN(dwBlockSize, MemCmd.dwLength);
|
||||
i = usb_bulk_write(hdl, 0x01, (char *)abData, dwChunk, 2000);
|
||||
if (i < 1) {
|
||||
fprintf(stderr, "usb_bulk_write failed %d\n", i);
|
||||
break;
|
||||
}
|
||||
MemCmd.dwLength -= dwChunk;
|
||||
dwBytes += dwBlockSize;
|
||||
if (stoptimer() > MAX_TIME) {
|
||||
break;
|
||||
}
|
||||
((unsigned int*)abData)[0]++;
|
||||
}
|
||||
if (i<0)
|
||||
break;
|
||||
iTimer = stoptimer();
|
||||
if (iTimer)
|
||||
fprintf(stderr, " %7d bytes in %d ms = %d kB/s\n", dwBytes, iTimer, dwBytes / iTimer);
|
||||
// stdout
|
||||
printf("%d,%d,%d\n", dwBlockSize, dwBytes, iTimer);
|
||||
#endif
|
||||
#if 1
|
||||
fprintf(stderr, "* read :");
|
||||
// send a vendor request for a read
|
||||
MemCmd.dwAddress = 0;
|
||||
MemCmd.dwLength = 20 * 1024;
|
||||
i = usb_control_msg(hdl, BM_REQUEST_TYPE, 0x01, 20, 1024, NULL, 0, 1000);
|
||||
if (i < 0) {
|
||||
fprintf(stderr, "usb_control_msg failed %d\n", i);
|
||||
break;
|
||||
}
|
||||
dwBytes = 0;
|
||||
starttimer();
|
||||
while (MemCmd.dwLength > 0) {
|
||||
dwChunk = MIN(dwBlockSize, MemCmd.dwLength);
|
||||
i = usb_bulk_read(hdl, 0x82, (char *)abData, dwChunk, 2000);
|
||||
if (i < 1) {
|
||||
fprintf(stderr, "usb_bulk_read failed %d\n", i);
|
||||
break;
|
||||
}
|
||||
MemCmd.dwLength -= dwChunk;
|
||||
dwBytes += dwBlockSize;
|
||||
if (stoptimer() > MAX_TIME) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i<0)
|
||||
break;
|
||||
iTimer = stoptimer();
|
||||
if (iTimer)
|
||||
fprintf(stderr, " %7d bytes in %d ms = %d kB/s\n", dwBytes, iTimer, dwBytes / iTimer);
|
||||
// stdout
|
||||
printf("%d,%d,%d\n", dwBlockSize, dwBytes, iTimer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
usb_release_interface(hdl, 0);
|
||||
usb_close(hdl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue