mirror of
https://github.com/STMicroelectronics/stm32-mw-usb-device.git
synced 2026-02-08 12:08:06 -05:00
474 lines
13 KiB
C
474 lines
13 KiB
C
/**
|
|
******************************************************************************
|
|
* @file usbd_ccid_sc_if_template.c
|
|
* @author MCD Application Team
|
|
* @brief SmartCard Interface file
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2021 STMicroelectronics.
|
|
* All rights reserved.
|
|
*
|
|
* This software is licensed under terms that can be found in the LICENSE file
|
|
* in the root directory of this software component.
|
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "usbd_ccid_sc_if_template.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
/* Private variables ---------------------------------------------------------*/
|
|
/* State Machine for the SmartCard Interface */
|
|
static SC_State SCState = SC_POWER_OFF;
|
|
|
|
/* APDU Transport Structures */
|
|
SC_ADPU_CommandsTypeDef SC_ADPU;
|
|
SC_ADPU_ResponseTypeDef SC_Response;
|
|
SC_Param_t SC_Param;
|
|
Protocol_01_DataTypeDef ProtocolData;
|
|
|
|
/* Extern variables ----------------------------------------------------------*/
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
static void SC_SaveVoltage(uint8_t voltage);
|
|
static void SC_Itf_UpdateParams(void);
|
|
|
|
/* Private functions ---------------------------------------------------------*/
|
|
/**
|
|
* @brief SC_Itf_IccPowerOn Manages the Warm and Cold Reset
|
|
and get the Answer to Reset from ICC
|
|
* @param voltage: required by host
|
|
* @retval None
|
|
*/
|
|
void SC_Itf_IccPowerOn(uint8_t voltage)
|
|
{
|
|
SCState = SC_POWER_ON;
|
|
SC_ADPU.Header.CLA = 0x00U;
|
|
SC_ADPU.Header.INS = SC_GET_A2R;
|
|
SC_ADPU.Header.P1 = 0x00U;
|
|
SC_ADPU.Header.P2 = 0x00U;
|
|
SC_ADPU.Body.LC = 0x00U;
|
|
|
|
/* Power ON the card */
|
|
SC_PowerCmd(SC_ENABLED);
|
|
|
|
/* Configure the Voltage, Even if IO is still not configured */
|
|
SC_VoltageConfig(voltage);
|
|
|
|
while ((SCState != SC_ACTIVE_ON_T0) && (SCState != SC_ACTIVE_ON_T1)
|
|
&& (SCState != SC_NO_INIT))
|
|
{
|
|
/* If Either The Card has become Active or Become De-Active */
|
|
SC_Handler(&SCState, &SC_ADPU, &SC_Response);
|
|
}
|
|
|
|
if ((SCState == SC_ACTIVE_ON_T0) || (SCState == SC_ACTIVE_ON_T1))
|
|
{
|
|
SC_Itf_UpdateParams();
|
|
/* Apply the Procedure Type Selection (PTS) */
|
|
SC_PTSConfig();
|
|
|
|
/* Save Voltage for Future use */
|
|
SC_SaveVoltage(voltage);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_Itf_IccPowerOff Power OFF the card
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void SC_Itf_IccPowerOff(void)
|
|
{
|
|
SC_PowerCmd(SC_DISABLED);
|
|
SC_SetState(SC_POWER_OFF);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize the parameters structures to the default value
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void SC_Itf_InitParams(void)
|
|
{
|
|
/*
|
|
FI, the reference to a clock rate conversion factor
|
|
over the bits b8 to b5
|
|
- DI, the reference to a baud rate adjustment factor
|
|
over the bits b4 to bl
|
|
*/
|
|
SC_Param.SC_A2R_FiDi = DEFAULT_FIDI;
|
|
SC_Param.SC_hostFiDi = DEFAULT_FIDI;
|
|
|
|
ProtocolData.bmFindexDindex = DEFAULT_FIDI;
|
|
|
|
/* Placeholder, Ignored */
|
|
/* 0 = Direct, first byte of the ICC ATR data. */
|
|
ProtocolData.bmTCCKST0 = DEFAULT_T01CONVCHECKSUM;
|
|
|
|
/* Extra GuardTime = 0 etu */
|
|
ProtocolData.bGuardTimeT0 = DEFAULT_EXTRA_GUARDTIME;
|
|
ProtocolData.bWaitingIntegerT0 = DEFAULT_WAITINGINTEGER;
|
|
ProtocolData.bClockStop = 0U; /* Stopping the Clock is not allowed */
|
|
|
|
/*T=1 protocol */
|
|
ProtocolData.bIfsc = DEFAULT_IFSC;
|
|
ProtocolData.bNad = DEFAULT_NAD;
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Save the A2R Parameters for further usage
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void SC_Itf_UpdateParams(void)
|
|
{
|
|
/*
|
|
FI, the reference to a clock rate conversion factor
|
|
over the bits b8 to b5
|
|
DI, the reference to a baud rate adjustment factor
|
|
over the bits b4 to bl
|
|
*/
|
|
SC_Param.SC_A2R_FiDi = SC_A2R.T[0].InterfaceByte[0].Value;
|
|
SC_Param.SC_hostFiDi = SC_A2R.T[0].InterfaceByte[0].Value;
|
|
|
|
ProtocolData.bmFindexDindex = SC_A2R.T[0].InterfaceByte[0].Value;
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_Itf_SetParams
|
|
* Set the parameters for CCID/USART interface
|
|
* @param pPtr: pointer to buffer containing the
|
|
* parameters to be set in USART
|
|
* @param T_01: type of protocol, T=1 or T=0
|
|
* @retval status value
|
|
*/
|
|
uint8_t SC_Itf_SetParams(Protocol_01_DataTypeDef *pPtr, uint8_t T_01)
|
|
{
|
|
/* uint16_t guardTime; */ /* Keep it 16b for handling 8b additions */
|
|
uint32_t fi_new;
|
|
uint32_t di_new;
|
|
Protocol_01_DataTypeDef New_DataStructure;
|
|
fi_new = pPtr->bmFindexDindex;
|
|
di_new = pPtr->bmFindexDindex;
|
|
|
|
New_DataStructure.bmTCCKST0 = pPtr->bmTCCKST0;
|
|
|
|
New_DataStructure.bGuardTimeT0 = pPtr->bGuardTimeT0;
|
|
New_DataStructure.bWaitingIntegerT0 = pPtr->bWaitingIntegerT0;
|
|
New_DataStructure.bClockStop = pPtr->bClockStop;
|
|
if (T_01 == 0x01U)
|
|
{
|
|
New_DataStructure.bIfsc = pPtr->bIfsc;
|
|
New_DataStructure.bNad = pPtr->bNad;
|
|
}
|
|
else
|
|
{
|
|
New_DataStructure.bIfsc = 0x00U;
|
|
New_DataStructure.bNad = 0x00U;
|
|
}
|
|
|
|
/* Check for the FIDI Value set by Host */
|
|
di_new &= (uint8_t)0x0F;
|
|
if (SC_GetDTableValue(di_new) == 0U)
|
|
{
|
|
return SLOTERROR_BAD_FIDI;
|
|
}
|
|
|
|
fi_new >>= 4U;
|
|
fi_new &= 0x0FU;
|
|
|
|
if (SC_GetDTableValue(fi_new) == 0U)
|
|
{
|
|
return SLOTERROR_BAD_FIDI;
|
|
}
|
|
|
|
if ((T_01 == 0x00U)
|
|
&& (New_DataStructure.bmTCCKST0 != 0x00U)
|
|
&& (New_DataStructure.bmTCCKST0 != 0x02U))
|
|
{
|
|
return SLOTERROR_BAD_T01CONVCHECKSUM;
|
|
}
|
|
|
|
if ((T_01 == 0x01U)
|
|
&& (New_DataStructure.bmTCCKST0 != 0x10U)
|
|
&& (New_DataStructure.bmTCCKST0 != 0x11U)
|
|
&& (New_DataStructure.bmTCCKST0 != 0x12U)
|
|
&& (New_DataStructure.bmTCCKST0 != 0x13U))
|
|
{
|
|
return SLOTERROR_BAD_T01CONVCHECKSUM;
|
|
}
|
|
|
|
if ((New_DataStructure.bWaitingIntegerT0 >= 0xA0U)
|
|
&& ((New_DataStructure.bmTCCKST0 & 0x10U) == 0x10U))
|
|
{
|
|
return SLOTERROR_BAD_WAITINGINTEGER;
|
|
}
|
|
if ((New_DataStructure.bClockStop != 0x00U)
|
|
&& (New_DataStructure.bClockStop != 0x03U))
|
|
{
|
|
return SLOTERROR_BAD_CLOCKSTOP;
|
|
}
|
|
if (New_DataStructure.bNad != 0x00U)
|
|
{
|
|
return SLOTERROR_BAD_NAD;
|
|
}
|
|
/* Put Total GuardTime in USART Settings */
|
|
/* USART_SetGuardTime(SC_USART, (uint8_t)(guardTime + DEFAULT_EXTRA_GUARDTIME)); */
|
|
|
|
/* Save Extra GuardTime Value */
|
|
ProtocolData.bGuardTimeT0 = New_DataStructure.bGuardTimeT0;
|
|
ProtocolData.bmTCCKST0 = New_DataStructure.bmTCCKST0;
|
|
ProtocolData.bWaitingIntegerT0 = New_DataStructure.bWaitingIntegerT0;
|
|
ProtocolData.bClockStop = New_DataStructure.bClockStop;
|
|
ProtocolData.bIfsc = New_DataStructure.bIfsc;
|
|
ProtocolData.bNad = New_DataStructure.bNad;
|
|
|
|
/* Save New bmFindexDindex */
|
|
SC_Param.SC_hostFiDi = pPtr->bmFindexDindex;
|
|
SC_PTSConfig();
|
|
|
|
ProtocolData.bmFindexDindex = pPtr->bmFindexDindex;
|
|
|
|
return SLOT_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_Itf_Escape function from the host
|
|
* This is user implementable
|
|
* @param ptrEscape: pointer to buffer containing the Escape data
|
|
* @param escapeLen: length of escaped data
|
|
* @param responseBuff: pointer containing escape buffer response
|
|
* @param responseLen: length of escape response buffer
|
|
* @retval status value
|
|
*/
|
|
uint8_t SC_Itf_Escape(uint8_t *ptrEscape, uint32_t escapeLen,
|
|
uint8_t *responseBuff, uint32_t *responseLen)
|
|
{
|
|
UNUSED(ptrEscape);
|
|
UNUSED(escapeLen);
|
|
UNUSED(responseBuff);
|
|
UNUSED(responseLen);
|
|
|
|
/* Manufacturer specific implementation ... */
|
|
/*
|
|
uint32_t idx;
|
|
uint8_t *pResBuff = responseBuff;
|
|
uint8_t *pEscape = ptrEscape;
|
|
|
|
for(idx = 0; idx < escapeLen; idx++)
|
|
{
|
|
*pResBuff = *pEscape;
|
|
pResBuff++;
|
|
pEscape++;
|
|
}
|
|
|
|
*responseLen = escapeLen;
|
|
*/
|
|
return SLOT_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_Itf_SetClock function to define Clock Status request from the host.
|
|
* This is user implementable
|
|
* @param bClockCommand: Clock status from the host
|
|
* @retval status value
|
|
*/
|
|
uint8_t SC_Itf_SetClock(uint8_t bClockCommand)
|
|
{
|
|
/* bClockCommand
|
|
00h restarts Clock
|
|
01h Stops Clock in the state shown in the bClockStop
|
|
field of the PC_to_RDR_SetParameters command
|
|
and RDR_to_PC_Parameters message.*/
|
|
|
|
if (bClockCommand == 0U)
|
|
{
|
|
/* 00h restarts Clock : Since Clock is always running, PASS this command */
|
|
return SLOT_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
if (bClockCommand == 1U)
|
|
{
|
|
return SLOTERROR_BAD_CLOCKCOMMAND;
|
|
}
|
|
}
|
|
|
|
return SLOTERROR_CMD_NOT_SUPPORTED;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_Itf_XferBlock function from the host.
|
|
* This is user implementable
|
|
* @param ptrBlock : Pointer containing the data from host
|
|
* @param blockLen : length of block data for the data transfer
|
|
* @param expectedLen: expected length of data transfer
|
|
* @param CCID_BulkIn_Data: Pointer containing the CCID Bulk In Data Structure
|
|
* @retval status value
|
|
*/
|
|
uint8_t SC_Itf_XferBlock(uint8_t *ptrBlock, uint32_t blockLen, uint16_t expectedLen,
|
|
USBD_CCID_BulkIn_DataTypeDef *CCID_BulkIn_Data)
|
|
{
|
|
uint8_t ErrorCode = SLOT_NO_ERROR;
|
|
UNUSED(CCID_BulkIn_Data);
|
|
UNUSED(expectedLen);
|
|
UNUSED(blockLen);
|
|
UNUSED(ptrBlock);
|
|
|
|
if (ProtocolNUM_OUT == 0x00U)
|
|
{
|
|
/* Add your code here */
|
|
}
|
|
|
|
if (ProtocolNUM_OUT == 0x01U)
|
|
{
|
|
/* Add your code here */
|
|
}
|
|
|
|
if (ErrorCode != SLOT_NO_ERROR)
|
|
{
|
|
return ErrorCode;
|
|
}
|
|
|
|
return ErrorCode;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief SC_Itf_T0Apdu
|
|
Class Specific Request from the host to provide supported data rates
|
|
* This is Optional function & user implementable
|
|
* @param bmChanges : value specifying which parameter is valid in
|
|
* command among next bClassGetResponse, bClassEnvelope
|
|
* @param bClassGetResponse : Value to force the class byte of the
|
|
* header in a Get Response command.
|
|
* @param bClassEnvelope : Value to force the class byte of the header
|
|
* in a Envelope command.
|
|
* @retval status value
|
|
*/
|
|
uint8_t SC_Itf_T0Apdu(uint8_t bmChanges, uint8_t bClassGetResponse,
|
|
uint8_t bClassEnvelope)
|
|
{
|
|
UNUSED(bClassEnvelope);
|
|
UNUSED(bClassGetResponse);
|
|
|
|
/* User have to fill the pbuf with the GetDataRates data buffer */
|
|
|
|
if (bmChanges == 0U)
|
|
{
|
|
/* Bit cleared indicates that the associated field is not significant and
|
|
that default behaviour defined in CCID class descriptor is selected */
|
|
return SLOT_NO_ERROR;
|
|
}
|
|
|
|
return SLOTERROR_CMD_NOT_SUPPORTED;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_Itf_Mechanical
|
|
Mechanical Function being requested by Host
|
|
* This is Optional function & user implementable
|
|
* @param bFunction : value corresponds to the mechanical function
|
|
* being requested by host
|
|
* @retval status value
|
|
*/
|
|
uint8_t SC_Itf_Mechanical(uint8_t bFunction)
|
|
{
|
|
UNUSED(bFunction);
|
|
|
|
return SLOTERROR_CMD_NOT_SUPPORTED;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_Itf_SetDataRateAndClockFrequency
|
|
* Set the Clock and data Rate of the Interface
|
|
* This is Optional function & user implementable
|
|
* @param dwClockFrequency : value of clock in kHz requested by host
|
|
* @param dwDataRate : value of data rate requested by host
|
|
* @retval status value
|
|
*/
|
|
uint8_t SC_Itf_SetDataRateAndClockFrequency(uint32_t dwClockFrequency,
|
|
uint32_t dwDataRate)
|
|
{
|
|
/* User have to fill the pbuf with the GetDataRates data buffer */
|
|
|
|
if ((dwDataRate == USBD_CCID_DEFAULT_DATA_RATE) &&
|
|
(dwClockFrequency == USBD_CCID_DEFAULT_CLOCK_FREQ))
|
|
{
|
|
return SLOT_NO_ERROR;
|
|
}
|
|
|
|
return SLOTERROR_CMD_NOT_SUPPORTED;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_Itf_Secure
|
|
* Process the Secure command
|
|
* This is Optional function & user implementable
|
|
* @param dwLength : length of data from the host
|
|
* @param bBWI : Block Waiting Timeout sent by host
|
|
* @param wLevelParameter : Parameters sent by host
|
|
* @param pbuf : buffer containing the data
|
|
* @param returnLen : Length of data expected to return
|
|
* @retval status value
|
|
*/
|
|
uint8_t SC_Itf_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
|
|
uint8_t *pbuf, uint32_t *returnLen)
|
|
{
|
|
UNUSED(pbuf);
|
|
UNUSED(wLevelParameter);
|
|
UNUSED(bBWI);
|
|
UNUSED(dwLength);
|
|
*returnLen = 0U;
|
|
|
|
return SLOTERROR_CMD_NOT_SUPPORTED;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_SaveVoltage
|
|
Saves the voltage value to be saved for further usage
|
|
* @param voltage: voltage value to be saved for further usage
|
|
* @retval None
|
|
*/
|
|
static void SC_SaveVoltage(uint8_t voltage)
|
|
{
|
|
SC_Param.voltage = voltage;
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Provides the value of SCState variable
|
|
* @param None
|
|
* @retval uint8_t SCState
|
|
*/
|
|
uint8_t SC_GetState(void)
|
|
{
|
|
return (uint8_t)SCState;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the value of SCState variable to Off
|
|
* @param scState: value of SCState to be updated
|
|
* @retval None
|
|
*/
|
|
void SC_SetState(SC_State scState)
|
|
{
|
|
SCState = scState;
|
|
|
|
return;
|
|
}
|