PC/SC (Personal Computer/Smart Card) specification, PC/SC specification as a standard interface between card reader and card and computer, realizes the interaction between card and card reader of different manufacturers.
The source code pcsc-lite running under Linux is http://pcsclite.alioth.debian.org/
There are demo routines
1. Establishing Resource Manager Context
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,LPCVOID pvReserved2, LPSCARDCONTEXT phContext); Note: This must be the first SCard function called in PC/SC applications, and all applications must establish their own context. Parameters: dwScope: Input Type: Represents the scope of context establishment, establishes local or remote connections, and currently supports SCARD_SCOPE_SYSTEM (completing device database operations in the system domain) pvReserved1: Input Type: Reserved, NULL pvReserved2: Input Type: Reserved, NULL phContext: Output type: Returns the created resource manager context Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h //@code SCARDCONTEXT hContext; LONG rv; rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &posContext); if(rv != SCARD_S_SUCCESS) { LOGE("SCardEstablishContext::failed!\n"); ret = ERROR_APP_CONTEXT; return ret; }
2. Get a list of card readers available in the system
LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,LPSTR mszReaders, LPDWORD pcchReaders); Explain: After creating the context, you can get a list of available card readers for system installation in the context Parameters: hContext: Input type; ScardEstablishContext() establishes a resource manager context that cannot be NULL mszGroups: Input type; the name of the card reader group, when NULL, means listing all card readers. mszReaders: Output type; the name of the card reader installed in the system, separated by' 0'and followed by two consecutive' 0' names pcchReaders: Input and Output Types; Length of mszReaders This function is used in a variety of ways, mainly to create space for the card reader list in different ways. 1. When mszReaders are NULL, calling SCardListReaders once gives pcchReaders the size of space they need to output mszReaders, and then applies for memory space by malloc. 2. When mszReaders are NULL and pcchReaders = SCARD_AUTOALLOCATE, SCardListReaders will automatically apply for memory, but they must be released using SCardFreeMemory(hContext, mszReaders) after use. 3. When mszReaders are not NULL, they need to be passed in their length with pcchReaders, and SCardListReaders will place the list of card readers in the applied space memory. Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h Here are three ways to create code examples: //@code1 SCARDCONTEXT hContext; LPSTR mszReaders; DWORD dwReaders; LONG rv; ... rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); mszReaders = malloc(sizeof(char)*dwReaders); rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); ... free(mszReaders); //@code2 SCARDCONTEXT hContext; LPSTR mszReaders; DWORD dwReaders; LONG rv; ... rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); dwReaders = SCARD_AUTOALLOCATE; rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); ... rv = SCardFreeMemory(hContext, mszReaders); //@code3 SCARDCONTEXT hContext; LPSTR mszReaders[512]; DWORD dwReaders; LONG rv; ... rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); dwReaders = sizeof(mszReaders); rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); ... Below is the pick-up code for the name of the card reader. char name[128][3]; ptr = mszReaders; int count = 0; while ((*ptr != '\0') && (dwReaders > 0) && (count < 3)) { strcpy(&name[0][count], ptr); lens = strlen(&name[0][count]); ptr += (lens + 1); dwReaders -= (lens + 1); count++; LOGD("SCardListReaders::Reader Count %d Name:%s\n", count, &name[0][count]); } 01-17 10:56:44.727: D/smartcardjni(2393): SCardListReaders::Reader Count 1 Name:ZNG Terminal2012-1402 00 00 01-17 10:56:44.727: D/smartcardjni(2393): SCardListReaders::Reader Count 2 Name:ZNG Terminal2012-1402 01 00
3. Insertion of monitoring cards
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,SCARD_READERSTATE *rgReaderStates, DWORD cReaders); Explain: Blocking monitor card insertion or status change Parameters: hContext: Input type; Resource Manager context established by ScardEstablishContext() dwTimeout: Input type; listen for wait time, 0 or INFINITE (0xFFFFFFFFFFFF) indicates permanent wait rgReaderStates: Input and output types; SCARD_READERSTATE structure cReaders: Input Type; Card Channel Number Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h typedef struct { const char *szReader; // card reader name void *pvUserData; // Private Data DWORD dwCurrent State; // Current State of Card Reader Events after DWORD dwEventState; //Reader status changes DWORD cbAtr; //ATR length unsigned char rgbAtr[MAX_ATR_SIZE];//ATR } SCARD_READERSTATE, *LPSCARD_READERSTATE; //@code SCARDCONTEXT hContext; SCARD_READERSTATE rgReaderStates[2]; LONG rv; ... rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); ... rgReaderStates[0].szReader = "Reader X"; rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE; rgReaderStates[1].szReader = "\\\\?PnP?\\Notification"; rgReaderStates[1].dwCurrentState = SCARD_STATE_UNAWARE; ... rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 2); printf("reader state: 0x%04X\n", rgReaderStates[0].dwEventState); printf("reader state: 0x%04X\n", rgReaderStates[1].dwEventState); If (rgReaderStates [0]. dwEventState & SCARD_STATE_PRESENT)// Card Insertion { } If (rgReaderStates [0]. dwEventState & SCARD_STATE_EMPTY)// Card Removal { } //@endcode
4. Connect Card Reader
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,LPDWORD pdwActiveProtocol); Description: After using this interface, the reader will power on and read ATR. Parameters: hContext: Input type; Resource Manager context established by ScardEstablishContext() szReader: Input Type: Reader Name to Connect dwShareMode: Input type: Connection type SCARD_SHARE_SHARED Multiple applications share the same smart card SCARD_SHARE_EXCLUSIVE Application Exclusive Smart Card SCARD_SHARE_DIRECT Private Type, No Access to Other Applications DwPreferred Protocols: Input Type: Protocol Type Used SCARD_PROTOCOL_T0 T=0 Protocol SCARD_PROTOCOL_T1 T=1 Protocol SCARD_PROTOCOL_RAW Original Protocol phCard: Output Type: Connection Handle of Card pdwActiveProtocol: Output Type: Actual Protocol SCARD_PROTOCOL_T0 Use the T=0 protocol. SCARD_PROTOCOL_T1 Use the T=1 protocol. Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
5. Obtain card status and ATR
LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,LPDWORD pcchReaderLen, LPDWORD pdwState,LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen); Explain: Parameters: hCard: Input type: Card connection handle established by SCardConnect() mszReaderName: Input and Output Type: Connected Reader Name pcchReaderLen: Input and output type: length of mszReaderName, using the same method as pcchReaders in SCardListReaders pdwState: Output Type: Current Status of Card Reader SCARD_UNKNOWN 0x0001 /**< Unknown state */ SCARD_ABSENT 0x0002 /**< Card is absent */ SCARD_PRESENT 0x0004 /**< Card is present */ SCARD_SWALLOWED 0x0008 /**< Card not powered */ SCARD_POWERED 0x0010 /**< Card is powered */ SCARD_NEGOTIABLE 0x0020 /**< Ready for PTS */ SCARD_SPECIFIC 0x0040 /**< PTS has been set */ pdwProtocol: Output Type: Current Protocol Type of Card Reader SCARD_PROTOCOL_T0 Use the T=0 protocol. SCARD_PROTOCOL_T1 Use the T=1 protocol. pbAtr: Output Type: ATR of Current Card pcbAtrLen: Input and output type: length of pbAtr, using the same method as pcchReaders in SCardListReaders Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h //@code ... dwAtrLen = sizeof(pbAtr); dwReaderLen = sizeof(pbReader); rv = SCardStatus(posReaderList.readerList[using_reader_id].hCard, pbReader, &dwReaderLen, &dwState, &dwProt, pbAtr, &dwAtrLen); if (rv != SCARD_S_SUCCESS) { LOGE("SCardStatus %s (0x%lX)\n" , pcsc_stringify_error(rv), rv); ret = SCARD_STATUS_FALSE; } LOGD("pbReader: %s\n", pbReader); LOGD("pbAtr: %s\n", pbAtr);
6. Data transmission of card reader
LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,LPDWORD pcbRecvLength); Description: APDU data transmission can be carried out after successful connection of slave card Parameters: hCard: Input type: Card connection handle established by SCardConnect() pioSendPci: Input and Output Type: A Pointer to the Header Structure of the Sending Instruction Protocol, defined by the SCARD_IO_REQUEST Structure pbSendBuffer: Input type: APPU instruction sent to card cbSendLength: Input type: APDU length pioRecvPci: Input and Output Type: A pointer to the received instruction protocol header structure, defined by the SCARD_IO_REQUEST structure and set to NULL if not returned pbRecvBuffer: Output Type: Data Returned from Card pcbRecvLength: Input and Output Type: Actual Size of pbRecvBuffer Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h typedef struct { unsigned long dwProtocol; /**< Protocol identifier */ unsigned long cbPciLength; /**< Protocol Control Inf Length */ }SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST; //@code rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); dwSendLength = sizeof(pbSendBuffer); dwRecvLength = sizeof(pbRecvBuffer); rv = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, dwSendLength,&pioRecvPci, pbRecvBuffer, &dwRecvLength);
7. Exclusive visits
This set of operations is used before and after SCardTransmit(), making the transmission operation safer and more reliable.
LONG SCardBeginTransaction(SCARDHANDLE hCard); Description: Start a transaction to prevent other applications from accessing smart cards Parameters: hCard: Input type: Card connection handle established by SCardConnect() LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition); Description: End a transaction and allow other reference programs to access smart cards Parameters: hCard: Input type: Card connection handle established by SCardConnect() dwDisposition input type: end of operation on card reader
8. Reconnect the card reader
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol); Description: Connect the card reader that is being connected again, equal to hot reset Parameters: hCard: Input type: Card connection handle established by SCardConnect() dwShareMode: Input type: Connection type SCARD_SHARE_SHARED Multiple applications share the same smart card SCARD_SHARE_EXCLUSIVE Application Exclusive Smart Card SCARD_SHARE_DIRECT Private Type, No Access to Other Applications DwPreferred Protocols: Input Type: Protocol Type Used SCARD_PROTOCOL_T0 T=0 Protocol SCARD_PROTOCOL_T1 T=1 Protocol SCARD_PROTOCOL_RAW Original Protocol dwInitialization: Input type: The operation specified by the card reader, often used for restart SCARD_LEAVE_CARD - Do nothing. SCARD_RESET_CARD - Reset the card (warm reset). SCARD_UNPOWER_CARD - Power down the card (cold reset). SCARD_EJECT_CARD - Eject the card. pdwActiveProtocol: Output Type: Actual Protocol Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h
9. Disconnect the card reader
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition); Description: disconnect card reader connection Parameters: hCard: Input type: Card connection handle established by SCardConnect() dwDisposition input type: operation of card reader when disconnected SCARD_LEAVE_CARD 0x0000 /**< Do nothing on close */ SCARD_RESET_CARD 0x0001 /**< Reset on close */ SCARD_UNPOWER_CARD 0x0002 /**< Power down on close */ SCARD_EJECT_CARD 0x0003 /**< Eject on close */ Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h //@code rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
10. Release context
LONG SCardReleaseContext(SCARDCONTEXT hContext); Description: Release resource manager context before application termination Parameters: hContext: Input type; Resource Manager context established by ScardEstablishContext() Return: Successful return to SCARD_S_SUCCESS Failure returns other values, defined in pcsclite.h
Sample code:
//***********************************
#define MAX_READER_COUNTS 3
typedef struct _strReaderListInfo
{
char reader[128];
int trans_begin;
SCARDHANDLE hCard;
DWORD dwActiveProtocol;
SCARD_IO_REQUEST pioSendPci;
SCARD_IO_REQUEST pioRecvPci;
}StrReaderListInfo, *pStrReaderListInfo;
typedef struct _strReaderList
{
int count;
StrReaderListInfo readerList[MAX_READER_COUNTS];
}StrReaderList, *pStrReaderList;
unsigned int posReaderId = 1; //readerid
StrReaderList posReaderList = {0};
SCARDCONTEXT posContext = 0;
DWORD posActiveProtocol[MAX_READER_COUNTS];
//Context initialization
unsigned int Pcscd_Init()
{
LOGD("%s",__FUNCTION__);
unsigned int ret = ERROR_NONE;
LONG rv = 0;
unsigned int lens = 0;
DWORD dwReaders;
unsigned char reader_list_buf[512];
pStrReaderListInfo pStrInfo;
unsigned char *ptr = NULL;
unsigned int tryAgain = 0;
START:
if(posContext != 0)
{
LOGE("SCardEstablishContext::Context has already been created,Release!\n");
rv = SCardReleaseContext(hContext);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardReleaseContext::failed!\n");
}
hContext = 0;
}
//Create context
memset(&posReaderList, 0, sizeof(StrReaderList));
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &posContext);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardEstablishContext::failed!\n");
ret = ERROR_APP_CONTEXT;
return ret;
}
LOGD("SCardEstablishContext::success!\n");
//Get the card reader list
dwReaders = sizeof(reader_list_buf);
rv = SCardListReaders(posContext, NULL, reader_list_buf, &dwReaders);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardListReaders::native failed!(0x%x)\n",rv);
if(posContext != 0)
{
SCardReleaseContext(posContext);
posContext = 0;
}
if(rv == SCARD_E_NO_READERS_AVAILABLE)
{
ret = ERROR_APP_REBOOT_POS;
}
else
{
ret = ERROR_APP_LISTREADER;
}
return ret;
}
reader_list_buf[dwReaders] = 0x00;
reader_list_buf[dwReaders + 1] = 0x00;
posReaderList.count = 0;
ptr = reader_list_buf;
while ((*ptr != '\0') && (dwReaders > 0))
{
pStrInfo = &posReaderList.readerList[posReaderList.count];
strcpy(pStrInfo->reader, ptr);
lens = strlen(pStrInfo->reader);
ptr += (lens + 1);
dwReaders -= (lens + 1);
// pStrInfo->hCard = 0;
posReaderList.count++;
LOGD("SCardListReaders::Reader Count %d Name:%s\n", posReaderList.count, pStrInfo->reader);
if(posReaderList.count >= MAX_READER_COUNTS)
{
break;
}
}
if (posReaderList.count < 2)
{
LOGE("[%d]::reader count = %d!!!\n",__LINE__,posReaderList.count);
SCardStopDeamon(posContext);
sleep(3);
if(posContext != 0)
{
SCardReleaseContext(posContext);
posContext = 0;
}
if(tryAgain == 0)
{
ret = ERROR_NONE;
tryAgain = 1;
LOGE("init try again");
goto START;
}
else
{
ret = ERROR_APP_LISTREADER;
return ret;
}
}
LOGD("SCardListReaders::success!\r\n");
ret = ERROR_NONE;
return ret;
}
//Release context
unsigned int Pcscd_Release()
{
LOGD("%s",__FUNCTION__);
unsigned int ret = ERROR_NONE;
int rv;
pStrReaderListInfo pStrInfo;
if(posContext == 0)
{
LOGE("SCardReleaseContext::Context has not been created!\n");
ret = ERROR_NONE;
return ret;
}
memset(&posReaderList, 0, sizeof(StrReaderList));
rv = SCardReleaseContext(posContext);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardReleaseContext::native failed!\n");
posContext = 0;
ret = ERROR_APP_CONTEXT;
return ret;
}
posContext = 0;
LOGD("SCardReleaseContext::success!\n");
ret = ERROR_NONE;
return ret;
}
//Disconnect card connection
int PBOC_DisConnect(unsigned int using_reader_id)
{
LOGD("%s(%d)",__FUNCTION__,using_reader_id);
LONG rv;
pStrReaderListInfo pStrInfo;
if(using_reader_id < 0 || using_reader_id >= posReaderList.count)
{
LOGE("[%d]reader id is wrong(%d)\n",__LINE__, using_reader_id);
// Nok_Reason = ErrorReason_PCSCD_READERS_ID;
return FALSE;
}
pStrInfo = &posReaderList.readerList[using_reader_id];
if(pStrInfo->trans_begin == 1)
{
rv = SCardEndTransaction(pStrInfo->hCard,SCARD_LEAVE_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::SCardEndTransaction: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
pStrInfo->trans_begin = 0;
}
if(pStrInfo->hCard != 0)
{
rv = SCardDisconnect(pStrInfo->hCard,SCARD_UNPOWER_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::SCardDisconnect: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
pStrInfo->hCard = 0;
}
return TRUE;
}
int PBOC_OpenCard(unsigned char* pAtr,unsigned int * pAtrlen)
{
int ret;
LOGD("%s",__FUNCTION__);
//Check card
DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
BYTE pbAtr[MAX_ATR_SIZE] = "";
char pbReader[MAX_READERNAME] = "";
pStrReaderListInfo pStrInfo;
SCARD_READERSTATE rgReaderStates[1];
pStrInfo = &posReaderList.readerList[posReaderId];
dwAtrLen = sizeof(pbAtr);
dwReaderLen = sizeof(pbReader);
smart_card_type = 0;
rgReaderStates[0].szReader = posReaderList.readerList[posReaderId].reader;
rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
//Check for card insertion
ret = SCardGetStatusChange(posContext,INFINITE,rgReaderStates,1);
if (ret != SCARD_S_SUCCESS)
{
printf("SCardGetStatusChange err\r\n");
return -1;
}
LOGD("SCardGetStatusChange ok\r\n");
LOGD("rgReaderStates[0].dwEventState == %ld\r\n",rgReaderStates[0].dwEventState);
if(rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT)//Stuck in
{
ret= SCardConnect(posContext, pStrInfo->reader, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &pStrInfo->hCard, &posActiveProtocol[posReaderId]);
if (ret == SCARD_S_SUCCESS)
{
ret = SCardStatus(pStrInfo->hCard, pbReader, &dwReaderLen, &dwState, &dwProt,pbAtr, &dwAtrLen);
if (ret != SCARD_S_SUCCESS)
{
return -1;
}
MyPrintfBuff("CardAtr:",pbAtr, dwAtrLen);
//judge ATR Is it a non-contact card?
if((pbAtr[2] == 0x81 && pbAtr[3] == 0x01)||(pbAtr[2] == 0x11 && pbAtr[3] == 0x01) )
{
smart_card_type = 2;
}
//Judgment of ATR Non-contact Cards
else if((pbAtr[1] == 0x70 && pbAtr[2] == 0x11) )
{
smart_card_type = 3;
}
//Determine whether ATR is a contact card?
else if(!((pbAtr[2] == 0x81 && pbAtr[3] == 0x01)||(pbAtr[2] == 0x11 && pbAtr[3] == 0x01) ||(pbAtr[1] == 0x60 && pbAtr[2] == 0x00)))
{
smart_card_type = 1;
}
else
{
smart_card_type = -1;
}
switch(posActiveProtocol[posReaderId])
{
case SCARD_PROTOCOL_T0:
pStrInfo->pioSendPci = *SCARD_PCI_T0;
LOGD("using T0");
break;
case SCARD_PROTOCOL_T1:
pStrInfo->pioSendPci = *SCARD_PCI_T1;
LOGD("using T1");
break;
default:
LOGE("Unknown protocol. No card present?\n");
}
MyMemcpy(pAtr,pbAtr, dwAtrLen);
*pAtrlen = dwAtrLen;
}
else
{
}
}
return smart_card_type;
}
//Establish card connection and prepare for transmission
int PBOC_Connect(int using_reader_id)
{
LOGD("%s(%d)",__FUNCTION__,using_reader_id);
LONG rv;
int ret = TRUE;
DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
BYTE pbAtr[MAX_ATR_SIZE] = "";
char pbReader[MAX_READERNAME] = "";
pStrReaderListInfo pStrInfo;
unsigned int i;
unsigned int counts = 0;
if(using_reader_id < 0 || using_reader_id >= posReaderList.count)
{
LOGE("[%d]reader id is wrong(%d)\n",__LINE__, using_reader_id);
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_READERS_ID;
goto ERROR;
}
pStrInfo = &posReaderList.readerList[using_reader_id];
/* connect to a reader (even without a card) */
LOGD("[%d]Using reader: %s\n",__LINE__, posReaderList.readerList[using_reader_id].reader);
while(1)
{
if(posReaderList.readerList[using_reader_id].hCard != 0)
{
LOGD("connected(%d)",(int)posActiveProtocol[using_reader_id]);
rv = SCARD_S_SUCCESS;
LOGD("SCardReconnect");
rv = SCardReconnect(posReaderList.readerList[using_reader_id].hCard, /*SCARD_SHARE_SHARED*/SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,SCARD_RESET_CARD, (DWORD*)&posActiveProtocol);
}
else
{
LOGD("connect");
rv = SCardConnect(posContext, posReaderList.readerList[using_reader_id].reader, /*SCARD_SHARE_EXCLUSIVE*/SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &posReaderList.readerList[using_reader_id].hCard, &posActiveProtocol[using_reader_id]);
}
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardConnect %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
counts++;
if(rv == SCARD_E_SHARING_VIOLATION)
{
if(counts < 10)
{
usleep(500*1000);
LOGE("reader is busy,wait 500ms try again(%d)",counts);
continue;
}
}
else if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
if(counts < 2)
{
LOGE("try again(%d)",counts);
continue;
}
}
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_CONNECT_READERS;
goto ERROR_NOTHING;
}
else
{
break;
}
}
pStrInfo->dwActiveProtocol = posActiveProtocol[using_reader_id];
/* get card status */
dwAtrLen = sizeof(pbAtr);
dwReaderLen = sizeof(pbReader);
rv = SCardStatus(posReaderList.readerList[using_reader_id].hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
pbAtr, &dwAtrLen);
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardStatus %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_GET_READERS_STATUS;
goto ERROR;
}
LOGD(" State: 0x%04lX\n", dwState);
if (dwState & SCARD_ABSENT)
{
LOGE("No card inserted\n");
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_NO_CARDS_INSIDE;
goto ERROR;
}
switch(posActiveProtocol[using_reader_id])
{
case SCARD_PROTOCOL_T0:
pStrInfo->pioSendPci = *SCARD_PCI_T0;
LOGD("using T0");
break;
case SCARD_PROTOCOL_T1:
pStrInfo->pioSendPci = *SCARD_PCI_T1;
LOGD("using T1");
break;
default:
LOGE("Unknown protocol. No card present?\n");
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_NO_PROTOCOLS_SELECT;
goto ERROR;
}
rv = SCardBeginTransaction(posReaderList.readerList[using_reader_id].hCard);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("SCardBeginTransaction %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_BEGIN_TRANSACTION;
goto ERROR;
}
pStrInfo->trans_begin = 1;
LOGD("SCardBeginTransaction::success!\n");
return ret;
ERROR:
rv = SCardDisconnect(posReaderList.readerList[using_reader_id].hCard,SCARD_UNPOWER_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::SCardDisconnect: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
ERROR_NOTHING:
return ret;
}
//Connect the card and get ATR
int PBOC_PowerOn(int using_reader_id,unsigned char* pAtr,unsigned int * pAtrlen)
{
LOGD("%s",__FUNCTION__);
LONG rv;
int ret = TRUE;
DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
BYTE pbAtr[MAX_ATR_SIZE] = "";
char pbReader[MAX_READERNAME] = "";
pStrReaderListInfo pStrInfo;
unsigned int i;
unsigned int counts = 0;
if(using_reader_id < 0 || using_reader_id >= posReaderList.count)
{
LOGE("[%d]reader id is wrong(%d)\n",__LINE__, using_reader_id);
ret = FALSE;
return ret;
}
pStrInfo = &posReaderList.readerList[using_reader_id];
/* connect to a reader (even without a card) */
LOGD("[%d]Using reader: %s\n",__LINE__, posReaderList.readerList[using_reader_id].reader);
while(1)
{
if(pStrInfo->hCard != 0)
{
LOGD("SCardConnect(%d)",(int)posActiveProtocol[using_reader_id]);
rv = SCARD_S_SUCCESS;
//LOGD("SCardReconnect");
//rv = SCardReconnect(pStrInfo->hCard, /*SCARD_SHARE_SHARED*/SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
// SCARD_RESET_CARD, &dwposActiveProtocol);
}
else
{
LOGD("SCardConnect");
rv = SCardConnect(posContext, pStrInfo->reader, /*SCARD_SHARE_SHARED*/SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &pStrInfo->hCard, &posActiveProtocol[using_reader_id]);
}
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardConnect %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
counts++;
if(rv == SCARD_E_SHARING_VIOLATION)
{
if(counts < 10)
{
usleep(500*1000);
LOGE("reader is busy,wait 500ms try again(%d)",counts);
continue;
}
}
else if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
usleep(2000*1000);
Pcscd_Init();
if(counts < 2)
{
LOGE("try again(%d)",counts);
continue;
}
}
ret = FALSE;
goto ERROR_NOTHING;
}
else
{
break;
}
}
pStrInfo->dwActiveProtocol = posActiveProtocol[using_reader_id];
/* get card status */
dwAtrLen = sizeof(pbAtr);
dwReaderLen = sizeof(pbReader);
//Get card status information
rv = SCardStatus(pStrInfo->hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
pbAtr, &dwAtrLen);
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardStatus %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = FALSE;
goto ERROR;
}
LOGD(" State: 0x%04lX\n", dwState);
if (dwState & SCARD_ABSENT)
{
LOGE("No card inserted\n");
ret = FALSE;
goto ERROR;
}
switch(posActiveProtocol[using_reader_id])
{
case SCARD_PROTOCOL_T0:
pStrInfo->pioSendPci = *SCARD_PCI_T0;
LOGD("using T0");
break;
case SCARD_PROTOCOL_T1:
pStrInfo->pioSendPci = *SCARD_PCI_T1;
LOGD("using T1");
break;
default:
LOGE("Unknown protocol. No card present?\n");
ret = FALSE;
goto ERROR;
}
MyMemcpy(pbAtr,pAtr,dwAtrLen);
*pAtrlen = dwAtrLen;
//Prepare for transmission status
rv = SCardBeginTransaction(pStrInfo->hCard);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("SCardBeginTransaction %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = FALSE;
goto ERROR;
}
pStrInfo->trans_begin = 1;
LOGD("SCardBeginTransaction::success!\n");
return ret;
ERROR:
rv = SCardDisconnect(pStrInfo->hCard,SCARD_UNPOWER_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::SCardDisconnect: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
ERROR_NOTHING:
return ret;
}
int PBOC_PowerOff(int using_reader_id)
{
LOGD("%s",__FUNCTION__);
LONG rv;
pStrReaderListInfo pStrInfo;
pStrInfo = &posReaderList.readerList[using_reader_id];
//End of transmission
if(pStrInfo->trans_begin == 1)
{
rv = SCardEndTransaction(pStrInfo->hCard,SCARD_LEAVE_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
ResetReader();
}
LOGE("[%d]::SCardEndTransaction: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
pStrInfo->trans_begin = 0;
}
//Disconnect
if(posReaderList.readerList[using_reader_id].hCard != 0)
{
LOGD("SCardDisconnect");
rv = SCardDisconnect(pStrInfo->hCard,SCARD_UNPOWER_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::CloudPos_PowerOff: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
pStrInfo->hCard = 0;
}
return rv;
}
int PBOC_APDU_SendAPI(unsigned int using_reader_id,unsigned char * bSendBuffer,unsigned int send_length,unsigned char * bRecvBuffer,unsigned int *length)
{
LOGD("%s",__FUNCTION__);
LONG rv;
int ret = 0;
unsigned int i;
unsigned char temp[64] = {0};
//char debug_buffer[512] = {0};
pStrReaderListInfo pStrInfo;
if(using_reader_id < 0 || using_reader_id >= posReaderList.count)
{
LOGE("[%d]reader id is wrong(%d)\n",__LINE__, using_reader_id);
ret = FALSE;
goto SEND_ERROR;
}
#ifdef SE_KL81
if(send_length%64 == 54)
{
LOGI("fill 0xFFFF");
bSendBuffer[send_length] = 0xFF;
bSendBuffer[send_length+1] = 0xFF;
send_length += 2;
}
#endif
pStrInfo = &posReaderList.readerList[using_reader_id];
/* APDU select applet */
LOGD("[%d]::PBOC_APDU_SendAPI()::Dev send to card:\n",__LINE__);
if(send_length >= 256)
{
LOGD("send_length is bigger then print buffer length");
}
else
{
MyPrintfBuff("APDU_send:",bSendBuffer, send_length);
}
*length = MAX_BUFFER_SIZE_SZ;
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
if(memcmp(&pStrInfo->pioSendPci,SCARD_PCI_T0,sizeof(pStrInfo->pioSendPci)) == 0)
{
LOGD("using T0");
}
else if(memcmp(&pStrInfo->pioSendPci,SCARD_PCI_T1,sizeof(pStrInfo->pioSendPci)) == 0)
{
LOGD("using T1");
}
else
{
LOGD("using None");
}
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD)send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD *)length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
LOGE("SCardTransmit error,try again!(0x%08x)(%d)",(unsigned int)rv,*length);
snprintf(temp,sizeof(temp),"SCardTransmit error(0x%x)",(unsigned int)rv);
sleep(1);
*length = MAX_BUFFER_SIZE_SZ;
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD )send_length,
&pStrInfo->pioRecvPci, bRecvBuffer,(DWORD *) length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("(rv = 0x%08x)",(unsigned int)rv);
snprintf(temp,sizeof(temp),"SCardTransmit error again(0x%x)",(unsigned int)rv);
ret = FALSE;
goto SEND_ERROR;
}
}
LOGD("[%d]::Card response to dev:\n",__LINE__);
if(*length >= 5120)
{
LOGD("length is bigger then print buffer length.");
}
else
{
MyPrintfBuff("APDU_Recv:",bRecvBuffer, *length);
}
if(*length > 54 && (*length+10)%64 == 2 && (bRecvBuffer[*length-2] == 0xFF && bRecvBuffer[*length-1] == 0xFF))
{
LOGD("clean FFFF");
(*length) -= 2;
}
PRASE_CARD_RETURN_STATUS:
if(bRecvBuffer[*length-2] == 0x61)
{
LOGD("[%d]::Dev 0x61 to card:\n",__LINE__);
memset(bSendBuffer,0x00,MAX_BUFFER_SIZE_SZ);
usleep(100*1000);
LOGD("[%d]::Card with the remaining returned to %02x%02x\n",__LINE__,bRecvBuffer[0],bRecvBuffer[1]);
send_length = 5;//00 C0 00 00 2A
memcpy(bSendBuffer, "\x00\xC0\x00\x00",send_length-1);
bSendBuffer[send_length-1] = bRecvBuffer[*length-1];
LOGD("[%d]::Dev send to card:\n",__LINE__);
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
*length = MAX_BUFFER_SIZE_SZ;
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD )send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD *)length);
MyPrintfBuff("APDU_Recv:",bRecvBuffer, *length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
LOGE("SCardTransmit error,try again!");
snprintf(temp,sizeof(temp),"SCardTransmit error(0x%x)",(unsigned int)rv);
*length = MAX_BUFFER_SIZE_SZ;
sleep(1);
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD )send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD *)length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("SCardTransmit error!");
snprintf(temp,sizeof(temp),"SCardTransmit error again(0x%x)",(unsigned int)rv);
ret = FALSE;
goto SEND_ERROR;
}
}
LOGD("[%d]::Card response to dev:\n",__LINE__);
//memset(debug_buffer,0,sizeof(debug_buffer));
if(*length >= 5120)
{
LOGE("length is bigger then print buffer length");
}
else
{
// myAsciiToHex(bRecvBuffer, debug_buffer, *length);
MyPrintfBuff("APDU_Recv:",bRecvBuffer, *length);
}
if(*length > 54 && (*length+10)%64 == 2 && (bRecvBuffer[*length-2] == 0xFF && bRecvBuffer[*length-1] == 0xFF))
{
LOGD("clean FFFF");
(*length) -= 2;
}
}
else if(bRecvBuffer[*length-2] == 0x6C)
{
LOGD("[%d]::Dev 0x6C to card:\n",__LINE__);
bSendBuffer[send_length-1] = bRecvBuffer[*length-1];
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer,(DWORD ) send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD *)length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
LOGE("SCardTransmit error,try again!");
*length = MAX_BUFFER_SIZE_SZ;
sleep(1);
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD )send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD*)length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
// Nok_Reason = ErrorReason_PCSCD_TRANSMIT;
ret = FALSE;
goto SEND_ERROR;
}
}
if(*length > 54 && (*length+10)%64 == 2 && (bRecvBuffer[*length-2] == 0xFF && bRecvBuffer[*length-1] == 0xFF))
{
LOGD("clean FFFF");
(*length) -= 2;
}
goto PRASE_CARD_RETURN_STATUS;
}
else if((bRecvBuffer[*length-2] == 0x6A )&&( bRecvBuffer[*length-1] == 0x83))
{
LOGD("[%d]::Card response 6A83",__LINE__);
}
else if((bRecvBuffer[*length-2] != 0x90)||(bRecvBuffer[*length-1] != 0x00))
{
LOGE("Cards respont isn't 0x9000(0x%02X%02X)!\n",bRecvBuffer[*length-2],bRecvBuffer[*length-1]);
}
else
{
//LOGD("[%d]::Card response to dev:\n",__LINE__);
//memset(debug_buffer,0,sizeof(debug_buffer));
if(*length >= 5120)
{
LOGE("length is bigger then print buffer length");
}
else
{
//myAsciiToHex(bRecvBuffer, debug_buffer, *length);
//MyPrintfBuff("APDU_Recv:",bRecvBuffer, *length);
}
}
SEND_ERROR:
return ret;
}
//main.c
//Using test program to communicate between PSAM card and ICC card
ret = Pcscd_Init();
if(ret != 0)//Card reader not found
{
return -1;
}
while(1)
{
printf("Please input command:\n");
printf("################################\n");
printf("'0' is select PSAM CARD\n");
printf("'1' is select ICC CARD\n");
printf("'quit' is return\n");
printf("'break' is go back\n");
printf("################################\n");
MyMemset(camd_buf,0,sizeof(camd_buf));
scanf("%s",camd_buf);
getchar();
if(MyMemcmp("0",camd_buf,MyStrlen("0")) == 0)
{
while(1)
{
printf("Please input APDU:\n");
MyMemset(camd_buf,0,sizeof(camd_buf));
scanf("%s",camd_buf);
getchar();
if(MyMemcmp("break",camd_buf,MyStrlen("break")) == 0)
break;
MyStrToHex((camd_buf),send_buf);
ret = CloudPos_SendToPcscd((unsigned char *)send_buf,0,recv_buf,&recv_len);
MyPrintfBuff("recv_buf::",recv_buf,recv_len);
}
}
else if(memcmp("1",camd_buf,MyStrlen("1")) == 0)
{
ret = PBOC_Connect(1);
if(ret == FALSE)
{
printf("Connect(1) error Please try again!\n");
}
else
{
printf("Connect(1) sucess\n");
while(1)
{
printf("Please input APDU:\n");
MyMemset(camd_buf,0,sizeof(camd_buf));
scanf("%s",camd_buf);
getchar();
if(MyMemcmp("break",camd_buf,MyStrlen("break")) == 0)
break;
send_len = MyStrToHex((camd_buf),send_buf);
ret = PBOC_APDU_SendAPI(1,send_buf,send_len,recv_buf,&recv_len);
MyPrintfBuff("recv_buf::",recv_buf,recv_len);
}
}
PBOC_DisConnect(1);
}
else if(MyMemcmp("quit",camd_buf,MyStrlen("quit")) == 0)
{
break;
}
}
Pcscd_Release();