diff options
Diffstat (limited to 'usb/otg')
-rw-r--r-- | usb/otg/compiler.h | 65 | ||||
-rw-r--r-- | usb/otg/usb_drv.c | 246 | ||||
-rw-r--r-- | usb/otg/usb_drv.h | 859 | ||||
-rw-r--r-- | usb/otg/usb_host_enum.c | 670 | ||||
-rw-r--r-- | usb/otg/usb_host_enum.h | 329 | ||||
-rw-r--r-- | usb/otg/usb_host_enum_with_srp_hnp.c | 754 | ||||
-rw-r--r-- | usb/otg/usb_host_task.c | 1260 | ||||
-rw-r--r-- | usb/otg/usb_host_task.h | 230 | ||||
-rw-r--r-- | usb/otg/usb_host_task_with_srp_hnp.c | 1493 | ||||
-rw-r--r-- | usb/otg/usb_task.c | 999 | ||||
-rw-r--r-- | usb/otg/usb_task.h | 232 | ||||
-rw-r--r-- | usb/otg/usb_task_host_only.c | 287 | ||||
-rw-r--r-- | usb/otg/usb_task_with_SRP_HNP.c | 852 |
13 files changed, 8276 insertions, 0 deletions
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 <conf_usb.h>
+#include "usb_drv.h"
+#include <utility/trace.h>
+
+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<<ept);
+
+ AT91C_BASE_OTGHS->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; i<MAX_EP_NB; i++) {
+ if (interrupt_flags & (1<<i)) {
+ return (i);
+ }
+ }
+ // This return should never occurs ....
+ TRACE_ERROR("Error\n\r");
+ return MAX_EP_NB+1;
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void host_configure_address( unsigned char pipe, unsigned char addr)
+{
+ if( pipe == 0 ) {
+ AT91C_BASE_OTGHS->OTGHS_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<<pip);
+
+ if((type & AT91C_OTGHS_PTYPE_INT_PIP)==0) {
+ freq =0;
+ }
+
+ AT91C_BASE_OTGHS->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<<UIDE))
+#define Usb_enable_uid_pin() AT91C_BASE_OTGHS->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<<UVCONE))
+#define Usb_enable_uvcon_pin()
+//#define Usb_enable_uvcon_pin() { const Pin pinDRVVUS = PIN_USB_DRV_VBUS;PIO_Set(&pinDRVVUS); }
+//jcb
+/// Use device full speed mode (default mode)
+//#define Usb_full_speed_mode() (UDCON &= ~(1<<LSM))
+/// For device mode, force low speed mode
+//#define Usb_low_speed_mode() (UDCON |= (1<<LSM))
+#define Usb_low_speed_mode() AT91C_BASE_OTGHS->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<<OTGPADE))
+#define Usb_enable_vbus_pad() {AT91C_BASE_OTGHS->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<<OTGPADE))
+#define Usb_disable_vbus_pad() AT91C_BASE_OTGHS->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<<FRZCLK))
+#define Usb_freeze_clock() // AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_FRZCLKCTRL
+//jcb
+//#define Usb_unfreeze_clock() (USBCON &= ~(1<<FRZCLK))
+#define Usb_unfreeze_clock() // AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_FRZCLKCTRL
+//#define Is_usb_clock_freezed() ((USBCON & (1<<FRZCLK)) ? TRUE : FALSE)
+#define Is_usb_clock_freezed() (AT91C_BASE_OTGHS->OTGHS_CTRL & AT91C_OTGHS_FRZCLKCTRL)
+
+//#define Usb_enable_id_interrupt() (USBCON |= (1<<IDTE))
+#define Usb_enable_id_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_IDT
+//#define Usb_disable_id_interrupt() (USBCON &= ~(1<<IDTE))
+#define Usb_disable_id_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_IDT
+//#define Is_usb_id_interrupt_enabled() ((USBCON & (1<<IDTE)) ? TRUE : FALSE)
+#define Is_usb_id_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_CTRL & AT91C_OTGHS_IDT)
+//#define Is_usb_id_device() ((USBSTA & (1<<ID)) ? TRUE : FALSE)
+#define Is_usb_id_device() (AT91C_BASE_OTGHS->OTGHS_SR & AT91C_OTGHS_ID)
+//#define Is_usb_id_host() ((USBSTA & (1<<ID)) ? FALSE : TRUE)
+#define Is_usb_id_host() !Is_usb_id_device()
+//#define Usb_ack_id_transition() (USBINT = ~(1<<IDTI))
+#define Usb_ack_id_transition() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_IDT
+//#define Is_usb_id_transition() ((USBINT & (1<<IDTI)) ? TRUE : FALSE)
+#define Is_usb_id_transition() (AT91C_BASE_OTGHS->OTGHS_SR & AT91C_OTGHS_IDT)
+
+//#define Usb_enable_vbus_interrupt() (USBCON |= (1<<VBUSTE))
+//#define Usb_enable_vbus_interrupt() (Set_bits(AVR32_USB_usbcon, AVR32_USB_USBCON_VBUSTE_MASK))
+#define Usb_enable_vbus_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_VBUSTI
+//#define Usb_disable_vbus_interrupt() (USBCON &= ~(1<<VBUSTE))
+#define Usb_disable_vbus_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_VBUSTI
+//#define Is_usb_vbus_interrupt_enabled() ((USBCON & (1<<VBUSTE)) ? TRUE : FALSE)
+#define Is_usb_vbus_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_CTRL & AT91C_OTGHS_VBUSTI)
+//#define Is_usb_vbus_high() ((USBSTA & (1<<VBUS)) ? TRUE : FALSE)
+
+#define Is_usb_vbus_high() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_VBUSSR)==AT91C_OTGHS_VBUSSR)
+//#define Is_usb_vbus_low() ((USBSTA & (1<<VBUS)) ? FALSE : TRUE)
+#define Is_usb_vbus_low() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_VBUSSR)!=AT91C_OTGHS_VBUSSR)
+//#define Usb_ack_vbus_transition() (USBINT = ~(1<<VBUSTI))
+#define Usb_ack_vbus_transition() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_VBUSTI
+//#define Is_usb_vbus_transition() ((USBINT & (1<<VBUSTI)) ? TRUE : FALSE)
+#define Is_usb_vbus_transition() (AT91C_BASE_OTGHS->OTGHS_CTRL & AT91C_OTGHS_VBUSTI)
+
+/// requests for VBus activation
+//#define Usb_enable_vbus() (OTGCON |= (1<<VBUSREQ))
+#define Usb_enable_vbus() AT91C_BASE_OTGHS->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<<UVCONE))
+//#define Usb_enable_manual_vbus() (PORTE|=0x80,DDRE|=0x80,Usb_disable_uvcon_pin())
+#define Usb_enable_manual_vbus() AT91C_BASE_OTGHS->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<<HNPREQ))
+#define Usb_device_initiate_hnp() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_HNPREQ
+/// stops a Host Negociation Protocol
+//#define Usb_device_stop_hnp() (OTGCON &= ~(1<<HNPREQ))
+#define Usb_device_stop_hnp() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPREQ
+/// accepts a Host Negociation Protocol
+//#define Usb_host_accept_hnp() (OTGCON |= (1<<HNPREQ))
+#define Usb_host_accept_hnp() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_HNPREQ
+/// rejects a Host Negociation Protocol
+//#define Usb_host_reject_hnp() (OTGCON &= ~(1<<HNPREQ))
+#define Usb_host_reject_hnp() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPREQ
+/// initiates a Session Request Protocol
+//#define Usb_device_initiate_srp() (OTGCON |= (1<<SRPREQ))
+#define Usb_device_initiate_srp() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_SRPREQ
+/// selects VBus as SRP method
+//#define Usb_select_vbus_srp_method() (OTGCON |= (1<<SRPSEL))
+#define Usb_select_vbus_srp_method() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_SRPSEL
+/// selects data line as SRP method
+//#define Usb_select_data_srp_method() (OTGCON &= ~(1<<SRPSEL))
+#define Usb_select_data_srp_method() AT91C_BASE_OTGHS->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<<VBUSREQ)) ? TRUE : FALSE)
+/// tests if a HNP occurs
+//#define Is_usb_hnp() ((OTGCON & (1<<HNPREQ)) ? TRUE : FALSE)
+#define Is_usb_hnp() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_ROLEEX) == AT91C_OTGHS_ROLEEX)
+/// tests if a SRP from device occurs
+//#define Is_usb_device_srp() ((OTGCON & (1<<SRPREQ)) ? TRUE : FALSE)
+/// tests if device is initiating SRP
+//#define Is_usb_device_initiating_srp() ((OTGCON & (1<<SRPREQ)) ? TRUE : FALSE)
+#define Is_usb_device_initiating_srp() (AT91C_BASE_OTGHS->OTGHS_CTRL&AT91C_OTGHS_SRPREQ)
+
+/// acks suspend time out interrupt
+//#define Usb_ack_suspend_time_out_interrupt() (OTGINT &= ~(1<<STOI))
+#define Usb_ack_suspend_time_out_interrupt() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_STO
+/// enables suspend time out interrupt
+//#define Usb_enable_suspend_time_out_interrupt() (OTGIEN |= (1<<STOE))
+#define Usb_enable_suspend_time_out_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_STO
+/// disables suspend time out interrupt
+//#define Usb_disable_suspend_time_out_interrupt() (OTGIEN &= ~(1<<STOE))
+#define Usb_disable_suspend_time_out_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_STO
+//#define Is_suspend_time_out_interrupt_enabled() ((OTGIEN & (1<<STOE)) ? TRUE : FALSE)
+#define Is_suspend_time_out_interrupt_enabled() ((AT91C_BASE_OTGHS->OTGHS_CTRL&AT91C_OTGHS_STO)==AT91C_OTGHS_STO)
+/// tests if a suspend time out occurs
+//#define Is_usb_suspend_time_out_interrupt() ((OTGINT & (1<<STOI)) ? TRUE : FALSE)
+#define Is_usb_suspend_time_out_interrupt() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_STO)==AT91C_OTGHS_STO)
+
+/// enables HNP error interrupt
+//#define Usb_enable_hnp_error_interrupt() (OTGIEN |= (1<<HNPERRE))
+#define Usb_enable_hnp_error_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_HNPERR
+/// disables HNP error interrupt
+//#define Usb_disable_hnp_error_interrupt() (OTGIEN &= ~(1<<HNPERRE))
+#define Usb_disable_hnp_error_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPERR
+//#define Is_hnp_error_interrupt_enabled() ((OTGIEN & (1<<HNPERRE)) ? TRUE : FALSE)
+#define Is_hnp_error_interrupt_enabled() ((AT91C_BASE_OTGHS->OTGHS_CTRL&AT91C_OTGHS_HNPERR)==AT91C_OTGHS_HNPERR)
+/// acks HNP error interrupt
+//#define Usb_ack_hnp_error_interrupt() (OTGINT &= ~(1<<HNPERRI))
+#define Usb_ack_hnp_error_interrupt() AT91C_BASE_OTGHS->OTGHS_SCR |= AT91C_OTGHS_HNPERR
+/// tests if a HNP error occurs
+//#define Is_usb_hnp_error_interrupt() ((OTGINT & (1<<HNPERRI)) ? TRUE : FALSE)
+#define Is_usb_hnp_error_interrupt() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_HNPERR) == AT91C_OTGHS_HNPERR)
+
+/// enables role exchange interrupt
+//#define Usb_enable_role_exchange_interrupt() (OTGIEN |= (1<<ROLEEXE))
+#define Usb_enable_role_exchange_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_ROLEEX
+/// disables role exchange interrupt
+//#define Usb_disable_role_exchange_interrupt() (OTGIEN &= ~(1<<ROLEEXE))
+#define Usb_disable_role_exchange_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_ROLEEX
+//#define Is_role_exchange_interrupt_enabled() ((OTGIEN & (1<<ROLEEXE)) ? TRUE : FALSE)
+#define Is_role_exchange_interrupt_enabled() ((AT91C_BASE_OTGHS->OTGHS_CTRL&AT91C_OTGHS_ROLEEX)==AT91C_OTGHS_ROLEEX)
+/// acks role exchange interrupt
+//#define Usb_ack_role_exchange_interrupt() (OTGINT &= ~(1<<ROLEEXI))
+#define Usb_ack_role_exchange_interrupt() AT91C_BASE_OTGHS->OTGHS_SCR |= AT91C_OTGHS_ROLEEX
+/// tests if a role exchange occurs
+//#define Is_usb_role_exchange_interrupt() ((OTGINT & (1<<ROLEEXI)) ? TRUE : FALSE)
+#define Is_usb_role_exchange_interrupt() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_ROLEEX)==AT91C_OTGHS_ROLEEX)
+
+/// enables B device connection error interrupt
+//#define Usb_enable_bconnection_error_interrupt() (OTGIEN |= (1<<BCERRE))
+#define Usb_enable_bconnection_error_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_BCERR
+/// disables B device connection error interrupt
+//#define Usb_disable_bconnection_error_interrupt() (OTGIEN &= ~(1<<BCERRE))
+#define Usb_disable_bconnection_error_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_BCERR
+//#define Is_bconnection_error_interrupt_enabled() ((OTGIEN & (1<<BCERRE)) ? TRUE : FALSE)
+/// acks B device connection error interrupt
+#define Usb_ack_bconnection_error_interrupt() AT91C_BASE_OTGHS->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<<VBERRE))
+/// disables VBus error interrupt
+//#define Usb_disable_vbus_error_interrupt() (OTGIEN &= ~(1<<VBERRE))
+//#define Is_vbus_error_interrupt_enabled() ((OTGIEN & (1<<VBERRE)) ? TRUE : FALSE)
+/// acks VBus error interrupt
+#define Usb_ack_vbus_error_interrupt() AT91C_BASE_OTGHS->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<<SRPE))
+#define Usb_enable_srp_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_SRP
+/// disables SRP interrupt
+//#define Usb_disable_srp_interrupt() (OTGIEN &= ~(1<<SRPE))
+#define Usb_disable_srp_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_SRP
+//#define Is_srp_interrupt_enabled() ((OTGIEN & (1<<SRPE)) ? TRUE : FALSE)
+#define Is_usb_srp_interrupt_enabled() ((AT91C_BASE_OTGHS->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<<RMWKUP)) ? TRUE : FALSE)
+#define Is_usb_pending_remote_wake_up() (AT91C_BASE_OTGHS->OTGHS_DEVCTRL | AT91C_OTGHS_RMWKUP)
+/// acks remote wake-up
+//#define Usb_ack_remote_wake_up_start() (UDINT = ~(1<<UPRSMI))
+#define Usb_ack_remote_wake_up_start() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_UPRSM
+
+/// enables resume interrupt
+//#define Usb_enable_resume_interrupt() (UDIEN |= (1<<EORSME))
+/// disables resume interrupt
+#define Usb_disable_resume_interrupt() AT91C_BASE_OTGHS->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<<EORSTE))
+#define Is_reset_interrupt_enabled() (AT91C_BASE_OTGHS->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<<SOFE))
+#define Usb_disable_sof_interrupt() AT91C_BASE_OTGHS->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<<SUSPE))
+#define Usb_disable_suspend_interrupt() AT91C_BASE_OTGHS->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<<FNCERR)) ? TRUE : FALSE)
+/// @}
+#define UDFNUML ((AT91C_BASE_OTGHS->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<<ALLOC))
+#define Host_allocate_memory()
+/// un-allocates the current configuration in DPRAM memory
+//#define Host_unallocate_memory() (UPCFG1X &= ~(1<<ALLOC))
+#define Host_unallocate_memory()
+
+extern void host_configure_pipe(U8 pip, U8 type, U8 token, U8 ep_num, U8 size, U8 bank, U8 freq);
+
+#define Is_usb_pipe_configured(pip) \
+ ((0 == (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[pip] & AT91C_OTGHS_CFGOK))?FALSE:TRUE)
+
+/// enables SOF generation
+//#define Host_enable_sof() (UHCON |= (1<<SOFEN))
+#define Host_enable_sof() AT91C_BASE_OTGHS->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<<RESET)) ? TRUE : FALSE)
+#define Host_is_reset() (AT91C_BASE_OTGHS->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<<RESUME)) ? TRUE : FALSE)
+#define Host_is_resume() (AT91C_BASE_OTGHS->OTGHS_HSTCTRL&AT91C_OTGHS_RESUME)
+
+/// enables host start of frame interrupt
+//#define Host_enable_sof_interrupt() (UHIEN |= (1<<HSOFE))
+#define Host_enable_sof_interrupt() AT91C_BASE_OTGHS->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<<HSOFI)) ? TRUE : FALSE)
+#define Is_host_sof() (AT91C_BASE_OTGHS->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<<HWUPI)) ? TRUE : FALSE)
+/// Ack host wake up detection
+#define Is_host_hwup() (AT91C_BASE_OTGHS->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<<RSMEDE)) ? TRUE : FALSE)
+/// Ack host down stream resume sent
+//#define Is_host_down_stream_resume() ((UHINT & (1<<RSMEDI)) ? TRUE : FALSE)
+#define Is_host_down_stream_resume() (AT91C_BASE_OTGHS->OTGHS_HSTISR&AT91C_OTGHS_RSMEDI)
+//#define Host_ack_down_stream_resume() (UHINT &= ~(1<<RSMEDI))
+#define Host_ack_down_stream_resume() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_RSMEDI
+
+/// enables host remote wake up interrupt detection
+//#define Host_enable_remote_wakeup_interrupt() (UHIEN |= (1<<RXRSME))
+#define Host_enable_remote_wakeup_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_RXRSMI
+/// disables host remote wake up interrupt detection
+//#define Host_disable_remote_wakeup_interrupt() (UHIEN &= ~(1<<RXRSME))
+#define Host_disable_remote_wakeup_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_RXRSMI
+//#define Is_host_remote_wakeup_interrupt_enabled() ((UHIEN & (1<<RXRSME)) ? TRUE : FALSE)
+#define Is_host_remote_wakeup_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_HSTISR&AT91C_OTGHS_RXRSMI)
+/// tests if host wake up detected
+//#define Host_is_remote_wakeup() ((UHINT & (1<<RXRSMI)) ? TRUE : FALSE)
+/// Ack host wake up detection
+//#define Is_host_remote_wakeup() ((UHINT & (1<<RXRSMI)) ? TRUE : FALSE)
+#define Is_host_remote_wakeup() ((AT91C_BASE_OTGHS->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<<DCONNE))
+#define Host_enable_device_connection_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_DCONN
+/// disables USB device connection interrupt
+//#define Host_disable_device_connection_interrupt() (UHIEN &= ~(1<<DCONNE))
+#define Is_host_device_connection_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_HSTIMR & AT91C_OTGHS_DCONN)
+/// tests if a USB device has been detected
+//#define Is_device_connection() (UHINT & (1<<DCONNI))
+#define Is_device_connection() (AT91C_BASE_OTGHS->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<<DCONNI))
+#define Host_ack_device_connection() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_DCONN
+
+/// tests if a USB device has been removed
+//#define Is_device_disconnection() (UHINT & (1<<DDISCI) ? TRUE : FALSE)
+#define Is_device_disconnection() (AT91C_BASE_OTGHS->OTGHS_HSTISR & AT91C_OTGHS_DDIS)
+/// enables host device disconnection interrupt
+//#define Host_enable_device_disconnection_interrupt() (UHIEN |= (1<<DDISCE))
+#define Host_enable_device_disconnection_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_DDIS
+/// disables USB device connection interrupt
+//#define Host_disable_device_disconnection_interrupt() (UHIEN &= ~(1<<DDISCE))
+#define Host_disable_device_disconnection_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_DDIS
+//#define Is_host_device_disconnection_interrupt_enabled() ((UHIEN & (1<<DDISCE)) ? TRUE : FALSE)
+#define Is_host_device_disconnection_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_HSTIMR & AT91C_OTGHS_DDIS)
+/// tests if a USB device has been removed
+//#define Is_device_disconnection() (UHINT & (1<<DDISCI) ? TRUE : FALSE)
+//#define Is_host_device_disconnection() (AT91C_BASE_OTGHS->OTGHS_HSTISR & AT91C_OTGHS_DDIS)
+/// acks device disconnection
+//#define Host_ack_device_disconnection() (UHINT = ~(1<<DDISCI))
+#define Host_ack_device_disconnection() AT91C_BASE_OTGHS->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<<RSTE))
+/// disables host USB reset interrupt
+//#define Host_disable_reset_interrupt() (UHIEN &= ~(1<<RSTE))
+#define Host_disable_reset_interrupt() (AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_RSTI)
+//#define Is_host_reset_interrupt_enabled() ((UHIEN & (1<<RSTE)) ? TRUE : FALSE)
+/// acks host USB reset sent
+//#define Host_ack_reset() (UHINT = ~(1<<RSTI))
+#define Host_ack_reset() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_RSTI
+/// tests if USB reset has been sent
+
+
+/// switches on VBus
+//#define Host_vbus_request() (OTGCON |= (1<<VBUSREQ))
+/// switches off VBus
+//#define Host_clear_vbus_request() (OTGCON |= (1<<VBUSRQC))
+#define Host_clear_vbus_request() AT91C_BASE_OTGHS->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<<PEN))
+#define Host_enable_pipe() AT91C_BASE_OTGHS->OTGHS_HSTPIP |= (1<<global_pipe_nb)
+/// disables pipe
+//#define Host_disable_pipe() (UPCONX &= ~(1<<PEN))
+#define Host_disable_pipe() AT91C_BASE_OTGHS->OTGHS_HSTPIP &= ~(unsigned int)(1<<global_pipe_nb)
+
+/// sets SETUP token
+//#define Host_set_token_setup() (UPCFG0X = UPCFG0X & ~MSK_TOKEN_SETUP) AT91C_OTGHS_PTOKEN
+#define Host_set_token_setup() AT91C_BASE_OTGHS->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<<MSK_PEPNUM))
+//#define Host_get_endpoint_number() (UPCFG0X & (MSK_PEPNUM))
+#define Host_get_endpoint_number() (unsigned char)((AT91C_BASE_OTGHS->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<<MSK_NBUSYBK)) != 0)
+#define Is_host_one_bank_busy(pip) ((AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[pip]&AT91C_OTGHS_NBUSYBK)!=0)
+/// returns the number of busy banks
+//#define Host_number_of_busy_bank() (UPSTAX & (1<<MSK_NBUSYBK))
+
+/// resets the pipe
+//#define Host_reset_pipe(p) (UPRST = 1<<p , UPRST = 0)
+#define Host_reset_pipe(pip) AT91C_BASE_OTGHS->OTGHS_HSTPIP|=(1<<16<<pip);\
+ AT91C_BASE_OTGHS->OTGHS_HSTPIP&=~(unsigned int)(1<<16<<pip)
+
+/// writes a byte into the pipe FIFO
+//#define Host_write_byte(dat) (UPDATX = dat)
+//#define Host_write_byte(data) AT91C_BASE_OTGHS_EPTFIFO->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<<PFREEZE))
+//#define Host_freeze_pipe() TRACE_DEBUG("freeze\n\r");AT91C_BASE_OTGHS->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<<PFREEZE))
+//#define Host_unfreeze_pipe() TRACE_DEBUG("unfreeze\n\r");while(!(AT91C_BASE_OTGHS->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<<PFREEZE))
+#define Is_host_pipe_freeze() (AT91C_BASE_OTGHS->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<<TXOUTI)) ? TRUE : FALSE)
+#define Is_host_control_out_sent() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXOUT)
+/// tests if a STALL has been received
+//#define Is_host_stall() ((UPINTX & (1<<RXSTALLI)) ? TRUE : FALSE)
+#define Is_host_stall() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RXSTALL)
+/// tests if an error occurs on current pipe
+//#define Is_host_pipe_error() ((UPINTX & (1<<PERRI)) ? TRUE : FALSE)
+#define Is_host_pipe_error() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_PERR)
+
+/// sends a setup
+//#define Host_send_setup() (UPINTX &= ~(1<<FIFOCON))
+#define Host_send_setup() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON
+/// sends a control IN
+//#define Host_send_control_in() (UPINTX &= ~(1<<FIFOCON))
+#define Host_send_control_in() AT91C_BASE_OTGHS->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<<FIFOCON))
+#define Host_send_control_out() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON
+
+/// acks control OUT
+//#define Host_ack_control_out() (UPINTX &= ~(1<<TXOUTI))
+#define Host_ack_control_out() AT91C_BASE_OTGHS->OTGHS_HSTPIPICR[0] = AT91C_OTGHS_TXOUT
+/// acks control IN
+//#define Host_ack_control_in() (UPINTX &= ~(1<<RXINI))
+#define Host_ack_control_in() AT91C_BASE_OTGHS->OTGHS_HSTPIPICR[0] = AT91C_OTGHS_RXINI
+/// acks setup
+//#define Host_ack_setup() (UPINTX &= ~(1<<TXSTPI))
+#define Host_ack_setup() AT91C_BASE_OTGHS->OTGHS_HSTPIPICR[0] = AT91C_OTGHS_TXSTPI
+/// acks STALL reception
+//#define Host_ack_stall() (UPINTX &= ~(1<<RXSTALLI))
+#define Host_ack_stall() AT91C_BASE_OTGHS->OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_RXSTALL
+
+/// sends a OUT
+//#define Host_send_out() (UPINTX &= ~(1<<FIFOCON))
+#define Host_send_out() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FIFOCON
+/// tests if OUT has been sent
+//#define Is_host_out_sent() ((UPINTX & (1<<TXOUTI)) ? TRUE : FALSE)
+#define Is_host_out_sent() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_TXOUT)
+/// acks OUT sent
+//#define Host_ack_out_sent() (UPINTX &= ~(1<<TXOUTI))
+#define Host_ack_out_sent() AT91C_BASE_OTGHS->OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_TXOUT
+
+/// tests if IN received
+//#define Is_host_in_received() ((UPINTX & (1<<RXINI)) ? TRUE : FALSE)
+#define Is_host_in_received() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RXINI)
+/// acks IN reception
+//#define Host_ack_in_received() (UPINTX &= ~(1<<RXINI))
+#define Host_ack_in_received() AT91C_BASE_OTGHS->OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_RXINI
+/// sends a IN
+//#define Host_send_in() (UPINTX &= ~(1<<FIFOCON))
+#define Host_send_in() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FIFOCON
+/// tests if nak handshake has been received
+//#define Is_host_nak_received() ((UPINTX & (1<<NAKEDI)) ? TRUE : FALSE)
+#define Is_host_nak_received() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_NAKEDI)
+/// acks NAk received sent
+//#define Host_ack_nak_received() (UPINTX &= ~(1<<NAKEDI))
+#define Host_ack_nak_received() AT91C_BASE_OTGHS->OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_NAKEDI
+
+/// tests if endpoint read allowed
+//#define Is_host_read_enabled() (UPINTX&(1<<RWAL))
+#define Is_host_read_enabled() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RWALL)
+/// tests if endpoint read allowed
+//#define Is_host_write_enabled() (UPINTX&(1<<RWAL))
+
+/// sets IN in standard mode
+//#define Host_standard_in_mode() (UPCONX &= ~(1<<INMODE))
+#define Host_standard_in_mode() AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_INMOD
+/// sets IN in continuous mode
+//#define Host_continuous_in_mode() (UPCONX |= (1<<INMODE))
+#define Host_continuous_in_mode() AT91C_BASE_OTGHS->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<<TXOUTE))
+#define Host_enable_transmit_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_TXOUT
+/// Disable pipe end transmission interrupt
+//#define Host_disable_transmit_interrupt() (UPIENX &= ~(1<<TXOUTE))
+#define Host_disable_transmit_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_TXOUT
+
+/// Enable pipe reception interrupt
+//#define Host_enable_receive_interrupt() (UPIENX |= (1<<RXINE))
+#define Host_enable_receive_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_RXINI
+/// Disable pipe recption interrupt
+//#define Host_disable_receive_interrupt() (UPIENX &= ~(1<<RXINE))
+#define Host_disable_receive_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_RXINI
+
+/// Enable pipe stall interrupt
+//#define Host_enable_stall_interrupt() (UPIENX |= (1<<RXSTALLE))
+#define Host_enable_stall_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_RXSTALL
+/// Disable pipe stall interrupt
+//#define Host_disable_stall_interrupt() (UPIENX &= ~(1<<RXSTALLE))
+#define Host_disable_stall_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_RXSTALL
+
+/// Enable pipe error interrupt
+//#define Host_enable_error_interrupt() (UPIENX |= (1<<PERRE))
+#define Host_enable_error_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_PERR
+/// Disable pipe error interrupt
+//#define Host_disable_error_interrupt() (UPIENX &= ~(1<<PERRE))
+#define Host_disable_error_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_PERR
+
+/// Enable pipe NAK interrupt
+//#define Host_enable_nak_interrupt() (UPIENX |= (1<<NAKEDE))
+#define Host_enable_nak_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_NAKEDI
+/// Disable pipe NAK interrupt
+//#define Host_disable_nak_interrupt() (UPIENX &= ~(1<<NAKEDE))
+#define Host_disable_nak_interrupt() AT91C_BASE_OTGHS->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 <conf_usb.h>
+#include "usb/otg/usb_drv.h"
+#include "usb_host_enum.h"
+#include "usb/otg/usb_task.h"
+#include "usb_host_task.h"
+#include <utility/trace.h>
+#include <usb/common/core/USBGenericDescriptor.h>
+
+//------------------------------------------------------------------------------
+// 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<nb_interface_supported;i++)
+ {
+ ep_index=0;
+ // First look for the target interface descriptor offset
+ descriptor_offset = get_interface_descriptor_offset(interface_supported[i].interface_nb,interface_supported[i].altset_nb);
+ // Get the number of endpoint to configure for this interface
+ nb_endpoint_to_configure = data_stage[descriptor_offset+OFFSET_FIELS_NB_OF_EP];
+ // Get the first Endpoint descriptor offset to configure
+ descriptor_offset += data_stage[descriptor_offset+OFFSET_DESCRIPTOR_LENGHT]; // pointing on endpoint descriptor
+
+ // While there is at least one pipe to configure
+ while (nb_endpoint_to_configure)
+ {
+ // Check and look for an Endpoint descriptor
+ while (data_stage[descriptor_offset+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_ENDPOINT)
+ {
+ descriptor_offset += data_stage[descriptor_offset];
+ if(descriptor_offset > 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<nb_interface_supported;i++)
+ }
+ Host_set_configured();
+ return HOST_TRUE;
+}
+
+//------------------------------------------------------------------------------
+/// returns the offset in data_stage where to find the interface descriptor
+/// whose number and alternate setting values are passed as parameters
+//------------------------------------------------------------------------------
+T_DESC_OFFSET get_interface_descriptor_offset(U8 interface, U8 alt)
+{
+ T_DESC_OFFSET descriptor_offset;
+
+ TRACE_DEBUG("get_interface_descriptor_offset\n\r");
+ //nb_interface = data_stage[OFFSET_FIELD_NB_INTERFACE]; // Detects the number of interfaces in this configuration
+ descriptor_offset = data_stage[OFFSET_DESCRIPTOR_LENGHT]; // now pointing on next descriptor
+
+ while(descriptor_offset < SIZEOF_DATA_STAGE) // Look in all interfaces declared in the configuration
+ {
+ while (data_stage[descriptor_offset+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_INTERFACE)
+ {
+ descriptor_offset += data_stage[descriptor_offset];
+ if(descriptor_offset > 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; i<MAX_EP_NB; i++)
+ {
+ if(ep_table[i] == ep_addr)
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// generic Pipe 0 management function
+/// used to send and receive control request over pipe 0
+//------------------------------------------------------------------------------
+U8 host_send_control(U8* data_pointer)
+{
+ U16 data_length;
+ U8 sav_int_sof_enable;
+ U16 status;
+ int *pFifoInt;
+
+ Usb_ack_event(EVT_HOST_SOF);
+ sav_int_sof_enable=Is_host_sof_interrupt_enabled();
+ Host_enable_sof_interrupt(); // SOF software detection is in interrupt sub-routine
+ while(Is_not_usb_event(EVT_HOST_SOF)) // Wait 1 sof
+ {
+ if (Is_host_emergency_exit())
+ {
+ status=CONTROL_TIMEOUT;
+ TRACE_DEBUG("Is_host_emergency_exit\n\r");
+ Host_freeze_pipe();
+ Host_reset_pipe(0);
+ goto host_send_control_end;
+ }
+ }
+ if (sav_int_sof_enable==FALSE)
+ {
+ Host_disable_sof_interrupt(); // enter in suspend mode
+ }
+
+ Host_select_pipe(0);
+ Host_set_token_setup();
+ Host_ack_setup();
+ Host_unfreeze_pipe();
+
+ // Send the setup request fields
+ pFifoInt = (int*)&usb_request;
+ Host_write_32(*pFifoInt);
+ pFifoInt++;
+ Host_write_32(*pFifoInt);
+
+ Host_send_setup();
+
+ while(Is_host_setup_sent() == FALSE) // wait for SETUP ack
+ {
+ 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()) // Any error ?
+ {
+ status = Host_error_status();
+ Host_ack_all_errors();
+ goto host_send_control_end; // Send error status
+ }
+ }
+
+ // Setup token sent now send In or OUT token
+ // Before just wait one SOF
+ Usb_ack_event(EVT_HOST_SOF);
+ sav_int_sof_enable=Is_host_sof_interrupt_enabled();
+ Host_enable_sof_interrupt();
+ Host_freeze_pipe();
+ data_length = usb_request.wLength;
+ while(Is_not_usb_event(EVT_HOST_SOF)) // Wait 1 sof
+ {
+ if (Is_host_emergency_exit())
+ {
+ status=CONTROL_TIMEOUT;
+ Host_freeze_pipe();
+ Host_reset_pipe(0);
+ goto host_send_control_end;
+ }
+ }
+ if (sav_int_sof_enable==FALSE)
+ {
+ Host_disable_sof_interrupt();
+ } // Restore SOF interrupt enable
+
+ // IN request management ---------------------------------------------
+ if(usb_request.bmRequestType & 0x80) // bmRequestType : Data stage IN (bmRequestType==1)
+ {
+ Host_standard_in_mode();
+ //jcb // We send 1 IN
+ // Host_in_request_number(0, 0);
+ Host_set_token_in();
+ while(data_length != 0)
+ {
+ 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;
+ }
+ }
+ status = Host_data_length_U8();
+ if (status == host_get_pipe_length())
+ {
+ data_length -= status;
+ if (usb_request.uncomplete_read == TRUE) // uncomplete_read
+ {
+ data_length = 0;
+ }
+ }
+ else
+ {
+ data_length = 0;
+ }
+ Address_fifochar_endpoint(0);
+
+ while (status!=0)
+ {
+ *data_pointer = Host_read_byte();
+ data_pointer++;
+ status--;
+ }
+ Host_freeze_pipe();
+ Host_ack_control_in();
+ Host_send_control_in();
+ //jcb
+ // if( 0 != data_length )
+ // {
+ // Host_unfreeze_pipe();
+ // }
+ } // end of IN data stage
+ Host_set_token_out();
+ Host_unfreeze_pipe();
+ Host_ack_control_out();
+ 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;
+ }
+ }
+
+ // Test Low Speed
+ if( AT91C_OTGHS_SPEED_SR_LS == (*AT91C_OTGHS_SR & AT91C_OTGHS_SPEED_SR_LS)) {
+ TRACE_DEBUG("LOW SPEED\n\r");
+ // Reset UTMI
+ *AT91C_OTGHS_TSTA2 |= AT91C_OTGHS_UTMIRESET;
+ *AT91C_OTGHS_TSTA2 &= ~(unsigned int)AT91C_OTGHS_UTMIRESET;
+ }
+ Host_ack_control_out();
+ // Wait end of transfer
+ while( (AT91C_BASE_OTGHS->OTGHS_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 <usb/common/core/USBFeatureRequest.h>
+#include <usb/common/core/USBEndpointDescriptor.h>
+#include <usb/common/core/USBGenericRequest.h>
+#include <usb/common/core/USBGenericDescriptor.h>
+#include <usb/otg/usb_task.h>
+
+//------------------------------------------------------------------------------
+// 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<<BIT_SELF_POWERED)) ? TRUE : FALSE)
+
+#define BIT_REMOTE_WAKEUP 5 // offset
+/// returns true if the device supports remote wake_up
+#define Is_device_supports_remote_wakeup() ((bmattributes & (1<<BIT_REMOTE_WAKEUP)) ? TRUE : FALSE)
+
+#define BIT_SRP_SUPPORT 0 // offset
+/// returns true if the device supports SRP
+#define Is_device_supports_srp() ((otg_features_supported & (1<<BIT_SRP_SUPPORT)) ? TRUE : FALSE)
+
+#define BIT_HNP_SUPPORT 1 // offset
+/// returns true if the device supports HNP
+#define Is_device_supports_hnp() ((otg_features_supported & (1<<BIT_HNP_SUPPORT)) ? TRUE : FALSE)
+
+
+//------------------------------------------------------------------------------
+// Exported variables
+//------------------------------------------------------------------------------
+extern U8 ep_table[];
+extern U8 nb_interface_supported;
+extern S_interface interface_supported[MAX_INTERFACE_SUPPORTED];
+extern U16 device_PID;
+extern U16 device_VID;
+extern U8 bmattributes;
+extern U8 maxpower;
+
+//-----------------------------------------------------------------------------
+// Exported functions
+//-----------------------------------------------------------------------------
+extern U8 host_check_VID_PID(void);
+extern U8 host_check_OTG_features(void);
+extern U8 host_check_class (void);
+extern U8 host_auto_configure_endpoint(void);
+extern T_DESC_OFFSET get_interface_descriptor_offset(U8 interface, U8 alt);
+extern U8 host_get_hwd_pipe_nb(U8 ep_addr);
+extern U8 host_send_control(U8*);
+
+
+#endif // _USB_HOST_ENUM_H_
+
diff --git a/usb/otg/usb_host_enum_with_srp_hnp.c b/usb/otg/usb_host_enum_with_srp_hnp.c new file mode 100644 index 0000000..0220515 --- /dev/null +++ b/usb/otg/usb_host_enum_with_srp_hnp.c @@ -0,0 +1,754 @@ +/* ----------------------------------------------------------------------------
+ * 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 <conf_usb.h>
+#include "usb/otg/usb_drv.h"
+#include "usb_host_enum.h"
+#include "usb/otg/usb_task.h"
+#include "usb_host_task.h"
+#include <utility/trace.h>
+#include <usb/common/core/USBGenericDescriptor.h>
+
+//------------------------------------------------------------------------------
+// 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<nb_interface_supported;i++)
+ {
+ ep_index=0;
+ // First look for the target interface descriptor offset
+ descriptor_offset = get_interface_descriptor_offset(interface_supported[i].interface_nb,interface_supported[i].altset_nb);
+ // Get the number of endpoint to configure for this interface
+ nb_endpoint_to_configure = data_stage[descriptor_offset+OFFSET_FIELS_NB_OF_EP];
+ // Get the first Endpoint descriptor offset to configure
+ descriptor_offset += data_stage[descriptor_offset+OFFSET_DESCRIPTOR_LENGHT]; // pointing on endpoint descriptor
+
+ // While there is at least one pipe to configure
+ while (nb_endpoint_to_configure)
+ {
+ // Check and look for an Endpoint descriptor
+ while (data_stage[descriptor_offset+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_ENDPOINT)
+ {
+ descriptor_offset += data_stage[descriptor_offset];
+ if(descriptor_offset > 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<nb_interface_supported;i++)
+ }
+ Host_set_configured();
+ return HOST_TRUE;
+}
+
+//------------------------------------------------------------------------------
+/// returns the offset in data_stage where to find the interface descriptor
+/// whose number and alternate setting values are passed as parameters
+//------------------------------------------------------------------------------
+T_DESC_OFFSET get_interface_descriptor_offset(U8 interface, U8 alt)
+{
+ T_DESC_OFFSET descriptor_offset;
+
+ TRACE_DEBUG("get_interface_descriptor_offset\n\r");
+ //nb_interface = data_stage[OFFSET_FIELD_NB_INTERFACE]; // Detects the number of interfaces in this configuration
+ descriptor_offset = data_stage[OFFSET_DESCRIPTOR_LENGHT]; // now pointing on next descriptor
+
+ while(descriptor_offset < SIZEOF_DATA_STAGE) // Look in all interfaces declared in the configuration
+ {
+ while (data_stage[descriptor_offset+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_INTERFACE)
+ {
+ descriptor_offset += data_stage[descriptor_offset];
+ if(descriptor_offset > 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; i<MAX_EP_NB; i++)
+ {
+ if(ep_table[i] == ep_addr)
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// generic Pipe 0 management function
+/// used to send and receive control request over pipe 0
+//------------------------------------------------------------------------------
+U8 host_send_control(U8* data_pointer)
+{
+ U16 data_length;
+ U8 sav_int_sof_enable;
+ U16 status;
+ int *pFifoInt;
+
+ Usb_ack_event(EVT_HOST_SOF);
+ sav_int_sof_enable=Is_host_sof_interrupt_enabled();
+ Host_enable_sof_interrupt(); // SOF software detection is in interrupt sub-routine
+ while(Is_not_usb_event(EVT_HOST_SOF)) // Wait 1 sof
+ {
+ if (Is_host_emergency_exit())
+ {
+ status=CONTROL_TIMEOUT;
+ TRACE_DEBUG("Is_host_emergency_exit\n\r");
+ Host_freeze_pipe();
+ Host_reset_pipe(0);
+ goto host_send_control_end;
+ }
+ }
+ if (sav_int_sof_enable==FALSE)
+ {
+ Host_disable_sof_interrupt(); // enter in suspend mode
+ }
+
+ Host_select_pipe(0);
+ Host_set_token_setup();
+ Host_ack_setup();
+ Host_unfreeze_pipe();
+
+ // Send the setup request fields
+ pFifoInt = (int*)&usb_request;
+ Host_write_32(*pFifoInt);
+ pFifoInt++;
+ Host_write_32(*pFifoInt);
+
+ Host_send_setup();
+
+ while(Is_host_setup_sent() == FALSE) // wait for SETUP ack
+ {
+ 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_emergency_exit())
+ {
+ status = CONTROL_TIMEOUT;
+ Host_freeze_pipe();
+ Host_reset_pipe(0);
+ goto host_send_control_end;
+ }
+ if(Is_host_pipe_error()) // Any error ?
+ {
+ status = Host_error_status();
+ Host_ack_all_errors();
+ goto host_send_control_end; // Send error status
+ }
+ }
+
+ // Setup token sent now send In or OUT token
+ // Before just wait one SOF
+ Usb_ack_event(EVT_HOST_SOF);
+ sav_int_sof_enable=Is_host_sof_interrupt_enabled();
+ Host_enable_sof_interrupt();
+ Host_freeze_pipe();
+ data_length = usb_request.wLength;
+ while(Is_not_usb_event(EVT_HOST_SOF)) // Wait 1 sof
+ {
+ if (Is_host_emergency_exit())
+ {
+ status=CONTROL_TIMEOUT;
+ Host_freeze_pipe();
+ Host_reset_pipe(0);
+ goto host_send_control_end;
+ }
+ }
+ if (sav_int_sof_enable==FALSE)
+ {
+ Host_disable_sof_interrupt();
+ } // Restore SOF interrupt enable
+
+ // IN request management ---------------------------------------------
+ if(usb_request.bmRequestType & 0x80) // bmRequestType : Data stage IN (bmRequestType==1)
+ {
+ Host_standard_in_mode();
+ //jcb // We send 1 IN
+ // Host_in_request_number(0, 0);
+ Host_set_token_in();
+ while(data_length != 0)
+ {
+ 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;
+ }
+ }
+ status = Host_data_length_U8();
+ if (status == host_get_pipe_length())
+ {
+ data_length -= status;
+ if (usb_request.uncomplete_read == TRUE) // uncomplete_read
+ {
+ data_length = 0;
+ }
+ }
+ else
+ {
+ data_length = 0;
+ }
+ Address_fifochar_endpoint(0);
+
+ while (status!=0)
+ {
+ *data_pointer = Host_read_byte();
+ data_pointer++;
+ status--;
+ }
+ Host_freeze_pipe();
+ Host_ack_control_in();
+ Host_send_control_in();
+ } // end of IN data stage
+ Host_set_token_out();
+ Host_unfreeze_pipe();
+ Host_ack_control_out();
+ Host_send_control_out();
+
+ while(!Is_host_control_out_sent())
+ {
+ 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_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;
+ }
+ }
+
+ // Test Low Speed
+ if( AT91C_OTGHS_SPEED_SR_LS == (*AT91C_OTGHS_SR & AT91C_OTGHS_SPEED_SR_LS)) {
+ TRACE_DEBUG("LOW SPEED\n\r");
+ // Reset UTMI
+ *AT91C_OTGHS_TSTA2 |= AT91C_OTGHS_UTMIRESET;
+ *AT91C_OTGHS_TSTA2 &= ~(unsigned int)AT91C_OTGHS_UTMIRESET;
+ }
+ Host_ack_control_out();
+ // Wait end of transfer
+ while( (AT91C_BASE_OTGHS->OTGHS_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 <memories/Media.h>
+#include "conf_usb.h"
+#include <usb/common/core/USBConfigurationOTG.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/massstorage/MSDDriver.h>
+#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 <utility/trace.h>
+#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; i<SIZEOF_DATA_STAGE; i++ ) {
+ data_stage[i] = 0;
+ }
+ Usb_disable();
+ Usb_enable();
+ Usb_unfreeze_clock();
+ USBD_Connect();
+ Usb_enable_uvcon_pin();
+ Usb_select_host();
+ Usb_disable_vbus_hw_control(); // Force Vbus generation without timeout
+ Host_enable_device_disconnection_interrupt();
+ 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;
+
+ //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; hostSOFCounter<MAX_EP_NB; hostSOFCounter++) {
+ ep_table[hostSOFCounter]=0;
+ }// Reset PIPE lookup table with device EP addr
+ nb_interface_supported=0;
+ Host_clear_device_supported(); // Reset Device status
+ Host_clear_configured();
+ Host_clear_device_ready();
+ Usb_clear_all_event(); // Clear all software events
+ new_device_connected=0;
+ if (Is_usb_id_host()) {
+ if(pOTGDescriptor->bOTGSoftwareVbusCtrl == 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<WAIT_100MS) { // wait 100ms after USB reset
+ if (Is_usb_event(EVT_HOST_SOF)) {
+ Usb_ack_event(EVT_HOST_SOF);
+ hostSOFCounter++;
+ }// Count Start Of frame
+ if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {
+ TRACE_DEBUG("goto error 2\n\r");
+ goto device_attached_error;
+ }
+ }
+ device_state = DEVICE_POWERED;
+ hostSOFCounter=0;
+
+ }
+
+
+device_attached_error:
+ // Device connection error, or vbus pb -> 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()<host_get_pipe_length()))
+ {
+ n = 0;
+ }
+ else
+ {
+ n -= Host_byte_counter();
+ }
+ (*nb_data) += Host_byte_counter(); // Update nb of byte received
+
+ Address_fifochar_endpoint(global_pipe_nb);
+ for (i=Host_byte_counter(); i; i--)
+ {
+ *buf = Host_read_byte();
+ buf++;
+ }
+ }
+ else // more bytes received than expected
+ { // TODO error code management
+ *nb_data += n;
+ Address_fifochar_endpoint(global_pipe_nb);
+ for (i=n; i; i--) // Byte number limited to the initial request (limit tab over pb)
+ {
+ *buf = Host_read_byte();
+ buf++;
+ }
+ n=0;
+ }
+ Host_ack_in_received();
+ }
+
+ Host_freeze_pipe();
+
+host_get_data_end:
+ if (sav_int_sof_enable==FALSE)
+ {
+ Host_disable_sof_interrupt();
+ }
+ return ((U8)status);
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void reset_it_pipe_str(void)
+{
+ U8 i;
+ TRACE_DEBUG("reset_it_pipe_str\n\r");
+ for(i=0;i<MAX_EP_NB;i++)
+ {
+ it_pipe_str[i].enable=DISABLE;
+ it_pipe_str[i].timeout=0;
+ }
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+U8 is_any_interrupt_pipe_active(void)
+{
+ U8 i;
+ TRACE_DEBUG("is_any_interrupt_pipe_active\n\r");
+ for(i=0;i<MAX_EP_NB;i++)
+ {
+ if(it_pipe_str[i].enable==ENABLE) return TRUE;
+ }
+ return FALSE;
+}
+
+//------------------------------------------------------------------------------
+/// 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_interrupt(U8 pipe, U16 nb_data, U8 *buf,void(*handle)(U8 status, U16 nb_byte))
+{
+ TRACE_DEBUG("host_get_data_interrupt\n\r");
+ Host_select_pipe(pipe);
+ if(it_pipe_str[pipe].enable==ENABLE)
+ {
+ return HOST_FALSE;
+ }
+ else
+ {
+ if(is_any_interrupt_pipe_active()==FALSE)
+ {
+ g_sav_int_sof_enable=Is_host_sof_interrupt_enabled();
+ Host_enable_sof_interrupt();
+ }
+ it_pipe_str[pipe].enable=ENABLE;
+ it_pipe_str[pipe].nb_byte_to_process=nb_data;
+ it_pipe_str[pipe].nb_byte_processed=0;
+ it_pipe_str[pipe].ptr_buf=buf;
+ it_pipe_str[pipe].handle=handle;
+ it_pipe_str[pipe].timeout=0;
+ it_pipe_str[pipe].nak_timeout=NAK_RECEIVE_TIMEOUT;
+
+ private_sof_counter=0; // Reset the counter in SOF detection sub-routine
+ Host_reset_pipe(pipe);
+ Host_enable_stall_interrupt();
+#if (NAK_TIMEOUT_ENABLE==ENABLE)
+ Host_enable_nak_interrupt();
+#endif
+ Host_enable_error_interrupt();
+ Host_enable_receive_interrupt();
+ Host_ack_stall();
+ Host_ack_nak_received();
+
+ Host_continuous_in_mode();
+ Host_set_token_in();
+ Host_unfreeze_pipe();
+ return HOST_TRUE;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// This function send nb_data pointed with *buf with the pipe number specified
+//------------------------------------------------------------------------------
+U8 host_send_data_interrupt(U8 pipe,
+ U16 nb_data,
+ U8 *buf,
+ void(*handle)(U8 status, U16 nb_byte))
+{
+ U16 i;
+ U8 *ptr_buf=buf;
+
+ TRACE_DEBUG("host_send_data_interrupt\n\r");
+ Host_select_pipe(pipe);
+ if(it_pipe_str[pipe].enable==ENABLE)
+ {
+ return HOST_FALSE;
+ }
+ else
+ {
+ if(is_any_interrupt_pipe_active()==FALSE)
+ {
+ g_sav_int_sof_enable=Is_host_sof_interrupt_enabled();
+ Host_enable_sof_interrupt();
+ }
+ it_pipe_str[pipe].enable=ENABLE;
+ it_pipe_str[pipe].nb_byte_to_process=nb_data;
+ it_pipe_str[pipe].nb_byte_processed=0;
+ it_pipe_str[pipe].ptr_buf=buf;
+ it_pipe_str[pipe].handle=handle;
+
+ it_pipe_str[pipe].timeout=0;
+ it_pipe_str[pipe].nak_timeout=NAK_SEND_TIMEOUT;
+ it_pipe_str[pipe].nb_byte_on_going=0;
+
+ Host_reset_pipe(pipe);
+ Host_unfreeze_pipe();
+ // Prepare data to be sent
+ i = host_get_pipe_length();
+ if ( i > 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()<host_get_pipe_length())) //Received less than remaining, but less than pipe capacity
+ {
+ n=0;
+ }
+ else
+ {
+ n-=Host_byte_counter();
+ }
+ it_pipe_str[pipe_nb].nb_byte_processed += Host_byte_counter(); // Update nb of byte received
+
+ Address_fifochar_endpoint(global_pipe_nb);
+ for (i=Host_byte_counter();i;i--)
+ {
+ *ptr_buf = Host_read_byte();
+ ptr_buf++;
+ }
+ }
+ else // more bytes received than expected
+ { // TODO error code management
+ it_pipe_str[pipe_nb].nb_byte_processed+=n;
+ Address_fifochar_endpoint(global_pipe_nb);
+ for ( i=n; i; i-- ) // Byte number limited to the initial request (limit tab over pb)
+ {
+ *ptr_buf = Host_read_byte();
+ ptr_buf++;
+ }
+ n=0;
+ }
+ Host_ack_in_received();
+ if(n>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 <conf_usb.h>
+#include <usb/otg/usb_host_enum.h>
+
+#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<30s)
+#define Init_ta_srp_counter() (otg_ta_srp_wait_connect = 0)
+#define Is_ta_srp_counter_overflow() ((otg_ta_srp_wait_connect > 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 <memories/Media.h>
+#include "conf_usb.h"
+#include <conf_scheduler.h>
+#include <usb/common/core/USBConfigurationOTG.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/massstorage/MSDDriver.h>
+#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 <utility/trace.h>
+#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; i<SIZEOF_DATA_STAGE; i++ ) {
+ data_stage[i] = 0;
+ }
+ Usb_disable();
+ Usb_enable();
+ Usb_unfreeze_clock();
+ USBD_Connect();
+ Usb_enable_uvcon_pin();
+ Usb_select_host();
+ Usb_disable_vbus_hw_control(); // Force Vbus generation without timeout
+ Host_enable_device_disconnection_interrupt();
+ Usb_enable_id_interrupt();
+ if( pOTGDescriptor->bOTGADevSRPReaction == 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; hostSOFCounter<MAX_EP_NB; hostSOFCounter++) {
+ ep_table[hostSOFCounter]=0;
+ }// Reset PIPE lookup table with device EP addr
+ nb_interface_supported=0;
+ Host_clear_device_supported(); // Reset Device status
+ Host_clear_configured();
+ Host_clear_device_ready();
+ Usb_clear_all_event(); // Clear all software events
+ new_device_connected=0;
+ Host_end_session_started_srp();
+ Peripheral_is_not_otg_device();
+ Usb_host_reject_hnp();
+ Usb_disable_role_exchange_interrupt();
+ Usb_disable_hnp_error_interrupt();
+ if (Is_usb_id_host()) {
+ if(pOTGDescriptor->bOTGSoftwareVbusCtrl == 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) { // wait 100ms after USB reset
+ if (Is_usb_event(EVT_HOST_SOF)) {
+ Usb_ack_event(EVT_HOST_SOF);
+ hostSOFCounter++;
+ }// Count Start Of frame
+ if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {
+ TRACE_DEBUG("goto error 2\n\r");
+ goto device_attached_error;
+ }
+ if (Is_usb_device_enabled()) {
+ break;
+ }
+ }
+ device_state = DEVICE_POWERED;
+ hostSOFCounter=0;
+
+ }
+
+
+ device_attached_error:
+ 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
+ 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()<host_get_pipe_length()))
+ {
+ n = 0;
+ }
+ else
+ {
+ n -= Host_byte_counter();
+ }
+ (*nb_data) += Host_byte_counter(); // Update nb of byte received
+
+ Address_fifochar_endpoint(global_pipe_nb);
+ for (i=Host_byte_counter(); i; i--)
+ {
+ *buf = Host_read_byte();
+ buf++;
+ }
+ }
+ else // more bytes received than expected
+ { // TODO error code management
+ *nb_data += n;
+ Address_fifochar_endpoint(global_pipe_nb);
+ for (i=n; i; i--) // Byte number limited to the initial request (limit tab over pb)
+ {
+ *buf = Host_read_byte();
+ buf++;
+ }
+ n=0;
+ }
+ Host_ack_in_received();
+ }
+
+ Host_freeze_pipe();
+
+host_get_data_end:
+ if (sav_int_sof_enable==FALSE)
+ {
+ Host_disable_sof_interrupt();
+ }
+ return ((U8)status);
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void reset_it_pipe_str(void)
+{
+ U8 i;
+ TRACE_DEBUG("reset_it_pipe_str\n\r");
+ for(i=0;i<MAX_EP_NB;i++)
+ {
+ it_pipe_str[i].enable=DISABLE;
+ it_pipe_str[i].timeout=0;
+ }
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+U8 is_any_interrupt_pipe_active(void)
+{
+ U8 i;
+ TRACE_DEBUG("is_any_interrupt_pipe_active\n\r");
+ for(i=0;i<MAX_EP_NB;i++)
+ {
+ if(it_pipe_str[i].enable==ENABLE) return TRUE;
+ }
+ return FALSE;
+}
+
+//------------------------------------------------------------------------------
+/// 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_interrupt(U8 pipe, U16 nb_data, U8 *buf,void(*handle)(U8 status, U16 nb_byte))
+{
+ TRACE_DEBUG("host_get_data_interrupt\n\r");
+ Host_select_pipe(pipe);
+ if(it_pipe_str[pipe].enable==ENABLE)
+ {
+ return HOST_FALSE;
+ }
+ else
+ {
+ if(is_any_interrupt_pipe_active()==FALSE)
+ {
+ g_sav_int_sof_enable=Is_host_sof_interrupt_enabled();
+ Host_enable_sof_interrupt();
+ }
+ it_pipe_str[pipe].enable=ENABLE;
+ it_pipe_str[pipe].nb_byte_to_process=nb_data;
+ it_pipe_str[pipe].nb_byte_processed=0;
+ it_pipe_str[pipe].ptr_buf=buf;
+ it_pipe_str[pipe].handle=handle;
+ it_pipe_str[pipe].timeout=0;
+ it_pipe_str[pipe].nak_timeout=NAK_RECEIVE_TIMEOUT;
+
+ private_sof_counter=0; // Reset the counter in SOF detection sub-routine
+ Host_reset_pipe(pipe);
+ Host_enable_stall_interrupt();
+#if (NAK_TIMEOUT_ENABLE==ENABLE)
+ Host_enable_nak_interrupt();
+#endif
+ Host_enable_error_interrupt();
+ Host_enable_receive_interrupt();
+ Host_ack_stall();
+ Host_ack_nak_received();
+
+ Host_continuous_in_mode();
+ Host_set_token_in();
+ Host_unfreeze_pipe();
+ return HOST_TRUE;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// This function send nb_data pointed with *buf with the pipe number specified
+//------------------------------------------------------------------------------
+U8 host_send_data_interrupt(U8 pipe,
+ U16 nb_data,
+ U8 *buf,
+ void(*handle)(U8 status, U16 nb_byte))
+{
+ U16 i;
+ U8 *ptr_buf=buf;
+
+ TRACE_DEBUG("host_send_data_interrupt\n\r");
+ Host_select_pipe(pipe);
+ if(it_pipe_str[pipe].enable==ENABLE)
+ {
+ return HOST_FALSE;
+ }
+ else
+ {
+ if(is_any_interrupt_pipe_active()==FALSE)
+ {
+ g_sav_int_sof_enable=Is_host_sof_interrupt_enabled();
+ Host_enable_sof_interrupt();
+ }
+ it_pipe_str[pipe].enable=ENABLE;
+ it_pipe_str[pipe].nb_byte_to_process=nb_data;
+ it_pipe_str[pipe].nb_byte_processed=0;
+ it_pipe_str[pipe].ptr_buf=buf;
+ it_pipe_str[pipe].handle=handle;
+
+ it_pipe_str[pipe].timeout=0;
+ it_pipe_str[pipe].nak_timeout=NAK_SEND_TIMEOUT;
+ it_pipe_str[pipe].nb_byte_on_going=0;
+
+ Host_reset_pipe(pipe);
+ Host_unfreeze_pipe();
+ // Prepare data to be sent
+ i = host_get_pipe_length();
+ if ( i > 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()<host_get_pipe_length())) //Received less than remaining, but less than pipe capacity
+ {
+ n=0;
+ }
+ else
+ {
+ n-=Host_byte_counter();
+ }
+ it_pipe_str[pipe_nb].nb_byte_processed += Host_byte_counter(); // Update nb of byte received
+
+ Address_fifochar_endpoint(global_pipe_nb);
+ for (i=Host_byte_counter();i;i--)
+ {
+ *ptr_buf = Host_read_byte();
+ ptr_buf++;
+ }
+ }
+ else // more bytes received than expected
+ { // TODO error code management
+ it_pipe_str[pipe_nb].nb_byte_processed+=n;
+ Address_fifochar_endpoint(global_pipe_nb);
+ for ( i=n; i; i-- ) // Byte number limited to the initial request (limit tab over pb)
+ {
+ *ptr_buf = Host_read_byte();
+ ptr_buf++;
+ }
+ n=0;
+ }
+ Host_ack_in_received();
+ if(n>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 <memories/Media.h>
+#include "main.h"
+#include <msd/conf_usb.h>
+#include <utility/trace.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/massstorage/MSDDriver.h>
+#include <usb/device/massstorage/MSDLun.h>
+#include <usb/device/core/USBDCallbacks.h>
+#include <usb/common/core/USBFeatureRequest.h>
+#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 <memories/Media.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/massstorage/MSDDriver.h>
+#include <usb/device/massstorage/MSDLun.h>
+#include <usb/device/core/USBDCallbacks.h>
+#include <usb/device/massstorage/MSD.h>
+#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;i<MAX_EP_NB;i++) {
+ if(it_pipe_str[i].enable==ENABLE) {
+ save_pipe_nb=Host_get_selected_pipe();
+ Host_select_pipe(i);
+ if((++it_pipe_str[i].timeout>TIMEOUT_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 <otg_user_task.h>
+
+//------------------------------------------------------------------------------
+// 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<<x)
+#define Usb_ack_event(x) g_usb_event &= ~(1<<x)
+#define Usb_clear_all_event() g_usb_event = 0
+#define Is_usb_event(x) ((g_usb_event & (1<<x)) ? TRUE : FALSE)
+#define Is_not_usb_event(x) ((g_usb_event & (1<<x)) ? FALSE: TRUE)
+
+#define Is_host_emergency_exit() (Is_usb_event(EVT_HOST_DISCONNECTION) || Is_usb_event(EVT_USB_DEVICE_FUNCTION))
+//#define Is_usb_device() ((g_usb_mode==USB_MODE_DEVICE) ? TRUE : FALSE)
+//#define Is_usb_host() ((g_usb_mode==USB_MODE_HOST) ? TRUE : FALSE)
+
+#define Otg_send_event(x) g_otg_event |= (1<<x)
+//#define Otg_ack_event(x) g_otg_event &= ~(1<<x)
+//#define Otg_clear_all_event() g_otg_event = 0
+//#define Is_otg_event(x) ((g_otg_event & (1<<x)) ? TRUE : FALSE)
+//#define Is_not_otg_event(x) ((g_otg_event & (1<<x)) ? FALSE: TRUE)
+
+#define EVT_USB_POWERED 1 // USB plugged
+#define EVT_USB_UNPOWERED 2 // USB un-plugged
+#define EVT_USB_DEVICE_FUNCTION 3 // USB in device
+#define EVT_USB_HOST_FUNCTION 4 // USB in host
+#define EVT_USB_SUSPEND 5 // USB suspend
+#define EVT_USB_WAKE_UP 6 // USB wake up
+#define EVT_USB_RESUME 7 // USB resume
+#define EVT_USB_RESET 8 // USB reset
+#define EVT_HOST_SOF 9 // Host start of frame sent
+#define EVT_HOST_HWUP 10 // Host wakeup detected
+#define EVT_HOST_DISCONNECTION 11 // The target device is disconnected
+#define EVT_HOST_REMOTE_WAKEUP 12 // Remote WakeUp has been received (Host)
+
+
+#define EVT_OTG_HNP_ERROR 1 // The HNP has failed (A has not responded)
+#define EVT_OTG_HNP_SUCCESS 2 // The HNP has succedeed
+//#define EVT_OTG_SRP_RECEIVED 3 // A-Device received a SRP
+#define EVT_OTG_DEV_UNSUPPORTED 4 // An error occured while the device was enumerated
+//#define EVT_OTG_DEVICE_CONNECTED 5 // B-Device has been configured
+
+
+
+#define BDEV_HNP_NB_RETRY 3 // number of times that a B-Device retries a HNP with a failure as a result
+ // after "n" failures, the "b_hnp_enable" feature is cancelled
+
+//!
+//! @brief Definitions of OTG user requests (user software requests)
+//!
+#define USER_RQST_SRP 0x01
+#define USER_RQST_SUSPEND 0x02
+#define USER_RQST_VBUS 0x04 // Vbus TOGGLE
+#define USER_RQST_HNP 0x08
+//#define USER_RQST_RESUME 0x10
+//#define USER_RQST_RESET 0x20
+#define USER_RQST_DISCONNECT 0x40
+
+// Ask for the B-PERIPH to generate a SRP
+//#define Is_user_requested_srp() (((otg_user_request&USER_RQST_SRP) != 0) ? TRUE : FALSE)
+#define Set_user_request_srp() otg_user_request |= USER_RQST_SRP
+//#define Ack_user_request_srp() otg_user_request &= ~USER_RQST_SRP
+
+// Ask for the A-HOST to enter suspend
+#define Is_user_requested_suspend() (((otg_user_request&USER_RQST_SUSPEND) != 0) ? TRUE : FALSE)
+#define Set_user_request_suspend() otg_user_request |= USER_RQST_SUSPEND
+#define Ack_user_request_suspend() otg_user_request &= ~USER_RQST_SUSPEND
+
+// Ask for the A-HOST to toggle Vbus
+#define Is_user_requested_vbus() (((otg_user_request&USER_RQST_VBUS) != 0) ? TRUE : FALSE)
+#define Set_user_request_vbus() otg_user_request |= USER_RQST_VBUS
+#define Ack_user_request_vbus() otg_user_request &= ~USER_RQST_VBUS
+
+// Ask for an HNP initiation on both devices
+#define Is_user_requested_hnp() (((otg_user_request&USER_RQST_HNP) != 0) ? TRUE : FALSE)
+#define Set_user_request_hnp() otg_user_request |= USER_RQST_HNP
+#define Ack_user_request_hnp() otg_user_request &= ~USER_RQST_HNP
+
+// Ask for the B-PERIPH or the A-PERIPH to disconnect from the bus
+#define Is_user_requested_disc() (((otg_user_request&USER_RQST_DISCONNECT) != 0) ? TRUE : FALSE)
+#define Set_user_request_disc() otg_user_request |= USER_RQST_DISCONNECT
+//#define Ack_user_request_disc() otg_user_request &= ~USER_RQST_DISCONNECT
+
+
+#define Clear_all_user_request() otg_user_request = 0
+
+
+
+//! @brief OTG Messaging definitions
+//! "No Silent Failure" rule makes any OTG compliant device handle messaging functions
+//! Differents means are supported : LCD display, LEDs, etc.
+
+//#define MSG_DISPLAY_NODELAY 0xFFFF
+//#define OTG_TEMPO_1SEC 0x01F4 // 500 (x2ms)
+#define OTG_TEMPO_2SEC 0x03E8 // 1000
+#define OTG_TEMPO_3SEC 0x05DC // 1500
+#define OTG_TEMPO_4SEC 0x07D0 // 2000
+//#define OTR_TEMPO_5SEC 0x09C4 // 2500
+
+// These messages ID numbers must be used with the OTG messaging functions
+//#define OTGMSG_SRP_STARTED 1 // Event
+#define OTGMSG_SRP_A_NO_RESP 2 // FAILURE msg
+//#define OTGMSG_A_RESPONDED 3 // Event
+//#define OTGMSG_CONNECTED_TO_A 4 // Event
+#define OTGMSG_UNSUPPORTED 5 // FAILURE msg
+#define OTGMSG_UNSUPPORTED_HUB 6 // FAILURE msg
+#define OTGMSG_SRP_RECEIVED 7 // Event
+#define OTGMSG_DEVICE_NO_RESP 8 // FAILURE msg
+#define OTGMSG_VBUS_SURCHARGE 9 // Event
+
+//------------------------------------------------------------------------------
+// Exported variables
+//------------------------------------------------------------------------------
+
+extern U8 usb_configuration_nb;
+extern U8 otg_device_sessions;
+extern U8 b_uut_device_state;
+extern volatile U8 otg_features_supported;
+extern U8 otg_user_request;
+extern U8 g_usb_mode;
+extern volatile U8 private_sof_counter;
+extern volatile U16 g_usb_event;
+extern U16 otg_msg_event_delay;
+extern U16 otg_msg_failure_delay;
+
+extern void Otg_messaging_init(void);
+extern void Otg_output_failure_msg(U8);
+extern void Otg_output_failure_clear(void);
+//! Otg_print_new_event_message(str,tm) displays the "str" message on the EVENT line during the "tm" delay (x2ms)
+#define Otg_print_new_event_message(str,tm) (Otg_output_event_msg(str), otg_msg_event_delay = tm)
+#define Otg_clear_event_message() Otg_output_event_clear()
+#define Get_event_msg_delay() (otg_msg_event_delay)
+#define Decrement_event_msg_delay() (otg_msg_event_delay--)
+//! Otg_print_new_failure_message(str,tm) displays the "str" message on the FAILURE line during the "tm" delay (x2ms)
+#define Otg_print_new_failure_message(str,tm) (Otg_output_failure_msg(str), otg_msg_failure_delay = tm)
+#define Otg_clear_failure_message() Otg_output_failure_clear()
+#define Get_failure_msg_delay() (otg_msg_failure_delay)
+#define Decrement_failure_msg_delay() (otg_msg_failure_delay--)
+
+
+
+//-----------------------------------------------------------------------------
+// Exported functions
+//-----------------------------------------------------------------------------
+extern void usb_task_init(void);
+extern void usb_task(void);
+extern void usb_general_interrupt(void);
+extern void otg_timer_interrupt(void);
+extern void Otg_message_task_init(void);
+extern void Otg_message_task(void);
+extern void otg_not_supported_device(void);
+
+#endif /* _USB_TASK_H_ */
+
diff --git a/usb/otg/usb_task_host_only.c b/usb/otg/usb_task_host_only.c new file mode 100644 index 0000000..bdeed82 --- /dev/null +++ b/usb/otg/usb_task_host_only.c @@ -0,0 +1,287 @@ +/* ----------------------------------------------------------------------------
+ * 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 <memories/Media.h>
+#include "main.h"
+#include <conf_usb.h>
+#include <utility/trace.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/massstorage/MSDDriver.h>
+#include <usb/device/massstorage/MSDLun.h>
+#include <usb/device/core/USBDCallbacks.h>
+#include <usb/common/core/USBFeatureRequest.h>
+#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;i<MAX_EP_NB;i++) {
+ if(it_pipe_str[i].enable==ENABLE) {
+ save_pipe_nb=Host_get_selected_pipe();
+ Host_select_pipe(i);
+ if((++it_pipe_str[i].timeout>TIMEOUT_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 <memories/Media.h>
+#include "main.h"
+#include <conf_usb.h>
+#include <conf_scheduler.h>
+#include <utility/trace.h>
+#include <usb/common/core/USBConfigurationOTG.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/massstorage/MSDDriver.h>
+#include <usb/device/massstorage/MSDLun.h>
+#include <usb/device/core/USBDCallbacks.h>
+#include <usb/common/core/USBFeatureRequest.h>
+#include "otg_user_task.h"
+#include "usb_task.h"
+#include "usb/otg/usb_drv.h"
+#include "usb/otg/usb_host_task.h"
+
+#include <memories/Media.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/massstorage/MSDDriver.h>
+#include <usb/device/massstorage/MSDLun.h>
+#include <usb/device/core/USBDCallbacks.h>
+#include <usb/device/massstorage/MSD.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;
+
+///
+/// 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;i<MAX_EP_NB;i++) {
+ if(it_pipe_str[i].enable==ENABLE) {
+ save_pipe_nb=Host_get_selected_pipe();
+ Host_select_pipe(i);
+ if((++it_pipe_str[i].timeout>TIMEOUT_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);
+}
+
+
|