Hi,

I am trying to implement a composite USB device, which consists of a Smart card 
Chip Card Interface Device (CCID) and a mass storage device, on an embedded 
platform (ARM processor) using Configfs composite gadget. I was able to 
successfully setup the mass storage device but I am having some issues with the 
CCID part. My question is, is it possible to setup a USB composite device 
consisting of a smart card CCID and a mass storage device using Configfs? Or 
more generally speaking, how can I pass a class descriptor, specific to a 
particular interface, to Configfs? I am using kernel 3.14 with Configfs 
compiled into the kernel only with mass storage and FunctionFS support.

Here is some background and what I have tried thus far...

Using a previous implementation, I was able to successfully expose the embedded 
device as a CCID using gadgetfs and implementing the necessary user space 
application. I am hoping to improve on this by adding a mass storage device, 
and to me Configfs looks like the way to go. My idea is to use the mass_storage 
function of Configfs to expose the mass storage device and FunctionFS the 
expose the CCID.

My current implementation is setup by using the following bash script (this is 
only for the CCID):
#--------------------------------------------------------------------
CONFIG_HOME=/sys/kernel/config/usb_gadget

mount -t configfs configfs /sys/kernel/config

mkdir $CONFIG_HOME/g1
cd $CONFIG_HOME/g1
echo 0x0200 > bcdUSB
echo 0x2A18 > idVendor
echo 0x5000 > idProduct

mkdir strings/0x409
echo "my-manufacturer" > strings/0x409/manufacturer
echo "my-product" > strings/0x409/product
echo "my-serialnumber" > strings/0x409/serialnumber

mkdir functions/ffs.ccid
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "Config 1" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower
ln -s functions/ffs.ccid configs/c.1

mount -t functionfs ccid /dev/gadget
#---------------------------------------------------------------------

After this, I tweaked the previous CCID user space implementation to only pass 
the interface, class, and endpoint descriptors to the control endpoint "ep0". 
But I get the following error from the kernel after I run the user space 
application:
"ffs_do_desc()
hid descriptor
invalid length: 54 (descriptor 33)".
This means that one of my descriptors, length 54, is not equal to the size of a 
hid_descriptor structure.

It appears as if the problem lies with the class descriptor (USB specification 
http://www.usb.org/developers/docs/devclass_docs/DWG_Smart-Card_CCID_Rev110.pdf 
page 17). Digging around in the kernel code I found the problem (f_fs.c). The 
CCID descriptor is identified by a bDescriptorType value of 0x21 which happens 
to correspond to the HID_DT_HID (USB_TYPE_CLASS | 0x01) makro used to identify 
the type of descriptor in function ffs_do_desc(). The kernel therefore thinks I 
am passing a HID descriptor when in fact I am passing a Smart card CCID class 
descriptor. I suspect the question now boils down to, "How do I pass a class 
descriptor to Configfs"?

The USB descriptors of my device should look like this:
Device descriptor
    Configuration descriptor
        Interface descriptor (USB_CLASS_CSCID)
            Class descriptor
            Endpoint descriptor
            Endpoint descriptor

Here is the output from lsusb when I used the gadgetfs implementation (I 
presume the new implementation should generate the same descriptors):
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x2a18 
  idProduct          0x5000 
  bcdDevice            3.14
  iManufacturer           1 
  iProduct                2 
  iSerial                 3 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           86
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              250mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        11 Chip/SmartCard
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              5 
      ChipCard Interface Descriptor:
        bLength                54
        bDescriptorType        33
        bcdCCID              1.10  (Warning: Only accurate for version 1.0)
        nMaxSlotIndex           0
        bVoltageSupport         7  5.0V 3.0V 1.8V 
        dwProtocols             3  T=0 T=1
        dwDefaultClock       5000
        dwMaxiumumClock      5000
        bNumClockSupported      1
        dwDataRate         115200 bps
        dwMaxDataRate      115200 bps
        bNumDataRatesSupp.      1
        dwMaxIFSD             254
        dwSyncProtocols  00000000 
        dwMechanical     00000000 
        dwFeatures       0014047E
          Auto configuration based on ATR
          Auto activation on insert
          Auto voltage selection
          Auto clock change
          Auto baud rate change
          Auto parameter negotation made by CCID
          Auto IFSD exchange
          Short and extended APDU level exchange
        dwMaxCCIDMsgLen     65504
        bClassGetResponse    echo
        bClassEnvelope       echo
        wlcdLayout           none
        bPINSupport             0 
        bMaxCCIDBusySlots       1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0

I was curious what would happen if I briefly convinced the kernel that my 
descriptor data was correct and removed the error checking from the 
ffs_do_desc() function for HID_DT_HID descriptors (this is the part of the code 
that is raising the error). The result was that the implementation works on 
Linux (I tested on Ubuntu 14.04 and was able to communicate with my device) but 
not on Windows. lsusb generates the same USB descriptor as shown above for the 
"hacked" implementation. This is obviously not a valid solution but the result 
of mere curiosity.

Any help and suggestions will be much appreciated!

Cheers,
Pieter

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to