[PATCH 16/27] hw/usb/dev-smartcard-reader: derive queue counts from start/end indices

Marc-AndrĂ© Lureau <[email protected]> Wed, 05 Aug 2026 15:51:06 +0400
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
Replace the redundant bulk_in_pending_num and pending_answers_num shadow
counters with helper functions that compute the count from (end - start).
This removes redundant bookkeeping and potential issues.

pending_answers_num is kept for migration reasons, but since
pending_answers_{start,end} are not migrated, we can just do a best
effort for the following migration fix.

Signed-off-by: Marc-AndrĂ© Lureau <[email protected]>
---
 hw/usb/dev-smartcard-reader.c | 47 +++++++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 20 deletions(-)

diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 3f128791f3ef..e3c86cb90e6c 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -295,14 +295,13 @@ struct USBCCIDState {
     BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
     uint32_t bulk_in_pending_start;
     uint32_t bulk_in_pending_end; /* first free */
-    uint32_t bulk_in_pending_num;
     uint8_t  bulk_out_data[BULK_OUT_DATA_SIZE];
     uint32_t bulk_out_pos;
     uint64_t last_answer_error;
     Answer pending_answers[PENDING_ANSWERS_NUM];
     uint32_t pending_answers_start;
     uint32_t pending_answers_end;
-    uint32_t pending_answers_num;
+    uint32_t pending_answers_num; /* for migration compatibility */
     uint8_t  bError;
     uint8_t  bmCommandStatus;
     uint8_t  bProtocolNum;
@@ -315,6 +314,20 @@ struct USBCCIDState {
     bool accurate_message_length;
 };
 
+static uint32_t ccid_bulk_in_pending_num(USBCCIDState *s)
+{
+    uint32_t n = s->bulk_in_pending_end - s->bulk_in_pending_start;
+    assert(n <= BULK_IN_PENDING_NUM);
+    return n;
+}
+
+static uint32_t ccid_pending_answers_num(USBCCIDState *s)
+{
+    uint32_t n = s->pending_answers_end - s->pending_answers_start;
+    assert(n <= PENDING_ANSWERS_NUM);
+    return n;
+}
+
 /*
  * CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
  * "USB Device Framework", section 9.6.1, in the Universal Serial Bus
@@ -513,12 +526,11 @@ static void ccid_card_apdu_from_guest(CCIDCardState *card,
 
 static bool ccid_has_pending_answers(USBCCIDState *s)
 {
-    return s->pending_answers_num > 0;
+    return ccid_pending_answers_num(s) > 0;
 }
 
 static void ccid_clear_pending_answers(USBCCIDState *s)
 {
-    s->pending_answers_num = 0;
     s->pending_answers_start = 0;
     s->pending_answers_end = 0;
 }
@@ -533,7 +545,7 @@ static void ccid_print_pending_answers(USBCCIDState *s)
         DPRINTF(s, D_VERBOSE, " empty\n");
         return;
     }
-    for (i = s->pending_answers_start, count = s->pending_answers_num ;
+    for (i = s->pending_answers_start, count = ccid_pending_answers_num(s) ;
          count > 0; count--, i++) {
         answer = &s->pending_answers[i % PENDING_ANSWERS_NUM];
         if (count == 1) {
@@ -548,8 +560,7 @@ static void ccid_add_pending_answer(USBCCIDState *s, CCID_Header *hdr)
 {
     Answer *answer;
 
-    assert(s->pending_answers_num < PENDING_ANSWERS_NUM);
-    s->pending_answers_num++;
+    assert(ccid_pending_answers_num(s) < PENDING_ANSWERS_NUM);
     answer =
         &s->pending_answers[(s->pending_answers_end++) % PENDING_ANSWERS_NUM];
     answer->slot = hdr->bSlot;
@@ -562,8 +573,7 @@ static void ccid_remove_pending_answer(USBCCIDState *s,
 {
     Answer *answer;
 
-    assert(s->pending_answers_num > 0);
-    s->pending_answers_num--;
+    assert(ccid_pending_answers_num(s) > 0);
     answer =
         &s->pending_answers[(s->pending_answers_start++) % PENDING_ANSWERS_NUM];
     *slot = answer->slot;
@@ -581,24 +591,22 @@ static void ccid_bulk_in_clear(USBCCIDState *s)
     }
     s->bulk_in_pending_start = 0;
     s->bulk_in_pending_end = 0;
-    s->bulk_in_pending_num = 0;
 }
 
 static void ccid_bulk_in_release(USBCCIDState *s)
 {
     BulkIn *bulk_in;
 
-    assert(s->bulk_in_pending_num > 0);
+    assert(ccid_bulk_in_pending_num(s) > 0);
     bulk_in =
         &s->bulk_in_pending[s->bulk_in_pending_start % BULK_IN_PENDING_NUM];
     bulk_in->pos = 0;
     s->bulk_in_pending_start++;
-    s->bulk_in_pending_num--;
 }
 
 static BulkIn *ccid_bulk_in_peek(USBCCIDState *s)
 {
-    if (s->bulk_in_pending_num == 0) {
+    if (ccid_bulk_in_pending_num(s) == 0) {
         return NULL;
     }
     return &s->bulk_in_pending[
@@ -618,14 +626,13 @@ static void *ccid_reserve_recv_buf(USBCCIDState *s, uint16_t len)
                            __func__, len, BULK_IN_BUF_SIZE);
         return NULL;
     }
-    if (s->bulk_in_pending_num >= BULK_IN_PENDING_NUM) {
+    if (ccid_bulk_in_pending_num(s) >= BULK_IN_PENDING_NUM) {
         DPRINTF(s, D_WARN, "usb-ccid.c: %s: No free bulk_in buffers. "
                            "discarding message.\n", __func__);
         return NULL;
     }
     bulk_in =
         &s->bulk_in_pending[(s->bulk_in_pending_end++) % BULK_IN_PENDING_NUM];
-    s->bulk_in_pending_num++;
     bulk_in->len = len;
     return bulk_in->data;
 }
@@ -988,7 +995,7 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
         ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq);
         return;
     }
-    if (s->pending_answers_num > 0) {
+    if (ccid_pending_answers_num(s) > 0) {
         DPRINTF(s, D_WARN,
                 "usb-ccid: slot already busy, rejecting apdu\n");
         ccid_report_error_failed(s, ERROR_CMD_SLOT_BUSY);
@@ -1039,7 +1046,7 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
      * first packet when all response slots are committed.
      */
     if (s->bulk_out_pos == 0 && /* start of message */
-        s->bulk_in_pending_num + s->pending_answers_num >=
+        ccid_bulk_in_pending_num(s) + ccid_pending_answers_num(s) >=
             BULK_IN_PENDING_NUM) {
         p->status = USB_RET_NAK;
         return;
@@ -1233,7 +1240,7 @@ static void ccid_flush_pending_answers(USBCCIDState *s)
 
 static Answer *ccid_peek_next_answer(USBCCIDState *s)
 {
-    return s->pending_answers_num == 0
+    return ccid_pending_answers_num(s) == 0
         ? NULL
         : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
 }
@@ -1440,7 +1447,7 @@ static bool ccid_pre_save(void *opaque, Error **errp)
 {
     USBCCIDState *s = opaque;
 
-    if (s->pending_answers_num || s->bulk_in_pending_num) {
+    if (ccid_pending_answers_num(s) || ccid_bulk_in_pending_num(s)) {
         error_setg(errp, "usb-ccid has pending queue state which cannot be "
                    "migrated safely");
         return false;
@@ -1512,7 +1519,7 @@ static const VMStateDescription ccid_vmstate = {
         VMSTATE_UINT32(bulk_in_pending_end, USBCCIDState),
         VMSTATE_STRUCT_ARRAY(pending_answers, USBCCIDState,
                         PENDING_ANSWERS_NUM, 1, answer_vmstate, Answer),
-        VMSTATE_UINT32(pending_answers_num, USBCCIDState),
+        VMSTATE_UINT32(pending_answers_num, USBCCIDState), /* for compatibility */
         VMSTATE_UNUSED(1), /* was migration_state */
         VMSTATE_UINT32(state_vmstate, USBCCIDState),
         VMSTATE_END_OF_LIST()

-- 
2.55.0