CCID config, init, run

Switching to config 1 and 2 works, but to 3 and 4 usb_enum.py is
hanging for some reason. Switching the USB config from Sniffer to
CCID reader was not tested yet.
diff --git a/sam3s_example/simtrace/cciddriver.c b/sam3s_example/simtrace/cciddriver.c
new file mode 100644
index 0000000..65e469a
--- /dev/null
+++ b/sam3s_example/simtrace/cciddriver.c
@@ -0,0 +1,1018 @@
+/* ----------------------------------------------------------------------------
+ *         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
+
+/// Returns the minimum between two values.
+#define MIN(a, b)       ((a < b) ? a : b)
+
+//------------------------------------------------------------------------------
+//         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 = getConfigDesc(CFG_NUM_CCID);
+}
+
+//------------------------------------------------------------------------------
+/// 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 )
+{
+    TRACE_DEBUG(".");
+
+    // Header fields settings
+    ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
+    ccidDriver.sCcidMessage.wLength   = 0;
+    ccidDriver.sCcidMessage.bStatus   = ccidDriver.SlotStatus;
+    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 );
+    if (status == 0) {
+        TRACE_DEBUG("Timeout occured while reading ATR");
+// FIXME: react properly to timeout..
+//        return;
+    }
+
+    if( length > 5 ) {
+        ccidDriver.ProtocolDataStructure[1] = Atr[5]&0x0F; // TD(1)
+        ccidDriver.bProtocol = Atr[5]&0x0F;           // TD(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 )
+{
+    unsigned char indexMessage = 0;
+
+    //TRACE_DEBUG(".");
+
+    // Check the block length
+    if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) {
+
+        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) {
+
+                    // Send commande APDU
+                    indexMessage = ISO7816_XfrBlockTPDU_T0( ccidDriver.sCcidCommand.APDU , 
+                                            ccidDriver.sCcidMessage.abData, 
+                                            ccidDriver.sCcidCommand.wLength );
+                }
+                else {
+                    if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_T1) {
+                        TRACE_INFO("Not supported T=1\n\r");
+                    }
+                    else {
+                        TRACE_INFO("Not supported\n\r");
+                    }
+                }
+                break;
+
+            case CCID_FEATURES_EXC_APDU:
+                TRACE_INFO("Not supported\n\r");
+                break;
+
+            default:
+                break;
+        }
+
+    }
+
+    ccidDriver.sCcidMessage.wLength = indexMessage;
+    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_DEBUG(".");
+
+    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 = USBD_Write( CCID_EPT_DATA_IN, (void*)&ccidDriver.sCcidMessage, 
+                              ccidDriver.sCcidMessage.bSizeToSend, 0, 0 );
+
+        TRACE_DEBUG("bStatus: 0x%x\n\r", bStatus);
+
+    } while (bStatus != USBD_STATUS_SUCCESS);
+}
+
+
+//------------------------------------------------------------------------------
+///  Description: CCID Command dispatcher
+//------------------------------------------------------------------------------
+static void CCIDCommandDispatcher( void )
+{
+    unsigned char MessageToSend = 0;
+
+    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");
+    }
+
+    printf("typ=0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
+    TRACE_DEBUG("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_DEBUG("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: 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\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\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 0
+#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(".");
+
+    do {
+
+        bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand,
+                             sizeof(S_ccid_bulk_out_header),
+                             (TransferCallback)&CCIDCommandDispatcher,
+                             (void*)0 );
+//        TRACE_DEBUG("bStat: %x\n\r", bStatus);
+    } 
+    while (bStatus != USBD_STATUS_SUCCESS);
+
+}
+
+
+//------------------------------------------------------------------------------
+/// 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 );
+}
+
+