Smartcard USB driver - Bulk IN message problem

Hello,
Writing a an USB smartcard driver, I choose to start a new thread instead of continue the last thread i ve initiated.
I have written the configuration for the LPC2368. Here the configuration:

const BYTE USB_ConfigDescriptor[] = {

/* Configuration 1 */
  USB_CONFIGUARTION_DESC_SIZE,       /* bDescriptorType */
  USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
  WBVAL(                             /* wTotalLength */
    USB_CONFIGUARTION_DESC_SIZE +
    USB_INTERFACE_DESC_SIZE     +
    SMARTCARD_CLASS_DESC_SIZE               +
    3*USB_ENDPOINT_DESC_SIZE
  ),
  0x01,                              /* bNumInterfaces */
  0x01,                              /* bConfigurationValue */
  0x03,                              /* iConfiguration */
  /*USB_CONFIG_BUS_POWERED */       /* bmAttributes */
  0x80,
  USB_CONFIG_POWER_MA(100),          /* bMaxPower */

/* Interface 0, Alternate Setting 0, HID Class */
  USB_INTERFACE_DESC_SIZE,           /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,     /* bDescriptorType */
  0x00,                              /* bInterfaceNumber */
  0x00,                              /* bAlternateSetting */
  0x03,                              /* bNumEndpoints */
  0x0b,                                                          /* bInterfaceClass */
  //USB_DEVICE_CLASS_HUMAN_INTERFACE,  /* bInterfaceClass */
  0x00,                 /* bInterfaceSubClass */
  0x00,                 /* bInterfaceProtocol */
  0x00,                              /* iInterface */
  /* Smartcard Class Descriptor */
  SMARTCARD_CLASS_DESC_SIZE,                     /* bLength */
  SMARTCARD_SMARTCARD_DESCRIPTOR_TYPE,           /* bDescriptorType */
  WBVAL(0x0100), /* 1.00 */             /* bcdCCID */
  0x00,                                                 /* bMaxSlotIndex */
  0x07,                                                         /* bVoltageSupport: 5v, 3v and 1.8v */
  0x03,0x00,0x00,0x00,                                  // dwProtocols: supports T=0 and T=1
  0xF8,0x34,0x00,0x00,                                  // dwDefaultClock: 13,56 Mhz (0x00000FA0)
  0xF8,0x34,0x00,0x00,                                  // dwMaximumClock: 13,56 Mhz (0x00000FA0)
  0x00,                                                                 // bNumClockSupported => no manual setting
  0x00,0x2A,0x00,0x00,                                  // dwDataRate: 10752 bps (0x00002A00)
  0x08,0xF8,0x01,0x00,                                  // dwMaxDataRate: 129032 bps (0x0001F808)
  0x00,                                                                 // bNumDataRatesSupported => no manual setting
  0xFE,0x00,0x00,0x00,                                  /* IFSD */
  0x00,0x00,0x00,0x00,                                  /* Synchron Protocol */
  0x00,0x00,0x00,0x00,                                  /* Mechanical Features, DWORD */
  (0x04 | 0x08 | 0x10 | 0x40 | 0x02),(0x01 | 0x02),0x02,0x00,           /* Features - Automatic activation - clk, baud rate, voltage :automatic - short APDU level exchange*/
  // CCID can set ICC in clock stop mode - Automatic IFSD exchange(for T=1)
  0x0F,0x01,0x00,0x00,                              /* Max CCID Message Length : Maximun block size + header (261 + 10)*/
  0xFF,                                                             /* Class Get Response */
  0XFF,                                                         /* Class enveloppe */
  0x00,0x00,                                                    /* wLayout */
  0x00,                                                                 /* Pin Support */
  0x01,                                                         /* Max CCID Busy Slots */

/* Endpoint, INTERRUPT In */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  0x81,                                          /* bEndpointAddress */
  USB_ENDPOINT_TYPE_INTERRUPT,       /* bmAttributes */
  WBVAL(0x0008),                     /* wMaxPacketSize */
  0x18,          /* 32ms */          /* bInterval */

/* Endpoint, SMART CARD Bulk In */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  0x82,                /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,       /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  0x00,          /* 32ms */          /* bInterval */

/* Endpoint, SMART CARD BULK Out (from the host to the device) */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  0x02,               /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,       /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  0x00,          /* 32ms */          /* bInterval */

  /* Terminator */
  0                                  /* bLength */
};


The endpoints seem to be well configured since I can write {50, 03, 00, 00} on the Interrupt EP IN :

BYTE smcSlotStatusChange (void)
{
        BYTE msg[4];
        msg[0] = RDR_to_PC_NotifySlotChange; //bMessageType : 50
        msg[1] = 0x03;  //bmSlotICCstate 00000011 -  slot 0 status changed and slot 0 current state is ICC present (manual that I linked page 56)

        EP1DataSnd.pData = msg;
        EP1DataSnd.Count = 4;
        USB_DataInStage1(); //write to the EP IN 0x81
        return 0;
}

The host respond successfully with the telegram {63, 00, 00, 00, 00, 00, 01, 00, 00, 00} (PC_to_RDR_ICCPowerOff).

Then I successfully sended the RDR_to_PC_Slotstatus in the Bulk IN (0x82) {81, 00, 00, 00, 00, 00, 01, 01, 00, 01}

The host respond successfully with the telegram {62, 00, 00, 00, 00, 00, 02, 00, 00, 00} (PC_to_RDR_ICCPowerON).

THEN I TRIED TO SEND A RDR_to_PC_Datablock but the host doesn't catch it! I tried with the telegramms:
BYTE FirstDataBlock[14] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xXX, 0x40, 0xFE, 0x00}; //
BYTE FirstDataBlock[14] = {0x80, 0x04, 0x00, 0x00, 0x00, 0xXX, 0xFF, 0x40, 0xFE, 0x00, 0x03, 0x00, 0x00,0x00};

where 0xXX ist the last BULK-OUT received bSeq BYTE
but the Host does'nt take it! I can't see it on the USBLYzer!

Has anybody an Idea about it?

Here the protocol functions:

void smcDispatchMessage()
{
        BYTE ErrorCode;
//Initialize the pointers
        UsbMessageBuffer = EP2DataRcv.pData;
        UsbInMessageBuffer = EP2DataRcv.pData;

        switch (*UsbMessageBuffer)
        {
                case PC_to_RDR_IccPowerOn: //0x62
                        ErrorCode = PC_to_RDR_IccPowerON();
                        smcDataBlock(ErrorCode, FirstDataBlock);
                        break;
                case PC_to_RDR_IccPowerOff: //0x63
                        ErrorCode = PC_to_RDR_IccPowerOFF();
                        smcSlotStatus(ErrorCode, IccPowerON);
                        break;
}
}


Thanks in advance!


Parents
  • Here the functions:

    void smcSlotStatus(BYTE Err, BYTE* Mess)         //cnt = 10
    {
        *(UsbInMessageBuffer+OFFSET_BMESSAGETYPE) = Mess[0];
            *(UsbInMessageBuffer+OFFSET_BSTATUS) = CRD_GetSlotStatus();     //0x00
            *(UsbInMessageBuffer+OFFSET_BERROR) = Mess[OFFSET_BERROR];
            if(Err != SLOT_NO_ERROR)
            {
            *(UsbInMessageBuffer+OFFSET_BSTATUS) += 0x40;
            *(UsbInMessageBuffer+OFFSET_DWLENGTH) = 0x00;
            *(UsbInMessageBuffer+OFFSET_DWLENGTH+1) = 0x00;
            *(UsbInMessageBuffer+OFFSET_DWLENGTH+2) = 0x00;
            *(UsbInMessageBuffer+OFFSET_DWLENGTH+3) = 0x00;
            *(UsbInMessageBuffer+OFFSET_BERROR) = Err;
            };
            *(UsbInMessageBuffer+OFFSET_BSEQ)   =  *(UsbMessageBuffer+OFFSET_BSEQ);
            *(UsbInMessageBuffer+OFFSET_BSEQ+1) = Mess[OFFSET_BSEQ+1];
            *(UsbInMessageBuffer+OFFSET_BCLOCKSTATUS) = Mess[OFFSET_BCLOCKSTATUS];
            //UsbInMessageBuffer[OFFSET_BCLOCKSTATUS] = CRD_GetClockStatus();       */
            /* Copy the bytes and the size to the send buffer */
            EP2DataSnd.pData = UsbInMessageBuffer;
            EP2DataSnd.Count = OFFSET_BCLOCKSTATUS + 1;
            USB_DataInStage2();
            //Put the pointer to the start position
            UsbInMessageBuffer -= OFFSET_BCLOCKSTATUS;
    }
    
    void smcDataBlock(BYTE Err, BYTE* Mess)
    {
            *(UsbInMessageBuffer+OFFSET_BMESSAGETYPE) = Mess[0];
            *(UsbInMessageBuffer+OFFSET_BSTATUS) = CRD_GetSlotStatus();
            *(UsbInMessageBuffer+OFFSET_DWLENGTH) = Mess[OFFSET_DWLENGTH];
            *(UsbInMessageBuffer+OFFSET_DWLENGTH+1) = Mess[OFFSET_DWLENGTH+1];
            *(UsbInMessageBuffer+OFFSET_DWLENGTH+2) = Mess[OFFSET_DWLENGTH+2];
            *(UsbInMessageBuffer+OFFSET_DWLENGTH+3) = Mess[OFFSET_DWLENGTH+3];
            *(UsbInMessageBuffer+OFFSET_BSEQ)   =  *(UsbMessageBuffer+OFFSET_BSEQ);
            *(UsbInMessageBuffer+OFFSET_BSEQ+1) = Mess[OFFSET_BSEQ+1];
            *(UsbInMessageBuffer+OFFSET_BSEQ+2) = Mess[OFFSET_BSEQ+2];
            *(UsbInMessageBuffer+OFFSET_BCHAINPARAMETER) = Mess[OFFSET_BCHAINPARAMETER];
    
            for(index = 0; index<10; index++)
                    Result[index] = *(UsbInMessageBuffer+index);
            /* Copy the bytes and the size to the send buffer */
            EP2DataSnd.pData = UsbInMessageBuffer;
            EP2DataSnd.Count = OFFSET_BCHAINPARAMETER + 5;
            USB_DataInStage2();
    
            //Put the pointer to the start position
            UsbInMessageBuffer += OFFSET_BCHAINPARAMETER;
    }
    
    BYTE PC_to_RDR_IccPowerOFF(void)
    {
            if(*(UsbMessageBuffer+OFFSET_BSLOT) != 0)
                    return SLOTERROR_BAD_SLOT;
            if(*(UsbMessageBuffer+OFFSET_DWLENGTH) != 0 || *(UsbMessageBuffer+OFFSET_DWLENGTH+1) != 0
                    || *(UsbMessageBuffer+OFFSET_DWLENGTH+2) != 0 || *(UsbMessageBuffer+OFFSET_DWLENGTH+3) != 0)
                    return SLOTERROR_BAD_LENTGH;
            if( *(UsbMessageBuffer+OFFSET_ABRFU_3B) != 0 || *(UsbMessageBuffer+OFFSET_ABRFU_3B+1) != 0
                    ||*(UsbMessageBuffer+OFFSET_ABRFU_3B+2) != 0)
                    return SLOTERROR_BAD_ABRFU_3B;
    
      return SLOT_NO_ERROR;
    }
    
    BYTE PC_to_RDR_IccPowerON (void)
    {
            //BYTE ErrorCode;
    //      BYTE Voltage;
    
            if(*(UsbMessageBuffer+OFFSET_BSLOT) != 0)
                    return SLOTERROR_BAD_SLOT;
            if(*(UsbMessageBuffer+OFFSET_DWLENGTH) != 0 || *(UsbMessageBuffer+OFFSET_DWLENGTH+1) != 0
               || *(UsbMessageBuffer+OFFSET_DWLENGTH+2) != 0 || *(UsbMessageBuffer+OFFSET_DWLENGTH+3) != 0)
                    return SLOTERROR_BAD_LENTGH;
            if(*(UsbMessageBuffer+OFFSET_BPOWERSELECT) >= 0x04)
                    return SLOTERROR_BAD_POWERSELECT;
            if(*(UsbMessageBuffer+OFFSET_ABRFU_3B) != 0 || *(UsbMessageBuffer+OFFSET_ABRFU_3B+1) != 0)
                    return SLOTERROR_BAD_ABRFU_2B;
    
            return SLOT_NO_ERROR;
    }
    

    Thanks

  • > I choose to start a new thread instead of continue the last thread i ve initiated.

    It's better to show the original thread for reference,
    http://www.keil.com/forum/docs/thread15614.asp



    > but the Host does'nt take it! I can't see it on the USBLYzer!

    Looking in the sniffer log closely, you'll be aware that URBs (USB Request Blocks) are shown in a pair.
    In some sniffer, the pair is called down and up.
    The first one, down, shows a request to lower system driver, and the second one, up, is the reply to the request.
    For IN endpoint, the reply holds the transfer (packets) from the device.

    If you don't see the first one, the host doesn't read the IN endpoint, actually.
    In most case, the device driver doesn't like the last response from the device.

    If you see the first one, but don't see the second one, the device doesn't put the packet into the IN EP.
    It suggests an error on the firmware side.

    Which one is your case?



    smcSlotStatusChange()
    In the Smartcard Class Descriptor, single slot is declared (bMaxSlotIndex = 0).
    Send back just 2 byte of RDR_to_PC_NotifySlotChange message, {0x50, 0x03}
    What is USB_DataInStage1() ? Isn't just USB_WriteEP() call enough?

    #define CCID_EVENT_EP 0x81
    USB_WriteEP( CCID_EVENT_EP, msg, 2);

    Also, what is USB_DataInStage2() in smcSlotStatus() ?
    USB_WriteEP() is enough, too

    If USB_WriteEP() and USB_ReadEP() are called in main line code,
    guard these calls with disabling USB interrupt around these calls temporarily,
    or apply SWI. It is discussed recently on this topic.

    "No HID interrupt IN transfers"
    http://www.keil.com/forum/docs/thread15613.asp

    Tsuneo

Reply
  • > I choose to start a new thread instead of continue the last thread i ve initiated.

    It's better to show the original thread for reference,
    http://www.keil.com/forum/docs/thread15614.asp



    > but the Host does'nt take it! I can't see it on the USBLYzer!

    Looking in the sniffer log closely, you'll be aware that URBs (USB Request Blocks) are shown in a pair.
    In some sniffer, the pair is called down and up.
    The first one, down, shows a request to lower system driver, and the second one, up, is the reply to the request.
    For IN endpoint, the reply holds the transfer (packets) from the device.

    If you don't see the first one, the host doesn't read the IN endpoint, actually.
    In most case, the device driver doesn't like the last response from the device.

    If you see the first one, but don't see the second one, the device doesn't put the packet into the IN EP.
    It suggests an error on the firmware side.

    Which one is your case?



    smcSlotStatusChange()
    In the Smartcard Class Descriptor, single slot is declared (bMaxSlotIndex = 0).
    Send back just 2 byte of RDR_to_PC_NotifySlotChange message, {0x50, 0x03}
    What is USB_DataInStage1() ? Isn't just USB_WriteEP() call enough?

    #define CCID_EVENT_EP 0x81
    USB_WriteEP( CCID_EVENT_EP, msg, 2);

    Also, what is USB_DataInStage2() in smcSlotStatus() ?
    USB_WriteEP() is enough, too

    If USB_WriteEP() and USB_ReadEP() are called in main line code,
    guard these calls with disabling USB interrupt around these calls temporarily,
    or apply SWI. It is discussed recently on this topic.

    "No HID interrupt IN transfers"
    http://www.keil.com/forum/docs/thread15613.asp

    Tsuneo

Children
More questions in this forum