Changeset 52254 in vbox
- Timestamp:
- Aug 2, 2014 3:34:53 PM (10 years ago)
- Location:
- trunk/src/VBox/Devices/USB
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
r51636 r52254 586 586 LogFlow(("vusbRhCancelUrbsEp: pRh=%p pUrb=%p\n", pRh)); 587 587 588 /* Tear down reaper thread on the device. */589 PVUSBDEV pDev = pUrb->VUsb.pDev;590 int rc = vusbDevUrbIoThreadDestroy(pDev);591 if (RT_FAILURE(rc))592 return rc;593 594 588 vusbUrbCancel(pUrb, CANCELMODE_UNDO); 595 589 596 PVUSBURB pRipe; 597 if (pUrb->enmState == VUSBURBSTATE_REAPED) 598 pRipe = pUrb; 599 else 600 pRipe = pUrb->pUsbIns->pReg->pfnUrbReap(pUrb->pUsbIns, 0); 601 if (pRipe) 602 { 603 pRipe->enmStatus = VUSBSTATUS_CRC; 604 vusbUrbRipe(pRipe); 605 } 606 607 rc = vusbDevUrbIoThreadCreate(pDev); 608 return rc; 590 /* The reaper thread will take care of completing the URB. */ 591 592 return VINF_SUCCESS; 609 593 } 610 594 … … 615 599 616 600 /* 617 * Tear down all reaper threads first to avoid concurrency issues.618 * pfnUrbReap is not thread safe.619 */620 PVUSBDEV pDev = pRh->pDevices;621 while (pDev)622 {623 int rc = vusbDevUrbIoThreadDestroy(pDev);624 AssertRC(rc); /* Should not fail. */625 pDev = pDev->pNext;626 }627 628 /*629 601 * Cancel the URBS. 630 602 */ 603 RTCritSectEnter(&pRh->CritSect); 631 604 PVUSBURB pUrb = pRh->pAsyncUrbHead; 632 605 LogFlow(("vusbRhCancelAllUrbs: pRh=%p\n", pRh)); … … 637 610 pUrb = pNext; 638 611 } 639 640 /* 641 * Reap any URBs which now are ripe. 642 */ 643 pUrb = pRh->pAsyncUrbHead; 644 while (pUrb) 645 { 646 PVUSBURB pRipe; 647 if (pUrb->enmState == VUSBURBSTATE_REAPED) 648 pRipe = pUrb; 649 else 650 pRipe = pUrb->pUsbIns->pReg->pfnUrbReap(pUrb->pUsbIns, 0); 651 if (!pRipe || pUrb == pRipe) 652 pUrb = pUrb->VUsb.pNext; 653 if (pRipe) 654 { 655 pRipe->enmStatus = VUSBSTATUS_CRC; 656 vusbUrbRipe(pRipe); 657 } 658 } 659 660 /* 661 * Create the reaper threads again. 662 */ 663 pDev = pRh->pDevices; 664 while (pDev) 665 { 666 int rc = vusbDevUrbIoThreadCreate(pDev); 667 AssertRC(rc); /** @todo: What if this fails? */ 668 pDev = pDev->pNext; 669 } 612 RTCritSectLeave(&pRh->CritSect); 670 613 } 671 614 -
trunk/src/VBox/Devices/USB/VUSBDevice.cpp
r52148 r52254 132 132 pPipe, g_apszCtlStates[pPipe->pCtrl ? pPipe->pCtrl->enmStage : 3])); 133 133 134 pPipe->ReadAheadThread = NIL_RTTHREAD;135 134 if ((pEndPtDesc->Core.bmAttributes & 0x3) == 0) 136 135 { … … 144 143 pPipe->in = pEndPtDesc; 145 144 146 #if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) 145 #if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN) 147 146 /* 148 147 * For high-speed isochronous input endpoints, spin off a read-ahead buffering thread. 149 148 */ 150 149 if ((pEndPtDesc->Core.bmAttributes & 0x03) == 1) 151 vusbReadAheadStart(pDev, pPipe);150 pPipe->hReadAhead = vusbReadAheadStart(pDev, pPipe); 152 151 #endif 153 152 } … … 185 184 186 185 /* If there was a read-ahead thread associated with this endpoint, tell it to go away. */ 187 if (pPipe-> pvReadAheadArgs)186 if (pPipe->hReadAhead) 188 187 { 189 188 Log(("vusb: and tell read-ahead thread for the endpoint to terminate\n")); 190 vusbReadAheadStop(pPipe->pvReadAheadArgs); 189 vusbReadAheadStop(pPipe->hReadAhead); 190 pPipe->hReadAhead = NULL; 191 191 } 192 192 } … … 315 315 if (pDev->pUsbIns->pReg->pfnUsbSetConfiguration) 316 316 { 317 int rc = pDev->pUsbIns->pReg->pfnUsbSetConfiguration(pDev->pUsbIns, pNewCfgDesc->Core.bConfigurationValue, 318 pDev->pCurCfgDesc, pDev->paIfStates, pNewCfgDesc); 317 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetConfiguration, 5, 318 pDev->pUsbIns, pNewCfgDesc->Core.bConfigurationValue, 319 pDev->pCurCfgDesc, pDev->paIfStates, pNewCfgDesc); 319 320 if (RT_FAILURE(rc)) 320 321 { … … 459 460 if (pDev->pUsbIns->pReg->pfnUsbSetInterface) 460 461 { 461 int rc = pDev->pUsbIns->pReg->pfnUsbSetInterface(pDev->pUsbIns, iIf, iAlt);462 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetInterface, 3, pDev->pUsbIns, iIf, iAlt); 462 463 if (RT_FAILURE(rc)) 463 464 { … … 529 530 && pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint) 530 531 { 531 int rc = pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint(pDev->pUsbIns, pSetup->wIndex); 532 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint, 533 2, pDev->pUsbIns, pSetup->wIndex); 532 534 return RT_SUCCESS(rc); 533 535 } … … 1131 1133 1132 1134 /* Process any URBs waiting to be cancelled first. */ 1133 int rc = RTReqQueueProcess(pDev->hReqQueue Cancel, 0); /* Don't wait if there is nothing to do. */1135 int rc = RTReqQueueProcess(pDev->hReqQueueSync, 0); /* Don't wait if there is nothing to do. */ 1134 1136 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); 1135 1136 /* Woken up or there is an URB to queue. */1137 PRTQUEUEATOMICITEM pHead = RTQueueAtomicRemoveAll(&pDev->QueueUrb);1138 while (pHead)1139 {1140 PVUSBURB pUrb = RT_FROM_MEMBER(pHead, VUSBURB, Dev.QueueItem);1141 1142 pHead = pHead->pNext;1143 1144 LogFlow(("%s: Queuing URB\n", pUrb->pszDesc));1145 rc = pUrb->pUsbIns->pReg->pfnUrbQueue(pUrb->pUsbIns, pUrb);1146 if (RT_FAILURE(rc))1147 {1148 LogFlow(("%s: Queuing URB failed with %Rrc\n", pUrb->pszDesc, rc));1149 1150 /*1151 * The device was detached, so we fail everything.1152 * (We should really detach and destroy the device, but we'll have to wait till Main reacts.)1153 */1154 if (rc == VERR_VUSB_DEVICE_NOT_ATTACHED)1155 rc = vusbUrbSubmitHardError(pUrb);1156 1157 /*1158 * We don't increment error count if async URBs are in flight, in1159 * this case we just assume we need to throttle back, this also1160 * makes sure we don't halt bulk endpoints at the wrong time.1161 */1162 else if ( RT_FAILURE(rc)1163 && !pDev->aPipes[pUrb->EndPt].async1164 /* && pUrb->enmType == VUSBXFERTYPE_BULK ?? */1165 && !vusbUrbErrorRh(pUrb))1166 {1167 /* don't retry it anymore. */1168 pUrb->enmState = VUSBURBSTATE_REAPED;1169 pUrb->enmStatus = VUSBSTATUS_CRC;1170 vusbUrbCompletionRh(pUrb);1171 }1172 }1173 }1174 1137 } 1175 1138 … … 1300 1263 1301 1264 /* Destroy request queue. */ 1302 int rc = RTReqQueueDestroy(pDev->hReqQueue Cancel);1265 int rc = RTReqQueueDestroy(pDev->hReqQueueSync); 1303 1266 AssertRC(rc); 1304 1267 … … 1656 1619 } 1657 1620 1621 1622 /** 1623 * Executes a given function synchronously on the I/O thread waiting for it to complete. 1624 * 1625 * @returns IPRT status code. 1626 * @param pDev The USB device instance data 1627 * @param pfnFunction The function to execute. 1628 * @param cArgs Number of arguments to the function. 1629 * @param ... The parameter list. 1630 * 1631 * @remarks See remarks on RTReqQueueCallV 1632 */ 1633 DECLHIDDEN(int) vusbDevIoThreadExecSync(PVUSBDEV pDev, PFNRT pfnFunction, unsigned cArgs, ...) 1634 { 1635 int rc = VINF_SUCCESS; 1636 PRTREQ hReq = NULL; 1637 va_list va; 1638 1639 va_start(va, cArgs); 1640 Assert(pDev->hUrbIoThread != NIL_RTTHREAD); 1641 if (RT_LIKELY(pDev->hUrbIoThread != NIL_RTTHREAD)) 1642 { 1643 rc = RTReqQueueCallV(pDev->hReqQueueSync, &hReq, 0 /* cMillies */, RTREQFLAGS_IPRT_STATUS, pfnFunction, cArgs, va); 1644 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); 1645 vusbDevUrbIoThreadWakeup(pDev); 1646 rc = RTReqWait(hReq, RT_INDEFINITE_WAIT); 1647 AssertRC(rc); 1648 } 1649 else 1650 rc = VERR_INVALID_STATE; 1651 1652 va_end(va); 1653 return rc; 1654 } 1655 1656 static DECLCALLBACK(int) vusbDevGetDescriptorCacheWorker(PPDMUSBINS pUsbIns, PCPDMUSBDESCCACHE *ppDescCache) 1657 { 1658 *ppDescCache = pUsbIns->pReg->pfnUsbGetDescriptorCache(pUsbIns); 1659 return VINF_SUCCESS; 1660 } 1658 1661 1659 1662 /** … … 1696 1699 pDev->pvResetArgs = NULL; 1697 1700 pDev->pResetTimer = NULL; 1698 RTQueueAtomicInit(&pDev->QueueUrb);1699 1701 1700 1702 /* … … 1705 1707 AssertRCReturn(rc, rc); 1706 1708 1709 /* Setup request queue executing synchronous tasks on the I/O thread. */ 1710 rc = RTReqQueueCreate(&pDev->hReqQueueSync); 1711 AssertRCReturn(rc, rc); 1712 1713 /* Create I/O thread. */ 1714 rc = vusbDevUrbIoThreadCreate(pDev); 1715 AssertRCReturn(rc, rc); 1716 1707 1717 /* 1708 1718 * Get the descriptor cache from the device. (shall cannot fail) 1709 1719 */ 1710 pDev->pDescCache = pUsbIns->pReg->pfnUsbGetDescriptorCache(pUsbIns); 1711 Assert(pDev->pDescCache); 1720 rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbDevGetDescriptorCacheWorker, 2, pUsbIns, &pDev->pDescCache); 1721 AssertRC(rc); 1722 AssertPtr(pDev->pDescCache); 1712 1723 #ifdef VBOX_STRICT 1713 1724 if (pDev->pDescCache->fUseCachedStringsDescriptors) … … 1740 1751 AssertMsgReturn(pDev->paIfStates, ("RTMemAllocZ(%d) failed\n", cbIface), VERR_NO_MEMORY); 1741 1752 1742 /* Setup request queue for cancelling URBs synchronously. */1743 rc = RTReqQueueCreate(&pDev->hReqQueueCancel);1744 AssertRCReturn(rc, rc);1745 1746 rc = vusbDevUrbIoThreadCreate(pDev);1747 AssertRCReturn(rc, rc);1748 1749 1753 return VINF_SUCCESS; 1750 1754 } -
trunk/src/VBox/Devices/USB/VUSBInternal.h
r52150 r52254 113 113 void vusbMsgResetExtraData(PVUSBCTRLEXTRA pExtra); 114 114 115 /** Opaque VUSB read ahead buffer management handle. */ 116 typedef struct VUSBREADAHEADINT *VUSBREADAHEAD; 115 117 116 118 /** … … 125 127 /** Count of active async transfers. */ 126 128 volatile uint32_t async; 127 /** The periodic read-ahead buffer thread. */ 128 RTTHREAD ReadAheadThread; 129 /** Pointer to the reset thread arguments. */ 130 void *pvReadAheadArgs; 131 /** Pointer to the first buffered URB. */ 132 PVUSBURB pBuffUrbHead; 133 /** Pointer to the last buffered URB. */ 134 PVUSBURB pBuffUrbTail; 135 /** Count of URBs in read-ahead buffer. */ 136 uint32_t cBuffered; 137 /** Count of URBs submitted for read-ahead but not yet reaped. */ 138 uint32_t cSubmitted; 129 /** Read ahead handle. */ 130 VUSBREADAHEAD hReadAhead; 139 131 } VUSBPIPE; 140 132 /** Pointer to a VUSB pipe structure. */ … … 218 210 /** URB submit and reap thread. */ 219 211 RTTHREAD hUrbIoThread; 220 /** Queue of URBs to submit. */ 221 RTQUEUEATOMIC QueueUrb; 222 /** Request queue for cancelling URBs on the I/O thread. */ 223 RTREQQUEUE hReqQueueCancel; 212 /** Request queue for executing tasks on the I/O thread which should be done 213 * synchronous and without any other thread accessing the USB device. */ 214 RTREQQUEUE hReqQueueSync; 224 215 /** Flag whether the URB I/O thread should terminate. */ 225 216 bool volatile fTerminate; … … 455 446 int vusbDevUrbIoThreadCreate(PVUSBDEV pDev); 456 447 int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev); 448 DECLHIDDEN(int) vusbDevIoThreadExecSync(PVUSBDEV pDev, PFNRT pfnFunction, unsigned cArgs, ...); 457 449 458 450 void vusbUrbCompletionReadAhead(PVUSBURB pUrb); 459 voidvusbReadAheadStart(PVUSBDEV pDev, PVUSBPIPE pPipe);460 void vusbReadAheadStop( void *pvReadAheadArgs);451 VUSBREADAHEAD vusbReadAheadStart(PVUSBDEV pDev, PVUSBPIPE pPipe); 452 void vusbReadAheadStop(VUSBREADAHEAD hReadAhead); 461 453 int vusbUrbQueueAsyncRh(PVUSBURB pUrb); 462 int vusbUrbSubmitBufferedRead(PVUSBURB pUrb, PVUSBPIPE pPipe);454 int vusbUrbSubmitBufferedRead(PVUSBURB pUrb, VUSBREADAHEAD hReadAhead); 463 455 PVUSBURB vusbRhNewUrb(PVUSBROOTHUB pRh, uint8_t DstAddress, uint32_t cbData, uint32_t cTds); 464 456 -
trunk/src/VBox/Devices/USB/VUSBReadAhead.cpp
r50453 r52254 32 32 #include <iprt/assert.h> 33 33 #include <iprt/asm.h> 34 #include <iprt/critsect.h> 34 35 #include "VUSBInternal.h" 35 36 … … 40 41 41 42 /** 42 * Argument package of vusbDevReadAheadThread().43 */ 44 typedef struct vusb_read_ahead_args43 * VUSB Readahead instance data. 44 */ 45 typedef struct VUSBREADAHEADINT 45 46 { 46 47 /** Pointer to the device which the thread is for. */ … … 51 52 bool fHighSpeed; 52 53 /** A flag telling the thread to terminate. */ 53 bool fTerminate; 54 } VUSBREADAHEADARGS, *PVUSBREADAHEADARGS; 54 volatile bool fTerminate; 55 /** Maximum number of URBs to submit. */ 56 uint32_t cUrbsMax; 57 /** The periodic read-ahead buffer thread. */ 58 RTTHREAD hReadAheadThread; 59 /** Pointer to the first buffered URB. */ 60 PVUSBURB pBuffUrbHead; 61 /** Pointer to the last buffered URB. */ 62 PVUSBURB pBuffUrbTail; 63 /** Count of URBs in read-ahead buffer. */ 64 uint32_t cBuffered; 65 /** Count of URBs submitted for read-ahead but not yet reaped. */ 66 uint32_t cSubmitted; 67 /** Critical section to serialize access the buffered URB list. */ 68 RTCRITSECT CritSectBuffUrbList; 69 } VUSBREADAHEADINT, *PVUSBREADAHEADINT; 55 70 56 71 … … 156 171 static DECLCALLBACK(int) vusbDevReadAheadThread(RTTHREAD Thread, void *pvUser) 157 172 { 173 PVUSBREADAHEADINT pThis = (PVUSBREADAHEADINT)pvUser; 158 174 PVUSBPIPE pPipe; 159 PVUSBREADAHEADARGS pArgs = (PVUSBREADAHEADARGS)pvUser;160 175 PCVUSBDESCENDPOINT pDesc; 161 176 PVUSBURB pUrb; … … 164 179 165 180 LogFlow(("vusb: periodic read-ahead buffer thread started\n")); 166 Assert(p Args);167 Assert(p Args->pPipe && pArgs->pDev);168 169 pPipe = p Args->pPipe;181 Assert(pThis); 182 Assert(pThis->pPipe && pThis->pDev); 183 184 pPipe = pThis->pPipe; 170 185 pDesc = &pPipe->in->Core; 171 186 Assert(pDesc); 172 187 173 /* The previous read-ahead thread could be still running (vusbReadAheadStop sets only 174 * fTerminate to true and returns immediately). Therefore we have to wait until the 175 * previous thread is done and all submitted URBs are completed. */ 176 while ( pPipe->cSubmitted > 0 177 && pPipe->cBuffered > 0) 178 { 179 Log2(("vusbDevReadAheadThread: still %u packets submitted, waiting before starting...\n", pPipe->cSubmitted)); 180 RTThreadSleep(1); 181 } 182 pPipe->pvReadAheadArgs = pArgs; 183 pPipe->cBuffered = 0; 188 Assert(!pThis->cSubmitted && !pThis->cBuffered); 184 189 185 190 /* Figure out the maximum bandwidth we might need */ 186 if (p Args->fHighSpeed)191 if (pThis->fHighSpeed) 187 192 { 188 193 /* High-speed endpoint */ … … 207 212 * queue the URBs here, they are reaped on a different thread. 208 213 */ 209 while ( pArgs->fTerminate == false)210 { 211 while (p Pipe->cSubmitted < 120 && pPipe->cBuffered < 120)212 { 213 pUrb = vusbDevNewIsocUrb(p Args->pDev, pDesc->bEndpointAddress & 0xF, interval, max_pkt_size * mult);214 while (!pThis->fTerminate) 215 { 216 while (pThis->cSubmitted < pThis->cUrbsMax && pThis->cBuffered < pThis->cUrbsMax) 217 { 218 pUrb = vusbDevNewIsocUrb(pThis->pDev, pDesc->bEndpointAddress & 0xF, interval, max_pkt_size * mult); 214 219 if (!pUrb) { 215 220 /* Happens if device was unplugged. */ 216 221 Log(("vusb: read-ahead thread failed to allocate new URB; exiting\n")); 217 vusbReadAheadStop(p vUser);222 vusbReadAheadStop(pThis); 218 223 break; 219 224 } … … 230 235 /* Happens if device was unplugged. */ 231 236 Log(("vusb: read-ahead thread failed to queue URB with %Rrc; exiting\n", rc)); 232 vusbReadAheadStop(pvUser); 237 pThis->cUrbsMax = pThis->cSubmitted; 238 pUrb->VUsb.pfnFree(pUrb); 233 239 break; 234 240 } 235 ++pPipe->cSubmitted; 241 else 242 ASMAtomicIncU32(&pThis->cSubmitted); 236 243 } 237 244 RTThreadSleep(1); 238 245 } 239 246 LogFlow(("vusb: periodic read-ahead buffer thread exiting\n")); 240 pPipe->pvReadAheadArgs = NULL;241 247 242 248 /* wait until there are no more submitted packets */ 243 while (p Pipe->cSubmitted > 0)244 { 245 Log2(("vusbDevReadAheadThread: still %u packets submitted, waiting before terminating...\n", p Pipe->cSubmitted));249 while (pThis->cSubmitted > 0) 250 { 251 Log2(("vusbDevReadAheadThread: still %u packets submitted, waiting before terminating...\n", pThis->cSubmitted)); 246 252 RTThreadSleep(1); 247 253 } 248 254 255 RTCritSectEnter(&pThis->CritSectBuffUrbList); 249 256 /* 250 257 * Free all still buffered URBs because another endpoint with a different packet size 251 258 * and complete different data formats might be served later. 252 259 */ 253 while (p Pipe->pBuffUrbHead)254 { 255 PVUSBURB pBufferedUrb = p Pipe->pBuffUrbHead;256 257 p Pipe->pBuffUrbHead = pBufferedUrb->Hci.pNext;260 while (pThis->pBuffUrbHead) 261 { 262 PVUSBURB pBufferedUrb = pThis->pBuffUrbHead; 263 264 pThis->pBuffUrbHead = pBufferedUrb->Hci.pNext; 258 265 pBufferedUrb->VUsb.pfnFree(pBufferedUrb); 259 266 } 260 267 261 pPipe->pBuffUrbTail = NULL;262 pPipe->cBuffered = 0;263 RTMemTmpFree(p Args);268 RTCritSectLeave(&pThis->CritSectBuffUrbList); 269 RTCritSectDelete(&pThis->CritSectBuffUrbList); 270 RTMemTmpFree(pThis); 264 271 265 272 return rc; … … 275 282 Assert(pUrb); 276 283 Assert(pUrb->Hci.pNext); 277 PVUSBREADAHEAD ARGS pArgs = (PVUSBREADAHEADARGS)pUrb->Hci.pNext;278 PVUSBPIPE pPipe = pArgs->pPipe;284 PVUSBREADAHEADINT pThis = (PVUSBREADAHEADINT)pUrb->Hci.pNext; 285 PVUSBPIPE pPipe = pThis->pPipe; 279 286 Assert(pPipe); 280 287 288 RTCritSectEnter(&pThis->CritSectBuffUrbList); 281 289 pUrb->Hci.pNext = NULL; // @todo: use a more suitable field 282 if (p Pipe->pBuffUrbHead == NULL)290 if (pThis->pBuffUrbHead == NULL) 283 291 { 284 292 // The queue is empty, this is easy 285 Assert(!p Pipe->pBuffUrbTail);286 p Pipe->pBuffUrbTail = pPipe->pBuffUrbHead = pUrb;293 Assert(!pThis->pBuffUrbTail); 294 pThis->pBuffUrbTail = pThis->pBuffUrbHead = pUrb; 287 295 } 288 296 else 289 297 { 290 298 // Some URBs are queued already 291 Assert(pPipe->pBuffUrbTail); 292 Assert(!pPipe->pBuffUrbTail->Hci.pNext); 293 pPipe->pBuffUrbTail = pPipe->pBuffUrbTail->Hci.pNext = pUrb; 294 } 295 --pPipe->cSubmitted; 296 ++pPipe->cBuffered; 299 Assert(pThis->pBuffUrbTail); 300 Assert(!pThis->pBuffUrbTail->Hci.pNext); 301 pThis->pBuffUrbTail = pThis->pBuffUrbTail->Hci.pNext = pUrb; 302 } 303 ASMAtomicDecU32(&pThis->cSubmitted); 304 ++pThis->cBuffered; 305 RTCritSectLeave(&pThis->CritSectBuffUrbList); 297 306 } 298 307 … … 303 312 * 304 313 * @param pUrb The URB submitted by HC 305 * @param pPipe The pipe with read-ahead buffering314 * @param hReadAhead The read-ahead buffering instance 306 315 * 307 316 * @return int Status code 308 317 */ 309 int vusbUrbSubmitBufferedRead(PVUSBURB pUrb, PVUSBPIPE pPipe) 310 { 311 PVUSBURB pBufferedUrb; 312 Assert(pUrb && pPipe); 313 314 pBufferedUrb = pPipe->pBuffUrbHead; 318 int vusbUrbSubmitBufferedRead(PVUSBURB pUrb, VUSBREADAHEAD hReadAhead) 319 { 320 PVUSBREADAHEADINT pThis = hReadAhead; 321 PVUSBURB pBufferedUrb; 322 Assert(pUrb && pThis); 323 324 RTCritSectEnter(&pThis->CritSectBuffUrbList); 325 pBufferedUrb = pThis->pBuffUrbHead; 315 326 if (pBufferedUrb) 316 327 { … … 318 329 319 330 // There's a URB available in the read-ahead buffer; use it 320 pPipe->pBuffUrbHead = pBufferedUrb->Hci.pNext; 321 if (pPipe->pBuffUrbHead == NULL) 322 pPipe->pBuffUrbTail = NULL; 323 324 --pPipe->cBuffered; 331 pThis->pBuffUrbHead = pBufferedUrb->Hci.pNext; 332 if (pThis->pBuffUrbHead == NULL) 333 pThis->pBuffUrbTail = NULL; 334 335 --pThis->cBuffered; 336 RTCritSectLeave(&pThis->CritSectBuffUrbList); 325 337 326 338 // Make sure the buffered URB is what we expect … … 358 370 else 359 371 { 372 RTCritSectLeave(&pThis->CritSectBuffUrbList); 360 373 // No URB on hand. Either we exhausted the buffer (shouldn't happen!) or the guest simply 361 374 // asked for data too soon. Pretend that the device didn't deliver any data. … … 370 383 // This assertion is wrong as the URB could be re-allocated in the meantime by the EMT (race) 371 384 // Assert(pUrb->enmState == VUSBURBSTATE_FREE); 372 LogFlow((" %s: vusbUrbSubmitBufferedRead: No buffered URB available!\n", pBufferedUrb->pszDesc));385 LogFlow(("vusbUrbSubmitBufferedRead: No buffered URB available!\n")); 373 386 } 374 387 return VINF_SUCCESS; … … 377 390 /* Read-ahead start/stop functions, used primarily to keep the PVUSBREADAHEADARGS struct private to this module. */ 378 391 379 voidvusbReadAheadStart(PVUSBDEV pDev, PVUSBPIPE pPipe)392 VUSBREADAHEAD vusbReadAheadStart(PVUSBDEV pDev, PVUSBPIPE pPipe) 380 393 { 381 394 int rc; 382 PVUSBREADAHEAD ARGS pArgs = (PVUSBREADAHEADARGS)RTMemTmpAlloc(sizeof(*pArgs));383 384 if (p Args)395 PVUSBREADAHEADINT pThis = (PVUSBREADAHEADINT)RTMemTmpAlloc(sizeof(VUSBREADAHEADINT)); 396 397 if (pThis) 385 398 { 386 399 PVUSBROOTHUB pRh = vusbDevGetRh(pDev); 387 pArgs->pDev = pDev; 388 pArgs->pPipe = pPipe; 389 pArgs->fTerminate = false; 390 pArgs->fHighSpeed = pRh && ((pRh->fHcVersions & VUSB_STDVER_20) != 0); 391 if (pArgs->fHighSpeed) 392 rc = RTThreadCreate(&pPipe->ReadAheadThread, vusbDevReadAheadThread, pArgs, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "USBISOC"); 393 else 394 rc = VERR_VUSB_DEVICE_NOT_ATTACHED; // No buffering for low/full-speed devices at the moment, needs testing. 400 pThis->pDev = pDev; 401 pThis->pPipe = pPipe; 402 pThis->fTerminate = false; 403 pThis->fHighSpeed = pRh && ((pRh->fHcVersions & VUSB_STDVER_20) != 0); 404 pThis->cUrbsMax = 120; 405 pThis->pBuffUrbHead = NULL; 406 pThis->pBuffUrbTail = NULL; 407 pThis->cBuffered = 0; 408 pThis->cSubmitted = 0; 409 rc = RTCritSectInit(&pThis->CritSectBuffUrbList); 395 410 if (RT_SUCCESS(rc)) 396 411 { 397 Log(("vusb: created isochronous read-ahead thread\n")); 398 } 399 else 400 { 401 Log(("vusb: isochronous read-ahead thread creation failed, rc=%d\n", rc)); 402 pPipe->ReadAheadThread = NIL_RTTHREAD; 403 RTMemTmpFree(pArgs); 404 } 405 } 412 if (pThis->fHighSpeed) 413 rc = RTThreadCreate(&pThis->hReadAheadThread, vusbDevReadAheadThread, pThis, 0, RTTHREADTYPE_IO, 0 /* fFlags */, "USBISOC"); 414 else 415 rc = VERR_VUSB_DEVICE_NOT_ATTACHED; // No buffering for low/full-speed devices at the moment, needs testing. 416 if (RT_SUCCESS(rc)) 417 { 418 Log(("vusb: created isochronous read-ahead thread\n")); 419 return pThis; 420 } 421 else 422 Log(("vusb: isochronous read-ahead thread creation failed, rc=%d\n", rc)); 423 424 rc = RTCritSectDelete(&pThis->CritSectBuffUrbList); 425 AssertRC(rc); 426 } 427 428 RTMemTmpFree(pThis); 429 } 430 406 431 /* If thread creation failed for any reason, simply fall back to standard processing. */ 407 } 408 409 void vusbReadAheadStop(void *pvReadAheadArgs) 410 { 411 PVUSBREADAHEADARGS pArgs = (PVUSBREADAHEADARGS)pvReadAheadArgs; 432 return NULL; 433 } 434 435 void vusbReadAheadStop(VUSBREADAHEAD hReadAhead) 436 { 437 PVUSBREADAHEADINT pThis = hReadAhead; 412 438 Log(("vusb: terminating read-ahead thread for endpoint\n")); 413 pArgs->fTerminate = true;439 ASMAtomicXchgBool(&pThis->fTerminate, true); 414 440 } 415 441 -
trunk/src/VBox/Devices/USB/VUSBUrb.cpp
r52148 r52254 1120 1120 #endif 1121 1121 1122 /** @todo explain why we do this pDev change. */1123 PVUSBDEV pTmp = pUrb->VUsb.pDev;1124 pUrb->VUsb.pDev = &pRh->Hub.Dev;1125 1122 pRh->pIRhPort->pfnXferCompletion(pRh->pIRhPort, pUrb); 1126 pUrb->VUsb.pDev = pTmp;1127 1123 if (pUrb->enmState == VUSBURBSTATE_REAPED) 1128 1124 { … … 1205 1201 } 1206 1202 1203 RTCritSectEnter(&pRh->CritSect); 1204 int rc = pUrb->pUsbIns->pReg->pfnUrbQueue(pUrb->pUsbIns, pUrb); 1205 if (RT_FAILURE(rc)) 1206 { 1207 LogFlow(("%s: vusbUrbQueueAsyncRh: returns %Rrc (queue_urb)\n", pUrb->pszDesc, rc)); 1208 RTCritSectLeave(&pRh->CritSect); 1209 return rc; 1210 } 1211 1207 1212 ASMAtomicIncU32(&pDev->aPipes[pUrb->EndPt].async); 1208 1213 1209 1214 /* Queue the pUrb on the roothub */ 1210 RTCritSectEnter(&pRh->CritSect);1211 1215 pUrb->VUsb.pNext = pRh->pAsyncUrbHead; 1212 1216 if (pRh->pAsyncUrbHead) … … 1215 1219 pUrb->VUsb.ppPrev = &pRh->pAsyncUrbHead; 1216 1220 RTCritSectLeave(&pRh->CritSect); 1217 1218 RTQueueAtomicInsert(&pDev->QueueUrb, &pUrb->Dev.QueueItem);1219 vusbDevUrbIoThreadWakeup(pDev);1220 1221 1221 1222 return VINF_SUCCESS; … … 1881 1882 1882 1883 #ifdef VBOX_WITH_USB 1883 if (pPipe && pPipe-> pBuffUrbHead)1884 { 1885 rc = vusbUrbSubmitBufferedRead(pUrb, pPipe );1884 if (pPipe && pPipe->hReadAhead) 1885 { 1886 rc = vusbUrbSubmitBufferedRead(pUrb, pPipe->hReadAhead); 1886 1887 return rc; 1887 1888 } … … 2125 2126 void vusbUrbCancel(PVUSBURB pUrb, CANCELMODE mode) 2126 2127 { 2127 PRTREQ hReq = NULL; 2128 2129 if (pUrb->VUsb.pDev->hUrbIoThread != NIL_RTTHREAD) 2130 { 2131 int rc = RTReqQueueCallVoid(pUrb->VUsb.pDev->hReqQueueCancel, &hReq, 0, 2132 (PFNRT)vusbUrbCancelWorker, 2, pUrb, mode); 2133 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); 2134 vusbDevUrbIoThreadWakeup(pUrb->VUsb.pDev); 2135 rc = RTReqWait(hReq, RT_INDEFINITE_WAIT); 2136 AssertRC(rc); 2137 } 2138 else /* Call the worker directly. */ 2139 vusbUrbCancelWorker(pUrb, mode); 2128 int rc = vusbDevIoThreadExecSync(pUrb->VUsb.pDev, (PFNRT)vusbUrbCancelWorker, 2, pUrb, mode); 2129 AssertRC(rc); 2140 2130 } 2141 2131 -
trunk/src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp
r50234 r52254 233 233 /** The list of free Darwin URBs. Singly linked. */ 234 234 PUSBPROXYURBOSX pFreeHead; 235 /** The list of active Darwin URBs. Doubly linked.236 * Only the split head will appear in this list. */237 PUSBPROXYURBOSX pInFlightHead;238 235 /** The list of landed Darwin URBs. Doubly linked. 239 236 * Only the split head will appear in this list. */ … … 241 238 /** The tail of the landed Darwin URBs. */ 242 239 PUSBPROXYURBOSX pTaxingTail; 243 /* Runloop source for waking up the reaper thread. */ 240 /** Last reaper runloop reference, there can be only one runloop at a time. */ 241 CFRunLoopRef hRunLoopReapingLast; 242 /** Runloop source for waking up the reaper thread. */ 244 243 CFRunLoopSourceRef hRunLoopSrcWakeRef; 245 244 /** List of threads used for reaping which can be woken up. */ … … 290 289 291 290 /** 291 * Kicks the reaper thread if it sleeps currently to respond to state changes 292 * or to pick up completed URBs. 293 * 294 * @returns nothing. 295 * @param pDevOsX The darwin device instance data. 296 */ 297 static void usbProxyDarwinReaperKick(PUSBPROXYDEVOSX pDevOsX) 298 { 299 CFRunLoopRef hRunLoopWake = (CFRunLoopRef)ASMAtomicReadPtr((void * volatile *)&pDevOsX->hRunLoopReaping); 300 if (hRunLoopWake) 301 { 302 LogFlowFunc(("Waking runloop %p\n", hRunLoopWake)); 303 CFRunLoopSourceSignal(pDevOsX->hRunLoopSrcWakeRef); 304 CFRunLoopWakeUp(hRunLoopWake); 305 } 306 } 307 308 /** 292 309 * Adds Source ref to current run loop and adds it the list of runloops. 293 310 */ … … 368 385 pUrbOsX = pDevOsX->pFreeHead; 369 386 if (pUrbOsX) 387 { 370 388 pDevOsX->pFreeHead = pUrbOsX->pNext; 389 RTCritSectLeave(&pDevOsX->CritSect); 390 } 371 391 else 372 392 { … … 375 395 if (!pUrbOsX) 376 396 return NULL; 377 RTCritSectEnter(&pDevOsX->CritSect);378 397 } 379 398 pUrbOsX->pVUsbUrb = NULL; … … 381 400 pUrbOsX->enmType = VUSBXFERTYPE_INVALID; 382 401 383 /*384 * Link it into the active list385 */386 pUrbOsX->pPrev = NULL;387 pUrbOsX->pNext = pDevOsX->pInFlightHead;388 if (pUrbOsX->pNext)389 pUrbOsX->pNext->pPrev = pUrbOsX;390 pDevOsX->pInFlightHead = pUrbOsX;391 392 RTCritSectLeave(&pDevOsX->CritSect);393 402 return pUrbOsX; 394 403 } … … 500 509 { 501 510 RTCritSectEnter(&pDevOsX->CritSect); 502 503 /*504 * Remove from the active or taxing list.505 */506 if (pUrbOsX->pNext)507 pUrbOsX->pNext->pPrev = pUrbOsX->pPrev;508 else if (pDevOsX->pTaxingTail == pUrbOsX)509 pDevOsX->pTaxingTail = pUrbOsX->pPrev;510 511 if (pUrbOsX->pPrev)512 pUrbOsX->pPrev->pNext = pUrbOsX->pNext;513 else if (pDevOsX->pTaxingHead == pUrbOsX)514 pDevOsX->pTaxingHead = pUrbOsX->pNext;515 else if (pDevOsX->pInFlightHead == pUrbOsX)516 pDevOsX->pInFlightHead = pUrbOsX->pNext;517 else518 AssertFailed();519 511 520 512 #ifdef USE_LOW_LATENCY_API … … 595 587 PUSBPROXYDEVOSX pDevOsX = pUrbOsX->pDevOsX; 596 588 const uint32_t cb = (uintptr_t)Size; 597 598 RTCritSectEnter(&pDevOsX->CritSect);599 589 600 590 /* … … 646 636 } 647 637 648 /* 649 * Remove from the active list. 650 */ 651 if (pUrbOsX->pNext) 652 pUrbOsX->pNext->pPrev = pUrbOsX->pPrev; 653 if (pUrbOsX->pPrev) 654 pUrbOsX->pPrev->pNext = pUrbOsX->pNext; 655 else 656 { 657 Assert(pDevOsX->pInFlightHead == pUrbOsX); 658 pDevOsX->pInFlightHead = pUrbOsX->pNext; 659 } 638 RTCritSectEnter(&pDevOsX->CritSect); 660 639 661 640 /* … … 683 662 static void usbProxyDarwinReleaseAllInterfaces(PUSBPROXYDEVOSX pDevOsX) 684 663 { 664 RTCritSectEnter(&pDevOsX->CritSect); 665 666 /* Kick the reaper thread out of sleep. */ 667 usbProxyDarwinReaperKick(pDevOsX); 668 685 669 PUSBPROXYIFOSX pIf = pDevOsX->pIfHead; 686 670 pDevOsX->pIfHead = pDevOsX->pIfTail = NULL; … … 728 712 pIf = pNext; 729 713 } 714 RTCritSectLeave(&pDevOsX->CritSect); 730 715 } 731 716 … … 808 793 { 809 794 PUSBPROXYDEV pProxyDev = pDevOsX->pProxyDev; 795 796 RTCritSectEnter(&pDevOsX->CritSect); 810 797 811 798 /* … … 968 955 rc = VERR_GENERAL_FAILURE; 969 956 } 957 958 RTCritSectLeave(&pDevOsX->CritSect); 970 959 return rc; 971 960 } … … 1074 1063 return; 1075 1064 } 1065 1076 1066 1077 1067 /* -=-=-=-=-=- The exported methods -=-=-=-=-=- */ … … 1240 1230 if (RT_SUCCESS(vrc)) 1241 1231 { 1242 pDevOsX->USBDevice = USBDevice; 1243 pDevOsX->ppDevI = ppDevI; 1244 pDevOsX->pProxyDev = pProxyDev; 1232 pDevOsX->USBDevice = USBDevice; 1233 pDevOsX->ppDevI = ppDevI; 1234 pDevOsX->pProxyDev = pProxyDev; 1235 pDevOsX->pTaxingHead = NULL; 1236 pDevOsX->pTaxingTail = NULL; 1237 pDevOsX->hRunLoopReapingLast = NULL; 1245 1238 1246 1239 /* … … 1409 1402 1410 1403 PUSBPROXYURBOSX pUrbOsX; 1411 while ((pUrbOsX = pDevOsX->pInFlightHead) != NULL)1412 {1413 pDevOsX->pInFlightHead = pUrbOsX->pNext;1414 //RTMemFree(pUrbOsX); - leak these for now, fix later.1415 }1416 1417 1404 while ((pUrbOsX = pDevOsX->pFreeHead) != NULL) 1418 1405 { … … 1622 1609 if (pUrb->EndPt) 1623 1610 { 1611 /* Make sure the interface is there. */ 1624 1612 const uint8_t EndPt = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0); 1625 1613 pIf = usbProxyDarwinGetInterfaceForEndpoint(pDevOsX, EndPt, &u8PipeRef, &pPipe); … … 1630 1618 return VERR_NOT_FOUND; 1631 1619 } 1632 1633 if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), pIf->RunLoopSrcRef, g_pRunLoopMode))1634 usbProxyDarwinAddRunLoopRef(&pIf->HeadOfRunLoopLst, pIf->RunLoopSrcRef);1635 1636 1620 } 1637 1621 /* else: pIf == NULL -> default control pipe.*/ 1638 1639 if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), pDevOsX->RunLoopSrcRef, g_pRunLoopMode))1640 usbProxyDarwinAddRunLoopRef(&pDevOsX->HeadOfRunLoopLst, pDevOsX->RunLoopSrcRef);1641 1622 1642 1623 /* … … 1800 1781 case kIOUSBPipeStalled: 1801 1782 { 1783 /* Increment in flight counter because the completion handler will decrease it always. */ 1802 1784 usbProxyDarwinUrbAsyncComplete(pUrbOsX, kIOUSBPipeStalled, 0); 1803 1785 Log(("%s: usbProxyDarwinUrbQueue: pProxyDev=%s EndPt=%d cbData=%d - failed irc=%#x! (stall)\n", … … 1807 1789 } 1808 1790 1791 usbProxyDarwinUrbFree(pDevOsX, pUrbOsX); 1809 1792 Log(("%s: usbProxyDarwinUrbQueue: pProxyDev=%s EndPt=%d cbData=%d - failed irc=%#x!\n", 1810 1793 pUrb->pszDesc, pProxyDev->pUsbIns->pszName, pUrb->EndPt, pUrb->cbData, irc)); … … 1829 1812 Assert(!pDevOsX->hRunLoopReaping); 1830 1813 1831 if (!CFRunLoopContainsSource(hRunLoopRef, pDevOsX->hRunLoopSrcWakeRef, g_pRunLoopMode)) 1832 usbProxyDarwinAddRunLoopRef(&pDevOsX->HeadOfRunLoopWakeLst, pDevOsX->hRunLoopSrcWakeRef); 1814 /* 1815 * If the last seen runloop for reaping differs we have to check whether the 1816 * the runloop sources are in the new runloop. 1817 */ 1818 if (pDevOsX->hRunLoopReapingLast != hRunLoopRef) 1819 { 1820 RTCritSectEnter(&pDevOsX->CritSect); 1821 1822 /* Every pipe. */ 1823 if (!pDevOsX->pIfHead) 1824 usbProxyDarwinSeizeAllInterfaces(pDevOsX, true /* make the best out of it */); 1825 1826 PUSBPROXYIFOSX pIf; 1827 for (pIf = pDevOsX->pIfHead; pIf; pIf = pIf->pNext) 1828 { 1829 if (!CFRunLoopContainsSource(hRunLoopRef, pIf->RunLoopSrcRef, g_pRunLoopMode)) 1830 usbProxyDarwinAddRunLoopRef(&pIf->HeadOfRunLoopLst, pIf->RunLoopSrcRef); 1831 } 1832 1833 /* Default control pipe. */ 1834 if (!CFRunLoopContainsSource(hRunLoopRef, pDevOsX->RunLoopSrcRef, g_pRunLoopMode)) 1835 usbProxyDarwinAddRunLoopRef(&pDevOsX->HeadOfRunLoopLst, pDevOsX->RunLoopSrcRef); 1836 1837 /* Runloop wakeup source. */ 1838 if (!CFRunLoopContainsSource(hRunLoopRef, pDevOsX->hRunLoopSrcWakeRef, g_pRunLoopMode)) 1839 usbProxyDarwinAddRunLoopRef(&pDevOsX->HeadOfRunLoopWakeLst, pDevOsX->hRunLoopSrcWakeRef); 1840 RTCritSectLeave(&pDevOsX->CritSect); 1841 1842 pDevOsX->hRunLoopReapingLast = hRunLoopRef; 1843 } 1833 1844 1834 1845 ASMAtomicXchgPtr((void * volatile *)&pDevOsX->hRunLoopReaping, hRunLoopRef); … … 1842 1853 1843 1854 /* 1844 * If we've got any in-flight URBs, excercise the runloop. 1845 */ 1846 if (pDevOsX->pInFlightHead) 1847 CFRunLoopRunInMode(g_pRunLoopMode, 0.0, false); 1848 1855 * Excercise the runloop until we get an URB or we time out. 1856 */ 1849 1857 if ( !pDevOsX->pTaxingHead 1850 1858 && cMillies) … … 1865 1873 if (pUrbOsX) 1866 1874 { 1875 /* 1876 * Remove from the taxing list. 1877 */ 1878 if (pUrbOsX->pNext) 1879 pUrbOsX->pNext->pPrev = pUrbOsX->pPrev; 1880 else if (pDevOsX->pTaxingTail == pUrbOsX) 1881 pDevOsX->pTaxingTail = pUrbOsX->pPrev; 1882 1883 if (pUrbOsX->pPrev) 1884 pUrbOsX->pPrev->pNext = pUrbOsX->pNext; 1885 else if (pDevOsX->pTaxingHead == pUrbOsX) 1886 pDevOsX->pTaxingHead = pUrbOsX->pNext; 1887 else 1888 AssertFailed(); 1889 1867 1890 pUrb = pUrbOsX->pVUsbUrb; 1868 1891 if (pUrb) … … 1938 1961 1939 1962 ASMAtomicXchgBool(&pDevOsX->fReapingThreadWake, true); 1940 1941 CFRunLoopRef hRunLoopWake = (CFRunLoopRef)ASMAtomicReadPtr((void * volatile *)&pDevOsX->hRunLoopReaping); 1942 if (hRunLoopWake) 1943 { 1944 LogFlow(("usbProxyDarwinWakeup: Waking runloop %p\n", hRunLoopWake)); 1945 CFRunLoopSourceSignal(pDevOsX->hRunLoopSrcWakeRef); 1946 CFRunLoopWakeUp(hRunLoopWake); 1947 } 1948 1963 usbProxyDarwinReaperKick(pDevOsX); 1949 1964 return VINF_SUCCESS; 1950 1965 } -
trunk/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
r50234 r52254 76 76 # define RTCRITSECT void * 77 77 static inline int rtcsNoop() { return VINF_SUCCESS; } 78 static inline bool rtcsTrue() { return true; } 78 79 # define RTCritSectInit(a) rtcsNoop() 79 80 # define RTCritSectDelete(a) rtcsNoop() 80 81 # define RTCritSectEnter(a) rtcsNoop() 81 82 # define RTCritSectLeave(a) rtcsNoop() 83 # define RTCritSectIsOwner(a) rtcsTrue() 82 84 #endif 83 85 #include <VBox/err.h> … … 91 93 #include <iprt/stream.h> 92 94 #include <iprt/string.h> 95 #include <iprt/list.h> 93 96 #if defined(NO_PORT_RESET) && !defined(NO_LOGICAL_RECONNECT) 94 97 # include <iprt/thread.h> … … 107 110 { 108 111 /** The kernel URB data */ 109 struct usbdevfs_urb KUrb;112 struct usbdevfs_urb KUrb; 110 113 /** Space filler for the isochronous packets. */ 111 114 struct usbdevfs_iso_packet_desc aIsocPktsDonUseTheseUseTheOnesInKUrb[8]; 112 /** The millisecond timestamp when this URB was submitted. */ 113 uint64_t u64SubmitTS; 114 /** Pointer to the next linux URB. */ 115 struct USBPROXYURBLNX *pNext; 116 /** Pointer to the previous linux URB. */ 117 struct USBPROXYURBLNX *pPrev; 115 /** Node to link the URB in of the existing lists. */ 116 RTLISTNODE NodeList; 118 117 /** If we've split the VUSBURB up into multiple linux URBs, this is points to the head. */ 119 struct USBPROXYURBLNX *pSplitHead;118 struct USBPROXYURBLNX *pSplitHead; 120 119 /** The next linux URB if split up. */ 121 struct USBPROXYURBLNX *pSplitNext; 122 /** Whether it has timed out and should be shot down on the next failing reap call. */ 123 bool fTimedOut; 124 /** Indicates that this URB has been canceled by timeout and should return an CRC error. */ 125 bool fCanceledByTimedOut; 120 struct USBPROXYURBLNX *pSplitNext; 126 121 /** Don't report these back. */ 127 bool fCanceledBySubmit;122 bool fCanceledBySubmit; 128 123 /** This split element is reaped. */ 129 bool fSplitElementReaped;124 bool fSplitElementReaped; 130 125 /** Size to transfer in remaining fragments of a split URB */ 131 uint32_t cbSplitRemaining;126 uint32_t cbSplitRemaining; 132 127 } USBPROXYURBLNX, *PUSBPROXYURBLNX; 133 128 … … 139 134 /** The open file. */ 140 135 RTFILE hFile; 141 /** Critical section protecting the twolists. */136 /** Critical section protecting the lists. */ 142 137 RTCRITSECT CritSect; 143 /** The list of free linux URBs . Singly linked. */144 PUSBPROXYURBLNX pFreeHead;145 /** The list of active linux URBs. Doubly linked.138 /** The list of free linux URBs (USBPROXYURBLNX). */ 139 RTLISTANCHOR ListFree; 140 /** The list of active linux URBs. 146 141 * We must maintain this so we can properly reap URBs of a detached device. 147 * Only the split head will appear in this list. */148 PUSBPROXYURBLNX pInFlightHead;142 * Only the split head will appear in this list. (USBPROXYURBLNX) */ 143 RTLISTANCHOR ListInFlight; 149 144 /** The list of landed linux URBs. Doubly linked. 150 * Only the split head will appear in this list. */ 151 PUSBPROXYURBLNX pTaxingHead; 152 /** The tail of the landed linux URBs. */ 153 PUSBPROXYURBLNX pTaxingTail; 145 * Only the split head will appear in this list. (USBPROXYURBLNX) */ 146 RTLISTANCHOR ListTaxing; 154 147 /** Are we using sysfs to find the active configuration? */ 155 148 bool fUsingSysfs; … … 233 226 pProxyDev->fDetached = true; 234 227 235 PUSBPROXYURBLNX pUrbTaxing = NULL; 236 PUSBPROXYURBLNX pUrbLnx = pDevLnx->pInFlightHead; 237 pDevLnx->pInFlightHead = NULL; 238 while (pUrbLnx) 239 { 240 PUSBPROXYURBLNX pCur = pUrbLnx; 241 pUrbLnx = pUrbLnx->pNext; 242 243 ioctl(RTFileToNative(pDevLnx->hFile), USBDEVFS_DISCARDURB, &pCur->KUrb); /* not sure if this is required.. */ 244 if (!pCur->KUrb.status) 245 pCur->KUrb.status = -ENODEV; 228 PUSBPROXYURBLNX pUrbLnx; 229 PUSBPROXYURBLNX pUrbLnxNext; 230 231 RTListForEachSafe(&pDevLnx->ListInFlight, pUrbLnx, pUrbLnxNext, USBPROXYURBLNX, NodeList) 232 { 233 RTListNodeRemove(&pUrbLnx->NodeList); 234 235 ioctl(RTFileToNative(pDevLnx->hFile), USBDEVFS_DISCARDURB, &pUrbLnx->KUrb); /* not sure if this is required.. */ 236 if (!pUrbLnx->KUrb.status) 237 pUrbLnx->KUrb.status = -ENODEV; 246 238 247 239 /* insert into the taxing list. */ 248 pCur->pPrev = NULL; 249 if ( !pCur->pSplitHead 250 || pCur == pCur->pSplitHead) 251 { 252 pCur->pNext = pUrbTaxing; 253 if (pUrbTaxing) 254 pUrbTaxing->pPrev = pCur; 255 pUrbTaxing = pCur; 256 } 257 else 258 pCur->pNext = NULL; 259 } 260 261 /* Append the URBs we shot down to the taxing queue. */ 262 if (pUrbTaxing) 263 { 264 pUrbTaxing->pPrev = pDevLnx->pTaxingTail; 265 if (pUrbTaxing->pPrev) 266 pUrbTaxing->pPrev->pNext = pUrbTaxing; 267 else 268 pDevLnx->pTaxingTail = pDevLnx->pTaxingHead = pUrbTaxing; 240 if ( !pUrbLnx->pSplitHead 241 || pUrbLnx == pUrbLnx->pSplitHead) 242 RTListAppend(&pDevLnx->ListTaxing, &pUrbLnx->NodeList); 269 243 } 270 244 … … 299 273 300 274 /** 275 * Links the given URB into the in flight list. 276 * 277 * @returns nothing. 278 * @param pDevLnx The proxy device instance - Linux specific data. 279 * @param pUrbLnx The URB to link into the in flight list. 280 */ 281 static void usbProxyLinuxUrbLinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURBLNX pUrbLnx) 282 { 283 Assert(RTCritSectIsOwner(&pDevLnx->CritSect)); 284 Assert(!pUrbLnx->pSplitHead); 285 RTListAppend(&pDevLnx->ListInFlight, &pUrbLnx->NodeList); 286 } 287 288 /** 289 * Unlinks the given URB from the in flight list. 290 * @returns nothing. 291 * @param pDevLnx The proxy device instance - Linux specific data. 292 * @param pUrbLnx The URB to link into the in flight list. 293 */ 294 static void usbProxyLinuxUrbUnlinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURBLNX pUrbLnx) 295 { 296 RTCritSectEnter(&pDevLnx->CritSect); 297 298 /* 299 * Remove from the active list. 300 */ 301 Assert(!pUrbLnx->pSplitHead || pUrbLnx->pSplitHead == pUrbLnx); 302 303 RTListNodeRemove(&pUrbLnx->NodeList); 304 pUrbLnx->pSplitHead = pUrbLnx->pSplitNext = NULL; 305 306 RTCritSectLeave(&pDevLnx->CritSect); 307 } 308 309 /** 301 310 * Allocates a linux URB request structure. 302 311 * @returns Pointer to an active URB request. … … 315 324 * Try remove a linux URB from the free list, if none there allocate a new one. 316 325 */ 317 pUrbLnx = pDevLnx->pFreeHead;326 pUrbLnx = RTListGetFirst(&pDevLnx->ListFree, USBPROXYURBLNX, NodeList); 318 327 if (pUrbLnx) 319 pDevLnx->pFreeHead = pUrbLnx->pNext; 328 { 329 RTListNodeRemove(&pUrbLnx->NodeList); 330 RTCritSectLeave(&pDevLnx->CritSect); 331 } 320 332 else 321 333 { … … 324 336 if (!pUrbLnx) 325 337 return NULL; 326 RTCritSectEnter(&pDevLnx->CritSect);327 } 338 } 339 328 340 pUrbLnx->pSplitHead = pSplitHead; 329 341 pUrbLnx->pSplitNext = NULL; 330 pUrbLnx->fTimedOut = false;331 pUrbLnx->fCanceledByTimedOut = false;332 342 pUrbLnx->fCanceledBySubmit = false; 333 343 pUrbLnx->fSplitElementReaped = false; 334 335 /*336 * Link it into the active list337 */338 if (!pSplitHead)339 {340 pUrbLnx->pPrev = NULL;341 pUrbLnx->pNext = pDevLnx->pInFlightHead;342 if (pUrbLnx->pNext)343 pUrbLnx->pNext->pPrev = pUrbLnx;344 pDevLnx->pInFlightHead = pUrbLnx;345 }346 else347 pUrbLnx->pPrev = pUrbLnx->pNext = (PUSBPROXYURBLNX)0xdead;348 349 RTCritSectLeave(&pDevLnx->CritSect);350 344 return pUrbLnx; 351 345 } … … 365 359 366 360 /* 367 * Remove from the active list.368 */369 if ( !pUrbLnx->pSplitHead370 || pUrbLnx->pSplitHead == pUrbLnx)371 {372 if (pUrbLnx->pNext)373 pUrbLnx->pNext->pPrev = pUrbLnx->pPrev;374 if (pUrbLnx->pPrev)375 pUrbLnx->pPrev->pNext = pUrbLnx->pNext;376 else377 pDevLnx->pInFlightHead = pUrbLnx->pNext;378 }379 pUrbLnx->pSplitHead = pUrbLnx->pSplitNext = NULL;380 381 /*382 361 * Link it into the free list. 383 362 */ 384 pUrbLnx->pPrev = NULL; 385 pUrbLnx->pNext = pDevLnx->pFreeHead; 386 pDevLnx->pFreeHead = pUrbLnx; 363 RTListAppend(&pDevLnx->ListFree, &pUrbLnx->NodeList); 387 364 388 365 RTCritSectLeave(&pDevLnx->CritSect); … … 409 386 pUrbLnx = pUrbLnx->pSplitNext; 410 387 Assert(pFree->pSplitHead); 388 pFree->pSplitHead = pFree->pSplitNext = NULL; 411 389 usbProxyLinuxUrbFree(pProxyDev, pFree); 412 390 } … … 665 643 */ 666 644 PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX); 645 646 RTListInit(&pDevLnx->ListFree); 647 RTListInit(&pDevLnx->ListInFlight); 648 RTListInit(&pDevLnx->ListTaxing); 667 649 pDevLnx->pszPath = RTStrDupN(pszPath, cchPath); 668 650 if (pDevLnx->pszPath) … … 782 764 783 765 PUSBPROXYURBLNX pUrbLnx; 784 while ((pUrbLnx = pDevLnx->pInFlightHead) != NULL) 785 { 786 pDevLnx->pInFlightHead = pUrbLnx->pNext; 766 PUSBPROXYURBLNX pUrbLnxNext; 767 RTListForEachSafe(&pDevLnx->ListInFlight, pUrbLnx, pUrbLnxNext, USBPROXYURBLNX, NodeList) 768 { 769 RTListNodeRemove(&pUrbLnx->NodeList); 770 787 771 if ( usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbLnx->KUrb, false, UINT32_MAX) 788 772 && errno != ENODEV 789 773 && errno != ENOENT) 790 774 AssertMsgFailed(("errno=%d\n", errno)); 775 791 776 if (pUrbLnx->pSplitHead) 792 777 { … … 809 794 } 810 795 811 while ((pUrbLnx = pDevLnx->pFreeHead) != NULL)812 { 813 pDevLnx->pFreeHead = pUrbLnx->pNext;796 RTListForEachSafe(&pDevLnx->ListFree, pUrbLnx, pUrbLnxNext, USBPROXYURBLNX, NodeList) 797 { 798 RTListNodeRemove(&pUrbLnx->NodeList); 814 799 RTMemFree(pUrbLnx); 815 800 } … … 1299 1284 pUrb, errno, pCur->KUrb.type, pCur->KUrb.endpoint, pCur->KUrb.buffer_length, cTries)); 1300 1285 if (errno != EBUSY && ++cTries < 3) /* this doesn't work for the floppy :/ */ 1301 {1302 pCur->u64SubmitTS = RTTimeMilliTS();1303 1286 continue; 1304 } 1287 1305 1288 return RTErrConvertFromErrno(errno); 1306 1289 } … … 1330 1313 return NULL; 1331 1314 } 1332 Assert(pHead->pNext != pNew); Assert(pHead->pPrev != pNew); Assert(pNew->pNext == pNew->pPrev);1333 1315 Assert(pNew->pSplitHead == pHead); 1334 1316 Assert(pNew->pSplitNext == NULL); … … 1433 1415 if (RT_FAILURE(rc)) 1434 1416 break; 1417 usbProxyLinuxUrbLinkInFlight(USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX), pCur); 1435 1418 } 1436 1419 } … … 1439 1422 { 1440 1423 pUrb->Dev.pvPrivate = pUrbLnx; 1424 usbProxyLinuxUrbLinkInFlight(USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX), pUrbLnx); 1441 1425 LogFlow(("usbProxyLinuxUrbQueueSplit: ok\n")); 1442 1426 return VINF_SUCCESS; … … 1513 1497 1514 1498 /* 1499 * We have to serialize access by using the critial section here because this 1500 * thread might be suspended after submitting the URB but before linking it into 1501 * the in flight list. This would get us in trouble when reaping the URB on another 1502 * thread while it isn't in the in flight list. 1503 * 1504 * Linking the URB into the list before submitting it like it was done in the past is not 1505 * possible either because submitting the URB might fail here because the device gets 1506 * detached. The reaper thread gets this event too and might race this thread before we 1507 * can unlink the URB from the active list and the common code might end up freeing 1508 * the common URB structure twice. 1509 */ 1510 RTCritSectEnter(&pDevLnx->CritSect); 1511 /* 1515 1512 * Submit it. 1516 1513 */ … … 1525 1522 if (pUrb->enmType == VUSBXFERTYPE_MSG) 1526 1523 usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData); 1524 1525 RTCritSectLeave(&pDevLnx->CritSect); 1527 1526 usbProxyLinuxUrbFree(pProxyDev, pUrbLnx); 1528 1529 1527 usbProxLinuxUrbUnplugged(pProxyDev); 1530 1528 return RTErrConvertFromErrno(errno); … … 1541 1539 if ( errno == EINVAL 1542 1540 && pUrb->cbData >= 8*_1K) 1541 { 1542 RTCritSectLeave(&pDevLnx->CritSect); 1543 1543 return usbProxyLinuxUrbQueueSplit(pProxyDev, pUrbLnx, pUrb); 1544 } 1544 1545 1545 1546 Log(("usb-linux: Queue URB %p -> %d!!! type=%d ep=%#x buffer_length=%#x cTries=%d\n", … … 1548 1549 continue; 1549 1550 1551 RTCritSectLeave(&pDevLnx->CritSect); 1550 1552 rc = RTErrConvertFromErrno(errno); 1551 1552 l_err:1553 1553 if (pUrb->enmType == VUSBXFERTYPE_MSG) 1554 1554 usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData); … … 1556 1556 return rc; 1557 1557 } 1558 pUrbLnx->u64SubmitTS = RTTimeMilliTS(); 1558 1559 usbProxyLinuxUrbLinkInFlight(pDevLnx, pUrbLnx); 1560 RTCritSectLeave(&pDevLnx->CritSect); 1559 1561 1560 1562 LogFlow(("usbProxyLinuxUrbQueue: ok\n")); 1561 1563 pUrb->Dev.pvPrivate = pUrbLnx; 1562 1564 return rc; 1563 }1564 1565 1566 /**1567 * Check if any or the in-flight URBs are taking too long and should be cancelled.1568 *1569 * Cancelling is done in three turns, first a URB is marked for timeout if it's1570 * exceeding a certain time limit. Then the next time it's encountered it is actually1571 * cancelled. The idea now is that it's supposed to be reaped and returned in the next1572 * round of calls.1573 *1574 * @param pProxyDev The proxy device.1575 * @param pDevLnx The linux backend data.1576 *1577 * @todo Make the HCI do proper timeout handling! Current timeout is 3 min and 20 seconds1578 * as not to break bloomberg which queues IN packages with 3 min timeouts.1579 */1580 static void vusbProxyLinuxUrbDoTimeouts(PUSBPROXYDEV pProxyDev, PUSBPROXYDEVLNX pDevLnx)1581 {1582 RTCritSectEnter(&pDevLnx->CritSect);1583 uint64_t u64MilliTS = RTTimeMilliTS();1584 PUSBPROXYURBLNX pCur;1585 for (pCur = pDevLnx->pInFlightHead;1586 pCur;1587 pCur = pCur->pNext)1588 {1589 if (pCur->fTimedOut)1590 {1591 if (pCur->pSplitHead)1592 {1593 /* split */1594 Assert(pCur == pCur->pSplitHead);1595 unsigned cFailures = 0;1596 PUSBPROXYURBLNX pCur2;1597 for (pCur2 = pCur; pCur2; pCur2 = pCur2->pSplitNext)1598 {1599 if (pCur2->fSplitElementReaped)1600 continue;1601 1602 if ( !usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pCur2->KUrb, true, UINT32_MAX)1603 || errno == ENOENT)1604 pCur2->fCanceledByTimedOut = true;1605 else if (errno != ENODEV)1606 Log(("vusbProxyLinuxUrbDoTimeouts: pUrb=%p failed errno=%d (!!split!!)\n", pCur2->KUrb.usercontext, errno));1607 else1608 goto l_leave; /* ENODEV means break and everything cancelled elsewhere. */1609 }1610 LogRel(("USB: Cancelled URB (%p) after %llums!! (cFailures=%d)\n",1611 pCur->KUrb.usercontext, (long long unsigned) u64MilliTS - pCur->u64SubmitTS, cFailures));1612 }1613 else1614 {1615 /* unsplit */1616 if ( !usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pCur->KUrb, true, UINT32_MAX)1617 || errno == -ENOENT)1618 {1619 pCur->fCanceledByTimedOut = true;1620 LogRel(("USB: Cancelled URB (%p) after %llums!!\n", pCur->KUrb.usercontext, (long long unsigned) u64MilliTS - pCur->u64SubmitTS));1621 }1622 else if (errno != ENODEV)1623 LogFlow(("vusbProxyLinuxUrbDoTimeouts: pUrb=%p failed errno=%d\n", pCur->KUrb.usercontext, errno));1624 else1625 goto l_leave; /* ENODEV means break and everything cancelled elsewhere. */1626 }1627 }1628 #if 01629 /* Disabled for the time being as some USB devices have URBs pending for an unknown amount of time.1630 * One example is the OmniKey CardMan 3821. */1631 else if (u64MilliTS - pCur->u64SubmitTS >= 200*1000 /* 200 sec (180 sec has been observed with XP) */)1632 pCur->fTimedOut = true;1633 #endif1634 }1635 1636 l_leave:1637 RTCritSectLeave(&pDevLnx->CritSect);1638 1565 } 1639 1566 … … 1695 1622 static VUSBSTATUS vusbProxyLinuxUrbGetStatus(PUSBPROXYURBLNX pUrbLnx) 1696 1623 { 1697 if ( pUrbLnx->fCanceledByTimedOut1698 && pUrbLnx->KUrb.status == 0)1699 return VUSBSTATUS_CRC;1700 1624 return vusbProxyLinuxStatusToVUsbStatus(pUrbLnx->KUrb.status); 1701 1625 } … … 1718 1642 * Any URBs pending delivery? 1719 1643 */ 1720 if ( pDevLnx->pTaxingHead)1644 if (!RTListIsEmpty(&pDevLnx->ListTaxing)) 1721 1645 { 1722 1646 RTCritSectEnter(&pDevLnx->CritSect); 1723 pUrbLnx = pDevLnx->pTaxingHead;1647 pUrbLnx = RTListGetFirst(&pDevLnx->ListTaxing, USBPROXYURBLNX, NodeList); 1724 1648 if (pUrbLnx) 1725 1649 { 1726 1650 /* unlink from the pending delivery list */ 1727 if (pUrbLnx->pNext) 1728 { 1729 pUrbLnx->pNext->pPrev = NULL; 1730 pDevLnx->pTaxingHead = pUrbLnx->pNext; 1731 } 1732 else 1733 pDevLnx->pTaxingHead = pDevLnx->pTaxingTail = NULL; 1651 RTListNodeRemove(&pDevLnx->ListTaxing); 1734 1652 1735 1653 /* temporarily into the active list, so free works right. */ 1736 pUrbLnx->pPrev = NULL; 1737 pUrbLnx->pNext = pDevLnx->pInFlightHead; 1738 if (pUrbLnx->pNext) 1739 pUrbLnx->pNext->pPrev = pUrbLnx; 1740 pDevLnx->pInFlightHead = pUrbLnx; 1654 RTListAppend(&pDevLnx->ListInFlight, &pUrbLnx->NodeList); 1741 1655 } 1742 1656 RTCritSectLeave(&pDevLnx->CritSect); … … 1744 1658 if (!pUrbLnx) 1745 1659 { 1746 /*1747 * Don't block if nothing is in the air.1748 */1749 if (!pDevLnx->pInFlightHead)1750 {1751 int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies;1752 1753 LogFlow(("Nothing in flight, going to sleep\n"));1754 1755 struct pollfd pfd;1756 1757 pfd.fd = RTPipeToNative(pDevLnx->hPipeWakeupR);1758 pfd.events = POLLIN | POLLHUP;1759 pfd.revents = 0;1760 1761 int rc = poll(&pfd, 1, cMilliesWait);1762 Log(("usbProxyLinuxUrbReap: poll rc = %d\n", rc));1763 if (rc >= 1)1764 {1765 /* Drain pipe. */1766 uint8_t bRead;1767 size_t cbIgnored = 0;1768 RTPipeRead(pDevLnx->hPipeWakeupR, &bRead, 1, &cbIgnored);1769 }1770 return NULL;1771 }1772 1773 1660 /* 1774 1661 * Block for requested period. … … 1807 1694 break; 1808 1695 } 1809 if (rc >= 0 /*|| errno == ETIMEOUT*/) 1810 { 1811 vusbProxyLinuxUrbDoTimeouts(pProxyDev, pDevLnx); 1696 if (rc >= 0) 1812 1697 return NULL; 1813 } 1698 1814 1699 if (errno != EAGAIN) 1815 1700 { … … 1832 1717 if (errno == ENODEV) 1833 1718 usbProxLinuxUrbUnplugged(pProxyDev); 1834 else if (errno == EAGAIN)1835 vusbProxyLinuxUrbDoTimeouts(pProxyDev, pDevLnx);1836 1719 else 1837 1720 Log(("usb-linux: Reap URB. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev))); … … 1922 1805 } 1923 1806 } 1807 usbProxyLinuxUrbUnlinkInFlight(pDevLnx, pUrbLnx); 1924 1808 usbProxyLinuxUrbFree(pProxyDev, pUrbLnx); 1925 1809 } … … 1935 1819 else 1936 1820 { 1821 usbProxyLinuxUrbUnlinkInFlight(pDevLnx, pUrbLnx); 1937 1822 usbProxyLinuxUrbFree(pProxyDev, pUrbLnx); 1938 1823 pUrb = NULL; -
trunk/src/VBox/Devices/USB/win/USBProxyDevice-win.cpp
r51738 r52254 2 2 /** @file 3 3 * USBPROXY - USB proxy, Win32 backend 4 *5 * NOTE: This code assumes only one thread will use it at a time!!6 * bird: usbProxyWinReset() will be called in a separate thread because it7 * will usually take >=10ms. So, the assumption is broken.8 4 */ 9 5
Note:
See TracChangeset
for help on using the changeset viewer.