mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-17 13:48:32 +03:00
The define PR was introduced to switch quickly between TRACE levels for specific debug print messages. Now, it all became debug output, since it is not needed in normal operation.
1033 lines
35 KiB
C
1033 lines
35 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 <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 {
|
||
|
||
/// Standard USB device driver instance
|
||
USBDDriver usbdDriver;
|
||
/// 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");
|
||
|
||
// 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();
|
||
}
|
||
}
|
||
|
||
|
||
#if 0
|
||
//------------------------------------------------------------------------------
|
||
/// 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(&(ccidDriver.usbdDriver), 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
|
||
#endif
|
||
|
||
|
||
//------------------------------------------------------------------------------
|
||
/// Handles SmartCart request
|
||
//------------------------------------------------------------------------------
|
||
void CCID_SmartCardRequest( void )
|
||
{
|
||
unsigned char bStatus;
|
||
TRACE_DEBUG("CCID_req\n");
|
||
|
||
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 );
|
||
}
|
||
|
||
|