Skip to content

Instantly share code, notes, and snippets.

@yrezgui
Created May 13, 2013 13:18
Show Gist options
  • Save yrezgui/5568249 to your computer and use it in GitHub Desktop.
Save yrezgui/5568249 to your computer and use it in GitHub Desktop.
#include "StdAfx.h"
#include "CDirectUSB.h"
#include "CTools.h"
#ifdef _DEBUG
using namespace System::Diagnostics;
#endif
#define OUTPUT_SIZE 512 // Buffer TX size
// Device configuration
#define MY_CONFIG 1
__declspec(align(2))struct CCID_MESSAGE
{
BYTE bMessageType;
BYTE bLen1;
BYTE bLen2;
BYTE bLen3;
BYTE bLen4;
BYTE bSlot;
BYTE bSeq;
BYTE Msg1;
BYTE Msg2;
BYTE Msg3;
};
CDirectUSB::~CDirectUSB()
{
if (hdevice != NULL)
{
ShutDownCard();
usb_release_interface(hdevice, MyInterface);
usb_close(hdevice);
}
}
void CDirectUSB::Init(char* com_port)
{
struct usb_bus *bus;
struct usb_device *dev;
String^ MY_VID;
String^ MY_PID;
String^ MY_NUM;
size_t iPosition;
int ret;
BYTE BufOUT[10];
hdevice = NULL;
#ifdef _DEBUG
usb_set_debug(3);
#endif
strcpy(readername, com_port);
// Recherche VID
iPosition = strcspn(com_port,"/");
if (iPosition==strlen(com_port))
{
CTools::LogEvent("No VID found in %s",readername);
throw new CReaderException(CREADER_ERROR_MESSAGE,"No VID found in %s",readername);
}
MY_VID = gcnew String(com_port);
MY_VID = MY_VID->Substring(0,iPosition);
com_port+=iPosition;
com_port++;
// Recherche PID
iPosition = strcspn(com_port,"/");
if (iPosition==strlen(com_port))
{
CTools::LogEvent("No PID found in %s",readername);
throw new CReaderException(CREADER_ERROR_MESSAGE,"No PID found in %s",readername);
}
MY_PID = gcnew String(com_port);
MY_PID=MY_PID->Substring(0,iPosition);
com_port+=iPosition;
com_port++;
// Recherche Num
MY_NUM = gcnew String(com_port);
// initialize the library
usb_init();
// find all busses
usb_find_busses();
// find all connected devices
usb_find_devices();
// Search for devices
for (bus = usb_get_busses(); bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
#ifdef _DEBUG
Debug::WriteLine("VID: " + Convert::ToString(dev->descriptor.idVendor,16) + " - PID: " + Convert::ToString(dev->descriptor.idProduct,16) + " - Num: " + Convert::ToString(dev->devnum,10));
#endif
if ((Convert::ToString(dev->descriptor.idVendor,16) == MY_VID->ToLower()) && (Convert::ToString(dev->descriptor.idProduct,16) == MY_PID->ToLower()) && (Convert::ToString(dev->devnum,10) == MY_NUM->ToLower()))
{
hdevice = usb_open(dev);
break;
}
}
if (hdevice != NULL)
break;
}
if (hdevice == NULL)
{
CTools::LogEvent("%s Reader not found",readername);
throw new CReaderException(CREADER_ERROR_MESSAGE,"%s Reader not found",readername);
}
// Set Configuration
ret = usb_set_configuration(hdevice,MY_CONFIG);
if (ret < 0)
{
usb_close(hdevice);
CTools::LogEvent("usb_set_configuration : %d",ret);
throw new CReaderException(CREADER_ERROR_MESSAGE,"%s Reader not found",readername);
}
// Claim Interface
MyInterface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber;
ret = usb_claim_interface(hdevice,MyInterface);
if (ret < 0)
{
usb_close(hdevice);
CTools::LogEvent("usb_claim_interface : %d",ret);
throw new CReaderException(CREADER_ERROR_MESSAGE,"%s Reader not found",readername);
}
// get bulk endpoints numbers
for (int i=0;i<dev->config[0].interface[0].altsetting[0].bNumEndpoints;i++)
{
// Bulk ?
if (dev->config[0].interface[0].altsetting[0].endpoint[i].bmAttributes == USB_ENDPOINT_TYPE_BULK)
{
// In or Out EndPoint ?
if ((dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_DIR_MASK)
EndPoint_IN = dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress;
else
EndPoint_OUT = dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress;
}
// interrupt ?
else if (dev->config[0].interface[0].altsetting[0].endpoint[i].bmAttributes == USB_ENDPOINT_TYPE_INTERRUPT)
{
if ((dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_DIR_MASK)
EndPoint_IT = dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress;
}
}
// Xiring Teo (Omnikey) - RDR_to_PC_NotifySlotChange
if ((MY_VID->ToUpper() == "76B") && (MY_PID->ToUpper() == "A022"))
{
// Il y a un TimeOut si pas de changement du status de la carte...
ret = usb_interrupt_read(hdevice,EndPoint_IT,(char *)BufOUT,sizeof(BufOUT),10);
}
}
BOOL CDirectUSB::IsCardPresent()
{
DWORD LnRep;
BYTE pDataRep[OUTPUT_SIZE];
WORD SW;
try
{
ResetCard(&LnRep, pDataRep, &SW);
}
catch(CReaderException *e)
{
#ifdef _DEBUG
Debug::WriteLine(e->GetErrorMessage()->ToString());
#endif
return FALSE;
}
return TRUE;}
void CDirectUSB::ShutDownCard()
{
int ret;
DWORD MyLenOut;
BYTE BufOUT[OUTPUT_SIZE];
ret = ControlUSB((BYTE *)"\x63\x00\x00\x00\x00\x00\x00\x00\x00\x00",10,BufOUT,&MyLenOut);
if (ret<=0)
{
throw new CReaderException(CREADER_CARD_ABSENT, "PC_to_RDR_IccPowerOff %d %s",ret,strerror(errno));
}
}
void CDirectUSB::ResetCard(DWORD * pLnRep, BYTE * pDataRep, WORD * SW)
{
int ret;
DWORD MyLenOut;
BYTE BufOUT[OUTPUT_SIZE];
*pLnRep = 0;
*SW = 0;
// PC_to_RDR_IccPowerOff
ShutDownCard();
// PC_to_RDR_IccPowerOn
ret = ControlUSB((BYTE *)"\x62\x00\x00\x00\x00\x00\x01\x00\x00\x00",10,BufOUT,&MyLenOut);
if (ret<=0)
{
throw new CReaderException(CREADER_CARD_ABSENT, "PC_to_RDR_IccPowerOn %d %s",ret,strerror(errno));
}
struct CCID_MESSAGE *ptr;
ptr = (struct CCID_MESSAGE *) BufOUT;
if (BufOUT[7] == 0)
{
*pLnRep = ptr->bLen1;
memcpy(pDataRep,&BufOUT[10],ptr->bLen1);
*SW = pDataRep[*pLnRep-2]*256 + pDataRep[*pLnRep-1];
}
else
throw new CReaderException(CREADER_CARD_ABSENT, "PC_to_RDR_IccPowerOn Status : %x", BufOUT[7]);
bSlot = 0;
bSeq = 1;
}
void CDirectUSB::Reset(DWORD * pLnRep, BYTE * pDataRep, WORD * SW)
{
ResetCard(pLnRep, pDataRep, SW);
}
void CDirectUSB::InCard(BYTE CLA, BYTE INS, BYTE P1, BYTE P2, BYTE Lc, BYTE * pDataBuf, WORD ExpectedSW, WORD * SW)
{
int ret;
DWORD MyLenIn=0;
DWORD MyLenOut;
BYTE BufIn[OUTPUT_SIZE];
BYTE BufOUT[OUTPUT_SIZE];
DWORD MyCmdLen;
*SW = 0;
memset(BufIn,0,sizeof(BufIn));
MyCmdLen = 5 + Lc;
BufIn[MyLenIn++]=0x6F; // bMessageType
BufIn[MyLenIn++]=(BYTE)((MyCmdLen>>0) & 0xFF); // dwLength
BufIn[MyLenIn++]=(BYTE)((MyCmdLen>>8) & 0xFF); // dwLength
BufIn[MyLenIn++]=(BYTE)((MyCmdLen>>16) & 0xFF); // dwLength
BufIn[MyLenIn++]=(BYTE)((MyCmdLen>>24) & 0xFF); // dwLength
BufIn[MyLenIn++]=bSlot; // bSlot
BufIn[MyLenIn++]=++bSeq; // bSeq
BufIn[MyLenIn++]=0x00; // bBWI
BufIn[MyLenIn++]=0x00; // wLevelParameter
BufIn[MyLenIn++]=0x00; // wLevelParameter
BufIn[MyLenIn++]=CLA; // abData...
BufIn[MyLenIn++]=INS;
BufIn[MyLenIn++]=P1;
BufIn[MyLenIn++]=P2;
BufIn[MyLenIn++]=Lc;
memcpy(&BufIn[MyLenIn],pDataBuf,Lc);
MyLenIn+=Lc;
ret = ControlUSB(BufIn,MyLenIn,BufOUT,&MyLenOut);
if (ret<=0)
{
throw new CReaderException(CREADER_ERROR_MESSAGE, "PC_to_RDR_XfrBlock %d %s",ret,strerror(errno));
}
struct CCID_MESSAGE *ptr;
ptr = (struct CCID_MESSAGE *) BufOUT;
if (BufOUT[7] == 0)
{
*SW = BufOUT[10]*256 + BufOUT[11];
}
else
throw new CReaderException(CREADER_ERROR_MESSAGE, "PC_to_RDR_XfrBlock Status : %x", BufOUT[7]);
// Contrôle SW
if (ExpectedSW!=0)
{
if (*SW!=ExpectedSW)
{
throw new CReaderException(CREADER_CARD_WRONG_SW, "InCard SW Error: Expected SW=0x%04X, Returned SW=0x%04X",ExpectedSW,*SW);
}
}
}
void CDirectUSB::OutCard(BYTE CLA, BYTE INS, BYTE P1, BYTE P2, BYTE Le, DWORD * pLnRep, BYTE * pDataRep, WORD ExpectedSW, WORD * SW)
{
int ret;
DWORD MyLenIn=0;
DWORD MyLenOut;
BYTE BufIn[OUTPUT_SIZE];
BYTE BufOUT[OUTPUT_SIZE];
DWORD MyCmdLen;
*pLnRep = 0;
*SW = 0;
memset(BufIn,0,sizeof(BufIn));
MyCmdLen = 5;
BufIn[MyLenIn++]=0x6F; // bMessageType
BufIn[MyLenIn++]=(BYTE)((MyCmdLen>>0) & 0xFF); // dwLength
BufIn[MyLenIn++]=(BYTE)((MyCmdLen>>8) & 0xFF); // dwLength
BufIn[MyLenIn++]=(BYTE)((MyCmdLen>>16) & 0xFF); // dwLength
BufIn[MyLenIn++]=(BYTE)((MyCmdLen>>24) & 0xFF); // dwLength
BufIn[MyLenIn++]=bSlot; // bSlot
BufIn[MyLenIn++]=++bSeq; // bSeq
BufIn[MyLenIn++]=0x00; // bBWI
BufIn[MyLenIn++]=0x00; // wLevelParameter
BufIn[MyLenIn++]=0x00; // wLevelParameter
BufIn[MyLenIn++]=CLA; // abData...
BufIn[MyLenIn++]=INS;
BufIn[MyLenIn++]=P1;
BufIn[MyLenIn++]=P2;
BufIn[MyLenIn++]=Le;
ret = ControlUSB(BufIn,MyLenIn,BufOUT,&MyLenOut);
if (ret<=0)
{
throw new CReaderException(CREADER_ERROR_MESSAGE, "PC_to_RDR_XfrBlock %d %s",ret,strerror(errno));
}
struct CCID_MESSAGE *ptr;
ptr = (struct CCID_MESSAGE *) BufOUT;
if (BufOUT[7] == 0)
{
*pLnRep = ptr->bLen1;
memcpy(pDataRep,&BufOUT[10],ptr->bLen1);
*SW = pDataRep[*pLnRep-2]*256 + pDataRep[*pLnRep-1];
*pLnRep-=2;
}
else
throw new CReaderException(CREADER_ERROR_MESSAGE, "PC_to_RDR_XfrBlock Status : %x", BufOUT[7]);
// Contrôle SW
if (ExpectedSW!=0)
{
if (*SW!=ExpectedSW)
{
throw new CReaderException(CREADER_CARD_WRONG_SW, "OutCard SW Error: Expected SW=0x%04X, Returned SW=0x%04X",ExpectedSW,*SW);
}
}
}
void CDirectUSB::InOutCard(BYTE CLA, BYTE INS, BYTE P1, BYTE P2, BYTE Lc, BYTE * pDataBuf, BYTE Le, DWORD * pLnRep, BYTE * pDataRep, WORD ExpectedSW, WORD * SW)
{
*pLnRep = 0;
*SW = 0;
// En ISO 7816
InCard(CLA,INS,P1,P2,Lc,pDataBuf,0,SW);
if ((*SW==0x9000) || (*SW==0x6200) || ((*SW&0xFF00)==0x6100))
{
if ((*SW&0xFF00)==0x6100)
Le = (BYTE)(*SW&0x00FF);
OutCard(0x00,0xC0,0x00,0x00,Le,pLnRep,pDataRep,ExpectedSW,SW);
}
// Contrôle SW
if (ExpectedSW!=0)
{
if (*SW!=ExpectedSW)
{
throw new CReaderException(CREADER_CARD_WRONG_SW, "InOutCard SW Error: Expected SW=0x%04X, Returned SW=0x%04X",ExpectedSW,*SW);
}
}
}
//*****************************************************************************
//* ControlUSB
//*****************************************************************************
DWORD CDirectUSB::ControlUSB(BYTE *DataIn, DWORD LenDataIn, BYTE *DataOut, DWORD *LenOut)
{
int ret;
*LenOut = 0;
ret = usb_bulk_write(hdevice,EndPoint_OUT,(char *)DataIn,LenDataIn,5000);
if (ret != LenDataIn)
{
CTools::LogEvent("usb_bulk_write : %d %s",ret,strerror(errno));
}
else
{
ret = usb_bulk_read(hdevice,EndPoint_IN,(char *)DataOut,OUTPUT_SIZE,5000);
if (ret < 0)
{
CTools::LogEvent("usb_bulk_read : %d %s",ret,strerror(errno));
}
else
{
*LenOut = ret;
}
}
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment