Changeset 59775 in vbox for trunk/src/VBox/Devices/USB
- Timestamp:
- Feb 22, 2016 1:58:44 PM (9 years ago)
- Location:
- trunk/src/VBox/Devices/USB
- Files:
-
- 5 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
r59737 r59775 360 360 361 361 /** 362 * Worker routine for vusbRhConnNewUrb() and vusbDevNewIsocUrb().363 */ 364 PVUSBURB vusbRhNewUrb(PVUSBROOTHUB pRh, uint8_t DstAddress, PVUSBDEV pDev, VUSBXFERTYPE enmType,365 VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag)362 * Worker routine for vusbRhConnNewUrb(). 363 */ 364 static PVUSBURB vusbRhNewUrb(PVUSBROOTHUB pRh, uint8_t DstAddress, PVUSBDEV pDev, VUSBXFERTYPE enmType, 365 VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag) 366 366 { 367 367 PVUSBURBPOOL pUrbPool = &pRh->Hub.Dev.UrbPool; -
trunk/src/VBox/Devices/USB/VUSBBufferedPipe.cpp
r59774 r59775 1 1 /* $Id$ */ 2 2 /** @file 3 * Virtual USB - Read-ahead buffering for periodic endpoints.3 * Virtual USB - Buffering for isochronous in/outpipes. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-201 5Oracle Corporation7 * Copyright (C) 2006-2016 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 *********************************************************************************************************************************/ 22 22 #define LOG_GROUP LOG_GROUP_DRV_VUSB 23 #include <VBox/vmm/pdm.h>24 #include <VBox/vmm/vmapi.h>25 23 #include <VBox/err.h> 26 24 #include <VBox/log.h> 27 25 #include <iprt/alloc.h> 28 #include <iprt/time.h> 29 #include <iprt/thread.h> 30 #include <iprt/semaphore.h> 26 #include <iprt/assert.h> 31 27 #include <iprt/string.h> 32 #include <iprt/assert.h> 33 #include <iprt/asm.h> 28 #include <iprt/path.h> 34 29 #include <iprt/critsect.h> 30 #include <iprt/circbuf.h> 35 31 #include "VUSBInternal.h" 36 32 … … 41 37 42 38 /** 43 * VUSB Readahead instance data. 44 */ 45 typedef struct VUSBREADAHEADINT 39 * Copy of the isoc packet descriptors. 40 */ 41 typedef struct VUSBISOCDESC 42 { 43 /** Total number of bytes described by the packets. */ 44 size_t cbTotal; 45 /** The number of isochronous packets described in aIsocPkts. */ 46 uint32_t cIsocPkts; 47 /** The iso packets. */ 48 VUSBURBISOCPKT aIsocPkts[8]; 49 } VUSBISOCDESC; 50 /** Pointer to a isoc packets descriptor. */ 51 typedef VUSBISOCDESC *PVUSBISOCDESC; 52 53 /** 54 * Buffered pipe state. 55 */ 56 typedef enum VUSBBUFFEREDPIPESTATE 57 { 58 /** Invalid state. */ 59 VUSBBUFFEREDPIPESTATE_INVALID = 0, 60 /** The buffer is created. */ 61 VUSBBUFFEREDPIPESTATE_CREATING, 62 /** The buffer is destroyed. */ 63 VUSBBUFFEREDPIPESTATE_DESTROYING, 64 /** The buffer is filling with data. */ 65 VUSBBUFFEREDPIPESTATE_FILLING, 66 /** The buffer is streaming data to the guest/device based on the direction. */ 67 VUSBBUFFEREDPIPESTATE_STREAMING, 68 /** 32bit hack. */ 69 VUSBBUFFEREDPIPESTATE_32BIT_HACK = 0x7fffffff 70 } VUSBBUFFEREDPIPESTATE; 71 /** Pointer to a buffered pipe state. */ 72 typedef VUSBBUFFEREDPIPESTATE *PVUSBBUFFEREDPIPESTATE; 73 74 /** 75 * VUSB buffered pipe instance data. 76 */ 77 typedef struct VUSBBUFFEREDPIPEINT 46 78 { 47 79 /** Pointer to the device which the thread is for. */ 48 PVUSBDEV pDev;80 PVUSBDEV pDev; 49 81 /** Pointer to the pipe which the thread is servicing. */ 50 PVUSBPIPE pPipe; 51 /** A flag indicating a high-speed (vs. low/full-speed) endpoint. */ 52 bool fHighSpeed; 53 /** A flag telling the thread to terminate. */ 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; 82 PVUSBPIPE pPipe; 83 /** USB speed to serve. */ 84 VUSBSPEED enmSpeed; 85 /** The buffered pipe state. */ 86 VUSBBUFFEREDPIPESTATE enmState; 87 /** Maximum latency the buffer should cause. */ 88 uint32_t cLatencyMs; 89 /** Interval of the endpoint in frames (Low/Full-speed 1ms per frame, High-speed 125us). */ 90 unsigned uInterval; 91 /** Packet size. */ 92 size_t cbPktSize; 93 /** Endpoint. */ 94 unsigned uEndPt; 95 /** The direction of the buffering. */ 96 VUSBDIRECTION enmDirection; 97 /** Size of the ring buffer to keep all data for buffering. */ 98 size_t cbRingBufData; 99 /** The circular buffer keeping the data. */ 100 PRTCIRCBUF pRingBufData; 101 /** Number of URBs in flight on the device. */ 102 unsigned cUrbsInFlight; 103 /** Critical section protecting the ring buffer and. */ 104 RTCRITSECT CritSectBuffer; 105 /** Number of isoc descriptors for buffering. */ 106 unsigned cIsocDesc; 107 /** Current index into the isoc descriptor array for reading. */ 108 unsigned idxIsocDescRead; 109 /** Current index of the isoc descriptor for writing. */ 110 unsigned idxIsocDescWrite; 111 /** Array of isoc descriptors for pre buffering. */ 112 PVUSBISOCDESC paIsocDesc; 113 /** Our own URB pool. */ 114 VUSBURBPOOL UrbPool; 115 #ifdef DEBUG 116 /** Lock contention counter. */ 117 volatile uint32_t cLockContention; 118 #endif 119 #ifdef LOG_ENABLED 120 /** Serial number tag for logging. */ 121 uint32_t iSerial; 122 #endif 123 } VUSBBUFFEREDPIPEINT, *PVUSBBUFFEREDPIPEINT; 70 124 71 125 … … 74 128 *********************************************************************************************************************************/ 75 129 76 static PVUSBURB vusbDevNewIsocUrb(PVUSBDEV pDev, unsigned uEndPt, unsigned uInterval, unsigned uPktSize) 77 { 78 PVUSBURB pUrb; 79 unsigned cPackets = 0; 80 uint32_t cbTotal = 0; 81 unsigned uNextIndex = 0; 82 83 Assert(pDev); 84 Assert(uEndPt); 85 Assert(uInterval); 86 Assert(uPktSize); 87 88 /* Calculate the amount of data needed, taking the endpoint's bInterval into account */ 89 for (unsigned i = 0; i < 8; ++i) 90 { 91 if (i == uNextIndex) 92 { 93 cbTotal += uPktSize; 94 cPackets++; 95 uNextIndex += uInterval; 96 } 97 } 98 Assert(cbTotal <= 24576); 99 100 // @todo: What do we do if cPackets is 0? 130 /** 131 * Callback for freeing an URB. 132 * @param pUrb The URB to free. 133 */ 134 static DECLCALLBACK(void) vusbBufferedPipeFreeUrb(PVUSBURB pUrb) 135 { 136 /* 137 * Assert sanity. 138 */ 139 vusbUrbAssert(pUrb); 140 PVUSBBUFFEREDPIPEINT pThis = (PVUSBBUFFEREDPIPEINT)pUrb->pVUsb->pvFreeCtx; 141 AssertPtr(pThis); 142 143 /* 144 * Free the URB description (logging builds only). 145 */ 146 if (pUrb->pszDesc) 147 { 148 RTStrFree(pUrb->pszDesc); 149 pUrb->pszDesc = NULL; 150 } 151 152 vusbUrbPoolFree(&pThis->UrbPool, pUrb); 153 } 154 155 156 #ifdef DEBUG 157 /** 158 * Locks the buffered pipe for exclusive access. 159 * 160 * @returns nothing. 161 * @param pThis The buffered pipe instance. 162 */ 163 DECLINLINE(void) vusbBufferedPipeLock(PVUSBBUFFEREDPIPEINT pThis) 164 { 165 int rc = RTCritSectTryEnter(&pThis->CritSectBuffer); 166 if (rc == VERR_SEM_BUSY) 167 { 168 ASMAtomicIncU32(&pThis->cLockContention); 169 RTCritSectEnter(&pThis->CritSectBuffer); 170 } 171 } 172 #else 173 # define vusbBufferedPipeLock(a_pThis) RTCritSectEnter(&(a_pThis)->CritSectBuffer) 174 #endif 175 176 177 /** 178 * Create a new isochronous URB. 179 * 180 * @returns Pointer to the new URB or NULL on failure. 181 * @param pThis The buffered pipe instance. 182 * @param pIsocDesc The isochronous packet descriptor saved from the HC submitted URB. 183 */ 184 static PVUSBURB vusbBufferedPipeNewIsocUrb(PVUSBBUFFEREDPIPEINT pThis, PVUSBISOCDESC pIsocDesc) 185 { 186 PVUSBURB pUrb; 101 187 102 188 /* 103 189 * Allocate and initialize the URB. 104 190 */ 105 Assert(pDev->u8Address != VUSB_INVALID_ADDRESS); 106 107 PVUSBROOTHUB pRh = vusbDevGetRh(pDev); 108 if (!pRh) 109 /* can happen during disconnect */ 110 return NULL; 111 112 pUrb = vusbRhNewUrb(pRh, pDev->u8Address, NULL, VUSBXFERTYPE_ISOC, VUSBDIRECTION_IN, cbTotal, 1, "prab"); 191 Assert(pThis->pDev->u8Address != VUSB_INVALID_ADDRESS); 192 193 pUrb = vusbUrbPoolAlloc(&pThis->UrbPool, VUSBXFERTYPE_ISOC, pThis->enmDirection, pIsocDesc->cbTotal, 194 0, 0, 0); 113 195 if (!pUrb) 114 196 /* not much we can do here... */ 115 197 return NULL; 116 198 117 pUrb->EndPt = uEndPt; 118 pUrb->fShortNotOk = false; 119 pUrb->enmStatus = VUSBSTATUS_OK; 120 121 /* Set up the individual packets, again with bInterval in mind */ 122 pUrb->cIsocPkts = 8; 123 unsigned off = 0; 124 uNextIndex = 0; 125 for (unsigned i = 0; i < 8; i++) 199 pUrb->EndPt = pThis->uEndPt; 200 pUrb->fShortNotOk = false; 201 pUrb->enmStatus = VUSBSTATUS_OK; 202 pUrb->pVUsb->pvBuffered = pThis; 203 pUrb->pVUsb->pvFreeCtx = pThis; 204 pUrb->pVUsb->pfnFree = vusbBufferedPipeFreeUrb; 205 pUrb->DstAddress = pThis->pDev->u8Address; 206 pUrb->pVUsb->pDev = pThis->pDev; 207 208 #ifdef LOG_ENABLED 209 pThis->iSerial = (pThis->iSerial + 1) % 10000; 210 RTStrAPrintf(&pUrb->pszDesc, "URB %p isoc%c%04d (buffered)", pUrb, 211 (pUrb->enmDir == VUSBDIRECTION_IN) ? '<' : '>', 212 pThis->iSerial); 213 #endif 214 215 /* Copy data over. */ 216 void *pv = NULL; 217 size_t cb = 0; 218 RTCircBufAcquireReadBlock(pThis->pRingBufData, pIsocDesc->cbTotal, &pv, &cb); 219 memcpy(&pUrb->abData[0], pv, cb); 220 RTCircBufReleaseReadBlock(pThis->pRingBufData, cb); 221 /* Take possible wraparound in the ring buffer into account. */ 222 if (cb < pIsocDesc->cbTotal) 223 { 224 size_t cb2 = 0; 225 RTCircBufAcquireReadBlock(pThis->pRingBufData, pIsocDesc->cbTotal - cb, &pv, &cb2); 226 memcpy(&pUrb->abData[cb], pv, cb2); 227 RTCircBufReleaseReadBlock(pThis->pRingBufData, cb2); 228 Assert(pIsocDesc->cbTotal == cb + cb2); 229 } 230 231 /* Set up the individual packets. */ 232 pUrb->cIsocPkts = pIsocDesc->cIsocPkts; 233 for (unsigned i = 0; i < pUrb->cIsocPkts; i++) 126 234 { 127 235 pUrb->aIsocPkts[i].enmStatus = VUSBSTATUS_NOT_ACCESSED; 128 pUrb->aIsocPkts[i].off = off; 129 if (i == uNextIndex) // skip unused packets 236 pUrb->aIsocPkts[i].off = pIsocDesc->aIsocPkts[i].off; 237 pUrb->aIsocPkts[i].cb = pIsocDesc->aIsocPkts[i].cb; 238 } 239 240 return pUrb; 241 } 242 243 244 /** 245 * Stream waiting data to the device. 246 * 247 * @returns VBox status code. 248 * @param pThis The buffered pipe instance. 249 */ 250 static int vusbBufferedPipeStream(PVUSBBUFFEREDPIPEINT pThis) 251 { 252 int rc = VINF_SUCCESS; 253 254 while ( pThis->idxIsocDescRead != pThis->idxIsocDescWrite 255 && RT_SUCCESS(rc)) 256 { 257 PVUSBURB pUrb = vusbBufferedPipeNewIsocUrb(pThis, &pThis->paIsocDesc[pThis->idxIsocDescRead]); 258 if (pUrb) 130 259 { 131 pUrb->aIsocPkts[i].cb = uPktSize; 132 off += uPktSize; 133 uNextIndex += uInterval; 260 pUrb->enmState = VUSBURBSTATE_IN_FLIGHT; 261 rc = vusbUrbQueueAsyncRh(pUrb); 262 if (RT_SUCCESS(rc)) 263 pThis->cUrbsInFlight++; 264 else 265 pUrb->pVUsb->pfnFree(pUrb); 134 266 } 135 267 else 136 pUrb->aIsocPkts[i].cb = 0; 137 } 138 Assert(off == cbTotal); 139 return pUrb; 140 } 141 142 /** 143 * Thread function for performing read-ahead buffering of periodic input. 144 * 145 * This thread keeps a buffer (queue) filled with data read from a periodic 146 * input endpoint. 147 * 148 * The problem: In the EHCI emulation, there is a very short period between the 149 * time when the guest can schedule a request and the time when it expects the results. 150 * This leads to many dropped URBs because by the time we get the data from the host, 151 * the guest already gave up and moved on. 152 * 153 * The solution: For periodic transfers, we know the worst-case bandwidth. We can 154 * read ahead and buffer a few milliseconds worth of data. That way data is available 155 * by the time the guest asks for it and we can deliver it immediately. 156 * 157 * @returns success indicator. 158 * @param Thread This thread. 159 * @param pvUser Pointer to a VUSBREADAHEADARGS structure. 160 */ 161 static DECLCALLBACK(int) vusbDevReadAheadThread(RTTHREAD Thread, void *pvUser) 162 { 163 PVUSBREADAHEADINT pThis = (PVUSBREADAHEADINT)pvUser; 164 PVUSBPIPE pPipe; 165 PCVUSBDESCENDPOINT pDesc; 166 PVUSBURB pUrb; 167 int rc = VINF_SUCCESS; 168 unsigned max_pkt_size, mult, interval; 169 170 LogFlow(("vusb: periodic read-ahead buffer thread started\n")); 171 Assert(pThis); 172 Assert(pThis->pPipe && pThis->pDev); 173 174 pPipe = pThis->pPipe; 175 pDesc = &pPipe->in->Core; 176 Assert(pDesc); 177 178 Assert(!pThis->cSubmitted && !pThis->cBuffered); 179 180 /* Figure out the maximum bandwidth we might need */ 181 if (pThis->fHighSpeed) 268 rc = VERR_NO_MEMORY; 269 270 pThis->idxIsocDescRead = (pThis->idxIsocDescRead + 1) % pThis->cIsocDesc; 271 } 272 273 return rc; 274 } 275 276 277 /** 278 * Set parameters for the buffered pipe like packet size from the given endpoint. 279 * 280 * @returns VBox status code. 281 * @param pThis The buffered pipe instance. 282 * @param pDesc The endpoint descriptor to take the data from. 283 */ 284 static int vusbBufferedPipeSetParamsFromDescriptor(PVUSBBUFFEREDPIPEINT pThis, PCVUSBDESCENDPOINT pDesc) 285 { 286 int rc = VINF_SUCCESS; 287 unsigned cbPktMax, uInterval, uMult; 288 289 if (pThis->enmSpeed == VUSB_SPEED_HIGH) 182 290 { 183 291 /* High-speed endpoint */ 184 292 Assert((pDesc->wMaxPacketSize & 0x1fff) == pDesc->wMaxPacketSize); 185 293 Assert(pDesc->bInterval <= 16); 186 interval= pDesc->bInterval ? 1 << (pDesc->bInterval - 1) : 1;187 max_pkt_size= pDesc->wMaxPacketSize & 0x7ff;188 mult= ((pDesc->wMaxPacketSize & 0x1800) >> 11) + 1;189 } 190 else 294 uInterval = pDesc->bInterval ? 1 << (pDesc->bInterval - 1) : 1; 295 cbPktMax = pDesc->wMaxPacketSize & 0x7ff; 296 uMult = ((pDesc->wMaxPacketSize & 0x1800) >> 11) + 1; 297 } 298 else if (pThis->enmSpeed == VUSB_SPEED_FULL || pThis->enmSpeed == VUSB_SPEED_LOW) 191 299 { 192 300 /* Full- or low-speed endpoint */ 193 301 Assert((pDesc->wMaxPacketSize & 0x7ff) == pDesc->wMaxPacketSize); 194 interval = pDesc->bInterval; 195 max_pkt_size = pDesc->wMaxPacketSize; 196 mult = 1; 197 } 198 Log(("vusb: interval=%u, max pkt size=%u, multiplier=%u\n", interval, max_pkt_size, mult)); 199 200 /* 201 * Submit new URBs in a loop unless the buffer is too full (paused VM etc.). Note that we only 202 * queue the URBs here, they are reaped on a different thread. 203 */ 204 while (!pThis->fTerminate) 205 { 206 while (pThis->cSubmitted < pThis->cUrbsMax && pThis->cBuffered < pThis->cUrbsMax) 302 uInterval = pDesc->bInterval; 303 cbPktMax = pDesc->wMaxPacketSize; 304 uMult = 1; 305 } 306 else 307 { 308 /** @todo: Implement for super speed and up if it turns out to be required, at the moment it looks 309 * like we don't need it. */ 310 rc = VERR_NOT_SUPPORTED; 311 } 312 313 if (RT_SUCCESS(rc)) 314 { 315 pThis->uInterval = uInterval; 316 pThis->cbPktSize = cbPktMax * uMult; 317 pThis->uEndPt = pDesc->bEndpointAddress & 0xf; 318 319 unsigned cPackets = pThis->cLatencyMs / pThis->uInterval; 320 cPackets = RT_MAX(cPackets, 1); /* At least one packet. */ 321 pThis->cbRingBufData = pThis->cbPktSize * cPackets; 322 pThis->cIsocDesc = cPackets / 8 + ((cPackets % 8) ? 1 : 0); 323 } 324 325 return rc; 326 } 327 328 329 /** 330 * Completes an URB issued by the pipe buffer. 331 * 332 * @returns nothing. 333 * @param pUrb The completed URB. 334 */ 335 DECLHIDDEN(void) vusbBufferedPipeCompleteUrb(PVUSBURB pUrb) 336 { 337 Assert(pUrb); 338 Assert(pUrb->pVUsb->pvBuffered); 339 PVUSBBUFFEREDPIPEINT pThis = (PVUSBBUFFEREDPIPEINT)pUrb->pVUsb->pvBuffered; 340 341 vusbBufferedPipeLock(pThis); 342 343 #if defined(LOG_ENABLED) || defined(RT_STRICT) 344 unsigned cbXfer = 0; 345 for (unsigned i = 0; i < pUrb->cIsocPkts; i++) 346 { 347 LogFlowFunc(("packet %u: cb=%u enmStatus=%u\n", i, pUrb->aIsocPkts[i].cb, pUrb->aIsocPkts[i].enmStatus)); 348 cbXfer += pUrb->aIsocPkts[i].cb; 349 } 350 Assert(cbXfer == pUrb->cbData); 351 #endif 352 pUrb->pVUsb->pfnFree(pUrb); 353 pThis->cUrbsInFlight--; 354 355 /* Stream more data if available.*/ 356 if (pThis->enmState == VUSBBUFFEREDPIPESTATE_STREAMING) 357 vusbBufferedPipeStream(pThis); 358 RTCritSectLeave(&pThis->CritSectBuffer); 359 } 360 361 362 /** 363 * Submit and process the given URB, for outgoing endpoints we will buffer the content 364 * until we reached a threshold and start sending the data to the device. 365 * For incoming endpoints prefetched data is used to complete the URB immediately. 366 * 367 * @returns VBox status code. 368 * @param hBuffer The buffered pipe instance. 369 * @param pUrb The URB submitted by HC 370 */ 371 DECLHIDDEN(int) vusbBufferedPipeSubmitUrb(VUSBBUFFEREDPIPE hBuffer, PVUSBURB pUrb) 372 { 373 int rc = VINF_SUCCESS; 374 PVUSBBUFFEREDPIPEINT pThis = hBuffer; 375 376 AssertReturn(pThis->enmDirection == pUrb->enmDir, VERR_INTERNAL_ERROR); 377 AssertReturn(pUrb->enmType == VUSBXFERTYPE_ISOC, VERR_INTERNAL_ERROR); 378 379 vusbBufferedPipeLock(pThis); 380 381 if (pThis->enmDirection == VUSBDIRECTION_OUT) 382 { 383 void *pv = NULL; 384 size_t cb = 0; 385 386 /* Copy the data of the URB into our internal ring buffer. */ 387 RTCircBufAcquireWriteBlock(pThis->pRingBufData, pUrb->cbData, &pv, &cb); 388 memcpy(pv, &pUrb->abData[0], cb); 389 RTCircBufReleaseWriteBlock(pThis->pRingBufData, cb); 390 /* Take possible wraparound in the ring buffer into account. */ 391 if (cb < pUrb->cbData) 207 392 { 208 pUrb = vusbDevNewIsocUrb(pThis->pDev, pDesc->bEndpointAddress & 0xF, interval, max_pkt_size * mult); 209 if (!pUrb) { 210 /* Happens if device was unplugged. */ 211 Log(("vusb: read-ahead thread failed to allocate new URB; exiting\n")); 212 vusbReadAheadStop(pThis); 213 break; 393 size_t cb2 = 0; 394 RTCircBufAcquireWriteBlock(pThis->pRingBufData, pUrb->cbData - cb, &pv, &cb2); 395 memcpy(pv, &pUrb->abData[cb], cb2); 396 RTCircBufReleaseWriteBlock(pThis->pRingBufData, cb2); 397 Assert(pUrb->cbData == cb + cb2); 398 } 399 400 /* 401 * Copy the isoc packet descriptors over stuffing as much as possible into one. 402 * We recombine URBs into one if possible maximizing the number of frames 403 * one URB covers when we send it to the device. 404 */ 405 unsigned idxIsocPkt = 0; 406 for (unsigned iTry = 0; iTry < 2; iTry++) 407 { 408 PVUSBISOCDESC pIsocDesc = &pThis->paIsocDesc[pThis->idxIsocDescWrite]; 409 for (unsigned i = idxIsocPkt; i < pUrb->cIsocPkts && pIsocDesc->cIsocPkts < RT_ELEMENTS(pIsocDesc->aIsocPkts); i++) 410 { 411 pIsocDesc->aIsocPkts[pIsocDesc->cIsocPkts].enmStatus = VUSBSTATUS_NOT_ACCESSED; 412 pIsocDesc->aIsocPkts[pIsocDesc->cIsocPkts].off = pIsocDesc->cbTotal; 413 pIsocDesc->aIsocPkts[pIsocDesc->cIsocPkts].cb = pUrb->aIsocPkts[i].cb; 414 pIsocDesc->cbTotal += pUrb->aIsocPkts[i].cb; 415 pIsocDesc->cIsocPkts++; 416 idxIsocPkt++; 417 pUrb->aIsocPkts[i].enmStatus = VUSBSTATUS_OK; 214 418 } 215 419 216 Assert(pUrb->enmState == VUSBURBSTATE_ALLOCATED); 217 218 pUrb->pVUsb->pvReadAhead = pvUser; 219 pUrb->enmState = VUSBURBSTATE_IN_FLIGHT; 220 rc = vusbUrbQueueAsyncRh(pUrb); 221 if (RT_FAILURE(rc)) 420 if (pIsocDesc->cIsocPkts == RT_ELEMENTS(pIsocDesc->aIsocPkts)) 222 421 { 223 /* Happens if device was unplugged. */ 224 Log(("vusb: read-ahead thread failed to queue URB with %Rrc; exiting\n", rc)); 225 pThis->cUrbsMax = pThis->cSubmitted; 226 pUrb->pVUsb->pfnFree(pUrb); 227 break; 422 /* Advance to the next isoc descriptor. */ 423 pThis->idxIsocDescWrite = (pThis->idxIsocDescWrite + 1) % pThis->cIsocDesc; 424 pThis->paIsocDesc[pThis->idxIsocDescWrite].cbTotal = 0; 425 pThis->paIsocDesc[pThis->idxIsocDescWrite].cIsocPkts = 0; 426 /* On the first wraparound start streaming because our buffer is full. */ 427 if ( pThis->enmState == VUSBBUFFEREDPIPESTATE_FILLING 428 && pThis->idxIsocDescWrite == 0) 429 pThis->enmState = VUSBBUFFEREDPIPESTATE_STREAMING; 430 } 431 } 432 433 if (pThis->enmState == VUSBBUFFEREDPIPESTATE_STREAMING) 434 { 435 /* Stream anything we have. */ 436 rc = vusbBufferedPipeStream(pThis); 437 } 438 439 /* Complete the URB submitted by the HC. */ 440 pUrb->enmState = VUSBURBSTATE_REAPED; 441 pUrb->enmStatus = VUSBSTATUS_OK; 442 vusbUrbCompletionRh(pUrb); 443 } 444 else 445 { 446 AssertMsgFailed(("TODO")); 447 } 448 RTCritSectLeave(&pThis->CritSectBuffer); 449 return rc; 450 } 451 452 453 DECLHIDDEN(int) vusbBufferedPipeCreate(PVUSBDEV pDev, PVUSBPIPE pPipe, VUSBDIRECTION enmDirection, 454 VUSBSPEED enmSpeed, uint32_t cLatencyMs, 455 PVUSBBUFFEREDPIPE phBuffer) 456 { 457 int rc; 458 PVUSBBUFFEREDPIPEINT pThis = (PVUSBBUFFEREDPIPEINT)RTMemAllocZ(sizeof(VUSBBUFFEREDPIPEINT)); 459 460 AssertReturn(enmDirection == VUSBDIRECTION_IN || enmDirection == VUSBDIRECTION_OUT, 461 VERR_INVALID_PARAMETER); 462 AssertPtrReturn(pDev, VERR_INVALID_POINTER); 463 AssertPtrReturn(pPipe, VERR_INVALID_POINTER); 464 AssertPtrReturn(phBuffer, VERR_INVALID_POINTER); 465 466 if (!cLatencyMs) 467 { 468 *phBuffer = NULL; 469 return VINF_SUCCESS; 470 } 471 472 if (pThis) 473 { 474 PCVUSBDESCENDPOINT pDesc; 475 476 pThis->pDev = pDev; 477 pThis->pPipe = pPipe; 478 pThis->enmSpeed = enmSpeed; 479 pThis->cLatencyMs = cLatencyMs; 480 pThis->enmDirection = enmDirection; 481 pThis->enmState = VUSBBUFFEREDPIPESTATE_CREATING; 482 pThis->cUrbsInFlight = 0; 483 pThis->idxIsocDescRead = 0; 484 pThis->idxIsocDescWrite = 0; 485 #ifdef DEBUG 486 pThis->cLockContention = 0; 487 #endif 488 #ifdef LOG_ENABLED 489 pThis->iSerial = 0; 490 #endif 491 492 if (enmDirection == VUSBDIRECTION_IN) 493 pDesc = &pPipe->in->Core; 494 else 495 pDesc = &pPipe->out->Core; 496 Assert(pDesc); 497 498 rc = vusbBufferedPipeSetParamsFromDescriptor(pThis, pDesc); 499 if (RT_SUCCESS(rc)) 500 { 501 pThis->paIsocDesc = (PVUSBISOCDESC)RTMemAllocZ(pThis->cIsocDesc * sizeof(VUSBISOCDESC)); 502 if (RT_LIKELY(pThis->paIsocDesc)) 503 { 504 rc = vusbUrbPoolInit(&pThis->UrbPool); 505 if (RT_SUCCESS(rc)) 506 { 507 rc = RTCritSectInit(&pThis->CritSectBuffer); 508 if (RT_SUCCESS(rc)) 509 { 510 /* 511 * Create a ring buffer which can hold twice the amount of data 512 * for the required latency so we can fill the buffer with new data 513 * while the old one is still being used 514 */ 515 rc = RTCircBufCreate(&pThis->pRingBufData, 2 * pThis->cbRingBufData); 516 if (RT_SUCCESS(rc)) 517 { 518 /* 519 * For an input pipe start filling the buffer for an output endpoint 520 * we have to wait until the buffer is filled by the guest before 521 * starting to stream it to the device. 522 */ 523 if (enmDirection == VUSBDIRECTION_IN) 524 { 525 /** @todo */ 526 } 527 pThis->enmState = VUSBBUFFEREDPIPESTATE_FILLING; 528 *phBuffer = pThis; 529 return VINF_SUCCESS; 530 } 531 532 RTCritSectDelete(&pThis->CritSectBuffer); 533 } 534 535 RTMemFree(pThis->paIsocDesc); 536 } 228 537 } 229 538 else 230 ASMAtomicIncU32(&pThis->cSubmitted);539 rc = VERR_NO_MEMORY; 231 540 } 541 542 RTMemFree(pThis); 543 } 544 else 545 rc = VERR_NO_MEMORY; 546 547 return rc; 548 } 549 550 551 DECLHIDDEN(void) vusbBufferedPipeDestroy(VUSBBUFFEREDPIPE hBuffer) 552 { 553 PVUSBBUFFEREDPIPEINT pThis = hBuffer; 554 555 pThis->enmState = VUSBBUFFEREDPIPESTATE_DESTROYING; 556 557 /* Cancel all outstanding URBs. */ 558 vusbDevCancelAllUrbs(pThis->pDev, false /* fDetaching */); 559 560 vusbBufferedPipeLock(pThis); 561 pThis->cUrbsInFlight = 0; 562 563 /* Stream the last data. */ 564 vusbBufferedPipeStream(pThis); 565 566 /* Wait for any in flight URBs to complete. */ 567 while (pThis->cUrbsInFlight) 568 { 569 RTCritSectLeave(&pThis->CritSectBuffer); 232 570 RTThreadSleep(1); 233 } 234 LogFlow(("vusb: periodic read-ahead buffer thread exiting\n")); 235 236 /* wait until there are no more submitted packets */ 237 while (pThis->cSubmitted > 0) 238 { 239 Log2(("vusbDevReadAheadThread: still %u packets submitted, waiting before terminating...\n", pThis->cSubmitted)); 240 RTThreadSleep(1); 241 } 242 243 RTCritSectEnter(&pThis->CritSectBuffUrbList); 244 /* 245 * Free all still buffered URBs because another endpoint with a different packet size 246 * and complete different data formats might be served later. 247 */ 248 while (pThis->pBuffUrbHead) 249 { 250 PVUSBURB pBufferedUrb = pThis->pBuffUrbHead; 251 252 pThis->pBuffUrbHead = (PVUSBURB)pBufferedUrb->pVUsb->pvReadAhead; 253 pBufferedUrb->pVUsb->pfnFree(pBufferedUrb); 254 } 255 256 RTCritSectLeave(&pThis->CritSectBuffUrbList); 257 RTCritSectDelete(&pThis->CritSectBuffUrbList); 258 RTMemTmpFree(pThis); 259 260 return rc; 261 } 262 263 /** 264 * Completes a read-ahead URB. This function does *not* free the URB but puts 265 * it on a queue instead. The URB is only freed when the guest asks for the data 266 * (by reading on the buffered pipe) or when the pipe/device is torn down. 267 */ 268 void vusbUrbCompletionReadAhead(PVUSBURB pUrb) 269 { 270 Assert(pUrb); 271 Assert(pUrb->pVUsb->pvReadAhead); 272 PVUSBREADAHEADINT pThis = (PVUSBREADAHEADINT)pUrb->pVUsb->pvReadAhead; 273 PVUSBPIPE pPipe = pThis->pPipe; 274 Assert(pPipe); 275 276 RTCritSectEnter(&pThis->CritSectBuffUrbList); 277 pUrb->pVUsb->pvReadAhead = NULL; 278 if (pThis->pBuffUrbHead == NULL) 279 { 280 // The queue is empty, this is easy 281 Assert(!pThis->pBuffUrbTail); 282 pThis->pBuffUrbTail = pThis->pBuffUrbHead = pUrb; 283 } 284 else 285 { 286 // Some URBs are queued already 287 Assert(pThis->pBuffUrbTail); 288 Assert(!pThis->pBuffUrbTail->pVUsb->pvReadAhead); 289 pThis->pBuffUrbTail->pVUsb->pvReadAhead = pUrb; 290 pThis->pBuffUrbTail = pUrb; 291 } 292 ASMAtomicDecU32(&pThis->cSubmitted); 293 ++pThis->cBuffered; 294 RTCritSectLeave(&pThis->CritSectBuffUrbList); 295 } 296 297 /** 298 * Process a submit of an input URB on a pipe with read-ahead buffering. Instead 299 * of passing the URB to the proxy, we use previously read data stored in the 300 * read-ahead buffer, immediately complete the input URB and free the buffered URB. 301 * 302 * @param pUrb The URB submitted by HC 303 * @param hReadAhead The read-ahead buffering instance 304 * 305 * @return int Status code 306 */ 307 int vusbUrbSubmitBufferedRead(PVUSBURB pUrb, VUSBREADAHEAD hReadAhead) 308 { 309 PVUSBREADAHEADINT pThis = hReadAhead; 310 PVUSBURB pBufferedUrb; 311 Assert(pUrb && pThis); 312 313 RTCritSectEnter(&pThis->CritSectBuffUrbList); 314 pBufferedUrb = pThis->pBuffUrbHead; 315 if (pBufferedUrb) 316 { 317 unsigned cbTotal; 318 319 // There's a URB available in the read-ahead buffer; use it 320 pThis->pBuffUrbHead = (PVUSBURB)pBufferedUrb->pVUsb->pvReadAhead; 321 if (pThis->pBuffUrbHead == NULL) 322 pThis->pBuffUrbTail = NULL; 323 324 --pThis->cBuffered; 325 RTCritSectLeave(&pThis->CritSectBuffUrbList); 326 327 // Make sure the buffered URB is what we expect 328 Assert(pUrb->enmType == pBufferedUrb->enmType); 329 Assert(pUrb->EndPt == pBufferedUrb->EndPt); 330 Assert(pUrb->enmDir == pBufferedUrb->enmDir); 331 332 pUrb->enmState = VUSBURBSTATE_REAPED; 333 pUrb->enmStatus = pBufferedUrb->enmStatus; 334 cbTotal = 0; 335 // Copy status and data received from the device 336 for (unsigned i = 0; i < pUrb->cIsocPkts; ++i) 337 { 338 unsigned off, len; 339 340 off = pBufferedUrb->aIsocPkts[i].off; 341 len = pBufferedUrb->aIsocPkts[i].cb; 342 pUrb->aIsocPkts[i].cb = len; 343 pUrb->aIsocPkts[i].off = off; 344 pUrb->aIsocPkts[i].enmStatus = pBufferedUrb->aIsocPkts[i].enmStatus; 345 cbTotal += len; 346 //Assert(pUrb->pVUsb->cbDataAllocated >= cbTotal); /* Not publicly available anymore. */ 347 memcpy(&pUrb->abData[off], &pBufferedUrb->abData[off], len); 348 } 349 // Give back the data to the HC right away and then free the buffered URB 350 vusbUrbCompletionRh(pUrb); 351 // This assertion is wrong as the URB could be re-allocated in the meantime by the EMT (race) 352 // Assert(pUrb->enmState == VUSBURBSTATE_FREE); 353 Assert(pBufferedUrb->enmState == VUSBURBSTATE_REAPED); 354 LogFlow(("%s: vusbUrbSubmitBufferedRead: Freeing buffered URB\n", pBufferedUrb->pszDesc)); 355 pBufferedUrb->pVUsb->pfnFree(pBufferedUrb); 356 // This assertion is wrong as the URB could be re-allocated in the meantime by the EMT (race) 357 // Assert(pBufferedUrb->enmState == VUSBURBSTATE_FREE); 358 } 359 else 360 { 361 RTCritSectLeave(&pThis->CritSectBuffUrbList); 362 // No URB on hand. Either we exhausted the buffer (shouldn't happen!) or the guest simply 363 // asked for data too soon. Pretend that the device didn't deliver any data. 364 pUrb->enmState = VUSBURBSTATE_REAPED; 365 pUrb->enmStatus = VUSBSTATUS_DATA_UNDERRUN; 366 for (unsigned i = 0; i < pUrb->cIsocPkts; ++i) 367 { 368 pUrb->aIsocPkts[i].cb = 0; 369 pUrb->aIsocPkts[i].enmStatus = VUSBSTATUS_NOT_ACCESSED; 370 } 371 vusbUrbCompletionRh(pUrb); 372 // This assertion is wrong as the URB could be re-allocated in the meantime by the EMT (race) 373 // Assert(pUrb->enmState == VUSBURBSTATE_FREE); 374 LogFlow(("vusbUrbSubmitBufferedRead: No buffered URB available!\n")); 375 } 376 return VINF_SUCCESS; 377 } 378 379 /* Read-ahead start/stop functions, used primarily to keep the PVUSBREADAHEADARGS struct private to this module. */ 380 381 VUSBREADAHEAD vusbReadAheadStart(PVUSBDEV pDev, PVUSBPIPE pPipe) 382 { 383 int rc; 384 PVUSBREADAHEADINT pThis = (PVUSBREADAHEADINT)RTMemTmpAlloc(sizeof(VUSBREADAHEADINT)); 385 386 if (pThis) 387 { 388 PVUSBROOTHUB pRh = vusbDevGetRh(pDev); 389 pThis->pDev = pDev; 390 pThis->pPipe = pPipe; 391 pThis->fTerminate = false; 392 pThis->fHighSpeed = pRh && ((pRh->fHcVersions & VUSB_STDVER_20) != 0); 393 pThis->cUrbsMax = 120; 394 pThis->pBuffUrbHead = NULL; 395 pThis->pBuffUrbTail = NULL; 396 pThis->cBuffered = 0; 397 pThis->cSubmitted = 0; 398 rc = RTCritSectInit(&pThis->CritSectBuffUrbList); 399 if (RT_SUCCESS(rc)) 400 { 401 if (pThis->fHighSpeed) 402 rc = RTThreadCreate(&pThis->hReadAheadThread, vusbDevReadAheadThread, pThis, 0, RTTHREADTYPE_IO, 0 /* fFlags */, "USBISOC"); 403 else 404 rc = VERR_VUSB_DEVICE_NOT_ATTACHED; // No buffering for low/full-speed devices at the moment, needs testing. 405 if (RT_SUCCESS(rc)) 406 { 407 Log(("vusb: created isochronous read-ahead thread\n")); 408 return pThis; 409 } 410 else 411 Log(("vusb: isochronous read-ahead thread creation failed, rc=%d\n", rc)); 412 413 rc = RTCritSectDelete(&pThis->CritSectBuffUrbList); 414 AssertRC(rc); 415 } 416 417 RTMemTmpFree(pThis); 418 } 419 420 /* If thread creation failed for any reason, simply fall back to standard processing. */ 421 return NULL; 422 } 423 424 void vusbReadAheadStop(VUSBREADAHEAD hReadAhead) 425 { 426 PVUSBREADAHEADINT pThis = hReadAhead; 427 Log(("vusb: terminating read-ahead thread for endpoint\n")); 428 ASMAtomicXchgBool(&pThis->fTerminate, true); 429 } 430 431 /* 432 * Local Variables: 433 * mode: c 434 * c-file-style: "bsd" 435 * c-basic-offset: 4 436 * tab-width: 4 437 * indent-tabs-mode: s 438 * End: 439 */ 440 571 RTCritSectEnter(&pThis->CritSectBuffer); 572 } 573 574 RTCircBufDestroy(pThis->pRingBufData); 575 vusbUrbPoolDestroy(&pThis->UrbPool); 576 RTCritSectLeave(&pThis->CritSectBuffer); 577 LogRel(("VUSB: Destroyed buffered pipe with lock contention counter %u\n", pThis->cLockContention)); 578 RTMemFree(pThis->paIsocDesc); 579 RTMemFree(pThis); 580 } 581 582 -
trunk/src/VBox/Devices/USB/VUSBDevice.cpp
r59767 r59775 137 137 Log(("vusb: map input pipe on address %u\n", i8Addr)); 138 138 pPipe->in = pEndPtDesc; 139 140 ///@todo: This is currently utterly broken and causes untold damage.141 #if 0 //defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)142 /*143 * For high-speed isochronous input endpoints, spin off a read-ahead buffering thread.144 */145 if ((pEndPtDesc->Core.bmAttributes & 0x03) == 1)146 pPipe->hReadAhead = vusbReadAheadStart(pDev, pPipe);147 #endif148 139 } 149 140 else … … 151 142 Log(("vusb: map output pipe on address %u\n", i8Addr)); 152 143 pPipe->out = pEndPtDesc; 144 145 #if 0 146 if ((pEndPtDesc->Core.bmAttributes & 0x03) == 1) 147 { 148 int rc = vusbBufferedPipeCreate(pDev, pPipe, VUSBDIRECTION_OUT, pDev->pUsbIns->enmSpeed, 149 32 /* cLatencyMs*/, &pPipe->hBuffer); 150 if (RT_SUCCESS(rc)) 151 LogRel(("VUSB: Created a buffered pipe for isochronous output endpoint\n")); 152 else 153 LogRel(("VUSB: Failed to create a buffered pipe for isochronous output endpoint with rc=%Rrc\n", rc)); 154 } 155 #endif 153 156 } 154 157 … … 179 182 pPipe->in = NULL; 180 183 181 /* If there was a read-ahead thread associated with this endpoint, tell it to go away. */182 if (pPipe->h ReadAhead)184 /* Terminate the pipe buffer if created. */ 185 if (pPipe->hBuffer) 183 186 { 184 Log(("vusb: and tell read-ahead thread for the endpoint to terminate\n")); 185 vusbReadAheadStop(pPipe->hReadAhead); 186 pPipe->hReadAhead = NULL; 187 vusbBufferedPipeDestroy(pPipe->hBuffer); 188 pPipe->hBuffer = NULL; 187 189 } 188 190 } … … 191 193 Log(("vusb: unmap OUT pipe from address %u (%#x)\n", EndPt, pEndPtDesc->Core.bEndpointAddress)); 192 194 pPipe->out = NULL; 195 196 /* Terminate the pipe buffer if created. */ 197 if (pPipe->hBuffer) 198 { 199 vusbBufferedPipeDestroy(pPipe->hBuffer); 200 pPipe->hBuffer = NULL; 201 } 193 202 } 194 203 … … 228 237 pPipe->pCtrl = NULL; 229 238 230 if (pPipe->h ReadAhead)231 { 232 vusb ReadAheadStop(pPipe->hReadAhead);233 pPipe->h ReadAhead= NULL;239 if (pPipe->hBuffer) 240 { 241 vusbBufferedPipeDestroy(pPipe->hBuffer); 242 pPipe->hBuffer = NULL; 234 243 } 235 244 … … 1133 1142 * any URBs which isn't reaped. 1134 1143 */ 1135 static voidvusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching)1144 DECLHIDDEN(void) vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching) 1136 1145 { 1137 1146 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbDevCancelAllUrbsWorker, 2, pDev, fDetaching); -
trunk/src/VBox/Devices/USB/VUSBInternal.h
r59738 r59775 28 28 #include <VBox/vusb.h> 29 29 #include <VBox/vmm/stam.h> 30 #include <VBox/vmm/pdm.h> 31 #include <VBox/vmm/vmapi.h> 30 32 #include <VBox/vmm/pdmusb.h> 31 33 #include <iprt/asm.h> 32 34 #include <iprt/assert.h> 33 35 #include <iprt/req.h> 36 #include <iprt/asm.h> 34 37 #include <iprt/list.h> 35 38 … … 93 96 /** Submit timestamp. (logging only) */ 94 97 uint64_t u64SubmitTS; 95 /** Opaque data holder when this is a read-ahead URB. */96 void *pv ReadAhead;98 /** Opaque data holder when this is an URB from a buffered pipe. */ 99 void *pvBuffered; 97 100 } VUSBURBVUSBINT; 98 101 … … 144 147 void vusbMsgResetExtraData(PVUSBCTRLEXTRA pExtra); 145 148 146 /** Opaque VUSB read ahead buffer management handle. */ 147 typedef struct VUSBREADAHEADINT *VUSBREADAHEAD; 149 /** Opaque VUSB buffered pipe management handle. */ 150 typedef struct VUSBBUFFEREDPIPEINT *VUSBBUFFEREDPIPE; 151 /** Pointer to a VUSB buffered pipe handle. */ 152 typedef VUSBBUFFEREDPIPE *PVUSBBUFFEREDPIPE; 148 153 149 154 /** … … 160 165 /** Count of active async transfers. */ 161 166 volatile uint32_t async; 162 /** Read ahead handle. */163 VUSB READAHEAD hReadAhead;167 /** Pipe buffer - only valid for isochronous endpoints. */ 168 VUSBBUFFEREDPIPE hBuffer; 164 169 } VUSBPIPE; 165 170 /** Pointer to a VUSB pipe structure. */ … … 490 495 int vusbDevUrbIoThreadCreate(PVUSBDEV pDev); 491 496 int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev); 497 DECLHIDDEN(void) vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching); 492 498 DECLHIDDEN(int) vusbDevIoThreadExecV(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args); 493 499 DECLHIDDEN(int) vusbDevIoThreadExec(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...); … … 495 501 DECLHIDDEN(int) vusbUrbCancelWorker(PVUSBURB pUrb, CANCELMODE enmMode); 496 502 497 void vusbUrbCompletionReadAhead(PVUSBURB pUrb);498 VUSBREADAHEAD vusbReadAheadStart(PVUSBDEV pDev, PVUSBPIPE pPipe);499 void vusbReadAheadStop(VUSBREADAHEAD hReadAhead);500 503 int vusbUrbQueueAsyncRh(PVUSBURB pUrb); 501 int vusbUrbSubmitBufferedRead(PVUSBURB pUrb, VUSBREADAHEAD hReadAhead); 502 PVUSBURB vusbRhNewUrb(PVUSBROOTHUB pRh, uint8_t DstAddress, PVUSBDEV pDev, VUSBXFERTYPE enmType, 503 VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag); 504 505 /** 506 * Completes an URB from a buffered pipe. 507 * 508 * @returns nothing. 509 * @param pUrb The URB to complete. 510 */ 511 DECLHIDDEN(void) vusbBufferedPipeCompleteUrb(PVUSBURB pUrb); 512 513 /** 514 * Creates a new buffered pipe. 515 * 516 * @returns VBox status code. 517 * @retval VERR_NOT_SUPPORTED if buffering is not supported for the given pipe. 518 * @param pDev The device instance the pipe is associated with. 519 * @param pPipe The pipe to buffer. 520 * @param enmDirection The direction for the buffering. 521 * @param enmSpeed USB device speed. 522 * @param cLatencyMs The maximum latency the buffering should introduce, this influences 523 * the amount of data to buffer. 524 * @param phBuffer Where to store the handle to the buffer on success. 525 */ 526 DECLHIDDEN(int) vusbBufferedPipeCreate(PVUSBDEV pDev, PVUSBPIPE pPipe, VUSBDIRECTION enmDirection, 527 VUSBSPEED enmSpeed, uint32_t cLatencyMs, 528 PVUSBBUFFEREDPIPE phBuffer); 529 530 /** 531 * Destroys a buffered pipe, freeing all acquired resources. 532 * 533 * @returns nothing. 534 * @param hBuffer The buffered pipe handle. 535 */ 536 DECLHIDDEN(void) vusbBufferedPipeDestroy(VUSBBUFFEREDPIPE hBuffer); 537 538 /** 539 * Submits a URB from the HCD which is subject to buffering. 540 * 541 * @returns VBox status code. 542 * @param hBuffer The buffered pipe handle. 543 * @param pUrb The URB from the HCD which is subject to buffering. 544 */ 545 DECLHIDDEN(int) vusbBufferedPipeSubmitUrb(VUSBBUFFEREDPIPE hBuffer, PVUSBURB pUrb); 504 546 505 547 /** … … 508 550 * @returns VBox status code. 509 551 * @param pUrbPool The URB pool to initialize. 510 511 552 */ 512 553 DECLHIDDEN(int) vusbUrbPoolInit(PVUSBURBPOOL pUrbPool); -
trunk/src/VBox/Devices/USB/VUSBUrb.cpp
r59738 r59775 1122 1122 default: 1123 1123 pEndPtDesc = pDev->aPipes[pUrb->EndPt].out; 1124 pPipe = &pDev->aPipes[pUrb->EndPt]; 1124 1125 break; 1125 1126 } … … 1156 1157 1157 1158 #ifdef VBOX_WITH_USB 1158 if (pPipe && pPipe->h ReadAhead)1159 { 1160 rc = vusb UrbSubmitBufferedRead(pUrb, pPipe->hReadAhead);1159 if (pPipe && pPipe->hBuffer) 1160 { 1161 rc = vusbBufferedPipeSubmitUrb(pPipe->hBuffer, pUrb); 1161 1162 return rc; 1162 1163 } … … 1307 1308 #ifdef VBOX_WITH_USB 1308 1309 // Read-ahead URBs are handled differently 1309 if (pUrb->pVUsb->pv ReadAhead)1310 vusb UrbCompletionReadAhead(pUrb);1310 if (pUrb->pVUsb->pvBuffered) 1311 vusbBufferedPipeCompleteUrb(pUrb); 1311 1312 else 1312 1313 #endif -
trunk/src/VBox/Devices/USB/VUSBUrbPool.cpp
r59737 r59775 197 197 pUrb->pVUsb->pCtrlUrb = NULL; 198 198 pUrb->pVUsb->u64SubmitTS = 0; 199 pUrb->pVUsb->pv ReadAhead= NULL;199 pUrb->pVUsb->pvBuffered = NULL; 200 200 pUrb->Dev.pvPrivate = NULL; 201 201 pUrb->Dev.pNext = NULL;
Note:
See TracChangeset
for help on using the changeset viewer.