📄 tda8007.c
字号:
return 0;
}
}
}
/*************************************************************************
功能:热复位
参数:
返回值:-1: error
0: OK
**************************************************************************/
int tda_warmreset(uchar mode, unsigned char *rec_buf,
int * rec_len,
int cardname)
{
uchar val;
// Check for power status
val = tda_readregister(PCR);
if (!(val & PCR_START_MASK))
return ERR_POWERUP_VOLTAGE_INVALID;
// Apply reset
val = tda_readregister(PCR);
tda_writeregister(PCR,val & ~PCR_RSTIN_MASK);
// Call common getATR routine
return tda_ATRsequence(mode, rec_buf, rec_len);
}
/*************************************************************************
功能:复位应答
参数:
返回值:-1: error
0: OK
**************************************************************************/
static int tda_ATRsequence(uchar mode, uchar *rec_buf, int *rec_len)
{
volatile u8 val;
volatile u16 count;
uchar USRval;
uchar index;
uchar historicalBytes = 0;
uchar expectedCharacters = 0;
uchar etucount = 0;
uchar interfaceIteration = 1;
uchar done = 0;
uchar check = 0;
uchar i = 0;
// Default to T=0 mode
uchar T = 0;
uint curByte;
//printk("tda_ATRsequence L1125\n");
clearATRStruct(&lastATR[currentSlot]);
// Reset the UART
val = tda_readregister(CSR);
tda_writeregister(CSR,val & ~CSR_nRIU_MASK);
// Remove UART reset
val = tda_readregister(CSR);
tda_writeregister(CSR,val | CSR_nRIU_MASK);
// Set FIFO to 1 byte; parity Error Count 3 byte
tda_writeregister(FCR,0x00);
tda_writeregister(FCR,FCR_PEC0_MASK | FCR_PEC1_MASK);
// Set divisor
tda_writeregister(PDR,12);
// Set prescaler
tda_writeregister(UCR2,0x00);
// Enable auto convention
val = tda_readregister(UCR2);
tda_writeregister(UCR2,val & ~UCR2_nAUTOCONV_MASK);
// Set SS bit
tda_writeregister(UCR1,UCR1_SS_MASK);
// Wait 40000 to 45000 cycles to release reset
//printk("wait counters for reset\n");
tda_writeregister(TOC, 0x00);
delay_us(5);
tda_writeregister(TOR3, 0x00);
delay_us(5);
tda_writeregister(TOR2, 0x6C);
delay_us(5);
tda_writeregister(TOR1, 0x00);
delay_us(5);
tda_writeregister(TOC, 0x61);
//delay_us(5);
count = 0;
printk("TOC = %x\n",tda_readregister(TOC));
do
{
if(++count > 5000)
{
printk("Time 2 not end!\n");
break;
}
val = tda_readregister(USR);
}while (!(val & USR_TOL3_MASK));
printk("Set up counters for reset\n");
if (mode == POWERUP_ISO)
{
// Wait up to 40000 cycles for ATR to start
tda_writeregister(TOC,0x00);
delay_us(5);
tda_writeregister(TOR3,0x00);
delay_us(5);
tda_writeregister(TOR2,0x78);
delay_us(5);
tda_writeregister(TOR1,0x00);
delay_us(5);
tda_writeregister(TOC,0x61);
}
else // power up EMV
{
// Wait up to 40000 cycles for ATR to start and 19200 etu counter after first byte
tda_writeregister(TOC,0x00);
tda_writeregister(TOR3,0x00);
tda_writeregister(TOR2,0x78);
tda_writeregister(TOR1,0xC0);
tda_writeregister(TOC,0x65);
}
//printk("Release reset\n");
val = tda_readregister(PCR);
tda_writeregister(PCR,val | PCR_RSTIN_MASK);
while (1)
{
val = tda_readregister(MSR);
// If we see the first character come in, break.
if (val & MSR_TBE_RBF_MASK)break;
val = tda_readregister(USR);
if (val & (USR_PE_MASK|USR_FER_MASK|USR_OVR_MASK|USR_EA_MASK))
{
tda_powerdown();
if(val & USR_PE_MASK)
{
printk("ATR error: PARITY1_ERR\n");
return PARITY1_ERR;
}
else
{
printk("ATR error: USR=0x%2x\n", val);
return ERR_POWERUP_ATR_INVALID;
}
}
if (val & USR_TOL3_MASK)
{
tda_powerdown();
printk("No ATR within timeout\n");
return ERR_POWERUP_ATR_TIMEOUT;
}
}//end 1
if (mode == POWERUP_ISO)
{
// Set up timer for 9600 etu between characters in ATR
tda_writeregister(TOC,0x00);
delay_us(5);
tda_writeregister(TOR3,0x25);
delay_us(5);
tda_writeregister(TOR2,0x80);
delay_us(5);
tda_writeregister(TOR1,0x00);
delay_us(5);
// Start timer
tda_writeregister(TOC,0x61);
}
else // mode is EMV
{
// Set up timer for 9600 etu between characters in ATR, and
// maximum of 19200 etu for whole ATR
tda_writeregister(TOC,0x05);
tda_writeregister(TOR3,0x25);
tda_writeregister(TOR2,0x80);
tda_writeregister(TOR1,0xC0);
// Start timer
tda_writeregister(TOC,0x65);
}//end if
//printk("Getting ATR\n");
index = 0;
while (!done)
{
// Read UART status
USRval = tda_readregister(USR);
{
// If receive buffer full
if (USRval & USR_TBE_RBF_MASK)
{
// Read and store ATR byte
val = tda_readregister(URR);
curByte = val;
rec_buf[index++] = val;
if (index == 1)
{
lastATR[currentSlot].TS = curByte;
if ((curByte != 0x3f) && (curByte != 0x3b))
{
tda_powerdown();
return ERR_POWERUP_ATR_INVALID;
}
check = 0;
}
else
check ^= curByte;
if (index == 2)
{
historicalBytes = curByte & 0x0F;
expectedCharacters = curByte & 0xF0;
lastATR[currentSlot].T0 = curByte;
}
if (index > 2)
{
switch(expectedCharacters)
{
case 0x00:
// Historical characters
historicalBytes--;
lastATR[currentSlot].Historical[lastATR[currentSlot].HistoricalLength++] = curByte;
if (historicalBytes == 0)
{
if (T == 0)
{
done = 1;
}
else
expectedCharacters = 0x01; // Go to checksum state
}
break;
case 0x01:
// TCK case
lastATR[currentSlot].TCK = curByte;
done = 1;
break;
case 0x10:
case 0x30:
case 0x50:
case 0x70:
case 0x90:
case 0xB0:
case 0xD0:
case 0xF0:
// TA case
expectedCharacters &= 0xE0;
lastATR[currentSlot].TA[interfaceIteration] = curByte;
break;
case 0x20:
case 0x60:
case 0xA0:
case 0xE0:
// TB case
expectedCharacters &= 0xD0;
lastATR[currentSlot].TB[interfaceIteration] = curByte;
break;
case 0x40:
case 0xC0:
// TC case
expectedCharacters &= 0xB0;
lastATR[currentSlot].TC[interfaceIteration] = curByte;
break;
case 0x80:
// TD case
expectedCharacters=(curByte&0xF0);
// Handle zero historical characters
if ((expectedCharacters == 0x00) && (historicalBytes == 0))
{
if (T == 0)
{
done = 1;
}
else
expectedCharacters = 0x01;
}
lastATR[currentSlot].TD[interfaceIteration] = curByte;
// If we get TD1, we have the first protocol selection
if ((interfaceIteration==1))
{
T = curByte & 0x0F;
}
else
{
// Changing protocols is only valid under ISO (not allowed in EMV)
if (mode == POWERUP_ISO)
{
if ((curByte & 0x0F) != T)
{
T = curByte & 0x0F;
}
}
else
return ERR_POWERUP_ATR_INVALID; // You cannot change T protocol under EMV
}
interfaceIteration++;
break;
default:
tda_powerdown();
return ERR_POWERUP_ATR_INVALID;
break;
}
}
if (mode == POWERUP_ISO)
{
// Reset timer for 9600 etu between characters in ATR
tda_writeregister(TOC,0x00);
delay_us(5);
tda_writeregister(TOR3,0x25);
delay_us(5);
tda_writeregister(TOR2,0x80);
delay_us(5);
tda_writeregister(TOR1,0x00);
delay_us(5);
// Start timer
tda_writeregister(TOC,0x61);
}
else // mode is EMV
{
// Set up timer for 9600 etu between characters in ATR
// Don't modify TOR1 as it is in auto-reload mode.
tda_writeregister(TOC,0x05);
tda_writeregister(TOR3,0x25);
tda_writeregister(TOR2,0x80);
// Start timer
tda_writeregister(TOC,0x65);
}
}
}
// Read Timer status
if (USRval & USR_TOL3_MASK)
{
printk("Character waiting timeout\n");
tda_powerdown();
return ERR_POWERUP_ATR_TIMEOUT;
}
if ((mode == POWERUP_EMV) && (USRval & USR_TOL1_MASK))
{
// If 192 ETU rollover, increment total count
etucount++;
// If we exceed 192 * 100 or 19200 etu, we fail as the whole ATR has not come
if (etucount > 100)
{
printk("ATR waiting timeout\n");
tda_powerdown();
return ERR_POWERUP_ATR_TIMEOUT;
}
}
}//end !done
// If we are in T=1 protocol, we get a LRC (xor checksum) at the end
if (T == 1)
{
if (check != 0)
{
printk("LRC failed: 0x%2x\n",check);
tda_powerdown();
return ERR_POWERUP_ATR_CRC_FAILURE;
}
}
// Set ATR length for the ATR received
*rec_len = index;
// Set T protocol mode
TMode[currentSlot] = T;
// Set the 8007 UCR1.PROT mode according to T value
val = tda_readregister(UCR1);
if (T == 0)
tda_writeregister(UCR1,val & ~UCR1_PROT_MASK);
else
tda_writeregister(UCR1,val | UCR1_PROT_MASK);
// Set extra guard time if present in TC1, else use guard time of 0
if (lastATR[currentSlot].TC[1] != -1)
tda_writeregister(GTR,lastATR[currentSlot].TC[1]);
else
tda_writeregister(GTR,0xff);
// Set WWT if present in TC2 (only used for T=0), ISO7816 8.2
if (lastATR[currentSlot].TC[2] != -1)
WWT[currentSlot] = lastATR[currentSlot].TC[2] * 960;
else
WWT[currentSlot] = 960 * 10;
printk("WWT: %ld\n",WWT[currentSlot]);
if (mode == POWERUP_EMV)
{
if (lastATR[currentSlot].TB[3] == -1)
{
// FIXME: Should we power down here? It is an EMV violation
tda_powerdown();
return ERR_POWERUP_ATR_INVALID;
}
else
{
val = lastATR[currentSlot].TB[i] & 0x0F;
// Fail if CWI is out of range
if (val > 5)
{
// FIXME: Should we power down here? It is an EMV violation
tda_powerdown();
return ERR_POWERUP_ATR_INVALID;
}
val = (lastATR[currentSlot].TB[i] & 0x0F) >> 4;
// Fail if BWI is out of range
if (val > 4)
{
// FIXME: Should we power down here? It is an EMV violation
tda_powerdown();
return ERR_POWERUP_ATR_INVALID;
}
}
}
// Set default values for CWT and BWT, ISO7816 9.5.3.1 and 9.5.3.2
CWT[currentSlot] = 11 + (1 << 13);
for (i = 3;i < 8;i++)
{
// Set CWT and BWT if present in TBi
// FIXME: Check this algorithm again!
if (lastATR[currentSlot].TB[i] != -1)
{
val = lastATR[currentSlot].TB[i] & 0x0F;
CWT[currentSlot] = 11 + (1 << val);
val = (lastATR[currentSlot].TB[i] & 0x0F) >> 4;
if (val > 9)
{
// FIXME: Should we power down here? It is an ISO7816 violation.
tda_powerdown();
return ERR_POWERUP_ATR_INVALID;
}
break;
}
}
printk("CWT: %ld\n",CWT[currentSlot]);
return 0;
}
/*************************************************************************
功能:
参数:
返回值:-1: error
0: OK
**************************************************************************/
static int tda_powerdown(void)
{
u8 val;
// Power down the card
val = tda_readregister(PCR);
tda_writeregister(PCR,val & ~PCR_START_MASK);
return 0;
}
/*************************************************************************
功能:check card
参数:
返回值:-1: error
0: OK
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -