summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2009-01-19 13:41:25 +0000
committerMichael Sevakis <jethead71@rockbox.org>2009-01-19 13:41:25 +0000
commit616c98b38f6ddac0ac3dde8ec0fa248f835717e2 (patch)
tree5eeeabb85fbefa162a438edca88611c1bc688269
parentcef6399c4c3bcaa35733bdab8b9016b66b71a6f0 (diff)
downloadrockbox-616c98b38f6ddac0ac3dde8ec0fa248f835717e2.zip
rockbox-616c98b38f6ddac0ac3dde8ec0fa248f835717e2.tar.gz
rockbox-616c98b38f6ddac0ac3dde8ec0fa248f835717e2.tar.bz2
rockbox-616c98b38f6ddac0ac3dde8ec0fa248f835717e2.tar.xz
USB detection changes. c200/e200: Consider USB to be powered when charger is plugged but detect USB connection by bus reset. When received, disconnect and restart the driver fully enabled. imx31: Fix hack used to make initial connect succeeded-- set PHY type before initial reset. General: Move some target code out of usb-drv-arc.c and implement it in respective usb sources and CPU headers so things stay clean.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19797 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--bootloader/gigabeat-s.c1
-rw-r--r--firmware/export/config-c200.h3
-rw-r--r--firmware/export/config-e200.h3
-rw-r--r--firmware/export/config-gigabeat-s.h6
-rwxr-xr-xfirmware/export/imx31l.h8
-rw-r--r--firmware/export/pp5020.h7
-rw-r--r--firmware/export/usb.h8
-rw-r--r--firmware/export/usb_core.h10
-rw-r--r--firmware/export/usb_drv.h6
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/system-target.h8
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/usb-imx31.c35
-rw-r--r--firmware/target/arm/powermgmt-ascodec.c10
-rw-r--r--firmware/target/arm/usb-drv-arc.c186
-rw-r--r--firmware/target/arm/usb-fw-pp502x.c49
-rw-r--r--firmware/target/arm/usb-target.h7
-rw-r--r--firmware/usb.c65
-rw-r--r--firmware/usbstack/usb_core.c6
-rw-r--r--firmware/usbstack/usb_storage.c2
18 files changed, 276 insertions, 144 deletions
diff --git a/bootloader/gigabeat-s.c b/bootloader/gigabeat-s.c
index e860a2e..15cbcbe 100644
--- a/bootloader/gigabeat-s.c
+++ b/bootloader/gigabeat-s.c
@@ -95,7 +95,6 @@ static void handle_usb(void)
if (!usb_plugged() || !pause_if_button_pressed(true))
{
/* Bang on the controller */
- usb_init_device();
return;
}
diff --git a/firmware/export/config-c200.h b/firmware/export/config-c200.h
index d68d214..ff260dc 100644
--- a/firmware/export/config-c200.h
+++ b/firmware/export/config-c200.h
@@ -180,6 +180,9 @@
/* enable these for the experimental usb stack */
#define HAVE_USBSTACK
+#ifndef BOOTLOADER
+#define USB_DETECT_BY_DRV
+#endif
#define USB_VENDOR_ID 0x0781
#define USB_PRODUCT_ID 0x7450
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h
index 2be64d9..7b27391 100644
--- a/firmware/export/config-e200.h
+++ b/firmware/export/config-e200.h
@@ -177,6 +177,9 @@
/* enable these for the experimental usb stack */
#define HAVE_USBSTACK
+#ifndef BOOTLOADER
+#define USB_DETECT_BY_DRV
+#endif
#define USB_VENDOR_ID 0x0781
#define USB_PRODUCT_ID 0x7421
diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h
index 64f351c..9e6029f 100644
--- a/firmware/export/config-gigabeat-s.h
+++ b/firmware/export/config-gigabeat-s.h
@@ -176,10 +176,12 @@
/* USB On-the-go */
#define CONFIG_USBOTG USBOTG_ARC
-/* enable these for the experimental usb stack */
+/* enable these for the usb stack */
#define USE_ROCKBOX_USB
#define HAVE_USBSTACK
#define USB_STORAGE
+/* usb stack and driver settings */
+#define USB_PORTSCX_PHY_TYPE PORTSCX_PTS_ULPI
#define USB_VENDOR_ID 0x0930
#define USB_PRODUCT_ID 0x0010
@@ -201,7 +203,7 @@
/* Offset ( in the firmware file's header ) to the real data */
#define FIRMWARE_OFFSET_FILE_DATA 8
-#define HAVE_SERIAL
+//#define HAVE_SERIAL
#define HAVE_VOLUME_IN_LIST
/*Remove Comments from UART_INT to enable the UART interrupts,*/
diff --git a/firmware/export/imx31l.h b/firmware/export/imx31l.h
index b572c78..b55a56b 100755
--- a/firmware/export/imx31l.h
+++ b/firmware/export/imx31l.h
@@ -36,7 +36,11 @@
#define FRAME_SIZE (240*320*2)
#define DEVBSS_ATTR __attribute__((section(".devbss"),nocommon))
-#define QHARRAY_ATTR __attribute__((section(".qharray"),nocommon))
+/* USBOTG */
+#define USB_QHARRAY_ATTR __attribute__((section(".qharray"),nocommon,aligned(2048)))
+#define USB_NUM_ENDPOINTS 8
+#define USB_DEVBSS_ATTR DEVBSS_ATTR
+#define USB_BASE OTG_BASE_ADDR
/*
* AIPS 1
@@ -1580,6 +1584,4 @@
#define UART_FIFO_CTRL 0x881
#define TIMEOUT 1000
-#define USB_BASE OTG_BASE_ADDR
-
#endif /* __IMX31L_H__ */
diff --git a/firmware/export/pp5020.h b/firmware/export/pp5020.h
index b4919a2..0f622a9 100644
--- a/firmware/export/pp5020.h
+++ b/firmware/export/pp5020.h
@@ -23,7 +23,12 @@
/* All info gleaned and/or copied from the iPodLinux project. */
-#define QHARRAY_ATTR __attribute__((section(".qharray"),nocommon))
+/* USBOTG */
+#define USB_NUM_ENDPOINTS 3
+/* This needs to be 2048 byte aligned, but USB_QHARRAY_ATTR should take care
+ * of that */
+#define USB_QHARRAY_ATTR __attribute__((section(".qharray"),nocommon,aligned(4)))
+#define USB_DEVBSS_ATTR IBSS_ATTR
/* DRAM starts at 0x10000000, but in Rockbox we remap it to 0x00000000 */
#define DRAM_START 0x10000000
diff --git a/firmware/export/usb.h b/firmware/export/usb.h
index a6cfad5..0a0539a 100644
--- a/firmware/export/usb.h
+++ b/firmware/export/usb.h
@@ -33,8 +33,11 @@
enum {
USB_INSERTED, /* Event+State */
USB_EXTRACTED, /* Event+State */
-#ifdef HAVE_USB_POWER
- USB_POWERED, /* State */
+#if defined(HAVE_USB_POWER) || defined(USB_DETECT_BY_DRV)
+ USB_POWERED, /* Event+State */
+#endif
+#ifdef USB_DETECT_BY_DRV
+ USB_UNPOWERED, /* Event */
#endif
#ifdef HAVE_LCD_BITMAP
USB_SCREENDUMP, /* State */
@@ -107,6 +110,7 @@ struct usb_transfer_completion_event_data
void usb_init(void);
void usb_enable(bool on);
+void usb_attach(void);
void usb_start_monitoring(void);
void usb_close(void);
void usb_acknowledge(long id);
diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h
index 7af8e43..d0c8270 100644
--- a/firmware/export/usb_core.h
+++ b/firmware/export/usb_core.h
@@ -7,7 +7,7 @@
* \/ \/ \/ \/ \/
* $Id$
*
- * Copyright (C) 2007 by Björn Stenberg
+ * Copyright (C) 2007 by Björn Stenberg
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -35,14 +35,6 @@
/* endpoints */
#define EP_CONTROL 0
-#if CONFIG_CPU == IMX31L
-#define NUM_ENDPOINTS 8
-#define USBDEVBSS_ATTR DEVBSS_ATTR
-#else
-#define USBDEVBSS_ATTR IBSS_ATTR
-#define NUM_ENDPOINTS 3
-#endif
-
extern int usb_max_pkt_size;
struct usb_class_driver;
diff --git a/firmware/export/usb_drv.h b/firmware/export/usb_drv.h
index 3d2e689..23f6f4c 100644
--- a/firmware/export/usb_drv.h
+++ b/firmware/export/usb_drv.h
@@ -24,9 +24,13 @@
#include "kernel.h"
void usb_drv_startup(void);
+void usb_drv_usb_detect_event(void); /* Target implemented */
+void usb_drv_int_enable(bool enable); /* Target implemented */
+void usb_drv_reset(void);
void usb_drv_init(void);
void usb_drv_exit(void);
-void usb_drv_int(void);
+void usb_drv_attach(void);
+void usb_drv_int(void); /* Call from target INT handler */
void usb_drv_stall(int endpoint, bool stall,bool in);
bool usb_drv_stalled(int endpoint,bool in);
int usb_drv_send(int endpoint, void* ptr, int length);
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-target.h b/firmware/target/arm/imx31/gigabeat-s/system-target.h
index 847e6cf..b99b31d 100644
--- a/firmware/target/arm/imx31/gigabeat-s/system-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/system-target.h
@@ -31,6 +31,14 @@
#define CPUFREQ_MAX CPU_FREQ
#endif
+/* For USB driver - no accuracy assurance */
+static inline void udelay(unsigned int usecs)
+{
+ unsigned int x;
+ for (x = 0; x < 300*usecs; x++)
+ asm volatile ("");
+}
+
#if 0
static inline void udelay(unsigned int usecs)
{
diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c b/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c
index cd8b513..c0d7cb8 100644
--- a/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c
@@ -29,6 +29,7 @@
#include "usb-target.h"
#include "clkctl-imx31.h"
#include "power-imx31.h"
+#include "avic-imx31.h"
#include "mc13783.h"
static int usb_status = USB_EXTRACTED;
@@ -75,11 +76,7 @@ bool usb_plugged(void)
void usb_init_device(void)
{
- imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL);
-
- enable_transceiver(true);
-
- /* Module will be turned off later after firmware init */
+ /* Do one-time inits */
usb_drv_startup();
/* Initially poll */
@@ -91,19 +88,37 @@ void usb_init_device(void)
void usb_enable(bool on)
{
+ /* Module clock should be on since since this could be called with
+ * OFF initially and writing module registers would hardlock otherwise. */
+ imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL);
+ enable_transceiver(true);
+
if (on)
{
- imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL);
- enable_transceiver(true);
usb_core_init();
}
else
{
- /* Module clock should be on since this could be called first */
- imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL);
- enable_transceiver(true);
usb_core_exit();
enable_transceiver(false);
imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_OFF);
}
}
+
+void usb_attach(void)
+{
+ usb_enable(true);
+}
+
+static void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void)
+{
+ usb_drv_int(); /* Call driver handler */
+}
+
+void usb_drv_int_enable(bool enable)
+{
+ if (enable)
+ avic_enable_int(USB_OTG, IRQ, 7, USB_OTG_HANDLER);
+ else
+ avic_disable_int(USB_OTG);
+}
diff --git a/firmware/target/arm/powermgmt-ascodec.c b/firmware/target/arm/powermgmt-ascodec.c
index ab9fd7b..6ee6209 100644
--- a/firmware/target/arm/powermgmt-ascodec.c
+++ b/firmware/target/arm/powermgmt-ascodec.c
@@ -27,6 +27,8 @@
#include "adc.h"
#include "powermgmt.h"
#include "power.h"
+#include "usb-target.h"
+#include "usb.h"
/*===========================================================================
* These parameters may be defined per target:
@@ -132,6 +134,10 @@ static inline void charger_plugged(void)
{
batt_threshold = BATT_FULL_VOLTAGE; /* Start with topped value. */
battery_voltage_sync();
+#if defined(USB_STATUS_BY_EVENT) && defined(USB_DETECT_BY_DRV)
+ /* Charger pin detect is USB pin detect */
+ usb_connect_event(true);
+#endif
}
static inline void charger_control(void)
@@ -186,6 +192,10 @@ static inline void charger_unplugged(void)
disable_charger();
if (charge_state >= CHARGE_STATE_ERROR)
charge_state = DISCHARGING; /* Reset error */
+#if defined(USB_STATUS_BY_EVENT) && defined(USB_DETECT_BY_DRV)
+ /* Charger pin detect is USB pin detect */
+ usb_connect_event(false);
+#endif
}
/* Main charging algorithm - called from powermgmt.c */
diff --git a/firmware/target/arm/usb-drv-arc.c b/firmware/target/arm/usb-drv-arc.c
index 1cdc0f9..99845c2 100644
--- a/firmware/target/arm/usb-drv-arc.c
+++ b/firmware/target/arm/usb-drv-arc.c
@@ -9,7 +9,7 @@
*
* Driver for ARC USBOTG Device Controller
*
- * Copyright (C) 2007 by Björn Stenberg
+ * Copyright (C) 2007 by Björn Stenberg
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -33,11 +33,6 @@
//#define LOGF_ENABLE
#include "logf.h"
-#if CONFIG_CPU == IMX31L
-#include "avic-imx31.h"
-static void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void);
-#endif
-
/* USB device mode registers (Little Endian) */
#define REG_ID (*(volatile unsigned int *)(USB_BASE+0x000))
@@ -326,8 +321,8 @@ struct transfer_descriptor {
unsigned int reserved;
} __attribute__ ((packed));
-static struct transfer_descriptor td_array[NUM_ENDPOINTS*2]
- USBDEVBSS_ATTR __attribute__((aligned(32)));
+static struct transfer_descriptor td_array[USB_NUM_ENDPOINTS*2]
+ USB_DEVBSS_ATTR __attribute__((aligned(32)));
/* manual: 32.13.1 Endpoint Queue Head (dQH) */
struct queue_head {
@@ -342,17 +337,10 @@ struct queue_head {
unsigned int wait; /* for softwate use, indicates if the transfer is blocking */
} __attribute__((packed));
-#if CONFIG_CPU == IMX31L
-static struct queue_head qh_array[NUM_ENDPOINTS*2]
- QHARRAY_ATTR __attribute__((aligned (2048)));
-#else
-/* This still needs to be 2048 byte aligned, but QHARRAY_ATTR should take
- care of that */
-static struct queue_head qh_array[NUM_ENDPOINTS*2]
- QHARRAY_ATTR __attribute__((aligned (4)));
-#endif
+static struct queue_head qh_array[USB_NUM_ENDPOINTS*2]
+ USB_QHARRAY_ATTR;
-static struct wakeup transfer_completion_signal[NUM_ENDPOINTS*2]
+static struct wakeup transfer_completion_signal[USB_NUM_ENDPOINTS*2]
SHAREDBSS_ATTR;
static const unsigned int pipe2mask[] = {
@@ -363,7 +351,7 @@ static const unsigned int pipe2mask[] = {
0x10, 0x100000,
};
-static char ep_allocation[NUM_ENDPOINTS];
+static char ep_allocation[USB_NUM_ENDPOINTS];
/*-------------------------------------------------------------------------*/
static void transfer_completed(void);
@@ -378,52 +366,46 @@ static void init_control_queue_heads(void);
static void init_bulk_queue_heads(void);
static void init_endpoints(void);
/*-------------------------------------------------------------------------*/
-
-bool usb_drv_powered(void)
+static void usb_drv_stop(void)
{
- return (REG_OTGSC & OTGSC_B_SESSION_VALID) ? true : false;
+ /* disable interrupts */
+ REG_USBINTR = 0;
+ /* stop usb controller (disconnect) */
+ REG_USBCMD &= ~USBCMD_RUN;
}
-/* One-time driver startup init */
-void usb_drv_startup(void)
+void usb_drv_reset(void)
{
-#if CONFIG_CPU == IMX31L && defined(BOOTLOADER)
- /* This is the bootloader - activate the OTG controller or cold
- * connect later could/will fail */
+ int oldlevel = disable_irq_save();
REG_USBCMD &= ~USBCMD_RUN;
+ restore_irq(oldlevel);
+#ifdef USB_PORTSCX_PHY_TYPE
+ /* If a PHY type is specified, set it now */
+ REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | USB_PORTSCX_PHY_TYPE;
+#endif
sleep(HZ/20);
REG_USBCMD |= USBCMD_CTRL_RESET;
while (REG_USBCMD & USBCMD_CTRL_RESET);
+}
- /* Set to ULPI */
- REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_ULPI;
- sleep(HZ/10);
-#endif
-
+/* One-time driver startup init */
+void usb_drv_startup(void)
+{
/* Initialize all the signal objects once */
int i;
- for(i=0;i<NUM_ENDPOINTS*2;i++) {
+ for(i=0;i<USB_NUM_ENDPOINTS*2;i++) {
wakeup_init(&transfer_completion_signal[i]);
}
}
/* manual: 32.14.1 Device Controller Initialization */
-void usb_drv_init(void)
+static void _usb_drv_init(bool attach)
{
- REG_USBCMD &= ~USBCMD_RUN;
- sleep(HZ/20);
- REG_USBCMD |= USBCMD_CTRL_RESET;
- while (REG_USBCMD & USBCMD_CTRL_RESET);
-
+ usb_drv_reset();
REG_USBMODE = USBMODE_CTRL_MODE_DEVICE;
-#if CONFIG_CPU == IMX31L
- /* Set to ULPI */
- REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_ULPI;
-#endif
-
#ifdef USB_NO_HIGH_SPEED
/* Force device to full speed */
/* See 32.9.5.9.2 */
@@ -436,69 +418,76 @@ void usb_drv_init(void)
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;
-
-#if CONFIG_CPU == IMX31L
- avic_enable_int(USB_OTG, IRQ, 7, USB_OTG_HANDLER);
-#else
- /* enable USB IRQ in CPU */
- CPU_INT_EN = USB_MASK;
+#ifdef USB_DETECT_BY_DRV
+ if (!attach) {
+ /* enable RESET interrupt */
+ REG_USBINTR = USBINTR_RESET_EN;
+ }
+ else
#endif
+ {
+ /* enable USB interrupts */
+ REG_USBINTR =
+ USBINTR_INT_EN |
+ USBINTR_ERR_INT_EN |
+ USBINTR_PTC_DETECT_EN |
+ USBINTR_RESET_EN;
+ }
+
+ usb_drv_int_enable(true);
/* 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)attach;
}
-void usb_drv_exit(void)
+/** With USB_DETECT_BY_DRV, attach is distinct from init, otherwise eqivalent. **/
+
+/* USB_DETECT_BY_DRV - enable bus reset detection only
+ * else fully enable driver */
+void usb_drv_init(void)
{
- /* disable interrupts */
- REG_USBINTR = 0;
+ _usb_drv_init(false);
+}
- /* stop usb controller */
- REG_USBCMD &= ~USBCMD_RUN;
+#ifdef USB_DETECT_BY_DRV
+/* fully enable driver */
+void usb_drv_attach(void)
+{
+ sleep(HZ/10);
+ _usb_drv_init(true);
+}
+#endif /* USB_DETECT_BY_DRV */
+
+void usb_drv_exit(void)
+{
+ usb_drv_stop();
/* TODO : is one of these needed to save power ?
REG_PORTSC1 |= PORTSCX_PHY_LOW_POWER_SPD;
REG_USBCMD |= USBCMD_CTRL_RESET;
*/
-#if CONFIG_CPU == IMX31L
- avic_disable_int(USB_OTG);
-#else
- CPU_INT_DIS = USB_MASK;
-#endif
-
- cancel_cpu_boost();
+ usb_drv_int_enable(false);
}
-#if CONFIG_CPU == IMX31L
-static void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void)
-#else
void usb_drv_int(void)
-#endif
{
- unsigned int status = REG_USBSTS;
+ unsigned int usbintr = REG_USBINTR; /* Only watch enabled ints */
+ unsigned int status = REG_USBSTS & usbintr;
#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 */
@@ -523,8 +512,18 @@ void usb_drv_int(void)
/* reset interrupt */
if (status & USBSTS_RESET) {
REG_USBSTS = USBSTS_RESET;
- bus_reset();
- usb_core_bus_reset(); /* tell mom */
+#ifdef USB_DETECT_BY_DRV
+ if (UNLIKELY(usbintr == USBINTR_RESET_EN)) {
+ /* USB detected - detach and inform */
+ usb_drv_stop();
+ usb_drv_usb_detect_event();
+ }
+ else
+#endif
+ {
+ bus_reset();
+ usb_core_bus_reset(); /* tell mom */
+ }
}
/* port change */
@@ -588,7 +587,14 @@ int usb_drv_port_speed(void)
bool usb_drv_connected(void)
{
- return ((REG_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) !=0);
+ return (REG_PORTSC1 &
+ (PORTSCX_PORT_SUSPEND | PORTSCX_CURRENT_CONNECT_STATUS))
+ == PORTSCX_CURRENT_CONNECT_STATUS;
+}
+
+bool usb_drv_powered(void)
+{
+ return (REG_OTGSC & OTGSC_B_SESSION_VALID) ? true : false;
}
void usb_drv_set_address(int address)
@@ -628,10 +634,7 @@ void usb_drv_set_test_mode(int mode)
REG_PORTSC1 |= PORTSCX_PTC_FORCE_EN;
break;
}
- REG_USBCMD &= ~USBCMD_RUN;
- sleep(HZ/20);
- REG_USBCMD |= USBCMD_CTRL_RESET;
- while (REG_USBCMD & USBCMD_CTRL_RESET);
+ usb_drv_reset();
REG_USBCMD |= USBCMD_RUN;
}
@@ -735,7 +738,7 @@ void usb_drv_cancel_all_transfers(void)
while (REG_ENDPTFLUSH);
memset(td_array, 0, sizeof td_array);
- for(i=0;i<NUM_ENDPOINTS*2;i++) {
+ for(i=0;i<USB_NUM_ENDPOINTS*2;i++) {
if(qh_array[i].wait) {
qh_array[i].wait=0;
qh_array[i].status=DTD_STATUS_HALTED;
@@ -750,7 +753,7 @@ int usb_drv_request_endpoint(int dir)
bit=(dir & USB_DIR_IN)? 2:1;
- for (i=1; i < NUM_ENDPOINTS; i++) {
+ for (i=1; i < USB_NUM_ENDPOINTS; i++) {
if((ep_allocation[i] & bit)!=0)
continue;
ep_allocation[i] |= bit;
@@ -819,7 +822,7 @@ static void transfer_completed(void)
unsigned int mask = REG_ENDPTCOMPLETE;
REG_ENDPTCOMPLETE = mask;
- for (ep=0; ep<NUM_ENDPOINTS; ep++) {
+ for (ep=0; ep<USB_NUM_ENDPOINTS; ep++) {
int dir;
for (dir=0; dir<2; dir++) {
int pipe = ep * 2 + dir;
@@ -869,13 +872,8 @@ static void bus_reset(void)
logf("usb: double reset");
return;
}
-#if CONFIG_CPU == IMX31L
- int x;
- for (x = 0; x < 30000; x++)
- asm volatile ("");
-#else
+
udelay(100);
-#endif
}
if (REG_ENDPTPRIME) {
logf("usb: short reset timeout");
@@ -917,7 +915,7 @@ static void init_bulk_queue_heads(void)
/* TODO: this should take ep_allocation into account */
/*** bulk ***/
- for(i=1;i<NUM_ENDPOINTS;i++) {
+ for(i=1;i<USB_NUM_ENDPOINTS;i++) {
qh_array[i*2].max_pkt_length = rx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
qh_array[i*2].dtd.next_td_ptr = QH_NEXT_TERMINATE;
qh_array[i*2+1].max_pkt_length = tx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
@@ -930,7 +928,7 @@ static void init_endpoints(void)
int i;
/* TODO: this should take ep_allocation into account */
/* bulk */
- for(i=1;i<NUM_ENDPOINTS;i++) {
+ for(i=1;i<USB_NUM_ENDPOINTS;i++) {
REG_ENDPTCTRL(i) =
EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE |
EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE |
diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c
index a41ef9a..8a6d786 100644
--- a/firmware/target/arm/usb-fw-pp502x.c
+++ b/firmware/target/arm/usb-fw-pp502x.c
@@ -25,13 +25,13 @@
****************************************************************************/
#include "config.h"
#include "system.h"
+#include "usb-target.h"
#include "usb.h"
#include "button.h"
#include "ata.h"
#include "string.h"
#include "usb_core.h"
#include "usb_drv.h"
-#include "usb-target.h"
void usb_init_device(void)
{
@@ -94,6 +94,31 @@ void usb_enable(bool on)
}
}
+void usb_attach(void)
+{
+#ifdef USB_DETECT_BY_DRV
+ usb_drv_attach();
+#else
+ usb_enable(true);
+#endif
+}
+
+#ifdef USB_DETECT_BY_DRV
+/* Cannot tell charger pin from USB pin */
+static int usb_status = USB_EXTRACTED;
+
+void usb_connect_event(bool inserted)
+{
+ usb_status = inserted ? USB_INSERTED : USB_EXTRACTED;
+ usb_status_event(inserted ? USB_POWERED : USB_UNPOWERED);
+}
+
+/* Called during the bus reset interrupt when in detect mode */
+void usb_drv_usb_detect_event(void)
+{
+ usb_status_event(USB_INSERTED);
+}
+#else /* !USB_DETECT_BY_DRV */
static bool usb_pin_detect(void)
{
bool retval = false;
@@ -110,12 +135,12 @@ static bool usb_pin_detect(void)
retval = true;
#elif defined(SANSA_C200)
- /* GPIO H bit 1 is usb detect */
+ /* GPIO H bit 1 is usb/charger detect */
if (GPIOH_INPUT_VAL & 0x02)
retval = true;
#elif defined(SANSA_E200)
- /* GPIO B bit 4 is usb detect */
+ /* GPIO B bit 4 is usb/charger detect */
if (GPIOB_INPUT_VAL & 0x10)
retval = true;
@@ -137,16 +162,32 @@ static bool usb_pin_detect(void)
return retval;
}
+#endif /* USB_DETECT_BY_DRV */
-/* detect host or charger (INSERTED or POWERED) */
+void usb_drv_int_enable(bool enable)
+{
+ /* enable/disable USB IRQ in CPU */
+ if(enable) {
+ CPU_INT_EN = USB_MASK;
+ }
+ else {
+ CPU_INT_DIS = USB_MASK;
+ }
+}
+
+/* detect host or charger (INSERTED or EXTRACTED) */
int usb_detect(void)
{
+#ifdef USB_DETECT_BY_DRV
+ return usb_status;
+#else
if(usb_pin_detect()) {
return USB_INSERTED;
}
else {
return USB_EXTRACTED;
}
+#endif
}
#if defined(IPOD_COLOR) || defined(IPOD_4G) \
diff --git a/firmware/target/arm/usb-target.h b/firmware/target/arm/usb-target.h
index cdf6776..913ad80 100644
--- a/firmware/target/arm/usb-target.h
+++ b/firmware/target/arm/usb-target.h
@@ -23,4 +23,11 @@
void usb_init_device(void);
+#ifndef BOOTLOADER
+#if defined(SANSA_C200) || defined(SANSA_E200)
+#define USB_STATUS_BY_EVENT /* No USB tick */
+void usb_connect_event(bool inserted);
+#endif
+#endif /* BOOTLOADER */
+
#endif
diff --git a/firmware/usb.c b/firmware/usb.c
index 918d980..10a7ae1 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -34,11 +34,11 @@
#include "disk.h"
#include "panic.h"
#include "lcd.h"
+#include "usb-target.h"
#include "usb.h"
#include "button.h"
#include "sprintf.h"
#include "string.h"
-#include "usb-target.h"
#ifdef HAVE_USBSTACK
#include "usb_core.h"
#endif
@@ -129,11 +129,13 @@ static inline void usb_slave_mode(bool on)
#ifdef HAVE_PRIORITY_SCHEDULING
thread_set_priority(THREAD_ID_CURRENT, PRIORITY_REALTIME);
#endif
- usb_enable(true);
+ usb_attach();
}
else /* usb_state == USB_INSERTED (only!) */
{
+#ifndef USB_DETECT_BY_DRV
usb_enable(false);
+#endif
#ifdef HAVE_PRIORITY_SCHEDULING
thread_set_priority(THREAD_ID_CURRENT, PRIORITY_SYSTEM);
#endif
@@ -234,6 +236,26 @@ static void usb_thread(void)
(struct usb_transfer_completion_event_data*)ev.data);
break;
#endif
+#ifdef USB_DETECT_BY_DRV
+ /* In this case, these events the handle cable insertion USB
+ * driver determines INSERTED/EXTRACTED state. */
+ case USB_POWERED:
+ /* Set the state to USB_POWERED for now and enable the driver
+ * to detect a bus reset only. If a bus reset is detected,
+ * USB_INSERTED will be received. */
+ usb_state = USB_POWERED;
+ usb_enable(true);
+ break;
+
+ case USB_UNPOWERED:
+ usb_enable(false);
+ /* This part shouldn't be obligatory for anything that can
+ * reliably detect removal of the data lines. USB_EXTRACTED
+ * could be posted on that event while bus power remains
+ * available. */
+ queue_post(&usb_queue, USB_EXTRACTED, 0);
+ break;
+#endif /* USB_DETECT_BY_DRV */
case USB_INSERTED:
#ifdef HAVE_LCD_BITMAP
if(do_screendump_instead_of_usb)
@@ -244,14 +266,14 @@ static void usb_thread(void)
}
#endif
#ifdef HAVE_USB_POWER
- if (usb_power_button())
+ if(usb_power_button())
{
/* Only charging is desired */
usb_state = USB_POWERED;
#ifdef HAVE_USBSTACK
usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false);
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true);
- usb_enable(true);
+ usb_attach();
#endif
break;
}
@@ -272,7 +294,7 @@ static void usb_thread(void)
if(!exclusive_storage_access)
{
- usb_enable(true);
+ usb_attach();
break;
}
#endif /* HAVE_USBSTACK */
@@ -304,7 +326,7 @@ static void usb_thread(void)
usb_state = USB_EXTRACTED;
break; /* Connected for screendump only */
}
-#endif /* HAVE_LCD_BITMAP */
+#endif
#ifndef HAVE_USBSTACK /* Stack must undo this if POWERED state was transitional */
#ifdef HAVE_USB_POWER
if(usb_state == USB_POWERED)
@@ -312,7 +334,7 @@ static void usb_thread(void)
usb_state = USB_EXTRACTED;
break;
}
-#endif /* HAVE_USB_POWER */
+#endif
#endif /* HAVE_USBSTACK */
if(usb_state == USB_INSERTED)
{
@@ -324,9 +346,11 @@ static void usb_thread(void)
usb_state = USB_EXTRACTED;
#ifdef HAVE_USBSTACK
- if (!exclusive_storage_access)
+ if(!exclusive_storage_access)
{
+#ifndef USB_DETECT_BY_DRV /* Disabled handling USB_UNPOWERED */
usb_enable(false);
+#endif
break;
}
@@ -392,19 +416,34 @@ static void usb_thread(void)
#ifdef USB_STATUS_BY_EVENT
void usb_status_event(int current_status)
{
- /* Status should be USB_INSERTED or USB_EXTRACTED.
+ /* Status should be USB_POWERED, USB_UNPOWERED, USB_INSERTED or
+ * USB_EXTRACTED.
* Caller isn't expected to filter for changes in status. */
- if (usb_monitor_enabled && last_usb_status != current_status)
+ if(usb_monitor_enabled)
{
- last_usb_status = current_status;
- queue_post(&usb_queue, current_status, 0);
+ int oldstatus = disable_irq_save(); /* Dual-use function */
+
+ if(last_usb_status != current_status)
+ {
+ last_usb_status = current_status;
+ queue_post(&usb_queue, current_status, 0);
+ }
+
+ restore_irq(oldstatus);
}
}
void usb_start_monitoring(void)
{
+ int status = usb_detect();
+#ifdef USB_DETECT_BY_DRV
+ /* USB detection begins by USB_POWERED, not USB_INSERTED. If it is
+ * USB_EXTRACTED, then nothing changes and post will be skipped. */
+ if(USB_INSERTED == status)
+ status = USB_POWERED;
+#endif
usb_monitor_enabled = true;
- usb_status_event(usb_detect());
+ usb_status_event(status);
}
#else /* !USB_STATUS_BY_EVENT */
static void usb_tick(void)
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c
index 50c9d85..5fac5d3 100644
--- a/firmware/usbstack/usb_core.c
+++ b/firmware/usbstack/usb_core.c
@@ -175,7 +175,7 @@ static struct
completion_handler_t completion_handler[2];
control_handler_t control_handler[2];
struct usb_transfer_completion_event_data completion_event;
-} ep_data[NUM_ENDPOINTS];
+} ep_data[USB_NUM_ENDPOINTS];
static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
{
@@ -240,7 +240,7 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
static void usb_core_control_request_handler(struct usb_ctrlrequest* req);
-static unsigned char response_data[256] USBDEVBSS_ATTR;
+static unsigned char response_data[256] USB_DEVBSS_ATTR;
static short hex[16] = {'0','1','2','3','4','5','6','7',
@@ -476,7 +476,7 @@ static void allocate_interfaces_and_endpoints(void)
memset(ep_data,0,sizeof(ep_data));
- for (i = 0; i < NUM_ENDPOINTS; i++) {
+ for (i = 0; i < USB_NUM_ENDPOINTS; i++) {
usb_drv_release_endpoint(i | USB_DIR_OUT);
usb_drv_release_endpoint(i | USB_DIR_IN);
}
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c
index a70681d..e2d58cf 100644
--- a/firmware/usbstack/usb_storage.c
+++ b/firmware/usbstack/usb_storage.c
@@ -401,7 +401,7 @@ void usb_storage_init_connection(void)
#if CONFIG_CPU == IMX31L || CONFIG_USBOTG == USBOTG_ISP1583 || \
defined(CPU_TCC77X) || defined(CPU_TCC780X)
static unsigned char _transfer_buffer[BUFFER_SIZE*2]
- USBDEVBSS_ATTR __attribute__((aligned(32)));
+ USB_DEVBSS_ATTR __attribute__((aligned(32)));
tb.transfer_buffer = (void *)_transfer_buffer;
#else
/* TODO : check if bufsize is at least 32K ? */