📄 ds8007.c.bak
字号:
/*---------------------------------------------------------------------------
* Copyright (C) 2004 Dallas Semiconductor Corporation, All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Dallas Semiconductor
* shall not be used except as stated in the Dallas Semiconductor
* Branding Policy.
* ---------------------------------------------------------------------------
*/
/**
* \file ds8007.c
* \brief Interface library for Dallas Semiconductor's DS8007 smartcard interface chip
*
* This library contains routines required to communicate with smartcards
* via an DS8007 while conforming to:
* ISO 7816
* EMV 4.1
*
*/
#include <stdio.h>
#include <string.h>
#include <reg5000.h>
#include <absacc.h>
#include "DS8007.h"
#define DEBUG 1
void clearATRstruct(struct ATR*);
int16_t dssc_ATRsequence(uint8_t);
uint8_t workingBuffer[512];
uint8_t ATRLength[CARD_SLOTS];
struct ATR lastATR[CARD_SLOTS];
uint8_t TMode[CARD_SLOTS]; // T=0 or T=1
uint32_t WWT[CARD_SLOTS]; // Work wait time
uint32_t CWT[CARD_SLOTS]; // Character wait time
uint32_t BWT[CARD_SLOTS]; // Block wait time
uint8_t EDCtype[CARD_SLOTS];
uint8_t NAD[CARD_SLOTS]; // Node address byte to use when communicating in T=1
uint8_t IFSC[CARD_SLOTS]; // Maximum segment length when sending to card in T=1
uint8_t currentSlot = 0;
/*
Dump formatted contents of ATR struct
*/
void dumpATRStruct(struct ATR myatr)
{
int i;
printf("ATR\n");
printf("TS: %02bx\n",(uint8_t)myatr.TS);
printf("T0: %02bx\n",(uint8_t)myatr.T0);
for (i = 1;i < 8;i++)
{
if (myatr.TA[i] != -1)
printf("TA%d: %02bx\n",i,(uint8_t)myatr.TA[i]);
if (myatr.TB[i] != -1)
printf("TB%d: %02bx\n",i,(uint8_t)myatr.TB[i]);
if (myatr.TC[i] != -1)
printf("TC%d: %02bx\n",i,(uint8_t)myatr.TC[i]);
if (myatr.TD[i] != -1)
printf("TD%d: %02bx\n",i,(uint8_t)myatr.TD[i]);
}
for (i = 0;i < myatr.HistoricalLength;i++)
{
printf("%02bx ",myatr.Historical[i]);
}
printf("\n");
if (myatr.TCK != -1)
printf("TCK: %02bx\n",(uint8_t)myatr.TCK);
}
/*
Used to clear the ATR struct before card power up.
*/
void clearATRStruct(struct ATR *myatr)
{
memset(myatr,0xFF,sizeof(struct ATR));
myatr->HistoricalLength = 0;
}
/*
CCITT CRC 16
X^16+X^12+X^5+1
Be sure to use 0xFFFF as initial crc value.
*/
uint16_t update_crc(uint8_t value, uint16_t crc)
{
int i;
uint16_t newval = value << 8;
for (i = 0;i < 8;i++)
{
if ((crc ^ newval) & 0x8000)
{
crc <<= 1;
crc ^= 0x1021;
}
else
{
crc <<= 1;
}
newval <<= 1;
}
return crc;
}
/*
Read a byte from the UART or timeout after BWT (T=1), CWT (T=1) or WWT (T=0).
*/
int16_t readByte()
{
uint8_t val;
uint32_t timeout;
while(!(dssc_readregister(MSR) & MSR_TBE_RBF_MASK))
{
val = dssc_readregister(USR);
if (val & USR_PE_MASK)
{
return ERR_RECEIVE_PARITY;
}
if (val & (USR_TOL3_MASK|USR_TOL2_MASK|USR_TOL1_MASK))
{
return ERR_RECEIVE_TIMEOUT;
}
}
// Read and store byte
val = dssc_readregister(URR);
if (TMode[currentSlot] == 0)
timeout = WWT[currentSlot]; // Use WWT for T=0
else
timeout = CWT[currentSlot]; // Use CWT for T=1
// Set up timer for 24 bit timer, start immediately
dssc_writeregister(TOC,0x00);
dssc_writeregister(TOR3,timeout >> 16);
dssc_writeregister(TOR2,timeout >> 8);
dssc_writeregister(TOR1,timeout);
dssc_writeregister(TOC,0x68);
return val;
}
/*
Write a byte and leave the DS8007 in transmit mode
*/
void writeByte(uint8_t onebyte)
{
uint8_t val;
val = dssc_readregister(UCR1);
// set T bit
dssc_writeregister(UCR1,val | UCR1_T_R_MASK);
dssc_writeregister(UTR,onebyte);
// wait for byte to go out
while (!(dssc_readregister(USR) & USR_TBE_RBF_MASK));
}
/*
Write a byte and put the DS8007 in receive mode
*/
void writeLastByte(uint8_t onebyte)
{
uint8_t val;
uint32_t timeout;
if (TMode[currentSlot] == 0)
timeout = WWT[currentSlot]; // Use WWT for T=0
else
timeout = BWT[currentSlot]; // Use BWT for T=1
// Set up timer for 24 bit timer, edge trigger start
dssc_writeregister(TOC,0x00);
dssc_writeregister(TOR3,timeout >> 16);
dssc_writeregister(TOR2,timeout >> 8);
dssc_writeregister(TOR1,timeout);
dssc_writeregister(TOC,0x7C);
val = dssc_readregister(UCR1);
// set LCT and T bit
dssc_writeregister(UCR1,val | (UCR1_T_R_MASK|UCR1_LCT_MASK));
dssc_writeregister(UTR,onebyte);
// wait for byte to go out
while (!(dssc_readregister(USR) & USR_TBE_RBF_MASK));
}
/*
Generate Error Data Check value depending on EDC type
*/
uint16_t generateEDC(uint8_t type,uint8_t onebyte,uint16_t value)
{
if (type == EDC_TYPE_LRC)
{
return (value ^ onebyte);
}
else // type = CRC
{
return update_crc(onebyte,value);
}
}
/*
Send a T=1 formatted block.
Formats T=1 packet from raw input data. Length must already be
within the requirements of the destination smart card.
*/
void sendBlock(uint8_t NAD,uint8_t PCB,int16_t length,uint8_t *buffer,uint8_t type)
{
int i;
uint16_t EDC;
if (type == EDC_TYPE_LRC)
{
EDC = 0;
}
else // type = CRC
{
EDC = 0xFFFF;
}
writeByte(NAD);
EDC = generateEDC(type,NAD,EDC);
writeByte(PCB);
EDC = generateEDC(type,PCB,EDC);
writeByte(length);
EDC = generateEDC(type,length,EDC);
for (i=0;i<length;i++)
{
writeByte(buffer[i]);
EDC = generateEDC(type,buffer[i],EDC);
}
if (type == EDC_TYPE_LRC)
{
writeLastByte(EDC);
}
else // type = CRC
{
writeByte(EDC);
writeLastByte(EDC>>8);
}
}
/*
Receive a T=1 formatted block.
This does a raw receive, it does not check sequence numbers.
*/
int16_t receiveBlock(uint8_t *rNAD,uint8_t *rPCB,uint8_t *rLEN,uint8_t *buffer,uint8_t type)
{
int16_t retval;
int16_t index = 0;
uint16_t EDC;
int16_t i;
uint8_t expectedLength;
// Get NAD, PCB, and Length
retval = readByte();
if (retval < 0) return retval;
*rNAD = retval;
retval = readByte();
if (retval < 0) return retval;
*rPCB = retval;
retval = readByte();
if (retval < 0) return retval;
*rLEN = retval;
// Add one to length for LRC
expectedLength = *rLEN+1;
// Add additional byte if using CRC
if (type == EDC_TYPE_CRC)
expectedLength++;
// Get all data bytes plus EDC (1 or 2 bytes at end)
for (i = 0;i < expectedLength;i++)
{
retval = readByte();
if (retval < 0)
{
return retval;
}
buffer[index++] = retval;
}
// Check the LRC or CRC
if (type == EDC_TYPE_LRC)
{
EDC = 0;
EDC = generateEDC(EDC_TYPE_LRC,*rNAD,EDC);
EDC = generateEDC(EDC_TYPE_LRC,*rPCB,EDC);
EDC = generateEDC(EDC_TYPE_LRC,*rLEN,EDC);
for (i = 0;i < index;i++)
{
EDC = generateEDC(EDC_TYPE_LRC,buffer[i],EDC);
}
if (EDC != 0)
{
return ERR_RECEIVE_LRC;
}
}
else // EDC is CRC
{
EDC = 0xFFFF;
EDC = generateEDC(EDC_TYPE_LRC,*rNAD,EDC);
EDC = generateEDC(EDC_TYPE_LRC,*rPCB,EDC);
EDC = generateEDC(EDC_TYPE_LRC,*rLEN,EDC);
for (i = 0;i < (index-2);i++)
{
EDC = generateEDC(EDC_TYPE_CRC,buffer[i],EDC);
}
if (((EDC >> 8) != buffer[index-2]) ||
((EDC & 0xFF) != buffer[index-1]))
{
return ERR_RECEIVE_CRC;
}
}
return *rLEN;
}
/*
Send an S block for setting IFSD (card terminal buffer size)
*/
int16_t dssc_sendsblockIFSD(uint8_t IFSD)
{
uint8_t buffer[1];
uint8_t rNAD,rPCB,rLEN;
uint8_t rbuffer[100];
buffer[0] = IFSD;
sendBlock(0,0xC1,1,buffer,EDCtype[currentSlot]);
receiveBlock(&rNAD,&rPCB,&rLEN,rbuffer,EDCtype[currentSlot]);
// If we do not get a confirmation response, fail.
if ((rPCB == 0xE1) && (rLEN == 1) && (rbuffer[0] == IFSD))
return 0;
else
return ERR_SETIFSD_FAILURE;
}
/*
Set Node address info for this card
*/
void dssc_setNAD(uint8_t value)
{
NAD[currentSlot] = value;
}
/*
Send a message using T=1 protocol
*/
int16_t dssc_sendAPDUT1(uint8_t *buffer,int16_t length,uint8_t *rbuffer)
{
int16_t maxSegLength = IFSC[currentSlot]; // Set by ATR (TA3), or default to 0x20
int16_t retval;
uint8_t sequenceNumber = 0;
uint8_t rNAD,rPCB,rLEN;
uint8_t tempbuffer[512];
while (length > maxSegLength)
{
// Send block with chaining mode, current sequence number, and maximum length.
sendBlock(NAD[currentSlot],sequenceNumber|0x20,maxSegLength,buffer,EDCtype[currentSlot]);
retval = receiveBlock(&rNAD,&rPCB,&rLEN,tempbuffer,EDCtype[currentSlot]);
if (retval < 0) return retval;
// Check for bad sequence number return
if ((rPCB ^ ((sequenceNumber>>2) ^ 0x10)) != 0x80)
{
return ERR_RECEIVE_SEQUENCENUM;
}
sequenceNumber ^= 0x40;
buffer += maxSegLength;
length -= maxSegLength;
}
// Send last (or only) block. Then, we can wait for the receive side.
sendBlock(NAD[currentSlot],sequenceNumber,length,buffer,EDCtype[currentSlot]);
retval = receiveBlock(&rNAD,&rPCB,&rLEN,tempbuffer,EDCtype[currentSlot]);
if (retval < 0) return retval;
memcpy(rbuffer,tempbuffer,rLEN);
return retval;
}
/*
Send a message using T=0 protocol
*/
int16_t dssc_sendAPDUT0(uint8_t *buffer,int16_t length,uint8_t *rbuffer)
{
int index;
int16_t rindex = 0;
uint8_t val;
uint8_t INS = buffer[1];
int retval;
// Write 5 byte command header
for (index = 0;index < 4;)
writeByte(buffer[index++]);
writeLastByte(buffer[index++]);
while (1)
{
// Get procedure byte
retval = readByte();
if (retval < 0)
{
return retval;
}
val = retval;
if ((val & 0xFE) == INS)
{
// ACK, send/receive all remaining bytes
if (index < length)
{
for (;index < (length-1);index++)
writeByte(buffer[index]);
if (index < length)
writeLastByte(buffer[index++]);
// NOTE: Does not support VPP state change
}
else
{
// Read bytes up to Lc/P3 + 2
rindex = 0;
while ( (rindex < (buffer[4] + 2)) && ((retval = readByte()) >= 0) )
{
rbuffer[rindex++] = retval;
}
// return any error.
if (retval < 0)
return retval;
break;
}
}
else if ((val & 0xFE) == ~INS)
{
if (index < length)
{
// ACK, send/receive one remaining byte
if (index < length)
writeLastByte(buffer[index++]);
// NOTE: Does not support VPP state change
}
else
{
// Read one byte or timeout????
retval = readByte();
if (retval < 0)
{
// If we get anything other than a timeout, return the error.
if (retval != ERR_RECEIVE_TIMEOUT)
return retval;
break;
}
else
rbuffer[rindex++] = retval;
}
}
else if (val == 0x60)
{
// NULL
}
else if (((val & 0xF0) == 0x60) || ((val & 0xF0) == 0x90))
{
// SW1, get SW2
rbuffer[rindex++]=val;
val = readByte();
if (retval < 0) return retval;
rbuffer[rindex++]=val;
break;
}
}
return rindex;
}
/*
Send a message using T=0 or T=1 protocol
*/
int16_t dssc_sendAPDU(uint8_t *buffer,int16_t length,uint8_t *rbuffer)
{
switch (TMode[currentSlot])
{
case 0:
return dssc_sendAPDUT0(buffer,length,rbuffer);
break;
case 1:
return dssc_sendAPDUT1(buffer,length,rbuffer);
break;
default:
return ERR_PROTOCOL_UNSUPPORTED;
break;
}
}
int16_t dssc_warmreset(uint8_t mode)
{
uint8_t val;
// Check for power status
val = dssc_readregister(PCR);
if (!(val & PCR_START_MASK))
return ERR_POWERUP_VOLTAGE_INVALID;
// Apply reset
val = dssc_readregister(PCR);
dssc_writeregister(PCR,val & ~PCR_RSTIN_MASK);
// Call common getATR routine
return dssc_ATRsequence(mode);
}
int16_t dssc_powerup(uint8_t mode, uint8_t voltage)
{
uint8_t val;
// Compile time setting of operating crystal frequency
#if ((CRYSTAL_FREQUENCY_8007 >= 1000000L) && (CRYSTAL_FREQUENCY_8007 <= 5000000L))
// Set smartcard clock to 1/1 crystal
dssc_writeregister(CCR,0x00);
#elif ((CRYSTAL_FREQUENCY_8007 >= 2000000L) && (CRYSTAL_FREQUENCY_8007 <= 10000000L))
// Set smartcard clock to 1/2 crystal
dssc_writeregister(CCR,0x01);
#elif ((CRYSTAL_FREQUENCY_8007 >= 4000000L) && (CRYSTAL_FREQUENCY_8007 <= 20000000L))
// Set smartcard clock to 1/4 crystal
dssc_writeregister(CCR,0x02);
#elif ((CRYSTAL_FREQUENCY_8007 >= 8000000L) && (CRYSTAL_FREQUENCY_8007 <= 40000000L))
// Set smartcard clock to 1/8 crystal
dssc_writeregister(CCR,0x03);
#else
// Set smartcard clock to 1/2 internal oscillator (about 1.44MHz)
// NOTE: Can only change CCR.2 when shifting to internal oscillator
dssc_writeregister(CCR,0x01);
dssc_writeregister(CCR,0x05);
// Wait for internal oscillator to engage (check the MSR.CLKSW bit on page 18)
do
{
val = dssc_readregister(MSR);
}
while (!(val & MSR_CLKSW_MASK));
#endif
// Set the power supply voltage
val = dssc_readregister(PCR);
// Clear 1.8V and 3V bits
dssc_writeregister(PCR,val & ~(PCR_3V_5V_MASK|PCR_1V8_MASK));
switch(voltage)
{
case POWERUP_5V:
// Do nothing
break;
case POWERUP_3V:
val = dssc_readregister(PCR);
// Set 3V bit
dssc_writeregister(PCR,val | PCR_3V_5V_MASK);
break;
case POWERUP_1p8V:
val = dssc_readregister(PCR);
// Set 1.8V bit
dssc_writeregister(PCR,val | PCR_1V8_MASK);
break;
default:
return ERR_POWERUP_VOLTAGE_INVALID;
break;
}
// Apply reset
val = dssc_readregister(PCR);
dssc_writeregister(PCR,val & ~PCR_RSTIN_MASK);
val = dssc_readregister(HSR);
do
{
// Power the card, RST low, C4 and C8 high
val = dssc_readregister(PCR);
dssc_writeregister(PCR,val | (PCR_C8_MASK|PCR_C4_MASK|PCR_START_MASK));
val = dssc_readregister(HSR);
if (val & (HSR_PRTL2_MASK|HSR_PRTL1_MASK|HSR_PRL2_MASK|HSR_PRL1_MASK|HSR_PTL_MASK))
{
dssc_powerdown();
return ERR_POWERUP_INTERRUPTED;
}
val = dssc_readregister(PCR);
}
while (!(val & PCR_START_MASK));
//return 1;
// Call common getATR routine
return dssc_ATRsequence(mode);
}
int16_t dssc_ATRsequence(uint8_t mode)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -