mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-16 21:28:33 +03:00
* Fix UTF-8 encoding. This caused the endianness check to fail, which reads all .c and .h files. * Add .checkpatch.conf to skip linting for: firmware/atmel_softpack_libraries Change-Id: Ibb2e42e9b4307275a33e4000c201847a6bd60137
1033 lines
32 KiB
C
1033 lines
32 KiB
C
/* ----------------------------------------------------------------------------
|
|
* ATMEL Microcontroller Software Support
|
|
* ----------------------------------------------------------------------------
|
|
* Copyright (c) 2008, Atmel Corporation
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the disclaimer below.
|
|
*
|
|
* Atmel's name may not be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// \unit
|
|
///
|
|
/// !Purpose
|
|
///
|
|
/// CCID driver
|
|
///
|
|
/// !Usage
|
|
///
|
|
/// Explanation on the usage of the code made available through the header file.
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Headers
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "board.h"
|
|
#include "simtrace.h"
|
|
|
|
#ifdef HAVE_CCID
|
|
|
|
#include <USBDDriver.h>
|
|
#include <USBRequests.h>
|
|
#include <USBDescriptors.h>
|
|
//#include <usb/device/dfu/dfu.h>
|
|
#include <cciddriverdescriptors.h>
|
|
|
|
// FIXME: Remove DFU related stuff
|
|
/* no DFU bootloader is being used */
|
|
#define DFU_NUM_IF 0
|
|
#define DFU_IF_DESCRIPTORS_STRUCT
|
|
#define DFU_IF_DESCRIPTORS
|
|
|
|
#define DFU_NUM_STRINGS 0
|
|
#define DFU_STRING_DESCRIPTORS
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Local definition
|
|
//------------------------------------------------------------------------------
|
|
|
|
/// Constants: IDs: Device product ID.
|
|
//#define CCIDDriverDescriptors_PRODUCTID 0x6129
|
|
#define CCIDDriverDescriptors_PRODUCTID SIMTRACE_PRODUCT_ID
|
|
/// Constants: IDs: Device vendor ID.
|
|
#define CCIDDriverDescriptors_VENDORID ATMEL_VENDOR_ID
|
|
//#define CCIDDriverDescriptors_VENDORID 0x03EB
|
|
/// Constants: IDs: Device release number.
|
|
#define CCIDDriverDescriptors_RELEASE 0x0100
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Types
|
|
//------------------------------------------------------------------------------
|
|
|
|
/// Driver structure for an CCID device
|
|
typedef struct {
|
|
|
|
/// CCID message
|
|
S_ccid_bulk_in_header sCcidMessage;
|
|
/// CCID command
|
|
S_ccid_bulk_out_header sCcidCommand;
|
|
/// Interrupt message answer
|
|
unsigned char BufferINT[4];
|
|
/// Buffer data of message
|
|
unsigned char ProtocolDataStructure[10];
|
|
/// Protocol used
|
|
unsigned char bProtocol;
|
|
/// SlotStatus
|
|
/// Bit 0 = Slot 0 current state
|
|
/// Bit 1 = Slot 0 changed status
|
|
/// Bit 2 = Slot 1 current state
|
|
/// Bit 3 = Slot 1 changed status
|
|
/// Bit 4 = Slot 2 current state
|
|
/// Bit 5 = Slot 2 changed status
|
|
unsigned char SlotStatus;
|
|
|
|
} CCIDDriver;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Local variables
|
|
//------------------------------------------------------------------------------
|
|
|
|
/// Static instance of the CCID device driver.
|
|
static CCIDDriver ccidDriver;
|
|
static CCIDDriverConfigurationDescriptors *configurationDescriptorsFS;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Internal functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Initializes the CCID device driver.
|
|
//------------------------------------------------------------------------------
|
|
void CCIDDriver_Initialize( void )
|
|
{
|
|
configurationDescriptorsFS = (CCIDDriverConfigurationDescriptors *) configurationDescriptorsArr[CFG_NUM_CCID-1];
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Response Pipe, Bulk-IN Messages
|
|
/// Return the Slot Status to the host
|
|
/// Answer to:
|
|
/// PC_to_RDR_IccPowerOff
|
|
/// PC_to_RDR_GetSlotStatus
|
|
/// PC_to_RDR_IccClock
|
|
/// PC_to_RDR_T0APDU
|
|
/// PC_to_RDR_Mechanical
|
|
/// PC_to_RDR_Abort and Class specific ABORT request
|
|
//------------------------------------------------------------------------------
|
|
static void RDRtoPCSlotStatus( void )
|
|
{
|
|
// Header fields settings
|
|
ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
|
|
ccidDriver.sCcidMessage.wLength = 0;
|
|
|
|
if (ccidDriver.SlotStatus == ICC_INSERTED_EVENT) {
|
|
ccidDriver.sCcidMessage.bStatus = 0; /* ICC present and active card */
|
|
} else if (ccidDriver.SlotStatus == ICC_NOT_PRESENT) {
|
|
ccidDriver.sCcidMessage.bStatus = 2; /* No ICC present*/
|
|
} else{
|
|
TRACE_ERROR("Strange bStatus");
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
}
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
// 00h Clock running
|
|
// 01h Clock stopped in state L
|
|
// 02h Clock stopped in state H
|
|
// 03h Clock stopped in an unknown state
|
|
// All other values are Reserved for Future Use.
|
|
ccidDriver.sCcidMessage.bSpecific = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Response Pipe, Bulk-IN Messages
|
|
/// Answer to PC_to_RDR_IccPowerOn
|
|
//------------------------------------------------------------------------------
|
|
static void RDRtoPCDatablock_ATR( void )
|
|
{
|
|
unsigned char i;
|
|
unsigned char Atr[ATR_SIZE_MAX];
|
|
unsigned char length;
|
|
uint32_t status;
|
|
|
|
TRACE_DEBUG(".");
|
|
|
|
status = ISO7816_Datablock_ATR( Atr, &length );
|
|
ISO7816_Decode_ATR( Atr );
|
|
|
|
if (status == 0) {
|
|
TRACE_DEBUG("Timeout occured while reading ATR");
|
|
// FIXME: react properly to timeout..
|
|
// return;
|
|
}
|
|
|
|
// FIXME: More tests? Is bProtocol = Atr[3] ?
|
|
if( length > 5 ) {
|
|
ccidDriver.ProtocolDataStructure[1] = Atr[3]&0x0F; // TD(1)
|
|
ccidDriver.bProtocol = Atr[3]&0x0F; // TD(1)
|
|
TRACE_INFO("Protocol data structure: 0x%x\n\r",
|
|
ccidDriver.ProtocolDataStructure[1]);
|
|
}
|
|
|
|
// S_ccid_protocol_t0
|
|
// bmFindexDindex
|
|
ccidDriver.ProtocolDataStructure[0] = Atr[2]; // TA(1)
|
|
|
|
// bmTCCKST0
|
|
// For T=0 ,B0 - 0b, B7-2 - 000000b
|
|
// B1 - Convention used (b1=0 for direct, b1=1 for inverse)
|
|
|
|
// bGuardTimeT0
|
|
// Extra Guardtime between two characters. Add 0 to 254 etu to the normal
|
|
// guardtime of 12etu. FFh is the same as 00h.
|
|
ccidDriver.ProtocolDataStructure[2] = Atr[4]; // TC(1)
|
|
// AT91C_BASE_US0->US_TTGR = 0; // TC1
|
|
|
|
// bWaitingIntegerT0
|
|
// WI for T=0 used to define WWT
|
|
ccidDriver.ProtocolDataStructure[3] = Atr[7]; // TC(2)
|
|
|
|
// bClockStop
|
|
// ICC Clock Stop Support
|
|
// 00 = Stopping the Clock is not allowed
|
|
// 01 = Stop with Clock signal Low
|
|
// 02 = Stop with Clock signal High
|
|
// 03 = Stop with Clock either High or Low
|
|
ccidDriver.ProtocolDataStructure[4] = 0x00; // 0 to 3
|
|
|
|
// Header fields settings
|
|
ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
|
|
ccidDriver.sCcidMessage.wLength = length; // Size of ATR
|
|
ccidDriver.sCcidMessage.bSizeToSend += length; // Size of ATR
|
|
// bChainParameter: 00 the response APDU begins and ends in this command
|
|
ccidDriver.sCcidMessage.bSpecific = 0;
|
|
|
|
for( i=0; i<length; i++ ) {
|
|
|
|
ccidDriver.sCcidMessage.abData[i] = Atr[i];
|
|
}
|
|
|
|
// Set the slot to an active status
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Response Pipe, Bulk-IN Messages
|
|
/// In other cases, the response message has the following format:
|
|
/// The response data will contain the optional data returned by the ICC,
|
|
/// followed by the 2 byte-size status words SW1-SW2.
|
|
///
|
|
/// Answer to:
|
|
/// PC_to_RDR_XfrBlock
|
|
/// PC_to_RDR_Secure
|
|
//------------------------------------------------------------------------------
|
|
static void RDRtoPCDatablock( void )
|
|
{
|
|
//TRACE_DEBUG(".");
|
|
|
|
// Header fields settings
|
|
ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
|
|
ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
|
|
// bChainParameter: 00 the response APDU begins and ends in this command
|
|
ccidDriver.sCcidMessage.bSpecific = 0;
|
|
|
|
// Set the slot to an active status
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Response Pipe, Bulk-IN Messages
|
|
/// Answer to:
|
|
/// PC_to_RDR_GetParameters
|
|
/// PC_to_RDR_ResetParameters
|
|
/// PC_to_RDR_SetParameters
|
|
//------------------------------------------------------------------------------
|
|
static void RDRtoPCParameters( void )
|
|
{
|
|
unsigned int i;
|
|
|
|
TRACE_DEBUG(".");
|
|
|
|
// Header fields settings
|
|
ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_PARAMETERS;
|
|
|
|
//ccidDriver.sCcidMessage.bStatus = 0;
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
|
|
if( ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO ) {
|
|
|
|
// T=0
|
|
ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t0);
|
|
ccidDriver.sCcidMessage.bSpecific = PROTOCOL_TO;
|
|
}
|
|
else {
|
|
|
|
// T=1
|
|
ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t1);
|
|
ccidDriver.sCcidMessage.bSpecific = PROTOCOL_T1;
|
|
}
|
|
|
|
ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
|
|
|
|
for( i=0; i<ccidDriver.sCcidMessage.wLength; i++ ) {
|
|
ccidDriver.sCcidMessage.abData[i] = ccidDriver.ProtocolDataStructure[i];
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Response Pipe, Bulk-IN Messages
|
|
/// Answer to:
|
|
/// PC_to_RDR_Escape
|
|
//------------------------------------------------------------------------------
|
|
static void RDRtoPCEscape( unsigned char length, unsigned char *data_send_from_CCID )
|
|
{
|
|
unsigned int i;
|
|
|
|
TRACE_DEBUG(".");
|
|
|
|
// Header fields settings
|
|
ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_ESCAPE;
|
|
|
|
ccidDriver.sCcidMessage.wLength = length;
|
|
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
|
|
ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
|
|
|
|
for( i=0; i<length; i++ ) {
|
|
ccidDriver.sCcidMessage.abData[i] = data_send_from_CCID[i];
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Response Pipe, Bulk-IN Messages
|
|
/// Answer to:
|
|
/// PC_to_RDR_SetDataRateAndClockFrequency
|
|
//------------------------------------------------------------------------------
|
|
static void RDRtoPCDataRateAndClockFrequency( unsigned int dwClockFrequency,
|
|
unsigned int dwDataRate )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
// Header fields settings
|
|
ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATARATEANDCLOCKFREQUENCY;
|
|
|
|
ccidDriver.sCcidMessage.wLength = 8;
|
|
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
|
|
ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
|
|
|
|
ccidDriver.sCcidMessage.abData[0] = dwClockFrequency;
|
|
|
|
ccidDriver.sCcidMessage.abData[4] = dwDataRate;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// Power On Command - Cold Reset & Warm Reset
|
|
/// Return the ATR to the host
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRIccPowerOn( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
if( CCID_FEATURES_AUTO_VOLT == (configurationDescriptorsFS->ccid.dwFeatures & CCID_FEATURES_AUTO_VOLT) ) {
|
|
|
|
//bPowerSelect = ccidDriver.sCcidCommand.bSpecific_0;
|
|
ccidDriver.sCcidCommand.bSpecific_0 = VOLTS_AUTO;
|
|
}
|
|
|
|
ISO7816_warm_reset();
|
|
// ISO7816_cold_reset();
|
|
|
|
// for emulation only //JCB
|
|
if ( ccidDriver.sCcidCommand.bSpecific_0 != VOLTS_5_0 ) {
|
|
|
|
TRACE_ERROR("POWER_NOT_SUPPORTED\n\r");
|
|
}
|
|
|
|
else {
|
|
|
|
RDRtoPCDatablock_ATR();
|
|
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// Power Off Command - Set the ICC in an inactive state
|
|
/// Return the slot status to the host
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRIccPowerOff( void )
|
|
{
|
|
unsigned char bStatus;
|
|
|
|
TRACE_DEBUG(".");
|
|
|
|
ISO7816_IccPowerOff();
|
|
|
|
//JCB stub
|
|
bStatus = ICC_BS_PRESENT_NOTACTIVATED;
|
|
|
|
// Set the slot to an inactive status
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
|
|
// if error, see Table 6.1-2 errors
|
|
|
|
// Return the slot status to the host
|
|
RDRtoPCSlotStatus();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// Get slot status
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRGetSlotStatus( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
|
|
// Return the slot status to the host
|
|
RDRtoPCSlotStatus();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// If the command header is valid, an APDU command is received and can be read
|
|
/// by the application
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRXfrBlock( void )
|
|
{
|
|
uint16_t msglen = 0;
|
|
uint32_t ret;
|
|
|
|
TRACE_DEBUG("PCtoRDRXfrBlock\n\r");
|
|
|
|
// Check the block length
|
|
if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) {
|
|
TRACE_DEBUG("Err block/msg len");
|
|
ccidDriver.sCcidMessage.bStatus = 1;
|
|
ccidDriver.sCcidMessage.bError = 0;
|
|
}
|
|
// check bBWI
|
|
else if ( 0 != ccidDriver.sCcidCommand.bSpecific_0 ) {
|
|
|
|
TRACE_ERROR("Bad bBWI\n\r");
|
|
}
|
|
else {
|
|
|
|
// APDU or TPDU
|
|
switch(configurationDescriptorsFS->ccid.dwFeatures
|
|
& (CCID_FEATURES_EXC_TPDU|CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU)) {
|
|
|
|
case CCID_FEATURES_EXC_TPDU:
|
|
if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO) {
|
|
TRACE_DEBUG("APDU cmd: %x %x %x ..", ccidDriver.sCcidCommand.APDU[0], ccidDriver.sCcidCommand.APDU[1],ccidDriver.sCcidCommand.APDU[2] );
|
|
|
|
// Send commande APDU
|
|
ret = ISO7816_XfrBlockTPDU_T0( ccidDriver.sCcidCommand.APDU ,
|
|
ccidDriver.sCcidMessage.abData,
|
|
ccidDriver.sCcidCommand.wLength,
|
|
&msglen );
|
|
if (ret != 0) {
|
|
TRACE_ERROR("APDU could not be sent: (US_CSR = 0x%x)", ret);
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_T1) {
|
|
TRACE_DEBUG("Not supported T=1\n\r");
|
|
}
|
|
else {
|
|
TRACE_DEBUG("Not supported 0x%x\n\r", ccidDriver.ProtocolDataStructure[1]);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CCID_FEATURES_EXC_APDU:
|
|
TRACE_DEBUG("Not supported CCID_FEATURES_EXC_APDU\n\r");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
ccidDriver.sCcidMessage.wLength = msglen;
|
|
TRACE_DEBUG("USB: 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n\r", ccidDriver.sCcidMessage.abData[0],
|
|
ccidDriver.sCcidMessage.abData[1],
|
|
ccidDriver.sCcidMessage.abData[2],
|
|
ccidDriver.sCcidMessage.abData[3],
|
|
ccidDriver.sCcidMessage.abData[4] );
|
|
RDRtoPCDatablock();
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// return parameters by the command: RDR_to_PC_Parameters
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRGetParameters( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
// We support only one slot
|
|
|
|
// bmIccStatus
|
|
if( ISO7816_StatusReset() ) {
|
|
// 0: An ICC is present and active (power is on and stable, RST is inactive
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
}
|
|
else {
|
|
// 1: An ICC is present and inactive (not activated or shut down by hardware error)
|
|
ccidDriver.sCcidMessage.bStatus = 1;
|
|
}
|
|
|
|
RDRtoPCParameters();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This command resets the slot parameters to their default values
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRResetParameters( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
ccidDriver.SlotStatus = ICC_NOT_PRESENT;
|
|
ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
|
|
|
|
RDRtoPCParameters();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This command is used to change the parameters for a given slot.
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRSetParameters( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
ccidDriver.SlotStatus = ccidDriver.sCcidCommand.bSlot;
|
|
ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
|
|
// Not all feature supported
|
|
|
|
RDRtoPCParameters();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This command allows the CCID manufacturer to define and access extended
|
|
/// features.
|
|
/// Information sent via this command is processed by the CCID control logic.
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDREscape( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
// If needed by the user
|
|
ISO7816_Escape();
|
|
|
|
// stub, return all value send
|
|
RDRtoPCEscape( ccidDriver.sCcidCommand.wLength, ccidDriver.sCcidCommand.APDU);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This command stops or restarts the clock.
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRICCClock( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
if( 0 == ccidDriver.sCcidCommand.bSpecific_0 ) {
|
|
// restarts the clock
|
|
ISO7816_RestartClock();
|
|
}
|
|
else {
|
|
// stop clock in the state shown in the bClockStop field
|
|
ISO7816_StopClock();
|
|
}
|
|
|
|
RDRtoPCSlotStatus( );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This command changes the parameters used to perform the transportation of
|
|
/// APDU messages by the T=0 protocol.
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRtoAPDU( void )
|
|
{
|
|
unsigned char bmChanges;
|
|
unsigned char bClassGetResponse;
|
|
unsigned char bClassEnvelope;
|
|
|
|
TRACE_INFO(".");
|
|
|
|
if( configurationDescriptorsFS->ccid.dwFeatures == (CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU) ) {
|
|
|
|
bmChanges = ccidDriver.sCcidCommand.bSpecific_0;
|
|
bClassGetResponse = ccidDriver.sCcidCommand.bSpecific_1;
|
|
bClassEnvelope = ccidDriver.sCcidCommand.bSpecific_2;
|
|
|
|
ISO7816_toAPDU();
|
|
}
|
|
|
|
RDRtoPCSlotStatus();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This is a command message to allow entering the PIN for verification or
|
|
/// modification.
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRSecure( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
TRACE_DEBUG("For user\n\r");
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This command is used to manage motorized type CCID functionality.
|
|
/// The Lock Card function is used to hold the ICC.
|
|
/// This prevents an ICC from being easily removed from the CCID.
|
|
/// The Unlock Card function is used to remove the hold initiated by the Lock
|
|
/// Card function
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRMechanical( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
TRACE_DEBUG("Not implemented\n\r");
|
|
|
|
RDRtoPCSlotStatus();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This command is used with the Control pipe Abort request to tell the CCID
|
|
/// to stop any current transfer at the specified slot and return to a state
|
|
/// where the slot is ready to accept a new command pipe Bulk-OUT message.
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRAbort( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
RDRtoPCSlotStatus();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Command Pipe, Bulk-OUT Messages
|
|
/// This command is used to manually set the data rate and clock frequency of
|
|
/// a specific slot.
|
|
//------------------------------------------------------------------------------
|
|
static void PCtoRDRSetDataRateAndClockFrequency( void )
|
|
{
|
|
unsigned int dwClockFrequency;
|
|
unsigned int dwDataRate;
|
|
|
|
TRACE_DEBUG(".");
|
|
|
|
dwClockFrequency = ccidDriver.sCcidCommand.APDU[0]
|
|
+ (ccidDriver.sCcidCommand.APDU[1]<<8)
|
|
+ (ccidDriver.sCcidCommand.APDU[2]<<16)
|
|
+ (ccidDriver.sCcidCommand.APDU[3]<<24);
|
|
|
|
dwDataRate = ccidDriver.sCcidCommand.APDU[4]
|
|
+ (ccidDriver.sCcidCommand.APDU[5]<<8)
|
|
+ (ccidDriver.sCcidCommand.APDU[6]<<16)
|
|
+ (ccidDriver.sCcidCommand.APDU[7]<<24);
|
|
|
|
ISO7816_SetDataRateandClockFrequency( dwClockFrequency, dwDataRate );
|
|
|
|
RDRtoPCDataRateAndClockFrequency( dwClockFrequency, dwDataRate );
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Report the CMD_NOT_SUPPORTED error to the host
|
|
//------------------------------------------------------------------------------
|
|
static void vCCIDCommandNotSupported( void )
|
|
{
|
|
// Command not supported
|
|
// vCCIDReportError(CMD_NOT_SUPPORTED);
|
|
|
|
TRACE_DEBUG("CMD_NOT_SUPPORTED\n\r");
|
|
|
|
// Header fields settings
|
|
ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
|
|
ccidDriver.sCcidMessage.wLength = 0;
|
|
ccidDriver.sCcidMessage.bSpecific = 0;
|
|
|
|
ccidDriver.sCcidMessage.bStatus |= ICC_CS_FAILED;
|
|
|
|
// Send the response to the host
|
|
//vCCIDSendResponse();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Sent CCID response on USB
|
|
//------------------------------------------------------------------------------
|
|
static void vCCIDSendResponse( void )
|
|
{
|
|
unsigned char bStatus;
|
|
TRACE_DEBUG(".");
|
|
|
|
do {
|
|
bStatus = CCID_Write((void*)&ccidDriver.sCcidMessage,
|
|
ccidDriver.sCcidMessage.bSizeToSend, 0, 0 );
|
|
} while (bStatus != USBD_STATUS_SUCCESS);
|
|
|
|
TRACE_DEBUG("bStatus: 0x%x\n\r", bStatus);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description: CCID Command dispatcher
|
|
//------------------------------------------------------------------------------
|
|
static void CCIDCommandDispatcher( void *pArg, uint8_t status, uint32_t transferred, uint32_t remaining )
|
|
{
|
|
unsigned char MessageToSend = 0;
|
|
|
|
if (status != USBD_STATUS_SUCCESS) {
|
|
TRACE_ERROR("USB error: %d", status);
|
|
return;
|
|
}
|
|
TRACE_DEBUG("Command: 0x%X 0x%x 0x%X 0x%X 0x%X 0x%X 0x%X\n\r\n\r",
|
|
(unsigned int)ccidDriver.sCcidCommand.bMessageType,
|
|
(unsigned int)ccidDriver.sCcidCommand.wLength,
|
|
(unsigned int)ccidDriver.sCcidCommand.bSlot,
|
|
(unsigned int)ccidDriver.sCcidCommand.bSeq,
|
|
(unsigned int)ccidDriver.sCcidCommand.bSpecific_0,
|
|
(unsigned int)ccidDriver.sCcidCommand.bSpecific_1,
|
|
(unsigned int)ccidDriver.sCcidCommand.bSpecific_2);
|
|
|
|
// Check the slot number
|
|
if ( ccidDriver.sCcidCommand.bSlot > 0 ) {
|
|
|
|
TRACE_ERROR("BAD_SLOT_NUMBER\n\r");
|
|
}
|
|
|
|
TRACE_INFO("typ=0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
|
|
|
|
ccidDriver.sCcidMessage.bStatus = 0;
|
|
|
|
ccidDriver.sCcidMessage.bSeq = ccidDriver.sCcidCommand.bSeq;
|
|
ccidDriver.sCcidMessage.bSlot = ccidDriver.sCcidCommand.bSlot;
|
|
|
|
ccidDriver.sCcidMessage.bSizeToSend = sizeof(S_ccid_bulk_in_header)-(ABDATA_SIZE+1);
|
|
|
|
|
|
// Command dispatcher
|
|
switch ( ccidDriver.sCcidCommand.bMessageType ) {
|
|
|
|
case PC_TO_RDR_ICCPOWERON:
|
|
PCtoRDRIccPowerOn();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_ICCPOWEROFF:
|
|
PCtoRDRIccPowerOff();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_GETSLOTSTATUS:
|
|
PCtoRDRGetSlotStatus();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_XFRBLOCK:
|
|
PCtoRDRXfrBlock();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_GETPARAMETERS:
|
|
PCtoRDRGetParameters();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_RESETPARAMETERS:
|
|
PCtoRDRResetParameters();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_SETPARAMETERS:
|
|
PCtoRDRSetParameters();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_ESCAPE:
|
|
PCtoRDREscape();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_ICCCLOCK:
|
|
PCtoRDRICCClock();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_T0APDU:
|
|
// Only CCIDs reporting a short or extended APDU level in the dwFeatures
|
|
// field of the CCID class descriptor may take this command into account.
|
|
if( (CCID_FEATURES_EXC_SAPDU == (CCID_FEATURES_EXC_SAPDU&configurationDescriptorsFS->ccid.dwFeatures))
|
|
|| (CCID_FEATURES_EXC_APDU == (CCID_FEATURES_EXC_APDU &configurationDescriptorsFS->ccid.dwFeatures)) ) {
|
|
|
|
// command supported
|
|
PCtoRDRtoAPDU();
|
|
}
|
|
else {
|
|
// command not supported
|
|
TRACE_INFO("Not supported: PC_TO_RDR_T0APDU\n\r");
|
|
vCCIDCommandNotSupported();
|
|
}
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_SECURE:
|
|
PCtoRDRSecure();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_MECHANICAL:
|
|
PCtoRDRMechanical();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_ABORT:
|
|
PCtoRDRAbort();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
|
|
PCtoRDRSetDataRateAndClockFrequency();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
default:
|
|
TRACE_DEBUG("default: Not supported: 0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
|
|
vCCIDCommandNotSupported();
|
|
MessageToSend = 1;
|
|
break;
|
|
|
|
}
|
|
|
|
if( MessageToSend == 1 ) {
|
|
vCCIDSendResponse();
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// SETUP request handler for a CCID device
|
|
/// \param pRequest Pointer to a USBGenericRequest instance
|
|
//------------------------------------------------------------------------------
|
|
static void CCID_RequestHandler(const USBGenericRequest *pRequest)
|
|
{
|
|
TRACE_DEBUG("CCID_RHl\n\r");
|
|
|
|
// Check if this is a class request
|
|
if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_CLASS) {
|
|
|
|
// Check if the request is supported
|
|
switch (USBGenericRequest_GetRequest(pRequest)) {
|
|
|
|
case CCIDGenericRequest_ABORT:
|
|
TRACE_DEBUG("CCIDGenericRequest_ABORT\n\r");
|
|
break;
|
|
|
|
case CCIDGenericRequest_GET_CLOCK_FREQUENCIES:
|
|
TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_CLOCK_FREQUENCIES\n\r");
|
|
// A CCID with bNumClockSupported equal to 00h does not have
|
|
// to support this request
|
|
break;
|
|
|
|
case CCIDGenericRequest_GET_DATA_RATES:
|
|
TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_DATA_RATES\n\r");
|
|
// A CCID with bNumDataRatesSupported equal to 00h does not have
|
|
// to support this request.
|
|
break;
|
|
|
|
default:
|
|
TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request (%d)\n\r",
|
|
USBGenericRequest_GetRequest(pRequest));
|
|
USBD_Stall(0);
|
|
}
|
|
}
|
|
|
|
else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) {
|
|
|
|
// Forward request to the standard handler
|
|
USBDDriver_RequestHandler(USBD_GetDriver(), pRequest);
|
|
}
|
|
else {
|
|
|
|
// Unsupported request type
|
|
TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request type (%d)\n\r",
|
|
USBGenericRequest_GetType(pRequest));
|
|
USBD_Stall(0);
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Exported functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Optional callback re-implementation
|
|
//------------------------------------------------------------------------------
|
|
#if !defined(NOAUTOCALLBACK)
|
|
// not static function
|
|
void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
|
|
{
|
|
CCID_RequestHandler(request);
|
|
}
|
|
#endif
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Handles SmartCart request
|
|
//------------------------------------------------------------------------------
|
|
void CCID_SmartCardRequest( void )
|
|
{
|
|
unsigned char bStatus;
|
|
TRACE_DEBUG("CCID_req\n\r");
|
|
|
|
do {
|
|
|
|
bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand,
|
|
sizeof(S_ccid_bulk_out_header),
|
|
(TransferCallback)&CCIDCommandDispatcher,
|
|
(void*)0 );
|
|
}
|
|
while (0);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Reads data from the Data OUT endpoint
|
|
/// \param pBuffer Buffer to store the received data
|
|
/// \param dLength data buffer length
|
|
/// \param fCallback Optional callback function
|
|
/// \param pArgument Optional parameter for the callback function
|
|
/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
|
|
//------------------------------------------------------------------------------
|
|
unsigned char CCID_Read(void *pBuffer,
|
|
unsigned int dLength,
|
|
TransferCallback fCallback,
|
|
void *pArgument)
|
|
{
|
|
return USBD_Read(CCID_EPT_DATA_OUT, pBuffer, dLength, fCallback, pArgument);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Sends data through the Data IN endpoint
|
|
/// \param pBuffer Buffer holding the data to transmit
|
|
/// \param dLength Length of data buffer
|
|
/// \param fCallback Optional callback function
|
|
/// \param pArgument Optional parameter for the callback function
|
|
/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
|
|
//------------------------------------------------------------------------------
|
|
unsigned char CCID_Write(void *pBuffer,
|
|
unsigned int dLength,
|
|
TransferCallback fCallback,
|
|
void *pArgument)
|
|
{
|
|
return USBD_Write(CCID_EPT_DATA_IN, pBuffer, dLength, fCallback, pArgument);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Sends data through the interrupt endpoint, ICC insertion event
|
|
/// RDR_to_PC_NotifySlotChange
|
|
/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
|
|
//------------------------------------------------------------------------------
|
|
unsigned char CCID_Insertion( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
// Build the Interrupt-IN message
|
|
ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
|
|
ccidDriver.BufferINT[1] = ICC_INSERTED_EVENT;
|
|
ccidDriver.SlotStatus = ICC_INSERTED_EVENT;
|
|
|
|
// Notify the host that a ICC is inserted
|
|
return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Sends data through the interrupt endpoint, ICC removal event
|
|
/// RDR_to_PC_NotifySlotChange
|
|
/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
|
|
//------------------------------------------------------------------------------
|
|
unsigned char CCID_Removal( void )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
// Build the Interrupt-IN message
|
|
ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
|
|
ccidDriver.BufferINT[1] = ICC_NOT_PRESENT;
|
|
ccidDriver.SlotStatus = ICC_NOT_PRESENT;
|
|
|
|
// Notify the host that a ICC is inserted
|
|
return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Interrupt-IN Messages
|
|
/// This message is sent when any bit in the bHardwareErrorCode field is set.
|
|
/// If this message is sent when there is no "outstanding" command, the bSeq
|
|
/// field will be undefined.
|
|
/// \param bSlot ICC slot number
|
|
/// \param bSeq Sequence number of the bulk OUT command when the hardware error
|
|
/// occured
|
|
/// \param bHardwareErrorCode Hardware error code
|
|
/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
|
|
//------------------------------------------------------------------------------
|
|
unsigned char RDRtoPCHardwareError( unsigned char bSlot,
|
|
unsigned char bSeq,
|
|
unsigned char bHardwareErrorCode )
|
|
{
|
|
TRACE_DEBUG(".");
|
|
|
|
// Build the Interrupt-IN message
|
|
ccidDriver.BufferINT[0] = RDR_TO_PC_HARDWAREERROR;
|
|
ccidDriver.BufferINT[1] = bSlot;
|
|
ccidDriver.BufferINT[2] = bSeq;
|
|
ccidDriver.BufferINT[3] = bHardwareErrorCode;
|
|
|
|
// Notify the host that a ICC is inserted
|
|
return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 4, 0, 0 );
|
|
}
|
|
|
|
#endif /* HAVE_CCID */
|