From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- usb/otg/compiler.h | 65 ++ usb/otg/usb_drv.c | 246 ++++++ usb/otg/usb_drv.h | 859 +++++++++++++++++++ usb/otg/usb_host_enum.c | 670 +++++++++++++++ usb/otg/usb_host_enum.h | 329 ++++++++ usb/otg/usb_host_enum_with_srp_hnp.c | 754 +++++++++++++++++ usb/otg/usb_host_task.c | 1260 ++++++++++++++++++++++++++++ usb/otg/usb_host_task.h | 230 ++++++ usb/otg/usb_host_task_with_srp_hnp.c | 1493 ++++++++++++++++++++++++++++++++++ usb/otg/usb_task.c | 999 +++++++++++++++++++++++ usb/otg/usb_task.h | 232 ++++++ usb/otg/usb_task_host_only.c | 287 +++++++ usb/otg/usb_task_with_SRP_HNP.c | 852 +++++++++++++++++++ 13 files changed, 8276 insertions(+) create mode 100644 usb/otg/compiler.h create mode 100644 usb/otg/usb_drv.c create mode 100644 usb/otg/usb_drv.h create mode 100644 usb/otg/usb_host_enum.c create mode 100644 usb/otg/usb_host_enum.h create mode 100644 usb/otg/usb_host_enum_with_srp_hnp.c create mode 100644 usb/otg/usb_host_task.c create mode 100644 usb/otg/usb_host_task.h create mode 100644 usb/otg/usb_host_task_with_srp_hnp.c create mode 100644 usb/otg/usb_task.c create mode 100644 usb/otg/usb_task.h create mode 100644 usb/otg/usb_task_host_only.c create mode 100644 usb/otg/usb_task_with_SRP_HNP.c (limited to 'usb/otg') diff --git a/usb/otg/compiler.h b/usb/otg/compiler.h new file mode 100644 index 0000000..b85521b --- /dev/null +++ b/usb/otg/compiler.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _COMPILER_H_ +#define _COMPILER_H_ + +typedef float Float16; +typedef unsigned char U8 ; +typedef unsigned short U16; +typedef unsigned long U32; +typedef unsigned char Bool; + +typedef unsigned char Byte; + +typedef char bit; + +#define MSB0(u32) (((U8* )&u32)[3]) +#define MSB1(u32) (((U8* )&u32)[2]) +#define MSB2(u32) (((U8* )&u32)[1]) +#define MSB3(u32) (((U8* )&u32)[0]) +#define LSB0(u32) MSB3(u32) +#define LSB1(u32) MSB2(u32) +#define LSB2(u32) MSB1(u32) +#define LSB3(u32) MSB0(u32) +#define MSB(u16) (((U8* )&u16)[1]) +#define LSB(u16) (((U8* )&u16)[0]) +#define MSW(u32) (((U16*)&u32)[1]) +#define LSW(u32) (((U16*)&u32)[0]) + + +// Constants +#define DISABLE 0 +#define ENABLE 1 + +#define TRUE (1 == 1) +#define FALSE (0 == 1) + +#endif /* _COMPILER_H_ */ + diff --git a/usb/otg/usb_drv.c b/usb/otg/usb_drv.c new file mode 100644 index 0000000..c29689c --- /dev/null +++ b/usb/otg/usb_drv.c @@ -0,0 +1,246 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "usb_drv.h" +#include + +U8 global_pipe_nb=0; +U8 global_endpoint_nb=0; +unsigned char dBytes=0; +char* pFifo; + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//! This function configures an endpoint with the selected type. +U8 dev_configure_endpoint(U8 ept, U8 type, U8 dir, U8 size, U8 bank, U8 nyet) +{ + unsigned char status=0; + + // Enable endpoint + AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (1<OTGHS_DEVEPTCFG[ept] = (bank<<2)|(size<<4)|(dir<<8) + |AT91C_OTGHS_AUTOSW |(type<<11); + + AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[ept] |= AT91C_OTGHS_ALLOC; + if(!(AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[ept]&AT91C_OTGHS_CFGOK)) { + TRACE_ERROR("Bad endpoint configuration\n\r"); + status = 1; + } + if(nyet == NYET_ENABLED) { + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[ept] = AT91C_OTGHS_NYETDIS; + } + else { + AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[ept] = AT91C_OTGHS_NYETDIS; + } + return status; +} + + + + +//------------------------------------------------------------------------------ +// HOST +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +//! This function configures a pipe with the selected type. +//! @param config0 +//! @param config1 +//! @return Is_endpoint_configured. +//------------------------------------------------------------------------------ +U8 host_config_pipe(U8 config0, U8 config1) +{ + TRACE_DEBUG("host_config_pipe\n\r"); + Host_enable_pipe(); +// UPCFG0X = config0; +// UPCFG1X = config1; + Host_allocate_memory(); + return (Is_pipe_configured()); +} + +//------------------------------------------------------------------------------ +//! This function returns the size configuration register value according +//! to the endpint size detected inthe device enumeration process. +//! @return pipe size register value. +//------------------------------------------------------------------------------ +U8 host_determine_pipe_size(U16 size) +{ + //TRACE_DEBUG("host_determine_pipe_size\n\r"); + if(size <= 8 ) {return (SIZE_8 );} + else if(size <= 16 ) {return (SIZE_16 );} + else if(size <= 32 ) {return (SIZE_32 );} + else if(size <= 64 ) {return (SIZE_64 );} + else if(size <= 128) {return (SIZE_128 );} + else if(size <= 256) {return (SIZE_256 );} + else if(size <= 512) {return (SIZE_512 );} + else {return (SIZE_1024);} +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +U16 host_get_pipe_length(void) +{ + unsigned int size; + + size = (AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PSIZE)>>4; + //TRACE_DEBUG("host_get_pipe_length = %d\n\r", (int)size); + + if(size == SIZE_8 ) {return (8 );} + else if(size == SIZE_16 ) {return (16 );} + else if(size == SIZE_32 ) {return (32 );} + else if(size == SIZE_64 ) {return (64 );} + else if(size == SIZE_128) {return (128);} + else if(size == SIZE_256) {return (256);} + else if(size == SIZE_512) {return (512);} + else if(size == SIZE_1024){return (1024);} + else {TRACE_ERROR("Error size\n\r");return 0;} +} + + +//------------------------------------------------------------------------------ +//! host_disable_all_pipe. +//! +//! This function disable all pipes for the host controller +//! Usefull to execute upon device disconnection. +//! +//! @return none. +//------------------------------------------------------------------------------ +void host_disable_all_pipe(void) +{ + U8 i; + + TRACE_DEBUG("host_disable_all_pipe\n\r"); + for (i=0; i<7; i++) { + Host_reset_pipe(i); + Host_select_pipe(i); + Host_unallocate_memory(); + Host_disable_pipe(); + } +} + +//------------------------------------------------------------------------------ +//! @brief Returns the pipe number that generates a USB communication interrupt +//! +//! This function sould be called only when an interrupt has been detected. Otherwize +//! the return value is incorect +//! +//! @param none +//! +//! @return pipe_number +//------------------------------------------------------------------------------ +U8 host_get_nb_pipe_interrupt(void) +{ + U8 interrupt_flags; + U8 i; + + TRACE_DEBUG("host_get_nb_pipe_interrupt\n\r"); + interrupt_flags = Host_get_pipe_interrupt(); + for(i=0; iOTGHS_HSTADDR1 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P0; + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= ((addr<<0) & AT91C_OTGHS_UHADDR_P0); + } + else if( pipe == 1 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P1; + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= ((addr<<8) & AT91C_OTGHS_UHADDR_P1); + } + else if( pipe == 2 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P2; + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= ((addr<<16) & AT91C_OTGHS_UHADDR_P2); + } + else if( pipe == 3 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P3; + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= ((addr<<24) & AT91C_OTGHS_UHADDR_P3); + } + else if( pipe == 4 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P4; + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 |= ((addr<<0) & AT91C_OTGHS_UHADDR_P4); + } + else if( pipe == 5 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P5; + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 |= ((addr<<8) & AT91C_OTGHS_UHADDR_P5); + } + else if( pipe == 6 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P6; + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 |= ((addr<<16) & AT91C_OTGHS_UHADDR_P6); + } + else if( pipe == 7 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P7; + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 |= ((addr<<24) & AT91C_OTGHS_UHADDR_P7); + } + else if( pipe == 8 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR3 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P8; + AT91C_BASE_OTGHS->OTGHS_HSTADDR3 |= ((addr<<0) & AT91C_OTGHS_UHADDR_P8); + } + else if( pipe == 9 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR3 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P9; + AT91C_BASE_OTGHS->OTGHS_HSTADDR3 |= ((addr<<8) & AT91C_OTGHS_UHADDR_P9); + } + else { + TRACE_ERROR("pipe not defined\n\r"); + } +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +void host_configure_pipe(U8 pip, U8 type, U8 token, U8 ep_num, U8 size, U8 bank, U8 freq) +{ + AT91C_BASE_OTGHS->OTGHS_HSTPIP |= (1<OTGHS_HSTPIPCFG[pip] = (bank<< 2) | (size << 4) | (token<< 8) + | (type<<12) |(ep_num<<16)| (freq <<24); + AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[pip] |= AT91C_OTGHS_ALLOC; +} + + diff --git a/usb/otg/usb_drv.h b/usb/otg/usb_drv.h new file mode 100644 index 0000000..c9276fe --- /dev/null +++ b/usb/otg/usb_drv.h @@ -0,0 +1,859 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/// This file contains the USB low level driver definition + + +#ifndef _USB_DRV_H +#define _USB_DRV_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include "board.h" + +extern unsigned char dBytes; +extern char* pFifo_ctrl; +extern char* pFifo; + +//#define Address_fifo_endpoint(ep) (char*)&(AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[EPT_VIRTUAL_SIZE*ep]) +#define Address_fifochar_endpoint(ep) pFifo = (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * ep));dBytes=0 +//#define Address_fifochar_endpoint(ep) (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * ep)) +#define Address_fifo_endpoint(ep) (int*) ((int)(AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0) + (EPT_VIRTUAL_SIZE*(ep))) + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// USB_low_level_drivers USB low level drivers module + +#define MAX_EP_NB 7 + +#define EPT_VIRTUAL_SIZE 8192 + +#define EP_CONTROL 0 +#define PIPE_CONTROL 0 + +// USB EndPoint +#define MSK_EP_DIR 0x7F + +// Parameters for endpoint configuration +// These define are the values used to enable and configure an endpoint. +#define TYPE_CONTROL 0 +#define TYPE_ISOCHRONOUS 1 +#define TYPE_BULK 2 +#define TYPE_INTERRUPT 3 + +#define DIRECTION_OUT 0 +#define DIRECTION_IN 1 + +#define SIZE_8 0 +#define SIZE_16 1 +#define SIZE_32 2 +#define SIZE_64 3 +#define SIZE_128 4 +#define SIZE_256 5 +#define SIZE_512 6 +#define SIZE_1024 7 + +#define ONE_BANK 0 +#define TWO_BANKS 1 +#define TREE_BANKS 2 + +#define NYET_ENABLED 0 +#define NYET_DISABLED 1 + +#define TOKEN_SETUP 0 +#define TOKEN_IN 1 +#define TOKEN_OUT 2 + +#define Is_ep_addr_in(x) (x & 0x80) + +//Set_bits(AVR32_USB_uatst1,AVR32_USB_UATST1_LOADCNTA_MASK); +#define Usb_load_tsta1_countMask() AT91C_BASE_OTGHS->OTGHS_TSTA1 &= ~(unsigned int)AT91C_OTGHS_COUNTERA + +//#define AVR32_USB_UATST1_LOADCNTA_MASK_NONZERO 0x00008001 +#define Usb_load_tsta1_counta() AT91C_BASE_OTGHS->OTGHS_TSTA1 = AT91C_OTGHS_LOADCNTA | (AT91C_OTGHS_COUNTERA&0x01) + +//#define AVR32_USB_UATST2_FORCE_51MS_RESETHS_MASK 0x00000080 +#define USb_ForceHSRst_50ms() AT91C_BASE_OTGHS->OTGHS_TSTA2 |= AT91C_OTGHS_FORCHSRST + +//#define AVR32_USB_UATST2_FORCE_RESET_UTMI 0x00000100 +#define Usb_SetForceResetUTMI() AT91C_BASE_OTGHS->OTGHS_TSTA2 |= AT91C_OTGHS_UTMIRESET +#define Usb_ClrForceResetUTMI() AT91C_BASE_OTGHS->OTGHS_TSTA2 &= ~(unsigned int)AT91C_OTGHS_UTMIRESET + +//#define AVR32_USB_UATST2_HOSTHSDISCONNECTDISABLE_MASK +#define Usb_SetHSTDiconnectDisableMask() AT91C_BASE_OTGHS->OTGHS_TSTA2 |= AT91C_OTGHS_HSTHSDISCDIS +#define Usb_ClrHSTDiconnectDisableMask() AT91C_BASE_OTGHS->OTGHS_TSTA2 &= ~(unsigned int)AT91C_OTGHS_HSTHSDISCDIS + +#define Usb_enable_vbus_error_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_VBERR + +#define Is_Usb_InHighSpeed() (AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_SPEED_SR) == AT91C_OTGHS_SPEED_SR_HS + +/// OTG Timers customizing +// HOST : Minimum delay after Vbus requested to get it > Va_vbus_valid (otherwise => error) +//#define VBUSRISE_20MS 0x00 +//#define VBUSRISE_50MS 0x01 +#define VBUSRISE_70MS 0x02 +//#define VBUSRISE_100MS 0x03 +// DEVICE : Duration of Vbus pulse during SRP protocol +//#define VBUSPULSE_15MS 0x20 +//#define VBUSPULSE_23MS 0x21 +//#define VBUSPULSE_31MS 0x22 +#define VBUSPULSE_40MS 0x23 +// DEVICE : Minimum delay after Vbus < Vb_sess_end to enable SRP +//#define VFALLTMOUT_93MS 0x40 +//#define VFALLTMOUT_105MS 0x41 +//#define VFALLTMOUT_118MS 0x42 +#define VFALLTMOUT_131MS 0x43 +// HOST : Minimum pulse duration accepted as SRP pulse +//#define SRPMINDET_10US 0x60 +#define SRPMINDET_100US 0x61 +//#define SRPMINDET_1MS 0x62 +//#define SRPMINDET_11MS 0x63 + +//------------------------------------------------------------------------------ +// A R B I T R E R +//------------------------------------------------------------------------------ + +/// gen_usb USB common management drivers +/// These macros manage the USB controller + +/// Enable external UID pin +//#define Usb_enable_uid_pin() (UHWCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_UIDE +/// Disable external UID pin +//#define Usb_disable_uid_pin() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_UIDE +/// Disable external UID pin and force device mode +//#define Usb_force_device_mode() //{AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_UIDE; + // AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_UIMOD;} +/// Disable external UID pin and force host mode +//#define Usb_force_host_mode() //{AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_UIDE; + // AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_UIMOD;} +/// Enable external UVCON pin +//#define Usb_enable_uvcon_pin() // (UHWCON |= (1<OTGHS_DEVCTRL |= AT91C_OTGHS_LS + +#define Usb_enable() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_USBECTRL +#define Usb_disable() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_USBECTRL + +/// Enable VBUS pad +//#define Usb_enable_vbus_pad() (USBCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_USBECTRL;\ + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_OTGPADE;\ + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL;} +/// Disable VBUS pad +//#define Usb_disable_vbus_pad() (USBCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_OTGPADE + +#define Usb_select_device() Usb_enable_uid_pin() +#define Usb_select_host() Usb_enable_uid_pin() +#define Is_usb_device_enabled() (AT91C_BASE_OTGHS->OTGHS_SR & AT91C_OTGHS_ID) +#define Is_usb_host_enabled() !Is_usb_device_enabled() +/// Stop internal USB clock in interface (freeze the interface register) +//#define Usb_freeze_clock() (USBCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_FRZCLKCTRL +//jcb +//#define Usb_unfreeze_clock() (USBCON &= ~(1<OTGHS_CTRL &= ~AT91C_OTGHS_FRZCLKCTRL +//#define Is_usb_clock_freezed() ((USBCON & (1<OTGHS_CTRL & AT91C_OTGHS_FRZCLKCTRL) + +//#define Usb_enable_id_interrupt() (USBCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_IDT +//#define Usb_disable_id_interrupt() (USBCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_IDT +//#define Is_usb_id_interrupt_enabled() ((USBCON & (1<OTGHS_CTRL & AT91C_OTGHS_IDT) +//#define Is_usb_id_device() ((USBSTA & (1<OTGHS_SR & AT91C_OTGHS_ID) +//#define Is_usb_id_host() ((USBSTA & (1<OTGHS_SCR = AT91C_OTGHS_IDT +//#define Is_usb_id_transition() ((USBINT & (1<OTGHS_SR & AT91C_OTGHS_IDT) + +//#define Usb_enable_vbus_interrupt() (USBCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_VBUSTI +//#define Usb_disable_vbus_interrupt() (USBCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_VBUSTI +//#define Is_usb_vbus_interrupt_enabled() ((USBCON & (1<OTGHS_CTRL & AT91C_OTGHS_VBUSTI) +//#define Is_usb_vbus_high() ((USBSTA & (1<OTGHS_SR&AT91C_OTGHS_VBUSSR)==AT91C_OTGHS_VBUSSR) +//#define Is_usb_vbus_low() ((USBSTA & (1<OTGHS_SR&AT91C_OTGHS_VBUSSR)!=AT91C_OTGHS_VBUSSR) +//#define Usb_ack_vbus_transition() (USBINT = ~(1<OTGHS_SCR = AT91C_OTGHS_VBUSTI +//#define Is_usb_vbus_transition() ((USBINT & (1<OTGHS_CTRL & AT91C_OTGHS_VBUSTI) + +/// requests for VBus activation +//#define Usb_enable_vbus() (OTGCON |= (1<OTGHS_SFR = AT91C_OTGHS_VBUSRQ //JCB +/// requests for VBus desactivation +#define Usb_disable_vbus() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_VBUSRQ //JCB +/// Manually request VBUS without UVCON signal from USB interface +//#define Usb_disable_uvcon_pin() (UHWCON &= ~(1<OTGHS_SFR = AT91C_OTGHS_VBUSRQ //JCB +/// Manually request VBUS OFF without UVCON signal from USB interface +//#define Usb_disable_manual_vbus() (PORTE&=~0x80,DDRE|=0x80,Usb_enable_uvcon_pin()) +#define Usb_disable_manual_vbus() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_VBUSRQ //JCB + +/// initiates a Host Negociation Protocol +//#define Usb_device_initiate_hnp() (OTGCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_HNPREQ +/// stops a Host Negociation Protocol +//#define Usb_device_stop_hnp() (OTGCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPREQ +/// accepts a Host Negociation Protocol +//#define Usb_host_accept_hnp() (OTGCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_HNPREQ +/// rejects a Host Negociation Protocol +//#define Usb_host_reject_hnp() (OTGCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPREQ +/// initiates a Session Request Protocol +//#define Usb_device_initiate_srp() (OTGCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_SRPREQ +/// selects VBus as SRP method +//#define Usb_select_vbus_srp_method() (OTGCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_SRPSEL +/// selects data line as SRP method +//#define Usb_select_data_srp_method() (OTGCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_SRPSEL + + +/// enables hardware control on VBus +#define Usb_enable_vbus_hw_control() // AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_VBUSHWC +/// disables hardware control on VBus +#define Usb_disable_vbus_hw_control() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_VBUSHWC +/// tests if VBus has been requested +//#define Is_usb_vbus_enabled() ((OTGCON & (1<OTGHS_SR&AT91C_OTGHS_ROLEEX) == AT91C_OTGHS_ROLEEX) +/// tests if a SRP from device occurs +//#define Is_usb_device_srp() ((OTGCON & (1<OTGHS_CTRL&AT91C_OTGHS_SRPREQ) + +/// acks suspend time out interrupt +//#define Usb_ack_suspend_time_out_interrupt() (OTGINT &= ~(1<OTGHS_SCR = AT91C_OTGHS_STO +/// enables suspend time out interrupt +//#define Usb_enable_suspend_time_out_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_STO +/// disables suspend time out interrupt +//#define Usb_disable_suspend_time_out_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_STO +//#define Is_suspend_time_out_interrupt_enabled() ((OTGIEN & (1<OTGHS_CTRL&AT91C_OTGHS_STO)==AT91C_OTGHS_STO) +/// tests if a suspend time out occurs +//#define Is_usb_suspend_time_out_interrupt() ((OTGINT & (1<OTGHS_SR&AT91C_OTGHS_STO)==AT91C_OTGHS_STO) + +/// enables HNP error interrupt +//#define Usb_enable_hnp_error_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_HNPERR +/// disables HNP error interrupt +//#define Usb_disable_hnp_error_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPERR +//#define Is_hnp_error_interrupt_enabled() ((OTGIEN & (1<OTGHS_CTRL&AT91C_OTGHS_HNPERR)==AT91C_OTGHS_HNPERR) +/// acks HNP error interrupt +//#define Usb_ack_hnp_error_interrupt() (OTGINT &= ~(1<OTGHS_SCR |= AT91C_OTGHS_HNPERR +/// tests if a HNP error occurs +//#define Is_usb_hnp_error_interrupt() ((OTGINT & (1<OTGHS_SR&AT91C_OTGHS_HNPERR) == AT91C_OTGHS_HNPERR) + +/// enables role exchange interrupt +//#define Usb_enable_role_exchange_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_ROLEEX +/// disables role exchange interrupt +//#define Usb_disable_role_exchange_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_ROLEEX +//#define Is_role_exchange_interrupt_enabled() ((OTGIEN & (1<OTGHS_CTRL&AT91C_OTGHS_ROLEEX)==AT91C_OTGHS_ROLEEX) +/// acks role exchange interrupt +//#define Usb_ack_role_exchange_interrupt() (OTGINT &= ~(1<OTGHS_SCR |= AT91C_OTGHS_ROLEEX +/// tests if a role exchange occurs +//#define Is_usb_role_exchange_interrupt() ((OTGINT & (1<OTGHS_SR&AT91C_OTGHS_ROLEEX)==AT91C_OTGHS_ROLEEX) + +/// enables B device connection error interrupt +//#define Usb_enable_bconnection_error_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_BCERR +/// disables B device connection error interrupt +//#define Usb_disable_bconnection_error_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_BCERR +//#define Is_bconnection_error_interrupt_enabled() ((OTGIEN & (1<OTGHS_SCR = AT91C_OTGHS_BCERR +/// tests if a B device connection error occurs +#define Is_usb_bconnection_error_interrupt() FALSE//jcb (AT91C_BASE_OTGHS->OTGHS_SR & AT91C_OTGHS_BCERR) + +/// enables VBus error interrupt +//#define Usb_enable_vbus_error_interrupt() (OTGIEN |= (1<OTGHS_SCR = AT91C_OTGHS_VBERR +/// tests if a VBus error occurs +#define Is_usb_vbus_error_interrupt() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_VBERR)==AT91C_OTGHS_VBERR) + +/// enables SRP interrupt +//#define Usb_enable_srp_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_SRP +/// disables SRP interrupt +//#define Usb_disable_srp_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_SRP +//#define Is_srp_interrupt_enabled() ((OTGIEN & (1<OTGHS_CTRL&AT91C_OTGHS_SRP)==AT91C_OTGHS_SRP) +/// acks SRP interrupt +#define Usb_ack_srp_interrupt() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_SRP +/// tests if a SRP occurs +#define Is_usb_srp_interrupt() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_SRP)==AT91C_OTGHS_SRP) + + +//------------------------------------------------------------------------------ +// D E V I C E +//------------------------------------------------------------------------------ + +/// USB_device_driver USB device controller drivers +/// These macros manage the USB Device controller. + +/// test if remote wake-up still running +//#define Is_usb_pending_remote_wake_up() ((UDCON & (1<OTGHS_DEVCTRL | AT91C_OTGHS_RMWKUP) +/// acks remote wake-up +//#define Usb_ack_remote_wake_up_start() (UDINT = ~(1<OTGHS_DEVICR = AT91C_OTGHS_UPRSM + +/// enables resume interrupt +//#define Usb_enable_resume_interrupt() (UDIEN |= (1<OTGHS_DEVIDR = AT91C_OTGHS_EORSM +#define Is_resume_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_EORSM) +/// acks resume +#define Usb_ack_resume() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_EORSM +/// tests if resume occurs +#define Is_usb_resume() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_EORSM) + +/// enables wake-up interrupt +#define Usb_enable_wake_up_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_WAKEUP +/// disables wake-up interrupt +#define Usb_disable_wake_up_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIDR = AT91C_OTGHS_WAKEUP +#define Is_swake_up_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_DEVIMR & AT91C_OTGHS_WAKEUP) +/// acks wake-up +#define Usb_ack_wake_up() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_WAKEUP +/// tests if wake-up occurs +#define Is_usb_wake_up() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_WAKEUP) + +/// enables USB reset interrupt +#define Usb_enable_reset_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_EORST +/// disables USB reset interrupt +//#define Usb_disable_reset_interrupt() (UDIEN &= ~(1<OTGHS_DEVIMR & AT91C_OTGHS_EORST) +/// acks USB reset +#define Usb_ack_reset() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_EORST +/// tests if USB reset occurs +#define Is_usb_reset() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_EORST) + +/// enables Start Of Frame Interrupt +#define Usb_enable_sof_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_SOF +/// disables Start Of Frame Interrupt +//#define Usb_disable_sof_interrupt() (UDIEN &= ~(1<OTGHS_DEVIDR = AT91C_OTGHS_SOF +#define Is_sof_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_DEVIMR & AT91C_OTGHS_SOF) +/// acks Start Of Frame +#define Usb_ack_sof() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_SOF +/// tests if Start Of Frame occurs +#define Is_usb_sof() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_SOF) + +/// enables suspend state interrupt +#define Usb_enable_suspend_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_SUSP +/// disables suspend state interrupt +//#define Usb_disable_suspend_interrupt() (UDIEN &= ~(1<OTGHS_DEVIDR = AT91C_OTGHS_SUSP +#define Is_suspend_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_DEVIMR & AT91C_OTGHS_SUSP) +/// acks Suspend +#define Usb_ack_suspend() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_SUSP +/// tests if Suspend state detected +#define Is_usb_suspend() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_SUSP) + +/// returns the last frame number +//#define Usb_frame_number() ((unsigned short)((((unsigned short)UDFNUMH) << 8) | ((unsigned short)UDFNUML))) +/// tests if a crc error occurs in frame number +//#define Is_usb_frame_number_crc_error() ((UDMFN & (1<OTGHS_DEVFNUM&AT91C_OTGHS_FRAME_NUMBER)>>3) + + +// **************************************************************************** +// **************************************************************************** +// H O S T +// **************************************************************************** +// **************************************************************************** + +/// @defgroup host_management USB host controller drivers +/// These macros manage the USB Host controller. +/// @{ +/// allocates the current configuration in DPRAM memory +//#define Host_allocate_memory() (UPCFG1X |= (1<OTGHS_HSTPIPISR[pip] & AT91C_OTGHS_CFGOK))?FALSE:TRUE) + +/// enables SOF generation +//#define Host_enable_sof() (UHCON |= (1<OTGHS_HSTCTRL |= AT91C_OTGHS_SOFHST + +/// disables SOF generation +#define Host_disable_sof() AT91C_BASE_OTGHS->OTGHS_HSTCTRL &= ~(unsigned int)AT91C_OTGHS_SOFHST + +/// sends a USB Reset to the device +#define Host_send_reset() AT91C_BASE_OTGHS->OTGHS_HSTCTRL |= AT91C_OTGHS_RESET +// *AT91C_OTGHS_TSTA2 |= AT91C_OTGHS_FORCHSRST; +// *AT91C_OTGHS_TSTA2 |= AT91C_OTGHS_UTMIRESET; +// *AT91C_OTGHS_TSTA2 &= ~AT91C_OTGHS_UTMIRESET + +/// tests if USB Reset running +#define Is_host_sending_reset() (AT91C_BASE_OTGHS->OTGHS_HSTCTRL&AT91C_OTGHS_RESET) +//#define Host_is_reset() ((UHCON & (1<OTGHS_HSTCTRL&AT91C_OTGHS_RESET) +#define Is_host_reset() (AT91C_BASE_OTGHS->OTGHS_HSTCTRL&AT91C_OTGHS_RESET) + +/// sends a USB Resume to the device +#define Host_send_resume() AT91C_BASE_OTGHS->OTGHS_HSTCTRL |= AT91C_OTGHS_RESUME +/// tests if USB Resume running +//#define Host_is_resume() ((UHCON & (1<OTGHS_HSTCTRL&AT91C_OTGHS_RESUME) + +/// enables host start of frame interrupt +//#define Host_enable_sof_interrupt() (UHIEN |= (1<OTGHS_HSTIER = AT91C_OTGHS_HSOFI +/// enables host start of frame interrupt +#define Host_disable_sof_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_HSOFI +#define Is_host_sof_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_HSTIMR&AT91C_OTGHS_HSOFI) +/// tests if SOF detected +//#define Host_is_sof() ((UHINT & (1<OTGHS_HSTISR&AT91C_OTGHS_HSOFI) +#define Host_ack_sof() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_HSOFI + +/// enables host wake up interrupt detection +#define Host_enable_hwup_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_HWUPI +/// disables host wake up interrupt detection +#define Host_disable_hwup_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_HWUPI +#define Is_host_hwup_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_HSTIMR&AT91C_OTGHS_HWUPI) +/// tests if host wake up detected +//#define Host_is_hwup() ((UHINT & (1<OTGHS_HSTISR&AT91C_OTGHS_HWUPI) +#define Host_ack_hwup() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_HWUPI + + +/// enables host down stream rsm sent interrupt detection +#define Host_enable_down_stream_resume_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_RSMEDI +/// disables host down stream rsm sent interrupt detection +#define Host_disable_down_stream_resume_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_RSMEDI +//#define Is_host_down_stream_resume_interrupt_enabled() ((UHIEN & (1<OTGHS_HSTISR&AT91C_OTGHS_RSMEDI) +//#define Host_ack_down_stream_resume() (UHINT &= ~(1<OTGHS_HSTICR = AT91C_OTGHS_RSMEDI + +/// enables host remote wake up interrupt detection +//#define Host_enable_remote_wakeup_interrupt() (UHIEN |= (1<OTGHS_HSTIER = AT91C_OTGHS_RXRSMI +/// disables host remote wake up interrupt detection +//#define Host_disable_remote_wakeup_interrupt() (UHIEN &= ~(1<OTGHS_HSTIDR = AT91C_OTGHS_RXRSMI +//#define Is_host_remote_wakeup_interrupt_enabled() ((UHIEN & (1<OTGHS_HSTISR&AT91C_OTGHS_RXRSMI) +/// tests if host wake up detected +//#define Host_is_remote_wakeup() ((UHINT & (1<OTGHS_HSTISR&AT91C_OTGHS_RXRSMI) == AT91C_OTGHS_RXRSMI) +#define Host_ack_remote_wakeup() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_RXRSMI + +#define Host_disable_device_connection_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_DCONN +/// enables host device connection interrupt +//#define Host_enable_device_connection_interrupt() (UHIEN |= (1<OTGHS_HSTIER = AT91C_OTGHS_DCONN +/// disables USB device connection interrupt +//#define Host_disable_device_connection_interrupt() (UHIEN &= ~(1<OTGHS_HSTIMR & AT91C_OTGHS_DCONN) +/// tests if a USB device has been detected +//#define Is_device_connection() (UHINT & (1<OTGHS_HSTISR & AT91C_OTGHS_DCONN) +#define Is_host_device_connection() (AT91C_BASE_OTGHS->OTGHS_HSTISR & AT91C_OTGHS_DCONN) +/// acks device connection +//#define Host_ack_device_connection() (UHINT = ~(1<OTGHS_HSTICR = AT91C_OTGHS_DCONN + +/// tests if a USB device has been removed +//#define Is_device_disconnection() (UHINT & (1<OTGHS_HSTISR & AT91C_OTGHS_DDIS) +/// enables host device disconnection interrupt +//#define Host_enable_device_disconnection_interrupt() (UHIEN |= (1<OTGHS_HSTIER = AT91C_OTGHS_DDIS +/// disables USB device connection interrupt +//#define Host_disable_device_disconnection_interrupt() (UHIEN &= ~(1<OTGHS_HSTIDR = AT91C_OTGHS_DDIS +//#define Is_host_device_disconnection_interrupt_enabled() ((UHIEN & (1<OTGHS_HSTIMR & AT91C_OTGHS_DDIS) +/// tests if a USB device has been removed +//#define Is_device_disconnection() (UHINT & (1<OTGHS_HSTISR & AT91C_OTGHS_DDIS) +/// acks device disconnection +//#define Host_ack_device_disconnection() (UHINT = ~(1<OTGHS_HSTICR = AT91C_OTGHS_DDIS + +#define host_get_device_descriptor_incomplete() (usb_request.uncomplete_read == TRUE) +#define Host_enable_reset_sent_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_RSTI + + +#define Host_disable_reset_sent_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_RSTI +/// enables host USB reset interrupt +//#define Host_enable_reset_interrupt() (UHIEN |= (1<OTGHS_HSTIDR = AT91C_OTGHS_RSTI) +//#define Is_host_reset_interrupt_enabled() ((UHIEN & (1<OTGHS_HSTICR = AT91C_OTGHS_RSTI +/// tests if USB reset has been sent + + +/// switches on VBus +//#define Host_vbus_request() (OTGCON |= (1<OTGHS_SCR = AT91C_OTGHS_VBUSRQ //JCB +/// configures the address to use for the device +//#define Host_configure_address(addr) (UHADDR = addr & MSK_HADDR) +//#define Host_configure_address(addr) AT91C_BASE_OTGHS->OTGHS_HSTCTRL |= addr & 0x3F +//#define Host_configure_address(addr) AT91C_BASE_OTGHS->OTGHS_HSTADDR1 &= ~AT91C_OTGHS_UHADDR_P0; +// AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= (addr & AT91C_OTGHS_UHADDR_P0) + +/// Get connected device speed, returns TRUE when in full speed mode +#define Is_host_full_speed() (AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_SPEED) +/// @} + +#define Usb_disable_otg_pad() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_OTGPADE + + + +/// @defgroup general_pipe USB pipe drivers +/// These macros manage the common features of the pipes. +/// @{ +/// selects pipe for CPU interface +//#define Host_select_pipe(p) (UPNUM = (unsigned char)p) +#define Host_select_pipe(p) global_pipe_nb = p + +/// get the currently selected pipe number +//#define Host_get_selected_pipe() (UPNUM ) +#define Host_get_selected_pipe() (global_pipe_nb) + +/// enables pipe +//#define Host_enable_pipe() (UPCONX |= (1<OTGHS_HSTPIP |= (1<OTGHS_HSTPIP &= ~(unsigned int)(1<OTGHS_HSTPIPCFG[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_PTOKEN;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] |= AT91C_OTGHS_PTOKEN_SETUP +/// sets IN token +//#define Host_set_token_in() (UPCFG0X = (UPCFG0X & ~MSK_TOKEN_SETUP) | MSK_TOKEN_IN) +#define Host_set_token_in() AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_PTOKEN;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] |= AT91C_OTGHS_PTOKEN_IN +/// sets OUT token +//#define Host_set_token_out() (UPCFG0X = (UPCFG0X & ~MSK_TOKEN_SETUP) | MSK_TOKEN_OUT) +#define Host_set_token_out() AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_PTOKEN;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] |= AT91C_OTGHS_PTOKEN_OUT + +/// returns the number of the endpoint associated to the current pipe +//#define Host_get_endpoint_number() (UPCFG0X & (1<OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PEPNUM)>>16) + +/// returns pipe interrupt register +#define Host_get_pipe_interrupt() ((AT91C_BASE_OTGHS->OTGHS_HSTISR>>8)&0x7F) + +/// sets the interrupt frequency +//#define Host_set_interrupt_frequency(pip, frq) (AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[pip]|=AT91C_OTGHS_INTFRQ&(frq<<24)) + +/// tests if current pipe is configured +#define Is_pipe_configured() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb]&AT91C_OTGHS_CFGOK) +/// tests if at least one bank is busy +//#define Is_host_one_bank_busy() ((UPSTAX & (1<OTGHS_HSTPIPISR[pip]&AT91C_OTGHS_NBUSYBK)!=0) +/// returns the number of busy banks +//#define Host_number_of_busy_bank() (UPSTAX & (1<OTGHS_HSTPIP|=(1<<16<OTGHS_HSTPIP&=~(unsigned int)(1<<16<OTGHS_READEPT0[global_pipe_nb << 14]=data +//#define Host_write_byte(data) (((char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0))[dBytes++])=data +#define Host_write_byte(data) pFifo[dBytes++]=data + +#define Host_write_32(data) AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[0]=data +/// reads a byte from the pipe FIFO +//#define Host_read_byte() (UPDATX) +//#define Host_read_byte() (U8)(((char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0))[dBytes++]) +#define Host_read_byte() pFifo[dBytes++] +//#define Host_read_byte_index(pip, index) pfifo[index] = pEndpoint->pData[index++]; +//#define Host_read_32(pip) AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[pip << 14] + +/// freezes the pipe +//#define Host_freeze_pipe() (UPCONX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_FREEZE +#define Host_freeze_pipe() AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_FREEZE +/// un-freezees the pipe +//#define Host_unfreeze_pipe() (UPCONX &= ~(1<OTGHS_HSTPIPIMR[global_pipe_nb] & AT91C_OTGHS_FREEZE)); +// AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FREEZE +#define Host_unfreeze_pipe() while(!(AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[global_pipe_nb] & AT91C_OTGHS_FREEZE));\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FREEZE +/// tests if the current pipe is frozen +//#define Is_host_pipe_freeze() (UPCONX & (1<OTGHS_HSTPIPIMR[global_pipe_nb] & AT91C_OTGHS_FREEZE) + +/// resets data toggle +#define Host_reset_pipe_data_toggle(pip) AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[pip] = AT91C_OTGHS_RSTDT + +/// tests if SETUP has been sent +#define Is_host_setup_sent() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXSTPI) +/// tests if control IN has been received +#define Is_host_control_in_received() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0] & AT91C_OTGHS_RXINI) +/// tests if control OUT has been sent +//#define Is_host_control_out_sent() ((UPINTX & (1<OTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXOUT) +/// tests if a STALL has been received +//#define Is_host_stall() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RXSTALL) +/// tests if an error occurs on current pipe +//#define Is_host_pipe_error() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_PERR) + +/// sends a setup +//#define Host_send_setup() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON +/// sends a control IN +//#define Host_send_control_in() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON +#define Host_send_control() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON +/// sends a control OUT +//#define Host_send_control_out() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON + +/// acks control OUT +//#define Host_ack_control_out() (UPINTX &= ~(1<OTGHS_HSTPIPICR[0] = AT91C_OTGHS_TXOUT +/// acks control IN +//#define Host_ack_control_in() (UPINTX &= ~(1<OTGHS_HSTPIPICR[0] = AT91C_OTGHS_RXINI +/// acks setup +//#define Host_ack_setup() (UPINTX &= ~(1<OTGHS_HSTPIPICR[0] = AT91C_OTGHS_TXSTPI +/// acks STALL reception +//#define Host_ack_stall() (UPINTX &= ~(1<OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_RXSTALL + +/// sends a OUT +//#define Host_send_out() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FIFOCON +/// tests if OUT has been sent +//#define Is_host_out_sent() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_TXOUT) +/// acks OUT sent +//#define Host_ack_out_sent() (UPINTX &= ~(1<OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_TXOUT + +/// tests if IN received +//#define Is_host_in_received() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RXINI) +/// acks IN reception +//#define Host_ack_in_received() (UPINTX &= ~(1<OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_RXINI +/// sends a IN +//#define Host_send_in() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FIFOCON +/// tests if nak handshake has been received +//#define Is_host_nak_received() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_NAKEDI) +/// acks NAk received sent +//#define Host_ack_nak_received() (UPINTX &= ~(1<OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_NAKEDI + +/// tests if endpoint read allowed +//#define Is_host_read_enabled() (UPINTX&(1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RWALL) +/// tests if endpoint read allowed +//#define Is_host_write_enabled() (UPINTX&(1<OTGHS_HSTPIPINRQ[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_INMOD +/// sets IN in continuous mode +//#define Host_continuous_in_mode() (UPCONX |= (1<OTGHS_HSTPIPINRQ[global_pipe_nb] |= AT91C_OTGHS_INMOD + +/// sets number of IN requests to perform before freeze +//#define Host_in_request_number(in_num) (UPINRQX = (unsigned char)in_num) +#define Host_in_request_number(pip, in_num) AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[pip] &= ~(unsigned int)AT91C_OTGHS_INMOD;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[pip] &= ~(unsigned int)AT91C_OTGHS_INRQ;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[pip] |= in_num +/// returns number of remaining IN requests +//#define Host_get_in_request_number() (UPINRQX) + +/// returns number of bytes (8 bits) +//#define Host_data_length_U8() (UPBCLX) +#define Host_data_length_U8() (unsigned short)((AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb]&AT91C_OTGHS_PBYCT)>>20) +#define UPBCLX (unsigned short)((AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb]&AT91C_OTGHS_PBYCT)>>20) + +/// returns number of bytes (16 bits) +//#define Host_data_length_U16() ((((unsigned short)UPBCHX)<<8) | UPBCLX) +#define Host_data_length_U16() (unsigned short)((AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb]&AT91C_OTGHS_PBYCT)>>20) +/// for device compatibility +//#define Host_byte_counter() Host_data_length_U16() +#define Host_byte_counter() Host_data_length_U16() +/// for device compatibility +//#define Host_byte_counter_8() Host_data_length_U8() + +/// returns the size of the current pipe +//#define Host_get_pipe_length() ((unsigned short)0x08 << ((UPCFG1X & MSK_PSIZE)>>4)) +//#define Host_get_pipe_length() (unsigned short)(((AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PSIZE)>>4)? +// (8<<((AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PSIZE)>>4)):8) + +/// returns the type of the current pipe +//#define Host_get_pipe_type() (UPCFG0X>>6) +#define Host_get_pipe_type() ((AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PTYPE)>>12) + +/// tests if error occurs on pipe +//#define Host_error_status() (UPERRX & MSK_ERROR) +#define Host_error_status() (unsigned long)(AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[global_pipe_nb]) +/// acks all pipe error +//#define Host_ack_all_errors() (UPERRX = 0x00) +#define Host_ack_all_errors() AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[global_pipe_nb] = 0 + +/// Enable pipe end transmission interrupt +//#define Host_enable_transmit_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_TXOUT +/// Disable pipe end transmission interrupt +//#define Host_disable_transmit_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_TXOUT + +/// Enable pipe reception interrupt +//#define Host_enable_receive_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_RXINI +/// Disable pipe recption interrupt +//#define Host_disable_receive_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_RXINI + +/// Enable pipe stall interrupt +//#define Host_enable_stall_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_RXSTALL +/// Disable pipe stall interrupt +//#define Host_disable_stall_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_RXSTALL + +/// Enable pipe error interrupt +//#define Host_enable_error_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_PERR +/// Disable pipe error interrupt +//#define Host_disable_error_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_PERR + +/// Enable pipe NAK interrupt +//#define Host_enable_nak_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_NAKEDI +/// Disable pipe NAK interrupt +//#define Host_disable_nak_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_NAKEDI + +//#define Get_pipe_token(x) ((x & (0x80)) ? TOKEN_IN : TOKEN_OUT) +#define Get_pipe_token(x) ((x & (0x80)) ? TOKEN_IN : TOKEN_OUT) + + +//_____ D E C L A R A T I O N ______________________________________________ + +extern unsigned char dev_configure_endpoint(unsigned char ept, + unsigned char type, + unsigned char dir, + unsigned char size, + unsigned char bank, + unsigned char nyet); + + +extern unsigned char usb_select_enpoint_interrupt (void); +extern unsigned char usb_send_packet(unsigned char, unsigned char*, unsigned char); +extern unsigned char usb_read_packet(unsigned char, unsigned char*, unsigned char); + +extern unsigned char host_config_pipe(unsigned char, unsigned char); +extern unsigned char host_determine_pipe_size(unsigned short); +extern void host_disable_all_pipe(void); +extern unsigned char host_get_nb_pipe_interrupt(void); +extern U16 host_get_pipe_length(void); +extern void host_configure_address( unsigned char pipe, unsigned char addr); + +#endif // _USB_DRV_H + diff --git a/usb/otg/usb_host_enum.c b/usb/otg/usb_host_enum.c new file mode 100644 index 0000000..69c9ba5 --- /dev/null +++ b/usb/otg/usb_host_enum.c @@ -0,0 +1,670 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/// This file manages the host enumeration process + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include +#include "usb/otg/usb_drv.h" +#include "usb_host_enum.h" +#include "usb/otg/usb_task.h" +#include "usb_host_task.h" +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#if (MAX_INTERFACE_SUPPORTED<1) +#error MAX_INTERFACE_SUPPORTED<1 : The host controller should support at least one interface... +#endif + +#ifndef VID_PID_TABLE + #error VID_PID_TABLE should be defined somewhere (conf_usb.h) + // VID_PID_TABLE format definition: + // #define VID_PID_TABLE {VID1, number_of_pid_for_this_VID1, PID11_value,..., PID1X_Value + // ... + // ,VIDz, number_of_pid_for_this_VIDz, PIDz1_value,..., PIDzX_Value} +#endif + +#ifndef CLASS_SUBCLASS_PROTOCOL + #error CLASS_SUBCLASS_PROTOCOL shoud be defined somewhere (conf_usb.h) + // CLASS_SUBCLASS_PROTOCOL format definition: + // #define CLASS_SUBCLASS_PROTOCOL {CLASS1, SUB_CLASS1,PROTOCOL1, + // ... + // CLASSz, SUB_CLASSz,PROTOCOLz} +#endif + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +//! Const table of known devices (see conf_usb.h for table content) +U16 registered_VID_PID[] = VID_PID_TABLE; + +//! Const table of known class (see conf_usb.h for table content) +U8 registered_class[] = CLASS_SUBCLASS_PROTOCOL; + +//! Physical EP to address device endpoints look-up table +// This table is dynamically built with the "host_configure_endpoint_class" function +U8 ep_table[MAX_EP_NB]={0,0,0,0,0,0,0}; + +//! The number of interface the host is able to support in the device connected +U8 nb_interface_supported=0; + +S_interface interface_supported[MAX_INTERFACE_SUPPORTED]; + +//! PID of device connected +U16 device_PID; +//! VID of device connected +U16 device_VID; +//! bmAttributes byte of the connected device +U8 bmattributes; +//! maxpower byte of the connected device (Caution, unit is 2mA) +U8 maxpower; + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// checks if the VID and the PID are supported +/// (if the VID/PID belongs to the VID_PID table) +//------------------------------------------------------------------------------ +U8 host_check_VID_PID(void) +{ + U8 nb_of_vid; + U8 nb_of_pid; + + TRACE_DEBUG("host_check_VID_PID\n\r"); + // Rebuild VID PID from data stage + LSB(device_VID) = data_stage[OFFSET_FIELD_LSB_VID]; + MSB(device_VID) = data_stage[OFFSET_FIELD_MSB_VID]; + LSB(device_PID) = data_stage[OFFSET_FIELD_LSB_PID]; + MSB(device_PID) = data_stage[OFFSET_FIELD_MSB_PID]; + + // Compare detected VID PID with supported table + nb_of_vid=0; + while (nb_of_vid< sizeof(registered_VID_PID)/2) // /2 because registered_VID_PID table is U16... + { + TRACE_DEBUG("registered_VID_PID[%d]: 0x%X\n\r", nb_of_vid, registered_VID_PID[nb_of_vid]); + TRACE_DEBUG("device_VID: 0x%X\n\r", device_VID); + if (registered_VID_PID[nb_of_vid] == device_VID) // VID is correct + { + TRACE_DEBUG("Good VID\n\r"); + nb_of_pid = (U8)registered_VID_PID[nb_of_vid+1]; // store nb of PID for this VID + while (nb_of_pid != 0) + { + TRACE_DEBUG("registered_VID_PID[%d]: 0x%X\n\r", nb_of_vid+nb_of_pid+1, registered_VID_PID[nb_of_vid+nb_of_pid+1]); + TRACE_DEBUG("device_PID: 0x%X\n\r", device_PID); + if (registered_VID_PID[nb_of_vid+nb_of_pid+1] == device_PID) + { + TRACE_DEBUG("Good PID\n\r"); + return HOST_TRUE; + } + nb_of_pid--; + } + } + nb_of_vid+=registered_VID_PID[nb_of_vid+1]+2; + } + return HOST_FALSE; +} + + +//------------------------------------------------------------------------------ +/// checks if the device class is supported. +/// The function looks in all interface declared in the received dewcriptors, if +/// one of them match with the CLASS/SUB_CLASS/PROTOCOL table +//------------------------------------------------------------------------------ +U8 host_check_class(void) +{ + U8 class_table; + T_DESC_OFFSET descriptor_offset; + T_DESC_OFFSET conf_offset_end; + U16 config_size; + U8 device_class; + U8 device_subclass; + U8 device_protocol; + + TRACE_DEBUG("host_check_class\n\r"); + nb_interface_supported=0; //First asumes ,no interface is supported! + if (data_stage[OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_CONFIGURATION) // check if configuration descriptor + { + TRACE_DEBUG("host_check_class problem\n\r"); + return HOST_FALSE; + } + LSB(config_size) = data_stage[OFFSET_FIELD_TOTAL_LENGHT]; + MSB(config_size) = data_stage[OFFSET_FIELD_TOTAL_LENGHT+1]; + bmattributes = data_stage[OFFSET_FIELD_BMATTRIBUTES]; + maxpower = data_stage[OFFSET_FIELD_MAXPOWER]; + descriptor_offset = 0; + conf_offset_end = descriptor_offset + config_size; + + // Look in all interfaces declared in the configuration + while(descriptor_offset < conf_offset_end) + { + // Find next interface descriptor + while (data_stage[descriptor_offset+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_INTERFACE) + { + descriptor_offset += data_stage[descriptor_offset]; + if(descriptor_offset >= conf_offset_end) + { + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem2\n\r"); + return HOST_FALSE; + } + } + } + // Found an interface descriptor + // Get charateristics of this interface + device_class = data_stage[descriptor_offset + OFFSET_FIELD_CLASS]; + device_subclass = data_stage[descriptor_offset + OFFSET_FIELD_SUB_CLASS]; + device_protocol = data_stage[descriptor_offset + OFFSET_FIELD_PROTOCOL]; + // Look in registered class table for match + class_table=0; + while (class_table< sizeof(registered_class)) + { + if (registered_class[class_table] == device_class) // class is correct! + { + if (registered_class[class_table+1] == device_subclass) // sub class is correct! + { + if (registered_class[class_table+2] == device_protocol) // protocol is correct! + { + // Prepare for another item CLASS/SUB_CLASS/PROTOCOL in table + class_table+=3; + // Store this interface as supported interface + // Memorize its interface nb + interface_supported[nb_interface_supported].interface_nb=data_stage[descriptor_offset+OFFSET_FIELD_INTERFACE_NB]; + // its alternate setting + interface_supported[nb_interface_supported].altset_nb=data_stage[descriptor_offset+OFFSET_FIELD_ALT]; + // its USB class + interface_supported[nb_interface_supported].class=device_class; + // its USB subclass + interface_supported[nb_interface_supported].subclass=device_subclass; + // its USB protocol + interface_supported[nb_interface_supported].protocol=device_protocol; + // the number of endpoints associated to this interface + // Note: The associated endpoints addresses are stored during pipe attribution... + interface_supported[nb_interface_supported].nb_ep=data_stage[descriptor_offset+OFFSET_FIELS_NB_OF_EP]; + // Update the number of interface supported + nb_interface_supported++; + // Check the maximum number of interfaces we can support + if(nb_interface_supported>=MAX_INTERFACE_SUPPORTED) + { + TRACE_DEBUG("host_check_class ok1\n\r"); + return HOST_TRUE; + } + } + } + } + class_table+=3; // Check other item CLASS/SUB_CLASS/PROTOCOL in table + } + descriptor_offset += data_stage[descriptor_offset]; // Next descriptor + if(descriptor_offset > SIZEOF_DATA_STAGE) // Check overflow + { + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok3\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem3\n\r"); + return HOST_FALSE; + } + } + } + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok4\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem4\n\r"); + return HOST_FALSE; + } +} + +//------------------------------------------------------------------------------ +/// configures the pipe according to the device class of the +//------------------------------------------------------------------------------ +U8 host_auto_configure_endpoint(void) +{ + U8 nb_endpoint_to_configure; + T_DESC_OFFSET descriptor_offset; + U8 physical_pipe=1; // =1 cause lookup table assumes that physiacl pipe 0 is reserved for control + U8 i; + U8 ep_index; + + TRACE_DEBUG("host_auto_configure_endpoint\n\r"); + // For all interfaces to configure... + for(i=0;i SIZEOF_DATA_STAGE) // No more endpoint descriptor found -> Errror ! + { + TRACE_DEBUG("PB\n\r"); + return HOST_FALSE; + } + } + + // Select the new physical pipe to configure and get ride of any previous configuration for this physical pipe + Host_select_pipe(physical_pipe); + Host_disable_pipe(); + Host_enable_pipe(); + + // Build the pipe configuration according to the endpoint descriptors fields received + // + // host_configure_pipe( + // physical_pipe, // pipe nb in USB interface + // data_stage[descriptor_offset+OFFSET_FIELD_EP_TYPE], // pipe type (interrupt/BULK/ISO) + // Get_pipe_token(data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]), // pipe addr + // (data_stage[descriptor_offset+2] & MSK_EP_DIR), // pipe dir (IN/OUT) + // host_determine_pipe_size((U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE]),// pipe size + // ONE_BANK, // bumber of bank to allocate for pipe + // data_stage[descriptor_offset+OFFSET_FIELD_EP_INTERVAL] // interrupt period (for interrupt pipe) + // ); + + host_configure_pipe( + physical_pipe, + data_stage[descriptor_offset+OFFSET_FIELD_EP_TYPE], + Get_pipe_token(data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]), + (data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR] & MSK_EP_DIR), + host_determine_pipe_size( + (U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE_LOW] + + (((U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE_HIGH])<<8)), + ONE_BANK, + data_stage[descriptor_offset+OFFSET_FIELD_EP_INTERVAL] ); + + host_configure_address(physical_pipe, DEVICE_ADDRESS); + + // Update Physical Pipe lookup table with device enpoint address + ep_table[physical_pipe]=data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]; + physical_pipe++; + // Update endpoint addr table in supported interface structure + interface_supported[i].ep_addr[ep_index++]=data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]; + descriptor_offset += data_stage[descriptor_offset]; // pointing on next descriptor + + // All target endpoints configured ? + nb_endpoint_to_configure--; + } //for(i=0;i SIZEOF_DATA_STAGE) + { + return HOST_FALSE; + } + } + if (data_stage[descriptor_offset+OFFSET_FIELD_INTERFACE_NB]==interface + && data_stage[descriptor_offset+OFFSET_FIELD_ALT]==alt) + { + return descriptor_offset; + } + descriptor_offset += data_stage[descriptor_offset]; + } + return descriptor_offset; +} + +//------------------------------------------------------------------------------ +/// returns the physical pipe number linked to a logical endpoint address. +//------------------------------------------------------------------------------ +U8 host_get_hwd_pipe_nb(U8 ep_addr) +{ + U8 i; + + for(i=0; iOTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXSTPI) != 0); + // Freeze the pipe + Host_freeze_pipe(); + + status=(CONTROL_GOOD); + goto host_send_control_end; + } + + // OUT request management --------------------------------------------- + else // Data stage OUT (bmRequestType==0) + { + Host_set_token_out(); + Host_ack_control_out(); + while(data_length != 0) + { + Host_unfreeze_pipe(); + status = host_get_pipe_length(); + if ( (U16)status > data_length) + { + status = (U8)data_length; + data_length = 0; + } + else + { + data_length -= status; + } + Address_fifochar_endpoint(global_pipe_nb); + while (status!=0) + { + Host_write_byte(*data_pointer); + data_pointer++; + status--; + } + Host_send_control_out(); + while (!Is_host_control_out_sent()) + { + if (Is_host_emergency_exit()) + { + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if(Is_host_pipe_error()) + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_control_end; + } + if(Is_host_stall()) + { + status=CONTROL_STALL; + Host_ack_stall(); + goto host_send_control_end; + } + } + Host_ack_control_out(); + } // end of OUT data stage + Host_freeze_pipe(); + Host_set_token_in(); + Host_unfreeze_pipe(); + while(!Is_host_control_in_received()) + { + if (Is_host_emergency_exit()) + { + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if(Is_host_pipe_error()) + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_control_end; + } + if(Is_host_stall()) + { + status=CONTROL_STALL; + Host_ack_stall(); + goto host_send_control_end; + } + } + Host_ack_control_in(); + Host_freeze_pipe(); + Host_send_control_in(); + status=(CONTROL_GOOD); + goto host_send_control_end; + } + +host_send_control_end: + return ((U8)status); +} + + diff --git a/usb/otg/usb_host_enum.h b/usb/otg/usb_host_enum.h new file mode 100644 index 0000000..959cb52 --- /dev/null +++ b/usb/otg/usb_host_enum.h @@ -0,0 +1,329 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _USB_HOST_ENUM_H_ +#define _USB_HOST_ENUM_H_ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#ifndef SIZEOF_DATA_STAGE + #error SIZEOF_DATA_STAGE should be defined in conf_usb.h +#endif + +#if (SIZEOF_DATA_STAGE<0xFF) //! Optimize descriptor offset index according to data_stage[] size + #define T_DESC_OFFSET U8 //! U8 is enought and faster +#else + #define T_DESC_OFFSET U16 //! U16 required ! +#endif + +#ifndef MAX_EP_PER_INTERFACE + #define MAX_EP_PER_INTERFACE 4 +#endif + + + + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ +typedef struct +{ + U8 bmRequestType; //!< Characteristics of the request + U8 bRequest; //!< Specific request + U16 wValue; //!< field that varies according to request + U16 wIndex; //!< field that varies according to request + U16 wLength; //!< Number of bytes to transfer if Data + U8 uncomplete_read; //!< 1 = only one read +} S_usb_setup_data; + + +typedef struct +{ + U8 interface_nb; + U8 altset_nb; + U16 class; + U16 subclass; + U16 protocol; + U8 nb_ep; + U8 ep_addr[MAX_EP_PER_INTERFACE]; +} S_interface; + +#define CONTROL_GOOD 0 +#define CONTROL_TIMEOUT 0x08 +#define CONTROL_STALL 0x20 + + +//!< Set of defines for offset in data stage +#define OFFSET_FIELD_MAXPACKETSIZE 7 +#define OFFSET_FIELD_MSB_VID 9 +#define OFFSET_FIELD_LSB_VID 8 +#define OFFSET_FIELD_MSB_PID 11 +#define OFFSET_FIELD_LSB_PID 10 + +#define OFFSET_DESCRIPTOR_LENGHT 0 +#define OFFSET_FIELD_DESCRIPTOR_TYPE 1 +#define OFFSET_FIELD_TOTAL_LENGHT 2 +#define OFFSET_FIELD_BMATTRIBUTES 7 +#define OFFSET_FIELD_MAXPOWER 8 + +#define OFFSET_FIELD_OTG_FEATURES 2 +#define OTG_DESCRIPTOR_bLength 0x03 + +//! OFFSET for INTERFACE DESCRIPTORS +#define OFFSET_FIELD_INTERFACE_NB 2 +#define OFFSET_FIELD_ALT 3 +#define OFFSET_FIELS_NB_OF_EP 4 +#define OFFSET_FIELD_NB_INTERFACE 4 // Nb of endpoint used by this interface +#define OFFSET_FIELD_CLASS 5 +#define OFFSET_FIELD_SUB_CLASS 6 +#define OFFSET_FIELD_PROTOCOL 7 + + +#define OFFSET_FIELD_EP_ADDR 2 +#define OFFSET_FIELD_EP_TYPE 3 +#define OFFSET_FIELD_EP_SIZE_LOW 4 +#define OFFSET_FIELD_EP_SIZE_HIGH 5 +#define OFFSET_FIELD_EP_INTERVAL 6 + +//! defines for Hub detection +#define OFFSET_DEV_DESC_CLASS 4 // offset for the CLASS field in the Device Descriptor +#define HUB_CLASS_CODE 9 // value of Hub CLASS + + +#define HOST_FALSE 0 +#define HOST_TRUE 1 + + +//----------------------------------------------------------------------------- +// Exported macro +//----------------------------------------------------------------------------- + +/// send a clear endpoint request +#define host_clear_endpoint_feature(ep) (usb_request.bmRequestType = 0x02,\ + usb_request.bRequest = USBGenericRequest_CLEARFEATURE,\ + usb_request.wValue = USBFeatureRequest_ENDPOINTHALT << 8,\ + usb_request.wIndex = ep,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a get configuration request +#define host_get_configuration() (usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETCONFIGURATION,\ + usb_request.wValue = 0,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 1,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a set configuration request +#define host_set_configuration(cfg_nb) (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETCONFIGURATION,\ + usb_request.wValue = cfg_nb,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a set interface request to specify a specific alt setting for an +/// interface +#define host_set_interface(interface_nb,alt_setting) \ + (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETINTERFACE,\ + usb_request.wValue = alt_setting,\ + usb_request.wIndex = interface_nb,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send a get device desriptor request. +/// The descriptor table received is stored in data_stage array. +/// The received descriptors is limited to the control pipe lenght +#define host_get_device_descriptor_uncomplete() \ + (usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETDESCRIPTOR,\ + usb_request.wValue = USBGenericDescriptor_DEVICE << 8,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 64,\ + usb_request.uncomplete_read = TRUE,\ + host_send_control(data_stage)) + +/// send a get device desriptor request. +/// The descriptor table received is stored in data_stage array. +#define host_get_device_descriptor() (usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETDESCRIPTOR,\ + usb_request.wValue = USBGenericDescriptor_DEVICE << 8,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 18,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a get device configuration request. +/// The configuration descriptor table received is stored in data_stage array. +#define host_get_configuration_descriptor()(usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETDESCRIPTOR,\ + usb_request.wValue = USBGenericDescriptor_CONFIGURATION << 8,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 255,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +#define host_get_descriptor_uncomplete() (usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETDESCRIPTOR,\ + usb_request.wValue = 0,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 64,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a set address request. +#define host_set_address(addr) (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETADDRESS,\ + usb_request.wValue = (U16)addr,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send a set feature device remote wakeup +#define host_set_feature_remote_wakeup() (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETFEATURE,\ + usb_request.wValue = 1,\ + usb_request.wIndex = 1,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send a set feature "a_hnp_support" to tell to B-Device that A-Device support HNP +#define host_set_feature_a_hnp_support() (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETFEATURE,\ + usb_request.wValue = 4,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send a set feature "b_hnp_enable" to make B-Device initiating a HNP +#define host_set_feature_b_hnp_enable() (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETFEATURE,\ + usb_request.wValue = 3,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send the mass storage specific request "get max lun" +#define host_ms_get_max_lun() (usb_request.bmRequestType = 0xA1,\ + usb_request.bRequest = MS_GET_MAX_LUN,\ + usb_request.wValue = 0,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 1,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// returns the VID of the device connected +#define Get_VID() (device_VID) + +/// returns the PID of the device connected +#define Get_PID() (device_PID) + +/// returns the maximum power consumption ot hte connected device (unit is 2mA) +#define Get_maxpower() (maxpower) + +/// returns the USB class associated to the specified interface +#define Get_class(s_interface) (interface_supported[s_interface].class) + +/// returns the USB subclass associated to the specified interface +#define Get_subclass(s_interface) (interface_supported[s_interface].subclass) + +/// returns the USB protocol associated to the specified interface +#define Get_protocol(s_interface) (interface_supported[s_interface].protocol) + +/// returns endpoint address associated to the specified interface and +/// endpoint number in this interface. +#define Get_ep_addr(s_interface,n_ep) (interface_supported[s_interface].ep_addr[n_ep]) + +/// returns number of endpoints associated to +#define Get_nb_ep(s_interface) (interface_supported[s_interface].nb_ep) + +/// returns number of the alternate setting field associated to +#define Get_alts_s(s_interface) (interface_supported[s_interface].altset_nb) + +/// returns number of the interface number associated to +#define Get_interface_number(s_interface) (interface_supported[s_interface].interface_nb) + +/// returns the number of interface supported in the device connected +#define Get_nb_supported_interface() (nb_interface_supported) + +#define BIT_SELF_POWERED 6 // offset +/// returns true if the device connected is self powered +#define Is_device_self_powered() ((bmattributes & (1< +#include "usb/otg/usb_drv.h" +#include "usb_host_enum.h" +#include "usb/otg/usb_task.h" +#include "usb_host_task.h" +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#if (MAX_INTERFACE_SUPPORTED<1) +#error MAX_INTERFACE_SUPPORTED<1 : The host controller should support at least one interface... +#endif + +#ifndef VID_PID_TABLE + #error VID_PID_TABLE should be defined somewhere (conf_usb.h) + // VID_PID_TABLE format definition: + // #define VID_PID_TABLE {VID1, number_of_pid_for_this_VID1, PID11_value,..., PID1X_Value + // ... + // ,VIDz, number_of_pid_for_this_VIDz, PIDz1_value,..., PIDzX_Value} +#endif + +#ifndef CLASS_SUBCLASS_PROTOCOL + #error CLASS_SUBCLASS_PROTOCOL shoud be defined somewhere (conf_usb.h) + // CLASS_SUBCLASS_PROTOCOL format definition: + // #define CLASS_SUBCLASS_PROTOCOL {CLASS1, SUB_CLASS1,PROTOCOL1, + // ... + // CLASSz, SUB_CLASSz,PROTOCOLz} +#endif + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +//! Const table of known devices (see conf_usb.h for table content) +U16 registered_VID_PID[] = VID_PID_TABLE; + +//! Const table of known class (see conf_usb.h for table content) +U8 registered_class[] = CLASS_SUBCLASS_PROTOCOL; + +//! Physical EP to address device endpoints look-up table +// This table is dynamically built with the "host_configure_endpoint_class" function +U8 ep_table[MAX_EP_NB]={0,0,0,0,0,0,0}; + +//! The number of interface the host is able to support in the device connected +U8 nb_interface_supported=0; + +S_interface interface_supported[MAX_INTERFACE_SUPPORTED]; + +//! PID of device connected +U16 device_PID; +//! VID of device connected +U16 device_VID; +//! bmAttributes byte of the connected device +U8 bmattributes; +//! maxpower byte of the connected device (Caution, unit is 2mA) +U8 maxpower; + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// checks if the VID and the PID are supported +/// (if the VID/PID belongs to the VID_PID table) +//------------------------------------------------------------------------------ +U8 host_check_VID_PID(void) +{ + U8 nb_of_vid; + U8 nb_of_pid; + + TRACE_DEBUG("host_check_VID_PID\n\r"); + // Rebuild VID PID from data stage + LSB(device_VID) = data_stage[OFFSET_FIELD_LSB_VID]; + MSB(device_VID) = data_stage[OFFSET_FIELD_MSB_VID]; + LSB(device_PID) = data_stage[OFFSET_FIELD_LSB_PID]; + MSB(device_PID) = data_stage[OFFSET_FIELD_MSB_PID]; + + // Compare detected VID PID with supported table + nb_of_vid=0; + while (nb_of_vid< sizeof(registered_VID_PID)/2) // /2 because registered_VID_PID table is U16... + { + TRACE_DEBUG("registered_VID_PID[%d]: 0x%X\n\r", nb_of_vid, registered_VID_PID[nb_of_vid]); + TRACE_DEBUG("device_VID: 0x%X\n\r", device_VID); + if (registered_VID_PID[nb_of_vid] == device_VID) // VID is correct + { + TRACE_DEBUG("Good VID\n\r"); + nb_of_pid = (U8)registered_VID_PID[nb_of_vid+1]; // store nb of PID for this VID + while (nb_of_pid != 0) + { + TRACE_DEBUG("registered_VID_PID[%d]: 0x%X\n\r", nb_of_vid+nb_of_pid+1, registered_VID_PID[nb_of_vid+nb_of_pid+1]); + TRACE_DEBUG("device_PID: 0x%X\n\r", device_PID); + if (registered_VID_PID[nb_of_vid+nb_of_pid+1] == device_PID) + { + TRACE_DEBUG("Good PID\n\r"); + return HOST_TRUE; + } + nb_of_pid--; + } + } + nb_of_vid+=registered_VID_PID[nb_of_vid+1]+2; + } + return HOST_FALSE; +} + +//------------------------------------------------------------------------------ +/// checks if the OTG descriptor has been received and +/// indicates which features are supported +//------------------------------------------------------------------------------ +U8 host_check_OTG_features(void) +{ + U8 index; // variable offset used to search the OTG descriptor + U8 nb_bytes; // number of bytes of the config descriptor + + TRACE_DEBUG("host_check_OTG_features\n\r"); + Peripheral_is_not_otg_device(); // init + otg_features_supported = 0; + + nb_bytes = data_stage[OFFSET_FIELD_TOTAL_LENGHT]; + index = 0; + if (nb_bytes > 0x09) // check this is not a reduced/uncomplete config descriptor + { + while (index < nb_bytes) // search in the descriptors + { + if (data_stage[index+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_OTG) // IS the pointed descriptor THE OTG DESCRIPTOR ? + { + index += data_stage[index+OFFSET_DESCRIPTOR_LENGHT]; // NO, skip to next descriptor + } + else + { + if (data_stage[index+OFFSET_DESCRIPTOR_LENGHT] == OTG_DESCRIPTOR_bLength) // YES, check descriptor length + { + Peripheral_is_otg_device(); // an OTG descriptor has been found + otg_features_supported = data_stage[index+OFFSET_FIELD_OTG_FEATURES]; // load otg features supported + TRACE_DEBUG("OK\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("PB\n\r"); + return HOST_FALSE; // bad descriptor length + } + } + } + } + else + { + TRACE_DEBUG("PB1\n\r"); + return HOST_FALSE; // this was only a reduced/uncomplete configuration descriptor + } + TRACE_DEBUG("OK1\n\r"); + return HOST_TRUE; +} + + +//------------------------------------------------------------------------------ +/// checks if the device class is supported. +/// The function looks in all interface declared in the received dewcriptors, if +/// one of them match with the CLASS/SUB_CLASS/PROTOCOL table +//------------------------------------------------------------------------------ +U8 host_check_class(void) +{ + U8 class_table; + T_DESC_OFFSET descriptor_offset; + T_DESC_OFFSET conf_offset_end; + U16 config_size; + U8 device_class; + U8 device_subclass; + U8 device_protocol; + + TRACE_DEBUG("host_check_class\n\r"); + nb_interface_supported=0; //First asumes ,no interface is supported! + if (data_stage[OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_CONFIGURATION) // check if configuration descriptor + { + TRACE_DEBUG("host_check_class problem\n\r"); + return HOST_FALSE; + } + LSB(config_size) = data_stage[OFFSET_FIELD_TOTAL_LENGHT]; + MSB(config_size) = data_stage[OFFSET_FIELD_TOTAL_LENGHT+1]; + bmattributes = data_stage[OFFSET_FIELD_BMATTRIBUTES]; + maxpower = data_stage[OFFSET_FIELD_MAXPOWER]; + descriptor_offset = 0; + conf_offset_end = descriptor_offset + config_size; + + // Look in all interfaces declared in the configuration + while(descriptor_offset < conf_offset_end) + { + // Find next interface descriptor + while (data_stage[descriptor_offset+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_INTERFACE) + { + descriptor_offset += data_stage[descriptor_offset]; + if(descriptor_offset >= conf_offset_end) + { + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem2\n\r"); + return HOST_FALSE; + } + } + } + // Found an interface descriptor + // Get charateristics of this interface + device_class = data_stage[descriptor_offset + OFFSET_FIELD_CLASS]; + device_subclass = data_stage[descriptor_offset + OFFSET_FIELD_SUB_CLASS]; + device_protocol = data_stage[descriptor_offset + OFFSET_FIELD_PROTOCOL]; + // Look in registered class table for match + class_table=0; + while (class_table< sizeof(registered_class)) + { + if (registered_class[class_table] == device_class) // class is correct! + { + if (registered_class[class_table+1] == device_subclass) // sub class is correct! + { + if (registered_class[class_table+2] == device_protocol) // protocol is correct! + { + // Prepare for another item CLASS/SUB_CLASS/PROTOCOL in table + class_table+=3; + // Store this interface as supported interface + // Memorize its interface nb + interface_supported[nb_interface_supported].interface_nb=data_stage[descriptor_offset+OFFSET_FIELD_INTERFACE_NB]; + // its alternate setting + interface_supported[nb_interface_supported].altset_nb=data_stage[descriptor_offset+OFFSET_FIELD_ALT]; + // its USB class + interface_supported[nb_interface_supported].class=device_class; + // its USB subclass + interface_supported[nb_interface_supported].subclass=device_subclass; + // its USB protocol + interface_supported[nb_interface_supported].protocol=device_protocol; + // the number of endpoints associated to this interface + // Note: The associated endpoints addresses are stored during pipe attribution... + interface_supported[nb_interface_supported].nb_ep=data_stage[descriptor_offset+OFFSET_FIELS_NB_OF_EP]; + // Update the number of interface supported + nb_interface_supported++; + // Check the maximum number of interfaces we can support + if(nb_interface_supported>=MAX_INTERFACE_SUPPORTED) + { + TRACE_DEBUG("host_check_class ok1\n\r"); + return HOST_TRUE; + } + } + } + } + class_table+=3; // Check other item CLASS/SUB_CLASS/PROTOCOL in table + } + descriptor_offset += data_stage[descriptor_offset]; // Next descriptor + if(descriptor_offset > SIZEOF_DATA_STAGE) // Check overflow + { + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok3\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem3\n\r"); + return HOST_FALSE; + } + } + } + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok4\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem4\n\r"); + return HOST_FALSE; + } +} + +//------------------------------------------------------------------------------ +/// configures the pipe according to the device class of the +//------------------------------------------------------------------------------ +U8 host_auto_configure_endpoint(void) +{ + U8 nb_endpoint_to_configure; + T_DESC_OFFSET descriptor_offset; + U8 physical_pipe=1; // =1 cause lookup table assumes that physiacl pipe 0 is reserved for control + U8 i; + U8 ep_index; + + TRACE_DEBUG("host_auto_configure_endpoint\n\r"); + // For all interfaces to configure... + for(i=0;i SIZEOF_DATA_STAGE) // No more endpoint descriptor found -> Errror ! + { + TRACE_DEBUG("PB\n\r"); + return HOST_FALSE; + } + } + + // Select the new physical pipe to configure and get ride of any previous configuration for this physical pipe + Host_select_pipe(physical_pipe); + Host_disable_pipe(); + Host_enable_pipe(); + + // Build the pipe configuration according to the endpoint descriptors fields received + // + // host_configure_pipe( + // physical_pipe, // pipe nb in USB interface + // data_stage[descriptor_offset+OFFSET_FIELD_EP_TYPE], // pipe type (interrupt/BULK/ISO) + // Get_pipe_token(data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]), // pipe addr + // (data_stage[descriptor_offset+2] & MSK_EP_DIR), // pipe dir (IN/OUT) + // host_determine_pipe_size((U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE]),// pipe size + // ONE_BANK, // bumber of bank to allocate for pipe + // data_stage[descriptor_offset+OFFSET_FIELD_EP_INTERVAL] // interrupt period (for interrupt pipe) + // ); + + host_configure_pipe( + physical_pipe, + data_stage[descriptor_offset+OFFSET_FIELD_EP_TYPE], + Get_pipe_token(data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]), + (data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR] & MSK_EP_DIR), + host_determine_pipe_size( + (U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE_LOW] + + (((U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE_HIGH])<<8)), + ONE_BANK, + data_stage[descriptor_offset+OFFSET_FIELD_EP_INTERVAL] ); + + host_configure_address(physical_pipe, DEVICE_ADDRESS); + + // Update Physical Pipe lookup table with device enpoint address + ep_table[physical_pipe]=data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]; + physical_pipe++; + // Update endpoint addr table in supported interface structure + interface_supported[i].ep_addr[ep_index++]=data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]; + descriptor_offset += data_stage[descriptor_offset]; // pointing on next descriptor + + // All target endpoints configured ? + nb_endpoint_to_configure--; + } //for(i=0;i SIZEOF_DATA_STAGE) + { + return HOST_FALSE; + } + } + if (data_stage[descriptor_offset+OFFSET_FIELD_INTERFACE_NB]==interface + && data_stage[descriptor_offset+OFFSET_FIELD_ALT]==alt) + { + return descriptor_offset; + } + descriptor_offset += data_stage[descriptor_offset]; + } + return descriptor_offset; +} + +//------------------------------------------------------------------------------ +/// returns the physical pipe number linked to a logical endpoint address. +//------------------------------------------------------------------------------ +U8 host_get_hwd_pipe_nb(U8 ep_addr) +{ + U8 i; + + for(i=0; iOTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXSTPI) != 0); + // Freeze the pipe + Host_freeze_pipe(); + + status=(CONTROL_GOOD); + goto host_send_control_end; + } + + // OUT request management --------------------------------------------- + else // Data stage OUT (bmRequestType==0) + { + Host_set_token_out(); + Host_ack_control_out(); + while(data_length != 0) + { + Host_unfreeze_pipe(); + status = host_get_pipe_length(); + if ( (U16)status > data_length) + { + status = (U8)data_length; + data_length = 0; + } + else + { + data_length -= status; + } + Address_fifochar_endpoint(global_pipe_nb); + while (status!=0) + { + Host_write_byte(*data_pointer); + data_pointer++; + status--; + } + Host_send_control_out(); + while (!Is_host_control_out_sent()) + { + if (Is_host_emergency_exit()) + { + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if (Is_timeout_bdev_response_overflow()) + { + Otg_print_new_failure_message(OTGMSG_DEVICE_NO_RESP,OTG_TEMPO_4SEC); + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if(Is_host_pipe_error()) + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_control_end; + } + if(Is_host_stall()) + { + status=CONTROL_STALL; + Host_ack_stall(); + goto host_send_control_end; + } + } + Host_ack_control_out(); + } // end of OUT data stage + Host_freeze_pipe(); + Host_set_token_in(); + Host_unfreeze_pipe(); + while(!Is_host_control_in_received()) + { + if (Is_host_emergency_exit()) + { + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if (Is_timeout_bdev_response_overflow()) + { + Otg_print_new_failure_message(OTGMSG_DEVICE_NO_RESP,OTG_TEMPO_4SEC); + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if(Is_host_pipe_error()) + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_control_end; + } + if(Is_host_stall()) + { + status=CONTROL_STALL; + Host_ack_stall(); + goto host_send_control_end; + } + } + Host_ack_control_in(); + Host_freeze_pipe(); + Host_send_control_in(); + status=(CONTROL_GOOD); + goto host_send_control_end; + } + +host_send_control_end: + return ((U8)status); +} + + diff --git a/usb/otg/usb_host_task.c b/usb/otg/usb_host_task.c new file mode 100644 index 0000000..6d38400 --- /dev/null +++ b/usb/otg/usb_host_task.c @@ -0,0 +1,1260 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "conf_usb.h" +#include +#include +#include +#include "usb/otg/usb_task.h" +#include "usb_host_task.h" +#include "usb/otg/usb_drv.h" +#include "usb/otg/usb_host_enum.h" +#include +#include "main.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +//jcb #define WAIT_100MS 100 +// Wait 100 x 125 us = 12,5 ms before USB reset +//#define WAIT_100MS 800 +#define WAIT_100MS 100 + +#ifndef DEVICE_ADDRESS +#error DEVICE_ADDRESS should be defined somewhere in config files (conf_usb.h) +#endif + +#ifndef SIZEOF_DATA_STAGE +#error SIZEOF_DATA_STAGE should be defined in conf_usb.h +#endif + +#ifndef HOST_CONTINUOUS_SOF_INTERRUPT +#error HOST_CONTINUOUS_SOF_INTERRUPT should be defined as ENABLE or DISABLE in conf_usb.h +#endif + +#ifndef Usb_id_transition_action +#define Usb_id_transition_action() +#endif +#ifndef Host_device_disconnection_action +#define Host_device_disconnection_action() +#endif +#ifndef Host_device_connection_action +#define Host_device_connection_action() +#endif +#ifndef Host_sof_action +#define Host_sof_action() +#endif +#ifndef Host_suspend_action +#define Host_suspend_action() +#endif +#ifndef Host_hwup_action +#define Host_hwup_action() +#endif +#ifndef Host_device_not_supported_action +#define Host_device_not_supported_action() +#endif +#ifndef Host_device_class_not_supported_action +#define Host_device_class_not_supported_action() +#endif +#ifndef Host_device_supported_action +#define Host_device_supported_action() +#endif +#ifndef Host_device_error_action +#define Host_device_error_action() +#endif + +extern U8 id_changed_to_host_event; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +volatile S_pipe_int it_pipe_str[MAX_EP_NB]; +volatile U8 pipe_nb_save; +U8 g_sav_int_sof_enable; + +//! Its value represent the current state of the +//! device connected to the usb host controller +//! Value can be: +//! - DEVICE_ATTACHED +//! - DEVICE_POWERED +//! - DEVICE_SUSPENDED +//! - DEVICE_DEFAULT +//! - DEVICE_ADDRESSED +//! - DEVICE_CONFIGURED +//! - DEVICE_ERROR +//! - DEVICE_UNATTACHED +//! - DEVICE_READY +//! - DEVICE_WAIT_RESUME +//! - DEVICE_DISCONNECTED +//! - DEVICE_DISCONNECTED_ACK +//! - and these have been added for OTG : +//! - A_PERIPHERAL +//! - A_INIT_HNP +//! - A_SUSPEND +//! - A_END_HNP_WAIT_VFALL +U8 device_state; + +//! For control requests management over pipe 0 +S_usb_setup_data usb_request; + +//! Internal RAM buffer for USB data stage content +//! This buffer is required to setup host enumeration process +//! Its contains the device descriptors received. +//! Depending on the device descriptors lenght, its size can be optimized +//! with the SIZEOF_DATA_STAGE define of conf_usb.h file +U8 data_stage[SIZEOF_DATA_STAGE]; + +U8 device_status; +U8 request_resume; + + +U8 new_device_connected=0; + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ +static U16 hostSOFCounter; // As internal host start of frame counter + + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// This function initializes the USB controller in host mode and the associated +/// variables. +/// This function enables the USB controller for host mode operation. +//------------------------------------------------------------------------------ +void usb_host_task_init(void) +{ + unsigned int i; + + TRACE_DEBUG("usb_host_task_init\n\r"); + + for( i=0; ibOTGSoftwareVbusCtrl == ENABLE) { + if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()) + { + Usb_ack_bconnection_error_interrupt(); + Usb_ack_vbus_error_interrupt(); + Host_clear_vbus_request(); + } + if (Is_usb_id_host()) { + Host_ack_device_connection(); + // Usb_enable_manual_vbus(); + Usb_ack_bconnection_error_interrupt(); + Usb_enable_vbus_pad(); + Usb_enable_vbus(); + Host_vbus_action(); + } + + Usb_disable_vbus_pad(); + Usb_enable_manual_vbus(); + + if(Is_usb_srp_interrupt()) { + Usb_ack_srp_interrupt(); + // if Vbus was not already delivered, it is really an SRP (OTG B-Device) + device_state=DEVICE_ATTACHED; + Usb_ack_bconnection_error_interrupt(); + Usb_enable_vbus_pad(); + Usb_enable_vbus(); + Host_vbus_action(); + } + } + else { + Usb_enable_vbus(); // Give at least device power supply!!! + Host_vbus_action(); + if(Is_usb_vbus_high()) { + device_state=DEVICE_ATTACHED; + } // If VBUS ok goto to device connection expectation + } + } + break; + + case DEVICE_ATTACHED : + // DEVICE_ATTACHED state + // - Vbus is on + // - Try to detect device connection + if (Is_device_connection()) { // Device pull-up detected + //TRACE_DEBUG("Is_device_connection\n\r"); + Host_ack_device_connection(); + // Now device is connected, enable disconnection interrupt + Host_enable_device_disconnection_interrupt(); + // Reset device status + Host_clear_device_supported(); + Host_clear_configured(); + Host_clear_device_ready(); + Host_ack_sof(); + + TRACE_DEBUG("begin timer\n\r"); + gSystemTick = 0; + DelayMS(200); + TRACE_DEBUG("end timer\n\r"); + // Clear bad VBUS error + Usb_ack_vbus_error_interrupt(); + Host_disable_device_disconnection_interrupt(); + + Host_send_reset(); // First USB reset + Host_enable_sof(); // Start Start Of Frame generation + Host_enable_sof_interrupt(); // SOF will be detected under interrupt + + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()) { + } // Active wait of end of reset send + Host_ack_reset(); + //Workaround for some bugly devices with powerless pull up + //usually low speed where data line rise slowly and can be interpretaded as disconnection + for(hostSOFCounter=0;hostSOFCounter!=0xFFFF;hostSOFCounter++) { // Basic Timeout counter + if(Is_usb_event(EVT_HOST_SOF)) { //If we detect SOF, device is still alive and connected, just clear false disconnect flag + if(Is_device_disconnection()) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + break; + } + } + } + Host_enable_device_disconnection_interrupt(); + hostSOFCounter = 0; + while (hostSOFCounter Retry the connection process from the begining + if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()||Is_usb_vbus_low()) { + TRACE_DEBUG("HOST device_attached_error\n\r"); + TRACE_DEBUG("Is_usb_bconnection_error_interrupt: 0x%X\n\r", Is_usb_bconnection_error_interrupt()); + TRACE_DEBUG("Is_usb_vbus_error_interrupt: 0x%X\n\r", Is_usb_vbus_error_interrupt()); + TRACE_DEBUG("Is_usb_vbus_low: 0x%X\n\r", Is_usb_vbus_low()); + //while(1); //JCB for test, to be removed. + if (Is_usb_id_host()) { + Usb_ack_bconnection_error_interrupt(); + Usb_enable_vbus_hw_control(); + device_state=DEVICE_UNATTACHED; + Usb_disable_vbus(); + Usb_disable_vbus_pad(); + Usb_enable_vbus_pad(); + Usb_ack_vbus_error_interrupt(); + Usb_enable_vbus(); + Usb_disable_vbus_hw_control(); + Host_disable_sof(); + Host_vbus_action(); + } + else { + device_state = DEVICE_UNATTACHED; + } + } + break; + + case DEVICE_POWERED : + // DEVICE_POWERED state + // + // - Device connection (attach) as been detected, + // - Wait 100ms and configure default control pipe + // + //TRACE_INFO("Device Connection\n\r"); + Host_device_connection_action(); + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + if (hostSOFCounter++ >= WAIT_100MS) { + device_state = DEVICE_DEFAULT; + Host_select_pipe(PIPE_CONTROL); + Host_enable_pipe(); + host_configure_pipe(PIPE_CONTROL, + TYPE_CONTROL, + TOKEN_SETUP, + EP_CONTROL, + SIZE_64, + ONE_BANK, + 0 ); + device_state = DEVICE_DEFAULT; + } + } + break; + + case DEVICE_DEFAULT : + // DEVICE_DEFAULT state + // - Get device descriptor + // - Reconfigure Pipe 0 according to Device EP0 + // - Attribute device address + TRACE_DEBUG("DEVICE_DEFAULT\n\r"); + // Get first device descriptor + + if( CONTROL_GOOD == host_get_device_descriptor_uncomplete()) { + hostSOFCounter = 0; + while(hostSOFCounter<20) { // wait 20ms before USB reset (special buggly devices...) + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + hostSOFCounter++; + } + if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) { + break; + } + } + Host_disable_device_disconnection_interrupt(); + Host_send_reset(); // First USB reset + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()); // Active wait of end of reset send + Host_ack_reset(); + + + //Workaround for some bugly devices with powerless pull up + //usually low speed where data line rise slowly and can be interpretaded as disconnection + for(hostSOFCounter=0;hostSOFCounter!=0xFFFF;hostSOFCounter++) { // Basic Timeout counter + if(Is_usb_event(EVT_HOST_SOF)) { //If we detect SOF, device is still alive and connected, just clear false disconnect flag + if(Is_device_disconnection()) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + break; + } + } + } + Host_enable_device_disconnection_interrupt(); + hostSOFCounter = 0; + while(hostSOFCounter<200) { // wait 200ms after USB reset + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + hostSOFCounter++; + } + if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) { + break; + } + } + + Host_select_pipe(PIPE_CONTROL); + Host_disable_pipe(); + Host_unallocate_memory(); + Host_enable_pipe(); + // Re-Configure the Ctrl Pipe according to the device ctrl EP + + TRACE_DEBUG("Size: 0x%X\n\r", (U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE]); + TRACE_DEBUG("Size Pipe: 0x%X\n\r", host_determine_pipe_size((U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE])); + + host_configure_pipe(PIPE_CONTROL, + TYPE_CONTROL, + TOKEN_SETUP, + EP_CONTROL, + host_determine_pipe_size((U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE]), + ONE_BANK, + 0 ); + // Give an absolute device address + host_set_address(DEVICE_ADDRESS); + host_configure_address(PIPE_CONTROL, DEVICE_ADDRESS); + device_state = DEVICE_ADDRESSED; + } + else { + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_ADDRESSED : + // DEVICE_ADDRESSED state + // - Check if VID PID is in supported list + TRACE_DEBUG("DEVICE_ADDRESSED\n\r"); + if (CONTROL_GOOD == host_get_device_descriptor()) { + // Detect if the device connected belongs to the supported devices table + if (HOST_TRUE == host_check_VID_PID()) { + Host_set_device_supported(); + Host_device_supported_action(); + device_state = DEVICE_CONFIGURED; + } + else + { + } + + } + else {// Can not get device descriptor + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_CONFIGURED : + // DEVICE_CONFIGURED state + // - Configure pipes for the supported interface + // - Send Set_configuration() request + // - Goto full operating mode (device ready) + TRACE_DEBUG("DEVICE_CONFIGURED\n\r"); + if (CONTROL_GOOD == host_get_configuration_descriptor()) { + if (HOST_FALSE != host_check_class()) { // Class support OK? + host_auto_configure_endpoint(); + + if (Is_host_configured()) { + if (CONTROL_GOOD== host_set_configuration(1)) { // Send Set_configuration + // host_set_interface(interface_bound,interface_bound_alt_set); + // device and host are now fully configured + // goto DEVICE READY normal operation + device_state = DEVICE_READY; + // monitor device disconnection under interrupt + Host_enable_device_disconnection_interrupt(); + // If user host application requires SOF interrupt event + // Keep SOF interrupt enable otherwize, disable this interrupt +#if (HOST_CONTINUOUS_SOF_INTERRUPT==DISABLE) + Host_disable_sof_interrupt(); +#endif + new_device_connected=TRUE; + TRACE_INFO("Device Enumerated\n\r"); + } + else { // Problem during Set_configuration request... + device_state = DEVICE_ERROR; + } + } + } + else { // device class not supported... + device_state = DEVICE_ERROR; + TRACE_INFO("Unsupported Device\n\r"); + Host_device_class_not_supported_action(); + } + } + else { // Can not get configuration descriptors... + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_READY : + // DEVICE_READY state + // - Full standard operating mode + // - Nothing to do... + // Host full std operating mode! + new_device_connected=FALSE; + + // Handles user requests : "stop Vbus" and "suspend" + break; + + case DEVICE_ERROR : + //------------------------------------------------------ + // DEVICE_ERROR state + // - Error state + // - Do custom action call (probably go to default mode...) + TRACE_DEBUG("DEVICE_ERROR\n\r"); + Host_device_error_action(); + break; + + case DEVICE_SUSPENDED : + // DEVICE_SUSPENDED state + // - Host application request to suspend the device activity + // - State machine comes here thanks to Host_request_suspend() + TRACE_DEBUG("DEVICE_SUSPENDED\n\r"); + device_state=DEVICE_WAIT_RESUME; // wait for device resume event + if(Is_device_supports_remote_wakeup()) { // If the connected device supports remote wake up + if (CONTROL_GOOD != host_set_feature_remote_wakeup()) { + device_state = DEVICE_DISCONNECTED; // stop connexion because device has not accepted the feature + } + } + TRACE_INFO("Usb suspend\n\r"); + hostSOFCounter = Is_host_sof_interrupt_enabled(); //Save current sof interrupt enable state + Host_disable_sof_interrupt(); + Host_ack_sof(); + Host_disable_sof(); // Stop start of frame generation, this generates the suspend state + Host_ack_remote_wakeup(); + Host_enable_remote_wakeup_interrupt(); + Host_ack_hwup(); + Host_enable_hwup_interrupt(); // Enable host wake-up interrupt + // (this is the unique USB interrupt able to wake up the CPU core from power-down mode) + Usb_freeze_clock(); + Host_suspend_action(); // Custom action here! (for example go to power-save mode...) + } + break; + + case DEVICE_WAIT_RESUME : + // DEVICE_WAIT_RESUME state + // - Wait in this state till the host receives an upstream resume from the device + // - or the host software request the device to resume + TRACE_DEBUG("DEVICE_WAIT_RESUME\n\r"); + if(Is_usb_event(EVT_HOST_REMOTE_WAKEUP)|| Is_host_request_resume()) { // Remote wake up has been detected + // or Local resume request has been received + if(Is_host_request_resume()) { // Not a remote wakeup, but an host application request + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + // CAUTION HWUP can be cleared only when USB clock is active + // Pll_start_auto(); // First Restart the PLL for USB operation + // Wait_pll_ready(); // Get sure pll is lock + Usb_unfreeze_clock(); // Enable clock on USB interface + } + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_enable_sof(); + + if (Is_usb_event(EVT_HOST_REMOTE_WAKEUP)) { + Usb_ack_event(EVT_HOST_REMOTE_WAKEUP); // Ack software event + Host_disable_sof_interrupt(); + Host_ack_device_disconnection(); + Host_disable_device_disconnection_interrupt(); + + Host_send_resume(); // this other downstream resume is done to ensure min. 20ms of HOST DRIVING RESUME (not Device) + while (!Is_device_disconnection() && Host_is_resume()); + hostSOFCounter = 0; + Host_ack_sof(); + while (!Is_device_disconnection() && (hostSOFCounter != 12)) { // wait for min. 10ms of device recovery time + if (Is_host_sof()) { + Host_ack_sof(); + hostSOFCounter++; + } + } + if (Is_device_disconnection()) { + usb_host_task_init(); + device_state = DEVICE_DISCONNECTED; + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + } + else { + device_state = DEVICE_READY; + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + } + Host_enable_device_disconnection_interrupt(); + Host_ack_sof(); + } + else { + Host_send_resume(); // Send down stream resume + //----------------------- + // Work-around for case of Device disconnection during Suspend + // The disconnection is never detected and the Resume bit remains high (and RSMEDI flag never set) + // If the timeout elapses, it implies that the device has disconnected => macro is reset (to reset the Resume bit) + dec = 0; + while (dec < 0x4FFFF) { // several hundreds of ms + if (Is_host_down_stream_resume()) { // Wait Down stream resume sent + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + if(hostSOFCounter) { + Host_enable_sof_interrupt(); + } // Restore SOF interrupt enable state before suspend + device_state=DEVICE_READY; // Come back to full operating mode + TRACE_INFO("Usb resumed\n\r"); + dec = 0x3FFFFE; // will cause a loop end + } + dec++; + } + if (dec != 0x3FFFFF) { // if resume failed + usb_host_task_init(); + device_state = DEVICE_DISCONNECTED; + } + else + { + hostSOFCounter = 0; + Host_ack_sof(); + while (!Is_device_disconnection() && (hostSOFCounter != 12)) { // wait for min. 10ms of device recovery time + if (Is_host_sof()) { + Host_ack_sof(); + hostSOFCounter++; + } + } + } + //-----------------------End of Work Around + } + } + break; + + case DEVICE_DISCONNECTED : + // DEVICE_DISCONNECTED state + // - Device disconnection has been detected + // - Run scheduler in this state at least two times to get sure event is detected by all host application tasks + // - Go to DEVICE_DISCONNECTED_ACK state before DEVICE_UNATTACHED, to get sure scheduler calls all app tasks... + TRACE_DEBUG("DEVICE_DISCONNECTED\n\r"); + device_state = DEVICE_DISCONNECTED_ACK; + break; + + case DEVICE_DISCONNECTED_ACK : + // DEVICE_DISCONNECTED_ACK state + // - Device disconnection has been detected and managed bu applicatives tasks + // - Go to DEVICE_UNATTACHED state + TRACE_DEBUG("DEVICE_DISCONNECTED_ACK\n\r"); + host_disable_all_pipe(); + device_state = DEVICE_UNATTACHED; + break; + + + default : + // default state + // - Default case: ERROR + // - Goto no device state + TRACE_DEBUG("default\n\r"); + device_state = DEVICE_UNATTACHED; + break; + } +} + +//------------------------------------------------------------------------------ +/// This function send nb_data pointed with *buf with the pipe number specified +/// This function will activate the host sof interrupt to detect timeout. The +/// interrupt enable sof will be restore. +//------------------------------------------------------------------------------ +U8 host_send_data(U8 pipe, U16 nb_data, U8 *buf) +{ + U16 length; + U8 status=PIPE_GOOD; + U8 sav_int_sof_enable; + U8 nak_timeout; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + U16 cpt_nak; +#endif + U16 nb_data_loaded; + + TRACE_DEBUG("host_send_data[]%d: %d\n\r", pipe, nb_data); + + sav_int_sof_enable=Is_host_sof_interrupt_enabled(); // Save state of enable sof interrupt + Host_enable_sof_interrupt(); + Host_select_pipe(pipe); + + Host_set_token_in(); + + Host_set_token_out(); + Host_ack_out_sent(); + /* + TRACE_DEBUG("CTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_CTRL); + TRACE_DEBUG("SR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_SR); + TRACE_DEBUG("DEVCTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVCTRL); + TRACE_DEBUG("DEVISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVISR); + TRACE_DEBUG("DEVIMR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVIMR); + TRACE_DEBUG("DEVEPTISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[0]); + TRACE_DEBUG("HSTCTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTCTRL); + TRACE_DEBUG("HSTISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTISR); + TRACE_DEBUG("HSTIMR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTIMR); + TRACE_DEBUG("HSTPIP: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIP); + TRACE_DEBUG("HSTPIPCFG[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[0]); + TRACE_DEBUG("HSTPIPCFG[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[1]); + TRACE_DEBUG("HSTPIPCFG[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[2]); + TRACE_DEBUG("HSTPIPINRQ[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[0]); + TRACE_DEBUG("HSTPIPINRQ[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[1]); + TRACE_DEBUG("HSTPIPINRQ[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[2]); + TRACE_DEBUG("HSTPIPERR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[0]); + TRACE_DEBUG("HSTPIPERR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[1]); + TRACE_DEBUG("HSTPIPERR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[2]); + TRACE_DEBUG("HSTPIPISR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0]); + TRACE_DEBUG("HSTPIPISR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[1]); + TRACE_DEBUG("HSTPIPISR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[2]); + TRACE_DEBUG("HSTPIPIMR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[0]); + TRACE_DEBUG("HSTPIPIMR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[1]); + TRACE_DEBUG("HSTPIPIMR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[2]); + */ + while (nb_data != 0) { // While there is something to send... + Host_unfreeze_pipe(); + // Prepare data to be sent + length = host_get_pipe_length(); + TRACE_DEBUG("size=%d\n\r", length); + + if ( length > nb_data) { + nb_data_loaded = nb_data; + length = nb_data; + } + else { + nb_data_loaded = length; + } + Address_fifochar_endpoint(global_pipe_nb); + while (length!=0) { // Load Pipe buffer + Host_write_byte(*buf++); + //(((char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0))[dBytes++])=*(buf++); + //pFifo[dBytes++] = *buf; + //buf++; + length--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine +#if (NAK_TIMEOUT_ENABLE==ENABLE) + cpt_nak=0; +#endif + nak_timeout=0; + Host_ack_out_sent(); + Host_send_out(); + while (!Is_host_out_sent()) { + if (Is_host_emergency_exit()) { // Async disconnection or role change detected under interrupt + TRACE_DEBUG("Emergency exit\n\r"); + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + if (private_sof_counter>=250) { // Count 250ms (250sof) + TRACE_DEBUG("TimeOut Send Data\n\r"); + private_sof_counter=0; + if (nak_timeout++>=TIMEOUT_DELAY) { // Inc timeout and check for overflow + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + } + if (Is_host_pipe_error()) { // Any error ? + TRACE_DEBUG("pipe error\n\r"); + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_data_end; + } + if (Is_host_stall()) { // Stall management + TRACE_DEBUG("stall\n\r"); + status =PIPE_STALL; + Host_ack_stall(); + goto host_send_data_end; + } +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if(Is_host_nak_received()) { //NAK received + Host_ack_nak_received(); + if (cpt_nak++>NAK_SEND_TIMEOUT) { + TRACE_DEBUG("NAK timeout\n\r"); + status = PIPE_NAK_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + } +#endif + } + // Here OUT sent + nb_data -= nb_data_loaded; + status=PIPE_GOOD; // Frame correctly sent + Host_ack_out_sent(); + } + Host_freeze_pipe(); + +host_send_data_end: + // Restore sof interrupt enable state + if (sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + // And return... + return ((U8)status); +} + + + +//------------------------------------------------------------------------------ +/// This function receives nb_data pointed with *buf with the pipe number specified +/// The nb_data parameter is passed as a U16 pointer, thus the data pointed by this pointer +/// is updated with the final number of data byte received. +//------------------------------------------------------------------------------ +U8 host_get_data(U8 pipe, U16 *nb_data, U8 *buf) +{ + U8 status=PIPE_GOOD; + U8 sav_int_sof_enable; + U8 nak_timeout; + U16 n; + U16 i; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + U16 cpt_nak; +#endif + + // TRACE_DEBUG("host_get_data[%d]\n\r", pipe); + n=*nb_data; + *nb_data=0; + + sav_int_sof_enable=Is_host_sof_interrupt_enabled(); + Host_enable_sof_interrupt(); + + Host_select_pipe(pipe); + Host_set_token_in(); + Host_continuous_in_mode(); + // Host_ack_in_received(); + + while (n) { // While missing data... + // start IN request generation + Host_unfreeze_pipe(); + Host_send_in(); + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + nak_timeout=0; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + cpt_nak=0; +#endif + while (!Is_host_in_received()) + { + if (Is_host_emergency_exit()) // Async disconnection or role change detected under interrupt + { + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + if (private_sof_counter>=250) // Timeout management + { + private_sof_counter=0; // Done in host SOF interrupt + if (nak_timeout++>=TIMEOUT_DELAY)// Check for local timeout + { + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + } + if(Is_host_pipe_error()) // Error management + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_get_data_end; + } + if(Is_host_stall()) // STALL management + { + status =PIPE_STALL; + Host_reset_pipe(pipe); + Host_ack_stall(); + goto host_get_data_end; + } +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if(Is_host_nak_received()) //NAK received + { + Host_ack_nak_received(); + if (cpt_nak++>NAK_RECEIVE_TIMEOUT) + { + status = PIPE_NAK_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + } +#endif + } + status=PIPE_GOOD; + Host_freeze_pipe(); + if (Host_byte_counter()<=n) + { + if ((Host_byte_counter() < n)&&(Host_byte_counter() nb_data) // Pipe size> remaining data + { + i = nb_data; + nb_data = 0; + } + else // Pipe size < remaining data + { + nb_data -= i; + } + it_pipe_str[pipe].nb_byte_on_going+=i; // Update nb data processed + Address_fifochar_endpoint(global_pipe_nb); + while (i!=0) // Load Pipe buffer + { + Host_write_byte(*ptr_buf++); + i--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe].timeout=0; // Refresh timeout counter + Host_ack_out_sent(); + Host_ack_stall(); + Host_ack_nak_received(); + + Host_enable_stall_interrupt(); + Host_enable_error_interrupt(); +#if (NAK_TIMEOUT_ENABLE==ENABLE) + Host_enable_nak_interrupt(); +#endif + Host_enable_transmit_interrupt(); + Host_send_out(); // Send the USB frame + return HOST_TRUE; + } +} + +//------------------------------------------------------------------------------ +//! @brief USB pipe interrupt subroutine +//! +//! @param none +//! +//! @return none +//------------------------------------------------------------------------------ +void usb_pipe_interrupt(void) +{ + U8 pipe_nb; + U8 *ptr_buf; + void (*fct_handle)(U8 status,U16 nb_byte); + U16 n; + U8 i; + U8 do_call_back=FALSE; + + TRACE_DEBUG("usb_pipe_interrupt\n\r"); + + if(Host_get_pipe_interrupt()) { + + pipe_nb_save = Host_get_selected_pipe(); // Important! Save here working pipe number + pipe_nb=host_get_nb_pipe_interrupt(); // work with the correct pipe number that generates the interrupt + Host_select_pipe(pipe_nb); // Select this pipe + fct_handle=*(it_pipe_str[pipe_nb].handle); + + // Now try to detect what event generate an interrupt... + if (Is_host_pipe_error()) // Any error ? + { + TRACE_DEBUG("host_pipe_error\n\r"); + it_pipe_str[pipe_nb].status = Host_error_status(); + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + Host_ack_all_errors(); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + + if (Is_host_stall()) // Stall handshake received ? + { + TRACE_DEBUG("host_stall\n\r"); + it_pipe_str[pipe_nb].status=PIPE_STALL; + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if (Is_host_nak_received()) // NAK ? + { + Host_ack_nak_received(); + // check if number of NAK timeout error occurs (not for interrupt type pipe) + if((--it_pipe_str[pipe_nb].nak_timeout==0) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) + { + it_pipe_str[pipe_nb].status=PIPE_NAK_TIMEOUT; + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + } +#endif + + if (Is_host_in_received()) // Pipe IN reception ? + { + TRACE_DEBUG("host_in received\n\r"); + ptr_buf = it_pipe_str[pipe_nb].ptr_buf; + ptr_buf += it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer + n = it_pipe_str[pipe_nb].nb_byte_to_process; + n -= it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes + Host_freeze_pipe(); + if (Host_byte_counter()<=n) + { + if ((Host_byte_counter() < n)&&(Host_byte_counter()0) //still something to process + { + Host_unfreeze_pipe(); // Request another IN transfer + Host_send_in(); + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe_nb].timeout=0; // Reset timeout + it_pipe_str[pipe_nb].nak_timeout=NAK_RECEIVE_TIMEOUT; + } + else //end of transfer + { + it_pipe_str[pipe_nb].enable=DISABLE; + it_pipe_str[pipe_nb].status=PIPE_GOOD; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + } + } + + if(Is_host_out_sent()) // Pipe OUT sent ? + { + TRACE_DEBUG("host_out send\n\r"); + Host_ack_out_sent(); + it_pipe_str[pipe_nb].nb_byte_processed+=it_pipe_str[pipe_nb].nb_byte_on_going; + it_pipe_str[pipe_nb].nb_byte_on_going=0; + ptr_buf = it_pipe_str[pipe_nb].ptr_buf; + ptr_buf += it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer + n = it_pipe_str[pipe_nb].nb_byte_to_process; + n -= it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes + if(n>0) // Still data to process... + { + Host_unfreeze_pipe(); + // Prepare data to be sent + i = host_get_pipe_length(); + if ( i > n) // Pipe size> remaining data + { + i = n; + n = 0; + } + else // Pipe size < remaining data + { + n -= i; + } + it_pipe_str[pipe_nb].nb_byte_on_going+=i; // Update nb data processed + Address_fifochar_endpoint(global_pipe_nb); + while (i!=0) // Load Pipe buffer + { + Host_write_byte(*ptr_buf++); i--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe_nb].timeout=0; // Refresh timeout counter + it_pipe_str[pipe_nb].nak_timeout=NAK_SEND_TIMEOUT; + Host_send_out(); // Send the USB frame + } + else //n==0 Transfer is finished + { + it_pipe_str[pipe_nb].enable=DISABLE; // Tranfer end + it_pipe_str[pipe_nb].status=PIPE_GOOD; // Status OK + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + } + } + +usb_pipe_interrupt_end: + Host_select_pipe(pipe_nb_save); // Restore pipe number !!!! + if (is_any_interrupt_pipe_active()==FALSE) // If no more transfer is armed + { + if (g_sav_int_sof_enable==FALSE) + { + Host_disable_sof_interrupt(); + } + } + if(do_call_back) // Any callback functions to perform ? + { + fct_handle(it_pipe_str[pipe_nb].status,it_pipe_str[pipe_nb].nb_byte_processed); + } + + } + +} + + + diff --git a/usb/otg/usb_host_task.h b/usb/otg/usb_host_task.h new file mode 100644 index 0000000..af752ec --- /dev/null +++ b/usb/otg/usb_host_task.h @@ -0,0 +1,230 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ +#ifndef _USB_HOST_TASK_H_ +#define _USB_HOST_TASK_H_ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include +#include + +#include "main.h" + +//! @brief Selects the Reset Length (x11ms) +//! This value is the number of consecutives Reset sent by the Host +#define OTG_RESET_LENGTH 1 + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ +typedef struct +{ + bit enable; + U16 nb_byte_to_process; + U16 nb_byte_processed; + U16 nb_byte_on_going; + U8 *ptr_buf; + void(*handle)(U8 status, U16 nb_byte); + U8 status; + U8 timeout; + U16 nak_timeout; +} S_pipe_int; + + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#define PIPE_GOOD 0 +//#define PIPE_DATA_TOGGLE 0x01 +//#define PIPE_DATA_PID 0x02 +//#define PIPE_PID 0x04 +//#define PIPE_TIMEOUT 0x08 +//#define PIPE_CRC16 0x10 +#define PIPE_STALL 0x20 +#define PIPE_NAK_TIMEOUT 0x40 +#define PIPE_DELAY_TIMEOUT 0x80 + +// usb_host_task USB host task module +// Returns true when device connected and correctly enumerated. +// The host high level application should tests this before performing any applicative requests +// to the device connected +#define Is_host_ready() ((device_state==DEVICE_READY) ? TRUE : FALSE) + +/// Check if host controller is in suspend mode +#define Is_host_suspended() (((device_state==DEVICE_WAIT_RESUME) ||(device_state==DEVICE_SUSPENDED)) ? TRUE : FALSE) + +/// Check if host controller is not suspend mode +#define Is_host_not_suspended() (((device_state==DEVICE_WAIT_RESUME) ||(device_state==DEVICE_SUSPENDED)) ? FALSE : TRUE) + +/// This function should be called to make the host controller enter USB suspend mode +#define Host_request_suspend() (device_state=DEVICE_SUSPENDED) + +/// This function should be called to request the host controller to resume the USB bus +#define Host_request_resume() (request_resume=TRUE) + +/// Private ack for software event +#define Host_ack_request_resume() (request_resume=FALSE) + +/// Private check for resume sequence +#define Is_host_request_resume() ((request_resume==TRUE) ? TRUE : FALSE) + +/// Returns true when a new device is enumerated +#define Is_new_device_connection_event() (new_device_connected ? TRUE : FALSE) + +/// Returns true when the device disconnects from the host +#define Is_device_disconnection_event() ((device_state==DEVICE_DISCONNECTED_ACK || device_state==DEVICE_DISCONNECTED) ? TRUE : FALSE) + +/// Stop all interrupt attached to a pipe +#define Host_stop_pipe_interrupt(i) {Host_disable_transmit_interrupt();\ + Host_disable_receive_interrupt();\ + Host_disable_stall_interrupt();\ + Host_disable_error_interrupt();\ + Host_disable_nak_interrupt();\ + Host_reset_pipe(i); } + +/// device_state_value Host controller states +/// Defines for device state coding +#define DEVICE_UNATTACHED 0 +#define DEVICE_ATTACHED 1 +#define DEVICE_POWERED 2 +#define DEVICE_DEFAULT 3 +#define DEVICE_ADDRESSED 4 +#define DEVICE_CONFIGURED 5 +#define DEVICE_READY 6 +#define DEVICE_ERROR 7 +#define DEVICE_SUSPENDED 8 +#define DEVICE_WAIT_RESUME 9 +#define DEVICE_DISCONNECTED 10 +#define DEVICE_DISCONNECTED_ACK 11 +#define A_PERIPHERAL 12 // used for A-Device in OTG mode +#define A_INIT_HNP 13 +#define A_SUSPEND 14 +#define A_END_HNP_WAIT_VFALL 15 +#define A_TEMPO_VBUS_DISCHARGE 16 + + +#define Host_set_device_supported() (device_status |= 0x01) +#define Host_clear_device_supported() (device_status &= ~0x01) + +#define Host_set_device_ready() (device_status |= 0x02) +#define Host_clear_device_ready() (device_status &= ~0x02) + +#define Host_set_configured() (device_status |= 0x04) +#define Host_clear_configured() (device_status &= ~0x04) +#define Is_host_configured() (device_status & 0x04) + + + + +/// Has a SRP been received, and waiting for a connect of B-Device (Vbus delivered) +#define Srp_received_and_waiting_connect() (otg_a_device_srp |= 0x01) +#define Ack_srp_received_and_connect() (otg_a_device_srp &= ~0x01) +#define Is_srp_received_and_waiting_connect() (((otg_a_device_srp&0x01) != 0) ? TRUE : FALSE) +/// Is the current session has been started with SRP +#define Host_session_started_srp() (otg_a_device_srp |= 0x02) +#define Host_end_session_started_srp() (otg_a_device_srp &= ~0x02) +#define Is_host_session_started_srp() (((otg_a_device_srp&0x02) != 0) ? TRUE : FALSE) + +/// Is the current peripheral is an OTG device ? +#define Peripheral_is_not_otg_device() (otg_device_connected = 0x00) +#define Peripheral_is_otg_device() (otg_device_connected = 0x11) +#define Is_peripheral_otg_device() ((otg_device_connected != 0) ? TRUE : FALSE) + +/// Check if counter of Vbus delivery time after SRP is elapsed +// 0xDAC = 3500, 3500x2 = 7000 => 7s +#define T_VBUS_DELIV_AFTER_SRP 0xDAC // minimum time (x2ms) with Vbus ON once a SRP has been received (5s T_VBUS_DELIV_AFTER_SRP) ? TRUE : FALSE) + +/// Check if counter of A-Suspend delay is elapsed +/// Max. delay for a B-DEVICE to disconnect once the A-HOST has set suspend mode +// Min 200 ms +// 0x96 = 150 ,150x2 = 300 => 300 ms +#define TA_AIDL_BDIS 0x96 // minimum time (x2ms) in A_suspend state before stop Vbus (must be > 200ms) + // if value = 0, this is an infinite delay +#define Init_ta_aidl_bdis_counter() (otg_ta_aidl_bdis_tmr = TA_AIDL_BDIS) +#define Is_ta_aidl_bdis_counter_overflow() ((otg_ta_aidl_bdis_tmr == 0x0001) ? TRUE : FALSE) + +/// Check if counter otg_timeout_bdev_respond is elapsed +// 0xD00 = 3328, 3328x2 = 6656 => 6s +#define TM_OUT_MAX_BDEV_RESPONSE 0xD00 // maximum delay for the A-Device waiting for a response from B-Device once attached +#define Init_timeout_bdev_response() (otg_timeout_bdev_respond = TM_OUT_MAX_BDEV_RESPONSE) +#define Is_timeout_bdev_response_overflow() ((otg_timeout_bdev_respond == 0) ? TRUE : FALSE) + +/// Check if counter otg_ta_vbus_rise is elapsed +// 0x28 = 40, 40x2 = 80 => 80ms +#define TA_VBUS_RISE 0x28 // maximum delay for Vbus to reach the Va_vbus_valid threshold after being requested (must be < 100ms) +#define Init_ta_vbus_rise_counter() (otg_ta_vbus_rise = TA_VBUS_RISE) +#define Is_ta_vbus_rise_counter_overflow() ((otg_ta_vbus_rise == 0) ? TRUE : FALSE) + +/// Check if counter otg_ta_vbus_fall is elapsed +// 50x2 = 100 => 100ms +#define TA_VBUS_FALL 50 +#define Init_ta_vbus_fall_counter() (otg_end_hnp_vbus_delay = TA_VBUS_FALL) +#define Is_ta_vbus_fall_counter_overflow() ((otg_end_hnp_vbus_delay == 0) ? TRUE : FALSE) + + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ +extern U8 g_sav_int_sof_enable; +extern U8 device_state; +extern U8 request_resume; +extern U8 new_device_connected; + +// OTG Defines, Variables and Macros +// See "usb_host_task.c" file for description of variables role and use +extern U16 otg_ta_srp_wait_connect; +extern U16 otg_ta_aidl_bdis_tmr; +extern U8 otg_ta_vbus_rise; +extern U16 otg_timeout_bdev_respond; +extern U16 otg_end_hnp_vbus_delay; + +extern U8 otg_a_device_srp; +extern U8 otg_device_connected; +extern S_usb_setup_data usb_request; +extern U8 device_status; +extern U8 data_stage[SIZEOF_DATA_STAGE]; + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- +extern void usb_host_task_init(void); +extern void usb_host_task(void); +extern U8 host_send_data(U8 pipe, U16 nb_data, U8 *buf); +extern U8 host_get_data(U8 pipe, U16 *nb_data, U8 *buf); +extern void reset_it_pipe_str(void); +extern U8 is_any_interrupt_pipe_active(void); +extern U8 host_get_data_interrupt(U8 pipe, U16 nb_data, U8 *buf, void (*handle)(U8 status, U16 nb_byte)); +extern U8 host_send_data_interrupt(U8 pipe, U16 nb_data, U8 *buf, void (*handle)(U8 status, U16 nb_byte)); +extern void usb_pipe_interrupt(void); + +#endif // _USB_HOST_TASK_H_ + diff --git a/usb/otg/usb_host_task_with_srp_hnp.c b/usb/otg/usb_host_task_with_srp_hnp.c new file mode 100644 index 0000000..4cf02b7 --- /dev/null +++ b/usb/otg/usb_host_task_with_srp_hnp.c @@ -0,0 +1,1493 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "conf_usb.h" +#include +#include +#include +#include +#include "usb/otg/usb_task.h" +#include "usb_host_task.h" +#include "usb/otg/usb_drv.h" +#include "usb/otg/usb_host_enum.h" +#include +#include "main.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +//jcb #define WAIT_100MS 100 +// Wait 100 x 125 us = 12,5 ms before USB reset +//#define WAIT_100MS 800 +#define WAIT_100MS 100 + +#if (HOST_STRICT_VID_PID_TABLE != ENABLE) +#warning HOST_STRICT_VID_PID_TABLE must be defined to ENABLE to comply with Targeted Peripheral List requirements +#endif + + +#ifndef DEVICE_ADDRESS +#error DEVICE_ADDRESS should be defined somewhere in config files (conf_usb.h) +#endif + +#ifndef SIZEOF_DATA_STAGE +#error SIZEOF_DATA_STAGE should be defined in conf_usb.h +#endif + +#ifndef HOST_CONTINUOUS_SOF_INTERRUPT +#error HOST_CONTINUOUS_SOF_INTERRUPT should be defined as ENABLE or DISABLE in conf_usb.h +#endif + +#ifndef Usb_id_transition_action +#define Usb_id_transition_action() +#endif +#ifndef Host_device_disconnection_action +#define Host_device_disconnection_action() +#endif +#ifndef Host_device_connection_action +#define Host_device_connection_action() +#endif +#ifndef Host_sof_action +#define Host_sof_action() +#endif +#ifndef Host_suspend_action +#define Host_suspend_action() +#endif +#ifndef Host_hwup_action +#define Host_hwup_action() +#endif +#ifndef Host_device_not_supported_action +#define Host_device_not_supported_action() +#endif +#ifndef Host_device_class_not_supported_action +#define Host_device_class_not_supported_action() +#endif +#ifndef Host_device_supported_action +#define Host_device_supported_action() +#endif +#ifndef Host_device_error_action +#define Host_device_error_action() +#endif + +extern U8 id_changed_to_host_event; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +volatile S_pipe_int it_pipe_str[MAX_EP_NB]; +volatile U8 pipe_nb_save; +U8 g_sav_int_sof_enable; + +//! Min. delay after an SRP received, with VBUS delivered ON (waiting for a B-DEV connect) +U16 otg_ta_srp_wait_connect; +//! Max. delay for a B-DEVICE to disconnect once the A-HOST has set suspend mode +U16 otg_ta_aidl_bdis_tmr; +//! Max. delay for vbus to reach Va_vbus_valid threshold +U8 otg_ta_vbus_rise; +//! Max. delay once B-Device attached to respond to the first A-Device requests +U16 otg_timeout_bdev_respond; +//! Indicates if the connected peripheral is an OTG Device or not +U8 otg_device_connected; +//! Stores special events about SRP in A-Device mode +U8 otg_a_device_srp; +//! Variable used for timing Vbus discharge to avoid bounces around vbus_valid threshold +U16 otg_end_hnp_vbus_delay; + +//! Its value represent the current state of the +//! device connected to the usb host controller +//! Value can be: +//! - DEVICE_ATTACHED +//! - DEVICE_POWERED +//! - DEVICE_SUSPENDED +//! - DEVICE_DEFAULT +//! - DEVICE_ADDRESSED +//! - DEVICE_CONFIGURED +//! - DEVICE_ERROR +//! - DEVICE_UNATTACHED +//! - DEVICE_READY +//! - DEVICE_WAIT_RESUME +//! - DEVICE_DISCONNECTED +//! - DEVICE_DISCONNECTED_ACK +//! - and these have been added for OTG : +//! - A_PERIPHERAL +//! - A_INIT_HNP +//! - A_SUSPEND +//! - A_END_HNP_WAIT_VFALL +U8 device_state; + +//! For control requests management over pipe 0 +S_usb_setup_data usb_request; + +//! Internal RAM buffer for USB data stage content +//! This buffer is required to setup host enumeration process +//! Its contains the device descriptors received. +//! Depending on the device descriptors lenght, its size can be optimized +//! with the SIZEOF_DATA_STAGE define of conf_usb.h file +U8 data_stage[SIZEOF_DATA_STAGE]; + +U8 device_status; +U8 request_resume; + + +U8 new_device_connected=0; + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ +static U16 hostSOFCounter; // As internal host start of frame counter + + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// This function initializes the USB controller in host mode and the associated +/// variables. +/// This function enables the USB controller for host mode operation. +//------------------------------------------------------------------------------ +void usb_host_task_init(void) +{ + unsigned int i; + + TRACE_DEBUG("usb_host_task_init\n\r"); + + for( i=0; ibOTGADevSRPReaction == VBUS_PULSE) { + Usb_select_vbus_srp_method(); + } + else { + Usb_select_data_srp_method(); + } + device_state=DEVICE_UNATTACHED; +} + +//------------------------------------------------------------------------------ +/// Entry point of the USB host management +/// The aim is to manage the device target connection and enumeration +/// depending on the device_state, the function performs the required operations +/// to get the device enumerated and configured +/// Once the device is operationnal, the device_state value is DEVICE_READY +/// This state should be tested by the host task application before performing +/// any applicative requests to the device. +//------------------------------------------------------------------------------ +void usb_host_task(void) +{ + U32 dec; + U8 desc_temp; + + //TRACE_DEBUG("host_task "); + switch (device_state) { + case DEVICE_UNATTACHED: + // DEVICE_UNATTACHED state + // - Default init state + // - Try to give device power supply + //TRACE_DEBUG("DEVICE_UNATTACHED\n\r"); + for (hostSOFCounter=0; hostSOFCounterbOTGSoftwareVbusCtrl == ENABLE) { + if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()) + { + Usb_ack_bconnection_error_interrupt(); + Usb_ack_vbus_error_interrupt(); + Host_clear_vbus_request(); + } + + if(Is_usb_srp_interrupt()) { + Usb_ack_srp_interrupt(); + // if Vbus was not already delivered, it is really an SRP (OTG B-Device) + Otg_print_new_event_message(OTGMSG_SRP_RECEIVED,OTG_TEMPO_2SEC); + Host_session_started_srp(); + Init_ta_srp_counter(); + Srp_received_and_waiting_connect(); + Init_ta_vbus_rise_counter(); + device_state=DEVICE_ATTACHED; + Usb_ack_bconnection_error_interrupt(); + Usb_enable_vbus_pad(); + Usb_enable_vbus(); + Host_vbus_action(); + } + } + else { + Usb_enable_vbus(); // Give at least device power supply!!! + Host_vbus_action(); + if(Is_usb_vbus_high()) { + device_state=DEVICE_ATTACHED; + } // If VBUS ok goto to device connection expectation + } + } + else if (b_uut_device_state == B_HOST) { + device_state = DEVICE_ATTACHED; + } + break; + + case DEVICE_ATTACHED : + // DEVICE_ATTACHED state + // - Vbus is on + // - Try to detect device connection + if (Is_device_connection() || (Is_usb_id_device() && (b_uut_device_state == B_HOST))) { + //TRACE_DEBUG("Is_device_connection\n\r"); + Host_ack_device_connection(); + Ack_srp_received_and_connect(); // connection might have been requested by SRP + // Now device is connected, enable disconnection interrupt + Host_enable_device_disconnection_interrupt(); + // Reset device status + Host_clear_device_supported(); + Host_clear_configured(); + Host_clear_device_ready(); + Host_ack_sof(); + + TRACE_DEBUG("begin timer\n\r"); + gSystemTick = 0; + DelayMS(200); + TRACE_DEBUG("end timer\n\r"); + // Clear bad VBUS error + Usb_ack_vbus_error_interrupt(); + Host_disable_device_disconnection_interrupt(); + + Host_send_reset(); // First USB reset + Host_enable_sof(); // Start Start Of Frame generation + Host_enable_sof_interrupt(); // SOF will be detected under interrupt + + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()) { + if (Is_usb_device_enabled()) { + break; + } + } // Active wait of end of reset send + Host_ack_reset(); + // User can choose the number of consecutive resets sent + hostSOFCounter = 1; + while (hostSOFCounter != OTG_RESET_LENGTH ) { + Host_send_reset(); + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()) { + if (Is_usb_device_enabled()) { + break; + } + }// Active wait of end of reset send + Host_ack_reset(); + hostSOFCounter++; + } + + //Workaround for some bugly devices with powerless pull up + //usually low speed where data line rise slowly and can be interpretaded as disconnection + for(hostSOFCounter=0;hostSOFCounter!=0xFFFF;hostSOFCounter++) { // Basic Timeout counter + if(Is_usb_event(EVT_HOST_SOF)) { //If we detect SOF, device is still alive and connected, just clear false disconnect flag + if(Is_device_disconnection()) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + break; + } + } + } + Host_enable_device_disconnection_interrupt(); + hostSOFCounter = 0; + while (hostSOFCounter= WAIT_100MS) { + device_state = DEVICE_DEFAULT; + Host_select_pipe(PIPE_CONTROL); + Host_enable_pipe(); + host_configure_pipe(PIPE_CONTROL, + TYPE_CONTROL, + TOKEN_SETUP, + EP_CONTROL, + SIZE_64, + ONE_BANK, + 0 ); + device_state = DEVICE_DEFAULT; + } + } + break; + + case DEVICE_DEFAULT : + // DEVICE_DEFAULT state + // - Get device descriptor + // - Reconfigure Pipe 0 according to Device EP0 + // - Attribute device address + TRACE_DEBUG("DEVICE_DEFAULT\n\r"); + // Get first device descriptor + Peripheral_is_not_otg_device(); // init status variable + Init_timeout_bdev_response(); // init B-Device "waiting response" delay (handled by timer interrupt in usb_task.c) + + if( CONTROL_GOOD == host_get_device_descriptor_uncomplete()) { + hostSOFCounter = 0; + while(hostSOFCounter<20) { // wait 20ms before USB reset (special buggly devices...) + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + hostSOFCounter++; + } + if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) { + break; + } + } + Host_disable_device_disconnection_interrupt(); + Host_send_reset(); // First USB reset + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()); // Active wait of end of reset send + Host_ack_reset(); + hostSOFCounter = 1; + while (hostSOFCounter != OTG_RESET_LENGTH) { + Host_send_reset(); + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()); // Active wait of end of reset send + Host_ack_reset(); + hostSOFCounter++; + } + + //Workaround for some bugly devices with powerless pull up + //usually low speed where data line rise slowly and can be interpretaded as disconnection + for(hostSOFCounter=0;hostSOFCounter!=0xFFFF;hostSOFCounter++) { // Basic Timeout counter + if(Is_usb_event(EVT_HOST_SOF)) { //If we detect SOF, device is still alive and connected, just clear false disconnect flag + if(Is_device_disconnection()) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + break; + } + } + } + Host_enable_device_disconnection_interrupt(); + hostSOFCounter = 0; + while(hostSOFCounter<200) { // wait 200ms after USB reset + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + hostSOFCounter++; + } + if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) { + break; + } + } + + Host_select_pipe(PIPE_CONTROL); + Host_disable_pipe(); + Host_unallocate_memory(); + Host_enable_pipe(); + // Re-Configure the Ctrl Pipe according to the device ctrl EP + + TRACE_DEBUG("Size: 0x%X\n\r", (U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE]); + TRACE_DEBUG("Size Pipe: 0x%X\n\r", host_determine_pipe_size((U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE])); + + host_configure_pipe(PIPE_CONTROL, + TYPE_CONTROL, + TOKEN_SETUP, + EP_CONTROL, + host_determine_pipe_size((U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE]), + ONE_BANK, + 0 ); + // Give an absolute device address + host_set_address(DEVICE_ADDRESS); + host_configure_address(PIPE_CONTROL, DEVICE_ADDRESS); + device_state = DEVICE_ADDRESSED; + } + else { + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_ADDRESSED : + // DEVICE_ADDRESSED state + // - Check if VID PID is in supported list + TRACE_DEBUG("DEVICE_ADDRESSED\n\r"); + if (CONTROL_GOOD == host_get_device_descriptor()) { + // Detect if the device connected belongs to the supported devices table + if (HOST_TRUE == host_check_VID_PID()) { + Host_set_device_supported(); + Host_device_supported_action(); + device_state = DEVICE_CONFIGURED; + // In OTG A-HOST state, initiate a HNP if the OTG B-DEVICE has requested this session with a SRP + if ((pOTGDescriptor->bOTGEnableHNPAfterSRP == ENABLE) && Is_host_session_started_srp() && Is_usb_id_host()) { + device_state = A_INIT_HNP; + } + else { + if (Is_device_supports_hnp()) { + if (CONTROL_GOOD != host_set_feature_a_hnp_support()) { + device_state = A_END_HNP_WAIT_VFALL; // end session if Device STALLs the request + } + } + } + } + else + { + // In OTG, if the B-DEVICE VID/PID does not match the Target Peripheral List, it is seen as "Unsupported" + // - a HNP must be initiated if the device supports it + // - an error message must be displayed (and difference must be made between "Std device" and "Hub") + desc_temp = data_stage[OFFSET_DEV_DESC_CLASS]; // store the device class (for future hub check) + if (b_uut_device_state != B_HOST) { + if (Is_host_session_started_srp()) { + if (CONTROL_GOOD == host_get_configuration_descriptor()) { + host_check_OTG_features(); + if (Is_device_supports_hnp()) { + device_state = A_INIT_HNP; // unsupported (or test) device will cause a HNP request + } + else { + device_state = A_END_HNP_WAIT_VFALL; + if (desc_temp == HUB_CLASS_CODE) { + // Display "Hub unsupported" message + Otg_print_new_failure_message(OTGMSG_UNSUPPORTED_HUB,OTG_TEMPO_4SEC); + } + else { + // Display "Class unsupported" message + TRACE_DEBUG("Class unsupported\n\r"); + Otg_print_new_failure_message(OTGMSG_UNSUPPORTED,OTG_TEMPO_4SEC); + } + } + } + else { + device_state = A_END_HNP_WAIT_VFALL; + } + } + else { + device_state = A_INIT_HNP; + } + } + else + { + TRACE_DEBUG("VID/PID does not match the Target Peripheral List\n\r"); + Otg_print_new_failure_message(OTGMSG_UNSUPPORTED,OTG_TEMPO_4SEC); + Set_user_request_disc(); // ask end of session now + Set_user_request_suspend(); + } + } + + } + else {// Can not get device descriptor + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_CONFIGURED : + // DEVICE_CONFIGURED state + // - Configure pipes for the supported interface + // - Send Set_configuration() request + // - Goto full operating mode (device ready) + TRACE_DEBUG("DEVICE_CONFIGURED\n\r"); + if (CONTROL_GOOD == host_get_configuration_descriptor()) { + if (HOST_FALSE != host_check_class()) { // Class support OK? + // Collect information about peripheral OTG descriptor if present + host_check_OTG_features(); + host_auto_configure_endpoint(); + + if (Is_host_configured()) { + if (CONTROL_GOOD== host_set_configuration(1)) { // Send Set_configuration + // host_set_interface(interface_bound,interface_bound_alt_set); + // device and host are now fully configured + // goto DEVICE READY normal operation + device_state = DEVICE_READY; + // monitor device disconnection under interrupt + Host_enable_device_disconnection_interrupt(); + // If user host application requires SOF interrupt event + // Keep SOF interrupt enable otherwize, disable this interrupt +#if (HOST_CONTINUOUS_SOF_INTERRUPT==DISABLE) + Host_disable_sof_interrupt(); +#endif + new_device_connected=TRUE; + TRACE_INFO("Device Enumerated\n\r"); + } + else { // Problem during Set_configuration request... + device_state = DEVICE_ERROR; + } + } + } + else { // device class not supported... + device_state = DEVICE_ERROR; + TRACE_INFO("Unsupported Device\n\r"); + Host_device_class_not_supported_action(); + } + } + else { // Can not get configuration descriptors... + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_READY : + // DEVICE_READY state + // - Full standard operating mode + // - Nothing to do... + // Host full std operating mode! + new_device_connected=FALSE; + + // Handles user requests : "stop Vbus" and "suspend" + if (Is_usb_id_host()) { + if (Is_user_requested_suspend() || Is_user_requested_hnp()) { + // Before entering suspend mode, A-Host must send a SetFeature(b_hnp_enable) if supported by the B-Periph + Ack_user_request_hnp(); + Ack_user_request_suspend(); + device_state = A_INIT_HNP; + } + } + break; + + case DEVICE_ERROR : + //------------------------------------------------------ + // DEVICE_ERROR state + // - Error state + // - Do custom action call (probably go to default mode...) + TRACE_DEBUG("DEVICE_ERROR\n\r"); + device_state=DEVICE_UNATTACHED; + Host_device_error_action(); + break; + + case DEVICE_SUSPENDED : + // DEVICE_SUSPENDED state + // - Host application request to suspend the device activity + // - State machine comes here thanks to Host_request_suspend() + TRACE_DEBUG("DEVICE_SUSPENDED\n\r"); + // If OTG device, initiate a HNP process (go to specific state) + if (Is_peripheral_otg_device()) { + device_state = A_INIT_HNP; + } + else { + device_state=DEVICE_WAIT_RESUME; // wait for device resume event + if(Is_device_supports_remote_wakeup()) { // If the connected device supports remote wake up + if (CONTROL_GOOD != host_set_feature_remote_wakeup()) { + device_state = DEVICE_DISCONNECTED; // stop connexion because device has not accepted the feature + } + } + TRACE_INFO("Usb suspend\n\r"); + hostSOFCounter = Is_host_sof_interrupt_enabled(); //Save current sof interrupt enable state + Host_disable_sof_interrupt(); + Host_ack_sof(); + Host_disable_sof(); // Stop start of frame generation, this generates the suspend state + Host_ack_remote_wakeup(); + Host_enable_remote_wakeup_interrupt(); + Host_ack_hwup(); + Host_enable_hwup_interrupt(); // Enable host wake-up interrupt + // (this is the unique USB interrupt able to wake up the CPU core from power-down mode) + Usb_freeze_clock(); + Host_suspend_action(); // Custom action here! (for example go to power-save mode...) + } + break; + + case DEVICE_WAIT_RESUME : + // DEVICE_WAIT_RESUME state + // - Wait in this state till the host receives an upstream resume from the device + // - or the host software request the device to resume + TRACE_DEBUG("DEVICE_WAIT_RESUME\n\r"); + if(Is_usb_event(EVT_HOST_REMOTE_WAKEUP)|| Is_host_request_resume()) { // Remote wake up has been detected + // or Local resume request has been received + if(Is_host_request_resume()) { // Not a remote wakeup, but an host application request + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + // CAUTION HWUP can be cleared only when USB clock is active + // Pll_start_auto(); // First Restart the PLL for USB operation + // Wait_pll_ready(); // Get sure pll is lock + Usb_unfreeze_clock(); // Enable clock on USB interface + } + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_enable_sof(); + + if (Is_usb_event(EVT_HOST_REMOTE_WAKEUP)) { + Usb_ack_event(EVT_HOST_REMOTE_WAKEUP); // Ack software event + Host_disable_sof_interrupt(); + Host_ack_device_disconnection(); + Host_disable_device_disconnection_interrupt(); + + Host_send_resume(); // this other downstream resume is done to ensure min. 20ms of HOST DRIVING RESUME (not Device) + while (!Is_device_disconnection() && Host_is_resume()); + hostSOFCounter = 0; + Host_ack_sof(); + while (!Is_device_disconnection() && (hostSOFCounter != 12)) { // wait for min. 10ms of device recovery time + if (Is_host_sof()) { + Host_ack_sof(); + hostSOFCounter++; + } + } + if (Is_device_disconnection()) { + usb_host_task_init(); + device_state = DEVICE_DISCONNECTED; + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + } + else { + device_state = DEVICE_READY; + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + } + Host_enable_device_disconnection_interrupt(); + Host_ack_sof(); + } + else { + Host_send_resume(); // Send down stream resume + //----------------------- + // Work-around for case of Device disconnection during Suspend + // The disconnection is never detected and the Resume bit remains high (and RSMEDI flag never set) + // If the timeout elapses, it implies that the device has disconnected => macro is reset (to reset the Resume bit) + dec = 0; + while (dec < 0x4FFFF) { // several hundreds of ms + if (Is_host_down_stream_resume()) { // Wait Down stream resume sent + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + if(hostSOFCounter) { + Host_enable_sof_interrupt(); + } // Restore SOF interrupt enable state before suspend + device_state=DEVICE_READY; // Come back to full operating mode + TRACE_INFO("Usb resumed\n\r"); + dec = 0x3FFFFE; // will cause a loop end + } + dec++; + } + if (dec != 0x3FFFFF) { // if resume failed + usb_host_task_init(); + device_state = DEVICE_DISCONNECTED; + } + else + { + hostSOFCounter = 0; + Host_ack_sof(); + while (!Is_device_disconnection() && (hostSOFCounter != 12)) { // wait for min. 10ms of device recovery time + if (Is_host_sof()) { + Host_ack_sof(); + hostSOFCounter++; + } + } + } + //-----------------------End of Work Around + } + } + break; + + case DEVICE_DISCONNECTED : + // DEVICE_DISCONNECTED state + // - Device disconnection has been detected + // - Run scheduler in this state at least two times to get sure event is detected by all host application tasks + // - Go to DEVICE_DISCONNECTED_ACK state before DEVICE_UNATTACHED, to get sure scheduler calls all app tasks... + TRACE_DEBUG("DEVICE_DISCONNECTED\n\r"); + device_state = DEVICE_DISCONNECTED_ACK; + break; + + case DEVICE_DISCONNECTED_ACK : + // DEVICE_DISCONNECTED_ACK state + // - Device disconnection has been detected and managed bu applicatives tasks + // - Go to DEVICE_UNATTACHED state + TRACE_DEBUG("DEVICE_DISCONNECTED_ACK\n\r"); + host_disable_all_pipe(); + device_state = DEVICE_UNATTACHED; + End_session_with_srp(); + Usb_ack_srp_interrupt(); + break; + + case A_PERIPHERAL: + // OTG Specific states : A_PERIPHERAL (A-Host has been turned into a Device after a HNP) + // - End session (and stop driving Vbus) when detecting suspend condition + // - Disconnect on user request + // - Call standard (non-OTG) device task to handle the Endpoint 0 requests + TRACE_DEBUG("A_PERIPHERAL\n\r"); + // End of role exchange : A_PERIPH go into DEVICE_DISCONNECTED mode : stop supplying VBUS + if (Is_usb_event(EVT_USB_SUSPEND)) { + Clear_all_user_request(); + Usb_ack_event(EVT_USB_SUSPEND); + Usb_disable_wake_up_interrupt(); + Usb_ack_role_exchange_interrupt(); + Usb_select_host(); + USBD_Connect();//Usb_attach(); + Usb_unfreeze_clock(); + b_uut_device_state = B_IDLE; + device_state = A_END_HNP_WAIT_VFALL; + Usb_ack_srp_interrupt(); + } + if (Is_user_requested_disc() || Is_user_requested_vbus()) { + Clear_all_user_request(); + Usb_disable_suspend_interrupt(); + Usb_ack_role_exchange_interrupt(); + Usb_select_host(); + Usb_unfreeze_clock(); + b_uut_device_state = B_IDLE; + device_state = A_END_HNP_WAIT_VFALL; + } + if (!Is_device_disconnection_event() && (device_state != A_END_HNP_WAIT_VFALL)) { + //usb_device_task(); + //MSDDriver_StateMachine(); + Scheduler_task_3(); + } + break; + + case A_INIT_HNP: + // OTG Specific states : A_INIT_HNP + // - Software enters this state when it has been requested to initiate a HNP + // - Handle "set feature" commands such as B_HNP_ENABLE or REMOTE_WAKE_UP + // - Handle failures + TRACE_DEBUG("A_INIT_HNP\n\r"); + Ack_user_request_hnp(); + Ack_user_request_suspend(); + if (Is_peripheral_otg_device() || !Is_host_configured()) { + device_state = A_SUSPEND; + if(Is_device_supports_remote_wakeup() && Is_host_configured()) { // If the connected device supports remote wake up + if (CONTROL_GOOD == host_set_feature_remote_wakeup()) { + Host_ack_remote_wakeup(); + Host_enable_remote_wakeup_interrupt(); + Host_ack_hwup(); + Host_enable_hwup_interrupt(); // Enable host wake-up interrupt + } + else { + device_state = A_END_HNP_WAIT_VFALL; // stop connection because device has STALLed the feature + } + } + if (Is_device_supports_hnp() || !Is_host_configured()) { + if (CONTROL_GOOD == host_set_feature_b_hnp_enable()) { + // B-Device has not STALLed the SetFeature + Usb_host_accept_hnp(); + Usb_ack_role_exchange_interrupt(); + Usb_ack_hnp_error_interrupt(); + Usb_enable_role_exchange_interrupt(); + Usb_enable_hnp_error_interrupt(); + Host_disable_device_disconnection_interrupt(); + Host_disable_device_connection_interrupt(); + } + else { + Otg_print_new_failure_message(OTGMSG_DEVICE_NO_RESP,OTG_TEMPO_4SEC); + device_state = A_END_HNP_WAIT_VFALL; + } + } + Host_ack_remote_wakeup(); + Host_enable_remote_wakeup_interrupt(); + Init_ta_aidl_bdis_counter(); + Host_disable_sof_interrupt(); + Host_ack_sof(); + Host_disable_sof(); // Stop start of frame generation, this generates the suspend state + Usb_disable_suspend_interrupt(); + } + else { + device_state = DEVICE_SUSPENDED; + } + break; + + case A_SUSPEND: + // OTG Specific states : A_SUSPEND + // - A-Host enters this state when it has requested the B-DEVICE to start HNP, and have entered Suspend mode + // - Detects device silences (with HNP time-out management) and Resume condition + TRACE_DEBUG("A_SUSPEND\n\r"); + Usb_ack_suspend(); + // HNP is managed by interrupt (HNPERRI/ROLEEXI) + if (Is_ta_aidl_bdis_counter_overflow()) { + device_state = A_END_HNP_WAIT_VFALL; // stop Vbus = end of current session + } + if (Is_usb_event(EVT_HOST_HWUP)|| Is_host_request_resume()) { + device_state = DEVICE_WAIT_RESUME; + } + break; + + case A_END_HNP_WAIT_VFALL: + // OTG Specific states : A_END_HNP_WAIT_VFALL + // - A-PERIPH enters this state when it has detected a Suspend from the B-Host + // - It stop Vbus delivery and waits line discharge (to avoid spurious SRP detection) + TRACE_DEBUG("A_END_HNP_WAIT_VFALL\n\r"); + Usb_disable_manual_vbus(); + Usb_disable_vbus(); + usb_configuration_nb = 0; + Host_vbus_action(); + Clear_all_user_request(); + device_state = DEVICE_DISCONNECTED; + usb_host_task_init(); + break; + + case A_TEMPO_VBUS_DISCHARGE: + // OTG Specific states : A_TEMPO_VBUS_DISCHARGE + // - State entered from A_END_HNP_WAIT_VFALL, when Vbus has just reached the vbus_valid threshold + // - In this state we wait long enough (50ms) to be sure that Vbus is not valid on the other device (if still connected) + // - When delay is elapsed, go to reset state + TRACE_DEBUG("A_TEMPO_VBUS_DISCHARGE\n\r"); + if (otg_end_hnp_vbus_delay == 0) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + Usb_ack_role_exchange_interrupt(); + Usb_ack_srp_interrupt(); + device_state = DEVICE_DISCONNECTED; + } + break; + + default : + // default state + // - Default case: ERROR + // - Goto no device state + TRACE_DEBUG("default\n\r"); + device_state = DEVICE_UNATTACHED; + break; + } +} + +//------------------------------------------------------------------------------ +/// This function send nb_data pointed with *buf with the pipe number specified +/// This function will activate the host sof interrupt to detect timeout. The +/// interrupt enable sof will be restore. +//------------------------------------------------------------------------------ +U8 host_send_data(U8 pipe, U16 nb_data, U8 *buf) +{ + U16 length; + U8 status=PIPE_GOOD; + U8 sav_int_sof_enable; + U8 nak_timeout; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + U16 cpt_nak; +#endif + U16 nb_data_loaded; + + TRACE_DEBUG("host_send_data[]%d: %d\n\r", pipe, nb_data); + + sav_int_sof_enable=Is_host_sof_interrupt_enabled(); // Save state of enable sof interrupt + Host_enable_sof_interrupt(); + Host_select_pipe(pipe); + + Host_set_token_in(); + + Host_set_token_out(); + Host_ack_out_sent(); + /* + TRACE_DEBUG("CTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_CTRL); + TRACE_DEBUG("SR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_SR); + TRACE_DEBUG("DEVCTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVCTRL); + TRACE_DEBUG("DEVISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVISR); + TRACE_DEBUG("DEVIMR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVIMR); + TRACE_DEBUG("DEVEPTISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[0]); + TRACE_DEBUG("HSTCTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTCTRL); + TRACE_DEBUG("HSTISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTISR); + TRACE_DEBUG("HSTIMR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTIMR); + TRACE_DEBUG("HSTPIP: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIP); + TRACE_DEBUG("HSTPIPCFG[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[0]); + TRACE_DEBUG("HSTPIPCFG[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[1]); + TRACE_DEBUG("HSTPIPCFG[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[2]); + TRACE_DEBUG("HSTPIPINRQ[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[0]); + TRACE_DEBUG("HSTPIPINRQ[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[1]); + TRACE_DEBUG("HSTPIPINRQ[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[2]); + TRACE_DEBUG("HSTPIPERR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[0]); + TRACE_DEBUG("HSTPIPERR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[1]); + TRACE_DEBUG("HSTPIPERR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[2]); + TRACE_DEBUG("HSTPIPISR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0]); + TRACE_DEBUG("HSTPIPISR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[1]); + TRACE_DEBUG("HSTPIPISR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[2]); + TRACE_DEBUG("HSTPIPIMR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[0]); + TRACE_DEBUG("HSTPIPIMR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[1]); + TRACE_DEBUG("HSTPIPIMR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[2]); + */ + while (nb_data != 0) { // While there is something to send... + Host_unfreeze_pipe(); + // Prepare data to be sent + length = host_get_pipe_length(); + TRACE_DEBUG("size=%d\n\r", length); + + if ( length > nb_data) { + nb_data_loaded = nb_data; + length = nb_data; + } + else { + nb_data_loaded = length; + } + Address_fifochar_endpoint(global_pipe_nb); + while (length!=0) { // Load Pipe buffer + Host_write_byte(*buf++); + //(((char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0))[dBytes++])=*(buf++); + //pFifo[dBytes++] = *buf; + //buf++; + length--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine +#if (NAK_TIMEOUT_ENABLE==ENABLE) + cpt_nak=0; +#endif + nak_timeout=0; + Host_ack_out_sent(); + Host_send_out(); + while (!Is_host_out_sent()) { + if (Is_host_emergency_exit()) { // Async disconnection or role change detected under interrupt + TRACE_DEBUG("Emergency exit\n\r"); + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + if (private_sof_counter>=250) { // Count 250ms (250sof) + TRACE_DEBUG("TimeOut Send Data\n\r"); + private_sof_counter=0; + if (nak_timeout++>=TIMEOUT_DELAY) { // Inc timeout and check for overflow + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + } + if (Is_host_pipe_error()) { // Any error ? + TRACE_DEBUG("pipe error\n\r"); + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_data_end; + } + if (Is_host_stall()) { // Stall management + TRACE_DEBUG("stall\n\r"); + status =PIPE_STALL; + Host_ack_stall(); + goto host_send_data_end; + } +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if(Is_host_nak_received()) { //NAK received + Host_ack_nak_received(); + if (cpt_nak++>NAK_SEND_TIMEOUT) { + TRACE_DEBUG("NAK timeout\n\r"); + status = PIPE_NAK_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + } +#endif + } + // Here OUT sent + nb_data -= nb_data_loaded; + status=PIPE_GOOD; // Frame correctly sent + Host_ack_out_sent(); + } + Host_freeze_pipe(); + +host_send_data_end: + // Restore sof interrupt enable state + if (sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + // And return... + return ((U8)status); +} + + + +//------------------------------------------------------------------------------ +/// This function receives nb_data pointed with *buf with the pipe number specified +/// The nb_data parameter is passed as a U16 pointer, thus the data pointed by this pointer +/// is updated with the final number of data byte received. +//------------------------------------------------------------------------------ +U8 host_get_data(U8 pipe, U16 *nb_data, U8 *buf) +{ + U8 status=PIPE_GOOD; + U8 sav_int_sof_enable; + U8 nak_timeout; + U16 n; + U16 i; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + U16 cpt_nak; +#endif + + // TRACE_DEBUG("host_get_data[%d]\n\r", pipe); + n=*nb_data; + *nb_data=0; + + sav_int_sof_enable=Is_host_sof_interrupt_enabled(); + Host_enable_sof_interrupt(); + + Host_select_pipe(pipe); + Host_set_token_in(); + Host_continuous_in_mode(); + // Host_ack_in_received(); + + while (n) { // While missing data... + // start IN request generation + Host_unfreeze_pipe(); + Host_send_in(); + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + nak_timeout=0; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + cpt_nak=0; +#endif + while (!Is_host_in_received()) + { + if (Is_host_emergency_exit()) // Async disconnection or role change detected under interrupt + { + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + if (private_sof_counter>=250) // Timeout management + { + private_sof_counter=0; // Done in host SOF interrupt + if (nak_timeout++>=TIMEOUT_DELAY)// Check for local timeout + { + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + } + if(Is_host_pipe_error()) // Error management + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_get_data_end; + } + if(Is_host_stall()) // STALL management + { + status =PIPE_STALL; + Host_reset_pipe(pipe); + Host_ack_stall(); + goto host_get_data_end; + } +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if(Is_host_nak_received()) //NAK received + { + Host_ack_nak_received(); + if (cpt_nak++>NAK_RECEIVE_TIMEOUT) + { + status = PIPE_NAK_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + } +#endif + } + status=PIPE_GOOD; + Host_freeze_pipe(); + if (Host_byte_counter()<=n) + { + if ((Host_byte_counter() < n)&&(Host_byte_counter() nb_data) // Pipe size> remaining data + { + i = nb_data; + nb_data = 0; + } + else // Pipe size < remaining data + { + nb_data -= i; + } + it_pipe_str[pipe].nb_byte_on_going+=i; // Update nb data processed + Address_fifochar_endpoint(global_pipe_nb); + while (i!=0) // Load Pipe buffer + { + Host_write_byte(*ptr_buf++); + i--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe].timeout=0; // Refresh timeout counter + Host_ack_out_sent(); + Host_ack_stall(); + Host_ack_nak_received(); + + Host_enable_stall_interrupt(); + Host_enable_error_interrupt(); +#if (NAK_TIMEOUT_ENABLE==ENABLE) + Host_enable_nak_interrupt(); +#endif + Host_enable_transmit_interrupt(); + Host_send_out(); // Send the USB frame + return HOST_TRUE; + } +} + +//------------------------------------------------------------------------------ +//! @brief USB pipe interrupt subroutine +//! +//! @param none +//! +//! @return none +//------------------------------------------------------------------------------ +void usb_pipe_interrupt(void) +{ + U8 pipe_nb; + U8 *ptr_buf; + void (*fct_handle)(U8 status,U16 nb_byte); + U16 n; + U8 i; + U8 do_call_back=FALSE; + + TRACE_DEBUG("usb_pipe_interrupt\n\r"); + + if(Host_get_pipe_interrupt()) { + + pipe_nb_save = Host_get_selected_pipe(); // Important! Save here working pipe number + pipe_nb=host_get_nb_pipe_interrupt(); // work with the correct pipe number that generates the interrupt + Host_select_pipe(pipe_nb); // Select this pipe + fct_handle=*(it_pipe_str[pipe_nb].handle); + + // Now try to detect what event generate an interrupt... + if (Is_host_pipe_error()) // Any error ? + { + TRACE_DEBUG("host_pipe_error\n\r"); + it_pipe_str[pipe_nb].status = Host_error_status(); + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + Host_ack_all_errors(); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + + if (Is_host_stall()) // Stall handshake received ? + { + TRACE_DEBUG("host_stall\n\r"); + it_pipe_str[pipe_nb].status=PIPE_STALL; + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if (Is_host_nak_received()) // NAK ? + { + Host_ack_nak_received(); + // check if number of NAK timeout error occurs (not for interrupt type pipe) + if((--it_pipe_str[pipe_nb].nak_timeout==0) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) + { + it_pipe_str[pipe_nb].status=PIPE_NAK_TIMEOUT; + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + } +#endif + + if (Is_host_in_received()) // Pipe IN reception ? + { + TRACE_DEBUG("host_in received\n\r"); + ptr_buf = it_pipe_str[pipe_nb].ptr_buf; + ptr_buf += it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer + n = it_pipe_str[pipe_nb].nb_byte_to_process; + n -= it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes + Host_freeze_pipe(); + if (Host_byte_counter()<=n) + { + if ((Host_byte_counter() < n)&&(Host_byte_counter()0) //still something to process + { + Host_unfreeze_pipe(); // Request another IN transfer + Host_send_in(); + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe_nb].timeout=0; // Reset timeout + it_pipe_str[pipe_nb].nak_timeout=NAK_RECEIVE_TIMEOUT; + } + else //end of transfer + { + it_pipe_str[pipe_nb].enable=DISABLE; + it_pipe_str[pipe_nb].status=PIPE_GOOD; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + } + } + + if(Is_host_out_sent()) // Pipe OUT sent ? + { + TRACE_DEBUG("host_out send\n\r"); + Host_ack_out_sent(); + it_pipe_str[pipe_nb].nb_byte_processed+=it_pipe_str[pipe_nb].nb_byte_on_going; + it_pipe_str[pipe_nb].nb_byte_on_going=0; + ptr_buf = it_pipe_str[pipe_nb].ptr_buf; + ptr_buf += it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer + n = it_pipe_str[pipe_nb].nb_byte_to_process; + n -= it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes + if(n>0) // Still data to process... + { + Host_unfreeze_pipe(); + // Prepare data to be sent + i = host_get_pipe_length(); + if ( i > n) // Pipe size> remaining data + { + i = n; + n = 0; + } + else // Pipe size < remaining data + { + n -= i; + } + it_pipe_str[pipe_nb].nb_byte_on_going+=i; // Update nb data processed + Address_fifochar_endpoint(global_pipe_nb); + while (i!=0) // Load Pipe buffer + { + Host_write_byte(*ptr_buf++); i--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe_nb].timeout=0; // Refresh timeout counter + it_pipe_str[pipe_nb].nak_timeout=NAK_SEND_TIMEOUT; + Host_send_out(); // Send the USB frame + } + else //n==0 Transfer is finished + { + it_pipe_str[pipe_nb].enable=DISABLE; // Tranfer end + it_pipe_str[pipe_nb].status=PIPE_GOOD; // Status OK + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + } + } + +usb_pipe_interrupt_end: + Host_select_pipe(pipe_nb_save); // Restore pipe number !!!! + if (is_any_interrupt_pipe_active()==FALSE) // If no more transfer is armed + { + if (g_sav_int_sof_enable==FALSE) + { + Host_disable_sof_interrupt(); + } + } + if(do_call_back) // Any callback functions to perform ? + { + fct_handle(it_pipe_str[pipe_nb].status,it_pipe_str[pipe_nb].nb_byte_processed); + } + + } + +} + + + diff --git a/usb/otg/usb_task.c b/usb/otg/usb_task.c new file mode 100644 index 0000000..043879f --- /dev/null +++ b/usb/otg/usb_task.c @@ -0,0 +1,999 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + + + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "main.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "otg_user_task.h" +#include "usb_task.h" +#include "usb/otg/usb_drv.h" + +#if ((USB_HOST_FEATURE == ENABLE)) + #include "usb/otg/usb_host_task.h" +#endif + +#if ((USB_DEVICE_FEATURE == ENABLE)) +#include +#include +#include +#include +#include +#include +#include +#endif + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + + + +extern volatile unsigned int timer_set_counter; +#define Timer16_select(...) +#define Timer16_set_counter(value) timer_set_counter = value +#define Timer16_get_counter_low() (unsigned char)timer_set_counter + + +/// Returns the OTG features sent by the host by a SetFeature +/// Allow also to clear the features (only on a bus Reset or Session End) +#define Is_host_requested_hnp() (((otg_features_supported&USBFeatureRequest_OTG_B_HNP_ENABLE) != 0) ? TRUE : FALSE) +#define Clear_otg_features_from_host() (otg_features_supported = 0) + +#define Set_otg_custom_timer(ep) // STUB: todo + +#define USB_MODE_UNDEFINED 0x00 +#define USB_MODE_HOST 0x01 +#define USB_MODE_DEVICE 0x02 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +U8 otg_device_sessions; +U8 b_uut_device_state; +U16 otg_tb_srp_cpt; + +/// usb_connected is used to store USB events detected upon +/// USB general interrupt subroutine +/// Its value is managed by the following macros (See usb_task.h file) +/// Usb_send_event(x) +/// Usb_ack_event(x) +/// Usb_clear_all_event() +/// Is_usb_event(x) +/// Is_not_usb_event(x) +volatile U16 g_usb_event=0; + + +#if (USB_DEVICE_FEATURE == ENABLE) +/// +/// Public : (bit) usb_connected +/// usb_connected is set to TRUE when VBUS has been detected +/// usb_connected is set to FALSE otherwise +/// Used with USB_DEVICE_FEATURE == ENABLE only +//// +bit usb_connected; + +/// +/// Public : (U8) usb_configuration_nb +/// Store the number of the USB configuration used by the USB device +/// when its value is different from zero, it means the device mode is enumerated +/// Used with USB_DEVICE_FEATURE == ENABLE only +//// +U8 usb_configuration_nb; + +/// +/// Public : (U8) remote_wakeup_feature +/// Store a host request for remote wake up (set feature received) +//// +U8 remote_wakeup_feature; +#endif + + +#if (USB_HOST_FEATURE == ENABLE) +/// +/// Private : (U8) private_sof_counter +/// Incremented by host SOF interrupt subroutime +/// This counter is used to detect timeout in host requests. +/// It must not be modified by the user application tasks. +//// +volatile U8 private_sof_counter=0; + +extern volatile S_pipe_int it_pipe_str[MAX_EP_NB]; + +#endif + +#if ((USB_DEVICE_FEATURE == ENABLE)&& (USB_HOST_FEATURE == ENABLE)) +/// +/// Public : (U8) g_usb_mode +/// Used in dual role application (both device/host) to store +/// the current mode the usb controller is operating +//// + U8 g_usb_mode=USB_MODE_UNDEFINED; + U8 g_old_usb_mode; +#endif + + +#if (USB_OTG_FEATURE == ENABLE) + /// + /// Public : (U8) otg_features_supported; + /// -> A-Device side : indicates if the B-Device supports HNP and SRP (this is the bmAttributes field of OTG Decriptor) + /// -> B-Device side : indicates if the A-Device has enabled the "a_hnp_support" and "b_hnp_enable" features + volatile U8 otg_features_supported; + + /// Public : (U8) otg_user_request; + /// Store the last request of the user (see usb_device_task.h) + U8 otg_user_request; + + /// Public : (U16) otg_msg_event_delay; + /// Contains the current display duration of the OTG event message + U16 otg_msg_event_delay; + + /// Public : (U16) otg_msg_failure_delay; + /// Contains the current display duration of the OTG failure message + U16 otg_msg_failure_delay; + + /// Public : (U16) g_otg_event; + /// Contains several bits corresponding to differents OTG events (similar to g_usb_event) + volatile U16 g_otg_event; + + /// Public : (U8) otg_device_nb_hnp_retry; + /// Counts the number of times a HNP fails, before aborting the operations + U8 otg_device_nb_hnp_retry; + + U8 id_changed_to_host_event; + + volatile U8 otg_last_sof_received; // last SOF received in SOF interrupt + volatile U8 otg_last_sof_stored; // last SOF value stored in OTG Timer interrupt + volatile U8 reset_received; // indicates if a reset has been received from B-Host after a HNP (used in A-Periph mode) + + /// @brief VBUS Overload management + /// + /// Nothing to do ! If the condition is not defined in the board driver file + /// (i.e. if the board does not support Vbus overcurrent detection), + /// the macro is defined to false for firmware compatibility +#define Is_vbus_overcurrent() (FALSE) + + /// Private function prototypes + /// Tasks for OTG Messaging features + void Otg_message_task_init(void); + void Otg_message_task(void); +#endif + + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the USB process +/// Depending on the mode supported (HOST/DEVICE/DUAL_ROLE) the function calls +/// the coresponding USB mode initialization function +//------------------------------------------------------------------------------ +void usb_task_init(void) +{ + +// ---- DUAL ROLE DEVICE USB MODE --------------------------------------------- +#if (USB_OTG_FEATURE == ENABLE) + Otg_message_task_init(); // OTG program needs to display event messages to the user + b_uut_device_state = B_IDLE; // init state machines variables +#if (USB_HOST_FEATURE == ENABLE) + device_state = DEVICE_UNATTACHED; +#endif + otg_device_nb_hnp_retry = BDEV_HNP_NB_RETRY; + Clear_all_user_request(); +#endif + +#if (((USB_DEVICE_FEATURE == ENABLE) && (USB_HOST_FEATURE == ENABLE)) || (USB_OTG_FEATURE == ENABLE)) +#if (USB_OTG_FEATURE == ENABLE) + Usb_enable_uid_pin(); +#endif + + // delay=PORTA; + g_usb_mode=USB_MODE_UNDEFINED; + + if(Is_usb_id_device()) + { + g_usb_mode=USB_MODE_DEVICE; + //usb_device_task_init(); + MSDDriver_Initialize(luns, numMedias); + +#if (USB_OTG_FEATURE == ENABLE) + id_changed_to_host_event = DISABLE; +#endif + } + else + { + Usb_send_event(EVT_USB_HOST_FUNCTION); + g_usb_mode=USB_MODE_HOST; + Usb_ack_id_transition(); // REQUIRED !!! Startup with ID=0, Ack ID pin transistion (default hwd start up is device mode) + Usb_enable_id_interrupt(); + usb_host_task_init(); +#if (USB_OTG_FEATURE == ENABLE) + id_changed_to_host_event = ENABLE; +#endif + } +#if ((USB_DEVICE_FEATURE == ENABLE)&& (USB_HOST_FEATURE == ENABLE)) + g_old_usb_mode = g_usb_mode; // Store current usb mode, for mode change detection +#endif + // ------------------------------------------------------------------------- + + // ---- DEVICE ONLY USB MODE ----------------------------------------------- +#elif ((USB_DEVICE_FEATURE == ENABLE)&& (USB_HOST_FEATURE == DISABLE)) + //jcbUsb_force_device_mode(); + //usb_device_task_init(); + MSDDriver_Initialize(luns, numMedias); + // ------------------------------------------------------------------------- + + // ---- REDUCED HOST ONLY USB MODE ----------------------------------------- +#elif ((USB_DEVICE_FEATURE == DISABLE)&& (USB_HOST_FEATURE == ENABLE)) + //jcbUsb_force_host_mode(); + usb_host_task_init(); +#elif ((USB_DEVICE_FEATURE == DISABLE)&& (USB_HOST_FEATURE == DISABLE)) +#error at least one of USB_DEVICE_FEATURE or USB_HOST_FEATURE should be enabled +#endif + // ------------------------------------------------------------------------- + +} + + +//------------------------------------------------------------------------------ +/// Entry point of the USB mamnagement +/// Depending on the USB mode supported (HOST/DEVICE/DUAL_ROLE) the function +/// calls the coresponding USB management function +//------------------------------------------------------------------------------ +void usb_task(void) +{ + // ---- DUAL ROLE DEVICE USB MODE --------------------------------------------- +#if ((USB_DEVICE_FEATURE == ENABLE) && (USB_HOST_FEATURE == ENABLE)) + if(Is_usb_id_device()) { + g_usb_mode = USB_MODE_DEVICE; + } + else { + g_usb_mode = USB_MODE_HOST; + } + g_old_usb_mode = g_usb_mode; // Store current usb mode, for mode change detection + // Depending on current usb mode, launch the correct usb task (device or host) + +#if (USB_OTG_FEATURE == ENABLE) + // Configure OTG timers + Set_otg_custom_timer(VBUSRISE_70MS); + Set_otg_custom_timer(VBUSPULSE_40MS); + Set_otg_custom_timer(VFALLTMOUT_131MS); + Set_otg_custom_timer(SRPMINDET_100US); +#endif + + switch(g_usb_mode) { + case USB_MODE_DEVICE: + //usb_device_task(); + MSDDriver_StateMachine(); + break; + + case USB_MODE_HOST: + if( pOTGDescriptor.bOTGADevSRPReaction == VBUS_PULSE) { + Usb_select_vbus_srp_method(); + } + else { + Usb_select_data_srp_method(); + } + usb_host_task(); + // Handle Vbus overcurrent error (auto-disabled if not supported or not defined in board driver file) +#if (USB_OTG_FEATURE == ENABLE) + if (Is_vbus_overcurrent()) { + Otg_print_new_event_message(OTGMSG_VBUS_SURCHARGE,OTG_TEMPO_3SEC); + } +#endif + break; + + case USB_MODE_UNDEFINED: // No break ! + default: + break; + } + // ------------------------------------------------------------------------- + // ---- DEVICE ONLY USB MODE ----------------------------------------------- +#elif ((USB_DEVICE_FEATURE == ENABLE)&& (USB_HOST_FEATURE == DISABLE)) + //usb_device_task(); + MSDDriver_StateMachine(); + // ------------------------------------------------------------------------- + + // ---- REDUCED HOST ONLY USB MODE ----------------------------------------- +#elif ((USB_DEVICE_FEATURE == DISABLE)&& (USB_HOST_FEATURE == ENABLE)) + usb_host_task(); + // ------------------------------------------------------------------------- + + /// ---- ERROR, NO MODE ENABLE --------------------------------------------- +#elif ((USB_DEVICE_FEATURE == DISABLE)&& (USB_HOST_FEATURE == DISABLE)) +#error at least one of USB_DEVICE_FEATURE or USB_HOST_FEATURE should be enabled +#error otherwise the usb task has nothing to do ... +#endif + // ------------------------------------------------------------------------- + +#if (USB_OTG_FEATURE == ENABLE) + Otg_message_task(); +#endif +} + + + +//------------------------------------------------------------------------------ +/// USB interrupt subroutine +/// +/// This function is called each time a USB interrupt occurs. +/// The following USB DEVICE events are taken in charge: +/// - VBus On / Off +/// - Start Of Frame +/// - Suspend +/// - Wake-Up +/// - Resume +/// - Reset +/// - Start of frame +/// +/// The following USB HOST events are taken in charge: +/// - Device connection +/// - Device Disconnection +/// - Start Of Frame +/// - ID pin change +/// - SOF (or Keep alive in low speed) sent +/// - Wake up on USB line detected +/// +/// The following USB HOST events are taken in charge: +/// - HNP success (Role Exchange) +/// - HNP failure (HNP Error) +/// +/// For each event, the user can launch an action by completing +/// the associate define (See conf_usb.h file to add action upon events) +/// +/// Note: Only interrupts events that are enabled are processed +//------------------------------------------------------------------------------ +void usb_general_interrupt(void) +{ + U8 i; + U8 save_pipe_nb; + + // ---------- DEVICE events management ----------------------------------- + // ----------------------------------------------------------------------- +#if ((USB_DEVICE_FEATURE == ENABLE) || (USB_OTG_FEATURE == ENABLE)) + + //- VBUS state detection + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled() + && Is_usb_id_device()) { + Usb_ack_vbus_transition(); + + if (Is_usb_vbus_high()) { + usb_connected = TRUE; + Usb_vbus_on_action(); + Usb_send_event(EVT_USB_POWERED); + //jcb Usb_enable_reset_interrupt(); + //usb_start_device(); + USBD_Connect();//Usb_attach(); + } + else { + TRACE_DEBUG("VBUS low\n\r"); + USBD_Disconnect(); +#if (USB_OTG_FEATURE == ENABLE) + Usb_device_stop_hnp(); + TRACE_DEBUG("Usb_select_device4\n\r"); + Usb_select_device(); + Clear_all_user_request(); +#endif + Usb_vbus_off_action(); + usb_connected = FALSE; + usb_configuration_nb = 0; + Usb_send_event(EVT_USB_UNPOWERED); + } + + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Device start of frame received + if (Is_usb_sof() && Is_sof_interrupt_enabled()) { + // TRACE_DEBUG_WP("F"); // device + Usb_ack_sof(); + Usb_sof_action(); +#if (USB_OTG_FEATURE == ENABLE) + //sof_seen_in_session = TRUE; + otg_last_sof_received = UDFNUML; // store last frame number received +#endif + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Device Suspend event (no more USB activity detected) + if (Is_usb_suspend()) { //&& Is_suspend_interrupt_enabled()) { + //TRACE_DEBUG_WP("D\n\r"); +#if (USB_OTG_FEATURE == ENABLE) + // 1st : B-PERIPH mode ? + if (Is_usb_id_device()) { + // HNP Handler + TRACE_DEBUG("HNP Handler\n\r"); + //TRACE_DEBUG("device_state = %d\n\r", device_state); + //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + if (Is_host_requested_hnp() // "b_hnp_enable" feature received + && (Is_session_started_with_srp() || Is_user_requested_hnp() { + if (otg_device_nb_hnp_retry == 0) { + otg_features_supported &= ~USBFeatureRequest_OTG_B_HNP_ENABLE; + } + else { + Ack_user_request_hnp(); + Usb_ack_hnp_error_interrupt(); + Usb_ack_role_exchange_interrupt(); + Usb_enable_role_exchange_interrupt(); + Usb_enable_hnp_error_interrupt(); + Usb_device_initiate_hnp(); + otg_device_nb_hnp_retry--; + } + } + else + { + // Remote wake-up handler + //TRACE_DEBUG("Remote wake-up handler\n\r"); + //TRACE_DEBUG("device_state = %d\n\r", device_state); + //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + if ((remote_wakeup_feature == ENABLE) && (usb_configuration_nb != 0)) + { + //TRACE_DEBUG("enabled\n\r"); + // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up + // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume + // So the SUSPE enable bit must be cleared to avoid redundant interrupt + // **************** + // Please note also that is Vbus is lost during an upstream resume (Host disconnection), + // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent) + // remains set after the event, so that a good way to handle this feature is : + // Usb_initiate_remote_wake_up(); + // while (Is_usb_pending_remote_wake_up()) + // { + // if (Is_usb_vbus_low()) + // { + // // Emergency action (reset macro, etc.) if Vbus lost during resuming + // break; + // } + // } + // Usb_ack_remote_wake_up_start(); + // **************** + } + else { + //TRACE_DEBUG("disabled: %d %d\n\r", usb_configuration_nb, remote_wakeup_feature); + // No remote wake-up supported + Usb_send_event(EVT_USB_SUSPEND); + } + } + } + else + { + //TRACE_DEBUG("ici\n\r"); + // A-PERIPH mode (will cause a session end, handled in usb_host_task.c) + Usb_send_event(EVT_USB_SUSPEND); + Usb_suspend_action(); + //jcb Usb_ack_suspend(); + } +#else + // Remote wake-up handler + if ((remote_wakeup_feature == ENABLE) && (usb_configuration_nb != 0)) { + TRACE_DEBUG("Remote wake-up handler\n\r"); + Usb_disable_suspend_interrupt(); + Usb_ack_wake_up(); + Usb_enable_wake_up_interrupt(); + Usb_suspend_action(); + Usb_freeze_clock(); + // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up + // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume + // So the SUSPE enable bit must be cleared to avoid redundant interrupt + // **************** + // Please note also that is Vbus is lost during an upstream resume (Host disconnection), + // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent) + // remains set after the event, so that a good way to handle this feature is : + // Usb_unfreeze_clock(); + // Usb_initiate_remote_wake_up(); + // while (Is_usb_pending_remote_wake_up()) + // { + // if (Is_usb_vbus_low()) + // { + // // Emergency action (reset macro, etc.) if Vbus lost during resuming + // break; + // } + // } + // Usb_ack_remote_wake_up_start(); + // **************** + } + else { + // No remote wake-up supported + Usb_send_event(EVT_USB_SUSPEND); + Usb_suspend_action(); + Usb_ack_suspend(); + Usb_ack_wake_up(); // clear wake up to detect next event + Usb_enable_wake_up_interrupt(); + Usb_freeze_clock(); + } +#endif + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Wake up event (USB activity detected): Used to resume + if (Is_usb_wake_up() && Is_swake_up_interrupt_enabled()) { + TRACE_DEBUG("W\n\r"); + Usb_unfreeze_clock(); + Usb_send_event(EVT_USB_WAKE_UP); + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Resume state bus detection + if (Is_usb_resume() && Is_resume_interrupt_enabled()) { + TRACE_DEBUG("Resume state bus detect\n\r"); + Usb_send_event(EVT_USB_RESUME); + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - USB bus reset detection + if (Is_usb_reset()&& Is_reset_interrupt_enabled()) { + TRACE_DEBUG_WP("B\n\r"); +#if (USB_OTG_FEATURE == ENABLE) + if (Is_usb_id_host()) { + //TRACE_DEBUG_WP("id_host\n\r"); + dev_configure_endpoint(EP_CONTROL, + TYPE_CONTROL, + DIRECTION_OUT, + SIZE_64, + ONE_BANK, + NYET_DISABLED); + } + // First initialization is important to be synchronized + // A reset must first have been received + if (device_state == A_PERIPHERAL) { + //TRACE_DEBUG_WP("r A_PERIPHERAL\n\r"); + otg_last_sof_received = UDFNUML; + otg_last_sof_stored = UDFNUML; + Usb_ack_sof(); + Usb_enable_sof_interrupt(); + reset_received = TRUE; + Timer16_set_counter(0); + } +#endif + Usb_reset_action(); + Usb_send_event(EVT_USB_RESET); + } + + // ---------- OTG events management ------------------------------------ + // --------------------------------------------------------------------- +#if (USB_OTG_FEATURE == ENABLE) && (USB_HOST_FEATURE == ENABLE) + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - OTG HNP Success detection + if (Is_usb_role_exchange_interrupt() && Is_role_exchange_interrupt_enabled()) { + // TRACE_DEBUG("OTG HNP detect\n\r"); + Usb_ack_role_exchange_interrupt(); + Host_ack_device_connection(); + Host_ack_device_disconnection(); + Otg_send_event(EVT_OTG_HNP_SUCCESS); + End_session_with_srp(); + Clear_otg_features_from_host(); + if (Is_usb_id_host()) { + // HOST (A- or B-) mode + if ((device_state != A_PERIPHERAL) && (device_state != A_END_HNP_WAIT_VFALL)) { + static volatile unsigned int jcb; + // Current mode is A-HOST, device will take the A-PERIPHERAL role + b_uut_device_state = B_PERIPHERAL; + device_state = A_PERIPHERAL; + usb_connected = FALSE; + usb_configuration_nb = 0; + Usb_select_device(); + USBD_Connect();//Usb_attach(); + Usb_unfreeze_clock(); + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Usb_device_stop_hnp(); + Usb_ack_reset(); + Timer16_set_counter(0); + Usb_freeze_clock(); // USB clock can be freezed to slow down events and condition detection + //jcb while (Timer16_get_counter_low() != 20); + jcb=0; + while( jcb <100000){ jcb++; } + + Usb_unfreeze_clock(); + reset_received = FALSE; + Usb_disable_sof_interrupt(); // will be set in the next OTG Timer IT (mandatory) + + Usb_enable_suspend_interrupt(); + Usb_enable_reset_interrupt(); + dev_configure_endpoint(EP_CONTROL, + TYPE_CONTROL, + DIRECTION_OUT, + SIZE_64, + ONE_BANK, + NYET_DISABLED); + } + } + else { + // In B_HOST mode, the HNPREQ bit must not be cleared because it releases the bus in suspend mode (and sof can't start) + if ((b_uut_device_state != B_HOST) && (b_uut_device_state != B_END_HNP_SUSPEND)) { + static volatile unsigned int jcb2; + // Current mode is B-PERIPHERAL, device will go into B-HOST role + End_session_with_srp(); + Clear_otg_features_from_host(); + b_uut_device_state = B_HOST; + device_state = DEVICE_ATTACHED; + usb_connected = FALSE; + usb_configuration_nb = 0; + TRACE_DEBUG("Select host 3\n\r"); + Usb_select_host(); + + TRACE_DEBUG("Send reset\n\r"); + Host_send_reset(); // send the first RESET + while (Host_is_reset()); + TRACE_DEBUG("Reset passed\n\r"); + + jcb2=0; + while( jcb2 <1000000){ jcb2++; } + Host_enable_sof(); // start Host (sof) + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Clear_all_user_request(); + + TRACE_DEBUG("Select host 3\n\r"); + } + } + } + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - OTG HNP Failure detection + if (Is_usb_hnp() && Is_usb_hnp_error_interrupt()&& Is_hnp_error_interrupt_enabled()) { + TRACE_DEBUG("OTG HNP failure\n\r"); + Usb_device_stop_hnp(); + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Usb_ack_hnp_error_interrupt(); + if (Is_usb_id_device()) { + Otg_send_event(EVT_OTG_HNP_ERROR); + Clear_all_user_request(); + } + } +#endif +#endif// End DEVICE FEATURE MODE && USB_HOST_FEATURE + + // ---------- HOST events management ----------------------------------- + // --------------------------------------------------------------------- +#if (((USB_HOST_FEATURE == ENABLE) && (USB_DEVICE_FEATURE == ENABLE)) || (USB_OTG_FEATURE == ENABLE)) + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - ID pin change detection + if(Is_usb_id_transition()&&Is_usb_id_interrupt_enabled()) { + TRACE_DEBUG("ID pin change\n\r"); + TRACE_DEBUG("device_state = %d\n\r", device_state); + TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + Usb_device_stop_hnp(); +#if (USB_OTG_FEATURE == ENABLE) + Clear_all_user_request(); +#endif + if(Is_usb_id_device()) { + g_usb_mode = USB_MODE_DEVICE; + } + else { + g_usb_mode = USB_MODE_HOST; + } + Usb_ack_id_transition(); + if( g_usb_mode != g_old_usb_mode) { // Basic Debounce + if(Is_usb_id_device()) { // Going into device mode + Usb_send_event(EVT_USB_DEVICE_FUNCTION); +#if (USB_OTG_FEATURE == ENABLE) + b_uut_device_state = B_IDLE; +#endif + device_state = DEVICE_UNATTACHED; +#if (USB_OTG_FEATURE == ENABLE) + id_changed_to_host_event = DISABLE; +#endif + } + else { // Going into host mode +#if (USB_OTG_FEATURE == ENABLE) + b_uut_device_state = B_IDLE; +#endif + device_state = DEVICE_UNATTACHED; + Usb_send_event(EVT_USB_HOST_FUNCTION); +#if (USB_OTG_FEATURE == ENABLE) + id_changed_to_host_event = ENABLE; +#endif + } + Usb_id_transition_action(); + TRACE_INFO("Pin Id changed\n\r"); +#if ( ID_PIN_CHANGE_GENERATE_RESET == ENABLE) + // Hot ID transition generates wdt reset +#endif + } + } + +#endif +#if ((USB_HOST_FEATURE == ENABLE) || (USB_OTG_FEATURE == ENABLE)) + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - The device has been disconnected + // JCB to be fix + if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { + TRACE_DEBUG("device disconnect\n\r"); + host_disable_all_pipe(); + Host_ack_device_disconnection(); + device_state=DEVICE_DISCONNECTED; + Usb_send_event(EVT_HOST_DISCONNECTION); + TRACE_INFO("Device disconnected\n\r"); + Host_device_disconnection_action(); +#if (USB_OTG_FEATURE == ENABLE) + Clear_all_user_request(); +#endif + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Device connection + if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { + TRACE_DEBUG("device connect\n\r"); + Host_ack_device_connection(); + host_disable_all_pipe(); + Host_device_connection_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Start of frame has been sent + if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { + //TRACE_DEBUG_WP("_"); // host + Host_ack_sof(); + Usb_send_event(EVT_HOST_SOF); + private_sof_counter++; + + // delay timeout management for interrupt tranfer mode in host mode + if (private_sof_counter>=250) { // Count 1/4 sec + private_sof_counter=0; + for(i=0;iTIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { + it_pipe_str[i].enable=DISABLE; + it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; + Host_stop_pipe_interrupt(i); + if (is_any_interrupt_pipe_active()==FALSE) { // If no more transfer is armed + if (g_sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + } + it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); + } + Host_select_pipe(save_pipe_nb); + } + } + } + Host_sof_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Wake-up has been received + if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { + TRACE_DEBUG("Host wake up\n\r"); + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + Host_disable_remote_wakeup_interrupt(); + // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_ack_remote_wakeup(); + Usb_send_event(EVT_HOST_HWUP); // Send software event + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Host_hwup_action(); // Map custom action +#if (USB_OTG_FEATURE == ENABLE) + if (Is_usb_hnp()) { + Usb_host_reject_hnp(); + Usb_disable_hnp_error_interrupt(); + Usb_disable_role_exchange_interrupt(); + } +#endif + Host_send_resume(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // Remote Wake Up has been received + if (Is_host_remote_wakeup_interrupt_enabled() && Is_host_remote_wakeup()) { + TRACE_DEBUG("Remote wake up\n\r"); + Host_disable_remote_wakeup_interrupt(); + Host_disable_hwup_interrupt(); + Host_ack_remote_wakeup(); + Host_ack_hwup(); // Clear HWUP interrupt flag + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Usb_send_event(EVT_HOST_HWUP); // Send software event +#if (USB_OTG_FEATURE == ENABLE) + if (Is_usb_hnp()) { + Usb_host_reject_hnp(); + Usb_disable_hnp_error_interrupt(); + Usb_disable_role_exchange_interrupt(); + } +#endif + Host_send_resume(); + } +#endif // End HOST FEATURE MODE +} + + +#if (USB_OTG_FEATURE == ENABLE) + +//------------------------------------------------------------------------------ +/// OTG TIMER interrupt subroutine +/// This function is called each time a OTG Timer interrupt occurs +/// Function decrements the variables required by OTG program +void otg_timer_interrupt(void) +{ + /// OTG Messaging timer + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) + || (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_FAIL)) { + if ((Get_failure_msg_delay() != 0x0000) && (Get_failure_msg_delay() != 0xFFFF)) { + Decrement_failure_msg_delay(); + } + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) { + if ((Get_event_msg_delay() != 0x0000) && (Get_event_msg_delay() != 0xFFFF)) { + Decrement_event_msg_delay(); + } + } + } + /// Increments Tb_Srp counter if needed + if (Is_srp_sent_and_waiting_answer()) { + otg_tb_srp_cpt++; + } + /// Increments T_vbus_wait_connect if needed + if (Is_srp_received_and_waiting_connect()) { + otg_ta_srp_wait_connect++; + } + /// Decrements Ta_aidl_bdis timer if needed (A_suspend state) + if ((device_state == A_SUSPEND) && (otg_ta_aidl_bdis_tmr > 1)) { + otg_ta_aidl_bdis_tmr--; + } + /// Decrements Timeout_bdev_respond timer if needed + if ((device_state == DEVICE_DEFAULT) && (!Is_timeout_bdev_response_overflow())) { + otg_timeout_bdev_respond--; + } + /// Decrements Ta_vbus_rise timer if needed + if (!Is_ta_vbus_rise_counter_overflow()) { + otg_ta_vbus_rise--; + } + /// Decrements Ta_vbus_fall timer if needed + if (!Is_ta_vbus_fall_counter_overflow()) { + otg_end_hnp_vbus_delay--; + } + + /// Needed for compliance only + if (device_state == A_PERIPHERAL) { + if (Is_sof_interrupt_enabled() && (reset_received == TRUE)) { + if (otg_last_sof_stored != otg_last_sof_received) { + // No SOF is missing + otg_last_sof_received = otg_last_sof_stored; + } + else { + // SOF seems to be missing.. + Usb_freeze_clock(); + Usb_disable_sof_interrupt(); + reset_received = FALSE; + //jcb while (Timer16_get_counter_low() != 20); // overflow set to 62 in usb_task.h + Usb_unfreeze_clock(); + } + otg_last_sof_received = UDFNUML; + otg_last_sof_stored = UDFNUML; + } + } +} + + +//------------------------------------------------------------------------------ +/// OTG Messaging task initialization +/// Initializes variables and screen to prepare next messages to be handled +//------------------------------------------------------------------------------ +void Otg_message_task_init(void) +{ + TRACE_DEBUG("Otg_message_task_init\n\r"); + Otg_messaging_init(); + otg_msg_event_delay = 0; + otg_msg_failure_delay = 0; +} + + +//------------------------------------------------------------------------------ +/// OTG Messaging main task +/// OTG specifies that user must be kept informed of several events +/// This task allows user to display two kinds of messages : EVENT or FAILURE +/// For each new message, it can specify if the message remains displayed all +/// the time or only during a specified delay +//------------------------------------------------------------------------------ +void Otg_message_task(void) +{ + // Check if an OTG message must be erased (if it was set up for a specified delay) + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) + || (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_FAIL)) { + if (Get_failure_msg_delay() == 0) { + Otg_clear_failure_message(); + } + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) { + if (Get_event_msg_delay() == 0) { + Otg_clear_event_message(); + } + } + } +} +#endif // #if (USB_OTG_FEATURE == ENABLE) + + +//------------------------------------------------------------------------------ +/// Message "OTG not supported" +//------------------------------------------------------------------------------ +void otg_not_supported_device(void) +{ + TRACE_DEBUG("otg_not_supported_device\n\r"); + Otg_send_event(EVT_OTG_DEV_UNSUPPORTED); +} + + diff --git a/usb/otg/usb_task.h b/usb/otg/usb_task.h new file mode 100644 index 0000000..0ad2529 --- /dev/null +++ b/usb/otg/usb_task.h @@ -0,0 +1,232 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + + +//! @brief This file manages the USB task either device/host or both. +//! +//! The USB task selects the correct USB task (usb_device task or usb_host task +//! to be executed depending on the current mode available. +//! +//! This module also contains the general USB interrupt subroutine. This subroutine is used +//! to detect asynchronous USB events. +//! +//! Note: +//! - The usb_task belongs to the scheduler, the usb_device_task and usb_host do not, they are called +//! from the general usb_task +//! - See conf_usb.h file for more details about the configuration of this module + +#ifndef _USB_TASK_H_ +#define _USB_TASK_H_ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Definitions of B-Device states +#define B_IDLE 0 +//#define B_SRP_INIT 1 +#define B_PERIPHERAL 2 +//#define B_WAIT_ACON 3 +#define B_HOST 4 +#define B_END_HNP_SUSPEND 5 + +// OTG B-Device SRP protocole specific states or events + +//! Is the current session a result of a SRP ? +//#define Start_session_with_srp() (otg_device_sessions |= 0x01) +#define End_session_with_srp() (otg_device_sessions &= ~0x01) +#define Is_session_started_with_srp() (((otg_device_sessions&0x01) != 0) ? TRUE : FALSE) + +//! Has a SRP been sent, and waiting for an answer +//#define Srp_sent_and_waiting_answer() (otg_device_sessions |= 0x02) +//#define Ack_srp_sent_and_answer() (otg_device_sessions &= ~0x02) +#define Is_srp_sent_and_waiting_answer() (((otg_device_sessions&0x02) != 0) ? TRUE : FALSE) + +//! Is the Tb_Srp counter enabled ? Cleared by timer if Tb_Srp_Fail elapsed +//! Tb_Srp_Fail must be between 5 and 6 sec. With an interrupt routine executed each 2ms, its value becomes 2500 (used:5.2sec) +// 0x0A28 = 2600, 2600x2 = 5200 => 5s +//#define TB_SRP_FAIL_MIN 0x0A28 +//extern U16 otg_tb_srp_cpt; +//#define Init_tb_srp_counter() (otg_tb_srp_cpt = 0) +//#define Is_tb_srp_counter_overflow() ((otg_tb_srp_cpt > TB_SRP_FAIL_MIN) ? TRUE : FALSE) + +// usb_task USB task entry point module + +//! usb_software_evts USB software Events Management +//! Macros to manage USB events detected under interrupt +#define Usb_send_event(x) g_usb_event |= (1< +#include "main.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "otg_user_task.h" +#include "usb_task.h" +#include "usb/otg/usb_drv.h" +#include "usb/otg/usb_host_task.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + + + +extern volatile unsigned int timer_set_counter; +#define Timer16_select(...) +#define Timer16_set_counter(value) timer_set_counter = value +#define Timer16_get_counter_low() (unsigned char)timer_set_counter + + +/// Returns the OTG features sent by the host by a SetFeature +/// Allow also to clear the features (only on a bus Reset or Session End) +#define Is_host_requested_hnp() (((otg_features_supported&USBFeatureRequest_OTG_B_HNP_ENABLE) != 0) ? TRUE : FALSE) +#define Clear_otg_features_from_host() (otg_features_supported = 0) + +#define Set_otg_custom_timer(ep) // STUB: todo + +#define USB_MODE_UNDEFINED 0x00 +#define USB_MODE_HOST 0x01 +#define USB_MODE_DEVICE 0x02 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +U8 otg_device_sessions; +U8 b_uut_device_state; +U16 otg_tb_srp_cpt; + +/// usb_connected is used to store USB events detected upon +/// USB general interrupt subroutine +/// Its value is managed by the following macros (See usb_task.h file) +/// Usb_send_event(x) +/// Usb_ack_event(x) +/// Usb_clear_all_event() +/// Is_usb_event(x) +/// Is_not_usb_event(x) +volatile U16 g_usb_event=0; + + +/// +/// Private : (U8) private_sof_counter +/// Incremented by host SOF interrupt subroutime +/// This counter is used to detect timeout in host requests. +/// It must not be modified by the user application tasks. +//// +volatile U8 private_sof_counter=0; +extern volatile S_pipe_int it_pipe_str[MAX_EP_NB]; + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the USB process +/// Depending on the mode supported (HOST/DEVICE/DUAL_ROLE) the function calls +/// the coresponding USB mode initialization function +//------------------------------------------------------------------------------ +void usb_task_init(void) +{ + // ---- REDUCED HOST ONLY USB MODE ----------------------------------------- + //jcbUsb_force_host_mode(); + usb_host_task_init(); +} + + +//------------------------------------------------------------------------------ +/// Entry point of the USB mamnagement +/// Depending on the USB mode supported (HOST/DEVICE/DUAL_ROLE) the function +/// calls the coresponding USB management function +//------------------------------------------------------------------------------ +void usb_task(void) +{ + // ---- REDUCED HOST ONLY USB MODE ----------------------------------------- + usb_host_task(); +} + + + +//------------------------------------------------------------------------------ +/// USB interrupt subroutine +/// +/// This function is called each time a USB interrupt occurs. +/// The following USB DEVICE events are taken in charge: +/// - VBus On / Off +/// - Start Of Frame +/// - Suspend +/// - Wake-Up +/// - Resume +/// - Reset +/// - Start of frame +/// +/// The following USB HOST events are taken in charge: +/// - Device connection +/// - Device Disconnection +/// - Start Of Frame +/// - ID pin change +/// - SOF (or Keep alive in low speed) sent +/// - Wake up on USB line detected +/// +/// The following USB HOST events are taken in charge: +/// - HNP success (Role Exchange) +/// - HNP failure (HNP Error) +/// +/// For each event, the user can launch an action by completing +/// the associate define (See conf_usb.h file to add action upon events) +/// +/// Note: Only interrupts events that are enabled are processed +//------------------------------------------------------------------------------ +void usb_general_interrupt(void) +{ + //TRACE_DEBUG("usb_general_interrupt\n\r"); + U8 i; + U8 save_pipe_nb; + + // ---------- HOST events management ----------------------------------- + // --------------------------------------------------------------------- + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - The device has been disconnected + if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { + TRACE_DEBUG("device disconnect\n\r"); + host_disable_all_pipe(); + Host_ack_device_disconnection(); + device_state=DEVICE_DISCONNECTED; + Usb_send_event(EVT_HOST_DISCONNECTION); + TRACE_INFO("Device disconnected\n\r"); + Host_device_disconnection_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Device connection + if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { + TRACE_DEBUG("device connect\n\r"); + Host_ack_device_connection(); + host_disable_all_pipe(); + Host_device_connection_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Start of frame has been sent + if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { + //TRACE_DEBUG_WP("_"); // host + Host_ack_sof(); + Usb_send_event(EVT_HOST_SOF); + private_sof_counter++; + + // delay timeout management for interrupt tranfer mode in host mode +#if ((USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) + if (private_sof_counter>=250) { // Count 1/4 sec + private_sof_counter=0; + for(i=0;iTIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { + it_pipe_str[i].enable=DISABLE; + it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; + Host_stop_pipe_interrupt(i); + if (is_any_interrupt_pipe_active()==FALSE) { // If no more transfer is armed + if (g_sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + } + it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); + } + Host_select_pipe(save_pipe_nb); + } + } + } +#endif // (USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) + Host_sof_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Wake-up has been received + if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { + TRACE_DEBUG("Host wake up\n\r"); + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + Host_disable_remote_wakeup_interrupt(); + // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_ack_remote_wakeup(); + Usb_send_event(EVT_HOST_HWUP); // Send software event + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Host_hwup_action(); // Map custom action + Host_send_resume(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // Remote Wake Up has been received + if (Is_host_remote_wakeup_interrupt_enabled() && Is_host_remote_wakeup()) { + TRACE_DEBUG("Remote wake up\n\r"); + Host_disable_remote_wakeup_interrupt(); + Host_disable_hwup_interrupt(); + Host_ack_remote_wakeup(); + Host_ack_hwup(); // Clear HWUP interrupt flag + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Usb_send_event(EVT_HOST_HWUP); // Send software event + Host_send_resume(); + } +} + +//------------------------------------------------------------------------------ +/// Message "OTG not supported" +//------------------------------------------------------------------------------ +void otg_not_supported_device(void) +{ + TRACE_DEBUG("otg_not_supported_device\n\r"); + Otg_send_event(EVT_OTG_DEV_UNSUPPORTED); +} + + diff --git a/usb/otg/usb_task_with_SRP_HNP.c b/usb/otg/usb_task_with_SRP_HNP.c new file mode 100644 index 0000000..e5204de --- /dev/null +++ b/usb/otg/usb_task_with_SRP_HNP.c @@ -0,0 +1,852 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + + + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "main.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "otg_user_task.h" +#include "usb_task.h" +#include "usb/otg/usb_drv.h" +#include "usb/otg/usb_host_task.h" + +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + + + +extern volatile unsigned int timer_set_counter; +#define Timer16_select(...) +#define Timer16_set_counter(value) timer_set_counter = value +#define Timer16_get_counter_low() (unsigned char)timer_set_counter + + +/// Returns the OTG features sent by the host by a SetFeature +/// Allow also to clear the features (only on a bus Reset or Session End) +#define Is_host_requested_hnp() (((otg_features_supported&USBFeatureRequest_OTG_B_HNP_ENABLE) != 0) ? TRUE : FALSE) +#define Clear_otg_features_from_host() (otg_features_supported = 0) + +#define Set_otg_custom_timer(ep) // STUB: todo + +#define USB_MODE_UNDEFINED 0x00 +#define USB_MODE_HOST 0x01 +#define USB_MODE_DEVICE 0x02 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +U8 otg_device_sessions; +U8 b_uut_device_state; +U16 otg_tb_srp_cpt; + +/// usb_connected is used to store USB events detected upon +/// USB general interrupt subroutine +/// Its value is managed by the following macros (See usb_task.h file) +/// Usb_send_event(x) +/// Usb_ack_event(x) +/// Usb_clear_all_event() +/// Is_usb_event(x) +/// Is_not_usb_event(x) +volatile U16 g_usb_event=0; + +/// +/// Public : (bit) usb_connected +/// usb_connected is set to TRUE when VBUS has been detected +/// usb_connected is set to FALSE otherwise +bit usb_connected; + +/// +/// Public : (U8) usb_configuration_nb +/// Store the number of the USB configuration used by the USB device +/// when its value is different from zero, it means the device mode is enumerated +U8 usb_configuration_nb; + +/// +/// Public : (U8) remote_wakeup_feature +/// Store a host request for remote wake up (set feature received) +//// +U8 remote_wakeup_feature; + +/// +/// Private : (U8) private_sof_counter +/// Incremented by host SOF interrupt subroutime +/// This counter is used to detect timeout in host requests. +/// It must not be modified by the user application tasks. +//// +volatile U8 private_sof_counter=0; + +extern volatile S_pipe_int it_pipe_str[MAX_EP_NB]; + + +/// +/// Public : (U8) g_usb_mode +/// Used in dual role application (both device/host) to store +/// the current mode the usb controller is operating +//// +U8 g_usb_mode=USB_MODE_UNDEFINED; +U8 g_old_usb_mode; + + +/// +/// Public : (U8) otg_features_supported; +/// -> A-Device side : indicates if the B-Device supports HNP and SRP (this is the bmAttributes field of OTG Decriptor) +/// -> B-Device side : indicates if the A-Device has enabled the "a_hnp_support" and "b_hnp_enable" features +volatile U8 otg_features_supported; + +/// Public : (U8) otg_user_request; +/// Store the last request of the user (see usb_device_task.h) +U8 otg_user_request; + +/// Public : (U16) otg_msg_event_delay; +/// Contains the current display duration of the OTG event message +U16 otg_msg_event_delay; + +/// Public : (U16) otg_msg_failure_delay; +/// Contains the current display duration of the OTG failure message +U16 otg_msg_failure_delay; + +/// Public : (U16) g_otg_event; +/// Contains several bits corresponding to differents OTG events (similar to g_usb_event) +volatile U16 g_otg_event; + +/// Public : (U8) otg_device_nb_hnp_retry; +/// Counts the number of times a HNP fails, before aborting the operations +U8 otg_device_nb_hnp_retry; + +U8 id_changed_to_host_event; + +volatile U8 otg_last_sof_received; // last SOF received in SOF interrupt +volatile U8 otg_last_sof_stored; // last SOF value stored in OTG Timer interrupt +volatile U8 reset_received; // indicates if a reset has been received from B-Host after a HNP (used in A-Periph mode) + +/// @brief VBUS Overload management +/// +/// Nothing to do ! If the condition is not defined in the board driver file +/// (i.e. if the board does not support Vbus overcurrent detection), +/// the macro is defined to false for firmware compatibility +#define Is_vbus_overcurrent() (FALSE) + +/// Private function prototypes +/// Tasks for OTG Messaging features +void Otg_message_task_init(void); +void Otg_message_task(void); + + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the USB process +/// Depending on the mode supported (HOST/DEVICE/DUAL_ROLE) the function calls +/// the coresponding USB mode initialization function +//------------------------------------------------------------------------------ +void usb_task_init(void) +{ + // DUAL ROLE DEVICE USB MODE + Otg_message_task_init(); // OTG program needs to display event messages to the user + b_uut_device_state = B_IDLE; // init state machines variables + device_state = DEVICE_UNATTACHED; + otg_device_nb_hnp_retry = BDEV_HNP_NB_RETRY; + Clear_all_user_request(); + Usb_enable_uid_pin(); + + g_usb_mode=USB_MODE_UNDEFINED; + + if(Is_usb_id_device()) { + g_usb_mode=USB_MODE_DEVICE; +#ifdef MSD_PROJECT + MSDDriver_Initialize(luns, numMedias); +#else + // HID + HIDDMouseDriver_Initialize(); +#endif + id_changed_to_host_event = DISABLE; + } + else { + Usb_send_event(EVT_USB_HOST_FUNCTION); + g_usb_mode=USB_MODE_HOST; + // Startup with ID=0, Ack ID pin transistion (default hwd start up is device mode) + Usb_ack_id_transition(); + Usb_enable_id_interrupt(); + usb_host_task_init(); + id_changed_to_host_event = ENABLE; + } + // Store current usb mode, for mode change detection + g_old_usb_mode = g_usb_mode; +} + + +//------------------------------------------------------------------------------ +/// Entry point of the USB mamnagement +/// Depending on the USB mode supported (HOST/DEVICE/DUAL_ROLE) the function +/// calls the coresponding USB management function +//------------------------------------------------------------------------------ +void usb_task(void) +{ + // DUAL ROLE DEVICE USB MODE + if(Is_usb_id_device()) { + g_usb_mode = USB_MODE_DEVICE; + } + else { + g_usb_mode = USB_MODE_HOST; + } + g_old_usb_mode = g_usb_mode; // Store current usb mode, for mode change detection + // Depending on current usb mode, launch the correct usb task (device or host) + + // Configure OTG timers + Set_otg_custom_timer(VBUSRISE_70MS); + Set_otg_custom_timer(VBUSPULSE_40MS); + Set_otg_custom_timer(VFALLTMOUT_131MS); + Set_otg_custom_timer(SRPMINDET_100US); + + switch(g_usb_mode) { + case USB_MODE_DEVICE: + //usb_device_task(); + //MSDDriver_StateMachine(); + Scheduler_task_3(); + break; + + case USB_MODE_HOST: + if( pOTGDescriptor->bOTGADevSRPReaction == VBUS_PULSE) { + Usb_select_vbus_srp_method(); + } + else { + Usb_select_data_srp_method(); + } + usb_host_task(); + // Handle Vbus overcurrent error (auto-disabled if not supported or not defined in board driver file) + if (Is_vbus_overcurrent()) { + Otg_print_new_event_message(OTGMSG_VBUS_SURCHARGE,OTG_TEMPO_3SEC); + } + break; + + case USB_MODE_UNDEFINED: // No break ! + default: + break; + } + Otg_message_task(); +} + + + +//------------------------------------------------------------------------------ +/// USB interrupt subroutine +/// +/// This function is called each time a USB interrupt occurs. +/// The following USB DEVICE events are taken in charge: +/// - VBus On / Off +/// - Start Of Frame +/// - Suspend +/// - Wake-Up +/// - Resume +/// - Reset +/// - Start of frame +/// +/// The following USB HOST events are taken in charge: +/// - Device connection +/// - Device Disconnection +/// - Start Of Frame +/// - ID pin change +/// - SOF (or Keep alive in low speed) sent +/// - Wake up on USB line detected +/// +/// The following USB HOST events are taken in charge: +/// - HNP success (Role Exchange) +/// - HNP failure (HNP Error) +/// +/// For each event, the user can launch an action by completing +/// the associate define (See conf_usb.h file to add action upon events) +/// +/// Note: Only interrupts events that are enabled are processed +//------------------------------------------------------------------------------ +void usb_general_interrupt(void) +{ + //TRACE_DEBUG("usb_general_interrupt\n\r"); + + // ---------- DEVICE events management ----------------------------------- + // ----------------------------------------------------------------------- + + //- VBUS state detection + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled() + && Is_usb_id_device()) { + Usb_ack_vbus_transition(); + + if (Is_usb_vbus_high()) { + usb_connected = TRUE; + Usb_vbus_on_action(); + Usb_send_event(EVT_USB_POWERED); + //jcb Usb_enable_reset_interrupt(); + //usb_start_device(); + USBD_Connect();//Usb_attach(); + } + else { + TRACE_DEBUG("VBUS low\n\r"); + USBD_Disconnect(); + Usb_device_stop_hnp(); + TRACE_DEBUG("Usb_select_device4\n\r"); + Usb_select_device(); + Clear_all_user_request(); + Usb_vbus_off_action(); + usb_connected = FALSE; + usb_configuration_nb = 0; + Usb_send_event(EVT_USB_UNPOWERED); + } + + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Device start of frame received + if (Is_usb_sof() && Is_sof_interrupt_enabled()) { + // TRACE_DEBUG_WP("F"); // device + Usb_ack_sof(); + Usb_sof_action(); + //sof_seen_in_session = TRUE; + otg_last_sof_received = UDFNUML; // store last frame number received + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Device Suspend event (no more USB activity detected) + if (Is_usb_suspend()) { //&& Is_suspend_interrupt_enabled()) { + //TRACE_DEBUG_WP("D\n\r"); + // 1st : B-PERIPH mode ? + if (Is_usb_id_device()) { + // HNP Handler + TRACE_DEBUG("HNP Handler\n\r"); + //TRACE_DEBUG("device_state = %d\n\r", device_state); + //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + if (Is_host_requested_hnp() // "b_hnp_enable" feature received + && (Is_session_started_with_srp() || Is_user_requested_hnp() )) { + if (otg_device_nb_hnp_retry == 0) { + otg_features_supported &= ~USBFeatureRequest_OTG_B_HNP_ENABLE; + } + else { + Ack_user_request_hnp(); + Usb_ack_hnp_error_interrupt(); + Usb_ack_role_exchange_interrupt(); + Usb_enable_role_exchange_interrupt(); + Usb_enable_hnp_error_interrupt(); + Usb_device_initiate_hnp(); + otg_device_nb_hnp_retry--; + } + } + else + { + // Remote wake-up handler + //TRACE_DEBUG("Remote wake-up handler\n\r"); + //TRACE_DEBUG("device_state = %d\n\r", device_state); + //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + if ((remote_wakeup_feature == ENABLE) && (usb_configuration_nb != 0)) + { + //TRACE_DEBUG("enabled\n\r"); + // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up + // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume + // So the SUSPE enable bit must be cleared to avoid redundant interrupt + // **************** + // Please note also that is Vbus is lost during an upstream resume (Host disconnection), + // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent) + // remains set after the event, so that a good way to handle this feature is : + // Usb_initiate_remote_wake_up(); + // while (Is_usb_pending_remote_wake_up()) + // { + // if (Is_usb_vbus_low()) + // { + // // Emergency action (reset macro, etc.) if Vbus lost during resuming + // break; + // } + // } + // Usb_ack_remote_wake_up_start(); + // **************** + } + else { + //TRACE_DEBUG("disabled: %d %d\n\r", usb_configuration_nb, remote_wakeup_feature); + // No remote wake-up supported + Usb_send_event(EVT_USB_SUSPEND); + } + } + } + else + { + //TRACE_DEBUG("ici\n\r"); + // A-PERIPH mode (will cause a session end, handled in usb_host_task.c) + Usb_send_event(EVT_USB_SUSPEND); + Usb_suspend_action(); + //jcb Usb_ack_suspend(); + } + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Wake up event (USB activity detected): Used to resume + if (Is_usb_wake_up() && Is_swake_up_interrupt_enabled()) { + TRACE_DEBUG("W\n\r"); + Usb_unfreeze_clock(); + Usb_send_event(EVT_USB_WAKE_UP); + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Resume state bus detection + if (Is_usb_resume() && Is_resume_interrupt_enabled()) { + TRACE_DEBUG("Resume state bus detect\n\r"); + Usb_send_event(EVT_USB_RESUME); + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - USB bus reset detection + if (Is_usb_reset()&& Is_reset_interrupt_enabled()) { + TRACE_DEBUG_WP("B\n\r"); + if (Is_usb_id_host()) { + //TRACE_DEBUG_WP("id_host\n\r"); + dev_configure_endpoint(EP_CONTROL, + TYPE_CONTROL, + DIRECTION_OUT, + SIZE_64, + ONE_BANK, + NYET_DISABLED); + } + // First initialization is important to be synchronized + // A reset must first have been received + if (device_state == A_PERIPHERAL) { + //TRACE_DEBUG_WP("r A_PERIPHERAL\n\r"); + otg_last_sof_received = UDFNUML; + otg_last_sof_stored = UDFNUML; + Usb_ack_sof(); + Usb_enable_sof_interrupt(); + reset_received = TRUE; + Timer16_set_counter(0); + } + Usb_reset_action(); + Usb_send_event(EVT_USB_RESET); + } + + // ---------- OTG events management ------------------------------------ + // --------------------------------------------------------------------- + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - OTG HNP Success detection + if (Is_usb_role_exchange_interrupt() && Is_role_exchange_interrupt_enabled()) { + // TRACE_DEBUG("OTG HNP detect\n\r"); + Usb_ack_role_exchange_interrupt(); + Host_ack_device_connection(); + Host_ack_device_disconnection(); + Otg_send_event(EVT_OTG_HNP_SUCCESS); + End_session_with_srp(); + Clear_otg_features_from_host(); + if (Is_usb_id_host()) { + // HOST (A- or B-) mode + if ((device_state != A_PERIPHERAL) && (device_state != A_END_HNP_WAIT_VFALL)) { + static volatile unsigned int jcb; + // Current mode is A-HOST, device will take the A-PERIPHERAL role + b_uut_device_state = B_PERIPHERAL; + device_state = A_PERIPHERAL; + usb_connected = FALSE; + usb_configuration_nb = 0; + Usb_select_device(); + USBD_Connect();//Usb_attach(); + Usb_unfreeze_clock(); + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Usb_device_stop_hnp(); + Usb_ack_reset(); + Timer16_set_counter(0); + Usb_freeze_clock(); // USB clock can be freezed to slow down events and condition detection + //jcb while (Timer16_get_counter_low() != 20); + jcb=0; + while( jcb <100000){ jcb++; } + + Usb_unfreeze_clock(); + reset_received = FALSE; + Usb_disable_sof_interrupt(); // will be set in the next OTG Timer IT (mandatory) + + Usb_enable_suspend_interrupt(); + Usb_enable_reset_interrupt(); + dev_configure_endpoint(EP_CONTROL, + TYPE_CONTROL, + DIRECTION_OUT, + SIZE_64, + ONE_BANK, + NYET_DISABLED); + } + } + else { + // In B_HOST mode, the HNPREQ bit must not be cleared because it releases the bus in suspend mode (and sof can't start) + if ((b_uut_device_state != B_HOST) && (b_uut_device_state != B_END_HNP_SUSPEND)) { + static volatile unsigned int jcb2; + // Current mode is B-PERIPHERAL, device will go into B-HOST role + End_session_with_srp(); + Clear_otg_features_from_host(); + b_uut_device_state = B_HOST; + device_state = DEVICE_ATTACHED; + usb_connected = FALSE; + usb_configuration_nb = 0; + TRACE_DEBUG("Select host 3\n\r"); + Usb_select_host(); + + TRACE_DEBUG("Send reset\n\r"); + Host_send_reset(); // send the first RESET + while (Host_is_reset()); + TRACE_DEBUG("Reset passed\n\r"); + + jcb2=0; + while( jcb2 <1000000){ jcb2++; } + Host_enable_sof(); // start Host (sof) + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Clear_all_user_request(); + + TRACE_DEBUG("Select host 3\n\r"); + } + } + } + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - OTG HNP Failure detection + if (Is_usb_hnp() && Is_usb_hnp_error_interrupt()&& Is_hnp_error_interrupt_enabled()) { + TRACE_DEBUG("OTG HNP failure\n\r"); + Usb_device_stop_hnp(); + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Usb_ack_hnp_error_interrupt(); + if (Is_usb_id_device()) { + Otg_send_event(EVT_OTG_HNP_ERROR); + Clear_all_user_request(); + } + } + + // ---------- HOST events management ----------------------------------- + // --------------------------------------------------------------------- + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - ID pin change detection + if(Is_usb_id_transition()&&Is_usb_id_interrupt_enabled()) { + TRACE_DEBUG("ID pin change\n\r"); + TRACE_DEBUG("device_state = %d\n\r", device_state); + TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + Usb_device_stop_hnp(); + Clear_all_user_request(); + if(Is_usb_id_device()) { + g_usb_mode = USB_MODE_DEVICE; + } + else { + g_usb_mode = USB_MODE_HOST; + } + Usb_ack_id_transition(); + if( g_usb_mode != g_old_usb_mode) { // Basic Debounce + if(Is_usb_id_device()) { // Going into device mode + Usb_send_event(EVT_USB_DEVICE_FUNCTION); + b_uut_device_state = B_IDLE; + device_state = DEVICE_UNATTACHED; + id_changed_to_host_event = DISABLE; + } + else { // Going into host mode + b_uut_device_state = B_IDLE; + device_state = DEVICE_UNATTACHED; + Usb_send_event(EVT_USB_HOST_FUNCTION); + id_changed_to_host_event = ENABLE; + } + Usb_id_transition_action(); + TRACE_INFO("Pin Id changed\n\r"); + } + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - The device has been disconnected + // JCB to be fix + if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { + TRACE_DEBUG("device disconnect\n\r"); + host_disable_all_pipe(); + Host_ack_device_disconnection(); + device_state=DEVICE_DISCONNECTED; + Usb_send_event(EVT_HOST_DISCONNECTION); + TRACE_INFO("Device disconnected\n\r"); + Host_device_disconnection_action(); + Clear_all_user_request(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Device connection + if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { + TRACE_DEBUG("device connect\n\r"); + Host_ack_device_connection(); + host_disable_all_pipe(); + Host_device_connection_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Start of frame has been sent + if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { + //TRACE_DEBUG_WP("_"); // host + Host_ack_sof(); + Usb_send_event(EVT_HOST_SOF); + private_sof_counter++; + + // delay timeout management for interrupt tranfer mode in host mode +#if ((USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) + if (private_sof_counter>=250) { // Count 1/4 sec + private_sof_counter=0; + for(i=0;iTIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { + it_pipe_str[i].enable=DISABLE; + it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; + Host_stop_pipe_interrupt(i); + if (is_any_interrupt_pipe_active()==FALSE) { // If no more transfer is armed + if (g_sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + } + it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); + } + Host_select_pipe(save_pipe_nb); + } + } + } +#endif // (USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) + Host_sof_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Wake-up has been received + if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { + TRACE_DEBUG("Host wake up\n\r"); + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + Host_disable_remote_wakeup_interrupt(); + // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_ack_remote_wakeup(); + Usb_send_event(EVT_HOST_HWUP); // Send software event + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Host_hwup_action(); // Map custom action + if (Is_usb_hnp()) { + Usb_host_reject_hnp(); + Usb_disable_hnp_error_interrupt(); + Usb_disable_role_exchange_interrupt(); + } + Host_send_resume(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // Remote Wake Up has been received + if (Is_host_remote_wakeup_interrupt_enabled() && Is_host_remote_wakeup()) { + TRACE_DEBUG("Remote wake up\n\r"); + Host_disable_remote_wakeup_interrupt(); + Host_disable_hwup_interrupt(); + Host_ack_remote_wakeup(); + Host_ack_hwup(); // Clear HWUP interrupt flag + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Usb_send_event(EVT_HOST_HWUP); // Send software event + if (Is_usb_hnp()) { + Usb_host_reject_hnp(); + Usb_disable_hnp_error_interrupt(); + Usb_disable_role_exchange_interrupt(); + } + Host_send_resume(); + } +} + + +//------------------------------------------------------------------------------ +/// OTG TIMER interrupt subroutine +/// This function is called each time a OTG Timer interrupt occurs +/// Function decrements the variables required by OTG program +void otg_timer_interrupt(void) +{ + /// OTG Messaging timer + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) + || (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_FAIL)) { + if ((Get_failure_msg_delay() != 0x0000) && (Get_failure_msg_delay() != 0xFFFF)) { + Decrement_failure_msg_delay(); + } + if(pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) { + if ((Get_event_msg_delay() != 0x0000) && (Get_event_msg_delay() != 0xFFFF)) { + Decrement_event_msg_delay(); + } + } + } + /// Increments Tb_Srp counter if needed + if (Is_srp_sent_and_waiting_answer()) { + otg_tb_srp_cpt++; + } + /// Increments T_vbus_wait_connect if needed + if (Is_srp_received_and_waiting_connect()) { + otg_ta_srp_wait_connect++; + } + /// Decrements Ta_aidl_bdis timer if needed (A_suspend state) + if ((device_state == A_SUSPEND) && (otg_ta_aidl_bdis_tmr > 1)) { + otg_ta_aidl_bdis_tmr--; + } + /// Decrements Timeout_bdev_respond timer if needed + if ((device_state == DEVICE_DEFAULT) && (!Is_timeout_bdev_response_overflow())) { + otg_timeout_bdev_respond--; + } + /// Decrements Ta_vbus_rise timer if needed + if (!Is_ta_vbus_rise_counter_overflow()) { + otg_ta_vbus_rise--; + } + /// Decrements Ta_vbus_fall timer if needed + if (!Is_ta_vbus_fall_counter_overflow()) { + otg_end_hnp_vbus_delay--; + } + + /// Needed for compliance only + if (device_state == A_PERIPHERAL) { + if (Is_sof_interrupt_enabled() && (reset_received == TRUE)) { + if (otg_last_sof_stored != otg_last_sof_received) { + // No SOF is missing + otg_last_sof_received = otg_last_sof_stored; + } + else { + // SOF seems to be missing.. + Usb_freeze_clock(); + Usb_disable_sof_interrupt(); + reset_received = FALSE; + //jcb while (Timer16_get_counter_low() != 20); // overflow set to 62 in usb_task.h + Usb_unfreeze_clock(); + } + otg_last_sof_received = UDFNUML; + otg_last_sof_stored = UDFNUML; + } + } +} + + +//------------------------------------------------------------------------------ +/// OTG Messaging task initialization +/// Initializes variables and screen to prepare next messages to be handled +//------------------------------------------------------------------------------ +void Otg_message_task_init(void) +{ + TRACE_DEBUG("Otg_message_task_init\n\r"); + Otg_messaging_init(); + otg_msg_event_delay = 0; + otg_msg_failure_delay = 0; +} + + +//------------------------------------------------------------------------------ +/// OTG Messaging main task +/// OTG specifies that user must be kept informed of several events +/// This task allows user to display two kinds of messages : EVENT or FAILURE +/// For each new message, it can specify if the message remains displayed all +/// the time or only during a specified delay +//------------------------------------------------------------------------------ +void Otg_message_task(void) +{ + // Check if an OTG message must be erased (if it was set up for a specified delay) + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) + || (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_FAIL)) { + if (Get_failure_msg_delay() == 0) { + Otg_clear_failure_message(); + } + if(pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) { + if (Get_event_msg_delay() == 0) { + Otg_clear_event_message(); + } + } + } +} + + +//------------------------------------------------------------------------------ +/// Message "OTG not supported" +//------------------------------------------------------------------------------ +void otg_not_supported_device(void) +{ + TRACE_DEBUG("otg_not_supported_device\n\r"); + Otg_send_event(EVT_OTG_DEV_UNSUPPORTED); +} + + -- cgit v1.2.3