home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / usbd0906.zip / usb_20020906.zip / usbcalls / samples / Cardreader / Cardreader.cpp next >
C/C++ Source or Header  |  2001-11-13  |  18KB  |  660 lines

  1. #define INCL_DOS
  2. #include <os2.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6.  
  7. #include "..\..\usbcalls.h"
  8.  
  9. #include "GemCore.h"
  10. #include "GCUSBTransport.h"
  11.  
  12. #define VENDOR_GEMPLUS 0x08E6
  13. #define PRODUCT_GPC430 0x0430
  14. #define USBWRITE_PIPE   0x06
  15. #define USBREAD_PIPE    0x85
  16.  
  17.  
  18. #define MAX_CTN 256
  19. USBHANDLE hUSBDevice[MAX_CTN];
  20.  
  21. const UCHAR pcSetModeROSNOTLP[] = {0x01, 0x00, 0x01};
  22. // Slot specific (GemCore can manage 2 card slots)
  23. const UCHAR pcPowerUp[MAX_SLOT_NB]      = {0x12, 0x1A};
  24. const UCHAR pcPowerDown[MAX_SLOT_NB]    = {0x11, 0x19};
  25. const UCHAR pcISOOutput[MAX_SLOT_NB]    = {0x13, 0x1B};
  26. const UCHAR pcISOInput[MAX_SLOT_NB]     = {0x14, 0x1C};
  27. const UCHAR pcEchAPDU[MAX_SLOT_NB]      = {0x15, 0x1D};
  28. const UCHAR pcCardStatus[MAX_SLOT_NB]   = {0x17, 0x1F};
  29.  
  30. #define OK               0               /* Success */
  31. #define ERR_INVALID     -1               /* Invalid Data */
  32. #define ERR_CT          -8               /* CT Error */
  33. #define ERR_TRANS       -10              /* Transmission Error */
  34. #define ERR_MEMORY      -11              /* Memory Allocate Error */
  35. #define ERR_HTSI        -128             /* HTSI Error */
  36.  
  37. #define STATUS_SUCCESS 0
  38. #define STATUS_DEVICE_PROTOCOL_ERROR -128
  39.  
  40. char GCSendCommand(USHORT Ctn, ULONG nLengthIn,
  41.                    const PUCHAR pcBufferCmd,
  42.                    PULONG pnLengthOut,
  43.                    PUCHAR pcBufferOut);
  44.  
  45. char GCSendCommand(USHORT Ctn, ULONG nLengthIn,
  46.                    const PUCHAR pcBufferCmd,
  47.                    PULONG pnLengthOut,
  48.                    PUCHAR pcBufferOut)
  49. {
  50.     UCHAR pctr_to_card_buffer[GC_TR_BUF_SIZE];
  51.     UCHAR creturn_value;
  52.     USHORT nlength;
  53.  
  54.     creturn_value = STATUS_SUCCESS;
  55.  
  56.     if (GC_TR_BUF_SIZE <= nLengthIn)
  57.     {
  58.         // Buffer is too small (should not happen)
  59.         creturn_value = STATUS_DEVICE_PROTOCOL_ERROR;
  60.         goto finally;
  61.     }
  62.  
  63.     memcpy(pctr_to_card_buffer+1, pcBufferCmd, nLengthIn);
  64.     pctr_to_card_buffer[TR_OFFSET_LNG] = nLengthIn;
  65.     if(UsbBulkWrite( hUSBDevice[Ctn],
  66.                      USBWRITE_PIPE, 0,
  67.                      nLengthIn+1, pctr_to_card_buffer,
  68.                      100000) != 0)
  69.     {
  70.         creturn_value = STATUS_DEVICE_PROTOCOL_ERROR;
  71.         goto finally;
  72.     }
  73.  
  74.     nlength = 256; //sizeof(pctr_to_card_buffer);
  75.     if(UsbBulkRead( hUSBDevice[Ctn],
  76.                     USBREAD_PIPE, 0,
  77.                     &nlength, pctr_to_card_buffer,
  78.                     10000) != 0)
  79.     {
  80.         creturn_value = STATUS_DEVICE_PROTOCOL_ERROR;
  81.         goto finally;
  82.     }
  83.     if ( nlength < 1 )
  84.     {
  85.         // length byte not received
  86.         creturn_value = STATUS_DEVICE_PROTOCOL_ERROR;
  87.         goto finally;
  88.     }
  89.     nlength--;
  90.     *pnLengthOut = (*pnLengthOut<nlength) ? *pnLengthOut : nlength;
  91.     memcpy(pcBufferOut, pctr_to_card_buffer+1, *pnLengthOut);
  92. finally:
  93.     if ( creturn_value != STATUS_SUCCESS )
  94.         *pnLengthOut = 0;
  95.     // Clear buffer
  96.     memset(pctr_to_card_buffer, sizeof(pctr_to_card_buffer),0);
  97.     return creturn_value;
  98. }
  99.  
  100.  
  101. char CT_init ( USHORT Ctn,  USHORT pn )
  102. {
  103.   APIRET rc;
  104.   int IretVal;         /* Return for this function */
  105.   ULONG nlength;
  106.   UCHAR pcbuffer[RESP_BUF_SIZE];
  107.  
  108.   IretVal = ERR_MEMORY;        /* Could not allocate port */
  109.   if(Ctn< MAX_CTN && hUSBDevice[Ctn] == 0)
  110.   {
  111.     rc = UsbOpen( &hUSBDevice[Ctn],
  112.                   VENDOR_GEMPLUS,
  113.                   PRODUCT_GPC430,
  114.                   USB_ANY_PRODUCTVERSION,
  115.                   pn);
  116.     if(0==rc)
  117.       rc = UsbSetDeviceConfiguration(hUSBDevice[Ctn], 1);
  118.     if(0==rc)
  119.       IretVal = OK;
  120.  
  121.     nlength = sizeof(pcbuffer);
  122.     if ( GCSendCommand( Ctn, sizeof(pcSetModeROSNOTLP),
  123.                        (const PUCHAR)pcSetModeROSNOTLP,
  124.                        &nlength, pcbuffer) != STATUS_SUCCESS )
  125.     {
  126.       printf("IFD_GemPC430 : Setmode failed\n");
  127.       IretVal = ERR_HTSI;
  128.     }
  129.     else
  130.     {
  131.       // Check status returned by reader
  132.       if ( pcbuffer[STATUS_OFFSET] != GCORE_OK )
  133.       {
  134.         // Could not set reader mode
  135.         // For now, we consider this a "fatal" error
  136.         printf("IFD_GemPC430 : Setmode failed\n");
  137.         IretVal = ERR_HTSI;
  138.       }
  139.     }
  140.   }
  141.  
  142.   return IretVal;
  143. }
  144.  
  145. /* Closes the port in which the reader resides */
  146.  
  147. char CT_close( USHORT Ctn )
  148. {
  149.   if(Ctn< MAX_CTN && hUSBDevice[Ctn] != 0)
  150.   {
  151.     return (UsbClose(hUSBDevice[Ctn])==0)?OK:ERR_CT;
  152.   }
  153.   else
  154.     return ERR_CT;
  155. }
  156.  
  157. /* Sends/Receives Data to/from the Reader */
  158.  
  159. #define CMD_CLA 0
  160. #define CMD_INS 1
  161. #define CMD_P1  2
  162. #define CMD_P2  3
  163. #define CMD_LC  4
  164. #define CMD_LE  4
  165. #define TLV_TAG 5
  166. #define TLV_LEN 6
  167. #define TLV_DATA 7
  168.  
  169. BOOL ResetCT()
  170. {
  171.   return TRUE;
  172. }
  173.  
  174. BOOL ResetICC(USHORT Ctn, UCHAR ucSlot,UCHAR ucFlags, UCHAR ucNumBytes, USHORT *lr, UCHAR *rsp)
  175. {
  176.   ULONG nlength;
  177.   UCHAR pcbuffer[RESP_BUF_SIZE];
  178.   UCHAR pccmd_buffer[CMD_BUF_SIZE];
  179.   ULONG ncommand_length = 1; // there is at least the command byte
  180.  
  181.    // By default, assume it won't work :)
  182.   ULONG AtrLength = 0;
  183.  
  184.   // Build reset command
  185.   pccmd_buffer[OFFSET_CMD] = pcPowerUp[ucSlot-1];
  186. // PTS management should be added here
  187.  //send the command
  188.   nlength = sizeof(pcbuffer);
  189.   if ( GCSendCommand( Ctn,
  190.                       ncommand_length, pccmd_buffer,
  191.                       &nlength, pcbuffer) != STATUS_SUCCESS )
  192.   {
  193.     printf("IFD_GemPC430 : PowerUp failed\n");
  194.     rsp[0] = 0x64;
  195.     rsp[1] = 0x00;
  196.     *lr = 2;
  197.     return FALSE;
  198.   }
  199.   // Response analysis
  200.   if ( nlength < 1)
  201.   {
  202.     rsp[0] = 0x64;
  203.     rsp[1] = 0x00;
  204.     *lr = 2;
  205.     return FALSE;
  206.   }
  207.   // Remove command byte count from length
  208.   nlength--;
  209.   switch ( pcbuffer[STATUS_OFFSET] )
  210.   {
  211.     case GCORE_OK:
  212.     case GCORE_WRONG_TCK:
  213.       AtrLength = (nlength < MAX_ATR_SIZE) ? nlength: MAX_ATR_SIZE;
  214.       switch(ucFlags)
  215.       {
  216.         case 0:
  217.           rsp[0] = 0x90;
  218.           rsp[1] = 0x01; // Check Protocoltype of card from ATR.
  219.           *lr = 2;
  220.           break;
  221.         case 1:
  222.           memcpy(rsp, pcbuffer+ATR_OFFSET, AtrLength);
  223.           rsp[AtrLength]   = 0x90;
  224.           rsp[AtrLength+1] = 0x01; // Check Protocoltype of card from ATR.
  225.           *lr = 2 + AtrLength;
  226.           break;
  227.         case 2:
  228.           // ToDO Extract historical bytes...
  229.           rsp[0] = 0x90;
  230.           rsp[1] = 0x01; // Check Protocoltype of card from ATR.
  231.           *lr = 2;
  232.           break;
  233.       }
  234.       break;
  235.     default:
  236.       // There is a problem in getting the reset
  237.       rsp[0] = 0x64;
  238.       rsp[1] = 0x00;
  239.       *lr = 2;
  240.       return FALSE;
  241.   }
  242.   return TRUE;
  243. }
  244.  
  245. BOOL GetSlotState(USHORT Ctn, UCHAR ucSlot, UCHAR *ucPresence)
  246. {
  247.   UCHAR pcbuffer[RESP_BUF_SIZE];
  248.   ULONG nlength = sizeof(pcbuffer);
  249.   // Command is 1-byte long
  250.   if ( GCSendCommand( Ctn,
  251.                       1, (const PUCHAR)&pcCardStatus[ucSlot-1],
  252.                       &nlength, pcbuffer) != STATUS_SUCCESS )
  253.   {
  254.     printf("IFD_GemPC430 : CARD STATUS failed\n");
  255.     return FALSE;
  256.   }
  257.  
  258.   if ( (nlength < (OFFSET_STAT_BYTE+1)) ||
  259.           pcbuffer[STATUS_OFFSET] != GCORE_OK )
  260.   {
  261.     // Length should at least be 2 (nlength + reader status)
  262.     return FALSE;
  263.   }
  264.   *ucPresence =pcbuffer[OFFSET_STAT_BYTE];
  265.   return TRUE;
  266. }
  267.  
  268. BOOL PowerDownCard(USHORT Ctn,UCHAR ucSlot, USHORT *lr, UCHAR *rsp)
  269. {
  270.   UCHAR pcbuffer[RESP_BUF_SIZE];
  271.   ULONG nlength;
  272.   if ( GCSendCommand( Ctn,
  273.                       sizeof(pcPowerDown[ucSlot-1]),(const PUCHAR) &pcPowerDown[ucSlot-1],
  274.                       &nlength, pcbuffer) != STATUS_SUCCESS )
  275.   {
  276.     printf("IFD GemPC430 : PowerDown failed\n");
  277.     return FALSE;
  278.   }
  279.   return TRUE;
  280. }
  281.  
  282. // status functions
  283. BOOL GetCTManufacturerDO(USHORT Ctn, USHORT *lr, UCHAR *rsp)
  284. {
  285.   rsp[0] = 0x46;
  286.   rsp[1] = 0x0F;
  287.   memcpy(&rsp[2], " MMDE",5);
  288.   memcpy(&rsp[7], "  USB",5);
  289.   memcpy(&rsp[12]," 0.01",5);
  290.   rsp[17] = 0x90;
  291.   rsp[18] = 0x00;
  292.   *lr = 19;
  293.   return TRUE;
  294. }
  295.  
  296. BOOL GetICCStatusDO(USHORT Ctn, UCHAR ucSlot, USHORT *lr, UCHAR *rsp)
  297. {
  298.   *lr = 0;
  299.   if(ucSlot)
  300.   {
  301.     if(GetSlotState(Ctn, ucSlot, &rsp[2]) )
  302.     {
  303.       rsp[0] = 0x80;
  304.       rsp[1] = 0x01;
  305.       rsp[3] = 0x90;
  306.       rsp[4] = 0x00;
  307.       *lr=5;
  308.     }
  309.   }
  310.   else
  311.   {
  312.     if(GetSlotState(Ctn, 1, &rsp[2]) &&
  313.        GetSlotState(Ctn, 2, &rsp[3]) )
  314.     {
  315.       rsp[0] = 0x80;
  316.       rsp[1] = 0x02;
  317.       rsp[4] = 0x90;
  318.       rsp[5] = 0x00;
  319.       *lr=6;
  320.     }
  321.   }
  322.   return (*lr>0);
  323. }
  324.  
  325. BOOL GetFunctionalUnitDO(USHORT Ctn, USHORT *lr, UCHAR *rsp)
  326. {
  327.   // only ICC1 present
  328.   rsp[0] = 0x81;
  329.   rsp[1] = 0x01;
  330.   rsp[2] = 0x01;
  331.   rsp[3] = 0x90;
  332.   rsp[4] = 0x00;
  333.   *lr = 5;
  334.   return TRUE;
  335. }
  336.  
  337.  
  338. char  CT_data( USHORT Ctn, UCHAR *dad, UCHAR *sad,
  339.                USHORT lenc, UCHAR *cmd,
  340.                USHORT *lr, UCHAR *rsp )
  341. {
  342.  
  343.   /* Reader specific CT-BCS commands */
  344.  
  345.   int IretVal;                                /* Return Value    */
  346.   UCHAR Temp;
  347.  
  348.   switch( *dad )
  349.   {
  350.     case 0x01:
  351.     {             /* This command goes to the reader */
  352.  
  353.       // Don't get confused here this is for the return saying
  354.       // the source was the reader and the destination the host
  355.  
  356.       *dad = *sad;
  357.       *sad = 1;
  358.  
  359.       /*******************/
  360.       /* CT-BCS Commands */
  361.       /*******************/
  362.  
  363.       if(cmd[CMD_CLA] != 0x20)
  364.       {
  365.         rsp[0] = 0x6E;
  366.         rsp[1] = 0x00;
  367.         *lr = 2;
  368.       }
  369.       else
  370.       {
  371.         switch(cmd[CMD_INS])
  372.         {
  373.           case 0x10:
  374.           case 0x11:
  375.             // CHANGE:: Reset code goes here.
  376.             /* Get Status - Gets reader status */
  377.             switch(cmd[CMD_P1])
  378.             {
  379.               case 0: // Reset CT
  380.                  if(ResetCT())
  381.                    rsp[0] = 0x90;
  382.                  else
  383.                    rsp[0] = 0x64;
  384.                  rsp[1] = 0x00;
  385.                  *lr = 2;
  386.                 break;
  387.               case 1: // Reset ICC1
  388.               case 2: // Reset ICC2
  389.                 if(cmd[CMD_P2]<3)
  390.                   ResetICC(Ctn,cmd[CMD_P1],cmd[CMD_P2],cmd[CMD_LE],lr,rsp);
  391.                 else
  392.                 {
  393.                   rsp[0] = 0x6A;
  394.                   rsp[1] = 0x00;
  395.                   *lr = 2;
  396.                 }
  397.                 break;
  398.               default:
  399.                 rsp[0] = 0x6A;
  400.                 rsp[1] = 0x00;
  401.                 *lr = 2;
  402.                 break;
  403.             }
  404.             break;
  405.           case 0x12:
  406.             /* Request ICC  - Turns on the reader/card */
  407.             // CHANGE:: Request ICC code goes here.
  408.             /* Resets the Card/Terminal and returns Atr */
  409.             switch(cmd[CMD_P1])
  410.             {
  411.               case 1:
  412.               case 2: // Reset ICC2
  413.                 if((cmd[CMD_P2]&&0x03)<3)
  414.                 {
  415.                   // Check LC for display messages and Timeout
  416.                   if(cmd[CMD_LC])
  417.                   {
  418.                     int i=0;
  419.                     UCHAR *Msg = NULL;
  420.                     USHORT usTimeout = 0;
  421.                     BOOL fErr=FALSE;
  422.                     while (i<cmd[CMD_LC])
  423.                     {
  424.                       switch(cmd[TLV_TAG+i]) // switch on TAG
  425.                       {
  426.                         case 50:
  427.                           Msg = &cmd[TLV_LEN+i];
  428.                           i +=(cmd[TLV_LEN+i]+2);
  429.                           break;
  430.                         case 80:
  431.                           if(cmd[TLV_LEN+i]==1)
  432.                             usTimeout = cmd[TLV_DATA+i];
  433.                           else
  434.                             if(cmd[TLV_LEN+i]==2)
  435.                               usTimeout = cmd[TLV_DATA+i]*256+cmd[TLV_DATA+1+i];
  436.                           i +=(cmd[TLV_LEN+i]+2);
  437.                           break;
  438.                         default:
  439.                           i=cmd[CMD_LC];
  440.                           rsp[0] = 0x6D;
  441.                           rsp[1] = 0x00;
  442.                           *lr = 2;
  443.                           fErr=TRUE;
  444.                           break;
  445.                       }
  446.                     }
  447.                     if(!fErr)
  448.                     {
  449.                       if(Msg)
  450.                       {
  451.                         // Display Message
  452.                       }
  453.                       if(usTimeout)
  454.                       {
  455.                       }
  456.                     }
  457.                   }
  458.                   else
  459.                     ResetICC(Ctn,cmd[CMD_P1],cmd[CMD_P2],cmd[CMD_LE],lr,rsp);
  460.                 }
  461.                 else
  462.                 {
  463.                   rsp[0] = 0x6A;
  464.                   rsp[1] = 0x00;
  465.                   *lr = 2;
  466.                 }
  467.                 break;
  468.               default:
  469.                 rsp[0] = 0x6A;
  470.                 rsp[1] = 0x00;
  471.                 *lr = 2;
  472.                 break;
  473.             }
  474.             break;
  475.           case 0x13:
  476.              // CHANGE:: Get Status code goes here.
  477.             /* Eject ICC - Deactivates Reader  */
  478.             switch(cmd[CMD_P1])
  479.             {
  480.               case 0:
  481.                 switch(cmd[CMD_P2])
  482.                 {
  483.                   case 0x46:
  484.                     GetCTManufacturerDO(Ctn,lr,rsp);
  485.                     break;
  486.                   case 0x80:
  487.                     GetICCStatusDO(Ctn,cmd[CMD_P1],lr,rsp);
  488.                     break;
  489.                   case 0x81:
  490.                     GetFunctionalUnitDO(Ctn,lr,rsp);
  491.                     break;
  492.                   default:
  493.                     rsp[0] = 0x64;
  494.                     rsp[1] = 0x00;
  495.                     *lr = 2;
  496.                     break;
  497.                 }
  498.               case 1:
  499.               case 2:
  500.                 GetICCStatusDO(Ctn,cmd[CMD_P1],lr,rsp);
  501.               default:
  502.                 rsp[0] = 0x64;
  503.                 rsp[1] = 0x00;
  504.                 *lr = 2;
  505.                 break;
  506.             }
  507.             break;
  508.           case 0x14:
  509.             if( ((cmd[CMD_P1]!=1) && (cmd[CMD_P1]!=2)) || (cmd[CMD_P2]!= 0) )
  510.             {
  511.               rsp[0] = 0x64;
  512.               rsp[1] = 0x00;
  513.               *lr = 2;
  514.               break;
  515.             }
  516.             if( (cmd[CMD_LC]!= 0) || (lenc!=5) )
  517.             {
  518.  
  519.             }
  520.             else
  521.               PowerDownCard(Ctn,cmd[2],lr,rsp);
  522.             break;
  523.           case 0x15:
  524.             // CHANGE:: Eject ICC code goes here.
  525.             switch(cmd[CMD_P1])
  526.             {
  527.               case 1:
  528.               case 2:
  529.                 if( ((cmd[CMD_P2]&0xF0) != 0x00) &&
  530.                     ((cmd[CMD_P2]&0xF0) != 0xF0) )
  531.                 {
  532.                   rsp[0] = 0x64;
  533.                   rsp[1] = 0x00;
  534.                   *lr = 2;
  535.                   break;
  536.                 }
  537.                 // Check LC for display messages and Timeout
  538.                 if(cmd[CMD_LC])
  539.                 {
  540.                   int i=0;
  541.                   UCHAR *Msg = NULL;
  542.                   USHORT usTimeout = 0;
  543.                   BOOL fErr=FALSE;
  544.                   while (i<cmd[CMD_LC])
  545.                   {
  546.                     switch(cmd[TLV_TAG+i]) // switch on TAG
  547.                     {
  548.                       case 50:
  549.                         Msg = &cmd[TLV_LEN+i];
  550.                         i +=(cmd[TLV_LEN+i]+2);
  551.                         break;
  552.                       case 80:
  553.                         if(cmd[TLV_LEN+i]==1)
  554.                           usTimeout = cmd[TLV_DATA+i];
  555.                         else
  556.                           if(cmd[TLV_LEN+i]==2)
  557.                             usTimeout = cmd[TLV_DATA+i]*256+cmd[TLV_DATA+1+i];
  558.                         i +=(cmd[TLV_LEN+i]+2);
  559.                         break;
  560.                       default:
  561.                         i=cmd[CMD_LC];
  562.                         rsp[0] = 0x6D;
  563.                         rsp[1] = 0x00;
  564.                         *lr = 2;
  565.                         fErr=TRUE;
  566.                         break;
  567.                     }
  568.                   }
  569.                   if(!fErr)
  570.                   {
  571.                     if(Msg)
  572.                     {
  573.                       // Display Message
  574.                     }
  575.                     if(PowerDownCard(Ctn,cmd[CMD_P1],lr,rsp) && usTimeout!=0)
  576.                     {
  577.                       // Check for card removal for the duration of timeout.
  578.                     }
  579.                   }
  580.                 }
  581.                 else
  582.                   PowerDownCard(Ctn,cmd[CMD_P1],lr,rsp);
  583.                 break;
  584.               default:
  585.                 break;
  586.             }
  587.             break;
  588.         }// end switch(cmd[CMD_INS])
  589.       }
  590.       break;
  591.     }
  592.     case 0x00:
  593.     case 0x02:
  594.     {
  595.       /* This command goes to the ICC1 or ICC2*/
  596.  
  597.       // Don't get confused here this is for the return saying
  598.       // the source was the card and the destination the host
  599.        Temp = *dad;
  600.        *dad = *sad;
  601.        *sad = Temp;
  602.  
  603.  
  604.        // CHANGE:: Lots of code here.  This sends commands to the
  605.        // smartcard directly and places responses into rsp with size
  606.        // of lr.
  607.        break;
  608.     }
  609.     default:
  610.       IretVal = ERR_INVALID;              /* Invalid SAD/DAD Address */
  611.   }
  612.  
  613.   if (IretVal != OK)
  614.   {
  615.    *lr = 0;
  616.  
  617.   }
  618.  
  619.   return IretVal;
  620. }
  621.  
  622. void main()
  623. {
  624.   int rc,i;
  625.   ULONG ulNumDevices;
  626.   USBHANDLE hUSBDevice;
  627.   UCHAR ucData[20];
  628.   char brc;
  629.   rc = UsbQueryNumberDevices(&ulNumDevices);
  630.   printf("Num devices = %d (rc=%d)\r\n",ulNumDevices,rc);
  631.  
  632.   printf("Try to open Card Reader ... ");
  633.   brc = CT_init(0,0);
  634.  
  635.   if(!brc)
  636.   {
  637.     UCHAR ucReset[] ={0x20,0x11,0x01,0x01,0x00};
  638.     UCHAR ucResponse[64];
  639.     USHORT usRetLen = sizeof(ucResponse);
  640.     UCHAR sad = 2;
  641.     UCHAR dad = 1;
  642.     printf("SUCCESS\r\n try to reset card");
  643.     brc = CT_data(0, &dad, &sad, 5, ucReset, &usRetLen, ucResponse);
  644.     if(brc)
  645.     {
  646.       printf("FAILED!\r\n");
  647.     }
  648.     else
  649.     {
  650.       printf("ATR : ");
  651.       for(USHORT i =0;i< usRetLen;i++)
  652.         printf("%02X ",ucResponse[i]);
  653.       printf("\r\n");
  654.     }
  655.     CT_close(0);
  656.   }
  657.   else
  658.     printf("FAILED!\r\n");
  659. }
  660.