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