[PATCH 14/27] hw/usb/dev-smartcard-reader: release short bulk-in responses with xHCI
Marc-André Lureau <[email protected]> Wed, 05 Aug 2026 15:51:04 +0400
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
USBPacket describes the host controller's complete transfer request, not necessarily one packet on the USB wire. xHCI maps the buffers from all TRBs in a transfer descriptor into a single USBPacket, so p->iov.size can be much larger than the CCID bulk endpoint's 64-byte wMaxPacketSize. The smartcard reader kept a completed bulk-in response queued whenever the last copied chunk was exactly 64 bytes. This is necessary when the guest requested exactly 64 bytes: the next IN request must receive a zero-length packet to mark the end of the response. It is wrong when xHCI supplied a larger buffer, however. In that case the 64-byte result is already short relative to the USBPacket and xHCI completes the TD. Keeping the response current leaves it waiting for a ZLP request which never arrives and prevents later smartcard responses from being delivered. Release an exact-64-byte response when it is shorter than the host controller request, while retaining it for a request of exactly one maximum-sized packet. This fixes smartcard reader with xHCI. Signed-off-by: Marc-André Lureau <[email protected]> --- hw/usb/dev-smartcard-reader.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index d91376826c5c..699e236f624e 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1132,8 +1132,7 @@ err: s->bulk_out_pos = 0; } -static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p, - unsigned int max_packet_size) +static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p) { int len = 0; @@ -1148,7 +1147,7 @@ static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p, } s->current_bulk_in->pos += len; if (s->current_bulk_in->pos == s->current_bulk_in->len - && len != max_packet_size) { + && (len != CCID_MAX_PACKET_SIZE || len < p->iov.size)) { ccid_bulk_in_release(s); } } else { @@ -1180,7 +1179,7 @@ static void ccid_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_IN: switch (p->ep->nr) { case CCID_BULK_IN_EP: - ccid_bulk_in_copy_to_guest(s, p, dev->ep_ctl.max_packet_size); + ccid_bulk_in_copy_to_guest(s, p); break; case CCID_INT_IN_EP: if (s->notify_slot_change) { -- 2.55.0