mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-17 21:58:33 +03:00
1658 lines
51 KiB
C
1658 lines
51 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.
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
/**
|
||
* \file
|
||
*
|
||
* \section Purpose
|
||
*
|
||
* CCID driver
|
||
*
|
||
* \section Usage
|
||
*
|
||
* Explanation on the usage of the code made available through the header file.
|
||
* \addtogroup usbd_ccid
|
||
* @{
|
||
*/
|
||
|
||
/*------------------------------------------------------------------------------
|
||
* Headers
|
||
*------------------------------------------------------------------------------*/
|
||
#include "board.h"
|
||
|
||
|
||
#include "USBLib_Trace.h"
|
||
#include "USBD.h"
|
||
#include "USBDDriver.h"
|
||
#include "USBRequests.h"
|
||
//#include "USBStringDescriptor.h"
|
||
#include "cciddriver.h"
|
||
#include "cciddriverdescriptors.h"
|
||
#include "iso7816_4.h"
|
||
#include <string.h>
|
||
|
||
/*------------------------------------------------------------------------------
|
||
* Local definition
|
||
*------------------------------------------------------------------------------*/
|
||
|
||
/** Constants: IDs: Device product ID. */
|
||
|
||
#define CCIDDriverDescriptors_PRODUCTID 0x6129
|
||
/** Constants: IDs: Device 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
|
||
*------------------------------------------------------------------------------*/
|
||
|
||
#ifdef __ICCARM__ /* IAR */
|
||
#pragma pack(1) /* IAR */
|
||
#define __attribute__(...) /* IAR */
|
||
#endif /* IAR */
|
||
|
||
/**
|
||
* \typedef CCIDDriverConfigurationDescriptors
|
||
* \brief List of descriptors that make up the configuration descriptors of a
|
||
* device using the CCID driver.
|
||
*/
|
||
|
||
typedef struct _CCIDDriverConfigurationDescriptors
|
||
{
|
||
|
||
/** 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;
|
||
|
||
} __attribute__ ((packed)) CCIDDriverConfigurationDescriptors;
|
||
|
||
#ifdef __ICCARM__ /* IAR*/
|
||
#pragma pack() /* IAR*/
|
||
#endif /* IAR*/
|
||
|
||
/*------------------------------------------------------------------------------
|
||
* Types
|
||
*------------------------------------------------------------------------------*/
|
||
|
||
/** \brief 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,
|
||
CHIP_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, /* One interface in this configuration */
|
||
1, /* This is configuration #1 */
|
||
0, /* No associated string descriptor */
|
||
USBD_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–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 */
|
||
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_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(CHIP_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(CHIP_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(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION),
|
||
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
|
||
0x10
|
||
}
|
||
};
|
||
|
||
#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS)
|
||
static const CCIDDriverConfigurationDescriptors configurationDescriptorsHS = {
|
||
|
||
/* Standard USB configuration descriptor */
|
||
{
|
||
sizeof(USBConfigurationDescriptor),
|
||
USBGenericDescriptor_CONFIGURATION,
|
||
sizeof(CCIDDriverConfigurationDescriptors),
|
||
1, /* One interface in this configuration */
|
||
1, /* This is configuration #1 */
|
||
0, /* No associated string descriptor */
|
||
USBD_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–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 */
|
||
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_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(CHIP_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(CHIP_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(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION),
|
||
USBEndpointDescriptor_MAXINTERRUPTSIZE_HS),
|
||
0x10
|
||
}
|
||
};
|
||
|
||
/** 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 */
|
||
CHIP_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, /* One interface in this configuration */
|
||
1, /* This is configuration #1 */
|
||
0, /* No associated string descriptor */
|
||
USBD_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–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 */
|
||
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_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(CHIP_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(CHIP_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(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION),
|
||
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
|
||
0x10
|
||
}
|
||
};
|
||
|
||
/** OtherSpeed configuration descriptor in High Speed mode */
|
||
|
||
static const CCIDDriverConfigurationDescriptors sOtherSpeedConfigurationHS = {
|
||
|
||
/* Standard USB configuration descriptor */
|
||
|
||
{
|
||
sizeof(USBConfigurationDescriptor),
|
||
USBGenericDescriptor_OTHERSPEEDCONFIGURATION,
|
||
sizeof(CCIDDriverConfigurationDescriptors),
|
||
1, /* One interface in this configuration */
|
||
1, /* This is configuration #1 */
|
||
0, /* No associated string descriptor */
|
||
USBD_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–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 */
|
||
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_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(CHIP_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(CHIP_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(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION),
|
||
USBEndpointDescriptor_MAXINTERRUPTSIZE_HS),
|
||
0x10
|
||
}
|
||
};
|
||
#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
|
||
};
|
||
|
||
|
||
/** List of standard descriptors for the serial driver. */
|
||
const USBDDriverDescriptors ccidDriverDescriptors = {
|
||
|
||
&deviceDescriptor, /* FS */
|
||
|
||
(USBConfigurationDescriptor *) &configurationDescriptorsFS,
|
||
#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS)
|
||
(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 /* 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("RDRtoPCSlotStatus\n\r");
|
||
|
||
/* 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("RDRtoPCDatablock\n\r"); */
|
||
|
||
|
||
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 – 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("RDRtoPCDatablock\n\r"); */
|
||
|
||
|
||
/* 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("RDRtoPCParameters\n\r");
|
||
|
||
/* 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("RDRtoPCEscape\n\r");
|
||
|
||
/* 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("RDRtoPCDataRateAndClockFrequency\n\r");
|
||
|
||
/* 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("PCtoRDRIccPowerOn\n\r");
|
||
|
||
if( CCID_FEATURES_AUTO_VOLT == (configurationDescriptorsFS.ccid.dwFeatures & CCID_FEATURES_AUTO_VOLT) ) {
|
||
|
||
/* bPowerSelect = ccidDriver.sCcidCommand.bSpecific_0; */
|
||
|
||
ccidDriver.sCcidCommand.bSpecific_0 = VOLTS_AUTO;
|
||
}
|
||
|
||
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("PCtoRDRIccPowerOff\n\r");
|
||
|
||
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("PCtoRDRGetSlotStatus\n\r");
|
||
|
||
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;
|
||
unsigned char i;
|
||
|
||
/*TRACE_DEBUG("PCtoRDRXfrBlock\n\r"); */
|
||
|
||
|
||
i = 0;
|
||
|
||
/* 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("PCtoRDRGetParameters\n\r");
|
||
|
||
/* 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("PCtoRDRResetParameters\n\r");
|
||
|
||
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("PCtoRDRSetParameters\n\r");
|
||
|
||
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("PCtoRDREscape\n\r");
|
||
|
||
/* 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("PCtoRDRICCClock\n\r");
|
||
|
||
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("PCtoRDRtoAPDU\n\r");
|
||
|
||
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("PCtoRDRSecure\n\r");
|
||
|
||
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("PCtoRDRMechanical\n\r");
|
||
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("PCtoRDRAbort\n\r");
|
||
|
||
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("PCtoRDRSetDatarateandClockFrequency\n\r");
|
||
|
||
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;
|
||
|
||
do {
|
||
bStatus = USBD_Write( CCID_EPT_DATA_IN, (void*)&ccidDriver.sCcidMessage,
|
||
ccidDriver.sCcidMessage.bSizeToSend, 0, 0 );
|
||
}
|
||
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");
|
||
}
|
||
|
||
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;
|
||
|
||
do {
|
||
|
||
bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand,
|
||
sizeof(S_ccid_bulk_out_header),
|
||
(TransferCallback)&CCIDCommandDispatcher,
|
||
(void*)0 );
|
||
}
|
||
while (bStatus != USBD_STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
/**
|
||
* Initializes the CCID device driver.
|
||
*/
|
||
void CCIDDriver_Initialize( void )
|
||
{
|
||
TRACE_DEBUG("CCID_Init\n\r");
|
||
USBDDriver_Initialize(&(ccidDriver.usbdDriver),
|
||
&ccidDriverDescriptors,
|
||
0); /* Multiple interface settings not supported */
|
||
|
||
USBD_Init();
|
||
}
|
||
|
||
/**
|
||
* 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("CCID_Insertion\n\r");
|
||
|
||
/* 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("CCID_Removal\n\r");
|
||
|
||
/* 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("RDRtoPCHardwareError\n\r");
|
||
|
||
/* 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 );
|
||
}
|
||
|
||
|
||
/**@}*/
|