SAMV71 Xplained Ultra Software Package 1.3

USBH_HAL.c

Go to the documentation of this file.
00001 /**
00002  * \file
00003  *
00004  * \brief USB host driver
00005  * Compliance with common driver UHD
00006  *
00007  * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
00008  *
00009  * \asf_license_start
00010  *
00011  * \page License
00012  *
00013  * Redistribution and use in source and binary forms, with or without
00014  * modification, are permitted provided that the following conditions are met:
00015  *
00016  * 1. Redistributions of source code must retain the above copyright notice,
00017  *    this list of conditions and the following disclaimer.
00018  *
00019  * 2. Redistributions in binary form must reproduce the above copyright notice,
00020  *    this list of conditions and the following disclaimer in the documentation
00021  *    and/or other materials provided with the distribution.
00022  *
00023  * 3. The name of Atmel may not be used to endorse or promote products derived
00024  *    from this software without specific prior written permission.
00025  *
00026  * 4. This software may only be redistributed and used in connection with an
00027  *    Atmel microcontroller product.
00028  *
00029  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
00030  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00031  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00032  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
00033  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00034  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00035  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00036  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00037  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00038  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00039  * POSSIBILITY OF SUCH DAMAGE.
00040  *
00041  * \asf_license_stop
00042  *
00043  */
00044 /*
00045  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
00046  */
00047 
00048 #include "conf_usb_host.h"
00049 #include "board.h"
00050 #include "USBHDriver.h"
00051 #include "USBH.h"
00052 
00053 #include <string.h>
00054 #include <stdlib.h>
00055 
00056 
00057 
00058 #ifndef UHD_USB_INT_LEVEL
00059 # define UHD_USB_INT_LEVEL 5 // By default USB interrupt have low priority
00060 #endif
00061 
00062 #define USB_HOST_MAX_EP  9
00063 #define UHD_PIPE_USED(pipe)      (USB_HOST_MAX_EP >= pipe)
00064 
00065 #if (     (UHD_PIPE_USED( 1) && Is_uhd_pipe_dma_supported( 1)) \
00066     ||(UHD_PIPE_USED( 2) && Is_uhd_pipe_dma_supported( 2)) \
00067     ||(UHD_PIPE_USED( 3) && Is_uhd_pipe_dma_supported( 3)) \
00068     ||(UHD_PIPE_USED( 4) && Is_uhd_pipe_dma_supported( 4)) \
00069     ||(UHD_PIPE_USED( 5) && Is_uhd_pipe_dma_supported( 5)) \
00070     ||(UHD_PIPE_USED( 6) && Is_uhd_pipe_dma_supported( 6)) \
00071     ||(UHD_PIPE_USED( 7) && Is_uhd_pipe_dma_supported( 7)) \
00072     ||(UHD_PIPE_USED( 8) && Is_uhd_pipe_dma_supported( 8)) \
00073     ||(UHD_PIPE_USED( 9) && Is_uhd_pipe_dma_supported( 9)) \
00074     ||(UHD_PIPE_USED(10) && Is_uhd_pipe_dma_supported(10)) \
00075     ||(UHD_PIPE_USED(11) && Is_uhd_pipe_dma_supported(11)) \
00076     ||(UHD_PIPE_USED(12) && Is_uhd_pipe_dma_supported(12)) \
00077     ||(UHD_PIPE_USED(13) && Is_uhd_pipe_dma_supported(13)) \
00078     ||(UHD_PIPE_USED(14) && Is_uhd_pipe_dma_supported(14)) \
00079     ||(UHD_PIPE_USED(15) && Is_uhd_pipe_dma_supported(15)) \
00080     )
00081 # define UHD_PIPE_DMA_SUPPORTED
00082 #endif
00083 
00084 #if (     (UHD_PIPE_USED( 1) && !Is_uhd_pipe_dma_supported( 1)) \
00085     ||(UHD_PIPE_USED( 2) && !Is_uhd_pipe_dma_supported( 2)) \
00086     ||(UHD_PIPE_USED( 3) && !Is_uhd_pipe_dma_supported( 3)) \
00087     ||(UHD_PIPE_USED( 4) && !Is_uhd_pipe_dma_supported( 4)) \
00088     ||(UHD_PIPE_USED( 5) && !Is_uhd_pipe_dma_supported( 5)) \
00089     ||(UHD_PIPE_USED( 6) && !Is_uhd_pipe_dma_supported( 6)) \
00090     ||(UHD_PIPE_USED( 7) && !Is_uhd_pipe_dma_supported( 7)) \
00091     ||(UHD_PIPE_USED( 8) && !Is_uhd_pipe_dma_supported( 8)) \
00092     ||(UHD_PIPE_USED( 9) && !Is_uhd_pipe_dma_supported( 9)) \
00093     ||(UHD_PIPE_USED(10) && !Is_uhd_pipe_dma_supported(10)) \
00094     ||(UHD_PIPE_USED(11) && !Is_uhd_pipe_dma_supported(11)) \
00095     ||(UHD_PIPE_USED(12) && !Is_uhd_pipe_dma_supported(12)) \
00096     ||(UHD_PIPE_USED(13) && !Is_uhd_pipe_dma_supported(13)) \
00097     ||(UHD_PIPE_USED(14) && !Is_uhd_pipe_dma_supported(14)) \
00098     ||(UHD_PIPE_USED(15) && !Is_uhd_pipe_dma_supported(15)) \
00099     )
00100 # define UHD_PIPE_FIFO_SUPPORTED
00101 #endif
00102 
00103 
00104 
00105 // Optional UHC callbacks
00106 #ifndef UHC_MODE_CHANGE
00107 # define UHC_MODE_CHANGE(arg)
00108 #endif
00109 #ifndef UHC_SOF_EVENT
00110 # define UHC_SOF_EVENT()
00111 #endif
00112 #ifndef UHC_VBUS_CHANGE
00113 # define UHC_VBUS_CHANGE(b_present)
00114 #endif
00115 #ifndef UHC_VBUS_ERROR
00116 # define UHC_VBUS_ERROR()
00117 #endif
00118 
00119 /**
00120  * \ingroup usb_host_group
00121  * \defgroup uhd_group USB Host Driver (UHD)
00122  *
00123  * \section USB_CONF USB dual role configuration
00124  * The defines UHD_ENABLE and UDD_ENABLE must be added in project to allow
00125  * the USB low level (UHD) to manage or not the dual role (device and host).
00126  *
00127  * \section USBHS_CONF USBHS Custom configuration
00128  * The following USBHS driver configuration must be defined in conf_usb_host.h
00129  * file of the application.
00130  *
00131  * UHD_USB_INT_LEVEL<br>
00132  * Option to change the interrupt priority (0 to 15) by default 5 (recommended).
00133  *
00134  * UHD_USB_INT_FUN<br>
00135  * Option to fit interrupt function to what defined in exception table.
00136  *
00137  * UHD_ISOCHRONOUS_NB_BANK<br>
00138  * Feature to reduce or increase isochronous endpoints buffering (1 to 2).
00139  * Default value 2.
00140  *
00141  * UHD_BULK_NB_BANK<br>
00142  * Feature to reduce or increase bulk endpoints buffering (1 to 2).
00143  * Default value 2.
00144  *
00145  * UHD_INTERRUPT_NB_BANK<br>
00146  * Feature to reduce or increase interrupt endpoints buffering (1 to 2).
00147  * Default value 1.
00148  *
00149  * \section Callbacks management
00150  * The USB driver is fully managed by interrupt and does not request periodic
00151  * task. Thereby, the USB events use callbacks to transfer the information.
00152  * The callbacks can be declared in static during compilation
00153  * or dynamically during code execution.
00154  *
00155  * \section Power mode management
00156  * The driver uses the sleepmgr service to manage the different sleep modes.
00157  * The sleep mode depends on USB driver state (uhd_uotghs_state_enum).
00158  * @{
00159  */
00160 
00161 
00162 #ifndef UHD_ISOCHRONOUS_NB_BANK
00163 #  define UHD_ISOCHRONOUS_NB_BANK 2
00164 #else
00165 #  if (UHD_ISOCHRONOUS_NB_BANK < 1) || (UHD_ISOCHRONOUS_NB_BANK > 2)
00166 #    error UHD_ISOCHRONOUS_NB_BANK must be define with 1 or 2.
00167 #  endif
00168 #endif
00169 
00170 #ifndef UHD_BULK_NB_BANK
00171 #  define UHD_BULK_NB_BANK        2
00172 #else
00173 #  if (UHD_BULK_NB_BANK < 1) || (UHD_BULK_NB_BANK > 2)
00174 #    error UHD_BULK_NB_BANK must be define with 1 or 2.
00175 #  endif
00176 #endif
00177 
00178 #ifndef UHD_INTERRUPT_NB_BANK
00179 #  define UHD_INTERRUPT_NB_BANK   1
00180 #else
00181 #  if (UHD_INTERRUPT_NB_BANK < 1) || (UHD_INTERRUPT_NB_BANK > 2)
00182 #    error UHD_INTERRUPT_NB_BANK must be define with 1 or 2.
00183 #  endif
00184 #endif
00185 
00186 /**
00187  * \name Power management
00188  */
00189 //@{
00190 #ifndef UHD_NO_SLEEP_MGR
00191 
00192 #include "sleepmgr.h"
00193 //! States of USBHS interface
00194 enum uhd_uotghs_state_enum {
00195     UHD_STATE_OFF = 0,
00196     UHD_STATE_WAIT_ID_HOST = 1,
00197     UHD_STATE_NO_VBUS = 2,
00198     UHD_STATE_DISCONNECT = 3,
00199     UHD_STATE_SUSPEND = 4,
00200     UHD_STATE_IDLE = 5,
00201 };
00202 
00203 /*! \brief Manages the sleep mode following the USBHS state
00204  *
00205  * \param new_state  New USBHS state
00206  */
00207 static void uhd_sleep_mode(enum uhd_uotghs_state_enum new_state)
00208 {
00209     enum sleepmgr_mode sleep_mode[] = {
00210         SLEEPMGR_BACKUP,    // UHD_STATE_OFF (not used)
00211         SLEEPMGR_WAIT_FAST, // UHD_STATE_WAIT_ID_HOST
00212         SLEEPMGR_SLEEP_WFI, // UHD_STATE_NO_VBUS
00213         SLEEPMGR_SLEEP_WFI, // UHD_STATE_DISCONNECT
00214         SLEEPMGR_WAIT_FAST, // UHD_STATE_SUSPEND
00215         SLEEPMGR_SLEEP_WFI, // UHD_STATE_IDLE
00216     };
00217 
00218     static enum uhd_uotghs_state_enum uhd_state = UHD_STATE_OFF;
00219 
00220     if (uhd_state == new_state) {
00221         return; // No change
00222     }
00223     if (new_state != UHD_STATE_OFF) {
00224         // Lock new limit
00225         sleepmgr_lock_mode(sleep_mode[new_state]);
00226     }
00227     if (uhd_state != UHD_STATE_OFF) {
00228         // Unlock old limit
00229         sleepmgr_unlock_mode(sleep_mode[uhd_state]);
00230     }
00231     uhd_state = new_state;
00232 }
00233 
00234 #else
00235 #  define uhd_sleep_mode(arg)
00236 #endif // UHD_NO_SLEEP_MGR
00237 //@}
00238 
00239 
00240 //! Store the callback to be call at the end of reset signal
00241 static uhd_callback_reset_t uhd_reset_callback = NULL;
00242 
00243 /**
00244  * \name Control endpoint low level management routine.
00245  *
00246  * This function performs control endpoint management.
00247  * It handles the SETUP/DATA/HANDSHAKE phases of a control transaction.
00248  */
00249 //@{
00250 
00251 /**
00252  * \brief Structure to store the high level setup request
00253  */
00254 
00255 struct uhd_ctrl_request_t {
00256     //! Next setup request to process
00257     struct uhd_ctrl_request_t *next_request;
00258 
00259     //! Callback called when buffer is empty or full
00260     uhd_callback_setup_run_t callback_run;
00261     //! Callback called when request is completed
00262     uhd_callback_setup_end_t callback_end;
00263 
00264     //! Buffer to store the setup DATA phase
00265     uint8_t *payload;
00266 
00267     //! USB address of control endpoint
00268     uint8_t add;
00269 
00270     //! Setup request definition
00271     USBGenericRequest req;
00272 
00273     //! Size of buffer used in DATA phase
00274     uint16_t payload_size;
00275 };
00276 
00277 //! Entry points of setup request list
00278 struct uhd_ctrl_request_t *uhd_ctrl_request_first;
00279 struct uhd_ctrl_request_t *uhd_ctrl_request_last;
00280 
00281 //! Remaining time for on-going setup request (No request on-going if equal 0)
00282 volatile uint16_t uhd_ctrl_request_timeout;
00283 
00284 //! Number of transfered byte on DATA phase of current setup request
00285 uint16_t uhd_ctrl_nb_trans;
00286 
00287 //! Flag to delay a suspend request after all on-going setup request
00288 static bool uhd_b_suspend_requested;
00289 
00290 //! Bit definitions to store setup request state machine
00291 typedef enum {
00292     //! Wait a SETUP packet
00293     UHD_CTRL_REQ_PHASE_SETUP = 0,
00294     //! Wait a OUT data packet
00295     UHD_CTRL_REQ_PHASE_DATA_OUT = 1,
00296     //! Wait a IN data packet
00297     UHD_CTRL_REQ_PHASE_DATA_IN = 2,
00298     //! Wait a IN ZLP packet
00299     UHD_CTRL_REQ_PHASE_ZLP_IN = 3,
00300     //! Wait a OUT ZLP packet
00301     UHD_CTRL_REQ_PHASE_ZLP_OUT = 4,
00302 } uhd_ctrl_request_phase_t;
00303 uhd_ctrl_request_phase_t uhd_ctrl_request_phase;
00304 
00305 //@}
00306 
00307 
00308 /**
00309  * \name Management of bulk/interrupt/isochronous endpoints
00310  *
00311  * The UHD manages the data transfer on endpoints:
00312  * - Start data transfer on endpoint with USB DMA
00313  * - Send a ZLP packet if requested
00314  * - Call registered callback to signal end of transfer
00315  * The transfer abort and stall feature are supported.
00316  */
00317 //@{
00318 
00319 //! Structure definition to store registered jobs on a pipe
00320 typedef struct {
00321     //! Callback to call at the end of transfer
00322     uhd_callback_trans_t call_end;
00323 
00324     //! Buffer located in internal RAM to send or fill during job
00325     uint8_t *buf;
00326     //! Size of buffer to send or fill
00327     uint32_t buf_size;
00328     //! Total number of transfered data on endpoint
00329     uint32_t nb_trans;
00330 
00331     //! timeout on this request (ms)
00332     uint16_t timeout;
00333     //! A job is registered on this pipe
00334     uint16_t busy:1;
00335     //! A short packet is requested for this job on endpoint IN
00336     uint16_t b_shortpacket:1;
00337     //! Periodic packet start for this job
00338     uint16_t b_periodic_start:1;
00339 } USBH_PipeJob_t;
00340 
00341 //! Array to register a job on bulk/interrupt/isochronous endpoint
00342 static USBH_PipeJob_t uhd_pipe_job[USBHS_EPT_NUM - 1];
00343 
00344 //! Variables to manage the suspend/resume sequence
00345 static uint8_t uhd_suspend_start;
00346 static uint8_t uhd_resume_start;
00347 static uint16_t uhd_pipes_unfreeze;
00348 
00349 //@}
00350 static const Pin USB_HOST[] = PINS_VBUS_EN;
00351 
00352 static void USBH_HAL_ManageSof(void);
00353 static void USBH_HAL_ControlInterrupt(void);
00354 static void USBH_HAL_PhaseControlSetup(void);
00355 static void USBH_HAL_PhaseDataInStart(void);
00356 static void USBH_HAL_PhaseDataIn(void);
00357 static void USBH_HAL_InZLP(void);
00358 static void USBH_HAL_PhaseDataOut(void);
00359 static void USBH_HAL_OutZLP(void);
00360 static void USBH_HAL_ControlReqEnd(USBH_XfrStatus_t status);
00361 static USBH_XfrStatus_t USBH_HAL_GetPipeError(uint8_t pipe);
00362 static uint8_t USBH_HAL_GetPipe(uint8_t Addr, uint8_t bEndpoint);
00363 
00364 #ifdef UHD_PIPE_FIFO_SUPPORTED
00365 static void USBH_HAL_PipeOutReady(uint8_t pipe);
00366 static void USBH_HAL_PipeInReceived(uint8_t pipe);
00367 #endif
00368 #ifdef UHD_PIPE_DMA_SUPPORTED
00369 static void USBH_HAL_PipeXfrCmplt(uint8_t pipe);
00370 static void USBH_HAL_PipeDmaInterrupt(uint8_t pipe);
00371 #endif
00372 
00373 static void USBH_HAL_PipeInterrupt(uint8_t pipe);
00374 static void USBH_HAL_PipeAbort(uint8_t pipe, USBH_XfrStatus_t status);
00375 static void USBH_HAL_PipeXfrEnd(uint8_t pipe, USBH_XfrStatus_t status);
00376 
00377 
00378 //--------------------------------------------------------
00379 //--- INTERNAL ROUTINES TO MANAGED GLOBAL EVENTS
00380 
00381 /**
00382  * \internal
00383  * \brief Function called by USBHS interrupt handler to manage USB interrupts
00384  *
00385  * USB host interrupt events are split into four sections:
00386  * - USB line events
00387  *   (VBus error, device dis/connection, SOF, reset, suspend, resume, wakeup)
00388  * - control endpoint events
00389  *   (setup reception, end of data transfer, underflow, overflow, stall, error)
00390  * - bulk/interrupt/isochronous endpoints events
00391  *   (end of data transfer, stall, error)
00392  *
00393  * Note:
00394  * Here, the global interrupt mask is not cleared when an USB interrupt
00395  * is enabled because this one can not occurred during the USB ISR
00396  * (=during INTX is masked).
00397  * See Technical reference $3.8.3 Masking interrupt requests
00398  * in peripheral modules.
00399  */
00400 void USBHS_Handler(void)
00401 {
00402     uint8_t pipe_int, pipe_dma_int;
00403     uint32_t status = USBHS_GetHostStatus(USBHS, 0xFF);
00404     uint32_t statusInt =( status & USBHS_IsHostIntEnable(USBHS, 0xFF));
00405 
00406     memory_sync();
00407     TRACE_DEBUG("%c ", USBHS_IsUsbLowSpeed(USBHS) ? 'L' :
00408               (USBHS_IsUsbHighSpeed(USBHS) ? 'H' : 'F'));
00409     if(USBHS_IsUsbLowSpeed(USBHS) && (!(USBHS->USBHS_HSTCTRL & USBHS_DEVCTRL_SPDCONF_Msk)))
00410     {
00411       USBHS->USBHS_HSTCTRL |= USBHS_HSTCTRL_SPDCONF_LOW_POWER;
00412     }
00413     // Manage SOF interrupt
00414     if (status & USBHS_HSTISR_HSOFI) 
00415     {
00416       //Acknowledge SOF
00417       USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_HSOFIC);
00418       USBH_HAL_ManageSof();
00419     }
00420     else
00421     {      
00422       pipe_int = USBHS_GetInterruptPipeNum();
00423       pipe_dma_int = USBHS_GetInterruptPipeDmaNum();
00424      if (pipe_int == 0) {
00425         TRACE_DEBUG("Pipe0: ");
00426           // Interrupt acked by control endpoint managed
00427           USBH_HAL_ControlInterrupt();
00428       }
00429       else if (pipe_int != USBHS_EPT_NUM) {
00430          TRACE_DEBUG("Pipe%x: ", pipe_int);
00431           // Interrupt acked by bulk/interrupt/isochronous endpoint
00432           USBH_HAL_PipeInterrupt(pipe_int);
00433       }
00434   #ifdef UHD_PIPE_DMA_SUPPORTED
00435       
00436       else if (pipe_dma_int != USBHS_EPT_NUM) {
00437           TRACE_DEBUG("Pipe%x ", pipe_dma_int);
00438           // Interrupt DMA acked by bulk/interrupt/isochronous endpoint
00439           USBH_HAL_PipeDmaInterrupt(pipe_dma_int);
00440       }
00441   #endif
00442       // USB bus reset detection
00443       else if (status & USBHS_HSTISR_RSTI) 
00444       {
00445           TRACE_INFO_WP("RST ");
00446           USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_RSTIC);
00447           if (uhd_reset_callback != NULL) {
00448               uhd_reset_callback();
00449           }
00450       }
00451       
00452       // Check USB clock ready after asynchronous interrupt
00453       
00454 
00455       // Manage dis/connection event
00456       else if (statusInt & USBHS_HSTIMR_DDISCIE) {       
00457           USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_DDISCIC);
00458           USBHS_HostIntDisable(USBHS, USBHS_HSTIDR_DDISCIEC);
00459           TRACE_INFO("Disconnect--\n\r");
00460           // Stop reset signal, in case of disconnection during reset
00461           USBHS_StopReset();
00462           // Disable wakeup/resumes interrupts,
00463           // in case of disconnection during suspend mode
00464           USBHS_HostIntDisable(USBHS, ( USBHS_HSTIDR_HWUPIEC
00465                                        | USBHS_HSTIDR_RSMEDIEC
00466                                        | USBHS_HSTIDR_RXRSMIEC));
00467           uhd_sleep_mode(UHD_STATE_DISCONNECT);
00468           USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_DCONNIC);
00469           USBHS_HostIntEnable(USBHS, USBHS_HSTIER_DCONNIES);
00470           USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_HWUPIC);
00471           USBHS_HostIntEnable(USBHS, USBHS_HSTIER_HWUPIES);
00472           //otg_freeze_clock();
00473           uhd_suspend_start = 0;
00474           uhd_resume_start = 0;
00475           USBH_notify_connection(false);
00476       }
00477       else if (statusInt & USBHS_HSTIMR_DCONNIE) {
00478           TRACE_INFO("Connect-- ");
00479           USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_DCONNIC);
00480           USBHS_HostIntDisable(USBHS,USBHS_HSTIDR_DCONNIEC);
00481           USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_DDISCIC);
00482           USBHS_HostIntEnable(USBHS, USBHS_HSTIER_DDISCIES);
00483           USBHS_EnableSOF(USBHS);
00484           uhd_sleep_mode(UHD_STATE_IDLE);
00485           uhd_suspend_start = 0;
00486           uhd_resume_start = 0;
00487           USBH_notify_connection(true);
00488       }
00489 
00490       /* If Wakeup interrupt is enabled and triggered and connection intterupt is enabled  */
00491       else if((statusInt & USBHS_HSTISR_HWUPI ) && USBHS_IsHostIntEnable(USBHS, USBHS_HSTIMR_DCONNIE ) )
00492       {
00493           while (!USBHS_ISUsableClock(USBHS));
00494           USBHS_UnFreezeClock(USBHS);
00495           // Here the wakeup interrupt has been used to detect connection
00496            // with an asynchrone interrupt
00497           USBHS_HostIntDisable(USBHS, USBHS_HSTIDR_HWUPIEC);
00498           //uhd_sleep_mode(UHD_STATE_IDLE);
00499           
00500           USBHS_Set(USBHS, USBHS_SR_VBUSRQ);  // enable VBUS
00501           uhd_sleep_mode(UHD_STATE_DISCONNECT);
00502           UHC_VBUS_CHANGE(true); 
00503       }
00504 
00505 
00506       else if (USBHS_IsHostIntEnable(USBHS, USBHS_HSTIMR_HWUPIE) && (USBHS_GetHostStatus(USBHS, (USBHS_HSTISR_HWUPI |  USBHS_HSTISR_RSMEDI | USBHS_HSTISR_RXRSMI) ))) 
00507       {
00508           
00509           TRACE_INFO_WP("\n\rWKP ");
00510           while (!USBHS_ISUsableClock(USBHS));
00511           USBHS_UnFreezeClock(USBHS);
00512           // Disable wakeup/resumes interrupts
00513           USBHS_HostIntDisable(USBHS, (USBHS_HSTIDR_HWUPIEC
00514                                        | USBHS_HSTIDR_RSMEDIEC
00515                                        | USBHS_HSTIDR_RXRSMIEC) );
00516           USBHS_EnableSOF(USBHS);
00517           if ((!(USBHS_HSTISR_RSMEDI & status))
00518                   &&(!(USBHS_HSTISR_DDISCI & status))) {
00519               // It is a upstream resume
00520               // Note: When the CPU exits from a deep sleep mode, the event
00521               // Is_uhd_upstream_resume() can be not detected
00522               // because the USB clock are not available.
00523 
00524               // In High speed mode a downstream resume must be sent
00525               // after a upstream to avoid a disconnection.
00526               if (USBHS_IsUsbHighSpeed(USBHS)) {
00527                   USBHS_Resume();
00528               }
00529           }
00530           // Wait 50ms before restarting transfer
00531           uhd_resume_start = 50;
00532           uhd_sleep_mode(UHD_STATE_IDLE);
00533       }
00534       else
00535       {
00536         assert(false); // Interrupt event no managed
00537       }
00538       //TRACE_INFO_WP("\n\r");
00539     }   
00540 }
00541 
00542 
00543 void USBH_HAL_EnableUsbHost(void)
00544 {
00545     irqflags_t flags;
00546     
00547     // To avoid USB interrupt before end of initialization
00548     flags = cpu_irq_save();
00549 
00550     //USB_Initialized = true;
00551 
00552     //* Enable USB hardware clock
00553     sysclk_enable_usb();
00554     PMC_EnablePeripheral(ID_USBHS);
00555 
00556     // Always authorize asynchronous USB interrupts to exit of sleep mode
00557     // For SAM3 USB wake up device except BACKUP mode
00558     NVIC_SetPriority((IRQn_Type) ID_USBHS, UHD_USB_INT_LEVEL);
00559     NVIC_EnableIRQ((IRQn_Type) ID_USBHS);
00560 
00561     uhd_sleep_mode(UHD_STATE_OFF);
00562     
00563     PIO_Configure(USB_HOST, PIO_LISTSIZE(USB_HOST));
00564     
00565     PIO_Set(USB_HOST);  // Power off USB devices
00566 
00567     USBHS_UsbMode(USBHS, HOST_MODE);
00568  
00569     
00570     USBHS_UsbEnable(USBHS, true);
00571 
00572 #ifndef USB_HOST_HS_SUPPORT
00573     USBHS->USBHS_HSTCTRL |= USBHS_HSTCTRL_SPDCONF_LOW_POWER;
00574 #endif
00575 
00576     uhd_ctrl_request_first = NULL;
00577     uhd_ctrl_request_last = NULL;
00578     uhd_ctrl_request_timeout = 0;
00579     uhd_suspend_start = 0;
00580     uhd_resume_start = 0;
00581     uhd_b_suspend_requested = false;
00582 
00583     // Check USB clock
00584     USBHS_UnFreezeClock(USBHS);
00585     while (!USBHS_ISUsableClock(USBHS));
00586     
00587     // Clear all interrupts that may have been set by a previous host mode
00588     USBHS_ClearHostStatus(USBHS, (USBHS_HSTICR_DCONNIC | USBHS_HSTICR_DDISCIC
00589             | USBHS_HSTICR_HSOFIC  | USBHS_HSTICR_HWUPIC
00590             | USBHS_HSTICR_RSMEDIC | USBHS_HSTICR_RSTIC
00591             | USBHS_HSTICR_RXRSMIC));
00592     //memory_barrier();
00593     memory_sync();
00594 
00595     USBHS_VBusHWC(USBHS, false);
00596     uhd_sleep_mode(UHD_STATE_NO_VBUS);
00597     
00598     
00599      /** Freeze USB clock to use wakeup interrupt
00600      * to detect connection.
00601      * After detection of wakeup interrupt,
00602      * the clock is unfreeze to have the true
00603      * connection interrupt.
00604      */
00605     // wakeup
00606     USBHS_HostIntEnable(USBHS, USBHS_HSTIER_HWUPIES);
00607     uhd_sleep_mode(UHD_STATE_DISCONNECT);
00608     UHC_VBUS_CHANGE(true); /* Changed to HIGH */
00609     
00610     PIO_Clear(USB_HOST);    // power on USB device
00611     
00612     // Enable main control interrupt
00613     // Connection, SOF and reset
00614     USBHS_HostIntEnable(USBHS, (USBHS_HSTIER_RSTIES | USBHS_HSTIER_HSOFIES | USBHS_HSTIER_DCONNIES));
00615 
00616     USBHS_FreezeClock(USBHS);
00617         
00618     cpu_irq_restore(flags);
00619 
00620 }
00621 
00622 void USBH_HAL_DisableUsb(bool b_id_stop)
00623 {
00624     irqflags_t flags;
00625 
00626     // Check USB clock ready after a potential sleep mode < IDLE
00627     while (!USBHS_ISUsableClock(USBHS));
00628     USBHS_UnFreezeClock(USBHS);
00629     printf("USB disabled \n\r");
00630     
00631     // (Connection, disconnection, SOF and reset)
00632      USBHS_HostIntDisable(USBHS, (USBHS_HSTICR_DCONNIC | USBHS_HSTICR_DDISCIC
00633             | USBHS_HSTICR_HSOFIC  | USBHS_HSTICR_HWUPIC
00634             | USBHS_HSTICR_RSMEDIC | USBHS_HSTICR_RSTIC
00635             | USBHS_HSTICR_RXRSMIC));
00636 
00637     USBHS_DisableSOF();
00638     USBHS_Ack(USBHS, USBHS_SR_VBUSRQ);
00639     USBH_notify_connection(false);
00640 
00641     flags = cpu_irq_save();
00642     USBHS_FreezeClock(USBHS);
00643     USBHS_UsbEnable(USBHS, false);
00644     sysclk_disable_usb();
00645     PMC_DisablePeripheral(ID_USBHS);
00646     uhd_sleep_mode(UHD_STATE_OFF);
00647     cpu_irq_restore(flags);
00648 }
00649 
00650 USBH_Speed_t USBH_HAL_GetSpeed(void)
00651 {
00652     switch (USBHS_GetUsbSpeed(USBHS)) {
00653 
00654     case USBHS_SR_SPEED_HIGH_SPEED:
00655         return UHD_SPEED_HIGH;
00656 
00657     case USBHS_SR_SPEED_FULL_SPEED:
00658         return UHD_SPEED_FULL;
00659 
00660     case USBHS_SR_SPEED_LOW_SPEED:
00661         return UHD_SPEED_LOW;
00662 
00663     default:
00664         assert(false);
00665         return UHD_SPEED_LOW;
00666     }
00667 }
00668 
00669 uint16_t USBH_HAL_GetFrameNum(void)
00670 {
00671     return USBHS_HostGetSOF();
00672 }
00673 
00674 uint16_t USBH_HAL_GetMicroFrameNum(void)
00675 {
00676     return USBHS_HostGetMSOF();
00677 }
00678 
00679 void USBH_HAL_Reset(uhd_callback_reset_t callback)
00680 {
00681     uhd_reset_callback = callback;
00682     USBHS_Reset();
00683 }
00684 
00685 void USBH_HAL_Suspend(void)
00686 {
00687     uint8_t pipe;
00688     if (uhd_ctrl_request_timeout) {
00689         // Delay suspend after setup requests
00690         uhd_b_suspend_requested = true;
00691         return;
00692     }
00693     // Save pipe freeze states and freeze pipes
00694     uhd_pipes_unfreeze = 0;
00695     for (pipe = 1; pipe < USBHS_EPT_NUM; pipe++) {
00696         uhd_pipes_unfreeze |= (!USBHS_IsHostPipeIntTypeEnable(USBHS,pipe, USBHS_HSTPIPIMR_PFREEZE)) << pipe;
00697         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);
00698     }
00699     // Wait three SOFs before entering in suspend state
00700     uhd_suspend_start = 3;
00701 }
00702 
00703 bool USBH_HAL_IsSuspended(void)
00704 {
00705     return !USBHS_IsEnableSOF(USBHS);
00706 }
00707 
00708 void USBH_HAL_Resume(void)
00709 {
00710     if (USBHS_IsEnableSOF(USBHS)) {
00711         // Currently in IDLE mode (!=Suspend)
00712         if (uhd_suspend_start) {
00713             // Suspend mode on going
00714             // then stop it and start resume event
00715             uhd_suspend_start = 0;
00716             uhd_resume_start = 1;
00717         }
00718         return;
00719     }
00720     // Check USB clock ready after a potential sleep mode < IDLE
00721     while (!USBHS_ISUsableClock(USBHS));
00722     USBHS_UnFreezeClock(USBHS);
00723     USBHS_EnableSOF(USBHS);
00724     USBHS_Resume();
00725     uhd_sleep_mode(UHD_STATE_IDLE);
00726 }
00727 
00728 bool USBH_HAL_ConfigureControlPipe(uint8_t Addr, uint16_t ep_size)
00729 {
00730     uint8_t bSizeEpt;
00731     if (ep_size < 8) {
00732         return false;
00733     }
00734 #ifdef USB_HOST_HUB_SUPPORT
00735     if (USBHS_IsHostPipeEnable(USBHS, 0)) {
00736         // Already allocated
00737 #error TODO Add USB address in a list
00738         return true;
00739     }
00740 #endif
00741 
00742     USBHS_HostPipeEnable(USBHS, 0);
00743     
00744     /* Configure endpoint size */
00745     if(ep_size <= 8 )
00746         bSizeEpt = 0;
00747     else if (ep_size <= 16 )
00748         bSizeEpt = 1;
00749     else if (ep_size <= 32 )
00750         bSizeEpt = 2;
00751     else if (ep_size <= 64 )
00752         bSizeEpt = 3;
00753     else if (ep_size <= 128 )
00754         bSizeEpt = 4;
00755     else if (ep_size <= 256 )
00756         bSizeEpt = 5;
00757     else if (ep_size <= 512 )
00758         bSizeEpt = 6;
00759     else if (ep_size <= 1024 )
00760         bSizeEpt = 7;
00761 
00762 #ifdef USB_HOST_HUB_SUPPORT
00763     bSizeEpt = 3;   //64 bytes
00764 #endif
00765     USBHS_HostConfigure(USBHS, 0, USBHS_HSTPIPCFG_PBK_1_BANK, bSizeEpt, USBHS_HSTPIPCFG_PTYPE_CTRL, USBHS_HSTPIPCFG_PTOKEN_SETUP, 0, 0);
00766     USBHS_HostDisableAutoSw(USBHS, 0);
00767     USBHS_HostAllocMem(USBHS, 0);
00768     if (!USBHS_IsHostConfigOk(USBHS, 0)) {
00769         USBHS_HostPipeDisable(USBHS, 0);
00770         return false;
00771     }
00772     USBHS_HostSetAddr(USBHS, 0, Addr);
00773 
00774     // Always enable stall and error interrupts of control endpoint
00775     USBHS_HostEnablePipeIntType(USBHS, 0, (USBHS_HSTPIPIER_RXSTALLDES | USBHS_HSTPIPIER_PERRES) );
00776     USBHS_HostPipeIntEnable(USBHS, 0);
00777     return true;
00778 }
00779 
00780 bool USBH_HAL_ConfigurePipe(uint8_t Addr, USBEndpointDescriptor * ep_desc)
00781 {
00782     uint32_t ep_type, ep_dir;
00783     uint8_t ep_interval;
00784     uint8_t pipe;
00785     uint8_t bank, ep_addr, bSizeEpt;
00786 
00787     for (pipe = 1; pipe < USBHS_EPT_NUM; pipe++) {
00788         if (USBHS_IsHostPipeEnable(USBHS, pipe)) {
00789             continue;
00790         }
00791         USBHS_HostPipeEnable(USBHS, pipe);
00792         ep_addr = ep_desc->bEndpointAddress & USB_EP_ADDR_MASK;
00793         ep_dir = (ep_desc->bEndpointAddress & USB_EP_DIR_IN)?
00794             (USBHS_HSTPIPCFG_PTOKEN_IN):
00795             (USBHS_HSTPIPCFG_PTOKEN_OUT),
00796         ep_type = ep_desc->bmAttributes&USB_EP_TYPE_MASK;
00797         // Bank choice
00798         switch(ep_type) {
00799         case USBEndpointDescriptor_ISOCHRONOUS:
00800             bank = UHD_ISOCHRONOUS_NB_BANK;
00801             ep_interval = ep_desc->bInterval;
00802             ep_type = USBHS_HSTPIPCFG_PTYPE_ISO;
00803             break;
00804         case USBEndpointDescriptor_INTERRUPT:
00805             bank = UHD_INTERRUPT_NB_BANK;
00806             ep_interval = ep_desc->bInterval;
00807             ep_type = USBHS_HSTPIPCFG_PTYPE_INTRPT;
00808             break;
00809         case USBEndpointDescriptor_BULK:
00810             bank = UHD_BULK_NB_BANK;
00811             // 0 is required by USBHS hardware for bulk
00812             ep_interval = 0;
00813             ep_type = USBHS_HSTPIPCFG_PTYPE_BLK;
00814             break;
00815         default:
00816             assert(false);
00817             return false;
00818         }
00819         switch(bank) {
00820         case 1:
00821             bank = USBHS_HSTPIPCFG_PBK_1_BANK;
00822             break;
00823         case 2:
00824             bank = USBHS_HSTPIPCFG_PBK_2_BANK;
00825             break;
00826         case 3:
00827             bank = USBHS_HSTPIPCFG_PBK_3_BANK;
00828             break;
00829         default:
00830             assert(false);
00831             return false;
00832         }
00833 
00834             /* Configure endpoint size */
00835         if(ep_desc->wMaxPacketSize <= 8 )
00836             bSizeEpt = 0;
00837         else if (ep_desc->wMaxPacketSize <= 16 )
00838             bSizeEpt = 1;
00839         else if (ep_desc->wMaxPacketSize <= 32 )
00840             bSizeEpt = 2;
00841         else if (ep_desc->wMaxPacketSize <= 64 )
00842             bSizeEpt = 3;
00843         else if (ep_desc->wMaxPacketSize <= 128 )
00844             bSizeEpt = 4;
00845         else if (ep_desc->wMaxPacketSize <= 256 )
00846             bSizeEpt = 5;
00847         else if (ep_desc->wMaxPacketSize <= 512 )
00848             bSizeEpt = 6;
00849         else if (ep_desc->wMaxPacketSize <= 1024 )
00850             bSizeEpt = 7;
00851         
00852         
00853         USBHS_HostConfigure(USBHS, pipe, bank, bSizeEpt, ep_type, ep_dir, ep_addr, ep_interval);
00854         USBHS_HostEnableAutoSw(USBHS, pipe);
00855 
00856         USBHS_HostAllocMem(USBHS, pipe);
00857         if (!USBHS_IsHostConfigOk(USBHS, pipe)) {
00858             USBHS_HostPipeDisable(USBHS, pipe);
00859             return false;
00860         }
00861         
00862         USBHS_HostSetAddr(USBHS, pipe, Addr);
00863 
00864         USBHS_HostPipeEnable(USBHS, pipe);
00865 
00866         // Enable endpoint interrupts
00867         USBHS_HostDmaIntEnable(USBHS, pipe-1);
00868         USBHS_HostEnablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIER_RXSTALLDES | USBHS_HSTPIPIER_PERRES) );
00869         
00870         USBHS_HostPipeIntEnable(USBHS, pipe);
00871         
00872         return true;
00873     }
00874     return false;
00875 }
00876 
00877 
00878 void USBH_HAL_FreePipe(uint8_t Addr, uint8_t bEndpoint)
00879 {
00880     uint8_t pipe;
00881 #ifdef USB_HOST_HUB_SUPPORT
00882     if (bEndpoint == 0) {
00883         // Control endpoint does not be unallocated
00884 #error TODO the list address must be updated
00885         if (uhd_ctrl_request_timeout
00886                 && (uhd_ctrl_request_first->add == Addr)) {
00887             // Disable setup request if on this device
00888             USBH_HAL_ControlReqEnd(UHD_TRANS_DISCONNECT);
00889         }
00890         return;
00891     }
00892 #endif
00893     // Search endpoint(s) in all pipes
00894     for (pipe = 0; pipe < USBHS_EPT_NUM; pipe++) {
00895         if (!USBHS_IsHostPipeEnable(USBHS, pipe)) {
00896             continue;
00897         }
00898         if (Addr != USBHS_HostGetAddr(USBHS, pipe)) {
00899             continue;
00900         }
00901         if (bEndpoint != 0xFF) {
00902             // Disable specific endpoint number
00903             if (bEndpoint != USBHS_GetPipeEpAddr(USBHS, pipe)) {
00904                 continue; // Mismatch
00905             }
00906         }
00907         // Unalloc pipe
00908         USBHS_HostPipeDisable(USBHS, pipe);
00909         USBHS_HostFreeMem(USBHS, pipe);
00910 
00911         // Stop transfer on this pipe
00912 #ifndef USB_HOST_HUB_SUPPORT
00913         if (pipe == 0) {
00914             // Endpoint control
00915             if (uhd_ctrl_request_timeout) {
00916                 USBH_HAL_ControlReqEnd(UHD_TRANS_DISCONNECT);
00917             }
00918             continue;
00919         }
00920 #endif
00921         // Endpoint interrupt, bulk or isochronous
00922         USBH_HAL_PipeAbort(pipe, UHD_TRANS_DISCONNECT);
00923     }
00924 }
00925 
00926 bool USBH_HAL_SetupReq(
00927         uint8_t Addr,
00928         USBGenericRequest *req,
00929         uint8_t *payload,
00930         uint16_t payload_size,
00931         uhd_callback_setup_run_t callback_run,
00932         uhd_callback_setup_end_t callback_end)
00933 {
00934     irqflags_t flags;
00935     struct uhd_ctrl_request_t *request;
00936     bool b_start_request = false;
00937 
00938     request = malloc(sizeof(struct uhd_ctrl_request_t));
00939     if (request == NULL) {
00940         assert(false);
00941         return false;
00942     }
00943 
00944     // Fill structure
00945     request->add = (uint8_t) Addr;
00946     memcpy(&request->req, req, sizeof(USBGenericRequest));
00947     request->payload = payload;
00948     request->payload_size = payload_size;
00949     request->callback_run = callback_run;
00950     request->callback_end = callback_end;
00951     request->next_request = NULL;
00952 
00953     // Add this request in the queue
00954     flags = cpu_irq_save();
00955     if (uhd_ctrl_request_first == NULL) {
00956         uhd_ctrl_request_first = request;
00957         b_start_request = true;
00958     } else {
00959         uhd_ctrl_request_last->next_request = request;
00960     }
00961     uhd_ctrl_request_last = request;
00962     cpu_irq_restore(flags);
00963 
00964     if (b_start_request) {
00965         // Start immediately request
00966         USBH_HAL_PhaseControlSetup();
00967     }
00968     return true;
00969 }
00970 
00971 bool USBH_HAL_RunEndpoint(uint8_t Addr,
00972         uint8_t bEndpoint,
00973         bool b_shortpacket,
00974         uint8_t *buf,
00975         uint32_t buf_size,
00976         uint16_t timeout,
00977         uhd_callback_trans_t callback)
00978 {
00979     irqflags_t flags;
00980     uint8_t pipe;
00981     USBH_PipeJob_t *pJob;
00982 
00983     pipe = USBH_HAL_GetPipe(Addr,bEndpoint);
00984     if (pipe == USBHS_EPT_NUM) {
00985         return false; // pipe not found
00986     }
00987 #ifdef UHD_PIPE_FIFO_SUPPORTED
00988     bool b_pipe_in = (USBHS_HostGetToken(USBHS, pipe) == USBHS_HSTPIPCFG_PTOKEN_IN)?true:false;
00989 #endif
00990 
00991     // Get job about pipe
00992     pJob = &uhd_pipe_job[pipe-1];
00993     flags = cpu_irq_save();
00994     if (pJob->busy == true) {
00995         cpu_irq_restore(flags);
00996         return false; // Job already on going
00997     }
00998     pJob->busy = true;
00999 
01000     // No job running. Let's setup a new one.
01001     pJob->buf = buf;
01002     pJob->buf_size = buf_size;
01003     pJob->nb_trans = 0;
01004     pJob->timeout = timeout;
01005     pJob->b_shortpacket = b_shortpacket;
01006     pJob->call_end = callback;
01007     if( (USBHS_HostGetPipeType(USBHS, pipe) & (USBHS_HSTPIPCFG_PTYPE_ISO | USBHS_HSTPIPCFG_PTYPE_INTRPT)) && (USBHS_HostGetToken(USBHS, pipe) == USBHS_HSTPIPCFG_PTOKEN_OUT))
01008     /*if ((Is_uhd_pipe_int(pipe) || Is_uhd_pipe_iso(pipe))
01009             && (Is_uhd_pipe_out(pipe))) */
01010     {
01011         pJob->b_periodic_start = true;
01012     }
01013     cpu_irq_restore(flags);
01014 
01015 #ifdef UHD_PIPE_FIFO_SUPPORTED
01016     // No DMA support
01017     if (!Is_uhd_pipe_dma_supported(pipe)) {
01018         flags = cpu_irq_save();
01019         USBHS_HostDisableAutoSw(USBHS, pipe);;
01020         USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_PFREEZEC);
01021         if (b_pipe_in) {
01022             USBHS_HostEnableInReq(USBHS, pipe);
01023             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_RXINES);
01024             if (b_shortpacket) {
01025                 USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_SHORTPACKETIES);
01026             }
01027         } else {
01028             USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_NBUSYBKEC);
01029             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_TXOUTES);
01030         }
01031         USBHS_HostPipeIntEnable(USBHS, pipe);
01032         cpu_irq_restore(flags);
01033         return true;
01034     }
01035 #endif // UHD_PIPE_FIFO_SUPPORTED
01036 
01037 #ifdef UHD_PIPE_DMA_SUPPORTED
01038     // Request first transfer
01039     USBH_HAL_PipeXfrCmplt(pipe);
01040 #endif
01041     return true;
01042 }
01043 
01044 void USBH_HAL_AbortEndPoint(uint8_t Addr, uint8_t bEndpoint)
01045 {
01046     uint8_t pipe;
01047 
01048     pipe = USBH_HAL_GetPipe(Addr,bEndpoint);
01049     if (pipe == USBHS_EPT_NUM) {
01050         return; // pipe not found
01051     }
01052     USBH_HAL_PipeAbort(pipe,UHD_TRANS_ABORTED);
01053 }
01054 
01055 
01056 static void USBH_HAL_DelayedSuspend(void)
01057 {
01058   volatile uint8_t AsyncInt= ( USBHS_HSTIER_HWUPIES |USBHS_HSTIER_RSMEDIES | USBHS_HSTIER_RXRSMIES );
01059   
01060     if (--uhd_suspend_start == 0) {
01061         // In case of high CPU frequency,
01062         // the current Keep-Alive/SOF can be always on-going
01063         // then wait end of SOF generation
01064         // to be sure that disable SOF has been accepted
01065         uint8_t pos =
01066             (USBHS_GetUsbSpeed(USBHS) == USBHS_SR_SPEED_HIGH_SPEED) ?
01067                 13 : 114;
01068         while (pos < USBHS_HostGetFramePos()) {
01069             if (USBHS_GetHostStatus(USBHS, USBHS_HSTISR_DDISCI)) {
01070                 break;
01071             }
01072         }
01073         USBHS_DisableSOF();
01074 
01075         // When SOF is disabled, the current transmitted packet may
01076         // cause a resume.
01077         // Wait for a while to check this resume status and clear it.
01078         for (pos = 0; pos < 15; pos ++) {
01079             memory_barrier();
01080             if (USBHS_GetHostStatus(USBHS, USBHS_HSTICR_HWUPIC
01081                     | USBHS_HSTICR_RSMEDIC
01082                     | USBHS_HSTICR_RXRSMIC)) 
01083             {
01084                 break;
01085             }
01086         }
01087         
01088 
01089         // Ack previous wakeup and resumes interrupts
01090         USBHS_ClearHostStatus(USBHS, (  USBHS_HSTICR_HWUPIC
01091                                       | USBHS_HSTICR_RSMEDIC
01092                                       | USBHS_HSTICR_RXRSMIC));
01093 
01094         memory_sync();
01095         // Enable wakeup/resumes interrupts
01096         USBHS_HostIntEnable(USBHS, AsyncInt );
01097         
01098         
01099         USBHS_FreezeClock(USBHS);
01100         uhd_sleep_mode(UHD_STATE_SUSPEND);
01101     }
01102 }
01103 static void USBH_HAL_DelayedResume(void)
01104 {
01105     uint8_t pipe;
01106     if (--uhd_resume_start == 0) {
01107         // Restore pipes unfreezed
01108         for (pipe = 1; pipe < USBHS_EPT_NUM; pipe++) {
01109             if ((uhd_pipes_unfreeze >> pipe) & 0x01) {
01110                 USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_PFREEZEC);
01111             }
01112         }
01113         USBH_notify_resume();
01114     }
01115 }
01116 static void USBH_HAL_ControlTimeout(void)
01117 {
01118     if (uhd_ctrl_request_timeout) {
01119         // Setup request on-going
01120         if (--uhd_ctrl_request_timeout == 0) {
01121             TRACE_WARNING_WP("Timeout");
01122             // Stop request by freezing pipe
01123             USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_PFREEZES);
01124             USBH_HAL_ControlReqEnd(UHD_TRANS_TIMEOUT);
01125         }
01126     }
01127 }
01128 
01129 /**
01130  * \internal
01131  * \brief Manages timeouts and actions based on SOF events
01132  * - Suspend delay
01133  * - Resume delay
01134  * - Setup packet delay
01135  * - Timeout on endpoint control transfer
01136  * - Timeouts on bulk/interrupt/isochronous endpoint transfers
01137  * - UHC user notification
01138  * - SOF user notification
01139  */
01140 static void USBH_HAL_ManageSof(void)
01141 {
01142 //  USBHS_HostAckPipeIntType(USBHS, USBHS_HSTICR_HSOFIC);
01143 
01144     uint8_t pipe;
01145     // Manage the micro SOF
01146     if (USBHS_IsUsbHighSpeed(USBHS)) {
01147         static uint8_t msof_cpt = 0;
01148         if (++msof_cpt % 8) {
01149             // It is a micro SOF
01150             if (!uhd_suspend_start && !uhd_resume_start) {
01151                 // If no resume and no suspend on going
01152                 // then send Micro start of frame event (each 125?)
01153                 USBH_notify_sof(true);
01154             }
01155             return;
01156         }
01157     }
01158 
01159     // Manage a delay to enter in suspend
01160     if (uhd_suspend_start) {
01161         USBH_HAL_DelayedSuspend();
01162         return; // Abort SOF events
01163     }
01164     // Manage a delay to exit of suspend
01165     if (uhd_resume_start) {
01166         USBH_HAL_DelayedResume();
01167         return; // Abort SOF events
01168     }
01169     // Manage the timeout on endpoint control transfer
01170     USBH_HAL_ControlTimeout();
01171 
01172     // Manage the timeouts on endpoint transfer
01173     USBH_PipeJob_t *pJob;
01174     for (pipe = 1; pipe < USBHS_EPT_NUM; pipe++) {
01175         pJob = &uhd_pipe_job[pipe-1];
01176         if (pJob->busy == true) {
01177             if (pJob->timeout) {
01178                 // Timeout enabled on this job
01179                 if (--(pJob->timeout) == 0) {
01180                     // Abort job
01181                     USBH_HAL_PipeAbort(pipe,UHD_TRANS_TIMEOUT);
01182                 }
01183             }
01184             if (pJob->b_periodic_start) {
01185                 pJob->b_periodic_start = false;
01186                 USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_PFREEZEC);
01187             }
01188         }
01189     }
01190     // Notify the UHC
01191     USBH_notify_sof(false);
01192 
01193     // Notify the user application
01194     UHC_SOF_EVENT();
01195     memory_sync();
01196 }
01197 
01198 /**
01199  * \internal
01200  * \brief Manages the events related to control endpoint
01201  */
01202 static void USBH_HAL_ControlInterrupt(void)
01203 {
01204     
01205     // A setup request is on-going
01206     assert(uhd_ctrl_request_timeout!=0);
01207 
01208     // Disable setup, IN and OUT interrupts of control endpoint
01209     USBHS_HostDisablePipeIntType(USBHS, 0, (  USBHS_HSTPIPIDR_TXSTPEC
01210                                             | USBHS_HSTPIPIDR_RXINEC
01211                                             | USBHS_HSTPIPIDR_TXOUTEC) );
01212 
01213     // Search event on control endpoint
01214     if (USBHS_HostGetIntTypeStatus(USBHS, 0, USBHS_HSTPIPISR_TXSTPI) ) 
01215     {
01216         // SETUP packet sent
01217         USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_PFREEZES);
01218         USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_TXSTPIC);
01219         assert(uhd_ctrl_request_phase == UHD_CTRL_REQ_PHASE_SETUP);
01220 
01221         // Start DATA phase
01222         if ((uhd_ctrl_request_first->req.bmRequestType & USB_REQ_DIR_MASK)
01223                 == USB_REQ_DIR_IN) {
01224             USBH_HAL_PhaseDataInStart();
01225         } else {
01226             if (uhd_ctrl_request_first->req.wLength) {
01227                 USBH_HAL_PhaseDataOut();
01228             } else {
01229                 // No DATA phase
01230                 USBH_HAL_InZLP();
01231             }
01232         }
01233         return;
01234     }
01235     if (USBHS_HostGetIntTypeStatus(USBHS, 0,USBHS_HSTPIPISR_RXINI)) {
01236         // In case of low USB speed and with a high CPU frequency,
01237         // a ACK from host can be always running on USB line
01238         // then wait end of ACK on IN pipe.
01239         while (!USBHS_IsHostPipeIntTypeEnable(USBHS, 0, USBHS_HSTPIPIMR_PFREEZE));
01240 
01241         // IN packet received, Acknowledge
01242         USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_RXINIC);
01243         switch(uhd_ctrl_request_phase) {
01244         case UHD_CTRL_REQ_PHASE_DATA_IN:
01245             USBH_HAL_PhaseDataIn();
01246             break;
01247         case UHD_CTRL_REQ_PHASE_ZLP_IN:
01248             USBH_HAL_ControlReqEnd(UHD_TRANS_NOERROR);
01249             break;
01250         default:
01251             assert(false);
01252             break;
01253         }
01254         return;
01255     }
01256     if (USBHS_HostGetIntTypeStatus(USBHS, 0,USBHS_HSTPIPISR_TXOUTI)) {
01257         // OUT packet sent
01258         USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_PFREEZES);
01259         USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_TXOUTIC);
01260         switch(uhd_ctrl_request_phase) {
01261         case UHD_CTRL_REQ_PHASE_DATA_OUT:
01262             USBH_HAL_PhaseDataOut();
01263             break;
01264         case UHD_CTRL_REQ_PHASE_ZLP_OUT:
01265             USBH_HAL_ControlReqEnd(UHD_TRANS_NOERROR);
01266             break;
01267         default:
01268             assert(false);
01269             break;
01270         }
01271         return;
01272     }
01273     if (USBHS_HostGetIntTypeStatus(USBHS, 0,USBHS_HSTPIPISR_RXSTALLDI)) {
01274         // Stall Handshake received
01275         USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_RXSTALLDIC);
01276         USBH_HAL_ControlReqEnd(UHD_TRANS_STALL);
01277         return;
01278     }
01279     if (USBHS_HostGetIntTypeStatus(USBHS, 0,USBHS_HSTPIPISR_PERRI)) {
01280         // Get and ack error
01281         USBH_HAL_ControlReqEnd(USBH_HAL_GetPipeError(0));
01282         printf("Control pipe error \n\r");
01283         return;
01284     }
01285     memory_sync();
01286     assert(false); // Error system
01287 }
01288 
01289 /**
01290  * \internal
01291  * \brief Sends a USB setup packet to start a control request sequence
01292  */
01293 static void USBH_HAL_PhaseControlSetup(void)
01294 {
01295     union{
01296         volatile uint64_t value64;
01297         USBGenericRequest req;
01298     } setup;
01299     volatile uint64_t *pEpData;
01300 
01301     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_SETUP;
01302     memcpy(&setup.req, &uhd_ctrl_request_first->req, sizeof(USBGenericRequest));
01303     memory_sync();
01304 
01305     uhd_ctrl_nb_trans = 0;
01306 
01307     // Check pipe
01308 #ifdef USB_HOST_HUB_SUPPORT
01309     if (!USBHS_IsHostPipeEnable(USBHS, 0)) {
01310         USBH_HAL_ControlReqEnd(UHD_TRANS_DISCONNECT);
01311         return; // Endpoint not valid
01312     }
01313 #error TODO check address in list
01314     // Reconfigure USB address of pipe 0 used for all control endpoints
01315     uhd_configure_address(0, uhd_ctrl_request_first->add);
01316 #else
01317     if (!USBHS_IsHostPipeEnable(USBHS, 0) ||
01318             (uhd_ctrl_request_first->add != USBHS_HostGetAddr(USBHS, 0))) {
01319         USBH_HAL_ControlReqEnd(UHD_TRANS_DISCONNECT);
01320         return; // Endpoint not valid
01321     }
01322 #endif
01323 
01324     // Fill pipe
01325     USBHS_HostSetToken(USBHS, 0, USBHS_HSTPIPCFG_PTOKEN_SETUP);
01326     USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_TXSTPIC);
01327     assert(sizeof(setup) == sizeof(uint64_t));
01328 
01329     pEpData = (volatile uint64_t*)USBHS_RAM_ADDR;
01330     memory_sync();
01331     *pEpData = setup.value64;
01332     memory_barrier();
01333 
01334     uhd_ctrl_request_timeout = 5000;
01335     USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_TXSTPES);
01336     // Acknowledge FIFO control and unfreeze Pipe
01337     USBHS_HostDisablePipeIntType(USBHS, 0, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC));
01338     
01339 }
01340 
01341 /**
01342  * \internal
01343  * \brief Starts the DATA IN phase on control endpoint
01344  */
01345 static void USBH_HAL_PhaseDataInStart(void)
01346 {
01347     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_DATA_IN;
01348     // set pipe token
01349     USBHS_HostSetToken(USBHS, 0, USBHS_HSTPIPCFG_PTOKEN_IN);
01350     // Ack In and Short packet
01351     USBHS_HostAckPipeIntType(USBHS, 0, (USBHS_HSTPIPICR_RXINIC | USBHS_HSTPIPICR_SHORTPACKETIC) );
01352     
01353     USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_RXINES);
01354     // Acknowledge FIFO control and unfreeze Pipe
01355     USBHS_HostDisablePipeIntType(USBHS, 0, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC) );
01356                                             
01357     memory_sync();
01358 }
01359 
01360 /**
01361  * \internal
01362  * \brief Manages the DATA IN phase on control endpoint
01363  */
01364 static void USBH_HAL_PhaseDataIn(void)
01365 {
01366     bool b_short_packet;
01367     uint8_t *pEpData;
01368     uint8_t bPipe = 0;
01369     uint8_t nb_byte_received;
01370 
01371     // Get information to read data
01372     nb_byte_received = USBHS_HostGetPipeByteCount(USBHS, bPipe);
01373 #ifdef USB_HOST_HUB_SUPPORT
01374     //! In HUB mode, the control pipe is always configured to 64B
01375     //! thus the short packet flag must be computed
01376     b_short_packet = (nb_byte_received != USBHS_HostGetSize(USBHS, 0));
01377     USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_SHORTPACKETIC);
01378 #else
01379     b_short_packet = (USBHS_HostGetIntTypeStatus(USBHS, 0, USBHS_HSTPIPISR_SHORTPACKETI) == USBHS_HSTPIPISR_SHORTPACKETI)? true:false;
01380 #endif
01381 
01382     pEpData =  (uint8_t*)((uint32_t*)USBHS_RAM_ADDR
01383                                     + (EPT_VIRTUAL_SIZE * bPipe));
01384 uhd_ctrl_receiv_in_read_data:
01385   memory_sync();
01386     // Copy data from pipe to payload buffer
01387     while (uhd_ctrl_request_first->payload_size && nb_byte_received) {
01388         *uhd_ctrl_request_first->payload++ = *pEpData++;
01389         memory_sync();
01390         uhd_ctrl_nb_trans++;
01391         uhd_ctrl_request_first->payload_size--;
01392         nb_byte_received--;
01393         memory_barrier();
01394     }
01395 
01396     if (!uhd_ctrl_request_first->payload_size && nb_byte_received) {
01397         // payload buffer is full to store data remaining
01398         if (uhd_ctrl_request_first->callback_run == NULL
01399                 || !uhd_ctrl_request_first->callback_run(
01400                 USBHS_HostGetAddr(USBHS, bPipe),
01401                 &uhd_ctrl_request_first->payload,
01402                 &uhd_ctrl_request_first->payload_size)) {
01403             // DATA phase aborted by host
01404             goto uhd_ctrl_phase_data_in_end;
01405         }
01406         // The payload buffer has been updated by the callback
01407         // thus the data load can restart.
01408         goto uhd_ctrl_receiv_in_read_data;
01409     }
01410 
01411     // Test short packet
01412     if ((uhd_ctrl_nb_trans == uhd_ctrl_request_first->req.wLength)
01413             || b_short_packet) {
01414         // End of DATA phase or DATA phase abort from device
01415 uhd_ctrl_phase_data_in_end:
01416         USBH_HAL_OutZLP();
01417         return;
01418     }
01419 
01420     // Send a new IN packet request
01421     USBHS_HostEnablePipeIntType(USBHS, bPipe, USBHS_HSTPIPIER_RXINES);
01422     // ack Fifocon and unfreeze pipe
01423     USBHS_HostDisablePipeIntType(USBHS, bPipe, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC ));
01424 }
01425 
01426 /**
01427  * \internal
01428  * \brief Starts the ZLP IN phase on control endpoint
01429  */
01430 static void USBH_HAL_InZLP(void)
01431 {
01432     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_ZLP_IN;
01433     USBHS_HostSetToken(USBHS, 0, USBHS_HSTPIPCFG_PTOKEN_IN);
01434     USBHS_HostAckPipeIntType(USBHS, 0, (USBHS_HSTPIPICR_RXINIC | USBHS_HSTPIPICR_SHORTPACKETIC) );
01435     /*uhd_ack_in_received(0);
01436     uhd_ack_short_packet(0);*/
01437     USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_RXINES);
01438     // ack Fifocon and unfreeze pipe
01439     USBHS_HostDisablePipeIntType(USBHS, 0, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC ));
01440     memory_sync();
01441 }
01442 
01443 /**
01444  * \internal
01445  * \brief Manages the DATA OUT phase on control endpoint
01446  */
01447 static void USBH_HAL_PhaseDataOut(void)
01448 {
01449     uint8_t *pEpData;
01450     uint8_t bPipe = 0;
01451     uint8_t ep_ctrl_size;
01452 
01453     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_DATA_OUT;
01454 
01455     if (uhd_ctrl_nb_trans == uhd_ctrl_request_first->req.wLength) {
01456         // End of DATA phase
01457         USBH_HAL_InZLP();
01458         return;
01459     }
01460 
01461     if (!uhd_ctrl_request_first->payload_size) {
01462         // Buffer empty, then request a new buffer
01463         if (uhd_ctrl_request_first->callback_run==NULL
01464                 || !uhd_ctrl_request_first->callback_run(
01465                 USBHS_HostGetAddr(USBHS, bPipe),
01466                 &uhd_ctrl_request_first->payload,
01467                 &uhd_ctrl_request_first->payload_size)) {
01468             // DATA phase aborted by host
01469             USBH_HAL_InZLP();
01470             return;
01471         }
01472     }
01473 
01474 #ifdef USB_HOST_HUB_SUPPORT
01475     // TODO
01476 #else
01477     ep_ctrl_size = USBHS_HostGetSize(USBHS, bPipe);
01478 #endif
01479 
01480     // Fill pipe
01481     USBHS_HostSetToken(USBHS, bPipe, USBHS_HSTPIPCFG_PTOKEN_OUT);
01482     //uhd_configure_pipe_token(0, USBHS_HSTPIPCFG_PTOKEN_OUT);
01483     //uhd_ack_out_ready(0);
01484     USBHS_HostAckPipeIntType(USBHS, bPipe, USBHS_HSTPIPICR_TXOUTIC);
01485     pEpData =  (uint8_t*)((uint32_t*)USBHS_RAM_ADDR
01486                                     + (EPT_VIRTUAL_SIZE * bPipe));
01487     memory_sync();
01488     while ((uhd_ctrl_nb_trans < uhd_ctrl_request_first->req.wLength)
01489             && ep_ctrl_size && uhd_ctrl_request_first->payload_size) {
01490         *pEpData++ = *uhd_ctrl_request_first->payload++;
01491         memory_sync();
01492         uhd_ctrl_nb_trans++;
01493         ep_ctrl_size--;
01494         uhd_ctrl_request_first->payload_size--;
01495         memory_barrier();
01496     }
01497     //uhd_enable_out_ready_interrupt(0);
01498     USBHS_HostEnablePipeIntType(USBHS, bPipe, USBHS_HSTPIPIER_TXOUTES);
01499     USBHS_HostDisablePipeIntType(USBHS, bPipe, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC ) );
01500     //uhd_unfreeze_pipe(0);
01501 }
01502 
01503 /**
01504  * \internal
01505  * \brief Starts the ZLP OUT phase on control endpoint
01506  */
01507 static void USBH_HAL_OutZLP(void)
01508 {
01509     uint8_t bPipe = 0;
01510     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_ZLP_OUT;
01511     USBHS_HostSetToken(USBHS, bPipe, USBHS_HSTPIPCFG_PTOKEN_OUT);
01512     //uhd_configure_pipe_token(0, USBHS_HSTPIPCFG_PTOKEN_OUT);
01513     USBHS_HostAckPipeIntType(USBHS, bPipe, USBHS_HSTPIPICR_TXOUTIC);
01514     //uhd_ack_out_ready(0);
01515     USBHS_HostEnablePipeIntType(USBHS, bPipe, USBHS_HSTPIPIER_TXOUTES);
01516     //uhd_enable_out_ready_interrupt(0);
01517     USBHS_HostDisablePipeIntType(USBHS, bPipe, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC));
01518     //uhd_unfreeze_pipe(0);
01519 }
01520 
01521 /**
01522  * \internal
01523  * \brief Call the callback linked to control request
01524  * and start the next request from the queue.
01525 */
01526 static void USBH_HAL_ControlReqEnd(USBH_XfrStatus_t status)
01527 {
01528     uint8_t bPipe = 0;
01529     irqflags_t flags;
01530     uhd_callback_setup_end_t callback_end;
01531     struct uhd_ctrl_request_t *request_to_free;
01532     bool b_new_request;
01533 
01534     uhd_ctrl_request_timeout = 0;
01535 
01536     // Remove request from the control request list
01537     callback_end = uhd_ctrl_request_first->callback_end;
01538     request_to_free = uhd_ctrl_request_first;
01539     flags = cpu_irq_save();
01540     uhd_ctrl_request_first = uhd_ctrl_request_first->next_request;
01541     b_new_request = (uhd_ctrl_request_first != NULL);
01542     cpu_irq_restore(flags);
01543     free(request_to_free);
01544 
01545     // Call callback
01546     if (callback_end != NULL) {
01547         callback_end(USBHS_HostGetAddr(USBHS, bPipe), status, uhd_ctrl_nb_trans);
01548     }
01549 
01550     // If a setup request is pending and no started by previous callback
01551     if (b_new_request) {
01552         USBH_HAL_PhaseControlSetup();
01553     }
01554     if (uhd_b_suspend_requested) {
01555         // A suspend request has been delay after all setup request
01556         uhd_b_suspend_requested = false;
01557         USBH_HAL_Suspend();
01558     }
01559 }
01560 
01561 /**
01562  * \internal
01563  * \brief Translates the USBHS pipe error to UHD error
01564  *
01565  * \param pipe  Pipe number to use
01566  *
01567  * \return UHD transfer error
01568  */
01569 static USBH_XfrStatus_t USBH_HAL_GetPipeError(uint8_t pipe)
01570 {
01571     uint32_t error = USBHS_HostGetErr(USBHS, pipe, (USBHS_HSTPIPERR_DATATGL |
01572                                                     USBHS_HSTPIPERR_TIMEOUT |
01573                                                     USBHS_HSTPIPERR_PID |
01574                                                     USBHS_HSTPIPERR_DATAPID));
01575     USBHS_HostClearErr(USBHS, pipe, 0xFF);
01576     switch(error) {
01577     case USBHS_HSTPIPERR_DATATGL:
01578         return UHD_TRANS_DT_MISMATCH;
01579     case USBHS_HSTPIPERR_TIMEOUT:
01580         return UHD_TRANS_NOTRESPONDING;
01581     case USBHS_HSTPIPERR_DATAPID:
01582     case USBHS_HSTPIPERR_PID:
01583     default:
01584         return UHD_TRANS_PIDFAILURE;
01585     }
01586 }
01587 
01588 /**
01589  * \internal
01590  * \brief Returns the pipe number matching a USB endpoint
01591  *
01592  * \param Addr   USB address
01593  * \param bEndpoint  Endpoint number
01594  *
01595  * \return Pipe number
01596  */
01597 static uint8_t USBH_HAL_GetPipe(uint8_t Addr, uint8_t bEndpoint)
01598 {
01599     uint8_t pipe;
01600 
01601     // Search pipe
01602     for (pipe = 0; pipe < USBHS_EPT_NUM; pipe++) {
01603 
01604         if (!USBHS_IsHostPipeEnable(USBHS, pipe)) {
01605             continue;
01606         }
01607         if (Addr != USBHS_HostGetAddr(USBHS,pipe)) {
01608             continue;
01609         }
01610         if (bEndpoint != USBHS_GetPipeEpAddr(USBHS, pipe)) {
01611             continue;
01612         }
01613         break;
01614     }
01615     return pipe;
01616 }
01617 
01618 #ifdef UHD_PIPE_FIFO_SUPPORTED
01619 /**
01620  * \internal
01621  */
01622 static void USBH_HAL_PipeInReceived(uint8_t pipe)
01623 {
01624     USBH_PipeJob_t *pJob = &uhd_pipe_job[pipe - 1];
01625     uint32_t nb_data = 0, i;
01626     uint32_t nb_remain = pJob->buf_size - pJob->nb_trans;
01627     uint32_t pkt_size = USBHS_HostGetSize(USBHS, pipe);
01628     uint8_t *ptr_src =  (uint8_t*)((uint32_t*)USBHS_RAM_ADDR
01629                                     + (EPT_VIRTUAL_SIZE * pipe));
01630     uint8_t *ptr_dst = &pJob->buf[pJob->nb_trans];
01631     bool b_full = false, b_short = false;
01632 
01633     if (!pJob->busy) {
01634         return; // No job is running, then ignore it (system error)
01635     }
01636 
01637     // Read byte count
01638     nb_data = USBHS_HostGetPipeByteCount(USBHS, pipe);
01639     if (nb_data < pkt_size) {
01640         b_short = true;
01641     }
01642     // Copy data if there is
01643     if (nb_data > 0) {
01644         if (nb_data >= nb_remain) {
01645             nb_data = nb_remain;
01646             b_full = true;
01647         }
01648         // Modify job information
01649         pJob->nb_trans += nb_data;
01650         // Copy FIFO to buffer
01651         for (i = 0; i < nb_data; i++) {
01652             *ptr_dst++ = *ptr_src++;
01653             memory_sync();
01654         }
01655     }
01656     // Clear FIFO Status
01657     USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_FIFOCONC);
01658     // Finish job on error or short packet
01659     if (b_full || b_short) {
01660         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);
01661         USBHS_HostDisablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIDR_SHORTPACKETIEC | USBHS_HSTPIPIDR_RXINEC) );
01662         //uhd_disable_short_packet_interrupt(pipe);
01663         //uhd_disable_in_received_interrupt(pipe);
01664         USBHS_HostPipeIntDisable(USBHS, pipe);
01665         //uhd_disable_pipe_interrupt(pipe);
01666         USBHS_HostDisableInReq(USBHS, pipe);
01667         //uhd_disable_continuous_in_mode(pipe);
01668         USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01669     }
01670 }
01671 
01672 /**
01673  * \internal
01674  */
01675 static void USBH_HAL_PipeOutReady(uint8_t pipe)
01676 {
01677     USBH_PipeJob_t *pJob = &uhd_pipe_job[pipe - 1];
01678     uint32_t pkt_size = USBHS_HostGetSize(USBHS, pipe);
01679     uint32_t nb_data = 0, i;
01680     uint32_t nb_remain;
01681     uint8_t *ptr_src;
01682     uint8_t *ptr_dst;
01683 
01684     if (!pJob->busy) {
01685         return; // No job is running, then ignore it (system error)
01686     }
01687 
01688     // Transfer data
01689     USBHS_HostAckPipeIntType(USBHS,pipe, USBHS_HSTPIPICR_TXOUTIC);
01690 
01691     nb_remain = pJob->buf_size - pJob->nb_trans;
01692     nb_data = min(nb_remain, pkt_size);
01693 
01694     // If not ZLP, fill FIFO
01695     if (nb_data) {
01696         // Fill FIFO
01697         ptr_dst =  (uint8_t*)((uint32_t*)USBHS_RAM_ADDR
01698                                     + (EPT_VIRTUAL_SIZE * pipe));
01699         ptr_src = &pJob->buf[pJob->nb_trans];
01700         // Modify job information
01701         pJob->nb_trans += nb_data;
01702 
01703         memory_sync();
01704         // Copy buffer to FIFO
01705         for (i = 0; i < nb_data; i++) {
01706             *ptr_dst++ = *ptr_src++;
01707             memory_sync();
01708         }
01709     }
01710     // Switch to next bank
01711     USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_FIFOCONC);
01712     // ZLP is cleared if last packet is short
01713     if (nb_data < pkt_size) {
01714         pJob->b_shortpacket = false;
01715     }
01716     // All transfer done, including ZLP, Finish Job
01717     if (pJob->nb_trans >= pJob->buf_size && !pJob->b_shortpacket) {
01718         // At least one bank there, wait to freeze pipe
01719         USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_TXOUTEC);
01720         //uhd_disable_out_ready_interrupt(pipe);
01721         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_NBUSYBKES);
01722         return;
01723     }
01724 }
01725 
01726 #endif // #ifdef UHD_PIPE_FIFO_SUPPORTED
01727 
01728 #ifdef UHD_PIPE_DMA_SUPPORTED
01729 /**
01730  * \internal
01731  * \brief Computes and starts the next transfer on a pipe
01732  *
01733  * \param pipe  Pipe number
01734  */
01735 static void USBH_HAL_PipeXfrCmplt(uint8_t pipe)
01736 {
01737     uint32_t uhd_dma_ctrl = 0;
01738     USBH_PipeJob_t *pJob;
01739     uint32_t max_trans;
01740     uint32_t next_trans;
01741     irqflags_t flags;
01742     Usbhs    *pUdp  = USBHS;
01743     UsbhsHstdma *pUsbDma = &pUdp->USBHS_HSTDMA[pipe-1];
01744 
01745     // Get job corresponding at endpoint
01746     pJob = &uhd_pipe_job[pipe - 1];
01747 
01748     if (!pJob->busy) {
01749         return; // No job is running, then ignore it (system error)
01750     }
01751 
01752     if (pJob->nb_trans != pJob->buf_size) {
01753         // Need to send or receive other data
01754         next_trans = pJob->buf_size - pJob->nb_trans;
01755         max_trans = UHD_PIPE_MAX_TRANS;
01756         if (USBHS_HostGetToken(USBHS, pipe) == USBHS_HSTPIPCFG_PTOKEN_IN) {
01757             // 256 is the maximum of IN requests via UPINRQ
01758             if ((256L*USBHS_HostGetSize(USBHS, pipe)) < UHD_PIPE_MAX_TRANS) {
01759                 max_trans = 256L * USBHS_HostGetSize(USBHS, pipe);
01760             }
01761         }
01762         if (max_trans < next_trans) {
01763             // The USB hardware supports a maximum
01764             // transfer size of UHD_PIPE_MAX_TRANS Bytes
01765             next_trans = max_trans;
01766         }
01767 
01768         if (next_trans == UHD_PIPE_MAX_TRANS) {
01769             // Set 0 to transfer the maximum
01770             uhd_dma_ctrl = USBHS_HSTDMACONTROL_BUFF_LENGTH(0);
01771         } else {
01772             uhd_dma_ctrl = USBHS_HSTDMACONTROL_BUFF_LENGTH(next_trans);
01773         }
01774 
01775         if (USBHS_HSTPIPCFG_PTOKEN_OUT == USBHS_HostGetToken(USBHS, pipe)) {
01776             if (0 != (next_trans % USBHS_HostGetSize(USBHS, pipe))) {
01777                 // Enable short packet option
01778                 // else the DMA transfer is accepted
01779                 // and interrupt DMA valid but nothing is sent.
01780                 uhd_dma_ctrl |= USBHS_HSTDMACONTROL_END_B_EN;
01781                 // No need to request another ZLP
01782                 pJob->b_shortpacket = false;
01783             }
01784         } else {
01785             if ((USBEndpointDescriptor_ISOCHRONOUS != USBHS_HostGetPipeType(USBHS, pipe))
01786                     || ((int)next_trans <= USBHS_HostGetSize(USBHS, pipe))) {
01787                 // Enable short packet reception
01788                 uhd_dma_ctrl |= USBHS_HSTDMACONTROL_END_TR_IT
01789                         | USBHS_HSTDMACONTROL_END_TR_EN;
01790             }
01791         }
01792         // Start USB DMA to fill or read fifo of the selected endpoint
01793         USBHS_SetHostDmaBuffAdd(pUsbDma, (uint32_t) &pJob->buf[pJob->nb_trans]);
01794         uhd_dma_ctrl |= USBHS_HSTDMACONTROL_END_BUFFIT |
01795                 USBHS_HSTDMACONTROL_CHANN_ENB;
01796 
01797         // Disable IRQs to have a short sequence
01798         // between read of EOT_STA and DMA enable
01799         flags = cpu_irq_save();
01800         if (!(USBHS_GetHostPipeDmaStatus(pUsbDma)
01801                 & USBHS_HSTDMASTATUS_END_TR_ST)) {
01802             if (USBHS_HSTPIPCFG_PTOKEN_IN == USBHS_HostGetToken(USBHS, pipe)) {
01803                 uint32_t pipe_size = USBHS_HostGetSize(USBHS, pipe);
01804                 USBHS_HostInReq(USBHS, pipe, (next_trans + pipe_size-1) / pipe_size);
01805             }
01806             if (!pJob->b_periodic_start) {
01807                 USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_NBUSYBKEC);
01808                 USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_PFREEZEC);
01809             } else {
01810                 // Last bank not sent, just start
01811                 if (USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_NBUSYBKE)) {
01812                     USBHS_HostDisablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIDR_NBUSYBKEC | USBHS_HSTPIPIDR_PFREEZEC));
01813                 } else {
01814                     // Wait SOF to start
01815                 }
01816             }
01817             SCB_CleanInvalidateDCache();
01818             USBHS_HostConfigureDma(pUsbDma, uhd_dma_ctrl);
01819             pJob->nb_trans += next_trans;
01820             cpu_irq_restore(flags);
01821             return;
01822         }
01823         cpu_irq_restore(flags);
01824         // Here a ZLP has been received
01825         // and the DMA transfer must be not started.
01826         // It is the end of transfer
01827         pJob->buf_size = pJob->nb_trans;
01828     }
01829     if (USBHS_HSTPIPCFG_PTOKEN_OUT == USBHS_HostGetToken(USBHS, pipe)) {
01830         if (pJob->b_shortpacket) {
01831             // Need to send a ZLP (No possible with USB DMA)
01832             // enable interrupt to wait a free bank to sent ZLP
01833             USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_TXOUTIC);
01834             if (USBHS_HostGetIntTypeStatus(USBHS, pipe, USBHS_HSTPIPISR_RWALL)) {
01835                 // Force interrupt in case of pipe already free
01836                 USBHS_HostSetPipeIntType(USBHS, pipe, USBHS_HSTPIPIFR_TXOUTIS);
01837             }
01838             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_TXOUTES);
01839             return;
01840         }
01841     }
01842     // Call callback to signal end of transfer
01843     USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01844 }
01845 
01846 /**
01847  * \internal
01848  * \brief Manages the pipe DMA interrupt
01849  *
01850  * \param pipe  Pipe number
01851  */
01852 static void USBH_HAL_PipeDmaInterrupt(uint8_t pipe)
01853 {
01854     USBH_PipeJob_t *pJob;
01855     uint32_t nb_remaining;
01856     Usbhs    *pUdp  = USBHS;
01857     UsbhsHstdma *pUsbDma = &pUdp->USBHS_HSTDMA[pipe-1];
01858 
01859     SCB_CleanInvalidateDCache();
01860     if (USBHS_GetHostPipeDmaStatus(pUsbDma) & USBHS_HSTDMASTATUS_CHANN_ENB) 
01861     {
01862         return; // Ignore EOT_STA interrupt
01863     }
01864     // Save number of data no transfered
01865     nb_remaining = ( (USBHS_GetHostPipeDmaStatus(pUsbDma) & USBHS_HSTDMASTATUS_BUFF_COUNT_Msk) >> USBHS_HSTDMASTATUS_BUFF_COUNT_Pos);
01866     memory_sync();
01867     if (nb_remaining) {
01868         // Get job corresponding at endpoint
01869         pJob = &uhd_pipe_job[pipe - 1];
01870 
01871         // Transfer no complete (short packet or ZLP) then:
01872         // Update number of transfered data
01873         pJob->nb_trans -= nb_remaining;
01874 
01875         // Set transfer complete to stop the transfer
01876         pJob->buf_size = pJob->nb_trans;
01877     }
01878 
01879     if (USBHS_HSTPIPCFG_PTOKEN_OUT == USBHS_HostGetToken(USBHS, pipe)) 
01880     {
01881         // Wait that all banks are free to freeze clock of OUT endpoint
01882         // and call callback
01883         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_NBUSYBKES);
01884 
01885         // For ISO out, start another DMA transfer since no ACK needed
01886         if (USBHS_HostGetPipeType(USBHS, pipe) == USBHS_HSTPIPCFG_PTYPE_ISO) 
01887         {
01888             USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01889         }
01890     }
01891     else
01892     {
01893         if (!USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_PFREEZE)) {
01894             // Pipe is not freeze in case of :
01895             // - incomplete transfer when the request number INRQ is not complete.
01896             // - low USB speed and with a high CPU frequency,
01897             // a ACK from host can be always running on USB line.
01898 
01899             if (nb_remaining) {
01900                 // Freeze pipe in case of incomplete transfer
01901                 USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);
01902             } else {
01903                 // Wait freeze in case of ASK on going
01904                 while (!USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_PFREEZE)) {
01905                 }
01906             }
01907         }
01908 
01909         USBH_HAL_PipeXfrCmplt(pipe);
01910     }
01911 }
01912 #endif // ifdef UHD_PIPE_DMA_SUPPORTED
01913 
01914 /**
01915  * \internal
01916  * \brief Manages the following pipe interrupts:
01917  * - Real end of USB transfers (bank empty)
01918  * - One bank is free to send a OUT ZLP
01919  * - Stall received
01920  * - Error during transfer
01921  *
01922  * \param pipe  Pipe number
01923  */
01924 static void USBH_HAL_PipeInterrupt(uint8_t pipe)
01925 {
01926     uint32_t status = USBHS_HostGetIntTypeStatus(USBHS, pipe, 0xFFFFFFFF);
01927     uint32_t statusInt = status & USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, 0xFFFFFFFF);
01928 #ifdef UHD_PIPE_FIFO_SUPPORTED
01929     // for none DMA endpoints
01930     if (!Is_uhd_pipe_dma_supported(pipe)) {
01931         // SHORTPACKETI: Short received
01932         if (statusInt & USBHS_HSTPIPISR_SHORTPACKETI) 
01933         {
01934             USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_SHORTPACKETIC); //uhd_ack_short_packet(pipe);
01935             USBH_HAL_PipeInReceived(pipe);
01936             return;
01937         }
01938         // RXIN: Full packet received
01939         if (statusInt & USBHS_HSTPIPIMR_RXINE ) {
01940             USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_RXINIC);//uhd_ack_in_received(pipe);
01941             USBH_HAL_PipeInReceived(pipe);
01942             return;
01943         }
01944         // TXOUT: packet sent
01945         if (statusInt & USBHS_HSTPIPISR_TXOUTI) {
01946             USBH_HAL_PipeOutReady(pipe);
01947             return;
01948         }
01949         // OUT: all banks sent
01950         if (USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_NBUSYBKE)
01951                 && (0==USBHS_HostGetNumOfBusyBank(USBHS, pipe))) 
01952         {
01953             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);
01954             USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_NBUSYBKEC );
01955             //uhd_disable_bank_interrupt(pipe);
01956             USBHS_HostPipeIntDisable(USBHS, pipe);
01957             //uhd_disable_pipe_interrupt(pipe);
01958             USBHS_HostEnableAutoSw(USBHS, pipe);
01959             //uhd_enable_pipe_bank_autoswitch(pipe);
01960             USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01961             return;
01962         }
01963         if (status & USBHS_HSTPIPISR_RXSTALLDI) {
01964             USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_RXSTALLDIC); //uhd_ack_stall(pipe);
01965             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_RSTDTS);
01966             //uhd_reset_data_toggle(pipe);
01967             USBH_HAL_PipeAbort(pipe, UHD_TRANS_STALL);
01968             return;
01969         }
01970         if (status & USBHS_HSTPIPISR_PERRI) {
01971             // Get and ack error
01972             USBH_HAL_PipeAbort(pipe, USBH_HAL_GetPipeError(pipe));
01973             return;
01974         }
01975         assert(false); // Error system
01976         return;
01977     }
01978 #endif // UDD_EP_FIFO_SUPPORTED
01979 
01980 #ifdef UHD_PIPE_DMA_SUPPORTED
01981     // for DMA endpoints
01982     if (USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_NBUSYBKE) && (0==USBHS_HostGetNumOfBusyBank(USBHS, pipe))) {
01983         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);//uhd_freeze_pipe(pipe);
01984         USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_NBUSYBKEC);//uhd_disable_bank_interrupt(pipe);
01985         // For ISO, no ACK, finished when DMA done
01986         if (!(USBHS_HostGetPipeType(USBHS, pipe) == USBHS_HSTPIPCFG_PTYPE_ISO)) {
01987             USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01988         }
01989         return;
01990     }
01991     if (USBHS_HSTPIPIMR_TXOUTE & statusInt) 
01992     {
01993         USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_TXOUTEC);
01994         //uhd_disable_out_ready_interrupt(pipe);
01995         // One bank is free then send a ZLP
01996         USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_TXOUTIC); //uhd_ack_out_ready(pipe);
01997         USBHS_HostDisablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC));
01998         //USBHS_HostDisablePipeIntType(USBHS, pipe, );
01999         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_NBUSYBKES);
02000         return;
02001     }
02002     if (status & USBHS_HSTPIPISR_RXSTALLDI) {
02003         USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_RXSTALLDIC);//  uhd_ack_stall(pipe);
02004         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_RSTDTS);
02005         USBH_HAL_PipeAbort(pipe, UHD_TRANS_STALL);
02006         return;
02007     }
02008     if (status & USBHS_HSTPIPISR_PERRI) {
02009         // Get and ack error
02010         USBH_HAL_PipeAbort(pipe, USBH_HAL_GetPipeError(pipe));
02011         return;
02012     }
02013     assert(false); // Error system
02014 #endif // UHD_PIPE_DMA_SUPPORTED
02015 }
02016 
02017 /**
02018  * \internal
02019  * \brief Aborts the on going transfer on a pipe
02020  *
02021  * \param pipe   Pipe number
02022  * \param status Reason of abort
02023  */
02024 static void USBH_HAL_PipeAbort(uint8_t pipe, USBH_XfrStatus_t status)
02025 {
02026     Usbhs    *pUdp  = USBHS;
02027     UsbhsHstdma *pUsbDma = &pUdp->USBHS_HSTDMA[pipe-1];
02028     // Stop transfer
02029     USBHS_HostPipeReset(USBHS, pipe);
02030 
02031     // Autoswitch bank and interrupts has been reseted, then re-enable it
02032     USBHS_HostEnableAutoSw(USBHS, pipe);
02033     USBHS_HostEnablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIER_RXSTALLDES | USBHS_HSTPIPIER_PERRES) );
02034     //uhd_enable_pipe_error_interrupt(pipe);
02035     USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_TXOUTEC);
02036 #ifdef UHD_PIPE_DMA_SUPPORTED
02037     if (Is_uhd_pipe_dma_supported(pipe)) {
02038         USBHS_HostConfigureDma(pUsbDma, 0);
02039     }
02040 #endif
02041     USBH_HAL_PipeXfrEnd(pipe, status);
02042 }
02043 
02044 /**
02045  * \internal
02046  * \brief Call the callback linked to the end of pipe transfer
02047  *
02048  * \param pipe   Pipe number
02049  * \param status Status of the transfer
02050  */
02051 static void USBH_HAL_PipeXfrEnd(uint8_t pipe, USBH_XfrStatus_t status)
02052 {
02053     uint32_t dev_addr ,dev_ep;
02054     USBH_PipeJob_t *pJob;
02055     
02056     // Get job corresponding at endpoint
02057     pJob = &uhd_pipe_job[pipe - 1];
02058     if (pJob->busy == false) {
02059         return; // No job running
02060     }
02061     pJob->busy = false;
02062     if (NULL == pJob->call_end) {
02063         return; // No callback linked to job
02064     }
02065     dev_addr = USBHS_HostGetAddr(USBHS, pipe);
02066     dev_ep = USBHS_GetPipeEpAddr(USBHS, pipe);
02067     pJob->call_end(dev_addr, dev_ep, status, pJob->nb_trans);
02068 }
02069 
02070 //@}
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines