[PATCH 05/27] hw/usb/dev-smartcard-reader: fix dwMaxCCIDMessageLength descriptor

Marc-AndrĂ© Lureau <[email protected]> Wed, 05 Aug 2026 15:50:55 +0400
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
The CCID class descriptor advertises dwMaxCCIDMessageLength = 65554
(the extended-APDU maximum), but bulk-IN storage is only 384 bytes.
Since the device operates at TPDU level, the spec minimum is just
wMaxPacketSize (64 bytes), and the actual limit is the bulk-IN buffer.

Set dwMaxCCIDMessageLength to BULK_IN_BUF_SIZE (384) so the advertised
capability matches the implementation. Guard the change behind a
machine-compat property so older machine types preserve the original
descriptor for guest reproducibility.

Fixes: 367071447ec5 ("usb-ccid: add CCID bus")
Signed-off-by: Marc-AndrĂ© Lureau <[email protected]>
---
 hw/core/machine.c             |  1 +
 hw/usb/dev-smartcard-reader.c | 12 +++++++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index 73b4d82b4a1d..01e50ebe05e0 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -51,6 +51,7 @@ GlobalProperty hw_compat_11_0[] = {
     { TYPE_ARM_SMMUV3, "ssidsize", "0" },
     { TYPE_ARM_SMMUV3, "oas", "44" },
     { "migration", "switchover-ack-legacy", "on" },
+    { "usb-ccid", "x-accurate-message-length", "off" },
 };
 const size_t hw_compat_11_0_len = G_N_ELEMENTS(hw_compat_11_0);
 
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 3580465df368..a14062948071 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -314,6 +314,7 @@ struct USBCCIDState {
     uint8_t  powered;
     uint8_t  notify_slot_change;
     uint8_t  debug;
+    bool accurate_message_length;
 };
 
 /*
@@ -326,7 +327,7 @@ struct USBCCIDState {
  *   0dc3:1004 Athena Smartcard Solutions, Inc.
  */
 
-static const uint8_t qemu_ccid_descriptor[] = {
+static uint8_t qemu_ccid_descriptor[] = {
         /* Smart Card Device Class Descriptor */
         0x36,       /* u8  bLength; */
         0x21,       /* u8  bDescriptorType; Functional */
@@ -387,7 +388,10 @@ static const uint8_t qemu_ccid_descriptor[] = {
                      * u32 dwMaxCCIDMessageLength; For extended APDU in
                      * [261 + 10 , 65544 + 10]. Otherwise the minimum is
                      * wMaxPacketSize of the Bulk-OUT endpoint
+                     *
+                     * Corrected to BULK_IN_BUF_SIZE when x-accurate-message-length
                      */
+#define CCID_DESC_OFFSET_DW_MAX_MSG_LEN 44
         0x12, 0x00, 0x01, 0x00,
         0xFF,       /*
                      * u8  bClassGetResponse; Significant only for CCID that
@@ -1329,6 +1333,10 @@ static void ccid_realize(USBDevice *dev, Error **errp)
 {
     USBCCIDState *s = USB_CCID_DEV(dev);
 
+    if (s->accurate_message_length) {
+        stl_le_p(&qemu_ccid_descriptor[CCID_DESC_OFFSET_DW_MAX_MSG_LEN],
+                 BULK_IN_BUF_SIZE);
+    }
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
     qbus_init(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev), NULL);
@@ -1445,6 +1453,8 @@ static const VMStateDescription ccid_vmstate = {
 
 static const Property ccid_properties[] = {
     DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
+    DEFINE_PROP_BOOL("x-accurate-message-length", USBCCIDState,
+                     accurate_message_length, true),
 };
 
 static void ccid_class_initfn(ObjectClass *klass, const void *data)

-- 
2.55.0