mirror of
https://github.com/STMicroelectronics/stm32-mw-usb-device.git
synced 2026-02-08 12:08:06 -05:00
483 lines
12 KiB
C
483 lines
12 KiB
C
/**
|
|
******************************************************************************
|
|
* @file usbd_ccid_smartcard_template.c
|
|
* @author MCD Application Team
|
|
* @brief This file provides all the Smartcard firmware functions.
|
|
******************************************************************************
|
|
* @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.
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/** @addtogroup usbd_ccid_Smartcard
|
|
* @{
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "usbd_ccid_smartcard_template.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
/* Private variables ---------------------------------------------------------*/
|
|
/* Directories & Files ID */
|
|
/*The following Directories & Files ID can take any of following Values and can
|
|
be used in the smartcard application */
|
|
/*
|
|
const uint8_t MasterRoot[2] = {0x3F, 0x00};
|
|
const uint8_t GSMDir[2] = {0x7F, 0x20};
|
|
const uint8_t ICCID[2] = {0x2F, 0xE2};
|
|
const uint8_t IMSI[2] = {0x6F, 0x07};
|
|
|
|
__IO uint8_t ICCID_Content[10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
uint32_t CHV1Status = 0U;
|
|
|
|
uint8_t CHV1[8] = {'0', '0', '0', '0', '0', '0', '0', '0'};
|
|
__IO uint8_t IMSI_Content[9] = {0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
*/
|
|
|
|
/* F Table: Clock Rate Conversion Table from ISO/IEC 7816-3 */
|
|
/* static uint32_t F_Table[16] = {372, 372, 558, 744, 1116, 1488, 1860, 0, 0, 512, 768,
|
|
1024, 1536, 2048, 0, 0
|
|
}; */
|
|
|
|
|
|
/* D Table: Baud Rate Adjustment Factor Table from ISO/IEC 7816-3 */
|
|
static uint32_t D_Table[16] = {0, 1, 2, 4, 8, 16, 32, 64, 12, 20, 0, 0, 0, 0, 0, 0};
|
|
|
|
/* Global variables definition and initialization ----------------------------*/
|
|
SC_ATR SC_A2R;
|
|
uint8_t SC_ATR_Table[40];
|
|
uint8_t ProtocolNUM_OUT;
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
static void SC_Init(void);
|
|
static void SC_DeInit(void);
|
|
static void SC_AnswerReq(SC_State *SC_state, uint8_t *card, uint8_t length); /* Ask ATR */
|
|
static uint8_t SC_decode_Answer2reset(uint8_t *card); /* Decode ATR */
|
|
static void SC_SendData(SC_ADPU_Commands *SCADPU, SC_ADPU_Response *SC_ResponseStatus);
|
|
/* static void SC_Reset(GPIO_PinState ResetState); */
|
|
|
|
/* Private functions ---------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Handles all Smartcard states and serves to send and receive all
|
|
* communication data between Smartcard and reader.
|
|
* @param SCState: pointer to an SC_State enumeration that will contain the
|
|
* Smartcard state.
|
|
* @param SC_ADPU: pointer to an SC_ADPU_Commands structure that will be initialized.
|
|
* @param SC_Response: pointer to a SC_ADPU_Response structure which will be initialized.
|
|
* @retval None
|
|
*/
|
|
void SC_Handler(SC_State *SCState, SC_ADPU_Commands *SC_ADPU, SC_ADPU_Response *SC_Response)
|
|
{
|
|
uint32_t i, j;
|
|
|
|
switch (*SCState)
|
|
{
|
|
case SC_POWER_ON:
|
|
if (SC_ADPU->Header.INS == SC_GET_A2R)
|
|
{
|
|
/* Smartcard initialization */
|
|
SC_Init();
|
|
|
|
/* Reset Data from SC buffer */
|
|
for (i = 0U; i < 40U; i++)
|
|
{
|
|
SC_ATR_Table[i] = 0;
|
|
}
|
|
|
|
/* Reset SC_A2R Structure */
|
|
SC_A2R.TS = 0U;
|
|
SC_A2R.T0 = 0U;
|
|
|
|
for (i = 0U; i < MAX_PROTOCOLLEVEL; i++)
|
|
{
|
|
for (j = 0U; j < MAX_INTERFACEBYTE; j++)
|
|
{
|
|
SC_A2R.T[i].InterfaceByte[j].Status = 0U;
|
|
SC_A2R.T[i].InterfaceByte[j].Value = 0U;
|
|
}
|
|
}
|
|
|
|
for (i = 0U; i < HIST_LENGTH; i++)
|
|
{
|
|
SC_A2R.H[i] = 0U;
|
|
}
|
|
|
|
SC_A2R.Tlength = 0U;
|
|
SC_A2R.Hlength = 0U;
|
|
|
|
/* Next State */
|
|
*SCState = SC_RESET_LOW;
|
|
}
|
|
break;
|
|
|
|
case SC_RESET_LOW:
|
|
if (SC_ADPU->Header.INS == SC_GET_A2R)
|
|
{
|
|
/* If card is detected then Power ON, Card Reset and wait for an answer) */
|
|
if (SC_Detect() != 0U)
|
|
{
|
|
while (((*SCState) != SC_POWER_OFF) && ((*SCState) != SC_ACTIVE))
|
|
{
|
|
SC_AnswerReq(SCState, &SC_ATR_Table[0], 40U); /* Check for answer to reset */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*SCState) = SC_POWER_OFF;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SC_ACTIVE:
|
|
if (SC_ADPU->Header.INS == SC_GET_A2R)
|
|
{
|
|
uint8_t protocol = SC_decode_Answer2reset(&SC_ATR_Table[0]);
|
|
if (protocol == T0_PROTOCOL)
|
|
{
|
|
(*SCState) = SC_ACTIVE_ON_T0;
|
|
ProtocolNUM_OUT = T0_PROTOCOL;
|
|
}
|
|
else if (protocol == T1_PROTOCOL)
|
|
{
|
|
(*SCState) = SC_ACTIVE_ON_T1;
|
|
ProtocolNUM_OUT = T1_PROTOCOL;
|
|
}
|
|
else
|
|
{
|
|
(*SCState) = SC_POWER_OFF;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SC_ACTIVE_ON_T0:
|
|
/* process commands other than ATR */
|
|
SC_SendData(SC_ADPU, SC_Response);
|
|
break;
|
|
|
|
case SC_ACTIVE_ON_T1:
|
|
/* process commands other than ATR */
|
|
SC_SendData(SC_ADPU, SC_Response);
|
|
break;
|
|
|
|
case SC_POWER_OFF:
|
|
SC_DeInit(); /* Disable Smartcard interface */
|
|
break;
|
|
|
|
default:
|
|
(*SCState) = SC_POWER_OFF;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Enables or disables the power to the Smartcard.
|
|
* @param NewState: new state of the Smartcard power supply.
|
|
* This parameter can be: SC_ENABLED or SC_DISABLED.
|
|
* @retval None
|
|
*/
|
|
void SC_PowerCmd(SCPowerState NewState)
|
|
{
|
|
UNUSED(NewState);
|
|
/* enable or disable smartcard pin */
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Sets or clears the Smartcard reset pin.
|
|
* @param ResetState: this parameter specifies the state of the Smartcard
|
|
* reset pin. BitVal must be one of the BitAction enum values:
|
|
* @arg Bit_RESET: to clear the port pin.
|
|
* @arg Bit_SET: to set the port pin.
|
|
* @retval None
|
|
*/
|
|
/* static void SC_Reset(GPIO_PinState ResetState)
|
|
{
|
|
UNUSED(ResetState);
|
|
|
|
return;
|
|
}
|
|
*/
|
|
|
|
|
|
/**
|
|
* @brief Resends the byte that failed to be received (by the Smartcard) correctly.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
|
|
void SC_ParityErrorHandler(void)
|
|
{
|
|
/* Add your code here */
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Configures the IO speed (BaudRate) communication.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
|
|
void SC_PTSConfig(void)
|
|
{
|
|
/* Add your code here */
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Manages the Smartcard transport layer: send APDU commands and receives
|
|
* the APDU response.
|
|
* @param SC_ADPU: pointer to a SC_ADPU_Commands structure which will be initialized.
|
|
* @param SC_Response: pointer to a SC_ADPU_Response structure which will be initialized.
|
|
* @retval None
|
|
*/
|
|
static void SC_SendData(SC_ADPU_Commands *SCADPU, SC_ADPU_Response *SC_ResponseStatus)
|
|
{
|
|
uint8_t i;
|
|
uint8_t SC_Command[5];
|
|
uint8_t SC_DATA[LC_MAX];
|
|
|
|
UNUSED(SCADPU);
|
|
|
|
/* Reset response buffer */
|
|
for (i = 0U; i < LC_MAX; i++)
|
|
{
|
|
SC_ResponseStatus->Data[i] = 0U;
|
|
SC_DATA[i] = 0U;
|
|
}
|
|
|
|
/* User to add code here */
|
|
|
|
/* send command to ICC and get response status */
|
|
USBD_CCID_If_fops.Send_Process((uint8_t *)&SC_Command, (uint8_t *)&SC_DATA);
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief SC_AnswerReq
|
|
Requests the reset answer from card.
|
|
* @param SC_state: pointer to an SC_State enumeration that will contain the Smartcard state.
|
|
* @param atr_buffer: pointer to a buffer which will contain the card ATR.
|
|
* @param length: maximum ATR length
|
|
* @retval None
|
|
*/
|
|
static void SC_AnswerReq(SC_State *SC_state, uint8_t *atr_buffer, uint8_t length)
|
|
{
|
|
UNUSED(length);
|
|
UNUSED(atr_buffer);
|
|
|
|
/* to be implemented by USER */
|
|
switch (*SC_state)
|
|
{
|
|
case SC_RESET_LOW:
|
|
/* Check response with reset low */
|
|
(*SC_state) = SC_ACTIVE;
|
|
break;
|
|
|
|
case SC_ACTIVE:
|
|
break;
|
|
case SC_RESET_HIGH:
|
|
/* Check response with reset high */
|
|
|
|
break;
|
|
|
|
case SC_POWER_OFF:
|
|
/* Close Connection if no answer received */
|
|
|
|
break;
|
|
|
|
default:
|
|
(*SC_state) = SC_RESET_LOW;
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief SC_decode_Answer2reset
|
|
Decodes the Answer to reset received from card.
|
|
* @param card: pointer to the buffer containing the card ATR.
|
|
* @retval None
|
|
*/
|
|
static uint8_t SC_decode_Answer2reset(uint8_t *card)
|
|
{
|
|
uint32_t i, flag = 0U, protocol;
|
|
uint8_t index = 0U, level = 0U;
|
|
|
|
/******************************TS/T0 Decode************************************/
|
|
index++;
|
|
SC_A2R.TS = card[index]; /* Initial character */
|
|
|
|
index++;
|
|
SC_A2R.T0 = card[index]; /* Format character */
|
|
|
|
/*************************Historical Table Length Decode***********************/
|
|
SC_A2R.Hlength = SC_A2R.T0 & 0x0FU;
|
|
|
|
/******************************Protocol Level(1) Decode************************/
|
|
/* Check TD(1) if present */
|
|
if ((SC_A2R.T0 & 0x80U) == 0x80U)
|
|
{
|
|
flag = 1U;
|
|
}
|
|
|
|
/* Each bits in the T0 high nibble(b8 to b5) equal to 1 indicates the presence
|
|
of a further interface byte */
|
|
for (i = 0U; i < 4U; i++)
|
|
{
|
|
if ((((SC_A2R.T0 & 0xF0U) >> (4U + i)) & 0x1U) != 0U)
|
|
{
|
|
SC_A2R.T[level].InterfaceByte[i].Status = 1U;
|
|
index++;
|
|
SC_A2R.T[level].InterfaceByte[i].Value = card[index];
|
|
SC_A2R.Tlength++;
|
|
}
|
|
}
|
|
|
|
/*****************************T Decode*****************************************/
|
|
if (SC_A2R.T[level].InterfaceByte[3].Status == 1U)
|
|
{
|
|
/* Only the protocol(parameter T) present in TD(1) is detected
|
|
if two or more values of parameter T are present in TD(1), TD(2)..., so the
|
|
firmware should be updated to support them */
|
|
protocol = (uint8_t)(SC_A2R.T[level].InterfaceByte[SC_INTERFACEBYTE_TD].Value & 0x0FU);
|
|
}
|
|
else
|
|
{
|
|
protocol = 0U;
|
|
}
|
|
|
|
/* Protocol Level Increment */
|
|
/******************************Protocol Level(n>1) Decode**********************/
|
|
while (flag != 0U)
|
|
{
|
|
if ((SC_A2R.T[level].InterfaceByte[SC_INTERFACEBYTE_TD].Value & 0x80U) == 0x80U)
|
|
{
|
|
flag = 1U;
|
|
}
|
|
else
|
|
{
|
|
flag = 0U;
|
|
}
|
|
/* Each bits in the high nibble(b8 to b5) for the TD(i) equal to 1 indicates
|
|
the presence of a further interface byte */
|
|
for (i = 0U; i < 4U; i++)
|
|
{
|
|
if ((((SC_A2R.T[level].InterfaceByte[SC_INTERFACEBYTE_TD].Value & 0xF0U) >> (4U + i)) & 0x1U) != 0U)
|
|
{
|
|
SC_A2R.T[level + 1U].InterfaceByte[i].Status = 1U;
|
|
index++;
|
|
SC_A2R.T[level + 1U].InterfaceByte[i].Value = card[index];
|
|
SC_A2R.Tlength++;
|
|
}
|
|
}
|
|
level++;
|
|
}
|
|
|
|
for (i = 0U; i < SC_A2R.Hlength; i++)
|
|
{
|
|
SC_A2R.H[i] = card[i + 2U + SC_A2R.Tlength];
|
|
}
|
|
/*************************************TCK Decode*******************************/
|
|
SC_A2R.TCK = card[SC_A2R.Hlength + 2U + SC_A2R.Tlength];
|
|
|
|
return (uint8_t)protocol;
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes all peripheral used for Smartcard interface.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void SC_Init(void)
|
|
{
|
|
/*
|
|
Add your initialization code here
|
|
*/
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Deinitializes all resources used by the Smartcard interface.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void SC_DeInit(void)
|
|
{
|
|
/*
|
|
Add your deinitialization code here
|
|
*/
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Configures the card power voltage.
|
|
* @param SC_Voltage: specifies the card power voltage.
|
|
* This parameter can be one of the following values:
|
|
* @arg SC_VOLTAGE_5V: 5V cards.
|
|
* @arg SC_VOLTAGE_3V: 3V cards.
|
|
* @retval None
|
|
*/
|
|
void SC_VoltageConfig(uint32_t SC_Voltage)
|
|
{
|
|
UNUSED(SC_Voltage);
|
|
/* Add your code here */
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Configures GPIO hardware resources used for Samrtcard.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void SC_IOConfig(void)
|
|
{
|
|
/* Add your code here */
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Detects whether the Smartcard is present or not.
|
|
* @param None.
|
|
* @retval 1 - Smartcard inserted
|
|
* 0 - Smartcard not inserted
|
|
*/
|
|
uint8_t SC_Detect(void)
|
|
{
|
|
uint8_t PIN_State = 0U;
|
|
|
|
/* Add your code here */
|
|
|
|
return PIN_State;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the Right Value from the D_Table Index
|
|
* @param idx : Index to Read from the Table
|
|
* @retval Value read from the Table
|
|
*/
|
|
uint32_t SC_GetDTableValue(uint32_t idx)
|
|
{
|
|
return D_Table[idx];
|
|
}
|