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!
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
Oh sorry I ve forgotten the manual Im using:
www.usb.org/.../DWG_Smart-Card_CCID_Rev110.pdf
> 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
Hello, Thanks for replying Tsuneo
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. 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.
Well this is the case for me since the "down" URb says: "URB Bulk or Interrupt Transfer issued" and then the next URB says "URB Bulk or Interrupt Transfer failed"
This is the and the (I assume) unique tranfer failure I get from the USBlyzer! URB status is: "USBD_STATUS_BUFFER_OVERRUN", It a bit weird because its about 4 byte data even though Im trying to send at least 10 bytes data on the Bulk IN EP.
Send back just 2 byte of RDR_to_PC_NotifySlotChange message, {0x50, 0x03} I changed it but still get the same problem: BYTE FirstDataBlock[10] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, bSeqByte, 0x40, 0xFE, 0x00}; cannot be sent!
Here the definitions of USB_DataInStage1() and USB_DataInStage2():
void USB_DataInStage1 (void) { DWORD cnt; /*if the number of bytes is more than 1024, then cut it */ if (EP1DataSnd.Count > USB_MAX_PACKET0) { cnt = USB_MAX_PACKET0; } else { cnt = EP1DataSnd.Count; } cnt = USB_WriteEP(0x81, EP1DataSnd.pData,cnt); EP1DataSnd.pData += cnt; //increment the pointer to the datas to be transfered EP1DataSnd.Count -= cnt; //actualize the number of datas left to be transfered } void USB_DataInStage2 (void) { BYTE cnt; if (EP2DataSnd.Count > USB_MAX_PACKET0) { cnt = USB_MAX_PACKET0; } else { cnt = EP2DataSnd.Count; } cnt = USB_WriteEP(0x82, EP2DataSnd.pData,cnt); /********* this is for debugging purpose ************/ if ((*EP2DataSnd.pData == 0x80)&&(cnt>1)) { Result[0] = *(EP2DataSnd.pData); Result[1] = *(EP2DataSnd.pData+1); Result[2] = *(EP2DataSnd.pData+2); Result[3] = *(EP2DataSnd.pData+3); Result[4] = *(EP2DataSnd.pData+4); Result[5] = *(EP2DataSnd.pData+5); Result[6] = *(EP2DataSnd.pData+6); Result[7] = *(EP2DataSnd.pData+7); Result[8] = *(EP2DataSnd.pData+8); Result[9] = *(EP2DataSnd.pData+9);; set_cursor (0, 1); lcd_print ("RDR_to_PC_DataBlock sent"); } /****************** ***********************/ EP2DataSnd.pData += cnt; EP2DataSnd.Count -= cnt; }
Well I can't see any bug in these function definitions. By debbugging, I could see the datas to be sent in the Result array (USB_DataInStage2) and Im struggling to see where is the problem in the code!
I change the USB_writeEP as a SWI just exactly according to your recommendations in http://www.keil.com/forum/docs/thread15613.asp , IN VAIN!
I assume there is no problem in the bIntervals of the EP Configuration since the Full-Speed mode simply ignores these points. See www.usb.org/.../DWG_Smart-Card_CCID_Rev110.pdf page 21
Do you have any Idea on how to fix the problem?
Thank you very much
Ah after analysing the Sniffer I remark The URB IN at the Bulk IN 0x82 , Its the URB "down" one: "URB Bulk Transfer issued" But there is no "Reply" URB to this.
The particularity is this urb occurs after the host send the bytes {63, 00, 00, 00, 00, 00, 03, 00, 00, 00} (PC_to_RDR_ICCPowerOff).
So here the explanation of what is been displayed on the sniffer: 1- The host sends {62, 00, 00, 00, 00, 00, 02, 00, 00, 00} (PC_to_RDR_ICCPowerOn)
2- Then the device sends a URB "down" with a reply failure (4 bytes datas, nothing inside the data filed) URB Bulk Transfer failed (there is a successfull 74 bytes bulk IN tranfer before)
3- Then the host send the bytes {63, 00, 00, 00, 00, 00, 03, 00, 00, 00} (PC_to_RDR_ICCPowerOff).
4- Then I see my 10 bytes BULK IN transfer issue but with no reply URB.
It seems to be a timing problem maybe!
Do you have any idea on it?
Oh sorry, USB_MAX_PACKET0 ist of course 64 (as configured) and not 1024. I slightly changed USB_DataInStage2 for Data greater as 64:
void USB_DataInStage2 (void) { BYTE cnt; BYTE temp; temp = EP2DataSnd.Count; if (EP2DataSnd.Count > USB_MAX_PACKET0) { while(temp>USB_MAX_PACKET0) { temp-=USB_MAX_PACKET0; cnt = USB_WriteEP(0x82, EP2DataSnd.pData,USB_MAX_PACKET0); EP2DataSnd.pData += cnt; } cnt = USB_WriteEP(0x82, EP2DataSnd.pData,temp); } else { cnt = EP2DataSnd.Count; cnt = USB_WriteEP(0x82, EP2DataSnd.pData,cnt); } /********* this is for debugging purpose ************/ if ((*EP2DataSnd.pData == 0x80)&&(cnt>1)) { Result[0] = *(EP2DataSnd.pData); Result[1] = *(EP2DataSnd.pData+1); Result[2] = *(EP2DataSnd.pData+2); Result[3] = *(EP2DataSnd.pData+3); Result[4] = *(EP2DataSnd.pData+4); Result[5] = *(EP2DataSnd.pData+5); Result[6] = *(EP2DataSnd.pData+6); Result[7] = *(EP2DataSnd.pData+7); Result[8] = *(EP2DataSnd.pData+8); Result[9] = *(EP2DataSnd.pData+9);; set_cursor (0, 1); lcd_print ("RDR_to_PC_DataBlock sent"); } /****************** reinitialyze EP2DataSnd.Count ***********************/ EP2DataSnd.Count = 0; }
and here the while loop in the main.c:
while (1) // Loop forever { ///*****************USB****************** if (EP2DataSnd.Count>2) USB_DataInStage2(); smcDispatchMessage(); }
Well the problem still remains...
In the first place, is smcDispatchMessage() called from the main line (or timered) polling loop? Or USB_EndPoint2( USB_EVT_OUT ) (ie. EP2 ISR) calls the routine?
Either will do, But depending on the strategy you apply, the code flow differs significantly. This isn't directly concerned to current problem, but this code has another problem.
void USB_DataInStage2 (void) { ... if (EP2DataSnd.Count > USB_MAX_PACKET0) { while(temp>USB_MAX_PACKET0) { temp-=USB_MAX_PACKET0; cnt = USB_WriteEP(0x82, EP2DataSnd.pData,USB_MAX_PACKET0); EP2DataSnd.pData += cnt; } cnt = USB_WriteEP(0x82, EP2DataSnd.pData,temp); }
In above code, the large data is split into packets of endpoint wMaxPacketSize. So far, so good. But USB_WriteEP() is repeatedly called without checking buffer empty. It may cause overwrite to the EP buffer.
When USB_EndPoint2( USB_EVT_IN ) is called, it shows the timing in which the EP2 IN buffer goes empty. Raise a flag in USB_EndPoint2(), and poll this flag.