SAMV71 Xplained Ultra Software Package 1.4

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_HSTCTRL_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     else if (pipe_dma_int != USBHS_EPT_NUM) {
00436         TRACE_DEBUG("Pipe%x ", pipe_dma_int);
00437         // Interrupt DMA acked by bulk/interrupt/isochronous endpoint
00438         USBH_HAL_PipeDmaInterrupt(pipe_dma_int);
00439     }
00440   #endif
00441     // USB bus reset detection
00442     else if (status & USBHS_HSTISR_RSTI) 
00443     {
00444         TRACE_INFO_WP("RST ");
00445         USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_RSTIC);
00446         if (uhd_reset_callback != NULL) {
00447               uhd_reset_callback();
00448         }
00449     }
00450     
00451       // Check USB clock ready after asynchronous interrupt
00452 
00453       // Manage dis/connection event
00454     else if (statusInt & USBHS_HSTIMR_DDISCIE) {       
00455         USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_DDISCIC);
00456         USBHS_HostIntDisable(USBHS, USBHS_HSTIDR_DDISCIEC);
00457         TRACE_INFO("Disconnect--\n\r");
00458         // Stop reset signal, in case of disconnection during reset
00459         USBHS_StopReset();
00460         // Disable wakeup/resumes interrupts,
00461         // in case of disconnection during suspend mode
00462         USBHS_HostIntDisable(USBHS, ( USBHS_HSTIDR_HWUPIEC
00463                                     | USBHS_HSTIDR_RSMEDIEC
00464                                     | USBHS_HSTIDR_RXRSMIEC));
00465         uhd_sleep_mode(UHD_STATE_DISCONNECT);
00466         USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_DCONNIC);
00467         USBHS_HostIntEnable(USBHS, USBHS_HSTIER_DCONNIES);
00468         USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_HWUPIC);
00469         USBHS_HostIntEnable(USBHS, USBHS_HSTIER_HWUPIES);
00470     #ifdef USB_HOST_HS_SUPPORT
00471         USBHS_SetHostHighSpeed(USBHS);
00472     #endif
00473           //otg_freeze_clock();
00474         uhd_suspend_start = 0;
00475         uhd_resume_start = 0;
00476         USBH_notify_connection(false);
00477     }
00478     else if (statusInt & USBHS_HSTIMR_DCONNIE) {
00479         TRACE_INFO("Connect-- ");
00480         USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_DCONNIC);
00481         USBHS_HostIntDisable(USBHS,USBHS_HSTIDR_DCONNIEC);
00482         USBHS_ClearHostStatus(USBHS, USBHS_HSTICR_DDISCIC);
00483         USBHS_HostIntEnable(USBHS, USBHS_HSTIER_DDISCIES);
00484         USBHS_EnableSOF(USBHS);
00485         uhd_sleep_mode(UHD_STATE_IDLE);
00486         uhd_suspend_start = 0;
00487         uhd_resume_start = 0;
00488         USBH_notify_connection(true);
00489     }
00490 
00491     /* If Wakeup interrupt is enabled and triggered and connection interrupt is enabled  */
00492     else if((statusInt & USBHS_HSTISR_HWUPI ) && USBHS_IsHostIntEnable(USBHS, USBHS_HSTIMR_DCONNIE ) )
00493     {
00494         while (!USBHS_ISUsableClock(USBHS));
00495         USBHS_UnFreezeClock(USBHS);
00496         // Here the wakeup interrupt has been used to detect connection
00497          // with an asynchrone interrupt
00498         USBHS_HostIntDisable(USBHS, USBHS_HSTIDR_HWUPIEC);
00499         //uhd_sleep_mode(UHD_STATE_IDLE);
00500         
00501         USBHS_Set(USBHS, USBHS_SR_VBUSRQ);// enable VBUS
00502         uhd_sleep_mode(UHD_STATE_DISCONNECT);
00503         UHC_VBUS_CHANGE(true); 
00504     }
00505 
00506 
00507     else if (USBHS_IsHostIntEnable(USBHS, USBHS_HSTIMR_HWUPIE) && (USBHS_GetHostStatus(USBHS, (USBHS_HSTISR_HWUPI |  USBHS_HSTISR_RSMEDI | USBHS_HSTISR_RXRSMI) ))) 
00508     {
00509         
00510         TRACE_INFO_WP("\n\rWKP ");
00511         while (!USBHS_ISUsableClock(USBHS));
00512         USBHS_UnFreezeClock(USBHS);
00513         // Disable wakeup/resumes interrupts
00514         USBHS_HostIntDisable(USBHS, (USBHS_HSTIDR_HWUPIEC
00515                                      | USBHS_HSTIDR_RSMEDIEC
00516                                      | USBHS_HSTIDR_RXRSMIEC) );
00517         USBHS_EnableSOF(USBHS);
00518         if ((!(USBHS_HSTISR_RSMEDI & status))
00519                 &&(!(USBHS_HSTISR_DDISCI & status))) {
00520             // It is a upstream resume
00521             // Note: When the CPU exits from a deep sleep mode, the event
00522             // Is_uhd_upstream_resume() can be not detected
00523             // because the USB clock are not available.
00524 
00525             // In High speed mode a downstream resume must be sent
00526             // after a upstream to avoid a disconnection.
00527             if (USBHS_IsUsbHighSpeed(USBHS)) {
00528                 USBHS_Resume();
00529             }
00530         }
00531         // Wait 50ms before restarting transfer
00532         uhd_resume_start = 50;
00533         uhd_sleep_mode(UHD_STATE_IDLE);
00534     }
00535     else
00536     {
00537         assert(false); // Interrupt event no managed
00538     }
00539     //TRACE_INFO_WP("\n\r");
00540     } 
00541 }
00542 
00543 
00544 void USBH_HAL_EnableUsbHost(void)
00545 {
00546     irqflags_t flags;
00547     
00548     // To avoid USB interrupt before end of initialization
00549     flags = cpu_irq_save();
00550 
00551     //USB_Initialized = true;
00552 
00553     //* Enable USB hardware clock
00554     sysclk_enable_usb();
00555     PMC_EnablePeripheral(ID_USBHS);
00556 
00557     // Always authorize asynchronous USB interrupts to exit of sleep mode
00558     // For SAM3 USB wake up device except BACKUP mode
00559     NVIC_SetPriority((IRQn_Type) ID_USBHS, UHD_USB_INT_LEVEL);
00560     NVIC_EnableIRQ((IRQn_Type) ID_USBHS);
00561 
00562     uhd_sleep_mode(UHD_STATE_OFF);
00563     
00564     PIO_Configure(USB_HOST, PIO_LISTSIZE(USB_HOST));
00565     
00566     PIO_Set(USB_HOST);// Power off USB devices
00567 
00568     USBHS_UsbMode(USBHS, HOST_MODE);
00569  
00570     
00571     USBHS_UsbEnable(USBHS, true);
00572 
00573 #ifndef USB_HOST_HS_SUPPORT
00574     USBHS->USBHS_HSTCTRL |= USBHS_HSTCTRL_SPDCONF_LOW_POWER;
00575 #endif
00576 
00577     uhd_ctrl_request_first = NULL;
00578     uhd_ctrl_request_last = NULL;
00579     uhd_ctrl_request_timeout = 0;
00580     uhd_suspend_start = 0;
00581     uhd_resume_start = 0;
00582     uhd_b_suspend_requested = false;
00583 
00584     // Check USB clock
00585     USBHS_UnFreezeClock(USBHS);
00586     while (!USBHS_ISUsableClock(USBHS));
00587     
00588     // Clear all interrupts that may have been set by a previous host mode
00589     USBHS_ClearHostStatus(USBHS, (USBHS_HSTICR_DCONNIC | USBHS_HSTICR_DDISCIC
00590             | USBHS_HSTICR_HSOFIC  | USBHS_HSTICR_HWUPIC
00591             | USBHS_HSTICR_RSMEDIC | USBHS_HSTICR_RSTIC
00592             | USBHS_HSTICR_RXRSMIC));
00593     //memory_barrier();
00594     memory_sync();
00595 
00596     USBHS_VBusHWC(USBHS, false);
00597     uhd_sleep_mode(UHD_STATE_NO_VBUS);
00598     
00599     
00600      /** Freeze USB clock to use wakeup interrupt
00601      * to detect connection.
00602      * After detection of wakeup interrupt,
00603      * the clock is unfreeze to have the true
00604      * connection interrupt.
00605      */
00606     // wakeup
00607     USBHS_HostIntEnable(USBHS, USBHS_HSTIER_HWUPIES);
00608     uhd_sleep_mode(UHD_STATE_DISCONNECT);
00609     UHC_VBUS_CHANGE(true); /* Changed to HIGH */
00610     
00611     PIO_Clear(USB_HOST);// power on USB device
00612     
00613     // Enable main control interrupt
00614     // Connection, SOF and reset
00615     USBHS_HostIntEnable(USBHS, (USBHS_HSTIER_RSTIES | USBHS_HSTIER_HSOFIES | USBHS_HSTIER_DCONNIES));
00616 
00617     USBHS_FreezeClock(USBHS);
00618     
00619     cpu_irq_restore(flags);
00620 
00621 }
00622 
00623 void USBH_HAL_DisableUsb(bool b_id_stop)
00624 {
00625     irqflags_t flags;
00626 
00627     // Check USB clock ready after a potential sleep mode < IDLE
00628     while (!USBHS_ISUsableClock(USBHS));
00629     USBHS_UnFreezeClock(USBHS);
00630     printf("USB disabled \n\r");
00631     
00632     // (Connection, disconnection, SOF and reset)
00633      USBHS_HostIntDisable(USBHS, (USBHS_HSTICR_DCONNIC | USBHS_HSTICR_DDISCIC
00634             | USBHS_HSTICR_HSOFIC  | USBHS_HSTICR_HWUPIC
00635             | USBHS_HSTICR_RSMEDIC | USBHS_HSTICR_RSTIC
00636             | USBHS_HSTICR_RXRSMIC));
00637 
00638     USBHS_DisableSOF();
00639     USBHS_Ack(USBHS, USBHS_SR_VBUSRQ);
00640     USBH_notify_connection(false);
00641 
00642     flags = cpu_irq_save();
00643     USBHS_FreezeClock(USBHS);
00644     USBHS_UsbEnable(USBHS, false);
00645     sysclk_disable_usb();
00646     PMC_DisablePeripheral(ID_USBHS);
00647     uhd_sleep_mode(UHD_STATE_OFF);
00648     cpu_irq_restore(flags);
00649 }
00650 
00651 USBH_Speed_t USBH_HAL_GetSpeed(void)
00652 {
00653     switch (USBHS_GetUsbSpeed(USBHS)) {
00654 
00655     case USBHS_SR_SPEED_HIGH_SPEED:
00656         return UHD_SPEED_HIGH;
00657 
00658     case USBHS_SR_SPEED_FULL_SPEED:
00659         return UHD_SPEED_FULL;
00660 
00661     case USBHS_SR_SPEED_LOW_SPEED:
00662         return UHD_SPEED_LOW;
00663 
00664     default:
00665         assert(false);
00666         return UHD_SPEED_LOW;
00667     }
00668 }
00669 
00670 uint16_t USBH_HAL_GetFrameNum(void)
00671 {
00672     return USBHS_HostGetSOF();
00673 }
00674 
00675 uint16_t USBH_HAL_GetMicroFrameNum(void)
00676 {
00677     return USBHS_HostGetMSOF();
00678 }
00679 
00680 void USBH_HAL_Reset(uhd_callback_reset_t callback)
00681 {
00682     uhd_reset_callback = callback;
00683     USBHS_Reset();
00684 }
00685 
00686 void USBH_HAL_Suspend(void)
00687 {
00688     uint8_t pipe;
00689     if (uhd_ctrl_request_timeout) {
00690         // Delay suspend after setup requests
00691         uhd_b_suspend_requested = true;
00692         return;
00693     }
00694     // Save pipe freeze states and freeze pipes
00695     uhd_pipes_unfreeze = 0;
00696     for (pipe = 1; pipe < USBHS_EPT_NUM; pipe++) {
00697         uhd_pipes_unfreeze |= (!USBHS_IsHostPipeIntTypeEnable(USBHS,pipe, USBHS_HSTPIPIMR_PFREEZE)) << pipe;
00698         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);
00699     }
00700     // Wait three SOFs before entering in suspend state
00701     uhd_suspend_start = 3;
00702 }
00703 
00704 bool USBH_HAL_IsSuspended(void)
00705 {
00706     return !USBHS_IsEnableSOF(USBHS);
00707 }
00708 
00709 void USBH_HAL_Resume(void)
00710 {
00711     if (USBHS_IsEnableSOF(USBHS)) {
00712         // Currently in IDLE mode (!=Suspend)
00713         if (uhd_suspend_start) {
00714             // Suspend mode on going
00715             // then stop it and start resume event
00716             uhd_suspend_start = 0;
00717             uhd_resume_start = 1;
00718         }
00719         return;
00720     }
00721     // Check USB clock ready after a potential sleep mode < IDLE
00722     while (!USBHS_ISUsableClock(USBHS));
00723     USBHS_UnFreezeClock(USBHS);
00724     USBHS_EnableSOF(USBHS);
00725     USBHS_Resume();
00726     uhd_sleep_mode(UHD_STATE_IDLE);
00727 }
00728 
00729 bool USBH_HAL_ConfigureControlPipe(uint8_t Addr, uint16_t ep_size)
00730 {
00731     uint8_t bSizeEpt;
00732     if (ep_size < 8) {
00733         return false;
00734     }
00735 #ifdef USB_HOST_HUB_SUPPORT
00736     if (USBHS_IsHostPipeEnable(USBHS, 0)) {
00737         // Already allocated
00738 #error TODO Add USB address in a list
00739         return true;
00740     }
00741 #endif
00742 
00743     USBHS_HostPipeEnable(USBHS, 0);
00744     
00745     /* Configure endpoint size */
00746     if(ep_size <= 8 )
00747         bSizeEpt = 0;
00748     else if (ep_size <= 16 )
00749         bSizeEpt = 1;
00750     else if (ep_size <= 32 )
00751         bSizeEpt = 2;
00752     else if (ep_size <= 64 )
00753         bSizeEpt = 3;
00754     else if (ep_size <= 128 )
00755         bSizeEpt = 4;
00756     else if (ep_size <= 256 )
00757         bSizeEpt = 5;
00758     else if (ep_size <= 512 )
00759         bSizeEpt = 6;
00760     else if (ep_size <= 1024 )
00761         bSizeEpt = 7;
00762 
00763 #ifdef USB_HOST_HUB_SUPPORT
00764     bSizeEpt = 3; //64 bytes
00765 #endif
00766     USBHS_HostConfigure(USBHS, 0, USBHS_HSTPIPCFG_PBK_1_BANK, bSizeEpt, USBHS_HSTPIPCFG_PTYPE_CTRL, USBHS_HSTPIPCFG_PTOKEN_SETUP, 0, 0);
00767     USBHS_HostDisableAutoSw(USBHS, 0);
00768     USBHS_HostAllocMem(USBHS, 0);
00769     if (!USBHS_IsHostConfigOk(USBHS, 0)) {
00770         USBHS_HostPipeDisable(USBHS, 0);
00771         return false;
00772     }
00773     USBHS_HostSetAddr(USBHS, 0, Addr);
00774 
00775     // Always enable stall and error interrupts of control endpoint
00776     USBHS_HostEnablePipeIntType(USBHS, 0, (USBHS_HSTPIPIER_RXSTALLDES | USBHS_HSTPIPIER_PERRES) );
00777     USBHS_HostPipeIntEnable(USBHS, 0);
00778     return true;
00779 }
00780 
00781 bool USBH_HAL_ConfigurePipe(uint8_t Addr, USBEndpointDescriptor * ep_desc)
00782 {
00783     uint32_t ep_type, ep_dir;
00784     uint8_t ep_interval;
00785     uint8_t pipe;
00786     uint8_t bank, ep_addr, bSizeEpt;
00787 
00788     for (pipe = 1; pipe < USBHS_EPT_NUM; pipe++) {
00789         if (USBHS_IsHostPipeEnable(USBHS, pipe)) {
00790             continue;
00791         }
00792         USBHS_HostPipeEnable(USBHS, pipe);
00793         ep_addr = ep_desc->bEndpointAddress & USB_EP_ADDR_MASK;
00794         ep_dir = (ep_desc->bEndpointAddress & USB_EP_DIR_IN)?
00795             (USBHS_HSTPIPCFG_PTOKEN_IN):
00796             (USBHS_HSTPIPCFG_PTOKEN_OUT),
00797         ep_type = ep_desc->bmAttributes&USB_EP_TYPE_MASK;
00798         // Bank choice
00799         switch(ep_type) {
00800         case USBEndpointDescriptor_ISOCHRONOUS:
00801             bank = UHD_ISOCHRONOUS_NB_BANK;
00802             ep_interval = ep_desc->bInterval;
00803             ep_type = USBHS_HSTPIPCFG_PTYPE_ISO;
00804             break;
00805         case USBEndpointDescriptor_INTERRUPT:
00806             bank = UHD_INTERRUPT_NB_BANK;
00807             ep_interval = ep_desc->bInterval;
00808             ep_type = USBHS_HSTPIPCFG_PTYPE_INTRPT;
00809             break;
00810         case USBEndpointDescriptor_BULK:
00811             bank = UHD_BULK_NB_BANK;
00812             // 0 is required by USBHS hardware for bulk
00813             ep_interval = 0;
00814             ep_type = USBHS_HSTPIPCFG_PTYPE_BLK;
00815             break;
00816         default:
00817             assert(false);
00818             return false;
00819         }
00820         switch(bank) {
00821         case 1:
00822             bank = USBHS_HSTPIPCFG_PBK_1_BANK;
00823             break;
00824         case 2:
00825             bank = USBHS_HSTPIPCFG_PBK_2_BANK;
00826             break;
00827         case 3:
00828             bank = USBHS_HSTPIPCFG_PBK_3_BANK;
00829             break;
00830         default:
00831             assert(false);
00832             return false;
00833         }
00834 
00835             /* Configure endpoint size */
00836         if(ep_desc->wMaxPacketSize <= 8 )
00837             bSizeEpt = 0;
00838         else if (ep_desc->wMaxPacketSize <= 16 )
00839             bSizeEpt = 1;
00840         else if (ep_desc->wMaxPacketSize <= 32 )
00841             bSizeEpt = 2;
00842         else if (ep_desc->wMaxPacketSize <= 64 )
00843             bSizeEpt = 3;
00844         else if (ep_desc->wMaxPacketSize <= 128 )
00845             bSizeEpt = 4;
00846         else if (ep_desc->wMaxPacketSize <= 256 )
00847             bSizeEpt = 5;
00848         else if (ep_desc->wMaxPacketSize <= 512 )
00849             bSizeEpt = 6;
00850         else if (ep_desc->wMaxPacketSize <= 1024 )
00851             bSizeEpt = 7;
00852         
00853         
00854         USBHS_HostConfigure(USBHS, pipe, bank, bSizeEpt, ep_type, ep_dir, ep_addr, ep_interval);
00855         USBHS_HostEnableAutoSw(USBHS, pipe);
00856 
00857         USBHS_HostAllocMem(USBHS, pipe);
00858         if (!USBHS_IsHostConfigOk(USBHS, pipe)) {
00859             USBHS_HostPipeDisable(USBHS, pipe);
00860             return false;
00861         }
00862         
00863         USBHS_HostSetAddr(USBHS, pipe, Addr);
00864 
00865         USBHS_HostPipeEnable(USBHS, pipe);
00866 
00867         // Enable endpoint interrupts
00868         USBHS_HostDmaIntEnable(USBHS, pipe-1);
00869         USBHS_HostEnablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIER_RXSTALLDES | USBHS_HSTPIPIER_PERRES) );
00870         
00871         USBHS_HostPipeIntEnable(USBHS, pipe);
00872         
00873         return true;
00874     }
00875     return false;
00876 }
00877 
00878 
00879 void USBH_HAL_FreePipe(uint8_t Addr, uint8_t bEndpoint)
00880 {
00881     uint8_t pipe;
00882 #ifdef USB_HOST_HUB_SUPPORT
00883     if (bEndpoint == 0) {
00884         // Control endpoint does not be unallocated
00885 #error TODO the list address must be updated
00886         if (uhd_ctrl_request_timeout
00887                 && (uhd_ctrl_request_first->add == Addr)) {
00888             // Disable setup request if on this device
00889             USBH_HAL_ControlReqEnd(UHD_TRANS_DISCONNECT);
00890         }
00891         return;
00892     }
00893 #endif
00894     // Search endpoint(s) in all pipes
00895     for (pipe = 0; pipe < USBHS_EPT_NUM; pipe++) {
00896         if (!USBHS_IsHostPipeEnable(USBHS, pipe)) {
00897             continue;
00898         }
00899         if (Addr != USBHS_HostGetAddr(USBHS, pipe)) {
00900             continue;
00901         }
00902         if (bEndpoint != 0xFF) {
00903             // Disable specific endpoint number
00904             if (bEndpoint != USBHS_GetPipeEpAddr(USBHS, pipe)) {
00905                 continue; // Mismatch
00906             }
00907         }
00908         // Unalloc pipe
00909         USBHS_HostPipeDisable(USBHS, pipe);
00910         USBHS_HostFreeMem(USBHS, pipe);
00911 
00912         // Stop transfer on this pipe
00913 #ifndef USB_HOST_HUB_SUPPORT
00914         if (pipe == 0) {
00915             // Endpoint control
00916             if (uhd_ctrl_request_timeout) {
00917                 USBH_HAL_ControlReqEnd(UHD_TRANS_DISCONNECT);
00918             }
00919             continue;
00920         }
00921 #endif
00922         // Endpoint interrupt, bulk or isochronous
00923         USBH_HAL_PipeAbort(pipe, UHD_TRANS_DISCONNECT);
00924     }
00925 }
00926 
00927 bool USBH_HAL_SetupReq(
00928         uint8_t Addr,
00929         USBGenericRequest *req,
00930         uint8_t *payload,
00931         uint16_t payload_size,
00932         uhd_callback_setup_run_t callback_run,
00933         uhd_callback_setup_end_t callback_end)
00934 {
00935     irqflags_t flags;
00936     struct uhd_ctrl_request_t *request;
00937     bool b_start_request = false;
00938 
00939     request = malloc(sizeof(struct uhd_ctrl_request_t));
00940     if (request == NULL) {
00941         assert(false);
00942         return false;
00943     }
00944 
00945     // Fill structure
00946     request->add = (uint8_t) Addr;
00947     memcpy(&request->req, req, sizeof(USBGenericRequest));
00948     request->payload = payload;
00949     request->payload_size = payload_size;
00950     request->callback_run = callback_run;
00951     request->callback_end = callback_end;
00952     request->next_request = NULL;
00953 
00954     // Add this request in the queue
00955     flags = cpu_irq_save();
00956     if (uhd_ctrl_request_first == NULL) {
00957         uhd_ctrl_request_first = request;
00958         b_start_request = true;
00959     } else {
00960         uhd_ctrl_request_last->next_request = request;
00961     }
00962     uhd_ctrl_request_last = request;
00963     cpu_irq_restore(flags);
00964 
00965     if (b_start_request) {
00966         // Start immediately request
00967         USBH_HAL_PhaseControlSetup();
00968     }
00969     return true;
00970 }
00971 
00972 bool USBH_HAL_RunEndpoint(uint8_t Addr,
00973         uint8_t bEndpoint,
00974         bool b_shortpacket,
00975         uint8_t *buf,
00976         uint32_t buf_size,
00977         uint16_t timeout,
00978         uhd_callback_trans_t callback)
00979 {
00980     irqflags_t flags;
00981     uint8_t pipe;
00982     USBH_PipeJob_t *pJob;
00983 
00984     pipe = USBH_HAL_GetPipe(Addr,bEndpoint);
00985     if (pipe == USBHS_EPT_NUM) {
00986         return false; // pipe not found
00987     }
00988 #ifdef UHD_PIPE_FIFO_SUPPORTED
00989     bool b_pipe_in = (USBHS_HostGetToken(USBHS, pipe) == USBHS_HSTPIPCFG_PTOKEN_IN)?true:false;
00990 #endif
00991 
00992     // Get job about pipe
00993     pJob = &uhd_pipe_job[pipe-1];
00994     flags = cpu_irq_save();
00995     if (pJob->busy == true) {
00996         cpu_irq_restore(flags);
00997         return false; // Job already on going
00998     }
00999     pJob->busy = true;
01000 
01001     // No job running. Let's setup a new one.
01002     pJob->buf = buf;
01003     pJob->buf_size = buf_size;
01004     pJob->nb_trans = 0;
01005     pJob->timeout = timeout;
01006     pJob->b_shortpacket = b_shortpacket;
01007     pJob->call_end = callback;
01008     if( (USBHS_HostGetPipeType(USBHS, pipe) & (USBHS_HSTPIPCFG_PTYPE_ISO | USBHS_HSTPIPCFG_PTYPE_INTRPT)) && (USBHS_HostGetToken(USBHS, pipe) == USBHS_HSTPIPCFG_PTOKEN_OUT))
01009     /*if ((Is_uhd_pipe_int(pipe) || Is_uhd_pipe_iso(pipe))
01010             && (Is_uhd_pipe_out(pipe))) */
01011     {
01012         pJob->b_periodic_start = true;
01013     }
01014     cpu_irq_restore(flags);
01015 
01016 #ifdef UHD_PIPE_FIFO_SUPPORTED
01017     // No DMA support
01018     if (!Is_uhd_pipe_dma_supported(pipe)) {
01019         flags = cpu_irq_save();
01020         USBHS_HostDisableAutoSw(USBHS, pipe);;
01021         USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_PFREEZEC);
01022         if (b_pipe_in) {
01023             USBHS_HostEnableInReq(USBHS, pipe);
01024             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_RXINES);
01025             if (b_shortpacket) {
01026                 USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_SHORTPACKETIES);
01027             }
01028         } else {
01029             USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_NBUSYBKEC);
01030             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_TXOUTES);
01031         }
01032         USBHS_HostPipeIntEnable(USBHS, pipe);
01033         cpu_irq_restore(flags);
01034         return true;
01035     }
01036 #endif // UHD_PIPE_FIFO_SUPPORTED
01037 
01038 #ifdef UHD_PIPE_DMA_SUPPORTED
01039     // Request first transfer
01040     USBH_HAL_PipeXfrCmplt(pipe);
01041 #endif
01042     return true;
01043 }
01044 
01045 void USBH_HAL_AbortEndPoint(uint8_t Addr, uint8_t bEndpoint)
01046 {
01047     uint8_t pipe;
01048 
01049     pipe = USBH_HAL_GetPipe(Addr,bEndpoint);
01050     if (pipe == USBHS_EPT_NUM) {
01051         return; // pipe not found
01052     }
01053     USBH_HAL_PipeAbort(pipe,UHD_TRANS_ABORTED);
01054 }
01055 
01056 
01057 static void USBH_HAL_DelayedSuspend(void)
01058 {
01059     volatile uint8_t AsyncInt= ( USBHS_HSTIER_HWUPIES |USBHS_HSTIER_RSMEDIES | USBHS_HSTIER_RXRSMIES );
01060 
01061     if (--uhd_suspend_start == 0) {
01062         // In case of high CPU frequency,
01063         // the current Keep-Alive/SOF can be always on-going
01064         // then wait end of SOF generation
01065         // to be sure that disable SOF has been accepted
01066         uint8_t pos =
01067             (USBHS_GetUsbSpeed(USBHS) == USBHS_SR_SPEED_HIGH_SPEED) ?
01068                 13 : 114;
01069         while (pos < USBHS_HostGetFramePos()) {
01070             if (USBHS_GetHostStatus(USBHS, USBHS_HSTISR_DDISCI)) {
01071                 break;
01072             }
01073         }
01074         USBHS_DisableSOF();
01075 
01076         // When SOF is disabled, the current transmitted packet may
01077         // cause a resume.
01078         // Wait for a while to check this resume status and clear it.
01079         for (pos = 0; pos < 15; pos ++) {
01080             memory_barrier();
01081             if (USBHS_GetHostStatus(USBHS, USBHS_HSTICR_HWUPIC
01082                     | USBHS_HSTICR_RSMEDIC
01083                     | USBHS_HSTICR_RXRSMIC)) 
01084             {
01085                 break;
01086             }
01087         }
01088         
01089 
01090         // Ack previous wakeup and resumes interrupts
01091         USBHS_ClearHostStatus(USBHS, (  USBHS_HSTICR_HWUPIC
01092                                     | USBHS_HSTICR_RSMEDIC
01093                                     | USBHS_HSTICR_RXRSMIC));
01094 
01095         memory_sync();
01096         // Enable wakeup/resumes interrupts
01097         USBHS_HostIntEnable(USBHS, AsyncInt );
01098         
01099         
01100         USBHS_FreezeClock(USBHS);
01101         uhd_sleep_mode(UHD_STATE_SUSPEND);
01102     }
01103 }
01104 static void USBH_HAL_DelayedResume(void)
01105 {
01106     uint8_t pipe;
01107     if (--uhd_resume_start == 0) {
01108         // Restore pipes unfreezed
01109         for (pipe = 1; pipe < USBHS_EPT_NUM; pipe++) {
01110             if ((uhd_pipes_unfreeze >> pipe) & 0x01) {
01111                 USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_PFREEZEC);
01112             }
01113         }
01114         USBH_notify_resume();
01115     }
01116 }
01117 static void USBH_HAL_ControlTimeout(void)
01118 {
01119     if (uhd_ctrl_request_timeout) {
01120         // Setup request on-going
01121         if (--uhd_ctrl_request_timeout == 0) {
01122             TRACE_WARNING_WP("Timeout");
01123             // Stop request by freezing pipe
01124             USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_PFREEZES);
01125             USBH_HAL_ControlReqEnd(UHD_TRANS_TIMEOUT);
01126         }
01127     }
01128 }
01129 
01130 /**
01131  * \internal
01132  * \brief Manages timeouts and actions based on SOF events
01133  * - Suspend delay
01134  * - Resume delay
01135  * - Setup packet delay
01136  * - Timeout on endpoint control transfer
01137  * - Timeouts on bulk/interrupt/isochronous endpoint transfers
01138  * - UHC user notification
01139  * - SOF user notification
01140  */
01141 static void USBH_HAL_ManageSof(void)
01142 {
01143 //  USBHS_HostAckPipeIntType(USBHS, USBHS_HSTICR_HSOFIC);
01144 
01145     uint8_t pipe;
01146     // Manage the micro SOF
01147     if (USBHS_IsUsbHighSpeed(USBHS)) {
01148         static uint8_t msof_cpt = 0;
01149         if (++msof_cpt % 8) {
01150             // It is a micro SOF
01151             if (!uhd_suspend_start && !uhd_resume_start) {
01152                 // If no resume and no suspend on going
01153                 // then send Micro start of frame event (each 125?)
01154                 USBH_notify_sof(true);
01155             }
01156             return;
01157         }
01158     }
01159 
01160     // Manage a delay to enter in suspend
01161     if (uhd_suspend_start) {
01162         USBH_HAL_DelayedSuspend();
01163         return; // Abort SOF events
01164     }
01165     // Manage a delay to exit of suspend
01166     if (uhd_resume_start) {
01167         USBH_HAL_DelayedResume();
01168         return; // Abort SOF events
01169     }
01170     // Manage the timeout on endpoint control transfer
01171     USBH_HAL_ControlTimeout();
01172 
01173     // Manage the timeouts on endpoint transfer
01174     USBH_PipeJob_t *pJob;
01175     for (pipe = 1; pipe < USBHS_EPT_NUM; pipe++) {
01176         pJob = &uhd_pipe_job[pipe-1];
01177         if (pJob->busy == true) {
01178             if (pJob->timeout) {
01179                 // Timeout enabled on this job
01180                 if (--(pJob->timeout) == 0) {
01181                     // Abort job
01182                     USBH_HAL_PipeAbort(pipe,UHD_TRANS_TIMEOUT);
01183                 }
01184             }
01185             if (pJob->b_periodic_start) {
01186                 pJob->b_periodic_start = false;
01187                 USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_PFREEZEC);
01188             }
01189         }
01190     }
01191     // Notify the UHC
01192     USBH_notify_sof(false);
01193 
01194     // Notify the user application
01195     UHC_SOF_EVENT();
01196     memory_sync();
01197 }
01198 
01199 /**
01200  * \internal
01201  * \brief Manages the events related to control endpoint
01202  */
01203 static void USBH_HAL_ControlInterrupt(void)
01204 {
01205     
01206     // A setup request is on-going
01207     assert(uhd_ctrl_request_timeout!=0);
01208 
01209     // Disable setup, IN and OUT interrupts of control endpoint
01210     USBHS_HostDisablePipeIntType(USBHS, 0, (USBHS_HSTPIPIDR_TXSTPEC
01211                                             | USBHS_HSTPIPIDR_RXINEC
01212                                             | USBHS_HSTPIPIDR_TXOUTEC) );
01213 
01214     // Search event on control endpoint
01215     if (USBHS_HostGetIntTypeStatus(USBHS, 0, USBHS_HSTPIPISR_TXSTPI) ) 
01216     {
01217         // SETUP packet sent
01218         USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_PFREEZES);
01219         USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_TXSTPIC);
01220         assert(uhd_ctrl_request_phase == UHD_CTRL_REQ_PHASE_SETUP);
01221 
01222         // Start DATA phase
01223         if ((uhd_ctrl_request_first->req.bmRequestType & USB_REQ_DIR_MASK)
01224                 == USB_REQ_DIR_IN) {
01225             USBH_HAL_PhaseDataInStart();
01226         } else {
01227             if (uhd_ctrl_request_first->req.wLength) {
01228                 USBH_HAL_PhaseDataOut();
01229             } else {
01230                 // No DATA phase
01231                 USBH_HAL_InZLP();
01232             }
01233         }
01234         return;
01235     }
01236     if (USBHS_HostGetIntTypeStatus(USBHS, 0,USBHS_HSTPIPISR_RXINI)) {
01237         // In case of low USB speed and with a high CPU frequency,
01238         // a ACK from host can be always running on USB line
01239         // then wait end of ACK on IN pipe.
01240         while (!USBHS_IsHostPipeIntTypeEnable(USBHS, 0, USBHS_HSTPIPIMR_PFREEZE));
01241 
01242         // IN packet received, Acknowledge
01243         USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_RXINIC);
01244         switch(uhd_ctrl_request_phase) {
01245         case UHD_CTRL_REQ_PHASE_DATA_IN:
01246             USBH_HAL_PhaseDataIn();
01247             break;
01248         case UHD_CTRL_REQ_PHASE_ZLP_IN:
01249             USBH_HAL_ControlReqEnd(UHD_TRANS_NOERROR);
01250             break;
01251         default:
01252             assert(false);
01253             break;
01254         }
01255         return;
01256     }
01257     if (USBHS_HostGetIntTypeStatus(USBHS, 0,USBHS_HSTPIPISR_TXOUTI)) {
01258         // OUT packet sent
01259         USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_PFREEZES);
01260         USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_TXOUTIC);
01261         switch(uhd_ctrl_request_phase) {
01262         case UHD_CTRL_REQ_PHASE_DATA_OUT:
01263             USBH_HAL_PhaseDataOut();
01264             break;
01265         case UHD_CTRL_REQ_PHASE_ZLP_OUT:
01266             USBH_HAL_ControlReqEnd(UHD_TRANS_NOERROR);
01267             break;
01268         default:
01269             assert(false);
01270             break;
01271         }
01272         return;
01273     }
01274     if (USBHS_HostGetIntTypeStatus(USBHS, 0,USBHS_HSTPIPISR_RXSTALLDI)) {
01275         // Stall Handshake received
01276         USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_RXSTALLDIC);
01277         USBH_HAL_ControlReqEnd(UHD_TRANS_STALL);
01278         return;
01279     }
01280     if (USBHS_HostGetIntTypeStatus(USBHS, 0,USBHS_HSTPIPISR_PERRI)) {
01281         // Get and ack error
01282         USBH_HAL_ControlReqEnd(USBH_HAL_GetPipeError(0));
01283         printf("Control pipe error \n\r");
01284         return;
01285     }
01286     memory_sync();
01287     assert(false); // Error system
01288 }
01289 
01290 /**
01291  * \internal
01292  * \brief Sends a USB setup packet to start a control request sequence
01293  */
01294 static void USBH_HAL_PhaseControlSetup(void)
01295 {
01296     union{
01297         volatile uint64_t value64;
01298         USBGenericRequest req;
01299     } setup;
01300     volatile uint64_t *pEpData;
01301 
01302     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_SETUP;
01303     memcpy(&setup.req, &uhd_ctrl_request_first->req, sizeof(USBGenericRequest));
01304     memory_sync();
01305 
01306     uhd_ctrl_nb_trans = 0;
01307 
01308     // Check pipe
01309 #ifdef USB_HOST_HUB_SUPPORT
01310     if (!USBHS_IsHostPipeEnable(USBHS, 0)) {
01311         USBH_HAL_ControlReqEnd(UHD_TRANS_DISCONNECT);
01312         return; // Endpoint not valid
01313     }
01314 #error TODO check address in list
01315     // Reconfigure USB address of pipe 0 used for all control endpoints
01316     uhd_configure_address(0, uhd_ctrl_request_first->add);
01317 #else
01318     if (!USBHS_IsHostPipeEnable(USBHS, 0) ||
01319             (uhd_ctrl_request_first->add != USBHS_HostGetAddr(USBHS, 0))) {
01320         USBH_HAL_ControlReqEnd(UHD_TRANS_DISCONNECT);
01321         return; // Endpoint not valid
01322     }
01323 #endif
01324 
01325     // Fill pipe
01326     USBHS_HostSetToken(USBHS, 0, USBHS_HSTPIPCFG_PTOKEN_SETUP);
01327     USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_TXSTPIC);
01328     assert(sizeof(setup) == sizeof(uint64_t));
01329 
01330     pEpData = (volatile uint64_t*)USBHS_RAM_ADDR;
01331     memory_sync();
01332     *pEpData = setup.value64;
01333     memory_barrier();
01334 
01335     uhd_ctrl_request_timeout = 5000;
01336     USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_TXSTPES);
01337     // Acknowledge FIFO control and unfreeze Pipe
01338     USBHS_HostDisablePipeIntType(USBHS, 0, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC));
01339     
01340 }
01341 
01342 /**
01343  * \internal
01344  * \brief Starts the DATA IN phase on control endpoint
01345  */
01346 static void USBH_HAL_PhaseDataInStart(void)
01347 {
01348     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_DATA_IN;
01349     // set pipe token
01350     USBHS_HostSetToken(USBHS, 0, USBHS_HSTPIPCFG_PTOKEN_IN);
01351     // Ack In and Short packet
01352     USBHS_HostAckPipeIntType(USBHS, 0, (USBHS_HSTPIPICR_RXINIC | USBHS_HSTPIPICR_SHORTPACKETIC) );
01353     
01354     USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_RXINES);
01355     // Acknowledge FIFO control and unfreeze Pipe
01356     USBHS_HostDisablePipeIntType(USBHS, 0, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC) );
01357                                             
01358     memory_sync();
01359 }
01360 
01361 /**
01362  * \internal
01363  * \brief Manages the DATA IN phase on control endpoint
01364  */
01365 static void USBH_HAL_PhaseDataIn(void)
01366 {
01367     bool b_short_packet;
01368     uint8_t *pEpData;
01369     uint8_t bPipe = 0;
01370     uint8_t nb_byte_received;
01371 
01372     // Get information to read data
01373     nb_byte_received = USBHS_HostGetPipeByteCount(USBHS, bPipe);
01374 #ifdef USB_HOST_HUB_SUPPORT
01375     //! In HUB mode, the control pipe is always configured to 64B
01376     //! thus the short packet flag must be computed
01377     b_short_packet = (nb_byte_received != USBHS_HostGetSize(USBHS, 0));
01378     USBHS_HostAckPipeIntType(USBHS, 0, USBHS_HSTPIPICR_SHORTPACKETIC);
01379 #else
01380     b_short_packet = (USBHS_HostGetIntTypeStatus(USBHS, 0, USBHS_HSTPIPISR_SHORTPACKETI) == USBHS_HSTPIPISR_SHORTPACKETI)? true:false;
01381 #endif
01382 
01383     pEpData = (uint8_t*)((uint32_t*)USBHS_RAM_ADDR
01384                                     + (EPT_VIRTUAL_SIZE * bPipe));
01385 uhd_ctrl_receiv_in_read_data:
01386     memory_sync();
01387     // Copy data from pipe to payload buffer
01388     while (uhd_ctrl_request_first->payload_size && nb_byte_received) {
01389         *uhd_ctrl_request_first->payload++ = *pEpData++;
01390         memory_sync();
01391         uhd_ctrl_nb_trans++;
01392         uhd_ctrl_request_first->payload_size--;
01393         nb_byte_received--;
01394         memory_barrier();
01395     }
01396 
01397     if (!uhd_ctrl_request_first->payload_size && nb_byte_received) {
01398         // payload buffer is full to store data remaining
01399         if (uhd_ctrl_request_first->callback_run == NULL
01400                 || !uhd_ctrl_request_first->callback_run(
01401                 USBHS_HostGetAddr(USBHS, bPipe),
01402                 &uhd_ctrl_request_first->payload,
01403                 &uhd_ctrl_request_first->payload_size)) {
01404             // DATA phase aborted by host
01405             goto uhd_ctrl_phase_data_in_end;
01406         }
01407         // The payload buffer has been updated by the callback
01408         // thus the data load can restart.
01409         goto uhd_ctrl_receiv_in_read_data;
01410     }
01411 
01412     // Test short packet
01413     if ((uhd_ctrl_nb_trans == uhd_ctrl_request_first->req.wLength)
01414             || b_short_packet) {
01415         // End of DATA phase or DATA phase abort from device
01416 uhd_ctrl_phase_data_in_end:
01417         USBH_HAL_OutZLP();
01418         return;
01419     }
01420 
01421     // Send a new IN packet request
01422     USBHS_HostEnablePipeIntType(USBHS, bPipe, USBHS_HSTPIPIER_RXINES);
01423     // ack Fifocon and unfreeze pipe
01424     USBHS_HostDisablePipeIntType(USBHS, bPipe, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC ));
01425 }
01426 
01427 /**
01428  * \internal
01429  * \brief Starts the ZLP IN phase on control endpoint
01430  */
01431 static void USBH_HAL_InZLP(void)
01432 {
01433     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_ZLP_IN;
01434     USBHS_HostSetToken(USBHS, 0, USBHS_HSTPIPCFG_PTOKEN_IN);
01435     USBHS_HostAckPipeIntType(USBHS, 0, (USBHS_HSTPIPICR_RXINIC | USBHS_HSTPIPICR_SHORTPACKETIC) );
01436     /*uhd_ack_in_received(0);
01437     uhd_ack_short_packet(0);*/
01438     USBHS_HostEnablePipeIntType(USBHS, 0, USBHS_HSTPIPIER_RXINES);
01439     // ack Fifocon and unfreeze pipe
01440     USBHS_HostDisablePipeIntType(USBHS, 0, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC ));
01441     memory_sync();
01442 }
01443 
01444 /**
01445  * \internal
01446  * \brief Manages the DATA OUT phase on control endpoint
01447  */
01448 static void USBH_HAL_PhaseDataOut(void)
01449 {
01450     uint8_t *pEpData;
01451     uint8_t bPipe = 0;
01452     uint8_t ep_ctrl_size;
01453 
01454     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_DATA_OUT;
01455 
01456     if (uhd_ctrl_nb_trans == uhd_ctrl_request_first->req.wLength) {
01457         // End of DATA phase
01458         USBH_HAL_InZLP();
01459         return;
01460     }
01461 
01462     if (!uhd_ctrl_request_first->payload_size) {
01463         // Buffer empty, then request a new buffer
01464         if (uhd_ctrl_request_first->callback_run==NULL
01465                 || !uhd_ctrl_request_first->callback_run(
01466                 USBHS_HostGetAddr(USBHS, bPipe),
01467                 &uhd_ctrl_request_first->payload,
01468                 &uhd_ctrl_request_first->payload_size)) {
01469             // DATA phase aborted by host
01470             USBH_HAL_InZLP();
01471             return;
01472         }
01473     }
01474 
01475 #ifdef USB_HOST_HUB_SUPPORT
01476     // TODO
01477 #else
01478     ep_ctrl_size = USBHS_HostGetSize(USBHS, bPipe);
01479 #endif
01480 
01481     // Fill pipe
01482     USBHS_HostSetToken(USBHS, bPipe, USBHS_HSTPIPCFG_PTOKEN_OUT);
01483     //uhd_configure_pipe_token(0, USBHS_HSTPIPCFG_PTOKEN_OUT);
01484     //uhd_ack_out_ready(0);
01485     USBHS_HostAckPipeIntType(USBHS, bPipe, USBHS_HSTPIPICR_TXOUTIC);
01486     pEpData =(uint8_t*)((uint32_t*)USBHS_RAM_ADDR
01487                                     + (EPT_VIRTUAL_SIZE * bPipe));
01488     memory_sync();
01489     while ((uhd_ctrl_nb_trans < uhd_ctrl_request_first->req.wLength)
01490             && ep_ctrl_size && uhd_ctrl_request_first->payload_size) {
01491         *pEpData++ = *uhd_ctrl_request_first->payload++;
01492         memory_sync();
01493         uhd_ctrl_nb_trans++;
01494         ep_ctrl_size--;
01495         uhd_ctrl_request_first->payload_size--;
01496         memory_barrier();
01497     }
01498     //uhd_enable_out_ready_interrupt(0);
01499     USBHS_HostEnablePipeIntType(USBHS, bPipe, USBHS_HSTPIPIER_TXOUTES);
01500     USBHS_HostDisablePipeIntType(USBHS, bPipe, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC ) );
01501     //uhd_unfreeze_pipe(0);
01502 }
01503 
01504 /**
01505  * \internal
01506  * \brief Starts the ZLP OUT phase on control endpoint
01507  */
01508 static void USBH_HAL_OutZLP(void)
01509 {
01510     uint8_t bPipe = 0;
01511     uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_ZLP_OUT;
01512     USBHS_HostSetToken(USBHS, bPipe, USBHS_HSTPIPCFG_PTOKEN_OUT);
01513     //uhd_configure_pipe_token(0, USBHS_HSTPIPCFG_PTOKEN_OUT);
01514     USBHS_HostAckPipeIntType(USBHS, bPipe, USBHS_HSTPIPICR_TXOUTIC);
01515     //uhd_ack_out_ready(0);
01516     USBHS_HostEnablePipeIntType(USBHS, bPipe, USBHS_HSTPIPIER_TXOUTES);
01517     //uhd_enable_out_ready_interrupt(0);
01518     USBHS_HostDisablePipeIntType(USBHS, bPipe, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC));
01519     //uhd_unfreeze_pipe(0);
01520 }
01521 
01522 /**
01523  * \internal
01524  * \brief Call the callback linked to control request
01525  * and start the next request from the queue.
01526 */
01527 static void USBH_HAL_ControlReqEnd(USBH_XfrStatus_t status)
01528 {
01529     uint8_t bPipe = 0;
01530     irqflags_t flags;
01531     uhd_callback_setup_end_t callback_end;
01532     struct uhd_ctrl_request_t *request_to_free;
01533     bool b_new_request;
01534 
01535     uhd_ctrl_request_timeout = 0;
01536 
01537     // Remove request from the control request list
01538     callback_end = uhd_ctrl_request_first->callback_end;
01539     request_to_free = uhd_ctrl_request_first;
01540     flags = cpu_irq_save();
01541     uhd_ctrl_request_first = uhd_ctrl_request_first->next_request;
01542     b_new_request = (uhd_ctrl_request_first != NULL);
01543     cpu_irq_restore(flags);
01544     free(request_to_free);
01545 
01546     // Call callback
01547     if (callback_end != NULL) {
01548         callback_end(USBHS_HostGetAddr(USBHS, bPipe), status, uhd_ctrl_nb_trans);
01549     }
01550 
01551     // If a setup request is pending and no started by previous callback
01552     if (b_new_request) {
01553         USBH_HAL_PhaseControlSetup();
01554     }
01555     if (uhd_b_suspend_requested) {
01556         // A suspend request has been delay after all setup request
01557         uhd_b_suspend_requested = false;
01558         USBH_HAL_Suspend();
01559     }
01560 }
01561 
01562 /**
01563  * \internal
01564  * \brief Translates the USBHS pipe error to UHD error
01565  *
01566  * \param pipe Pipe number to use
01567  *
01568  * \return UHD transfer error
01569  */
01570 static USBH_XfrStatus_t USBH_HAL_GetPipeError(uint8_t pipe)
01571 {
01572     uint32_t error = USBHS_HostGetErr(USBHS, pipe, (USBHS_HSTPIPERR_DATATGL |
01573                                                     USBHS_HSTPIPERR_TIMEOUT |
01574                                                     USBHS_HSTPIPERR_PID |
01575                                                     USBHS_HSTPIPERR_DATAPID));
01576     USBHS_HostClearErr(USBHS, pipe, 0xFF);
01577     switch(error) {
01578     case USBHS_HSTPIPERR_DATATGL:
01579         return UHD_TRANS_DT_MISMATCH;
01580     case USBHS_HSTPIPERR_TIMEOUT:
01581         return UHD_TRANS_NOTRESPONDING;
01582     case USBHS_HSTPIPERR_DATAPID:
01583     case USBHS_HSTPIPERR_PID:
01584     default:
01585         return UHD_TRANS_PIDFAILURE;
01586     }
01587 }
01588 
01589 /**
01590  * \internal
01591  * \brief Returns the pipe number matching a USB endpoint
01592  *
01593  * \param Addr USB address
01594  * \param bEndpoint  Endpoint number
01595  *
01596  * \return Pipe number
01597  */
01598 static uint8_t USBH_HAL_GetPipe(uint8_t Addr, uint8_t bEndpoint)
01599 {
01600     uint8_t pipe;
01601 
01602     // Search pipe
01603     for (pipe = 0; pipe < USBHS_EPT_NUM; pipe++) {
01604 
01605         if (!USBHS_IsHostPipeEnable(USBHS, pipe)) {
01606             continue;
01607         }
01608         if (Addr != USBHS_HostGetAddr(USBHS,pipe)) {
01609             continue;
01610         }
01611         if (bEndpoint != USBHS_GetPipeEpAddr(USBHS, pipe)) {
01612             continue;
01613         }
01614         break;
01615     }
01616     return pipe;
01617 }
01618 
01619 #ifdef UHD_PIPE_FIFO_SUPPORTED
01620 /**
01621  * \internal
01622  */
01623 static void USBH_HAL_PipeInReceived(uint8_t pipe)
01624 {
01625     USBH_PipeJob_t *pJob = &uhd_pipe_job[pipe - 1];
01626     uint32_t nb_data = 0, i;
01627     uint32_t nb_remain = pJob->buf_size - pJob->nb_trans;
01628     uint32_t pkt_size = USBHS_HostGetSize(USBHS, pipe);
01629     uint8_t *ptr_src =(uint8_t*)((uint32_t*)USBHS_RAM_ADDR
01630                                     + (EPT_VIRTUAL_SIZE * pipe));
01631     uint8_t *ptr_dst = &pJob->buf[pJob->nb_trans];
01632     bool b_full = false, b_short = false;
01633 
01634     if (!pJob->busy) {
01635         return; // No job is running, then ignore it (system error)
01636     }
01637 
01638     // Read byte count
01639     nb_data = USBHS_HostGetPipeByteCount(USBHS, pipe);
01640     if (nb_data < pkt_size) {
01641         b_short = true;
01642     }
01643     // Copy data if there is
01644     if (nb_data > 0) {
01645         if (nb_data >= nb_remain) {
01646             nb_data = nb_remain;
01647             b_full = true;
01648         }
01649         // Modify job information
01650         pJob->nb_trans += nb_data;
01651         // Copy FIFO to buffer
01652         for (i = 0; i < nb_data; i++) {
01653             *ptr_dst++ = *ptr_src++;
01654             memory_sync();
01655         }
01656     }
01657     // Clear FIFO Status
01658     USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_FIFOCONC);
01659     // Finish job on error or short packet
01660     if (b_full || b_short) {
01661         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);
01662         USBHS_HostDisablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIDR_SHORTPACKETIEC | USBHS_HSTPIPIDR_RXINEC) );
01663         //uhd_disable_short_packet_interrupt(pipe);
01664         //uhd_disable_in_received_interrupt(pipe);
01665         USBHS_HostPipeIntDisable(USBHS, pipe);
01666         //uhd_disable_pipe_interrupt(pipe);
01667         USBHS_HostDisableInReq(USBHS, pipe);
01668         //uhd_disable_continuous_in_mode(pipe);
01669         USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01670     }
01671 }
01672 
01673 /**
01674  * \internal
01675  */
01676 static void USBH_HAL_PipeOutReady(uint8_t pipe)
01677 {
01678     USBH_PipeJob_t *pJob = &uhd_pipe_job[pipe - 1];
01679     uint32_t pkt_size = USBHS_HostGetSize(USBHS, pipe);
01680     uint32_t nb_data = 0, i;
01681     uint32_t nb_remain;
01682     uint8_t *ptr_src;
01683     uint8_t *ptr_dst;
01684 
01685     if (!pJob->busy) {
01686         return; // No job is running, then ignore it (system error)
01687     }
01688 
01689     // Transfer data
01690     USBHS_HostAckPipeIntType(USBHS,pipe, USBHS_HSTPIPICR_TXOUTIC);
01691 
01692     nb_remain = pJob->buf_size - pJob->nb_trans;
01693     nb_data = min(nb_remain, pkt_size);
01694 
01695     // If not ZLP, fill FIFO
01696     if (nb_data) {
01697         // Fill FIFO
01698         ptr_dst =(uint8_t*)((uint32_t*)USBHS_RAM_ADDR
01699                                     + (EPT_VIRTUAL_SIZE * pipe));
01700         ptr_src = &pJob->buf[pJob->nb_trans];
01701         // Modify job information
01702         pJob->nb_trans += nb_data;
01703 
01704         memory_sync();
01705         // Copy buffer to FIFO
01706         for (i = 0; i < nb_data; i++) {
01707             *ptr_dst++ = *ptr_src++;
01708             memory_sync();
01709         }
01710     }
01711     // Switch to next bank
01712     USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_FIFOCONC);
01713     // ZLP is cleared if last packet is short
01714     if (nb_data < pkt_size) {
01715         pJob->b_shortpacket = false;
01716     }
01717     // All transfer done, including ZLP, Finish Job
01718     if (pJob->nb_trans >= pJob->buf_size && !pJob->b_shortpacket) {
01719         // At least one bank there, wait to freeze pipe
01720         USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_TXOUTEC);
01721         //uhd_disable_out_ready_interrupt(pipe);
01722         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_NBUSYBKES);
01723         return;
01724     }
01725 }
01726 
01727 #endif // #ifdef UHD_PIPE_FIFO_SUPPORTED
01728 
01729 #ifdef UHD_PIPE_DMA_SUPPORTED
01730 /**
01731  * \internal
01732  * \brief Computes and starts the next transfer on a pipe
01733  *
01734  * \param pipe  Pipe number
01735  */
01736 static void USBH_HAL_PipeXfrCmplt(uint8_t pipe)
01737 {
01738     uint32_t uhd_dma_ctrl = 0;
01739     USBH_PipeJob_t *pJob;
01740     uint32_t max_trans;
01741     uint32_t next_trans;
01742     irqflags_t flags;
01743     Usbhs  *pUdp  = USBHS;
01744     UsbhsHstdma *pUsbDma = &pUdp->USBHS_HSTDMA[pipe-1];
01745 
01746     // Get job corresponding at endpoint
01747     pJob = &uhd_pipe_job[pipe - 1];
01748 
01749     if (!pJob->busy) {
01750         return; // No job is running, then ignore it (system error)
01751     }
01752 
01753     if (pJob->nb_trans != pJob->buf_size) {
01754         // Need to send or receive other data
01755         next_trans = pJob->buf_size - pJob->nb_trans;
01756         max_trans = UHD_PIPE_MAX_TRANS;
01757         if (USBHS_HostGetToken(USBHS, pipe) == USBHS_HSTPIPCFG_PTOKEN_IN) {
01758             // 256 is the maximum of IN requests via UPINRQ
01759             if ((256L*USBHS_HostGetSize(USBHS, pipe)) < UHD_PIPE_MAX_TRANS) {
01760                 max_trans = 256L * USBHS_HostGetSize(USBHS, pipe);
01761             }
01762         }
01763         if (max_trans < next_trans) {
01764             // The USB hardware supports a maximum
01765             // transfer size of UHD_PIPE_MAX_TRANS Bytes
01766             next_trans = max_trans;
01767         }
01768 
01769         if (next_trans == UHD_PIPE_MAX_TRANS) {
01770             // Set 0 to transfer the maximum
01771             uhd_dma_ctrl = USBHS_HSTDMACONTROL_BUFF_LENGTH(0);
01772         } else {
01773             uhd_dma_ctrl = USBHS_HSTDMACONTROL_BUFF_LENGTH(next_trans);
01774         }
01775 
01776         if (USBHS_HSTPIPCFG_PTOKEN_OUT == USBHS_HostGetToken(USBHS, pipe)) {
01777             if (0 != (next_trans % USBHS_HostGetSize(USBHS, pipe))) {
01778                 // Enable short packet option
01779                 // else the DMA transfer is accepted
01780                 // and interrupt DMA valid but nothing is sent.
01781                 uhd_dma_ctrl |= USBHS_HSTDMACONTROL_END_B_EN;
01782                 // No need to request another ZLP
01783                 pJob->b_shortpacket = false;
01784             }
01785         } else {
01786             if ((USBEndpointDescriptor_ISOCHRONOUS != USBHS_HostGetPipeType(USBHS, pipe))
01787                     || ((int)next_trans <= USBHS_HostGetSize(USBHS, pipe))) {
01788                 // Enable short packet reception
01789                 uhd_dma_ctrl |= USBHS_HSTDMACONTROL_END_TR_IT
01790                         | USBHS_HSTDMACONTROL_END_TR_EN;
01791             }
01792         }
01793         // Start USB DMA to fill or read fifo of the selected endpoint
01794         USBHS_SetHostDmaBuffAdd(pUsbDma, (uint32_t) &pJob->buf[pJob->nb_trans]);
01795         uhd_dma_ctrl |= USBHS_HSTDMACONTROL_END_BUFFIT |
01796                 USBHS_HSTDMACONTROL_CHANN_ENB;
01797 
01798         // Disable IRQs to have a short sequence
01799         // between read of EOT_STA and DMA enable
01800         flags = cpu_irq_save();
01801         if (!(USBHS_GetHostPipeDmaStatus(pUsbDma)
01802                 & USBHS_HSTDMASTATUS_END_TR_ST)) {
01803             if (USBHS_HSTPIPCFG_PTOKEN_IN == USBHS_HostGetToken(USBHS, pipe)) {
01804                 uint32_t pipe_size = USBHS_HostGetSize(USBHS, pipe);
01805                 USBHS_HostInReq(USBHS, pipe, (next_trans + pipe_size-1) / pipe_size);
01806             }
01807             if (!pJob->b_periodic_start) {
01808                 USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_NBUSYBKEC);
01809                 USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_PFREEZEC);
01810             } else {
01811                 // Last bank not sent, just start
01812                 if (USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_NBUSYBKE)) {
01813                     USBHS_HostDisablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIDR_NBUSYBKEC | USBHS_HSTPIPIDR_PFREEZEC));
01814                 } else {
01815                     // Wait SOF to start
01816                 }
01817             }
01818             SCB_CleanInvalidateDCache();
01819             USBHS_HostConfigureDma(pUsbDma, uhd_dma_ctrl);
01820             pJob->nb_trans += next_trans;
01821             cpu_irq_restore(flags);
01822             return;
01823         }
01824         cpu_irq_restore(flags);
01825         // Here a ZLP has been received
01826         // and the DMA transfer must be not started.
01827         // It is the end of transfer
01828         pJob->buf_size = pJob->nb_trans;
01829     }
01830     if (USBHS_HSTPIPCFG_PTOKEN_OUT == USBHS_HostGetToken(USBHS, pipe)) {
01831         if (pJob->b_shortpacket) {
01832             // Need to send a ZLP (No possible with USB DMA)
01833             // enable interrupt to wait a free bank to sent ZLP
01834             USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_TXOUTIC);
01835             if (USBHS_HostGetIntTypeStatus(USBHS, pipe, USBHS_HSTPIPISR_RWALL)) {
01836                 // Force interrupt in case of pipe already free
01837                 USBHS_HostSetPipeIntType(USBHS, pipe, USBHS_HSTPIPIFR_TXOUTIS);
01838             }
01839             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_TXOUTES);
01840             return;
01841         }
01842     }
01843     // Call callback to signal end of transfer
01844     USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01845 }
01846 
01847 /**
01848  * \internal
01849  * \brief Manages the pipe DMA interrupt
01850  *
01851  * \param pipe  Pipe number
01852  */
01853 static void USBH_HAL_PipeDmaInterrupt(uint8_t pipe)
01854 {
01855     USBH_PipeJob_t *pJob;
01856     uint32_t nb_remaining;
01857     Usbhs  *pUdp  = USBHS;
01858     UsbhsHstdma *pUsbDma = &pUdp->USBHS_HSTDMA[pipe-1];
01859 
01860     SCB_CleanInvalidateDCache();
01861     if (USBHS_GetHostPipeDmaStatus(pUsbDma) & USBHS_HSTDMASTATUS_CHANN_ENB) 
01862     {
01863         return; // Ignore EOT_STA interrupt
01864     }
01865     // Save number of data no transfered
01866     nb_remaining = ( (USBHS_GetHostPipeDmaStatus(pUsbDma) & USBHS_HSTDMASTATUS_BUFF_COUNT_Msk) >> USBHS_HSTDMASTATUS_BUFF_COUNT_Pos);
01867     memory_sync();
01868     if (nb_remaining) {
01869         // Get job corresponding at endpoint
01870         pJob = &uhd_pipe_job[pipe - 1];
01871 
01872         // Transfer no complete (short packet or ZLP) then:
01873         // Update number of transfered data
01874         pJob->nb_trans -= nb_remaining;
01875 
01876         // Set transfer complete to stop the transfer
01877         pJob->buf_size = pJob->nb_trans;
01878     }
01879 
01880     if (USBHS_HSTPIPCFG_PTOKEN_OUT == USBHS_HostGetToken(USBHS, pipe)) 
01881     {
01882         // Wait that all banks are free to freeze clock of OUT endpoint
01883         // and call callback
01884         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_NBUSYBKES);
01885 
01886         // For ISO out, start another DMA transfer since no ACK needed
01887         if (USBHS_HostGetPipeType(USBHS, pipe) == USBHS_HSTPIPCFG_PTYPE_ISO) 
01888         {
01889             USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01890         }
01891     }
01892     else
01893     {
01894         if (!USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_PFREEZE)) {
01895             // Pipe is not freeze in case of :
01896             // - incomplete transfer when the request number INRQ is not complete.
01897             // - low USB speed and with a high CPU frequency,
01898             // a ACK from host can be always running on USB line.
01899 
01900             if (nb_remaining) {
01901                 // Freeze pipe in case of incomplete transfer
01902                 USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);
01903             } else {
01904                 // Wait freeze in case of ASK on going
01905                 while (!USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_PFREEZE)) {
01906                 }
01907             }
01908         }
01909 
01910         USBH_HAL_PipeXfrCmplt(pipe);
01911     }
01912 }
01913 #endif // ifdef UHD_PIPE_DMA_SUPPORTED
01914 
01915 /**
01916  * \internal
01917  * \brief Manages the following pipe interrupts:
01918  * - Real end of USB transfers (bank empty)
01919  * - One bank is free to send a OUT ZLP
01920  * - Stall received
01921  * - Error during transfer
01922  *
01923  * \param pipe  Pipe number
01924  */
01925 static void USBH_HAL_PipeInterrupt(uint8_t pipe)
01926 {
01927     uint32_t status = USBHS_HostGetIntTypeStatus(USBHS, pipe, 0xFFFFFFFF);
01928     uint32_t statusInt = status & USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, 0xFFFFFFFF);
01929 #ifdef UHD_PIPE_FIFO_SUPPORTED
01930     // for none DMA endpoints
01931     if (!Is_uhd_pipe_dma_supported(pipe)) {
01932         // SHORTPACKETI: Short received
01933         if (statusInt & USBHS_HSTPIPISR_SHORTPACKETI) 
01934         {
01935             USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_SHORTPACKETIC); //uhd_ack_short_packet(pipe);
01936             USBH_HAL_PipeInReceived(pipe);
01937             return;
01938         }
01939         // RXIN: Full packet received
01940         if (statusInt & USBHS_HSTPIPIMR_RXINE ) {
01941             USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_RXINIC);//uhd_ack_in_received(pipe);
01942             USBH_HAL_PipeInReceived(pipe);
01943             return;
01944         }
01945         // TXOUT: packet sent
01946         if (statusInt & USBHS_HSTPIPISR_TXOUTI) {
01947             USBH_HAL_PipeOutReady(pipe);
01948             return;
01949         }
01950         // OUT: all banks sent
01951         if (USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_NBUSYBKE)
01952                 && (0==USBHS_HostGetNumOfBusyBank(USBHS, pipe))) 
01953         {
01954             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);
01955             USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_NBUSYBKEC );
01956             //uhd_disable_bank_interrupt(pipe);
01957             USBHS_HostPipeIntDisable(USBHS, pipe);
01958             //uhd_disable_pipe_interrupt(pipe);
01959             USBHS_HostEnableAutoSw(USBHS, pipe);
01960             //uhd_enable_pipe_bank_autoswitch(pipe);
01961             USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01962             return;
01963         }
01964         if (status & USBHS_HSTPIPISR_RXSTALLDI) {
01965             USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_RXSTALLDIC); //uhd_ack_stall(pipe);
01966             USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_RSTDTS);
01967             //uhd_reset_data_toggle(pipe);
01968             USBH_HAL_PipeAbort(pipe, UHD_TRANS_STALL);
01969             return;
01970         }
01971         if (status & USBHS_HSTPIPISR_PERRI) {
01972             // Get and ack error
01973             USBH_HAL_PipeAbort(pipe, USBH_HAL_GetPipeError(pipe));
01974             return;
01975         }
01976         assert(false); // Error system
01977         return;
01978     }
01979 #endif // UDD_EP_FIFO_SUPPORTED
01980 
01981 #ifdef UHD_PIPE_DMA_SUPPORTED
01982     // for DMA endpoints
01983     if (USBHS_IsHostPipeIntTypeEnable(USBHS, pipe, USBHS_HSTPIPIMR_NBUSYBKE) && (0==USBHS_HostGetNumOfBusyBank(USBHS, pipe))) {
01984         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_PFREEZES);//uhd_freeze_pipe(pipe);
01985         USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_NBUSYBKEC);//uhd_disable_bank_interrupt(pipe);
01986         // For ISO, no ACK, finished when DMA done
01987         if (!(USBHS_HostGetPipeType(USBHS, pipe) == USBHS_HSTPIPCFG_PTYPE_ISO)) {
01988             USBH_HAL_PipeXfrEnd(pipe, UHD_TRANS_NOERROR);
01989         }
01990         return;
01991     }
01992     if (USBHS_HSTPIPIMR_TXOUTE & statusInt) 
01993     {
01994         USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_TXOUTEC);
01995         //uhd_disable_out_ready_interrupt(pipe);
01996         // One bank is free then send a ZLP
01997         USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_TXOUTIC); //uhd_ack_out_ready(pipe);
01998         USBHS_HostDisablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIDR_FIFOCONC | USBHS_HSTPIPIDR_PFREEZEC));
01999         //USBHS_HostDisablePipeIntType(USBHS, pipe, );
02000         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_NBUSYBKES);
02001         return;
02002     }
02003     if (status & USBHS_HSTPIPISR_RXSTALLDI) {
02004         USBHS_HostAckPipeIntType(USBHS, pipe, USBHS_HSTPIPICR_RXSTALLDIC);//uhd_ack_stall(pipe);
02005         USBHS_HostEnablePipeIntType(USBHS, pipe, USBHS_HSTPIPIER_RSTDTS);
02006         USBH_HAL_PipeAbort(pipe, UHD_TRANS_STALL);
02007         return;
02008     }
02009     if (status & USBHS_HSTPIPISR_PERRI) {
02010         // Get and ack error
02011         USBH_HAL_PipeAbort(pipe, USBH_HAL_GetPipeError(pipe));
02012         return;
02013     }
02014     assert(false); // Error system
02015 #endif // UHD_PIPE_DMA_SUPPORTED
02016 }
02017 
02018 /**
02019  * \internal
02020  * \brief Aborts the on going transfer on a pipe
02021  *
02022  * \param pipe Pipe number
02023  * \param status Reason of abort
02024  */
02025 static void USBH_HAL_PipeAbort(uint8_t pipe, USBH_XfrStatus_t status)
02026 {
02027     Usbhs  *pUdp  = USBHS;
02028     UsbhsHstdma *pUsbDma = &pUdp->USBHS_HSTDMA[pipe-1];
02029     // Stop transfer
02030     USBHS_HostPipeReset(USBHS, pipe);
02031 
02032     // Autoswitch bank and interrupts has been reseted, then re-enable it
02033     USBHS_HostEnableAutoSw(USBHS, pipe);
02034     USBHS_HostEnablePipeIntType(USBHS, pipe, (USBHS_HSTPIPIER_RXSTALLDES | USBHS_HSTPIPIER_PERRES) );
02035     //uhd_enable_pipe_error_interrupt(pipe);
02036     USBHS_HostDisablePipeIntType(USBHS, pipe, USBHS_HSTPIPIDR_TXOUTEC);
02037 #ifdef UHD_PIPE_DMA_SUPPORTED
02038     if (Is_uhd_pipe_dma_supported(pipe)) {
02039         USBHS_HostConfigureDma(pUsbDma, 0);
02040     }
02041 #endif
02042     USBH_HAL_PipeXfrEnd(pipe, status);
02043 }
02044 
02045 /**
02046  * \internal
02047  * \brief Call the callback linked to the end of pipe transfer
02048  *
02049  * \param pipe Pipe number
02050  * \param status Status of the transfer
02051  */
02052 static void USBH_HAL_PipeXfrEnd(uint8_t pipe, USBH_XfrStatus_t status)
02053 {
02054     uint32_t dev_addr ,dev_ep;
02055     USBH_PipeJob_t *pJob;
02056     
02057     // Get job corresponding at endpoint
02058     pJob = &uhd_pipe_job[pipe - 1];
02059     if (pJob->busy == false) {
02060         return; // No job running
02061     }
02062     pJob->busy = false;
02063     if (NULL == pJob->call_end) {
02064         return; // No callback linked to job
02065     }
02066     dev_addr = USBHS_HostGetAddr(USBHS, pipe);
02067     dev_ep = USBHS_GetPipeEpAddr(USBHS, pipe);
02068     pJob->call_end(dev_addr, dev_ep, status, pJob->nb_trans);
02069 }
02070 
02071 //@}
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines