ccGamepadManager::~ccGamepadManager()
{
	releaseDevice();

	if (m_menu)
	{
		delete m_menu;
	}
}
Esempio n. 2
0
int main(int argc, char *argv[]){
  if (argc != 2){
    printHelp("flash");
    return 0;
  }
  struct device dev;
  getDevice(argv[1], &dev);
  readTests(&dev);
  printf("\n");
  writeTests(&dev);
  releaseDevice(&dev);
  return 0;
}
Esempio n. 3
0
int initVKeyboardDevice(char* uinputPath) {
    int i;
    int deviceHandle = -1;
    struct uinput_user_dev uidev;

    deviceHandle = open(uinputPath, O_WRONLY | O_NONBLOCK | O_NDELAY);

    // if a valid handle could be determined, try to enable key events
    if(deviceHandle > 0) {
        if(ioctl(deviceHandle, UI_SET_EVBIT, EV_KEY) < 0) {
            if(releaseDevice(deviceHandle) < 0) {
                exit(EXIT_FAILURE);
            } else {
                deviceHandle = -1;
            }
        } else {
			// register key events - only values from 1 to 255 are valid
            for(i=1; i<256; i++) {
                ioctl(deviceHandle, UI_SET_KEYBIT, i);
            }

            memset(&uidev, 0, sizeof (uidev));
            snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput_vkeyboard");
            uidev.id.bustype = BUS_USB;
            uidev.id.vendor  = 0x4711;
            uidev.id.product = 0x0815;
            uidev.id.version = 1;

            if (write(deviceHandle, &uidev, sizeof (uidev)) < 0) {
                exit(EXIT_FAILURE);
            }

            if (ioctl(deviceHandle, UI_DEV_CREATE) < 0) {
                exit(EXIT_FAILURE);
            }

            sleep(2);

        }
    }

    return deviceHandle;
}
static DECLCALLBACK(void) iface_CancelURB(PREMOTEUSBDEVICE pDevice, PREMOTEUSBQURB pRemoteURB)
{
    RemoteUSBBackend *pThis = pDevice->pOwner;

    VRDE_USB_REQ_CANCEL_URB_PARM parm;

    parm.code = VRDE_USB_REQ_CANCEL_URB;
    parm.id = pDevice->id;
    parm.handle = pRemoteURB->u32Handle;

    pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));

    requestDevice(pDevice);

    /* Remove this urb from the queue. It is safe because if
     * client will return the URB, it will be just ignored
     * in reapURB.
     */
    if (pRemoteURB->prev)
    {
        pRemoteURB->prev->next = pRemoteURB->next;
    }
    else
    {
        pDevice->pHeadQURBs = pRemoteURB->next;
    }

    if (pRemoteURB->next)
    {
        pRemoteURB->next->prev = pRemoteURB->prev;
    }
    else
    {
        pDevice->pTailQURBs = pRemoteURB->prev;
    }

    qurbFree(pRemoteURB);

    releaseDevice(pDevice);

    return;
}
Esempio n. 5
0
static unsigned int releaseDevices(deviceList *devList)
{
    usbDeviceList *list = (usbDeviceList*)devList;
    unsigned int count = list->deviceList.count;
    usbDevice *head, *prev = NULL;

    /* loop, but if head does not change then sleep a bit */
    while((head = (usbDevice*)firstItem(&list->deviceList)) != NULL)
    {
        if (head != prev)
            releaseDevice(&head->info);
        else
            sleep(100);
        prev = head;
    }

    /* illegal to access the list after this call */
    free(list);
    return count;
}
Esempio n. 6
0
int __cdecl wmain(void) {
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr)) {
        LOG(L"Failed CoInitializeEx: hr = 0x%08x", hr);
        return __LINE__;
    }
    CoUninitializeOnExit cuoe;

    // get active devices
    IMMDeviceEnumerator *pEnum = NULL;
    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
        (void**)&pEnum
    );
    if (FAILED(hr)) {
        LOG(L"Couldn't get device enumerator: hr = 0x%08x", hr);
        return __LINE__;
    }
    ReleaseOnExit releaseEnum(pEnum);
    
    IMMDeviceCollection *pDeviceCollection = NULL;
    hr = pEnum->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &pDeviceCollection);
    if (FAILED(hr)) {
        LOG(L"Couldn't get device collection: hr = 0x%08x", hr);
        return __LINE__;
    }
    ReleaseOnExit releaseDeviceCollection(pDeviceCollection);
    
    UINT nDevices = 0;
    hr = pDeviceCollection->GetCount(&nDevices);
    if (FAILED(hr)) {
        LOG(L"Couldn't get device collection count: hr = 0x%08x", hr);
        return __LINE__;
    }
    
    for (UINT i = 0; i < nDevices; i++) {
        IMMDevice *pDevice = NULL;
        hr = pDeviceCollection->Item(i, &pDevice);
        if (FAILED(hr)) {
            LOG(L"Couldn't get device: hr = 0x%08x", hr);
            return __LINE__;
        }
        ReleaseOnExit releaseDevice(pDevice);

        IMMEndpoint *pEndpoint = NULL;
        hr = pDevice->QueryInterface(IID_PPV_ARGS(&pEndpoint));
        if (FAILED(hr)) {
            LOG(L"Couldn't get endpoint: hr = 0x%08x", hr);
            return __LINE__;
        }
        ReleaseOnExit releaseEndpoint(pEndpoint);

        EDataFlow eDirection = eAll;
        hr = pEndpoint->GetDataFlow(&eDirection);
        if (FAILED(hr)) {
            LOG(L"Couldn't get data flow: hr = 0x%08x", hr);
            return __LINE__;
        }

        LOG(L"%s endpoint", StringFromDataFlow(eDirection));

        IPropertyStore *pPropertyStore = NULL;
        hr = pDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
        if (FAILED(hr)) {
            LOG(L"Couldn't get property store: hr = 0x%08x", hr);
            return __LINE__;
        }
        ReleaseOnExit releasePropertyStore(pPropertyStore);

        // get the long name property
        PROPVARIANT pv; PropVariantInit(&pv);
        hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
        if (FAILED(hr)) {
            LOG(L"Couldn't get friendly name: hr = 0x%08x", hr);
            return hr;
        }
        PropVariantClearOnExit clearPropVariant(&pv);

        LOG(L"Name: %s", pv.pwszVal);

        // get the ID
        WCHAR *wszId = NULL;
        hr = pDevice->GetId(&wszId);
        if (FAILED(hr)) {
            LOG(L"Couldn't get device ID: hr = 0x%08x", hr);
            return __LINE__;
        }
        CoTaskMemFreeOnExit releaseId(wszId);

        LOG(L"Endpoint ID: %s", wszId);

        // get device topology object for that endpoint
        IDeviceTopology *pDT = NULL;
        hr = pDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, (void**)&pDT);
        if (FAILED(hr)) {
            LOG(L"Couldn't get device topology object: hr = 0x%08x", hr);
            return __LINE__;
        }
        ReleaseOnExit releaseDT(pDT);

        // get the single connector for that endpoint
        IConnector *pConnector = NULL;
        hr = pDT->GetConnector(0, &pConnector);
        if (FAILED(hr)) {
            LOG(L"Couldn't get the connector on the endpoint: hr = 0x%08x", hr);
            return __LINE__;
        }
        ReleaseOnExit releaseConnector(pConnector);

        // QI on the device's connector for IPart
        IPart *pPart = NULL;
        hr = pConnector->QueryInterface(IID_PPV_ARGS(&pPart));
        if (FAILED(hr)) {
            LOG(L"Couldn't get the part: hr = 0x%08x", hr);
            return __LINE__;
        }
        ReleaseOnExit releasePart(pPart);

        // all the real work is done in this function
        // follow the connector from this trivial endpoint topology
        // over to the rest of the topologies
        hr = WalkTreeFromPart(pPart, eDirection, true, 1);
        if (FAILED(hr)) {
            LOG(L"Couldn't walk the tree: hr = 0x%08x", hr);
            return __LINE__;
        }

        LOG(L"");
    }

    return 0;
}
/* The function checks the URB queue for completed URBs. Also if the client
 * has requested URB polling, the function will send URB poll requests.
 */
static DECLCALLBACK(int) iface_ReapURB(PREMOTEUSBDEVICE pDevice, uint32_t u32Millies, void **ppvURB,
                                       uint32_t *pu32Len, uint32_t *pu32Err)
{
    int rc = VINF_SUCCESS;

    LogFlow(("RemoteUSBBackend::iface_ReapURB %d ms\n", u32Millies));

    if (pDevice->fFailed)
    {
        return VERR_VUSB_DEVICE_NOT_ATTACHED;
    }

    RemoteUSBBackend *pThis = pDevice->pOwner;

    /* Wait for transaction completion. */
    uint64_t u64StartTime = RTTimeMilliTS();

    if (pThis->pollingEnabledURB())
    {
        VRDE_USB_REQ_REAP_URB_PARM parm;

        parm.code = VRDE_USB_REQ_REAP_URB;

        pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
    }

    REMOTEUSBQURB *qurb = NULL;

    for (;;)
    {
        uint32_t u32ClientId;

        if (ASMAtomicXchgBool(&pDevice->fWokenUp, false))
            break;

        /* Scan queued URBs, look for completed. */
        requestDevice(pDevice);

        u32ClientId = pDevice->u32ClientId;

        qurb = pDevice->pHeadQURBs;

        while (qurb)
        {
            if (qurb->fCompleted)
            {
                /* Remove this completed urb from the queue. */
                if (qurb->prev)
                {
                    qurb->prev->next = qurb->next;
                }
                else
                {
                    pDevice->pHeadQURBs = qurb->next;
                }

                if (qurb->next)
                {
                    qurb->next->prev = qurb->prev;
                }
                else
                {
                    pDevice->pTailQURBs = qurb->prev;
                }

                qurb->next = NULL;
                qurb->prev = NULL;

                break;
            }

            qurb = qurb->next;
        }

        releaseDevice(pDevice);

        if (   qurb
            || !pDevice->pHeadQURBs
            || u32Millies == 0
            || pDevice->fFailed
            || (RTTimeMilliTS() - u64StartTime >= (uint64_t)u32Millies))
        {
            /* Got an URB or do not have to wait for an URB. */
            break;
        }

        LogFlow(("RemoteUSBBackend::iface_ReapURB iteration.\n"));

        RTThreadSleep(10);

        if (pThis->pollingEnabledURB())
        {
            VRDE_USB_REQ_REAP_URB_PARM parm;

            parm.code = VRDE_USB_REQ_REAP_URB;

            pThis->VRDPServer()->SendUSBRequest(u32ClientId, &parm, sizeof(parm));
        }
    }

    LogFlow(("RemoteUSBBackend::iface_ReapURB completed in %lld ms, qurb = %p\n", RTTimeMilliTS () - u64StartTime, qurb));

    if (!qurb)
    {
        *ppvURB = NULL;
        *pu32Len = 0;
        *pu32Err = VUSBSTATUS_OK;
    }
    else
    {
        *ppvURB = qurb->pvURB;
        *pu32Len = qurb->u32Len;
        *pu32Err = qurb->u32Err;

#ifdef LOG_ENABLED
        Log(("URB len = %d, data = %p\n", qurb->u32Len, qurb->pvURB));
        if (qurb->u32Len)
        {
            Log(("Received URB content:\n%.*Rhxd\n", qurb->u32Len, qurb->pvData));
        }
#endif

        qurbFree(qurb);
    }

    return rc;
}
static DECLCALLBACK(int) iface_QueueURB(PREMOTEUSBDEVICE pDevice, uint8_t u8Type, uint8_t u8Ep, uint8_t u8Direction,
                                        uint32_t u32Len, void *pvData, void *pvURB, PREMOTEUSBQURB *ppRemoteURB)
{
    int rc = VINF_SUCCESS;

#ifdef DEBUG_sunlover
    LogFlow(("RemoteUSBBackend::iface_QueueURB: u8Type = %d, u8Ep = %d, u8Direction = %d, data\n%.*Rhxd\n",
             u8Type, u8Ep, u8Direction, u32Len, pvData));
#endif /* DEBUG_sunlover */

    if (pDevice->fFailed)
    {
        return VERR_VUSB_DEVICE_NOT_ATTACHED;
    }

    RemoteUSBBackend *pThis = pDevice->pOwner;

    VRDE_USB_REQ_QUEUE_URB_PARM parm;
    uint32_t u32Handle = 0;
    uint32_t u32DataLen = 0;

    REMOTEUSBQURB *qurb = qurbAlloc(pDevice);

    if (qurb == NULL)
    {
        rc = VERR_NO_MEMORY;
        goto l_leave;
    }

    /*
     * Compute length of data which need to be transferred to the client.
     */
    switch(u8Direction)
    {
        case VUSB_DIRECTION_IN:
        {
            if (u8Type == VUSBXFERTYPE_MSG)
            {
                u32DataLen = 8; /* 8 byte header. */
                // u32DataLen = u32Len; // @todo do messages need all information?
            }
        } break;

        case VUSB_DIRECTION_OUT:
        {
            u32DataLen = u32Len;
        } break;

        default:
        {
            AssertFailed();
            rc = VERR_INVALID_PARAMETER;
            goto l_leave;
        }
    }

    parm.code = VRDE_USB_REQ_QUEUE_URB;
    parm.id = pDevice->id;

    u32Handle = pDevice->hURB++;
    if (u32Handle == 0)
    {
        u32Handle = pDevice->hURB++;
    }

    LogFlow(("RemoteUSBBackend::iface_QueueURB: handle = %d\n", u32Handle));

    parm.handle = u32Handle;

    switch(u8Type)
    {
        case VUSBXFERTYPE_CTRL: parm.type = VRDE_USB_TRANSFER_TYPE_CTRL; break;
        case VUSBXFERTYPE_ISOC: parm.type = VRDE_USB_TRANSFER_TYPE_ISOC; break;
        case VUSBXFERTYPE_BULK: parm.type = VRDE_USB_TRANSFER_TYPE_BULK; break;
        case VUSBXFERTYPE_INTR: parm.type = VRDE_USB_TRANSFER_TYPE_INTR; break;
        case VUSBXFERTYPE_MSG:  parm.type = VRDE_USB_TRANSFER_TYPE_MSG;  break;
        default: AssertFailed(); rc = VERR_INVALID_PARAMETER; goto l_leave;
    }

    parm.ep = u8Ep;

    switch(u8Direction)
    {
        case VUSB_DIRECTION_SETUP: AssertFailed(); parm.direction = VRDE_USB_DIRECTION_SETUP; break;
        case VUSB_DIRECTION_IN:    parm.direction = VRDE_USB_DIRECTION_IN;    break;
        case VUSB_DIRECTION_OUT:   parm.direction = VRDE_USB_DIRECTION_OUT;   break;
        default: AssertFailed(); rc = VERR_INVALID_PARAMETER; goto l_leave;
    }

    parm.urblen = u32Len;
    parm.datalen = u32DataLen;

    if (u32DataLen)
    {
        parm.data = pvData;
    }

    requestDevice (pDevice);

    /* Add at tail of queued urb list. */
    qurb->next       = NULL;
    qurb->prev       = pDevice->pTailQURBs;
    qurb->u32Err     = VRDE_USB_XFER_OK;
    qurb->u32Len     = u32Len;
    qurb->pvData     = pvData;
    qurb->pvURB      = pvURB;
    qurb->u32Handle  = u32Handle;
    qurb->fCompleted = false;
    qurb->fInput     = (u8Direction == VUSB_DIRECTION_IN);
    qurb->u32TransferredLen = 0;

    if (pDevice->pTailQURBs)
    {
        Assert(pDevice->pTailQURBs->next == NULL);
        pDevice->pTailQURBs->next = qurb;
    }
    else
    {
        /* This is the first URB to be added. */
        Assert(pDevice->pHeadQURBs == NULL);
        pDevice->pHeadQURBs = qurb;
    }

    pDevice->pTailQURBs = qurb;

    releaseDevice(pDevice);

    *ppRemoteURB = qurb;

    pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));

l_leave:
    if (RT_FAILURE(rc))
    {
        qurbFree(qurb);
    }

    return rc;
}
int RemoteUSBBackend::reapURB(const void *pvBody, uint32_t cbBody)
{
    int rc = VINF_SUCCESS;

    LogFlow(("RemoteUSBBackend::reapURB: pvBody = %p, cbBody = %d\n", pvBody, cbBody));

    VRDEUSBREQREAPURBBODY *pBody = (VRDEUSBREQREAPURBBODY *)pvBody;

    while (cbBody >= sizeof(VRDEUSBREQREAPURBBODY))
    {
        Log(("RemoteUSBBackend::reapURB: id = %d,  flags = %02X, error = %d, handle %d, len = %d.\n",
             pBody->id, pBody->flags, pBody->error, pBody->handle, pBody->len));

        uint8_t fu8ReapValidFlags;

        if (mClientVersion == VRDE_USB_VERSION_1 || mClientVersion == VRDE_USB_VERSION_2)
        {
            fu8ReapValidFlags = VRDE_USB_REAP_VALID_FLAGS;
        }
        else
        {
            fu8ReapValidFlags = VRDE_USB_REAP_VALID_FLAGS_3;
        }

        /* Verify client's data. */
        if (   (pBody->flags & ~fu8ReapValidFlags) != 0
            || sizeof(VRDEUSBREQREAPURBBODY) > cbBody
            || pBody->handle == 0)
        {
            LogFlow(("RemoteUSBBackend::reapURB: WARNING: invalid reply data. Skipping the reply.\n"));
            rc = VERR_INVALID_PARAMETER;
            break;
        }

        PREMOTEUSBDEVICE pDevice = deviceFromId(pBody->id);

        if (!pDevice)
        {
            LogFlow(("RemoteUSBBackend::reapURB: WARNING: invalid device id. Skipping the reply.\n"));
            rc = VERR_INVALID_PARAMETER;
            break;
        }

        uint32_t cbBodyData = 0; /* Data contained in the URB body structure for input URBs. */

        requestDevice(pDevice);

        /* Search the queued URB for given handle. */
        REMOTEUSBQURB *qurb = pDevice->pHeadQURBs;

        while (qurb && qurb->u32Handle != pBody->handle)
        {
            LogFlow(("RemoteUSBBackend::reapURB: searching: %p handle = %d.\n", qurb, qurb->u32Handle));
            qurb = qurb->next;
        }

        if (!qurb)
        {
            LogFlow(("RemoteUSBBackend::reapURB: Queued URB not found, probably already canceled. Skipping the URB.\n"));
        }
        else
        {
            LogFlow(("RemoteUSBBackend::reapURB: qurb = %p\n", qurb));

            /* Update the URB error field. */
            if (mClientVersion == VRDE_USB_VERSION_1)
            {
                switch(pBody->error)
                {
                    case VRDE_USB_XFER_OK:    qurb->u32Err = VUSBSTATUS_OK;    break;
                    case VRDE_USB_XFER_STALL: qurb->u32Err = VUSBSTATUS_STALL; break;
                    case VRDE_USB_XFER_DNR:   qurb->u32Err = VUSBSTATUS_DNR;   break;
                    case VRDE_USB_XFER_CRC:   qurb->u32Err = VUSBSTATUS_CRC;   break;
                    default: Log(("RemoteUSBBackend::reapURB: Invalid error %d\n", pBody->error));
                                              qurb->u32Err = VUSBSTATUS_DNR;   break;
                }
            }
            else if (   mClientVersion == VRDE_USB_VERSION_2
                     || mClientVersion == VRDE_USB_VERSION_3)
            {
                switch(pBody->error)
                {
                    case VRDE_USB_XFER_OK:    qurb->u32Err = VUSBSTATUS_OK;            break;
                    case VRDE_USB_XFER_STALL: qurb->u32Err = VUSBSTATUS_STALL;         break;
                    case VRDE_USB_XFER_DNR:   qurb->u32Err = VUSBSTATUS_DNR;           break;
                    case VRDE_USB_XFER_CRC:   qurb->u32Err = VUSBSTATUS_CRC;           break;
                    case VRDE_USB_XFER_DO:    qurb->u32Err = VUSBSTATUS_DATA_OVERRUN;  break;
                    case VRDE_USB_XFER_DU:    qurb->u32Err = VUSBSTATUS_DATA_UNDERRUN; break;

                    /* Unmapped errors. */
                    case VRDE_USB_XFER_BS:
                    case VRDE_USB_XFER_DTM:
                    case VRDE_USB_XFER_PCF:
                    case VRDE_USB_XFER_UPID:
                    case VRDE_USB_XFER_BO:
                    case VRDE_USB_XFER_BU:
                    case VRDE_USB_XFER_ERR:
                    default: Log(("RemoteUSBBackend::reapURB: Invalid error %d\n", pBody->error));
                                              qurb->u32Err = VUSBSTATUS_DNR;   break;
                }
            }
            else
            {
                qurb->u32Err = VUSBSTATUS_DNR;
            }

            /* Get the URB data. */
            bool fURBCompleted = true;

            if (qurb->fInput)
            {
                cbBodyData = pBody->len; /* VRDE_USB_DIRECTION_IN URBs include some data. */
            }

            if (   qurb->u32Err == VUSBSTATUS_OK
                && qurb->fInput)
            {
                LogFlow(("RemoteUSBBackend::reapURB: copying data %d bytes\n", pBody->len));

                uint32_t u32DataLen = qurb->u32TransferredLen + pBody->len;

                if (u32DataLen > qurb->u32Len)
                {
                    /* Received more data than expected for this URB. If there more fragments follow,
                     * they will be discarded because the URB handle will not be valid anymore.
                     */
                    qurb->u32Err = VUSBSTATUS_DNR;
                }
                else
                {
                    memcpy ((uint8_t *)qurb->pvData + qurb->u32TransferredLen, &pBody[1], pBody->len);
                }

                if (   qurb->u32Err == VUSBSTATUS_OK
                    && (pBody->flags & VRDE_USB_REAP_FLAG_FRAGMENT) != 0)
                {
                    /* If the client sends fragmented packets, accumulate the URB data. */
                    fURBCompleted = false;
                }
            }

            qurb->u32TransferredLen += pBody->len; /* Update the value for all URBs. */

            if (fURBCompleted)
            {
                /* Move the URB near the head of URB list, so that iface_ReapURB can
                 * find it faster. Note that the order of completion must be preserved!
                 */
                if (qurb->prev)
                {
                    /* The URB is not in the head. Unlink it from its current position. */
                    qurb->prev->next = qurb->next;

                    if (qurb->next)
                    {
                        qurb->next->prev = qurb->prev;
                    }
                    else
                    {
                        pDevice->pTailQURBs = qurb->prev;
                    }

                    /* And insert it to its new place. */
                    if (pDevice->pHeadQURBs->fCompleted)
                    {
                        /* At least one other completed URB; insert after the
                         * last completed URB.
                         */
                        REMOTEUSBQURB *prev_qurb = pDevice->pHeadQURBs;
                        while (prev_qurb->next && prev_qurb->next->fCompleted)
                            prev_qurb = prev_qurb->next;

                        qurb->next = prev_qurb->next;
                        qurb->prev = prev_qurb;

                        if (prev_qurb->next)
                            prev_qurb->next->prev = qurb;
                        else
                            pDevice->pTailQURBs = qurb;
                        prev_qurb->next = qurb;
                    }
                    else
                    {
                        /* No other completed URBs; insert at head. */
                        qurb->next = pDevice->pHeadQURBs;
                        qurb->prev = NULL;

                        pDevice->pHeadQURBs->prev = qurb;
                        pDevice->pHeadQURBs = qurb;
                    }
                }

                qurb->u32Len = qurb->u32TransferredLen; /* Update the final length. */
                qurb->fCompleted = true;
            }
        }

        releaseDevice (pDevice);

        if (pBody->flags & VRDE_USB_REAP_FLAG_LAST)
        {
            break;
        }

        /* There is probably a further URB body. */
        uint32_t cbBodySize = sizeof (VRDEUSBREQREAPURBBODY) + cbBodyData;

        if (cbBodySize > cbBody)
        {
            rc = VERR_INVALID_PARAMETER;
            break;
        }

        pBody = (VRDEUSBREQREAPURBBODY *)((uint8_t *)pBody + cbBodySize);
        cbBody -= cbBodySize;
    }

    LogFlow(("RemoteUSBBackend::reapURB: returns %Rrc\n", rc));

    return rc;
}