1- /* $Id: UsbCardReader.cpp 112403 2026-01-11 19:29:08Z knut.osmundsen @oracle.com $ */
1+ /* $Id: UsbCardReader.cpp 114701 2026-07-14 13:09:24Z vitali.pelenjow @oracle.com $ */
22/* * @file
33 * UsbCardReader - Usb Smart Card Reader implementation.
44 */
2626 */
2727
2828#define LOG_GROUP LOG_GROUP_USB_CARDREADER
29+ #include < VBox/AssertGuest.h>
2930#include < VBox/param.h>
3031#include < VBox/vmm/pdmusb.h>
3132#include < VBox/log.h>
@@ -933,9 +934,10 @@ static int uscrResponseOK(PUSBCARDREADER pThis,
933934}
934935
935936
936- static uint32_t uscrResponseRead (PUSBCARDREADER pThis,
937- uint8_t *pu8Data,
938- uint32_t cbData)
937+ static int uscrResponseRead (PUSBCARDREADER pThis,
938+ uint8_t *pu8Data,
939+ uint32_t cbData,
940+ uint32_t *pcbOut)
939941{
940942 USCRRSP *pRsp = pThis->pRspCurrent ;
941943
@@ -945,7 +947,7 @@ static uint32_t uscrResponseRead(PUSBCARDREADER pThis,
945947
946948 if (!pRsp)
947949 {
948- return 0 ;
950+ return VERR_NO_DATA ;
949951 }
950952
951953 RTListNodeRemove (&pRsp->nodeRsp );
@@ -983,7 +985,8 @@ static uint32_t uscrResponseRead(PUSBCARDREADER pThis,
983985 /* Save the current response pointer for next invocation. */
984986 pThis->pRspCurrent = pRsp;
985987
986- return cbToCopy;
988+ *pcbOut = cbToCopy;
989+ return VINF_SUCCESS ;
987990}
988991
989992static void uscrResponseCleanup (PUSBCARDREADER pThis)
@@ -1013,21 +1016,29 @@ static void uscrResponseCleanup(PUSBCARDREADER pThis)
10131016}
10141017
10151018
1016- typedef uint32_t FNREADDATA (PUSBCARDREADER pThis, uint8_t *pu8Data, uint32_t cbData);
1019+ /* Callback to read data into a bulk-in or interrupt URB. Returns VERR_NO_DATA if data is currently not available. */
1020+ typedef int FNREADDATA (PUSBCARDREADER pThis, uint8_t *pu8Data, uint32_t cbData, uint32_t *pcbOut);
10171021typedef FNREADDATA *PFNREADDATA ;
10181022
1019- static void urbQueueComplete (PUSBCARDREADER pThis, URBQUEUE *pQueue, PFNREADDATA pfnReadData, bool fDataOnly )
1023+ static void urbQueueComplete (PUSBCARDREADER pThis, URBQUEUE *pQueue, PFNREADDATA pfnReadData)
10201024{
10211025 PVUSBURB pUrb = pQueue->pUrbHead ;
10221026 while (pUrb)
10231027 {
1024- uint32_t cbDataReturned = pfnReadData?
1025- pfnReadData (pThis, &pUrb->pbData [0 ], pUrb->cbData ):
1026- 0 ;
1028+ uint32_t cbDataReturned = 0 ;
10271029
1028- if (fDataOnly && cbDataReturned == 0 )
1030+ /* 'pfnReadData == NULL' means that all queued URBs must be completed with no data. */
1031+ if (pfnReadData)
10291032 {
1030- break ;
1033+ int rc = pfnReadData (pThis, &pUrb->pbData [0 ], pUrb->cbData , &cbDataReturned);
1034+ if (rc == VERR_NO_DATA )
1035+ {
1036+ /* If the caller wants data and data is not available, then keep the URB in the queue for future data. */
1037+ break ;
1038+ }
1039+
1040+ if (RT_FAILURE (rc))
1041+ cbDataReturned = 0 ; /* Complete URB with zero data size. */
10311042 }
10321043
10331044 bool fRemoved = urbQueueRemove (pQueue, pUrb);
@@ -2388,17 +2399,17 @@ static int usbCardReaderBulkInPipe(PUSBCARDREADER pThis, PUSBCARDREADEREP pEp, P
23882399 * Add the URB to the BulkIn queue and complete URBs from the queue.
23892400 */
23902401 urbQueueAddTail (&pThis->urbQueues .BulkIn , pUrb);
2391- urbQueueComplete (pThis, &pThis->urbQueues .BulkIn , uscrResponseRead, true /* fDataOnly */ );
2402+ urbQueueComplete (pThis, &pThis->urbQueues .BulkIn , uscrResponseRead);
23922403
23932404 return VINF_SUCCESS ;
23942405}
23952406
23962407
2397- static uint32_t uscrEventRead (PUSBCARDREADER pThis, uint8_t *pu8Data, uint32_t cbData)
2408+ static int uscrEventRead (PUSBCARDREADER pThis, uint8_t *pu8Data, uint32_t cbData, uint32_t *pcbOut )
23982409{
2399- RT_NOREF1 (cbData);
2400- uint32_t cbReturned = 0 ;
2410+ ASSERT_GUEST_RETURN (cbData >= sizeof (VUSBCARDREADERNOTIFYSLOTCHANGE ), VERR_BUFFER_OVERFLOW );
24012411
2412+ int rc = VINF_SUCCESS ;
24022413 if (pThis->fICCStateChanged )
24032414 {
24042415 pThis->fICCStateChanged = false ;
@@ -2413,12 +2424,14 @@ static uint32_t uscrEventRead(PUSBCARDREADER pThis, uint8_t *pu8Data, uint32_t c
24132424 pNotify->bmSlotICCState |= 0x01 ; /* ICC present */
24142425 }
24152426
2416- cbReturned = sizeof (VUSBCARDREADERNOTIFYSLOTCHANGE );
2427+ *pcbOut = sizeof (VUSBCARDREADERNOTIFYSLOTCHANGE );
24172428
2418- UCRLOG ((" Reporting a slot change\n %.*Rhxs\n " , cbReturned , pu8Data));
2429+ UCRLOG ((" Reporting a slot change\n %.*Rhxs\n " , *pcbOut , pu8Data));
24192430 }
2431+ else
2432+ rc = VERR_NO_DATA ;
24202433
2421- return cbReturned ;
2434+ return rc ;
24222435}
24232436
24242437
@@ -2433,13 +2446,13 @@ static int usbCardReaderIntPipe(PUSBCARDREADER pThis, PUSBCARDREADEREP pEp, PVUS
24332446
24342447 /* If there is a pending URB, complete it without data. It is most likely cancelled.
24352448 *
2436- * The webcam does not complete URB if there is no data. Therefore if a new intr-in URB is submitted,
2449+ * The card reader does not complete URB if there is no data. Therefore if a new intr-in URB is submitted,
24372450 * it means that the old URB is not ok anymore and returned data in it may be lost.
24382451 */
2439- urbQueueComplete (pThis, &pThis->urbQueues .IntrIn , NULL /* no data */ , false /* fDataOnly */ );
2452+ urbQueueComplete (pThis, &pThis->urbQueues .IntrIn , NULL /* no data */ );
24402453
24412454 urbQueueAddTail (&pThis->urbQueues .IntrIn , pUrb);
2442- urbQueueComplete (pThis, &pThis->urbQueues .IntrIn , uscrEventRead, true /* fDataOnly */ );
2455+ urbQueueComplete (pThis, &pThis->urbQueues .IntrIn , uscrEventRead);
24432456
24442457 return VINF_SUCCESS ;
24452458}
@@ -2593,8 +2606,14 @@ static void uscrStatusMonitorProcess(PUSBCARDREADER pThis)
25932606 * because exclusive access is used. The disconnect request is sent if
25942607 * the card is connected: usbCardReaderSendDisconnect checks this condition.
25952608 */
2596- usbCardReaderSendDisconnect (pThis, pSlot, DISCONNECT_ONSTATUSCHANGE );
2597- pThis->enmICCConnState = ICCNOCONNECTION ;
2609+ if ((pThis->u32EventStateBackend & VBOX_SCARD_STATE_EMPTY ) != 0 )
2610+ {
2611+ /* Some clients send status change notifications even if PRESENT/EMPTY has not chnaged.
2612+ * Try to reconnect only if there is no card.
2613+ */
2614+ usbCardReaderSendDisconnect (pThis, pSlot, DISCONNECT_ONSTATUSCHANGE );
2615+ pThis->enmICCConnState = ICCNOCONNECTION ;
2616+ }
25982617
25992618 bool fForceChanged = (pThis->u32EventStateBackend & VBOX_SCARD_STATE_CHANGED ) != 0 ;
26002619
@@ -2661,7 +2680,7 @@ static DECLCALLBACK(int) uscrStatusMonitor(PPDMUSBINS pUsbIns, PPDMTHREAD pThrea
26612680 {
26622681 uscrStatusMonitorProcess (pThis);
26632682
2664- urbQueueComplete (pThis, &pThis->urbQueues .IntrIn , uscrEventRead, true /* fDataOnly */ );
2683+ urbQueueComplete (pThis, &pThis->urbQueues .IntrIn , uscrEventRead);
26652684 uscrUnlock (pThis);
26662685 }
26672686
@@ -2819,7 +2838,7 @@ static DECLCALLBACK(int) usbSCardReaderConnect(PPDMICARDREADERUP pInterface,
28192838 pThis->fu8Cmd &= ~VUSBCARDREADER_F_CMD_BUSY ;
28202839
28212840 /* Process possibly pending bulk-in URBs. */
2822- urbQueueComplete (pThis, &pThis->urbQueues .BulkIn , uscrResponseRead, true /* fDataOnly */ );
2841+ urbQueueComplete (pThis, &pThis->urbQueues .BulkIn , uscrResponseRead);
28232842
28242843 uscrUnlock (pThis);
28252844
@@ -2905,7 +2924,7 @@ static DECLCALLBACK(int) usbSCardReaderDisconnect(PPDMICARDREADERUP pInterface,
29052924 pThis->enmDisconnectReason = DISCONNECT_VOID ;
29062925
29072926 /* Process possibly pending bulk-in URBs. */
2908- urbQueueComplete (pThis, &pThis->urbQueues .BulkIn , uscrResponseRead, true /* fDataOnly */ );
2927+ urbQueueComplete (pThis, &pThis->urbQueues .BulkIn , uscrResponseRead);
29092928
29102929 uscrUnlock (pThis);
29112930
@@ -3102,7 +3121,7 @@ static DECLCALLBACK(int) usbSCardReaderTransmit(PPDMICARDREADERUP pInterface,
31023121 }
31033122
31043123 /* Process possibly pending bulk-in URBs. */
3105- urbQueueComplete (pThis, &pThis->urbQueues .BulkIn , uscrResponseRead, true /* fDataOnly */ );
3124+ urbQueueComplete (pThis, &pThis->urbQueues .BulkIn , uscrResponseRead);
31063125
31073126 uscrUnlock (pThis);
31083127
@@ -3258,7 +3277,7 @@ static DECLCALLBACK(int) usbSCardReaderConstruct(PPDMUSBINS pUsbIns, int iInstan
32583277 pThis->hEvtDoneQueue = NIL_RTSEMEVENT ;
32593278 rc = RTSemEventCreate (&pThis->hEvtDoneQueue );
32603279 if (RT_FAILURE (rc))
3261- return PDMUsbHlpVMSetError (pUsbIns, rc, RT_SRC_POS , N_ (" USBWEBCAM : Failed to create event semaphore" ));
3280+ return PDMUsbHlpVMSetError (pUsbIns, rc, RT_SRC_POS , N_ (" USBSCARDREADER : Failed to create event semaphore" ));
32623281
32633282 rc = PDMUsbHlpThreadCreate (pUsbIns, &pThis->pStatusMonitorThread , pThis,
32643283 uscrStatusMonitor, uscrStatusMonitorWakeUp,
0 commit comments