SAMV71 Xplained Ultra Software Package 1.5

USBH_HAL.c

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