diff options
| author | Michael Sevakis <jethead71@rockbox.org> | 2009-01-19 13:41:25 +0000 |
|---|---|---|
| committer | Michael Sevakis <jethead71@rockbox.org> | 2009-01-19 13:41:25 +0000 |
| commit | 616c98b38f6ddac0ac3dde8ec0fa248f835717e2 (patch) | |
| tree | 5eeeabb85fbefa162a438edca88611c1bc688269 /firmware | |
| parent | cef6399c4c3bcaa35733bdab8b9016b66b71a6f0 (diff) | |
| download | rockbox-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
Diffstat (limited to 'firmware')
| -rw-r--r-- | firmware/export/config-c200.h | 3 | ||||
| -rw-r--r-- | firmware/export/config-e200.h | 3 | ||||
| -rw-r--r-- | firmware/export/config-gigabeat-s.h | 6 | ||||
| -rwxr-xr-x | firmware/export/imx31l.h | 8 | ||||
| -rw-r--r-- | firmware/export/pp5020.h | 7 | ||||
| -rw-r--r-- | firmware/export/usb.h | 8 | ||||
| -rw-r--r-- | firmware/export/usb_core.h | 10 | ||||
| -rw-r--r-- | firmware/export/usb_drv.h | 6 | ||||
| -rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/system-target.h | 8 | ||||
| -rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/usb-imx31.c | 35 | ||||
| -rw-r--r-- | firmware/target/arm/powermgmt-ascodec.c | 10 | ||||
| -rw-r--r-- | firmware/target/arm/usb-drv-arc.c | 186 | ||||
| -rw-r--r-- | firmware/target/arm/usb-fw-pp502x.c | 49 | ||||
| -rw-r--r-- | firmware/target/arm/usb-target.h | 7 | ||||
| -rw-r--r-- | firmware/usb.c | 65 | ||||
| -rw-r--r-- | firmware/usbstack/usb_core.c | 6 | ||||
| -rw-r--r-- | firmware/usbstack/usb_storage.c | 2 |
17 files changed, 276 insertions, 143 deletions
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 ? */ |