www.pudn.com > agsm2-1.2_src.zip > parseATR.cpp


//adapt from wince driver smcutil.c 
#include "stdafx.h" 
#include "parseATR.h" 
 
static ULONG  
Pow2( 
	UCHAR Exponent 
	) 
{ 
	ULONG result = 1; 
 
	while(Exponent--) 
		result *= 2; 
 
	return result; 
}	 
 
VOID 
SmartcardInvertData( 
	PUCHAR Buffer, 
	ULONG Length 
    ) 
{ 
	ULONG i; 
 
	for (i = 0; i < Length; i++) { 
 
		UCHAR j, inv = 0; 
 
		for (j = 0; j < 8; j++) { 
 
			if (Buffer[i] & (1 << j)) { 
 
				inv |= 1 << (7 - j); 
			} 
		} 
		Buffer[i] = (inv ^ 0xFF); 
	} 
} 
 
CString parseATR( 
    PUCHAR atrString, ULONG atrLength,PSCARD_CARD_CAPABILITIES cardCapabilities ,ULONG fs 
    ) 
{ 
	UCHAR Y, Tck, TA[MAXIMUM_ATR_CODES], TB[MAXIMUM_ATR_CODES]; 
	UCHAR TC[MAXIMUM_ATR_CODES], TD[MAXIMUM_ATR_CODES]; 
	ULONG i,numProtocols = 0, protocolTypes = 0; 
	BOOLEAN TA2Present = FALSE; 
 
	if (atrLength < 2) 
		return _T("ATR is too short (Min. length is 2)"); 
 
	if (atrString[0] != 0x3b && atrString[0] != 0x3f && atrString[0] != 0x03) 
        return _T("Initial character of ATR is invalid"); 
 
	// Test for invers convention 
	if (*atrString == 0x03) { 
		cardCapabilities->InversConvention = TRUE; 
        // 
        // When the ATR starts with 0x03 then it  
        // has not been inverted already         	 
        // 
    	SmartcardInvertData( 
            cardCapabilities->ATR.Buffer,  
            cardCapabilities->ATR.Length 
            );             	 
        TRACE(_T("Card uses Inverse Convention\n")); 
	}  
 
 
	// 
	// The caller might be calling this function repeatedly in order to  
	// test if the ATR is valid. If the ATR we currently have here is 
	// not valid then we need to be able re-invert an inverted ATR. 
	// 
 
	atrString += 1; 
	atrLength -= 1; 
 
	// 
	// Calculate check char, but do not test now since if only T=0  
	// is present the ATR doesn't contain a check char 
	// 
	for (i = 0, Tck = 0; i < atrLength; i++) 
		    Tck ^= atrString[i]; 
 
	// Initialize various data 
	cardCapabilities->Protocol.Supported = 0; 
 
	memset(TA,0, sizeof(TA)); 
	memset(TB,0, sizeof(TB)); 
	memset(TC,0, sizeof(TC)); 
	memset(TD,0, sizeof(TD)); 
 
	// 
	// Set default values as described in ISO 7816-3 
	// 
     
	// TA1 codes Fl in high-byte and Dl in low-byte; 
	TA[0] = 0x11; 
	// TB1 codes II in bits b7/b6 and Pl1 in b5-b1. b8 has to be 0 
	TB[0] = 0x25; 
	// TC2 codes T=0 WI 
	TC[1] = 10; 
 
	// Translate ATR string to TA to TD values (See ISO) 
	cardCapabilities->HistoricalChars.Length = *atrString & 0x0f; 
 
	Y = *atrString++ & 0xf0; 
	atrLength -= 1; 
 
	for (i = 0; i < MAXIMUM_ATR_CODES; i++) { 
		if (Y & 0x10) { 
			if (i == 1) 
				TA2Present = TRUE;              	 
			TA[i] = *atrString++; 
        	atrLength -= 1; 
		} 
		if (Y & 0x20) { 
			TB[i] = *atrString++; 
			atrLength -= 1; 
		} 
		if (Y & 0x40) { 
			TC[i] = *atrString++; 
			atrLength -= 1; 
		} 
		if (Y & 0x80) { 
			Y = *atrString & 0xf0; 
			TD[i] = *atrString++ & 0x0f; 
			atrLength -= 1; 
			// Check if the next parameters are for a new protocol. 
			if (((1 << TD[i]) & protocolTypes) == 0) { 
				// Count the number of protocols that the card supports 
				numProtocols++; 
			} 
			protocolTypes |= 1 << TD[i]; 
		} else { 
			    break; 
		} 
	}  
 
	// Check if the card supports a protocol other than T=0 
	if (protocolTypes & ~1) { 
		// 
		// The atr contains a checksum byte. 
		// Exclude that from the historical byte length check 
		// 
		atrLength -=1;     	 
 
		// 
		// This card supports more than one protocol or a protocol  
		// other than T=0, so test if the checksum is correct 
		// 
		if (Tck != 0) 
                return _T("ATR Checksum is invalid"); 
	} 
 
	if (atrLength < 0 || 
            atrLength != cardCapabilities->HistoricalChars.Length) { 
            return _T("ATR length is inconsistent"); 
	} 
        
    // store historical characters 
	memcpy( 
		cardCapabilities->HistoricalChars.Buffer, 
		atrString, 
		cardCapabilities->HistoricalChars.Length 
		); 
 
    // 
	// Now convert TA - TD values to global interface bytes 
    // 
 
	// Clock rate conversion 
	cardCapabilities->Fl = (TA[0] & 0xf0) >> 4; 
 
	// bit rate adjustment 
	cardCapabilities->Dl = (TA[0] & 0x0f); 
 
	// Maximum programming current factor 
	cardCapabilities->II = (TB[0] & 0xc0) >> 6; 
 
	// Programming voltage in 0.1 Volts 
	cardCapabilities->P = (TB[1] ? TB[1] : (TB[0] & 0x1f) * 10); 
 
	// Extra guard time 
	cardCapabilities->N = TC[0]; 
 
	// 
	// Check if the Dl and Fl values are valid 
	//  
	if (BitRateAdjustment[cardCapabilities->Dl].DNumerator == 0 || 
		ClockRateConversion[cardCapabilities->Fl].F == 0) { 
        return _T("Dl or Fl invalid"); 
	} 
 
    TRACE( 
        _T("Card parameters from ATR:\n      Fl = %02x (%ld KHz), Dl = %02x, I = %02x, P = %02x, N = %02x\n"), 
        cardCapabilities->Fl, 
        ClockRateConversion[cardCapabilities->Fl].fs / 1000, 
        cardCapabilities->Dl, 
        cardCapabilities->II, 
        cardCapabilities->P, 
        cardCapabilities->N 
        ); 
 
    // 
    // assume default clock frequency 
    // 
    if (fs == 0)  
        fs = 372 * 9600l; 
 
    cardCapabilities->PtsData.Fl = cardCapabilities->Fl; 
    cardCapabilities->PtsData.Dl = cardCapabilities->Dl; 
    // 
    // We calculate the ETU on basis of the timing supplied by the  
    // clk-frequency of the reader 
    // 
    // 
    // Work etu in units of time resolution(TR) (NOT in seconds) 
    // 
    cardCapabilities->etu =  
        1 +     // required to round up 
   		(TR *  
   		BitRateAdjustment[cardCapabilities->Dl].DDivisor * 
		ClockRateConversion[cardCapabilities->Fl].F) / 
   		(BitRateAdjustment[cardCapabilities->Dl].DNumerator *  
        fs); 
 
    // 
	// guard time in micro seconds 
    // the guard time is the gap between the end of the 
    // current character and the beginning of the next character 
    // 
    cardCapabilities->GT = 0; 
 
    if (cardCapabilities->N == 0) 
        cardCapabilities->PtsData.StopBits = 2; 
    else if (cardCapabilities->N == 255) 
        cardCapabilities->PtsData.StopBits = 1;   	 
    else 
	    cardCapabilities->GT = cardCapabilities->N * cardCapabilities->etu; 
 
    TRACE( 
        _T("Calculated timing values:\n      Work etu = %ld micro sec, Guard time = %ld micro sec\n"), 
        cardCapabilities->etu, 
        cardCapabilities->GT); 
 
    // 
	// Now find protocol specific data 
    // 
 
    if (TD[0] == 0) { 
         
		cardCapabilities->Protocol.Supported |= 
			SCARD_PROTOCOL_T0; 
 
		cardCapabilities->T0.WI = TC[1]; 
 
		if (cardCapabilities->PtsData.Dl > 0 &&  
            cardCapabilities->PtsData.Dl < 6) { 
 
			cardCapabilities->T0.WT = 1 + 
				cardCapabilities->T0.WI * 
				960 * cardCapabilities->etu *  
		   		Pow2((UCHAR) (cardCapabilities->PtsData.Dl - 1)); 
 
		} else {  
 
			cardCapabilities->T0.WT = 1+ 
				cardCapabilities->T0.WI * 
				960 * cardCapabilities->etu / 
		   		Pow2((UCHAR) (cardCapabilities->PtsData.Dl - 1));			         
		}  
 
        TRACE( 
            _T("T=0 Values from ATR:\n      WI = %ld\n"), 
            cardCapabilities->T0.WI 
            ); 
        TRACE( 
            _T("T=0 Timing from ATR:\n      WT = %ld ms\n"), 
            cardCapabilities->T0.WT / 1000 
            ); 
    } 
 
    if (protocolTypes & SCARD_PROTOCOL_T1) { 
 
        for (i = 0; TD[i] != 1 && i < MAXIMUM_ATR_CODES; i++) 
            ; 
     
        for (; TD[i] == 1 && i < MAXIMUM_ATR_CODES; i++)  
            ; 
 
        if (i == MAXIMUM_ATR_CODES) { 
 
            return _T("Parse T1 error");         	 
        } 
 
		cardCapabilities->Protocol.Supported |=  
			SCARD_PROTOCOL_T1; 
 
		cardCapabilities->T1.IFSC =  
			(TA[i] ? TA[i] : 32); 
 
		cardCapabilities->T1.CWI =  
			((TB[i] & 0x0f) ? (TB[i] & 0x0f) : T1_CWI_DEFAULT); 
 
		cardCapabilities->T1.BWI =  
			((TB[i] & 0xf0) >> 4 ? (TB[i] & 0xf0) >> 4 : T1_BWI_DEFAULT); 
 
		cardCapabilities->T1.EDC =  
			(TC[i] & 0x01); 
 
		cardCapabilities->T1.CWT = 1 + 
			(Pow2(cardCapabilities->T1.CWI) + 11) * cardCapabilities->etu; 
 
		cardCapabilities->T1.BWT = 1 + 
			((Pow2(cardCapabilities->T1.BWI) * TR) / 10) +  
			11 * cardCapabilities->etu; 
 
        TRACE( 
            _T("   T=1 Values from ATR:\n      IFSC = %ld, CWI = %ld, BWI = %ld, EDC = %02x\n"), 
            cardCapabilities->T1.IFSC, 
            cardCapabilities->T1.CWI, 
            cardCapabilities->T1.BWI, 
            cardCapabilities->T1.EDC 
            ); 
        TRACE( 
            _T("   T=1 Timing from ATR:\n      CWT = %ld ms, BWT = %ld ms\n"), 
            cardCapabilities->T1.CWT / 1000, 
            cardCapabilities->T1.BWT / 1000 
            ); 
    } 
 
   return _T(""); 
}