1575 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			1575 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | //  am_hal_scard.c
 | ||
|  | //! @file
 | ||
|  | //!
 | ||
|  | //! @brief Functions for interfacing with the SCARD.
 | ||
|  | //!
 | ||
|  | //! @addtogroup scard3
 | ||
|  | //! @ingroup apollo3hal
 | ||
|  | //! @{
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Copyright (c) 2020, Ambiq Micro
 | ||
|  | // All rights reserved.
 | ||
|  | //
 | ||
|  | // Redistribution and use in source and binary forms, with or without
 | ||
|  | // modification, are permitted provided that the following conditions are met:
 | ||
|  | //
 | ||
|  | // 1. Redistributions of source code must retain the above copyright notice,
 | ||
|  | // this list of conditions and the following disclaimer.
 | ||
|  | //
 | ||
|  | // 2. Redistributions in binary form must reproduce the above copyright
 | ||
|  | // notice, this list of conditions and the following disclaimer in the
 | ||
|  | // documentation and/or other materials provided with the distribution.
 | ||
|  | //
 | ||
|  | // 3. Neither the name of the copyright holder nor the names of its
 | ||
|  | // contributors may be used to endorse or promote products derived from this
 | ||
|  | // software without specific prior written permission.
 | ||
|  | //
 | ||
|  | // Third party software included in this distribution is subject to the
 | ||
|  | // additional license terms as defined in the /docs/licenses directory.
 | ||
|  | //
 | ||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | ||
|  | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | ||
|  | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | ||
|  | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | ||
|  | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | ||
|  | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | ||
|  | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | ||
|  | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | ||
|  | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | ||
|  | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | ||
|  | // POSSIBILITY OF SUCH DAMAGE.
 | ||
|  | //
 | ||
|  | // This is part of revision 2.4.2 of the AmbiqSuite Development Package.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | 
 | ||
|  | #include <stdint.h>
 | ||
|  | #include <stdbool.h>
 | ||
|  | #include "am_mcu_apollo.h"
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // SCARD magic number for handle verification.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | #define AM_HAL_MAGIC_SCARD               0xEA9E06
 | ||
|  | 
 | ||
|  | #define AM_HAL_SCARD_CHK_HANDLE(h)                                             \
 | ||
|  |     ((h) &&                                                                   \ | ||
|  |      ((am_hal_handle_prefix_t *)(h))->s.bInit &&                              \ | ||
|  |      (((am_hal_handle_prefix_t *)(h))->s.magic == AM_HAL_MAGIC_SCARD)) | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Convenience macro for passing errors.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | #define RETURN_ON_ERROR(x)                                                    \
 | ||
|  |     if ((x) != AM_HAL_STATUS_SUCCESS)                                         \ | ||
|  |     {                                                                         \ | ||
|  |         return (x);                                                           \ | ||
|  |     }; | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Baudrate to byte-time in microseconds with a little extra margin.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | #define ONE_BIT_US(baudrate)       (AM_HAL_SCARD_CLK_FREQ/(baudrate))
 | ||
|  | #define ONE_BIT_DELAY(handle)                                                \
 | ||
|  |     am_hal_flash_delay(FLASH_CYCLES_US(ONE_BIT_US((handle)->ui32BaudRate))) | ||
|  | 
 | ||
|  | #define SCARD_MAX_SYNC_TIME_MS      10
 | ||
|  | 
 | ||
|  | #define delay_ms(ms)        am_hal_flash_delay(FLASH_CYCLES_US(1000 * (ms)))
 | ||
|  | #define delay_us(us)        am_hal_flash_delay(FLASH_CYCLES_US(us))
 | ||
|  | 
 | ||
|  | #define SCARD_WHILE_TIMEOUT_MS(expr, timeout, error)                                \
 | ||
|  | {                                                                         \ | ||
|  |     uint32_t ui32Timeout = 0;                                             \ | ||
|  |     while ( expr )                                                        \ | ||
|  |     {                                                                     \ | ||
|  |         if ( ui32Timeout == (timeout * 1000) )                            \ | ||
|  |         {                                                                 \ | ||
|  |             return error;                                                 \ | ||
|  |         }                                                                 \ | ||
|  |                                                                           \ | ||
|  |         delay_us(1);                                                      \ | ||
|  |         ui32Timeout++;                                                    \ | ||
|  |     }                                                                     \ | ||
|  | } | ||
|  | 
 | ||
|  | #define SCARD_SYNC_OPER(module, operation)   do{\
 | ||
|  |                                                 SCARDn(module)->SR1_b.SYNCEND = 1;\ | ||
|  |                                                 operation;\ | ||
|  |                                                 SCARD_WHILE_TIMEOUT_MS(!SCARDn(module)->SR1_b.SYNCEND, SCARD_MAX_SYNC_TIME_MS, AM_HAL_SCARD_STATUS_BUS_ERROR) ;\ | ||
|  |                                              } while ( 0 ) | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Transmission parameters F and D look-up tables
 | ||
|  | // Per the ETU 7816-3 protocol ETU is computed from 2 parameters, FI and DI.
 | ||
|  | // ETU: Elementary Time Unit
 | ||
|  | // FI: Clock rate conversion factor
 | ||
|  | // DI: Bit rate adjustment factor
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint16_t g_F_Integer[16][2] = | ||
|  | { | ||
|  |     // FI   { F, f(max)}
 | ||
|  |     /*0000*/{ 372,  4}, | ||
|  |     /*0001*/{ 372,  5}, | ||
|  |     /*0010*/{ 558,  6}, | ||
|  |     /*0011*/{ 744,  8}, | ||
|  |     /*0100*/{1116, 12}, | ||
|  |     /*0101*/{1488, 16}, | ||
|  |     /*0110*/{1860, 20}, | ||
|  |     /*0111*/{   0,  0}, | ||
|  |     /*1000*/{   0,  0}, | ||
|  |     /*1001*/{ 512,  5}, | ||
|  |     /*1010*/{ 768,  7},  //7.5
 | ||
|  |     /*1011*/{1024, 10}, | ||
|  |     /*1100*/{1536, 15}, | ||
|  |     /*1101*/{2048, 20}, | ||
|  |     /*1110*/{   0,  0}, | ||
|  |     /*1111*/{   0,  0} | ||
|  | }; | ||
|  | static uint8_t g_D_Integer[16] = | ||
|  | { | ||
|  |     //DI  0000 0001 0010 0011 0100 0101 0110 0111
 | ||
|  |     /*D*/    0,   1,   2,   4,   8,  16,  32,  64, | ||
|  |     //DI  1000 1001 1010 1011 1100 1101 1110 1111
 | ||
|  |     /*D*/   12,  20,   0,   0,   0,   0,   0,   0 | ||
|  | }; | ||
|  | 
 | ||
|  | static uint16_t g_WaitTime = AM_HAL_SCARD_WAIT_MAX_TIME; //Set to max
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Structure for handling SCARD register state information for power up/down
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | typedef struct | ||
|  | { | ||
|  |     bool bValid; | ||
|  |     uint32_t regIER; | ||
|  |     uint32_t regTCR; | ||
|  |     uint32_t regUCR; | ||
|  |     uint32_t regBPRL; | ||
|  |     uint32_t regBPRH; | ||
|  |     uint32_t regUCR1; | ||
|  |     uint32_t regIER1; | ||
|  |     uint32_t regGTR; | ||
|  |     uint32_t regRETXCNT; | ||
|  |     uint32_t regCLKCTRL; | ||
|  | } | ||
|  | am_hal_scard_register_state_t; | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Structure for handling SCARD instance state information.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | typedef struct | ||
|  | { | ||
|  |     am_hal_handle_prefix_t prefix; | ||
|  |     am_hal_scard_register_state_t sRegState; | ||
|  | 
 | ||
|  |     uint32_t ui32Module; | ||
|  | 
 | ||
|  |     bool bEnableTxQueue; | ||
|  |     am_hal_queue_t sTxQueue; | ||
|  | 
 | ||
|  |     bool bEnableRxQueue; | ||
|  |     am_hal_queue_t sRxQueue; | ||
|  | 
 | ||
|  |     uint32_t ui32BaudRate; | ||
|  | } | ||
|  | am_hal_scard_state_t; | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // State structure for each module.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | am_hal_scard_state_t g_am_hal_scard_states[AM_REG_SCARD_NUM_MODULES]; | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Allows the SCARD HAL to use extra space to store TX and RX data.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | buffer_configure(void *pHandle, uint8_t *pui8TxBuffer, uint32_t ui32TxBufferSize, | ||
|  |                  uint8_t *pui8RxBuffer, uint32_t ui32RxBufferSize) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32ErrorStatus; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to make sure this is a valid handle.
 | ||
|  |     //
 | ||
|  |     if ( !AM_HAL_SCARD_CHK_HANDLE(pHandle) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to see if we have a TX buffer.
 | ||
|  |     //
 | ||
|  |     if ( pui8TxBuffer && ui32TxBufferSize ) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // If so, initialzie the transmit queue, and enable the TX FIFO
 | ||
|  |         // interrupt.
 | ||
|  |         //
 | ||
|  |         pState->bEnableTxQueue = true; | ||
|  |         am_hal_queue_init(&pState->sTxQueue, pui8TxBuffer, 1, ui32TxBufferSize); | ||
|  |         ui32ErrorStatus = am_hal_scard_interrupt_enable(pHandle, 0, AM_HAL_SCARD_INT_TBERBFEN); | ||
|  |         RETURN_ON_ERROR(ui32ErrorStatus); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         //
 | ||
|  |         // If not, make sure the TX FIFO interrupt is disabled.
 | ||
|  |         //
 | ||
|  |         pState->bEnableTxQueue = false; | ||
|  |         ui32ErrorStatus = am_hal_scard_interrupt_disable(pHandle, 0, AM_HAL_SCARD_INT_TBERBFEN); | ||
|  |         RETURN_ON_ERROR(ui32ErrorStatus); | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to see if we have an RX buffer.
 | ||
|  |     //
 | ||
|  |     if ( pui8RxBuffer && ui32RxBufferSize ) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // If so, initialize the receive queue and the associated interupts.
 | ||
|  |         //
 | ||
|  |         pState->bEnableRxQueue = true; | ||
|  |         am_hal_queue_init(&pState->sRxQueue, pui8RxBuffer, 1, ui32RxBufferSize); | ||
|  |         ui32ErrorStatus = am_hal_scard_interrupt_enable(pHandle, 0, (AM_HAL_SCARD_INT_FHFEN | | ||
|  |                                                                      AM_HAL_SCARD_INT_FNEEN)); | ||
|  |         RETURN_ON_ERROR(ui32ErrorStatus); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         pState->bEnableRxQueue = false; | ||
|  |         ui32ErrorStatus = am_hal_scard_interrupt_disable(pHandle, 0, (AM_HAL_SCARD_INT_FHFEN | | ||
|  |                                                                       AM_HAL_SCARD_INT_FNEEN)); | ||
|  |         RETURN_ON_ERROR(ui32ErrorStatus); | ||
|  |     } | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // buffer_configure()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Initialization function.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_initialize(uint32_t ui32Module, void **ppHandle) | ||
|  | { | ||
|  |     //
 | ||
|  |     // Check that the request module is in range.
 | ||
|  |     //
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( ui32Module >= AM_REG_SCARD_NUM_MODULES ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_OUT_OF_RANGE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check for valid arguements.
 | ||
|  |     //
 | ||
|  |     if ( !ppHandle ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_ARG; | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check if the handle is unallocated.
 | ||
|  |     //
 | ||
|  |     if ( g_am_hal_scard_states[ui32Module].prefix.s.bInit ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_OPERATION; | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Initialize the handle.
 | ||
|  |     //
 | ||
|  |     g_am_hal_scard_states[ui32Module].prefix.s.bInit = true; | ||
|  |     g_am_hal_scard_states[ui32Module].prefix.s.magic = AM_HAL_MAGIC_SCARD; | ||
|  |     g_am_hal_scard_states[ui32Module].ui32Module = ui32Module; | ||
|  |     g_am_hal_scard_states[ui32Module].sRegState.bValid = false; | ||
|  |     g_am_hal_scard_states[ui32Module].ui32BaudRate = 0; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Return the handle.
 | ||
|  |     //
 | ||
|  |     *ppHandle = (void *)&g_am_hal_scard_states[ui32Module]; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Return the status.
 | ||
|  |     //
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_initialize()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // De-Initialization function.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_deinitialize(void *pHandle) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *)pHandle; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check the handle.
 | ||
|  |     //
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( !AM_HAL_SCARD_CHK_HANDLE(pHandle) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Reset the handle.
 | ||
|  |     //
 | ||
|  |     pState->prefix.s.bInit = false; | ||
|  |     pState->ui32Module = 0; | ||
|  |     pState->sRegState.bValid = false; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Return the status.
 | ||
|  |     //
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_deinitialize()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Power control functions.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_power_control(void *pHandle, | ||
|  |                            am_hal_sysctrl_power_state_e ePowerState, | ||
|  |                            bool bRetainState) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  | 
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( ui32Module >= AM_REG_SCARD_NUM_MODULES ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_OUT_OF_RANGE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     am_hal_pwrctrl_periph_e eSCCPowerModule = ((am_hal_pwrctrl_periph_e) | ||
|  |                                                 (AM_HAL_PWRCTRL_PERIPH_SCARD + | ||
|  |                                                  ui32Module)); | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to make sure this is a valid handle.
 | ||
|  |     //
 | ||
|  |     if ( !AM_HAL_SCARD_CHK_HANDLE(pHandle) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Decode the requested power state and update SCARD operation accordingly.
 | ||
|  |     //
 | ||
|  |     switch (ePowerState) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // Turn on the SCC.
 | ||
|  |         //
 | ||
|  |         case AM_HAL_SYSCTRL_WAKE: | ||
|  |             //
 | ||
|  |             // Make sure we don't try to restore an invalid state.
 | ||
|  |             //
 | ||
|  |             if ( bRetainState && !pState->sRegState.bValid ) | ||
|  |             { | ||
|  |                 return AM_HAL_STATUS_INVALID_OPERATION; | ||
|  |             } | ||
|  | 
 | ||
|  |             //
 | ||
|  |             // Enable power control.
 | ||
|  |             //
 | ||
|  |             am_hal_pwrctrl_periph_enable(eSCCPowerModule); | ||
|  | 
 | ||
|  |             if ( bRetainState ) | ||
|  |             { | ||
|  |                 //
 | ||
|  |                 // Restore SCC registers
 | ||
|  |                 //
 | ||
|  |                 AM_CRITICAL_BEGIN | ||
|  | 
 | ||
|  |                 SCARDn(ui32Module)->IER = pState->sRegState.regIER; | ||
|  |                 SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR = pState->sRegState.regTCR); | ||
|  |                 SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->UCR = pState->sRegState.regUCR); | ||
|  |                 SCARDn(ui32Module)->BPRL = pState->sRegState.regBPRL; | ||
|  |                 SCARDn(ui32Module)->BPRH   = pState->sRegState.regBPRH; | ||
|  |                 SCARDn(ui32Module)->UCR1 = pState->sRegState.regUCR1; | ||
|  |                 SCARDn(ui32Module)->IER1  = pState->sRegState.regIER1; | ||
|  |                 SCARDn(ui32Module)->GTR  = pState->sRegState.regGTR; | ||
|  |                 SCARDn(ui32Module)->RETXCNT  = pState->sRegState.regRETXCNT; | ||
|  |                 SCARDn(ui32Module)->CLKCTRL  = pState->sRegState.regCLKCTRL; | ||
|  |                 pState->sRegState.bValid = false; | ||
|  | 
 | ||
|  |                 AM_CRITICAL_END | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         //
 | ||
|  |         // Turn off the SCARD.
 | ||
|  |         //
 | ||
|  |         case AM_HAL_SYSCTRL_NORMALSLEEP: | ||
|  |         case AM_HAL_SYSCTRL_DEEPSLEEP: | ||
|  |             if ( bRetainState ) | ||
|  |             { | ||
|  |                 AM_CRITICAL_BEGIN | ||
|  | 
 | ||
|  |                 pState->sRegState.regIER = SCARDn(ui32Module)->IER; | ||
|  |                 pState->sRegState.regTCR = SCARDn(ui32Module)->TCR; | ||
|  |                 pState->sRegState.regUCR = SCARDn(ui32Module)->UCR; | ||
|  |                 pState->sRegState.regBPRL = SCARDn(ui32Module)->BPRL; | ||
|  |                 pState->sRegState.regBPRH   = SCARDn(ui32Module)->BPRH; | ||
|  |                 pState->sRegState.regUCR1 = SCARDn(ui32Module)->UCR1; | ||
|  |                 pState->sRegState.regIER1  = SCARDn(ui32Module)->IER1; | ||
|  |                 pState->sRegState.regGTR = SCARDn(ui32Module)->GTR; | ||
|  |                 pState->sRegState.regRETXCNT = SCARDn(ui32Module)->RETXCNT; | ||
|  |                 pState->sRegState.regCLKCTRL = SCARDn(ui32Module)->CLKCTRL; | ||
|  |                 pState->sRegState.bValid = true; | ||
|  | 
 | ||
|  |                 AM_CRITICAL_END | ||
|  |             } | ||
|  | 
 | ||
|  |             //
 | ||
|  |             // Clear all interrupts before sleeping as having a pending SCARD
 | ||
|  |             // interrupt burns power.
 | ||
|  |             //
 | ||
|  |             am_hal_scard_interrupt_clear(pState, 0, AM_HAL_SCARD_INT_ALL); | ||
|  |             am_hal_scard_interrupt_clear(pState, 1, AM_HAL_SCARD_INT_ALL); | ||
|  | 
 | ||
|  |             //
 | ||
|  |             // Disable power control.
 | ||
|  |             //
 | ||
|  |             am_hal_pwrctrl_periph_disable(eSCCPowerModule); | ||
|  |             break; | ||
|  | 
 | ||
|  |         default: | ||
|  |             return AM_HAL_STATUS_INVALID_ARG; | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Return the status.
 | ||
|  |     //
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_power_control()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // SCARD configuration.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_configure(void *pHandle, am_hal_scard_config_t *psConfig) | ||
|  | { | ||
|  |     uint32_t status = AM_HAL_STATUS_SUCCESS; | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to make sure this is a valid handle.
 | ||
|  |     //
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( !AM_HAL_SCARD_CHK_HANDLE(pHandle) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     //
 | ||
|  |     // Start by enabling the clocks, which needs to happen in a critical
 | ||
|  |     // section.
 | ||
|  |     //
 | ||
|  |     AM_CRITICAL_BEGIN | ||
|  | 
 | ||
|  |     SCARDn(ui32Module)->CLKCTRL_b.APBCLKEN = 1; | ||
|  |     SCARDn(ui32Module)->CLKCTRL_b.CLKEN = 1; | ||
|  | 
 | ||
|  |     AM_CRITICAL_END | ||
|  |     //
 | ||
|  |     // Set the baud rate.
 | ||
|  |     //
 | ||
|  |     status = am_hal_scard_control(pHandle, AM_HAL_SCARD_REQ_BAUDRATE, &psConfig->ui32Fidi); | ||
|  | 
 | ||
|  |     //RETURN_ON_ERROR(ui32ErrorStatus);
 | ||
|  |     //
 | ||
|  |     // Copy the configuration options into the appropriate registers.
 | ||
|  |     //
 | ||
|  |     status = am_hal_scard_control(pHandle, AM_HAL_SCARD_REQ_PROTOCOL, &psConfig->ui32Protocol); | ||
|  |     status = am_hal_scard_control(pHandle, AM_HAL_SCARD_REQ_CARD_FORMAT, &psConfig->ui32Direction); | ||
|  |     status = am_hal_scard_control(pHandle, AM_HAL_SCARD_REQ_PARITY, &psConfig->ui32Parity); | ||
|  |     status = am_hal_scard_control(pHandle, AM_HAL_SCARD_REQ_GUARDTIME, &psConfig->ui32GuardTime); | ||
|  |     SCARDn(ui32Module)->UCR1_b.CLKIOV = psConfig->ui32ClkLevel; | ||
|  |     status = am_hal_scard_control(pHandle, AM_HAL_SCARD_REQ_CLK_STOP, NULL); | ||
|  |     SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->UCR_b.RIU = 1); | ||
|  |     if ( AM_HAL_STATUS_SUCCESS != status ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_FAIL; | ||
|  |     } | ||
|  |     //
 | ||
|  |     // Set up any buffers that might exist.
 | ||
|  |     //
 | ||
|  |     buffer_configure(pHandle, | ||
|  |                      psConfig->pui8TxBuffer, | ||
|  |                      psConfig->ui32TxBufferSize, | ||
|  |                      psConfig->pui8RxBuffer, | ||
|  |                      psConfig->ui32RxBufferSize); | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_configure()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Set Baud Rate Register based on the parameters F and D.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static void | ||
|  | config_baudrate(void *pHandle, uint32_t ui32Fidi) | ||
|  | { | ||
|  |     uint16_t bpr; | ||
|  |     uint32_t ui32ActualBaud; | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  | 
 | ||
|  |     // F is the clock rate conversion integer
 | ||
|  |     // D is the baud rate adjustment integer
 | ||
|  |     //    1 ETU = (F/D)*(1/f) s
 | ||
|  |     // The default values of these parameters are:
 | ||
|  |     // F = 372 ; D = 1; f (max.) = 5 MHz
 | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // BPRL and BPRH are used for counting ETU
 | ||
|  |     //
 | ||
|  |     bpr = ((g_F_Integer[AM_HAL_SCARD_FI(ui32Fidi)][0] != 0) && (g_D_Integer[AM_HAL_SCARD_DI(ui32Fidi)] != 0)) ? \ | ||
|  |         g_F_Integer[AM_HAL_SCARD_FI(ui32Fidi)][0] / g_D_Integer[AM_HAL_SCARD_DI(ui32Fidi)] : \ | ||
|  |         g_F_Integer[AM_HAL_SCARD_FI(AM_HAL_SCARD_FI_DI_DEFAULT)][0] / g_D_Integer[AM_HAL_SCARD_DI(AM_HAL_SCARD_FI_DI_DEFAULT)]; | ||
|  | 
 | ||
|  |     SCARDn(ui32Module)->BPRL = bpr & 0xFF; | ||
|  |     SCARDn(ui32Module)->BPRH = (SCARDn(ui32Module)->BPRH & (~SCARD_BPRH_BPRH_Msk)) | ((bpr >> 8) & SCARD_BPRH_BPRH_Msk) ; | ||
|  |     ui32ActualBaud = (uint32_t)(AM_HAL_SCARD_CLK_FREQ / bpr); | ||
|  |     pState->ui32BaudRate = ui32ActualBaud; | ||
|  | } // config_baudrate()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Set card format, direct convention or inverse convention
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | config_cardformat(uint32_t ui32Module, uint32_t ui32Format) | ||
|  | { | ||
|  |     switch(ui32Format) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // Inverse convention
 | ||
|  |         //
 | ||
|  |         case AM_HAL_SCARD_CONV_MSB_0X3F: | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.AUTOCONV = 1); | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.CONV = 1); | ||
|  |             break; | ||
|  |         //
 | ||
|  |         // Direct convention
 | ||
|  |         //
 | ||
|  |         case AM_HAL_SCARD_CONV_LSB_0X3B: | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.AUTOCONV = 1); | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.CONV = 0); | ||
|  |             break; | ||
|  |         //
 | ||
|  |         // Not set by software, configured by the first received byte
 | ||
|  |         //
 | ||
|  |         case AM_HAL_SCARD_CONV_AUTO: | ||
|  |         default: | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.AUTOCONV = 0); | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.SS = 1); | ||
|  |             break; | ||
|  |     } | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Enable/disbale parity and set it to odd/even
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | config_parity(uint32_t ui32Module, uint32_t ui32Parity) | ||
|  | { | ||
|  |     //
 | ||
|  |     // T1 protocol
 | ||
|  |     //
 | ||
|  |     if ( SCARDn(ui32Module)->TCR_b.PROT ) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // Enable parity
 | ||
|  |         //
 | ||
|  |         if ( ui32Parity & 0xF0 ) | ||
|  |         { | ||
|  |             SCARDn(ui32Module)->UCR1_b.T1PAREN = 1; | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.FIP = ui32Parity & 0xF); | ||
|  |         } | ||
|  |         //
 | ||
|  |         // Disbale parity
 | ||
|  |         //
 | ||
|  |         else | ||
|  |         { | ||
|  |             SCARDn(ui32Module)->UCR1_b.T1PAREN = 0; | ||
|  |         } | ||
|  |     } | ||
|  |     //
 | ||
|  |     // T0 protocol, always enable parity
 | ||
|  |     //
 | ||
|  |     else | ||
|  |     { | ||
|  |         SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.FIP = ui32Parity & 0xF); | ||
|  |     } | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Set protocol, T0 or T1
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | config_protocol(uint32_t ui32Module, uint32_t ui32Protocol) | ||
|  | { | ||
|  |     if ( 1 == ui32Protocol ) | ||
|  |     { | ||
|  |         SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.PROT = AM_HAL_SCARD_PROTOCOL_T1); | ||
|  |     } | ||
|  |     else if ( 0 == ui32Protocol ) | ||
|  |     { | ||
|  |         SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.PROT = AM_HAL_SCARD_PROTOCOL_T0); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         return AM_HAL_SCARD_STATUS_PROTOCAL_NOT_SUPPORT; | ||
|  |     } | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Set and start ETU counter
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | config_etucounter(uint32_t ui32Module, uint16_t ui16Etu) | ||
|  | { | ||
|  |     //
 | ||
|  |     // Set low-8bit first, then set high-8bit, after software writes ECNTH, ETU counter starts counting
 | ||
|  |     //
 | ||
|  |     SCARD_WHILE_TIMEOUT_MS(!SCARDn(ui32Module)->SR1_b.IDLE, 100, AM_HAL_SCARD_STATUS_BUS_ERROR); | ||
|  |     SCARDn(ui32Module)->SR1_b.SYNCEND = 1; | ||
|  |     SCARDn(ui32Module)->ECNTL = (ui16Etu) & 0xFF; | ||
|  |     SCARD_WHILE_TIMEOUT_MS(!SCARDn(ui32Module)->SR1_b.SYNCEND, 100, AM_HAL_SCARD_STATUS_BUS_ERROR); | ||
|  |     SCARDn(ui32Module)->ECNTH = ((ui16Etu) >> 8); | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Read as much data from the SCARD FIFO as possible, up to ui32NumBytes
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t scard_fifo_read(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes, uint32_t *pui32NumBytesRead) | ||
|  | { | ||
|  |     uint32_t ui32ErrorStatus = AM_HAL_STATUS_SUCCESS; | ||
|  |     uint32_t i = 0; | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  |     uint8_t ui8Index = 0; | ||
|  | 
 | ||
|  |     SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.TR = 0); | ||
|  | 
 | ||
|  |     while ( ui32NumBytes ) | ||
|  |     { | ||
|  |         config_etucounter(ui32Module, g_WaitTime); | ||
|  |         while ( (!SCARDn(ui32Module)->SR_b.FNE) && (!SCARDn(ui32Module)->SR1_b.ECNTOVER) && (!SCARDn(ui32Module)->SR_b.PE) && (!SCARDn(ui32Module)->SR_b.FER) ); | ||
|  |         //
 | ||
|  |         // Read times out
 | ||
|  |         //
 | ||
|  |         if ( SCARDn(ui32Module)->SR1_b.ECNTOVER ) | ||
|  |         { | ||
|  |             break; | ||
|  |         } | ||
|  |         //
 | ||
|  |         // Parity error or Frame error
 | ||
|  |         //
 | ||
|  |         else if ( (SCARDn(ui32Module)->SR_b.PE) || (SCARDn(ui32Module)->SR_b.FER) ) | ||
|  |         { | ||
|  |             SCARDn(ui32Module)->SR_b.PE = 0; | ||
|  |             SCARDn(ui32Module)->SR_b.FER = 0; | ||
|  |             ui32ErrorStatus = AM_HAL_STATUS_FAIL; | ||
|  |             break; | ||
|  |         } | ||
|  |         //
 | ||
|  |         // RX FIFO is full, read 8 bytes out
 | ||
|  |         //
 | ||
|  |         else if ( SCARDn(ui32Module)->SR_b.TBERBF ) | ||
|  |         { | ||
|  |             for ( ui8Index = 0; ui8Index < AM_HAL_SCARD_FIFO_MAX; ui8Index++ ) | ||
|  |             { | ||
|  |                 pui8Data[i++] = SCARDn(ui32Module)->DR_b.DR; | ||
|  |             } | ||
|  |             ui32NumBytes -= AM_HAL_SCARD_FIFO_MAX; | ||
|  |         } | ||
|  |         //
 | ||
|  |         // RX FIFO is half full, read 4 bytes out
 | ||
|  |         //
 | ||
|  |         else if ( SCARDn(ui32Module)->SR_b.FHF ) | ||
|  |         { | ||
|  |             for ( ui8Index = 0; ui8Index < AM_HAL_SCARD_FIFO_MAX / 2; ui8Index++ ) | ||
|  |             { | ||
|  |                 pui8Data[i++] = SCARDn(ui32Module)->DR_b.DR; | ||
|  |             } | ||
|  |             ui32NumBytes -= AM_HAL_SCARD_FIFO_MAX / 2; | ||
|  |         } | ||
|  |         //
 | ||
|  |         // RX FIFO is not empty, read as much as we can
 | ||
|  |         //
 | ||
|  |         else if ( SCARDn(ui32Module)->SR_b.FNE ) | ||
|  |         { | ||
|  |             pui8Data[i++] = SCARDn(ui32Module)->DR_b.DR; | ||
|  |             ui32NumBytes--; | ||
|  |         } | ||
|  |     } | ||
|  |     if ( pui32NumBytesRead ) | ||
|  |     { | ||
|  |         *pui32NumBytesRead = i; | ||
|  |     } | ||
|  |     return ui32ErrorStatus; | ||
|  | } | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Read as much data from the SCARD FIFO as possible, up to ui32NumBytes
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t scard_fifo_write(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes, uint32_t *pui32NumBytesWritten) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  |     uint32_t i = 0; | ||
|  | 
 | ||
|  |     if ( ui32NumBytes ) | ||
|  |     { | ||
|  |         SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.TR = 1); | ||
|  | 
 | ||
|  |         while ( 1 != ui32NumBytes-- ) | ||
|  |         { | ||
|  |             //
 | ||
|  |             // Write 1 byte into DR
 | ||
|  |             //
 | ||
|  |             SCARDn(ui32Module)->DR_b.DR = pui8Data[i++]; | ||
|  |             SCARD_WHILE_TIMEOUT_MS((!SCARDn(ui32Module)->SR_b.TBERBF) && (!SCARDn(ui32Module)->SR_b.PE) && (!SCARDn(ui32Module)->SR_b.FER), 100, AM_HAL_SCARD_STATUS_BUS_ERROR); | ||
|  |             //
 | ||
|  |             // Parity error or Frame error
 | ||
|  |             //
 | ||
|  |             if ( (SCARDn(ui32Module)->SR_b.PE) || (SCARDn(ui32Module)->SR_b.FER) ) | ||
|  |             { | ||
|  |                 SCARDn(ui32Module)->SR_b.PE = 0; | ||
|  |                 SCARDn(ui32Module)->SR_b.FER = 0; | ||
|  |                 return AM_HAL_STATUS_FAIL; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         //
 | ||
|  |         // Enable fast TX to RX function before the last byte
 | ||
|  |         //
 | ||
|  |         SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.LCT = 1); | ||
|  |         SCARDn(ui32Module)->DR_b.DR = pui8Data[i++]; | ||
|  |         //
 | ||
|  |         // SCC should switch back to RX after all data sent out
 | ||
|  |         //
 | ||
|  |         SCARD_WHILE_TIMEOUT_MS((!SCARDn(ui32Module)->SR_b.FT2REND) && (!SCARDn(ui32Module)->SR_b.PE) && (!SCARDn(ui32Module)->SR_b.FER), 100, AM_HAL_SCARD_STATUS_BUS_ERROR); | ||
|  |         //
 | ||
|  |         // Parity error or Frame error
 | ||
|  |         //
 | ||
|  |         if ( (SCARDn(ui32Module)->SR_b.PE) || (SCARDn(ui32Module)->SR_b.FER) ) | ||
|  |         { | ||
|  |             SCARDn(ui32Module)->SR_b.PE = 0; | ||
|  |             SCARDn(ui32Module)->SR_b.FER = 0; | ||
|  |             return AM_HAL_STATUS_FAIL; | ||
|  |         } | ||
|  | 
 | ||
|  |         SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->TCR_b.TR = 0); | ||
|  |     } | ||
|  |     if ( pui32NumBytesWritten ) | ||
|  |     { | ||
|  |         *pui32NumBytesWritten = i; | ||
|  |     } | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Empty the SCARD RX FIFO, and place the data into the RX queue.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | rx_queue_update(void *pHandle) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  | 
 | ||
|  |     uint8_t pui8Data[AM_HAL_SCARD_FIFO_MAX]; | ||
|  |     uint32_t ui32BytesTransferred; | ||
|  |     uint32_t ui32ErrorStatus; | ||
|  | 
 | ||
|  |     AM_CRITICAL_BEGIN | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Read as much of the FIFO as we can.
 | ||
|  |     //
 | ||
|  |     ui32ErrorStatus = scard_fifo_read(pHandle, pui8Data, AM_HAL_SCARD_FIFO_MAX, | ||
|  |                                      &ui32BytesTransferred); | ||
|  |     //
 | ||
|  |     // If we were successful, go ahead and transfer the data along to the
 | ||
|  |     // buffer.
 | ||
|  |     //
 | ||
|  |     if ( ui32ErrorStatus == AM_HAL_STATUS_SUCCESS ) | ||
|  |     { | ||
|  |         if ( !am_hal_queue_item_add(&pState->sRxQueue, pui8Data, | ||
|  |                                     ui32BytesTransferred) ) | ||
|  |         { | ||
|  |             ui32ErrorStatus = AM_HAL_SCARD_STATUS_RX_QUEUE_FULL; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     AM_CRITICAL_END | ||
|  | 
 | ||
|  |     return ui32ErrorStatus; | ||
|  | } // rx_queue_update()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Transfer as much data as possible from the TX queue to the TX FIFO.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | tx_queue_update(void *pHandle) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  | 
 | ||
|  |     uint8_t pui8Data; | ||
|  |     uint32_t ui32BytesTransferred; | ||
|  |     uint32_t ui32ErrorStatus = AM_HAL_STATUS_SUCCESS; | ||
|  | 
 | ||
|  |     AM_CRITICAL_BEGIN | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Attempt to grab an item from the queue, and add it to the fifo.
 | ||
|  |     //
 | ||
|  |     while ( 1 ) | ||
|  |     { | ||
|  |         if ( am_hal_queue_item_get(&pState->sTxQueue, &pui8Data, 1) ) | ||
|  |         { | ||
|  |             ui32ErrorStatus = scard_fifo_write(pHandle, &pui8Data, 1, &ui32BytesTransferred); | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             //
 | ||
|  |             // If we didn't get anything from the queue, we can just return.
 | ||
|  |             //
 | ||
|  |             break; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     AM_CRITICAL_END | ||
|  | 
 | ||
|  |     return ui32ErrorStatus; | ||
|  | } // tx_queue_update()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Attempt to read N bytes from the FIFO, but give up if they aren't there.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | read_nonblocking(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes, | ||
|  |                  uint32_t *pui32NumBytesRead) | ||
|  | { | ||
|  |     uint32_t ui32BufferData; | ||
|  |     uint32_t ui32BytesTransferred; | ||
|  |     uint32_t ui32ErrorStatus = AM_HAL_STATUS_SUCCESS; | ||
|  | 
 | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to make sure this is a valid handle.
 | ||
|  |     //
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( (!AM_HAL_SCARD_CHK_HANDLE(pHandle)) || (NULL == pui8Data) || (NULL == pui32NumBytesRead) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Start by setting the number of bytes read to 0.
 | ||
|  |     //
 | ||
|  |     *pui32NumBytesRead = 0; | ||
|  | 
 | ||
|  |     if ( ui32NumBytes == 0 ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_SUCCESS; | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to see if the circular receive buffer has been enabled.
 | ||
|  |     //
 | ||
|  |     if ( pState->bEnableRxQueue ) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // If it is, update it, and then try to read the requested number of
 | ||
|  |         // bytes, giving up if fewer were actually found.
 | ||
|  |         //
 | ||
|  |         ui32ErrorStatus = rx_queue_update(pHandle); | ||
|  |         RETURN_ON_ERROR(ui32ErrorStatus); | ||
|  | 
 | ||
|  |         ui32BufferData = am_hal_queue_data_left(&pState->sRxQueue); | ||
|  | 
 | ||
|  |         ui32BytesTransferred = (ui32NumBytes < ui32BufferData ? | ||
|  |                                 ui32NumBytes : ui32BufferData); | ||
|  | 
 | ||
|  |         am_hal_queue_item_get(&pState->sRxQueue, pui8Data, ui32BytesTransferred); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         //
 | ||
|  |         // If the buffer isn't enabled, just read straight from the FIFO.
 | ||
|  |         //
 | ||
|  |         ui32ErrorStatus = scard_fifo_read(pHandle, pui8Data, ui32NumBytes, | ||
|  |                                          &ui32BytesTransferred); | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Let the caller know how much we transferred if they provided us with a
 | ||
|  |     // pointer.
 | ||
|  |     //
 | ||
|  |     *pui32NumBytesRead = ui32BytesTransferred; | ||
|  | 
 | ||
|  |     return ui32ErrorStatus; | ||
|  | } // read_nonblocking()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Attempt to write N bytes to the FIFO, but give up if there's no space.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | write_nonblocking(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes, | ||
|  |                   uint32_t *pui32NumBytesWritten) | ||
|  | { | ||
|  |     uint32_t ui32ErrorStatus; | ||
|  |     uint32_t ui32BufferSpace; | ||
|  |     uint32_t ui32BytesTransferred; | ||
|  | 
 | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to make sure this is a valid handle.
 | ||
|  |     //
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( (!AM_HAL_SCARD_CHK_HANDLE(pHandle)) || (NULL == pui8Data) || (NULL == pui32NumBytesWritten) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Let the caller know how much we transferred if they provided us with a
 | ||
|  |     // pointer.
 | ||
|  |     //
 | ||
|  |     *pui32NumBytesWritten = 0; | ||
|  | 
 | ||
|  |     if ( ui32NumBytes == 0 ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_SUCCESS; | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to see if the circular transmit buffer has been enabled.
 | ||
|  |     //
 | ||
|  |     if ( pState->bEnableTxQueue ) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // If it has, been enabled, write as much data to it as we can, and let
 | ||
|  |         // the caller know how much that was.
 | ||
|  |         //
 | ||
|  |         ui32BufferSpace = am_hal_queue_space_left(&pState->sTxQueue); | ||
|  | 
 | ||
|  |         ui32BytesTransferred = (ui32NumBytes < ui32BufferSpace ? | ||
|  |                              ui32NumBytes : ui32BufferSpace); | ||
|  | 
 | ||
|  |         am_hal_queue_item_add(&pState->sTxQueue, pui8Data, ui32BytesTransferred); | ||
|  | 
 | ||
|  |         //
 | ||
|  |         // Transfer as much data as possible from the queue to the fifo.
 | ||
|  |         //
 | ||
|  |         ui32ErrorStatus = tx_queue_update(pHandle); | ||
|  |         RETURN_ON_ERROR(ui32ErrorStatus); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         //
 | ||
|  |         // If the buffer isn't enabled, just write straight to the FIFO.
 | ||
|  |         //
 | ||
|  |         scard_fifo_write(pHandle, pui8Data, ui32NumBytes, | ||
|  |                      &ui32BytesTransferred); | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Let the caller know how much we transferred if they provided us with a
 | ||
|  |     // pointer.
 | ||
|  |     //
 | ||
|  |     *pui32NumBytesWritten = ui32BytesTransferred; | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // write_nonblocking()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // This function will keep reading bytes until it either gets N bytes or runs
 | ||
|  | // into an error.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | read_timeout(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes, | ||
|  |              uint32_t *pui32NumBytesRead, uint32_t ui32TimeoutMs) | ||
|  | { | ||
|  |     uint32_t ui32Status, ui32BytesRead, ui32RemainingBytes, | ||
|  |              ui32TimeSpent, i; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // If we don't have a timeout, just pass this directly to the nonblocking
 | ||
|  |     // call.
 | ||
|  |     //
 | ||
|  |     if ( ui32TimeoutMs == 0 ) | ||
|  |     { | ||
|  |         return read_nonblocking(pHandle, pui8Data, ui32NumBytes, | ||
|  |                                 pui32NumBytesRead); | ||
|  |     } | ||
|  | 
 | ||
|  |     i = 0; | ||
|  |     ui32RemainingBytes = ui32NumBytes; | ||
|  |     ui32TimeSpent = 0; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Loop until we're done reading. This will either be because we hit a
 | ||
|  |     // timeout, or we got the right number of bytes. If the caller specified
 | ||
|  |     // "wait forever", then don't check the timeout.
 | ||
|  |     //
 | ||
|  |     while ( ui32RemainingBytes && (ui32TimeSpent < ui32TimeoutMs) ) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // Read as much as we can.
 | ||
|  |         //
 | ||
|  |         ui32BytesRead = 0; | ||
|  |         ui32Status = read_nonblocking(pHandle, &pui8Data[i], | ||
|  |                                       ui32RemainingBytes, | ||
|  |                                       &ui32BytesRead); | ||
|  |         //
 | ||
|  |         // Update the tracking variables.
 | ||
|  |         //
 | ||
|  |         i += ui32BytesRead; | ||
|  |         ui32RemainingBytes -= ui32BytesRead; | ||
|  | 
 | ||
|  |         if ( ui32Status != AM_HAL_STATUS_SUCCESS ) | ||
|  |         { | ||
|  |             if ( pui32NumBytesRead ) | ||
|  |             { | ||
|  |                 *pui32NumBytesRead = i; | ||
|  |             } | ||
|  | 
 | ||
|  |             return ui32Status; | ||
|  |         } | ||
|  | 
 | ||
|  |         //
 | ||
|  |         // Update the timeout.
 | ||
|  |         //
 | ||
|  |         if ( ui32RemainingBytes ) | ||
|  |         { | ||
|  |             delay_us(1); | ||
|  | 
 | ||
|  |             if ( ui32TimeoutMs != AM_HAL_SCARD_WAIT_FOREVER ) | ||
|  |             { | ||
|  |                 ui32TimeSpent++; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     if ( pui32NumBytesRead ) | ||
|  |     { | ||
|  |         *pui32NumBytesRead = i; | ||
|  |     } | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // read_timeout()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // This function will keep writing bytes until it either sends N bytes or runs
 | ||
|  | // into an error.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | static uint32_t | ||
|  | write_timeout(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes, | ||
|  |               uint32_t *pui32NumBytesWritten, uint32_t ui32TimeoutMs) | ||
|  | { | ||
|  |     uint32_t ui32Status, ui32BytesWritten, ui32RemainingBytes, | ||
|  |              ui32TimeSpent, i; | ||
|  | 
 | ||
|  |     i = 0; | ||
|  |     ui32RemainingBytes = ui32NumBytes; | ||
|  |     ui32TimeSpent = 0; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // If we don't have a timeout, just pass this directly to the nonblocking
 | ||
|  |     // call.
 | ||
|  |     //
 | ||
|  |     if ( ui32TimeoutMs == 0 ) | ||
|  |     { | ||
|  |         return write_nonblocking(pHandle, pui8Data, ui32NumBytes, | ||
|  |                                  pui32NumBytesWritten); | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Loop until we're done write. This will either be because we hit a
 | ||
|  |     // timeout, or we sent the right number of bytes. If the caller specified
 | ||
|  |     // "wait forever", then don't check the timeout.
 | ||
|  |     //
 | ||
|  |     while ( ui32RemainingBytes && (ui32TimeSpent < ui32TimeoutMs) ) | ||
|  |     { | ||
|  |         //
 | ||
|  |         // Write as much as we can.
 | ||
|  |         //
 | ||
|  |         ui32BytesWritten = 0; | ||
|  |         ui32Status = write_nonblocking(pHandle, &pui8Data[i], | ||
|  |                                        ui32RemainingBytes, | ||
|  |                                        &ui32BytesWritten); | ||
|  |         //
 | ||
|  |         // Update the tracking variables.
 | ||
|  |         //
 | ||
|  |         i += ui32BytesWritten; | ||
|  |         ui32RemainingBytes -= ui32BytesWritten; | ||
|  | 
 | ||
|  |         if ( ui32Status != AM_HAL_STATUS_SUCCESS ) | ||
|  |         { | ||
|  |             if ( pui32NumBytesWritten ) | ||
|  |             { | ||
|  |                 *pui32NumBytesWritten = i; | ||
|  |             } | ||
|  | 
 | ||
|  |             return ui32Status; | ||
|  |         } | ||
|  | 
 | ||
|  |         //
 | ||
|  |         // Update the timeout.
 | ||
|  |         //
 | ||
|  |         if ( ui32RemainingBytes ) | ||
|  |         { | ||
|  |             delay_us(1); | ||
|  | 
 | ||
|  |             if ( ui32TimeoutMs != AM_HAL_SCARD_WAIT_FOREVER ) | ||
|  |             { | ||
|  |                 ui32TimeSpent++; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     if ( pui32NumBytesWritten ) | ||
|  |     { | ||
|  |         *pui32NumBytesWritten = i; | ||
|  |     } | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // write_timeout()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Send or receive bytes.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_transfer(void *pHandle, const am_hal_scard_transfer_t *pTransfer) | ||
|  | { | ||
|  |     //
 | ||
|  |     // Pick the right function to use based on the transfer structure.
 | ||
|  |     //
 | ||
|  |     if ( pTransfer->ui32Direction == AM_HAL_SCARD_WRITE ) | ||
|  |     { | ||
|  |         return write_timeout(pHandle, | ||
|  |                              pTransfer->pui8Data, | ||
|  |                              pTransfer->ui32NumBytes, | ||
|  |                              pTransfer->pui32BytesTransferred, | ||
|  |                              pTransfer->ui32TimeoutMs); | ||
|  |     } | ||
|  |     else if ( pTransfer->ui32Direction == AM_HAL_SCARD_READ ) | ||
|  |     { | ||
|  |         return read_timeout(pHandle, | ||
|  |                             pTransfer->pui8Data, | ||
|  |                             pTransfer->ui32NumBytes, | ||
|  |                             pTransfer->pui32BytesTransferred, | ||
|  |                             pTransfer->ui32TimeoutMs); | ||
|  |     } | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_INVALID_OPERATION; | ||
|  | } // am_hal_scard_transfer()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Wait for all of the traffic in the TX pipeline to be sent.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_tx_flush(void *pHandle) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // If we have a TX queue, we should wait for it to empty.
 | ||
|  |     //
 | ||
|  |     if ( pState->bEnableTxQueue ) | ||
|  |     { | ||
|  |         while ( am_hal_queue_data_left(&(pState->sTxQueue)) ) | ||
|  |         { | ||
|  |             ONE_BIT_DELAY(pState); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Wait for the IDLE bit to go high.
 | ||
|  |     //
 | ||
|  |     while ( SCARDn(ui32Module)->SR1_b.IDLE != 1 ) | ||
|  |     { | ||
|  |         ONE_BIT_DELAY(pState); | ||
|  |     } | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_tx_flush()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Interrupt service
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_interrupt_service(void *pHandle, uint32_t ui32Status, uint32_t *pui32ScardTxIdle) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  |     uint32_t ui32ErrorStatus; | ||
|  | 
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( !AM_HAL_SCARD_CHK_HANDLE(pHandle) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to see if we have filled the Rx FIFO past the configured limit, or
 | ||
|  |     // if we have an 'old' character or two sitting in the FIFO.
 | ||
|  |     //
 | ||
|  |     if ( (ui32Status & (SCARD_SR_TBERBF_Msk | SCARD_SR_FHF_Msk | SCARD_SR_FNE_Msk) ) && | ||
|  |          pState->bEnableRxQueue) | ||
|  |     { | ||
|  |         ui32ErrorStatus = rx_queue_update(pHandle); | ||
|  |         RETURN_ON_ERROR(ui32ErrorStatus); | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Check to see if our TX buffer has been recently emptied. If so, we
 | ||
|  |     // should refill it from the TX ring buffer.
 | ||
|  |     //
 | ||
|  |     if ( (ui32Status & SCARD_SR_TBERBF_Msk) && pState->bEnableTxQueue ) | ||
|  |     { | ||
|  |         ui32ErrorStatus = tx_queue_update(pHandle); | ||
|  |         RETURN_ON_ERROR(ui32ErrorStatus); | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // If this pointer is null, we can just return success now. There is no
 | ||
|  |     // need to figure out if the SCC is idle.
 | ||
|  |     //
 | ||
|  |     if ( pui32ScardTxIdle == 0 ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_SUCCESS; | ||
|  |     } | ||
|  | 
 | ||
|  |     if ( SCARDn(ui32Module)->SR1_b.IDLE == 1 ) | ||
|  |     { | ||
|  |         *pui32ScardTxIdle = true; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         *pui32ScardTxIdle = false; | ||
|  |     } | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Interrupt enable.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_interrupt_enable(void *pHandle, uint32_t ui32Index, uint32_t ui32IntMask) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  | 
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( (!AM_HAL_SCARD_CHK_HANDLE(pHandle)) || (ui32Index > 1) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     if ( 0 == ui32Index ) | ||
|  |     { | ||
|  |         SCARDn(ui32Module)->IER |= ui32IntMask; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         SCARDn(ui32Module)->IER1 |= ui32IntMask; | ||
|  |     } | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_interrupt_enable()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Interrupt disable.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_interrupt_disable(void *pHandle, uint32_t ui32Index, uint32_t ui32IntMask) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  | 
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( (!AM_HAL_SCARD_CHK_HANDLE(pHandle)) || (ui32Index > 1) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     if ( 0 == ui32Index ) | ||
|  |     { | ||
|  |         SCARDn(ui32Module)->IER &= ~ui32IntMask; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         SCARDn(ui32Module)->IER1 &= ~ui32IntMask; | ||
|  |     } | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_interrupt_disable()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Interrupt clear.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_interrupt_clear(void *pHandle, uint32_t ui32Index, uint32_t ui32IntMask) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  | 
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( (!AM_HAL_SCARD_CHK_HANDLE(pHandle)) || (ui32Index > 1) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     if ( 0 == ui32Index ) | ||
|  |     { | ||
|  |         SCARDn(ui32Module)->SR = ui32IntMask; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         SCARDn(ui32Module)->SR1 = ui32IntMask; | ||
|  |     } | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_interrupt_clear()
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | // Returns the interrupt status.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_interrupt_status_get(void *pHandle, uint32_t ui32Index, uint32_t *pui32Status) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pState = (am_hal_scard_state_t *) pHandle; | ||
|  |     uint32_t ui32Module = pState->ui32Module; | ||
|  | 
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( !AM_HAL_SCARD_CHK_HANDLE(pHandle) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // If requested, only return the interrupts that are enabled.
 | ||
|  |     //
 | ||
|  |     *pui32Status = ui32Index ? SCARDn(ui32Module)->SR1 : SCARDn(ui32Module)->SR; | ||
|  | 
 | ||
|  |     return AM_HAL_STATUS_SUCCESS; | ||
|  | } // am_hal_scard_interrupt_status_get()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | //*****************************************************************************
 | ||
|  | //
 | ||
|  | //! @brief SCARD control function
 | ||
|  | //!
 | ||
|  | //! @param handle       - handle for the SCARD.
 | ||
|  | //! @param eReq         - device specific special request code.
 | ||
|  | //! @param pArgs        - pointer to the request specific arguments.
 | ||
|  | //!
 | ||
|  | //! This function allows advanced settings
 | ||
|  | //!
 | ||
|  | //! @return status      - generic or interface specific status.
 | ||
|  | //
 | ||
|  | //*****************************************************************************
 | ||
|  | uint32_t | ||
|  | am_hal_scard_control(void *pHandle, am_hal_scard_request_e eReq, void *pArgs) | ||
|  | { | ||
|  |     am_hal_scard_state_t *pSCCState = (am_hal_scard_state_t*)pHandle; | ||
|  |     uint32_t status = AM_HAL_STATUS_SUCCESS; | ||
|  | 
 | ||
|  | #ifndef AM_HAL_DISABLE_API_VALIDATION
 | ||
|  |     if ( !AM_HAL_SCARD_CHK_HANDLE(pHandle) ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_HANDLE; | ||
|  |     } | ||
|  | 
 | ||
|  |     //
 | ||
|  |     // Validate the parameters
 | ||
|  |     //
 | ||
|  |     if ( eReq >= AM_HAL_SCARD_REQ_MAX ) | ||
|  |     { | ||
|  |         return AM_HAL_STATUS_INVALID_ARG; | ||
|  |     } | ||
|  | #endif // AM_HAL_DISABLE_API_VALIDATION
 | ||
|  | 
 | ||
|  |     uint32_t ui32Module = pSCCState->ui32Module; | ||
|  |     switch (eReq) | ||
|  |     { | ||
|  |         case AM_HAL_SCARD_REQ_ACTIVATE: | ||
|  |             { | ||
|  |                 uint16_t etu; | ||
|  |                 etu = ((SCARDn(ui32Module)->BPRH & SCARD_BPRH_BPRH_Msk) << 8); | ||
|  |                 etu = etu | SCARDn(ui32Module)->BPRL; | ||
|  |                 etu = (SCARD_RST_LOW_TIME / etu) + 1; | ||
|  | 
 | ||
|  |                 config_etucounter(ui32Module, etu); | ||
|  |                 SCARD_WHILE_TIMEOUT_MS(!SCARDn(ui32Module)->SR1_b.ECNTOVER, 1000, AM_HAL_SCARD_STATUS_BUS_ERROR); | ||
|  |                 SCARDn(ui32Module)->SR1_b.ECNTOVER = 1; | ||
|  |                 SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->UCR_b.RSTIN = 1); | ||
|  |             } | ||
|  |             break; | ||
|  |         case AM_HAL_SCARD_REQ_DEACTIVATE: | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->UCR_b.RSTIN = 0); | ||
|  |             break; | ||
|  |         case AM_HAL_SCARD_REQ_BAUDRATE: | ||
|  |             if ( pArgs ) | ||
|  |             { | ||
|  |                 config_baudrate(pHandle, *(uint32_t*)pArgs); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 status = AM_HAL_STATUS_INVALID_ARG; | ||
|  |             } | ||
|  |             break; | ||
|  |         case AM_HAL_SCARD_REQ_CARD_FORMAT: | ||
|  |             if ( pArgs ) | ||
|  |             { | ||
|  |                 config_cardformat(ui32Module, *(uint32_t*)pArgs); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 status = AM_HAL_STATUS_INVALID_ARG; | ||
|  |             } | ||
|  |             break; | ||
|  |         case AM_HAL_SCARD_REQ_PARITY: | ||
|  |             if ( pArgs ) | ||
|  |             { | ||
|  |                 config_parity(ui32Module, *(uint32_t*)pArgs); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 status = AM_HAL_STATUS_INVALID_ARG; | ||
|  |             } | ||
|  |             break; | ||
|  |         case AM_HAL_SCARD_REQ_PROTOCOL: | ||
|  |             if ( pArgs ) | ||
|  |             { | ||
|  |                 if ( AM_HAL_STATUS_SUCCESS != config_protocol(ui32Module, *(uint32_t*)pArgs) ) | ||
|  |                 { | ||
|  |                     status = AM_HAL_STATUS_INVALID_ARG; | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 status = AM_HAL_STATUS_INVALID_ARG; | ||
|  |             } | ||
|  |             break; | ||
|  |         case AM_HAL_SCARD_REQ_GUARDTIME: | ||
|  |             if ( pArgs ) | ||
|  |             { | ||
|  |                 SCARDn(ui32Module)->GTR = *(uint32_t*)pArgs; | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 status = AM_HAL_STATUS_INVALID_ARG; | ||
|  |             } | ||
|  |             break; | ||
|  |         case AM_HAL_SCARD_REQ_CLK_START: | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->UCR_b.CST = 0); | ||
|  |             break; | ||
|  |         case AM_HAL_SCARD_REQ_CLK_STOP: | ||
|  |             SCARD_SYNC_OPER(ui32Module, SCARDn(ui32Module)->UCR_b.CST = 1); | ||
|  |             break; | ||
|  |         default: | ||
|  |             status = AM_HAL_STATUS_INVALID_ARG; | ||
|  |     } | ||
|  | 
 | ||
|  |     return status; | ||
|  | } | ||
|  | 
 | ||
|  | 
 |