mirror of
https://github.com/STMicroelectronics/stm32-mw-usb-device.git
synced 2026-02-08 20:18:07 -05:00
Release v2.9.0
This commit is contained in:
968
Class/CCID/Src/usbd_ccid.c
Normal file
968
Class/CCID/Src/usbd_ccid.c
Normal file
@@ -0,0 +1,968 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file usbd_ccid.c
|
||||
* @author MCD Application Team
|
||||
* @brief This file provides the high layer firmware functions to manage
|
||||
* all the functionalities of the USB CCID Class:
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
* @verbatim
|
||||
*
|
||||
* ===================================================================
|
||||
* CCID Class Driver Description
|
||||
* ===================================================================
|
||||
* This module manages the Specification for Integrated Circuit(s)
|
||||
* Cards Interface Revision 1.1
|
||||
* This driver implements the following aspects of the specification:
|
||||
* - Device descriptor management
|
||||
* - Configuration descriptor management
|
||||
* - Enumeration as CCID device with 2 data endpoints (IN and OUT) and 1 command endpoint (IN)
|
||||
* and enumeration for each implemented memory interface
|
||||
* - Bulk OUT/IN data Transfers
|
||||
* - Requests management
|
||||
*
|
||||
* @endverbatim
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "usbd_ccid.h"
|
||||
#include "usbd_ccid_cmd.h"
|
||||
#include "usbd_ctlreq.h"
|
||||
/** @addtogroup STM32_USB_DEVICE_LIBRARY
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CCID
|
||||
* @brief usbd core module
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CCID_Private_TypesDefinitions
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/** @defgroup USBD_CCID_Private_Defines
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/** @defgroup USBD_CCID_Private_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/** @defgroup USBD_CCID_Private_FunctionPrototypes
|
||||
* @{
|
||||
*/
|
||||
static uint8_t USBD_CCID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
||||
static uint8_t USBD_CCID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
||||
static uint8_t USBD_CCID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
|
||||
static uint8_t USBD_CCID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
|
||||
static uint8_t USBD_CCID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
|
||||
static uint8_t USBD_CCID_DispatchCommand(USBD_HandleTypeDef *pdev);
|
||||
static uint8_t USBD_CCID_ReceiveCmdHeader(USBD_HandleTypeDef *pdev,
|
||||
uint8_t *pDst, uint16_t u8length);
|
||||
|
||||
static uint8_t *USBD_CCID_GetHSCfgDesc(uint16_t *length);
|
||||
static uint8_t *USBD_CCID_GetFSCfgDesc(uint16_t *length);
|
||||
static uint8_t *USBD_CCID_GetOtherSpeedCfgDesc(uint16_t *length);
|
||||
static uint8_t *USBD_CCID_GetDeviceQualifierDescriptor(uint16_t *length);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CCID_Private_Variables
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/* CCID interface class callbacks structure */
|
||||
USBD_ClassTypeDef USBD_CCID =
|
||||
{
|
||||
USBD_CCID_Init,
|
||||
USBD_CCID_DeInit,
|
||||
USBD_CCID_Setup,
|
||||
NULL, /*EP0_TxSent*/
|
||||
NULL, /*EP0_RxReady*/
|
||||
USBD_CCID_DataIn,
|
||||
USBD_CCID_DataOut,
|
||||
NULL, /*SOF */
|
||||
NULL, /*ISOIn*/
|
||||
NULL, /*ISOOut*/
|
||||
USBD_CCID_GetHSCfgDesc,
|
||||
USBD_CCID_GetFSCfgDesc,
|
||||
USBD_CCID_GetOtherSpeedCfgDesc,
|
||||
USBD_CCID_GetDeviceQualifierDescriptor,
|
||||
};
|
||||
|
||||
/* USB CCID device Configuration Descriptor */
|
||||
__ALIGN_BEGIN static uint8_t USBD_CCID_CfgHSDesc[USB_CCID_CONFIG_DESC_SIZ] __ALIGN_END =
|
||||
{
|
||||
/* Configuration Descriptor */
|
||||
0x09, /* bLength: Configuration Descriptor size */
|
||||
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
||||
USB_CCID_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */
|
||||
0x00,
|
||||
0x01, /* bNumInterfaces: 1 interface */
|
||||
0x01, /* bConfigurationValue: */
|
||||
0x00, /* iConfiguration: */
|
||||
#if (USBD_SELF_POWERED == 1U)
|
||||
0xC0, /* bmAttributes: Bus Powered according to user configuration */
|
||||
#else
|
||||
0x80, /* bmAttributes: Bus Powered according to user configuration */
|
||||
#endif
|
||||
USBD_MAX_POWER, /* MaxPower (mA) */
|
||||
|
||||
/******************** CCID **** interface ********************/
|
||||
CCID_INTERFACE_DESC_SIZE, /* bLength: Interface Descriptor size */
|
||||
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x03, /* bNumEndpoints: 3 endpoints used */
|
||||
USB_DEVICE_CLASS_CCID, /* bInterfaceClass: user's interface for CCID */
|
||||
0x00, /* bInterfaceSubClass : No subclass, can be changed but no description in USB 2.0 Spec */
|
||||
0x00, /* nInterfaceProtocol : None */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/******************* CCID class descriptor ********************/
|
||||
CCID_CLASS_DESC_SIZE, /* bLength: CCID Descriptor size */
|
||||
CCID_DESC_TYPE, /* bDescriptorType: Functional Descriptor type. */
|
||||
0x10, /* bcdCCID(LSB): CCID Class Spec release number (1.1) */
|
||||
0x01, /* bcdCCID(MSB) */
|
||||
|
||||
0x00, /* bMaxSlotIndex :highest available slot on this device */
|
||||
CCID_VOLTAGE_SUPP, /* bVoltageSupport: bVoltageSupport: 5v, 3v and 1.8v */
|
||||
LOBYTE(USBD_CCID_PROTOCOL), /* dwProtocols: supports T=0 and T=1 */
|
||||
HIBYTE(USBD_CCID_PROTOCOL),
|
||||
0x00,
|
||||
0x00,
|
||||
LOBYTE(USBD_CCID_DEFAULT_CLOCK_FREQ), /* dwDefaultClock: 3.6Mhz */
|
||||
HIBYTE(USBD_CCID_DEFAULT_CLOCK_FREQ),
|
||||
0x00,
|
||||
0x00,
|
||||
LOBYTE(USBD_CCID_MAX_CLOCK_FREQ), /* dwMaximumClock */
|
||||
HIBYTE(USBD_CCID_MAX_CLOCK_FREQ),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00, /* bNumClockSupported */
|
||||
LOBYTE(USBD_CCID_DEFAULT_DATA_RATE), /* dwDataRate: 9677 bps */
|
||||
HIBYTE(USBD_CCID_DEFAULT_DATA_RATE),
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
LOBYTE(USBD_CCID_MAX_DATA_RATE), /* dwMaxDataRate: */
|
||||
HIBYTE(USBD_CCID_MAX_DATA_RATE),
|
||||
0x00,
|
||||
0x00,
|
||||
0x35, /* bNumDataRatesSupported */
|
||||
|
||||
LOBYTE(USBD_CCID_MAX_INF_FIELD_SIZE), /* dwMaxIFSD: maximum IFSD supported for T=1 */
|
||||
HIBYTE(USBD_CCID_MAX_INF_FIELD_SIZE),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00, 0x00, 0x00, 0x00, /* dwSynchProtocols */
|
||||
0x00, 0x00, 0x00, 0x00, /* dwMechanical: no special characteristics */
|
||||
|
||||
0xBA, 0x04, EXCHANGE_LEVEL_FEATURE, 0x00, /* dwFeatures */
|
||||
LOBYTE(CCID_MAX_BLOCK_SIZE_HEADER), /* dwMaxCCIDMessageLength: Maximum block size + header*/
|
||||
HIBYTE(CCID_MAX_BLOCK_SIZE_HEADER),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00, /* bClassGetResponse*/
|
||||
0x00, /* bClassEnvelope */
|
||||
0x00, 0x00, /* wLcdLayout : 0000h no LCD. */
|
||||
0x03, /* bPINSupport : PIN verification and PIN modification */
|
||||
0x01, /* bMaxCCIDBusySlots */
|
||||
|
||||
/******************** CCID Endpoints ********************/
|
||||
CCID_ENDPOINT_DESC_SIZE, /* Endpoint descriptor length = 7 */
|
||||
USB_DESC_TYPE_ENDPOINT, /* Endpoint descriptor type */
|
||||
CCID_IN_EP, /* Endpoint address (IN, address 1) */
|
||||
USBD_EP_TYPE_BULK, /* Bulk endpoint type */
|
||||
|
||||
LOBYTE(CCID_DATA_HS_MAX_PACKET_SIZE),
|
||||
HIBYTE(CCID_DATA_HS_MAX_PACKET_SIZE),
|
||||
0x00, /* Polling interval in milliseconds */
|
||||
CCID_ENDPOINT_DESC_SIZE, /* Endpoint descriptor length = 7 */
|
||||
USB_DESC_TYPE_ENDPOINT, /* Endpoint descriptor type */
|
||||
CCID_OUT_EP, /* Endpoint address (OUT, address 1) */
|
||||
USBD_EP_TYPE_BULK, /* Bulk endpoint type */
|
||||
|
||||
LOBYTE(CCID_DATA_HS_MAX_PACKET_SIZE),
|
||||
HIBYTE(CCID_DATA_HS_MAX_PACKET_SIZE),
|
||||
0x00, /* Polling interval in milliseconds */
|
||||
CCID_ENDPOINT_DESC_SIZE, /* bLength: Endpoint Descriptor size */
|
||||
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType:*/
|
||||
CCID_CMD_EP, /* bEndpointAddress: Endpoint Address (IN) */
|
||||
USBD_EP_TYPE_INTR, /* bmAttributes: Interrupt endpoint */
|
||||
LOBYTE(CCID_CMD_PACKET_SIZE),
|
||||
HIBYTE(CCID_CMD_PACKET_SIZE),
|
||||
CCID_CMD_HS_BINTERVAL /* Polling interval in milliseconds */
|
||||
};
|
||||
|
||||
/* USB CCID device Configuration Descriptor */
|
||||
__ALIGN_BEGIN static uint8_t USBD_CCID_CfgFSDesc[USB_CCID_CONFIG_DESC_SIZ] __ALIGN_END =
|
||||
{
|
||||
/* Configuration Descriptor */
|
||||
0x09, /* bLength: Configuration Descriptor size */
|
||||
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
||||
USB_CCID_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */
|
||||
0x00,
|
||||
0x01, /* bNumInterfaces: 1 interface */
|
||||
0x01, /* bConfigurationValue: */
|
||||
0x00, /* iConfiguration: */
|
||||
#if (USBD_SELF_POWERED == 1U)
|
||||
0xC0, /* bmAttributes: Bus Powered according to user configuration */
|
||||
#else
|
||||
0x80, /* bmAttributes: Bus Powered according to user configuration */
|
||||
#endif
|
||||
USBD_MAX_POWER, /* MaxPower (mA) */
|
||||
|
||||
/******************** CCID **** interface ********************/
|
||||
CCID_INTERFACE_DESC_SIZE, /* bLength: Interface Descriptor size */
|
||||
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x03, /* bNumEndpoints: 3 endpoints used */
|
||||
USB_DEVICE_CLASS_CCID, /* bInterfaceClass: user's interface for CCID */
|
||||
0x00, /* bInterfaceSubClass : No subclass, can be changed but no description in USB 2.0 Spec */
|
||||
0x00, /* nInterfaceProtocol : None */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/******************* CCID class descriptor ********************/
|
||||
CCID_CLASS_DESC_SIZE, /* bLength: CCID Descriptor size */
|
||||
CCID_DESC_TYPE, /* bDescriptorType: Functional Descriptor type. */
|
||||
0x10, /* bcdCCID(LSB): CCID Class Spec release number (1.1) */
|
||||
0x01, /* bcdCCID(MSB) */
|
||||
|
||||
0x00, /* bMaxSlotIndex :highest available slot on this device */
|
||||
CCID_VOLTAGE_SUPP, /* bVoltageSupport: bVoltageSupport: 5v, 3v and 1.8v */
|
||||
LOBYTE(USBD_CCID_PROTOCOL), /* dwProtocols: supports T=0 and T=1 */
|
||||
HIBYTE(USBD_CCID_PROTOCOL),
|
||||
0x00,
|
||||
0x00,
|
||||
LOBYTE(USBD_CCID_DEFAULT_CLOCK_FREQ), /* dwDefaultClock: 3.6Mhz */
|
||||
HIBYTE(USBD_CCID_DEFAULT_CLOCK_FREQ),
|
||||
0x00,
|
||||
0x00,
|
||||
LOBYTE(USBD_CCID_MAX_CLOCK_FREQ), /* dwMaximumClock */
|
||||
HIBYTE(USBD_CCID_MAX_CLOCK_FREQ),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00, /* bNumClockSupported */
|
||||
LOBYTE(USBD_CCID_DEFAULT_DATA_RATE), /* dwDataRate: 9677 bps */
|
||||
HIBYTE(USBD_CCID_DEFAULT_DATA_RATE),
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
LOBYTE(USBD_CCID_MAX_DATA_RATE), /* dwMaxDataRate */
|
||||
HIBYTE(USBD_CCID_MAX_DATA_RATE),
|
||||
0x00,
|
||||
0x00,
|
||||
0x35, /* bNumDataRatesSupported */
|
||||
|
||||
LOBYTE(USBD_CCID_MAX_INF_FIELD_SIZE), /* dwMaxIFSD: maximum IFSD supported for T=1 */
|
||||
HIBYTE(USBD_CCID_MAX_INF_FIELD_SIZE),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00, 0x00, 0x00, 0x00, /* dwSynchProtocols */
|
||||
0x00, 0x00, 0x00, 0x00, /* dwMechanical: no special characteristics */
|
||||
|
||||
0xBA, 0x04, EXCHANGE_LEVEL_FEATURE, 0x00, /* dwFeatures */
|
||||
LOBYTE(CCID_MAX_BLOCK_SIZE_HEADER), /* dwMaxCCIDMessageLength: Maximum block size + header*/
|
||||
HIBYTE(CCID_MAX_BLOCK_SIZE_HEADER),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00, /* bClassGetResponse*/
|
||||
0x00, /* bClassEnvelope */
|
||||
0x00, 0x00, /* wLcdLayout : 0000h no LCD. */
|
||||
0x03, /* bPINSupport : PIN verification and PIN modification */
|
||||
0x01, /* bMaxCCIDBusySlots */
|
||||
|
||||
/******************** CCID Endpoints ********************/
|
||||
CCID_ENDPOINT_DESC_SIZE, /* Endpoint descriptor length = 7 */
|
||||
USB_DESC_TYPE_ENDPOINT, /* Endpoint descriptor type */
|
||||
CCID_IN_EP, /* Endpoint address (IN, address 1) */
|
||||
USBD_EP_TYPE_BULK, /* Bulk endpoint type */
|
||||
|
||||
LOBYTE(CCID_DATA_FS_MAX_PACKET_SIZE),
|
||||
HIBYTE(CCID_DATA_FS_MAX_PACKET_SIZE),
|
||||
0x00, /* Polling interval in milliseconds */
|
||||
CCID_ENDPOINT_DESC_SIZE, /* Endpoint descriptor length = 7 */
|
||||
USB_DESC_TYPE_ENDPOINT, /* Endpoint descriptor type */
|
||||
CCID_OUT_EP, /* Endpoint address (OUT, address 1) */
|
||||
USBD_EP_TYPE_BULK, /* Bulk endpoint type */
|
||||
|
||||
LOBYTE(CCID_DATA_FS_MAX_PACKET_SIZE),
|
||||
HIBYTE(CCID_DATA_FS_MAX_PACKET_SIZE),
|
||||
0x00, /* Polling interval in milliseconds */
|
||||
CCID_ENDPOINT_DESC_SIZE, /* bLength: Endpoint Descriptor size */
|
||||
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType:*/
|
||||
CCID_CMD_EP, /* bEndpointAddress: Endpoint Address (IN) */
|
||||
USBD_EP_TYPE_INTR, /* bmAttributes: Interrupt endpoint */
|
||||
LOBYTE(CCID_CMD_PACKET_SIZE),
|
||||
HIBYTE(CCID_CMD_PACKET_SIZE),
|
||||
CCID_CMD_FS_BINTERVAL /* Polling interval in milliseconds */
|
||||
};
|
||||
|
||||
/* USB Standard Device Descriptor */
|
||||
__ALIGN_BEGIN static uint8_t USBD_CCID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
|
||||
{
|
||||
USB_LEN_DEV_QUALIFIER_DESC,
|
||||
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x01,
|
||||
0x00,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CCID_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_Init
|
||||
* Initialize the CCID interface
|
||||
* @param pdev: device instance
|
||||
* @param cfgidx: Configuration index
|
||||
* @retval status
|
||||
*/
|
||||
static uint8_t USBD_CCID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid;
|
||||
UNUSED(cfgidx);
|
||||
|
||||
/* Allocate CCID structure */
|
||||
hccid = (USBD_CCID_HandleTypeDef *)USBD_malloc(sizeof(USBD_CCID_HandleTypeDef));
|
||||
|
||||
if (hccid == NULL)
|
||||
{
|
||||
pdev->pClassData = NULL;
|
||||
return (uint8_t)USBD_EMEM;
|
||||
}
|
||||
|
||||
pdev->pClassData = (void *)hccid;
|
||||
|
||||
/* Init the CCID parameters into a state where it can receive a new command message */
|
||||
hccid->USBD_CCID_Param.bAbortRequestFlag = 0U;
|
||||
hccid->USBD_CCID_Param.bSeq = 0U;
|
||||
hccid->USBD_CCID_Param.bSlot = 0U;
|
||||
hccid->MaxPcktLen = (pdev->dev_speed == USBD_SPEED_HIGH) ? \
|
||||
CCID_DATA_HS_MAX_PACKET_SIZE : CCID_DATA_FS_MAX_PACKET_SIZE;
|
||||
|
||||
/* Open EP IN */
|
||||
(void)USBD_LL_OpenEP(pdev, CCID_IN_EP, USBD_EP_TYPE_BULK, (uint16_t)hccid->MaxPcktLen);
|
||||
pdev->ep_in[CCID_IN_EP & 0xFU].is_used = 1U;
|
||||
|
||||
/* Open EP OUT */
|
||||
(void)USBD_LL_OpenEP(pdev, CCID_OUT_EP, USBD_EP_TYPE_BULK, (uint16_t)hccid->MaxPcktLen);
|
||||
pdev->ep_out[CCID_OUT_EP & 0xFU].is_used = 1U;
|
||||
|
||||
/* Open INTR EP IN */
|
||||
(void)USBD_LL_OpenEP(pdev, CCID_CMD_EP,
|
||||
USBD_EP_TYPE_INTR, CCID_CMD_PACKET_SIZE);
|
||||
pdev->ep_in[CCID_CMD_EP & 0xFU].is_used = 1U;
|
||||
|
||||
/* Init physical Interface components */
|
||||
((USBD_CCID_ItfTypeDef *)pdev->pUserData)->Init(pdev);
|
||||
|
||||
/* Prepare Out endpoint to receive next packet */
|
||||
(void)USBD_LL_PrepareReceive(pdev, CCID_OUT_EP,
|
||||
hccid->data, hccid->MaxPcktLen);
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_DeInit
|
||||
* DeInitialize the CCID layer
|
||||
* @param pdev: device instance
|
||||
* @param cfgidx: Configuration index
|
||||
* @retval status
|
||||
*/
|
||||
static uint8_t USBD_CCID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
||||
{
|
||||
UNUSED(cfgidx);
|
||||
|
||||
/* Close EP IN */
|
||||
(void)USBD_LL_CloseEP(pdev, CCID_IN_EP);
|
||||
pdev->ep_in[CCID_IN_EP & 0xFU].is_used = 0U;
|
||||
|
||||
/* Close EP OUT */
|
||||
(void)USBD_LL_CloseEP(pdev, CCID_OUT_EP);
|
||||
pdev->ep_out[CCID_OUT_EP & 0xFU].is_used = 0U;
|
||||
|
||||
/* Close EP Command */
|
||||
(void)USBD_LL_CloseEP(pdev, CCID_CMD_EP);
|
||||
pdev->ep_in[CCID_CMD_EP & 0xFU].is_used = 0U;
|
||||
|
||||
/* DeInit physical Interface components */
|
||||
if (pdev->pClassData != NULL)
|
||||
{
|
||||
((USBD_CCID_ItfTypeDef *)pdev->pUserData)->DeInit(pdev);
|
||||
(void)USBD_free(pdev->pClassData);
|
||||
pdev->pClassData = NULL;
|
||||
}
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_Setup
|
||||
* Handle the CCID specific requests
|
||||
* @param pdev: instance
|
||||
* @param req: usb requests
|
||||
* @retval status
|
||||
*/
|
||||
static uint8_t USBD_CCID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
USBD_CCID_ItfTypeDef *hCCIDitf = (USBD_CCID_ItfTypeDef *)pdev->pUserData;
|
||||
USBD_StatusTypeDef ret = USBD_OK;
|
||||
uint8_t ifalt = 0U;
|
||||
uint16_t status_info = 0U;
|
||||
uint16_t len;
|
||||
|
||||
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
||||
{
|
||||
/* Class request */
|
||||
case USB_REQ_TYPE_CLASS :
|
||||
if (req->wLength != 0U)
|
||||
{
|
||||
len = MIN(CCID_EP0_BUFF_SIZ, req->wLength);
|
||||
if ((req->bmRequest & 0x80U) != 0U)
|
||||
{
|
||||
hCCIDitf->Control(req->bRequest, hccid->data, &len);
|
||||
(void)USBD_CtlSendData(pdev, hccid->data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)USBD_CtlPrepareRx(pdev, hccid->data, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
len = 0U;
|
||||
hCCIDitf->Control(req->bRequest, (uint8_t *)&req->wValue, &len);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Interface & Endpoint request */
|
||||
case USB_REQ_TYPE_STANDARD:
|
||||
switch (req->bRequest)
|
||||
{
|
||||
case USB_REQ_GET_STATUS:
|
||||
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
||||
{
|
||||
(void)USBD_CtlSendData(pdev, (uint8_t *)&status_info, 2U);
|
||||
}
|
||||
else
|
||||
{
|
||||
USBD_CtlError(pdev, req);
|
||||
ret = USBD_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
||||
{
|
||||
(void)USBD_CtlSendData(pdev, &ifalt, 1U);
|
||||
}
|
||||
else
|
||||
{
|
||||
USBD_CtlError(pdev, req);
|
||||
ret = USBD_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
if (pdev->dev_state != USBD_STATE_CONFIGURED)
|
||||
{
|
||||
USBD_CtlError(pdev, req);
|
||||
ret = USBD_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
break;
|
||||
|
||||
default:
|
||||
USBD_CtlError(pdev, req);
|
||||
ret = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
USBD_CtlError(pdev, req);
|
||||
ret = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return (uint8_t)ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_DataIn
|
||||
* Data sent on non-control IN endpoint
|
||||
* @param pdev: device instance
|
||||
* @param epnum: endpoint number
|
||||
* @retval status
|
||||
*/
|
||||
static uint8_t USBD_CCID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
|
||||
if (epnum == (CCID_IN_EP & 0x7FU))
|
||||
{
|
||||
/* Filter the epnum by masking with 0x7f (mask of IN Direction) */
|
||||
|
||||
/*************** Handle Bulk Transfer IN data completion *****************/
|
||||
|
||||
switch (hccid->blkt_state)
|
||||
{
|
||||
case CCID_STATE_SEND_RESP:
|
||||
|
||||
/* won't wait ack to avoid missing a command */
|
||||
hccid->blkt_state = CCID_STATE_IDLE;
|
||||
|
||||
/* Prepare EP to Receive Cmd */
|
||||
(void)USBD_LL_PrepareReceive(pdev, CCID_OUT_EP,
|
||||
hccid->data, CCID_DATA_FS_MAX_PACKET_SIZE);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (epnum == (CCID_CMD_EP & 0x7FU))
|
||||
{
|
||||
/* Filter the epnum by masking with 0x7f (mask of IN Direction) */
|
||||
|
||||
/*************** Handle Interrupt Transfer IN data completion *****************/
|
||||
|
||||
(void)USBD_CCID_IntMessage(pdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (uint8_t)USBD_FAIL;
|
||||
}
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_DataOut
|
||||
* Data received on non-control Out endpoint
|
||||
* @param pdev: device instance
|
||||
* @param epnum: endpoint number
|
||||
* @retval status
|
||||
*/
|
||||
static uint8_t USBD_CCID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
uint16_t CurrPcktLen;
|
||||
|
||||
if (hccid == NULL)
|
||||
{
|
||||
return (uint8_t)USBD_EMEM;
|
||||
}
|
||||
|
||||
if (epnum == CCID_OUT_EP)
|
||||
{
|
||||
CurrPcktLen = (uint16_t)USBD_GetRxCount(pdev, epnum);
|
||||
|
||||
switch (hccid->blkt_state)
|
||||
{
|
||||
case CCID_STATE_IDLE:
|
||||
|
||||
if (CurrPcktLen >= (uint16_t)CCID_CMD_HEADER_SIZE)
|
||||
{
|
||||
hccid->UsbMessageLength = CurrPcktLen; /* Store for future use */
|
||||
|
||||
/* Fill CCID_BulkOut Data Buffer from USB Buffer */
|
||||
(void)USBD_CCID_ReceiveCmdHeader(pdev, (uint8_t *)&hccid->UsbBlkOutData.bMessageType,
|
||||
(uint16_t)CurrPcktLen);
|
||||
|
||||
/*
|
||||
Refer : 6 CCID Messages
|
||||
The response messages always contain the exact same slot number,
|
||||
and sequence number fields from the header that was contained in
|
||||
the Bulk-OUT command message.
|
||||
*/
|
||||
hccid->UsbBlkInData.bSlot = hccid->UsbBlkOutData.bSlot;
|
||||
hccid->UsbBlkInData.bSeq = hccid->UsbBlkOutData.bSeq;
|
||||
|
||||
if (CurrPcktLen < hccid->MaxPcktLen)
|
||||
{
|
||||
/* Short message, less than the EP Out Size, execute the command,
|
||||
if parameter like dwLength is too big, the appropriate command will
|
||||
give an error */
|
||||
(void)USBD_CCID_DispatchCommand(pdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if length of data to be sent by host is > buffer size */
|
||||
if (hccid->UsbBlkOutData.dwLength > (uint32_t)ABDATA_SIZE)
|
||||
{
|
||||
/* Too long data received.... Error ! */
|
||||
hccid->blkt_state = CCID_STATE_UNCORRECT_LENGTH;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* Expect more data on OUT EP */
|
||||
hccid->blkt_state = CCID_STATE_RECEIVE_DATA;
|
||||
|
||||
/* Prepare EP to Receive next Cmd */
|
||||
(void)USBD_LL_PrepareReceive(pdev, CCID_OUT_EP,
|
||||
hccid->data, hccid->MaxPcktLen);
|
||||
|
||||
} /* if (CurrPcktLen == CCID_DATA_MAX_PACKET_SIZE) ends */
|
||||
} /* if (CurrPcktLen >= CCID_DATA_MAX_PACKET_SIZE) ends */
|
||||
} /* if (CurrPcktLen >= CCID_CMD_HEADER_SIZE) ends */
|
||||
else
|
||||
{
|
||||
if (CurrPcktLen == 0x00U) /* Zero Length Packet Received */
|
||||
{
|
||||
hccid->blkt_state = CCID_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CCID_STATE_RECEIVE_DATA:
|
||||
hccid->UsbMessageLength += CurrPcktLen;
|
||||
|
||||
if (CurrPcktLen < hccid->MaxPcktLen)
|
||||
{
|
||||
/* Short message, less than the EP Out Size, execute the command,
|
||||
if parameter like dwLength is too big, the appropriate command will
|
||||
give an error */
|
||||
|
||||
/* Full command is received, process the Command */
|
||||
(void)USBD_CCID_ReceiveCmdHeader(pdev, (uint8_t *)&hccid->UsbBlkOutData.bMessageType,
|
||||
(uint16_t)CurrPcktLen);
|
||||
|
||||
(void)USBD_CCID_DispatchCommand(pdev);
|
||||
}
|
||||
else if (CurrPcktLen == hccid->MaxPcktLen)
|
||||
{
|
||||
if (hccid->UsbMessageLength < (hccid->UsbBlkOutData.dwLength + (uint32_t)CCID_CMD_HEADER_SIZE))
|
||||
{
|
||||
(void)USBD_CCID_ReceiveCmdHeader(pdev, (uint8_t *)&hccid->UsbBlkOutData.bMessageType,
|
||||
(uint16_t)CurrPcktLen); /* Copy data */
|
||||
|
||||
/* Prepare EP to Receive next Cmd */
|
||||
(void)USBD_LL_PrepareReceive(pdev, CCID_OUT_EP,
|
||||
hccid->data, hccid->MaxPcktLen);
|
||||
}
|
||||
else if (hccid->UsbMessageLength == (hccid->UsbBlkOutData.dwLength + (uint32_t)CCID_CMD_HEADER_SIZE))
|
||||
{
|
||||
/* Full command is received, process the Command */
|
||||
(void)USBD_CCID_ReceiveCmdHeader(pdev, (uint8_t *)&hccid->UsbBlkOutData.bMessageType,
|
||||
(uint16_t)CurrPcktLen);
|
||||
|
||||
(void)USBD_CCID_DispatchCommand(pdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Too long data received.... Error ! */
|
||||
hccid->blkt_state = CCID_STATE_UNCORRECT_LENGTH;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Too long data received.... Error ! */
|
||||
hccid->blkt_state = CCID_STATE_UNCORRECT_LENGTH;
|
||||
}
|
||||
break;
|
||||
|
||||
case CCID_STATE_UNCORRECT_LENGTH:
|
||||
hccid->blkt_state = CCID_STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (uint8_t)USBD_FAIL;
|
||||
}
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_DispatchCommand
|
||||
* Parse the commands and Process command
|
||||
* @param pdev: device instance
|
||||
* @retval status value
|
||||
*/
|
||||
static uint8_t USBD_CCID_DispatchCommand(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
uint8_t errorCode;
|
||||
|
||||
switch (hccid->UsbBlkOutData.bMessageType)
|
||||
{
|
||||
case PC_TO_RDR_ICCPOWERON:
|
||||
errorCode = PC_to_RDR_IccPowerOn(pdev);
|
||||
RDR_to_PC_DataBlock(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_ICCPOWEROFF:
|
||||
errorCode = PC_to_RDR_IccPowerOff(pdev);
|
||||
RDR_to_PC_SlotStatus(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_GETSLOTSTATUS:
|
||||
errorCode = PC_to_RDR_GetSlotStatus(pdev);
|
||||
RDR_to_PC_SlotStatus(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_XFRBLOCK:
|
||||
errorCode = PC_to_RDR_XfrBlock(pdev);
|
||||
RDR_to_PC_DataBlock(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_GETPARAMETERS:
|
||||
errorCode = PC_to_RDR_GetParameters(pdev);
|
||||
RDR_to_PC_Parameters(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_RESETPARAMETERS:
|
||||
errorCode = PC_to_RDR_ResetParameters(pdev);
|
||||
RDR_to_PC_Parameters(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_SETPARAMETERS:
|
||||
errorCode = PC_to_RDR_SetParameters(pdev);
|
||||
RDR_to_PC_Parameters(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_ESCAPE:
|
||||
errorCode = PC_to_RDR_Escape(pdev);
|
||||
RDR_to_PC_Escape(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_ICCCLOCK:
|
||||
errorCode = PC_to_RDR_IccClock(pdev);
|
||||
RDR_to_PC_SlotStatus(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_ABORT:
|
||||
errorCode = PC_to_RDR_Abort(pdev);
|
||||
RDR_to_PC_SlotStatus(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_T0APDU:
|
||||
errorCode = PC_TO_RDR_T0Apdu(pdev);
|
||||
RDR_to_PC_SlotStatus(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_MECHANICAL:
|
||||
errorCode = PC_TO_RDR_Mechanical(pdev);
|
||||
RDR_to_PC_SlotStatus(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
|
||||
errorCode = PC_TO_RDR_SetDataRateAndClockFrequency(pdev);
|
||||
RDR_to_PC_DataRateAndClockFrequency(errorCode, pdev);
|
||||
break;
|
||||
|
||||
case PC_TO_RDR_SECURE:
|
||||
errorCode = PC_TO_RDR_Secure(pdev);
|
||||
RDR_to_PC_DataBlock(errorCode, pdev);
|
||||
break;
|
||||
|
||||
default:
|
||||
RDR_to_PC_SlotStatus(SLOTERROR_CMD_NOT_SUPPORTED, pdev);
|
||||
break;
|
||||
}
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_Transfer_Data_Request
|
||||
* Prepare the request response to be sent to the host
|
||||
* @param pdev: device instance
|
||||
* @param dataPointer: Pointer to the data buffer to send
|
||||
* @param dataLen : number of bytes to send
|
||||
* @retval status value
|
||||
*/
|
||||
uint8_t USBD_CCID_Transfer_Data_Request(USBD_HandleTypeDef *pdev,
|
||||
uint8_t *dataPointer, uint16_t dataLen)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
USBD_CCID_ItfTypeDef *hCCIDitf = (USBD_CCID_ItfTypeDef *)pdev->pUserData;
|
||||
|
||||
UNUSED(dataPointer);
|
||||
|
||||
hccid->blkt_state = CCID_STATE_SEND_RESP;
|
||||
hccid->UsbMessageLength = hccid->UsbBlkInData.dwLength + (uint32_t)dataLen; /* Store for future use */
|
||||
|
||||
/* use the header declared size packet must be well formed */
|
||||
hCCIDitf->Response_SendData(pdev, (uint8_t *)&hccid->UsbBlkInData,
|
||||
(uint16_t)MIN(CCID_DATA_FS_MAX_PACKET_SIZE, hccid->UsbMessageLength));
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_ReceiveCmdHeader
|
||||
* Receive the Data from USB BulkOut Buffer to Pointer
|
||||
* @param pdev: device instance
|
||||
* @param pDst: destination address to copy the buffer
|
||||
* @param u8length: length of data to copy
|
||||
* @retval status
|
||||
*/
|
||||
static uint8_t USBD_CCID_ReceiveCmdHeader(USBD_HandleTypeDef *pdev,
|
||||
uint8_t *pDst, uint16_t u8length)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
uint8_t *pdst = pDst;
|
||||
uint32_t Counter;
|
||||
|
||||
for (Counter = 0U; Counter < u8length; Counter++)
|
||||
{
|
||||
*pdst = hccid->data[Counter];
|
||||
pdst++;
|
||||
}
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_IntMessage
|
||||
* Send the Interrupt-IN data to the host
|
||||
* @param pdev: device instance
|
||||
* @retval None
|
||||
*/
|
||||
uint8_t USBD_CCID_IntMessage(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
|
||||
/* Check if there is change in Smartcard Slot status */
|
||||
if (CCID_IsSlotStatusChange(pdev) != 0U)
|
||||
{
|
||||
/* Check Slot Status is changed. Card is Removed/Fitted */
|
||||
RDR_to_PC_NotifySlotChange(pdev);
|
||||
|
||||
/* Set the Slot status */
|
||||
((USBD_CCID_ItfTypeDef *)pdev->pUserData)->SetSlotStatus(pdev);
|
||||
|
||||
(void)USBD_LL_Transmit(pdev, CCID_CMD_EP, hccid->UsbIntData, 2U);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set the Slot status */
|
||||
((USBD_CCID_ItfTypeDef *)pdev->pUserData)->SetSlotStatus(pdev);
|
||||
}
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_GetHSCfgDesc
|
||||
* Return configuration descriptor
|
||||
* @param length pointer data length
|
||||
* @retval pointer to descriptor buffer
|
||||
*/
|
||||
static uint8_t *USBD_CCID_GetHSCfgDesc(uint16_t *length)
|
||||
{
|
||||
*length = (uint16_t)sizeof(USBD_CCID_CfgHSDesc);
|
||||
return USBD_CCID_CfgHSDesc;
|
||||
}
|
||||
/**
|
||||
* @brief USBD_CCID_GetFSCfgDesc
|
||||
* Return configuration descriptor
|
||||
* @param length : pointer data length
|
||||
* @retval pointer to descriptor buffer
|
||||
*/
|
||||
static uint8_t *USBD_CCID_GetFSCfgDesc(uint16_t *length)
|
||||
{
|
||||
*length = (uint16_t)sizeof(USBD_CCID_CfgFSDesc);
|
||||
return USBD_CCID_CfgFSDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_GetOtherSpeedCfgDesc
|
||||
* Return configuration descriptor
|
||||
* @param length : pointer data length
|
||||
* @retval pointer to descriptor buffer
|
||||
*/
|
||||
static uint8_t *USBD_CCID_GetOtherSpeedCfgDesc(uint16_t *length)
|
||||
{
|
||||
*length = (uint16_t)sizeof(USBD_CCID_CfgFSDesc);
|
||||
return USBD_CCID_CfgFSDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_GetDeviceQualifierDescriptor
|
||||
* return Device Qualifier descriptor
|
||||
* @param length : pointer data length
|
||||
* @retval pointer to descriptor buffer
|
||||
*/
|
||||
static uint8_t *USBD_CCID_GetDeviceQualifierDescriptor(uint16_t *length)
|
||||
{
|
||||
*length = (uint16_t)(sizeof(USBD_CCID_DeviceQualifierDesc));
|
||||
return USBD_CCID_DeviceQualifierDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CCID_RegisterInterface
|
||||
* @param pdev: device instance
|
||||
* @param fops: CD Interface callback
|
||||
* @retval status
|
||||
*/
|
||||
uint8_t USBD_CCID_RegisterInterface(USBD_HandleTypeDef *pdev,
|
||||
USBD_CCID_ItfTypeDef *fops)
|
||||
{
|
||||
if (fops == NULL)
|
||||
{
|
||||
return (uint8_t)USBD_FAIL;
|
||||
}
|
||||
|
||||
pdev->pUserData = fops;
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
1094
Class/CCID/Src/usbd_ccid_cmd.c
Normal file
1094
Class/CCID/Src/usbd_ccid_cmd.c
Normal file
File diff suppressed because it is too large
Load Diff
254
Class/CCID/Src/usbd_ccid_if_template.c
Normal file
254
Class/CCID/Src/usbd_ccid_if_template.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file usbd_ccid_if_template.c
|
||||
* @author MCD Application Team
|
||||
* @brief This file provides all the functions for USB Interface for CCID
|
||||
******************************************************************************
|
||||
* @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.h"
|
||||
#include "usbd_ccid_if_template.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
static REP_Command_t REP_command;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
static uint8_t CCID_Init(USBD_HandleTypeDef *pdev);
|
||||
static uint8_t CCID_DeInit(USBD_HandleTypeDef *pdev);
|
||||
static uint8_t CCID_ControlReq(uint8_t req, uint8_t *pbuf, uint16_t *length);
|
||||
static uint8_t CCID_Response_SendData(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t len);
|
||||
static uint8_t CCID_Send_Process(uint8_t *Command, uint8_t *Data);
|
||||
static uint8_t CCID_Response_Process(void);
|
||||
static uint8_t CCID_SetSlotStatus(USBD_HandleTypeDef *pdev);
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
USBD_CCID_ItfTypeDef USBD_CCID_If_fops =
|
||||
{
|
||||
CCID_Init,
|
||||
CCID_DeInit,
|
||||
CCID_ControlReq,
|
||||
CCID_Response_SendData,
|
||||
CCID_Send_Process,
|
||||
CCID_SetSlotStatus,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief CCID_Init
|
||||
* Initialize the CCID USB Layer
|
||||
* @param pdev: device instance
|
||||
* @retval status value
|
||||
*/
|
||||
uint8_t CCID_Init(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
|
||||
/* CCID Related Initialization */
|
||||
|
||||
hccid->blkt_state = CCID_STATE_IDLE;
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CCID_DeInit
|
||||
* Uninitialize the CCID Machine
|
||||
* @param pdev: device instance
|
||||
* @retval status value
|
||||
*/
|
||||
uint8_t CCID_DeInit(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
|
||||
hccid->blkt_state = CCID_STATE_IDLE;
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CCID_ControlReq
|
||||
* Manage the CCID class requests
|
||||
* @param Cmd: Command code
|
||||
* @param Buf: Buffer containing command data (request parameters)
|
||||
* @param Len: Number of data to be sent (in bytes)
|
||||
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
|
||||
*/
|
||||
static uint8_t CCID_ControlReq(uint8_t req, uint8_t *pbuf, uint16_t *length)
|
||||
{
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)(USBD_Device.pClassData);
|
||||
UNUSED(length);
|
||||
|
||||
switch (req)
|
||||
{
|
||||
case REQUEST_ABORT:
|
||||
/* The wValue field contains the slot number (bSlot) in the low byte
|
||||
and the sequence number (bSeq) in the high byte.*/
|
||||
hccid->slot_nb = ((uint16_t) * pbuf & 0x0fU);
|
||||
hccid->seq_nb = (((uint16_t) * pbuf & 0xf0U) >> 8);
|
||||
|
||||
if (CCID_CmdAbort((uint8_t)hccid->slot_nb, (uint8_t)hccid->seq_nb) != 0U)
|
||||
{
|
||||
/* If error is returned by lower layer :
|
||||
Generally Slot# may not have matched */
|
||||
return (int8_t)USBD_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
case REQUEST_GET_CLOCK_FREQUENCIES:
|
||||
|
||||
/* User have to fill the pbuf with the GetClockFrequency data buffer */
|
||||
|
||||
break;
|
||||
|
||||
case REQUEST_GET_DATA_RATES:
|
||||
|
||||
/* User have to fill the pbuf with the GetDataRates data buffer */
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNUSED(pbuf);
|
||||
|
||||
return ((int8_t)USBD_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CCID_Response_SendData
|
||||
* Send the data on bulk-in EP
|
||||
* @param pdev: device instance
|
||||
* @param buf: pointer to data buffer
|
||||
* @param len: Data Length
|
||||
* @retval status value
|
||||
*/
|
||||
uint8_t CCID_Response_SendData(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
(void)USBD_LL_Transmit(pdev, CCID_IN_EP, buf, len);
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CCID_SEND_Process
|
||||
* @param Command: pointer to a buffer containing command header
|
||||
* @param Data: pointer to a buffer containing data sent from Host
|
||||
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
|
||||
*/
|
||||
static uint8_t CCID_Send_Process(uint8_t *Command, uint8_t *Data)
|
||||
{
|
||||
Command_State_t Command_State = Command_NOT_OK;
|
||||
|
||||
/* Initialize ICC APP header */
|
||||
uint8_t SC_Command[5] = {0};
|
||||
UNUSED(Data);
|
||||
UNUSED(Command_State);
|
||||
UNUSED(SC_Command);
|
||||
|
||||
/* Start SC Demo ---------------------------------------------------------*/
|
||||
switch (Command[1]) /* type of instruction */
|
||||
{
|
||||
case SC_ENABLE:
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
case SC_VERIFY:
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
case SC_READ_BINARY :
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
case SC_CHANGE :
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* check if Command header is OK */
|
||||
(void)CCID_Response_Process(); /* Get ICC response */
|
||||
|
||||
return ((uint8_t)USBD_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CCID_Response_Process
|
||||
* @param None
|
||||
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
|
||||
*/
|
||||
static uint8_t CCID_Response_Process(void)
|
||||
{
|
||||
switch (REP_command)
|
||||
{
|
||||
case REP_OK:
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
case REP_NOT_OK :
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
case REP_NOT_SUPP :
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
case REP_ENABLED :
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
case REP_CHANGE :
|
||||
/* Add your code here */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ((uint8_t)USBD_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CCID_SetSlotStatus
|
||||
* Set Slot Status of the Interrupt Transfer
|
||||
* @param pdev: device instance
|
||||
* @retval status
|
||||
*/
|
||||
uint8_t CCID_SetSlotStatus(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
/* Get the CCID handler pointer */
|
||||
USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassData;
|
||||
|
||||
if ((hccid->SlotStatus.SlotStatus) == 1U) /* Transfer Complete Status
|
||||
of previous Interrupt transfer */
|
||||
{
|
||||
/* Add your code here */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add your code here */
|
||||
}
|
||||
|
||||
return (uint8_t)USBD_OK;
|
||||
}
|
||||
473
Class/CCID/Src/usbd_ccid_sc_if_template.c
Normal file
473
Class/CCID/Src/usbd_ccid_sc_if_template.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @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_Commands SC_ADPU;
|
||||
SC_ADPU_Response 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;
|
||||
}
|
||||
482
Class/CCID/Src/usbd_ccid_smartcard_template.c
Normal file
482
Class/CCID/Src/usbd_ccid_smartcard_template.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @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];
|
||||
}
|
||||
Reference in New Issue
Block a user