Trying to implement smart card reader with 3 slots on stm32f072. The reader for one card works quite well, but as soon as I try to add two more slots - there are problems. Knowing that CCID supports MultiSite I changed the descriptor file to the following:

  0x09,   /* bLength: Configuration Descriptor size */
  USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */

  0x01,   /* bNumInterfaces: 1 interface */
  0x01,   /* bConfigurationValue: */
  0x04,   /* iConfiguration: */
  0x80,         /*bmAttributes: bus powered */
  0x32,   /* MaxPower 100 mA */

 /********************  CCID **** interface ********************/
 0x09,   /* bLength: Interface Descriptor size */
 0x04,   /* bDescriptorType: */
 0x00,   /* bInterfaceNumber: Number of Interface */
 0x00,   /* bAlternateSetting: Alternate setting */
 0x03,   /* bNumEndpoints: 3 endpoints used */
 0x0B,   /* bInterfaceClass: user's interface for CCID */
 0x00,   /* bInterfaceSubClass : */
 0x00,   /* nInterfaceProtocol : None */
 0x05,   /* iInterface: */

 /*******************  CCID class descriptor ********************/
 0x36,   /* bLength: CCID Descriptor size */
 0x21,    /* bDescriptorType: Functional Descriptor type. */
 0x10,    /* bcdCCID(LSB): CCID Class Spec release number (1.00) */
 0x01,   /* bcdCCID(MSB) */

 0x02,    /* bMaxSlotIndex :highest available slot on this device */
 0x03,    /* bVoltageSupport: bit Wise OR for 01h-5.0V 02h-3.0V
                                04h 1.8V*/

 0x01,0x00,0x00,0x00,   /* dwProtocols: 0001h = Protocol T=0 */
 0x10,0x0E,0x00,0x00,   /* dwDefaultClock: 3.6Mhz = 3600kHz = 0x0E10, 
                         for 4 Mhz the value is (0x00000FA0) : 
                        This is used in ETU and waiting time calculations*/
 0x10,0x0E,0x00,0x00,   /* dwMaximumClock: Maximum supported ICC clock frequency  
                         in KHz. So, 3.6Mhz = 3600kHz = 0x0E10, 
                                       4 Mhz (0x00000FA0) : */
 0x00,          /* bNumClockSupported : no setting from PC 
                         If the value is 00h, the 
                        supported clock frequencies are assumed to be the 
                        default clock frequency defined by dwDefaultClock 
                        and the maximum clock frequency defined by 
                        dwMaximumClock */

 0xCD,0x25,0x00,0x00,   /* dwDataRate: Default ICC I/O data rate in bps
                        9677 bps = 0x25CD 
                        for example 10752 bps (0x00002A00) */

 0xCD,0x25,0x00,0x00,   /* dwMaxDataRate: Maximum supported ICC I/O data 
                        rate in bps */
 0x00,                 /* bNumDataRatesSupported :
                     The number of data rates that are supported by the CCID
                     If the value is 00h, all data rates between the default 
                     data rate dwDataRate and the maximum data rate 
                     dwMaxDataRate are supported.
                     Dont support GET_CLOCK_FREQUENCIES

 0x00,0x00,0x00,0x00,   /* dwMaxIFSD: 0 (T=0 only)   */
 0x00,0x00,0x00,0x00,   /* dwSynchProtocols  */
 0x00,0x00,0x00,0x00,   /* dwMechanical: no special characteristics */

                     /* dwFeatures: clk, baud rate, voltage : automatic */
                     /* 00000008h Automatic ICC voltage selection 
                     00000010h Automatic ICC clock frequency change
                     00000020h Automatic baud rate change according to 
                     active parameters provided by the Host or self 
                     determined 00000100h CCID can set 
                     ICC in clock stop mode      

                     Only one of the following values may be present to 
                     select a level of exchange:
                     00010000h TPDU level exchanges with CCID
                     00020000h Short APDU level exchange with CCID
                     00040000h Short and Extended APDU level exchange 
                     If none of those values : character level of exchange*/
 0x0F,0x01,0x00,0x00,  /* dwMaxCCIDMessageLength: Maximum block size + header*/
                     /* 261 + 10   */

 0x00,          /* bClassGetResponse*/
 0x00,          /* bClassEnvelope */
 0x00,0x00,     /* wLcdLayout : 0000h no LCD. */
 0x00,          /* bPINSupport : no PIN verif and modif  */
 0x03,          /* bMaxCCIDBusySlots    */

 /********************  CCID   Endpoints ********************/
 0x07,   /*Endpoint descriptor length = 7*/
 0x05,   /*Endpoint descriptor type */
 CCID_BULK_IN_EP,   /*Endpoint address (IN, address 1) */
 0x02,   /*Bulk endpoint type */
 0x00,   /*Polling interval in milliseconds */

 0x07,   /*Endpoint descriptor length = 7 */
 0x05,   /*Endpoint descriptor type */
 CCID_BULK_OUT_EP,   /*Endpoint address (OUT, address 1) */
 0x02,   /*Bulk endpoint type */
 0x00,   /*Polling interval in milliseconds*/

 0x07,   /*bLength: Endpoint Descriptor size*/
 0x05,   /*bDescriptorType:*/
 CCID_INTR_IN_EP,    /*bEndpointAddress: Endpoint Address (IN)*/
 0x03,   /* bmAttributes: Interrupt endpoint */
 0x18    /*Polling interval in milliseconds */

I also forcibly changed the response to the command RDR_to_PC_NotifySlotChange assignment 3Fh, which corresponds to the presence of cards in 3 slots. Windows provides and refers only to the slot 0.

Wanted to implement a composite usb, but ran into a problem - available only for stm32f072 7 endpoints, whereas for PCSC is needed for every 3 EP.

I was desperate to find a mistake. Can someone tell me how to solve this problem?


2 Answers 2


I know I was the one suggesting going the multi-slot route previously.

Unfortunately, after doing more research, it seems it isn't that simple: see Microsoft Class Drivers for USB CCID Smart Cards documentation:

Support for multiple slots on readers. If the reader has multiple slots, only slot 0 will be used. Devices that wish to expose multiple readers may develop a composite device (a CCID-compliant interface would then be required for each reader).

So it seems both the limits on the STM32 side and on the generic Microsoft driver side forbid you to go the easy route. The only solution left I now see is to develop your own PCSC driver (either with a custom protocol, or still conforming to the CCID specs). I know there are dual-interface (both contact and contactless) USB smart card readers that display themselves as two PCSC readers on Windows, so this is definitely possible (but they typically require a specific driver, indeed).

Note that the Linux CCID driver, however, claims to support multi-slot.

I can't provide much help on the driver development side, however (and if you need more information, StackOverflow would probably be more appropriate).


The transition to Linux is also not a success, because there are supported devices with a certain Vid and Pid. The problem was solved corny. I artificially swapped out the Vid and Pid of a multi-slot card reader assignment.

  • \$\begingroup\$ I believe your custom PID/VID can be added to a plist configuration file of the driver, so your reader gets recognized. Check the /usr/local/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist file, or something like that. Anyway, I am not sure the post here qualifies as an actual answer. That should probably have been a comment on my post. \$\endgroup\$
    – dim
    Commented Jun 5, 2019 at 13:29
  • \$\begingroup\$ I agree, but let it lie separately, because it turned out to be a simple solution that works on both Windows and Linux, without writing an additional draver or something else. Maybe someone will be useful. \$\endgroup\$ Commented Jun 6, 2019 at 4:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.