simtrace2/sam3s_example/atmel_softpack_libraries/usb/device/ccid/cciddriver.c

1526 lines
55 KiB
C
Raw Blame History

/* ----------------------------------------------------------------------------
* 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
//------------------------------------------------------------------------------
/// CCIDDriverConfiguration Descriptors
/// List of descriptors that make up the configuration descriptors of a
/// device using the CCID driver.
typedef struct {
/// Configuration descriptor
USBConfigurationDescriptor configuration;
/// Interface descriptor
USBInterfaceDescriptor interface;
/// CCID descriptor
CCIDDescriptor ccid;
/// Bulk OUT endpoint descriptor
USBEndpointDescriptor bulkOut;
/// Bulk IN endpoint descriptor
USBEndpointDescriptor bulkIn;
/// Interrupt OUT endpoint descriptor
USBEndpointDescriptor interruptIn;
DFU_IF_DESCRIPTORS_STRUCT
} __attribute__ ((packed)) CCIDDriverConfigurationDescriptors;
//------------------------------------------------------------------------------
// 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;
/// Standard USB device descriptor.
static const USBDeviceDescriptor deviceDescriptor = {
sizeof(USBDeviceDescriptor),
USBGenericDescriptor_DEVICE,
USBDeviceDescriptor_USB2_00,
0,
0,
0,
BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0),
CCIDDriverDescriptors_VENDORID,
CCIDDriverDescriptors_PRODUCTID,
CCIDDriverDescriptors_RELEASE,
1, // Index of manufacturer description
2, // Index of product description
3, // Index of serial number description
1 // One possible configuration
};
/// List of configuration descriptors.
static const CCIDDriverConfigurationDescriptors configurationDescriptorsFS = {
// Standard USB configuration descriptor
{
sizeof(USBConfigurationDescriptor),
USBGenericDescriptor_CONFIGURATION,
sizeof(CCIDDriverConfigurationDescriptors),
1+DFU_NUM_IF, // One interface in this configuration
1, // This is configuration #1
0, // No associated string descriptor
BOARD_USB_BMATTRIBUTES,
USBConfigurationDescriptor_POWER(100)
},
// CCID interface descriptor
// Table 4.3-1 Interface Descriptor
// Interface descriptor
{
sizeof(USBInterfaceDescriptor),
USBGenericDescriptor_INTERFACE,
0, // Interface 0
0, // No alternate settings
3, // uses bulk-IN, bulk-OUT and interrupt<70>IN
SMART_CARD_DEVICE_CLASS,
0, // Subclass code
0, // bulk transfers optional interrupt-IN
0 // No associated string descriptor
},
{
sizeof(CCIDDescriptor), // bLength: Size of this descriptor in bytes
CCID_DECRIPTOR_TYPE, // bDescriptorType:Functional descriptor type
CCID1_10, // bcdCCID: CCID version
0, // bMaxSlotIndex: Value 0 indicates that one slot is supported
VOLTS_5_0, // bVoltageSupport
(1 << PROTOCOL_TO), // dwProtocols
3580, // dwDefaultClock
3580, // dwMaxClock
0, // bNumClockSupported
9600, // dwDataRate : 9600 bauds
9600, // dwMaxDataRate : 9600 bauds
0, // bNumDataRatesSupported
0xfe, // dwMaxIFSD
0, // dwSynchProtocols
0, // dwMechanical
//0x00010042, // dwFeatures: Short APDU level exchanges
CCID_FEATURES_AUTO_CLOCK | CCID_FEATURES_AUTO_BAUD |
CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO | CCID_FEATURES_EXC_TPDU,
0x0000010F, // dwMaxCCIDMessageLength: For extended APDU level the value shall be between 261 + 10
0xFF, // bClassGetResponse: Echoes the class of the APDU
0xFF, // bClassEnvelope: Echoes the class of the APDU
0, // wLcdLayout: no LCD
0, // bPINSupport: No PIN
1 // bMaxCCIDBusySlot
},
// Bulk-OUT endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_OUT, CCID_EPT_DATA_OUT ),
USBEndpointDescriptor_BULK,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_OUT),
USBEndpointDescriptor_MAXBULKSIZE_FS),
0x00 // Does not apply to Bulk endpoints
},
// Bulk-IN endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_DATA_IN ),
USBEndpointDescriptor_BULK,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_IN),
USBEndpointDescriptor_MAXBULKSIZE_FS),
0x00 // Does not apply to Bulk endpoints
},
// Notification endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_NOTIFICATION ),
USBEndpointDescriptor_INTERRUPT,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION),
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
0x10
},
DFU_IF_DESCRIPTORS
};
#ifdef BOARD_USB_UDPHS
static const CCIDDriverConfigurationDescriptors configurationDescriptorsHS = {
// Standard USB configuration descriptor
{
sizeof(USBConfigurationDescriptor),
USBGenericDescriptor_CONFIGURATION,
sizeof(CCIDDriverConfigurationDescriptors),
1+DFU_NUM_IF, // One interface in this configuration
1, // This is configuration #1
0, // No associated string descriptor
BOARD_USB_BMATTRIBUTES,
USBConfigurationDescriptor_POWER(100)
},
// CCID interface descriptor
// Table 4.3-1 Interface Descriptor
// Interface descriptor
{
sizeof(USBInterfaceDescriptor),
USBGenericDescriptor_INTERFACE,
0, // Interface 0
0, // No alternate settings
3, // uses bulk-IN, bulk-OUT and interrupt<70>IN
SMART_CARD_DEVICE_CLASS,
0, // Subclass code
0, // bulk transfers optional interrupt-IN
0 // No associated string descriptor
},
{
sizeof(CCIDDescriptor), // bLength: Size of this descriptor in bytes
CCID_DECRIPTOR_TYPE, // bDescriptorType:Functional descriptor type
CCID1_10, // bcdCCID: CCID version
0, // bMaxSlotIndex: Value 0 indicates that one slot is supported
VOLTS_5_0, // bVoltageSupport
(1 << PROTOCOL_TO), // dwProtocols
3580, // dwDefaultClock
3580, // dwMaxClock
0, // bNumClockSupported
9600, // dwDataRate : 9600 bauds
9600, // dwMaxDataRate : 9600 bauds
0, // bNumDataRatesSupported
0xfe, // dwMaxIFSD
0, // dwSynchProtocols
0, // dwMechanical
//0x00010042, // dwFeatures: Short APDU level exchanges
CCID_FEATURES_AUTO_CLOCK | CCID_FEATURES_AUTO_BAUD |
CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO | CCID_FEATURES_EXC_TPDU,
0x0000010F, // dwMaxCCIDMessageLength: For extended APDU level the value shall be between 261 + 10
0xFF, // bClassGetResponse: Echoes the class of the APDU
0xFF, // bClassEnvelope: Echoes the class of the APDU
0, // wLcdLayout: no LCD
0, // bPINSupport: No PIN
1 // bMaxCCIDBusySlot
},
// Bulk-OUT endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_OUT, CCID_EPT_DATA_OUT ),
USBEndpointDescriptor_BULK,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_OUT),
USBEndpointDescriptor_MAXBULKSIZE_HS),
0x00 // Does not apply to Bulk endpoints
},
// Bulk-IN endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_DATA_IN ),
USBEndpointDescriptor_BULK,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_IN),
USBEndpointDescriptor_MAXBULKSIZE_HS),
0x00 // Does not apply to Bulk endpoints
},
// Notification endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_NOTIFICATION ),
USBEndpointDescriptor_INTERRUPT,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION),
USBEndpointDescriptor_MAXINTERRUPTSIZE_HS),
0x10
},
DFU_IF_DESCRIPTORS
};
/// Qualifier descriptor
const USBDeviceQualifierDescriptor deviceQualifierDescriptor = {
sizeof(USBDeviceQualifierDescriptor), // Size of this descriptor in bytes
USBGenericDescriptor_DEVICEQUALIFIER, // Qualifier Descriptor Type
USBDeviceDescriptor_USB2_00, // USB specification 2.00
0x00, // Class is specified in interface
0x00, // Subclass is specified in interface
0x00, // Protocol is specified in interface
BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0),
0x01, // One possible configuration
0x00 // Reserved for future use, must be zero
};
/// OtherSpeed configuration descriptor in Full Speed mode
static const CCIDDriverConfigurationDescriptors sOtherSpeedConfigurationFS = {
// Standard USB configuration descriptor
{
sizeof(USBConfigurationDescriptor),
USBGenericDescriptor_OTHERSPEEDCONFIGURATION,
sizeof(CCIDDriverConfigurationDescriptors),
1+DFU_NUM_IF, // One interface in this configuration
1, // This is configuration #1
0, // No associated string descriptor
BOARD_USB_BMATTRIBUTES,
USBConfigurationDescriptor_POWER(100)
},
// CCID interface descriptor
// Table 4.3-1 Interface Descriptor
// Interface descriptor
{
sizeof(USBInterfaceDescriptor),
USBGenericDescriptor_INTERFACE,
0, // Interface 0
0, // No alternate settings
3, // uses bulk-IN, bulk-OUT and interrupt<70>IN
SMART_CARD_DEVICE_CLASS,
0, // Subclass code
0, // bulk transfers optional interrupt-IN
0 // No associated string descriptor
},
{
sizeof(CCIDDescriptor), // bLength: Size of this descriptor in bytes
CCID_DECRIPTOR_TYPE, // bDescriptorType:Functional descriptor type
CCID1_10, // bcdCCID: CCID version
0, // bMaxSlotIndex: Value 0 indicates that one slot is supported
VOLTS_5_0, // bVoltageSupport
(1 << PROTOCOL_TO), // dwProtocols
3580, // dwDefaultClock
3580, // dwMaxClock
0, // bNumClockSupported
9600, // dwDataRate : 9600 bauds
9600, // dwMaxDataRate : 9600 bauds
0, // bNumDataRatesSupported
0xfe, // dwMaxIFSD
0, // dwSynchProtocols
0, // dwMechanical
//0x00010042, // dwFeatures: Short APDU level exchanges
CCID_FEATURES_AUTO_CLOCK | CCID_FEATURES_AUTO_BAUD |
CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO | CCID_FEATURES_EXC_TPDU,
0x0000010F, // dwMaxCCIDMessageLength: For extended APDU level the value shall be between 261 + 10
0xFF, // bClassGetResponse: Echoes the class of the APDU
0xFF, // bClassEnvelope: Echoes the class of the APDU
0, // wLcdLayout: no LCD
0, // bPINSupport: No PIN
1 // bMaxCCIDBusySlot
},
// Bulk-OUT endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_OUT, CCID_EPT_DATA_OUT ),
USBEndpointDescriptor_BULK,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_OUT),
USBEndpointDescriptor_MAXBULKSIZE_FS),
0x00 // Does not apply to Bulk endpoints
},
// Bulk-IN endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_DATA_IN ),
USBEndpointDescriptor_BULK,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_IN),
USBEndpointDescriptor_MAXBULKSIZE_FS),
0x00 // Does not apply to Bulk endpoints
},
// Notification endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_NOTIFICATION ),
USBEndpointDescriptor_INTERRUPT,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION),
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
0x10
},
DFU_IF_DESCRIPTORS
};
/// OtherSpeed configuration descriptor in High Speed mode
static const CCIDDriverConfigurationDescriptors sOtherSpeedConfigurationHS = {
// Standard USB configuration descriptor
{
sizeof(USBConfigurationDescriptor),
USBGenericDescriptor_OTHERSPEEDCONFIGURATION,
sizeof(CCIDDriverConfigurationDescriptors),
1+DFU_NUM_IF, // One interface in this configuration
1, // This is configuration #1
0, // No associated string descriptor
BOARD_USB_BMATTRIBUTES,
USBConfigurationDescriptor_POWER(100)
},
// CCID interface descriptor
// Table 4.3-1 Interface Descriptor
// Interface descriptor
{
sizeof(USBInterfaceDescriptor),
USBGenericDescriptor_INTERFACE,
0, // Interface 0
0, // No alternate settings
3, // uses bulk-IN, bulk-OUT and interrupt<70>IN
SMART_CARD_DEVICE_CLASS,
0, // Subclass code
0, // bulk transfers optional interrupt-IN
0 // No associated string descriptor
},
{
sizeof(CCIDDescriptor), // bLength: Size of this descriptor in bytes
CCID_DECRIPTOR_TYPE, // bDescriptorType:Functional descriptor type
CCID1_10, // bcdCCID: CCID version
0, // bMaxSlotIndex: Value 0 indicates that one slot is supported
VOLTS_5_0, // bVoltageSupport
(1 << PROTOCOL_TO), // dwProtocols
3580, // dwDefaultClock
3580, // dwMaxClock
0, // bNumClockSupported
9600, // dwDataRate : 9600 bauds
9600, // dwMaxDataRate : 9600 bauds
0, // bNumDataRatesSupported
0xfe, // dwMaxIFSD
0, // dwSynchProtocols
0, // dwMechanical
//0x00010042, // dwFeatures: Short APDU level exchanges
CCID_FEATURES_AUTO_CLOCK | CCID_FEATURES_AUTO_BAUD |
CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO | CCID_FEATURES_EXC_TPDU,
0x0000010F, // dwMaxCCIDMessageLength: For extended APDU level the value shall be between 261 + 10
0xFF, // bClassGetResponse: Echoes the class of the APDU
0xFF, // bClassEnvelope: Echoes the class of the APDU
0, // wLcdLayout: no LCD
0, // bPINSupport: No PIN
1 // bMaxCCIDBusySlot
},
// Bulk-OUT endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_OUT, CCID_EPT_DATA_OUT ),
USBEndpointDescriptor_BULK,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_OUT),
USBEndpointDescriptor_MAXBULKSIZE_HS),
0x00 // Does not apply to Bulk endpoints
},
// Bulk-IN endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_DATA_IN ),
USBEndpointDescriptor_BULK,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_IN),
USBEndpointDescriptor_MAXBULKSIZE_HS),
0x00 // Does not apply to Bulk endpoints
},
// Notification endpoint descriptor
{
sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_NOTIFICATION ),
USBEndpointDescriptor_INTERRUPT,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION),
USBEndpointDescriptor_MAXINTERRUPTSIZE_HS),
0x10
},
DFU_IF_DESCRIPTORS
};
#endif
/// Language ID string descriptor.
static const unsigned char languageIdDescriptor[] = {
USBStringDescriptor_LENGTH(1),
USBGenericDescriptor_STRING,
USBStringDescriptor_ENGLISH_US
};
/// Manufacturer name.
static const unsigned char manufacturerDescriptor[] = {
USBStringDescriptor_LENGTH(5),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('A'),
USBStringDescriptor_UNICODE('T'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('E'),
USBStringDescriptor_UNICODE('L')
};
/// Product name.
static const unsigned char productDescriptor[] = {
USBStringDescriptor_LENGTH(23),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('A'),
USBStringDescriptor_UNICODE('T'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('E'),
USBStringDescriptor_UNICODE('L'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('A'),
USBStringDescriptor_UNICODE('T'),
USBStringDescriptor_UNICODE('9'),
USBStringDescriptor_UNICODE('1'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('C'),
USBStringDescriptor_UNICODE('C'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('D'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('D'),
USBStringDescriptor_UNICODE('R'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('V'),
USBStringDescriptor_UNICODE('E'),
USBStringDescriptor_UNICODE('R'),
USBStringDescriptor_UNICODE(' ')
};
/// Product serial number.
static const unsigned char serialNumberDescriptor[] = {
USBStringDescriptor_LENGTH(12),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('0'),
USBStringDescriptor_UNICODE('1'),
USBStringDescriptor_UNICODE('2'),
USBStringDescriptor_UNICODE('3'),
USBStringDescriptor_UNICODE('4'),
USBStringDescriptor_UNICODE('5'),
USBStringDescriptor_UNICODE('6'),
USBStringDescriptor_UNICODE('7'),
USBStringDescriptor_UNICODE('8'),
USBStringDescriptor_UNICODE('9'),
USBStringDescriptor_UNICODE('A'),
USBStringDescriptor_UNICODE('F')
};
/// Array of pointers to string descriptors.
static const unsigned char *stringDescriptors[] = {
languageIdDescriptor,
manufacturerDescriptor,
productDescriptor,
serialNumberDescriptor,
DFU_STRING_DESCRIPTORS
};
/// List of standard descriptors for the serial driver.
const USBDDriverDescriptors ccidDriverDescriptors = {
&deviceDescriptor, // FS
(USBConfigurationDescriptor *) &configurationDescriptorsFS ,
#ifdef BOARD_USB_UDPHS
(USBDeviceQualifierDescriptor *) &deviceQualifierDescriptor, // FS
{ (USBConfigurationDescriptor *) &sOtherSpeedConfigurationFS },
&deviceDescriptor, // HS
{ (USBConfigurationDescriptor *) &configurationDescriptorsHS },
(USBDeviceQualifierDescriptor *) &deviceQualifierDescriptor, // HS
{ (USBConfigurationDescriptor *) &sOtherSpeedConfigurationHS },
#else
0, // No qualifier descriptor FS
0, // No other-speed configuration FS
0, // No device descriptor HS
0, // No configuration HS
0, // No qualifier descriptor HS
0, // No other-speed configuration HS
#endif
stringDescriptors,
4+DFU_NUM_STRINGS // Four string descriptors in array
};
//------------------------------------------------------------------------------
// Internal functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// 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;
//TRACE_DEBUG(".");
ISO7816_Datablock_ATR( Atr, &length );
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 <20> 0b, B7-2 <20> 000000b
// B1 <20> 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 !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(".");
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);
}
//------------------------------------------------------------------------------
/// Initializes the CCID device driver.
//------------------------------------------------------------------------------
void CCIDDriver_Initialize( void )
{
TRACE_DEBUG(".");
USBDDriver_Initialize(&(ccidDriver.usbdDriver),
&ccidDriverDescriptors,
0); // Multiple interface settings not supported
USBD_Init();
TRACE_DEBUG("%s", "leaving");
}
//------------------------------------------------------------------------------
/// 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 <20>outstanding<6E> 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 );
}