VirtualBox

Changeset 59775 in vbox for trunk/src/VBox/Devices/USB


Ignore:
Timestamp:
Feb 22, 2016 1:58:44 PM (9 years ago)
Author:
vboxsync
Message:

VUSB: Remove unused read ahead buffering code and replace with new implementation which in the end will work in both directions (only out implemented so far)

Location:
trunk/src/VBox/Devices/USB
Files:
5 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp

    r59737 r59775  
    360360
    361361/**
    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 */
     364static PVUSBURB vusbRhNewUrb(PVUSBROOTHUB pRh, uint8_t DstAddress, PVUSBDEV pDev, VUSBXFERTYPE enmType,
     365                             VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag)
    366366{
    367367    PVUSBURBPOOL pUrbPool = &pRh->Hub.Dev.UrbPool;
  • trunk/src/VBox/Devices/USB/VUSBBufferedPipe.cpp

    r59774 r59775  
    11/* $Id$ */
    22/** @file
    3  * Virtual USB - Read-ahead buffering for periodic endpoints.
     3 * Virtual USB - Buffering for isochronous in/outpipes.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2015 Oracle Corporation
     7 * Copyright (C) 2006-2016 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2121*********************************************************************************************************************************/
    2222#define LOG_GROUP LOG_GROUP_DRV_VUSB
    23 #include <VBox/vmm/pdm.h>
    24 #include <VBox/vmm/vmapi.h>
    2523#include <VBox/err.h>
    2624#include <VBox/log.h>
    2725#include <iprt/alloc.h>
    28 #include <iprt/time.h>
    29 #include <iprt/thread.h>
    30 #include <iprt/semaphore.h>
     26#include <iprt/assert.h>
    3127#include <iprt/string.h>
    32 #include <iprt/assert.h>
    33 #include <iprt/asm.h>
     28#include <iprt/path.h>
    3429#include <iprt/critsect.h>
     30#include <iprt/circbuf.h>
    3531#include "VUSBInternal.h"
    3632
     
    4137
    4238/**
    43  * VUSB Readahead instance data.
    44  */
    45 typedef struct VUSBREADAHEADINT
     39 * Copy of the isoc packet descriptors.
     40 */
     41typedef 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. */
     51typedef VUSBISOCDESC *PVUSBISOCDESC;
     52
     53/**
     54 * Buffered pipe state.
     55 */
     56typedef 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. */
     72typedef VUSBBUFFEREDPIPESTATE *PVUSBBUFFEREDPIPESTATE;
     73
     74/**
     75 * VUSB buffered pipe instance data.
     76 */
     77typedef struct VUSBBUFFEREDPIPEINT
    4678{
    4779    /** Pointer to the device which the thread is for. */
    48     PVUSBDEV            pDev;
     80    PVUSBDEV              pDev;
    4981    /** 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;
    70124
    71125
     
    74128*********************************************************************************************************************************/
    75129
    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 */
     134static 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 */
     163DECLINLINE(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 */
     184static PVUSBURB vusbBufferedPipeNewIsocUrb(PVUSBBUFFEREDPIPEINT pThis, PVUSBISOCDESC pIsocDesc)
     185{
     186    PVUSBURB pUrb;
    101187
    102188    /*
    103189     * Allocate and initialize the URB.
    104190     */
    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);
    113195    if (!pUrb)
    114196        /* not much we can do here... */
    115197        return NULL;
    116198
    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++)
    126234    {
    127235        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 */
     250static 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)
    130259        {
    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);
    134266        }
    135267        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 */
     284static 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)
    182290    {
    183291        /* High-speed endpoint */
    184292        Assert((pDesc->wMaxPacketSize & 0x1fff) == pDesc->wMaxPacketSize);
    185293        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)
    191299    {
    192300        /* Full- or low-speed endpoint */
    193301        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 */
     335DECLHIDDEN(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 */
     371DECLHIDDEN(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)
    207392        {
    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;
    214418            }
    215419
    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))
    222421            {
    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
     453DECLHIDDEN(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                }
    228537            }
    229538            else
    230                 ASMAtomicIncU32(&pThis->cSubmitted);
     539                rc = VERR_NO_MEMORY;
    231540        }
     541
     542        RTMemFree(pThis);
     543    }
     544    else
     545        rc = VERR_NO_MEMORY;
     546
     547    return rc;
     548}
     549
     550
     551DECLHIDDEN(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);
    232570        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  
    137137        Log(("vusb: map input pipe on address %u\n", i8Addr));
    138138        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 #endif
    148139    }
    149140    else
     
    151142        Log(("vusb: map output pipe on address %u\n", i8Addr));
    152143        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
    153156    }
    154157
     
    179182        pPipe->in = NULL;
    180183
    181         /* If there was a read-ahead thread associated with this endpoint, tell it to go away. */
    182         if (pPipe->hReadAhead)
     184        /* Terminate the pipe buffer if created. */
     185        if (pPipe->hBuffer)
    183186        {
    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;
    187189        }
    188190    }
     
    191193        Log(("vusb: unmap OUT pipe from address %u (%#x)\n", EndPt, pEndPtDesc->Core.bEndpointAddress));
    192194        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        }
    193202    }
    194203
     
    228237    pPipe->pCtrl = NULL;
    229238
    230     if (pPipe->hReadAhead)
    231     {
    232         vusbReadAheadStop(pPipe->hReadAhead);
    233         pPipe->hReadAhead = NULL;
     239    if (pPipe->hBuffer)
     240    {
     241        vusbBufferedPipeDestroy(pPipe->hBuffer);
     242        pPipe->hBuffer = NULL;
    234243    }
    235244
     
    11331142 *                      any URBs which isn't reaped.
    11341143 */
    1135 static void vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching)
     1144DECLHIDDEN(void) vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching)
    11361145{
    11371146    int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbDevCancelAllUrbsWorker, 2, pDev, fDetaching);
  • trunk/src/VBox/Devices/USB/VUSBInternal.h

    r59738 r59775  
    2828#include <VBox/vusb.h>
    2929#include <VBox/vmm/stam.h>
     30#include <VBox/vmm/pdm.h>
     31#include <VBox/vmm/vmapi.h>
    3032#include <VBox/vmm/pdmusb.h>
    3133#include <iprt/asm.h>
    3234#include <iprt/assert.h>
    3335#include <iprt/req.h>
     36#include <iprt/asm.h>
    3437#include <iprt/list.h>
    3538
     
    9396    /** Submit timestamp. (logging only) */
    9497    uint64_t        u64SubmitTS;
    95     /** Opaque data holder when this is a read-ahead URB. */
    96     void            *pvReadAhead;
     98    /** Opaque data holder when this is an URB from a buffered pipe. */
     99    void            *pvBuffered;
    97100} VUSBURBVUSBINT;
    98101
     
    144147void vusbMsgResetExtraData(PVUSBCTRLEXTRA pExtra);
    145148
    146 /** Opaque VUSB read ahead buffer management handle. */
    147 typedef struct VUSBREADAHEADINT *VUSBREADAHEAD;
     149/** Opaque VUSB buffered pipe management handle. */
     150typedef struct VUSBBUFFEREDPIPEINT *VUSBBUFFEREDPIPE;
     151/** Pointer to a VUSB buffered pipe handle. */
     152typedef VUSBBUFFEREDPIPE *PVUSBBUFFEREDPIPE;
    148153
    149154/**
     
    160165    /** Count of active async transfers. */
    161166    volatile uint32_t   async;
    162     /** Read ahead handle. */
    163     VUSBREADAHEAD       hReadAhead;
     167    /** Pipe buffer - only valid for isochronous endpoints. */
     168    VUSBBUFFEREDPIPE    hBuffer;
    164169} VUSBPIPE;
    165170/** Pointer to a VUSB pipe structure. */
     
    490495int vusbDevUrbIoThreadCreate(PVUSBDEV pDev);
    491496int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev);
     497DECLHIDDEN(void) vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching);
    492498DECLHIDDEN(int) vusbDevIoThreadExecV(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args);
    493499DECLHIDDEN(int) vusbDevIoThreadExec(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...);
     
    495501DECLHIDDEN(int) vusbUrbCancelWorker(PVUSBURB pUrb, CANCELMODE enmMode);
    496502
    497 void vusbUrbCompletionReadAhead(PVUSBURB pUrb);
    498 VUSBREADAHEAD vusbReadAheadStart(PVUSBDEV pDev, PVUSBPIPE pPipe);
    499 void vusbReadAheadStop(VUSBREADAHEAD hReadAhead);
    500503int  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 */
     511DECLHIDDEN(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 */
     526DECLHIDDEN(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 */
     536DECLHIDDEN(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 */
     545DECLHIDDEN(int)  vusbBufferedPipeSubmitUrb(VUSBBUFFEREDPIPE hBuffer, PVUSBURB pUrb);
    504546
    505547/**
     
    508550 * @returns VBox status code.
    509551 * @param   pUrbPool    The URB pool to initialize.
    510 
    511552 */
    512553DECLHIDDEN(int) vusbUrbPoolInit(PVUSBURBPOOL pUrbPool);
  • trunk/src/VBox/Devices/USB/VUSBUrb.cpp

    r59738 r59775  
    11221122        default:
    11231123            pEndPtDesc = pDev->aPipes[pUrb->EndPt].out;
     1124            pPipe = &pDev->aPipes[pUrb->EndPt];
    11241125            break;
    11251126    }
     
    11561157
    11571158#ifdef VBOX_WITH_USB
    1158     if (pPipe && pPipe->hReadAhead)
    1159     {
    1160         rc = vusbUrbSubmitBufferedRead(pUrb, pPipe->hReadAhead);
     1159    if (pPipe && pPipe->hBuffer)
     1160    {
     1161        rc = vusbBufferedPipeSubmitUrb(pPipe->hBuffer, pUrb);
    11611162        return rc;
    11621163    }
     
    13071308#ifdef VBOX_WITH_USB
    13081309    // Read-ahead URBs are handled differently
    1309     if (pUrb->pVUsb->pvReadAhead)
    1310         vusbUrbCompletionReadAhead(pUrb);
     1310    if (pUrb->pVUsb->pvBuffered)
     1311        vusbBufferedPipeCompleteUrb(pUrb);
    13111312    else
    13121313#endif
  • trunk/src/VBox/Devices/USB/VUSBUrbPool.cpp

    r59737 r59775  
    197197    pUrb->pVUsb->pCtrlUrb        = NULL;
    198198    pUrb->pVUsb->u64SubmitTS     = 0;
    199     pUrb->pVUsb->pvReadAhead     = NULL;
     199    pUrb->pVUsb->pvBuffered      = NULL;
    200200    pUrb->Dev.pvPrivate          = NULL;
    201201    pUrb->Dev.pNext              = NULL;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette