Signed-off-by: Klaus Ripke <klaus.ri...@secunet.com>

hw/usb/dev-smartcard-reader.c:
add option for a multislot usb ccid device, similar to audio multi.

(v2 with slight formatting fix on " + ")

---
 hw/usb/dev-smartcard-reader.c | 106 +++++++++++++++++++++++++++++++++-
 1 file changed, 103 insertions(+), 3 deletions(-)

diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-
reader.c
index be0a4fc3bc..30d8892b4e 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -90,10 +90,13 @@ OBJECT_DECLARE_SIMPLE_TYPE(USBCCIDState,
USB_CCID_DEV)
  *  usbccid.sys (winxp, others untested) is a class driver so it
doesn't care.
  *  linux has a number of class drivers, but openct filters based on
  *   vendor/product (/etc/openct.conf under fedora), hence Gemplus.
+ * Use a Omnikey/HID 3121 with multislot for distinction.
  */
 #define CCID_VENDOR_ID                  0x08e6
 #define CCID_PRODUCT_ID                 0x4433
 #define CCID_DEVICE_VERSION             0x0000
+#define CCID_VENDOR_ID_MULTI            0x076b
+#define CCID_PRODUCT_ID_MULTI           0x3021
 
 /*
  * BULK_OUT messages from PC to Reader
@@ -312,7 +315,9 @@ struct USBCCIDState {
     uint8_t  bmSlotICCState;
     uint8_t  powered;
     uint8_t  notify_slot_change;
+    /* properties */
     uint8_t  debug;
+    bool     multi;
 };
 
 /*
@@ -411,6 +416,34 @@ static const uint8_t qemu_ccid_descriptor[] = {
         0x01,       /* u8  bMaxCCIDBusySlots; */
 };
 
+static const uint8_t qemu_ccid_descriptor_multi[] = {
+        /* Smart Card Device Class Descriptor */
+        0x36,       /* u8  bLength; */
+        0x21,       /* u8  bDescriptorType; Functional */
+        0x10, 0x01, /* u16 bcdCCID; CCID Specification Release Number.
*/
+        0x0e,       /* u8  bMaxSlotIndex; 14, as 16 slots can cause
trouble. */
+        0x07,       /* u8  bVoltageSupport; 01h - 5.0v, 02h - 3.0, 03
- 1.8 */
+
+        0x01, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/
+        0x00, 0x00, /* PPPP: see above */
+        0xa0, 0x0f, 0x00, 0x00, /* u32 dwMaximumClock; */
+        0x00, 0x00, 0x01, 0x00,
+        0x00, /* u8 bNumClockSupported; see above */
+        0x80, 0x25, 0x00, 0x00, /* u32 dwMaxDataRate ; see above */
+        0x00, 0xC2, 0x01, 0x00,
+        0x00,       /* u8  bNumDataRatesSupported; see above */
+        0xfe, 0x00, 0x00, 0x00, /* u32 dwMaxIFSD; see above */
+        0x00, 0x00, 0x00, 0x00, /* u32 dwSyncProtocols; see above */
+        0x00, 0x00, 0x00, 0x00, /* u32 dwMechanical; see above */
+        0xfe, 0x04, 0x04, 0x00, /* u32 dwFeatures; 400 for better
compat. */
+        0x12, 0x00, 0x01, 0x00, /* u32 dwMaxCCIDMessageLength; see
above */
+        0xFF,       /* u8  bClassGetResponse; see above */
+        0xFF,       /* u8  bClassEnvelope; see above */
+        0x00, 0x00, /* u16 wLcdLayout; see above */
+        0x01,       /* u8  bPINSupport; see above */
+        0x0f,       /* u8  bMaxCCIDBusySlots; modified from 1 */
+};
+
 enum {
     STR_MANUFACTURER = 1,
     STR_PRODUCT,
@@ -457,6 +490,38 @@ static const USBDescIface desc_iface0 = {
     }
 };
 
+static const USBDescIface desc_iface0_multi = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 3,
+    .bInterfaceClass               = USB_CLASS_CSCID,
+    .bInterfaceSubClass            = USB_SUBCLASS_UNDEFINED,
+    .bInterfaceProtocol            = 0x00,
+    .iInterface                    = STR_INTERFACE,
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* smartcard descriptor */
+            .data = qemu_ccid_descriptor_multi,
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | CCID_INT_IN_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .bInterval             = 255,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | CCID_BULK_IN_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | CCID_BULK_OUT_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },
+    }
+};
+
 static const USBDescDevice desc_device = {
     .bcdUSB                        = 0x0110,
     .bMaxPacketSize0               = 64,
@@ -474,6 +539,23 @@ static const USBDescDevice desc_device = {
     },
 };
 
+static const USBDescDevice desc_device_multi = {
+    .bcdUSB                        = 0x0110,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = USB_CFG_ATT_ONE |
USB_CFG_ATT_SELFPOWER |
+                                     USB_CFG_ATT_WAKEUP,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface0_multi,
+        },
+    },
+};
+
 static const USBDesc desc_ccid = {
     .id = {
         .idVendor          = CCID_VENDOR_ID,
@@ -487,6 +569,19 @@ static const USBDesc desc_ccid = {
     .str  = desc_strings,
 };
 
+static const USBDesc desc_ccid_multi = {
+    .id = {
+        .idVendor          = CCID_VENDOR_ID_MULTI,
+        .idProduct         = CCID_PRODUCT_ID_MULTI,
+        .bcdDevice         = CCID_DEVICE_VERSION,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_multi,
+    .str  = desc_strings,
+};
+
 static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t
*len)
 {
     CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
@@ -1293,10 +1388,12 @@ static void ccid_card_realize(DeviceState
*qdev, Error **errp)
     USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
     USBCCIDState *s = USB_CCID_DEV(dev);
     Error *local_err = NULL;
+    const USBDesc *desc = usb_device_get_usb_desc(dev);
+    uint8_t bMaxSlotIndex = desc->full->confs[0].ifs-
>descs[0].data[4];
 
-    if (card->slot != 0) {
-        error_setg(errp, "usb-ccid supports one slot, can't add %d",
-                   card->slot);
+    if (card->slot > bMaxSlotIndex) {
+        error_setg(errp, "usb-ccid supports %d slots, can't add %d",
+                   bMaxSlotIndex + 1, card->slot);
         return;
     }
     if (s->card != NULL) {
@@ -1317,6 +1414,8 @@ static void ccid_realize(USBDevice *dev, Error
**errp)
 {
     USBCCIDState *s = USB_CCID_DEV(dev);
 
+    dev->usb_desc = s->multi ? &desc_ccid_multi : &desc_ccid;
+
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
     qbus_init(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev),
NULL);
@@ -1433,6 +1532,7 @@ static const VMStateDescription ccid_vmstate = {
 
 static Property ccid_properties[] = {
     DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
+    DEFINE_PROP_BOOL("multi", USBCCIDState, multi, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.34.1

-- 
Klaus Ripke
Senior Developer
Public Authorities Division
secunet Security Networks AG

Telefon:  +49 201 5454-2982

Reply via email to