USBProxyDevice.cpp revision 3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6c
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/* $Id$ */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/** @file
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USBProxy - USB device proxy.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Copyright (C) 2006-2007 Oracle Corporation
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * available from http://www.virtualbox.org. This file is free software;
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * General Public License (GPL) as published by the Free Software
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/*******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync* Header Files *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync*******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include <VBox/usb.h>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include <VBox/usbfilter.h>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include <VBox/pdm.h>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include <VBox/err.h>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include <iprt/alloc.h>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include <iprt/string.h>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include <VBox/log.h>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include <iprt/assert.h>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include "USBProxyDevice.h"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include "VUSBInternal.h"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include "Builtins.h"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/*******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync* Global Variables *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync*******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/** A dummy name used early during the construction phase to avoid log crashes. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic char g_szDummyName[] = "proxy xxxx:yyyy";
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/* Synchronously obtain a standard USB descriptor for a device, used in order
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to grab configuration descriptors when we first add the device
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic void *GetStdDescSync(PUSBPROXYDEV pProxyDev, uint8_t iDescType, uint8_t iIdx, uint16_t LangId, uint16_t cbHint)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("GetStdDescSync: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (;;)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Setup a MSG URB, queue and reap it.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync VUSBURB Urb;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertCompile(RT_SIZEOFMEMB(VUSBURB, abData) >= _4K);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.u32Magic = VUSBURB_MAGIC;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.enmState = VUSBURBSTATE_IN_FLIGHT;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.pszDesc = (char*)"URB sync";
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memset(&Urb.VUsb, 0, sizeof(Urb.VUsb));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memset(&Urb.Hci, 0, sizeof(Urb.Hci));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.Dev.pvPrivate = NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.Dev.pNext = NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.pUsbIns = pProxyDev->pUsbIns;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.DstAddress = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.EndPt = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.enmType = VUSBXFERTYPE_MSG;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.enmDir = VUSBDIRECTION_IN;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.fShortNotOk = false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.enmStatus = VUSBSTATUS_INVALID;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cbHint = RT_MIN(cbHint, sizeof(Urb.abData) - sizeof(VUSBSETUP));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Urb.cbData = cbHint + sizeof(VUSBSETUP);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBSETUP pSetup = (PVUSBSETUP)Urb.abData;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pSetup->bmRequestType = VUSB_DIR_TO_HOST | VUSB_REQ_STANDARD | VUSB_TO_DEVICE;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pSetup->bRequest = VUSB_REQ_GET_DESCRIPTOR;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pSetup->wValue = (iDescType << 8) | iIdx;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pSetup->wIndex = LangId;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pSetup->wLength = cbHint;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!pProxyDev->pOps->pfnUrbQueue(&Urb))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Don't wait forever, it's just a simple request that should
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return immediately. Since we're executing in the EMT thread
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync it's important not to get stuck here. (Some of the builtin
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync iMac devices may not refuse respond for instance.) */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBURB pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, 10000 /* ms */);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!pUrbReaped)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->pOps->pfnUrbCancel(&Urb);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, RT_INDEFINITE_WAIT);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pUrbReaped != &Urb)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: pfnUrbReap failed, pUrbReaped=%p\n", pUrbReaped));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (Urb.enmStatus != VUSBSTATUS_OK)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: Urb.enmStatus=%d\n", Urb.enmStatus));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Check the length, config descriptors have total_length field
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint8_t *pbDesc = (uint8_t *)(pSetup + 1);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t cbDesc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (iDescType == VUSB_DT_CONFIG)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (Urb.cbData < sizeof(VUSBSETUP) + 4)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: Urb.cbData=%#x (min 4)\n", Urb.cbData));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cbDesc = RT_LE2H_U16(((uint16_t *)pbDesc)[1]);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (Urb.cbData < sizeof(VUSBSETUP) + 1)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: Urb.cbData=%#x (min 1)\n", Urb.cbData));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cbDesc = ((uint8_t *)pbDesc)[0];
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: got Urb.cbData=%u, cbDesc=%u cbHint=%u\n", Urb.cbData, cbDesc, cbHint));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( Urb.cbData == cbHint + sizeof(VUSBSETUP)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && cbDesc > Urb.cbData - sizeof(VUSBSETUP))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cbHint = cbDesc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (cbHint > sizeof(Urb.abData))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertMsgFailed(("cbHint=%u\n", cbHint));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync continue;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Assert(cbDesc <= Urb.cbData - sizeof(VUSBSETUP));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#ifdef LOG_ENABLED
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync vusbUrbTrace(&Urb, "GetStdDescSync", true);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#endif
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Fine, we got everything return a heap duplicate of the descriptor.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return RTMemDup(pbDesc, cbDesc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Frees a descriptor returned by GetStdDescSync().
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic void free_desc(void *pvDesc)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync RTMemFree(pvDesc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Get and a device descriptor and byteswap it appropriately.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic bool usbProxyGetDeviceDesc(PUSBPROXYDEV pProxyDev, PVUSBDESCDEVICE pOut)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Get the descriptor from the device.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCDEVICE pIn = (PVUSBDESCDEVICE)GetStdDescSync(pProxyDev, VUSB_DT_DEVICE, 0, 0, VUSB_DT_DEVICE_MIN_LEN);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!pIn)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyGetDeviceDesc: pProxyDev=%s: GetStdDescSync failed\n", pProxyDev->pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pIn->bLength < VUSB_DT_DEVICE_MIN_LEN)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: pProxyDev=%s: Corrupted device descriptor. bLength=%d\n", pProxyDev->pUsbIns->pszName, pIn->bLength));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Convert it.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bLength = VUSB_DT_DEVICE_MIN_LEN;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bDescriptorType = VUSB_DT_DEVICE;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bcdUSB = RT_LE2H_U16(pIn->bcdUSB);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bDeviceClass = pIn->bDeviceClass;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bDeviceSubClass = pIn->bDeviceSubClass;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bDeviceProtocol = pIn->bDeviceProtocol;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bMaxPacketSize0 = pIn->bMaxPacketSize0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->idVendor = RT_LE2H_U16(pIn->idVendor);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->idProduct = RT_LE2H_U16(pIn->idProduct);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bcdDevice = RT_LE2H_U16(pIn->bcdDevice);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->iManufacturer = pIn->iManufacturer;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->iProduct = pIn->iProduct;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->iSerialNumber = pIn->iSerialNumber;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bNumConfigurations = pIn->bNumConfigurations;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync free_desc(pIn);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return true;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Count the numbers and types of each kind of descriptor that we need to
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * copy out of the config descriptor
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstruct desc_counts
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync size_t num_ed, num_id, num_if;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** bitmap (128 bits) */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t idmap[4];
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync};
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic int count_descriptors(struct desc_counts *cnt, uint8_t *buf, size_t len)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCCONFIG cfg;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint8_t *tmp, *end;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t i, x;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memset(cnt, 0, sizeof(*cnt));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync end = buf + len;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cfg = (PVUSBDESCCONFIG)buf;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( cfg->bLength < VUSB_DT_CONFIG_MIN_LEN )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( cfg->bLength > len )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (tmp = buf + cfg->bLength; ((tmp + 1) < end) && *tmp; tmp += *tmp)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint8_t type;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t ifnum;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCINTERFACE id;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCENDPOINT ed;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync type = *(tmp + 1);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync switch ( type ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case VUSB_DT_INTERFACE:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync id = (PVUSBDESCINTERFACE)tmp;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( id->bLength < VUSB_DT_INTERFACE_MIN_LEN )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cnt->num_id++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ifnum = id->bInterfaceNumber;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cnt->idmap[ifnum >> 6] |= (1 << (ifnum & 0x1f));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case VUSB_DT_ENDPOINT:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ed = (PVUSBDESCENDPOINT)tmp;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( ed->bLength < VUSB_DT_ENDPOINT_MIN_LEN )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cnt->num_ed++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync default:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* count interfaces */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for(i=0; i < RT_ELEMENTS(cnt->idmap); i++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for(x=1; x; x<<=1)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( cnt->idmap[i] & x )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cnt->num_if++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return 1;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/* Setup a vusb_interface structure given some preallocated structures
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to use, (we counted them already)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic int copy_interface(PVUSBINTERFACE pIf, uint8_t ifnum,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCINTERFACEEX *id, PVUSBDESCENDPOINTEX *ed,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint8_t *buf, size_t len)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCINTERFACEEX cur_if = NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t altmap[4] = {0,};
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint8_t *tmp, *end = buf + len;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint8_t alt;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int state;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync size_t num_ep = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync buf += *(uint8_t *)buf;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pIf->cSettings = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pIf->paSettings = NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (tmp = buf, state = 0; ((tmp + 1) < end) && *tmp; tmp += *tmp)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint8_t type;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCINTERFACE ifd;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCENDPOINT epd;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCENDPOINTEX cur_ep;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync type = tmp[1];
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync switch ( type ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case VUSB_DT_INTERFACE:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync state = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ifd = (PVUSBDESCINTERFACE)tmp;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Ignoring this interface */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( ifd->bInterfaceNumber != ifnum )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Check we didnt see this alternate setting already
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * because that will break stuff
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync alt = ifd->bAlternateSetting;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( altmap[alt >> 6] & (1 << (alt & 0x1f)) )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync altmap[alt >> 6] |= (1 << (alt & 0x1f));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cur_if = *id;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync (*id)++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( pIf->cSettings == 0 )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pIf->paSettings = cur_if;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memcpy(cur_if, ifd, sizeof(cur_if->Core));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo copy any additional descriptor bytes into pvMore */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pIf->cSettings++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync state = 1;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync num_ep = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case VUSB_DT_ENDPOINT:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( state == 0 )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync epd = (PVUSBDESCENDPOINT)tmp;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cur_ep = *ed;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync (*ed)++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( num_ep == 0 )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cur_if->paEndpoints = cur_ep;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( num_ep > cur_if->Core.bNumEndpoints )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memcpy(cur_ep, epd, sizeof(cur_ep->Core));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo copy any additional descriptor bytes into pvMore */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cur_ep->Core.wMaxPacketSize = RT_LE2H_U16(cur_ep->Core.wMaxPacketSize);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync num_ep++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync default:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo Here be dragons! Additional descriptors needs copying into pvClass
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * (RTMemDup be your friend). @bugref{2693} */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return 1;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Copy all of a devices config descriptors, this is needed so that the USB
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * core layer knows all about how to map the different functions on to the
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * virtual USB bus.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic bool copy_config(PUSBPROXYDEV pProxyDev, uint8_t idx, PVUSBDESCCONFIGEX out)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCCONFIG cfg;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBINTERFACE pIf;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCINTERFACEEX ifd;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCENDPOINTEX epd;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync struct desc_counts cnt;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync void *descs;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync size_t tot_len;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync size_t cbIface;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t i, x;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync descs = GetStdDescSync(pProxyDev, VUSB_DT_CONFIG, idx, 0, VUSB_DT_CONFIG_MIN_LEN);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( descs == NULL ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("copy_config: GetStdDescSync failed\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cfg = (PVUSBDESCCONFIG)descs;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync tot_len = RT_LE2H_U16(cfg->wTotalLength);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( !count_descriptors(&cnt, (uint8_t *)descs, tot_len) ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("copy_config: count_descriptors failed\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync goto err;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( cfg->bNumInterfaces != cnt.num_if )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: config%u: bNumInterfaces %u != %u\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync idx, cfg->bNumInterfaces, cnt.num_if));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: config%u: %u bytes id=%u ed=%u if=%u\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync idx, tot_len, cnt.num_id, cnt.num_ed, cnt.num_if));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cbIface = cnt.num_if * sizeof(VUSBINTERFACE)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync + cnt.num_id * sizeof(VUSBDESCINTERFACEEX)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync + cnt.num_ed * sizeof(VUSBDESCENDPOINTEX);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->paIfs = (PCVUSBINTERFACE)RTMemAllocZ(cbIface);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( out->paIfs == NULL ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync free_desc(descs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pIf = (PVUSBINTERFACE)out->paIfs;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ifd = (PVUSBDESCINTERFACEEX)&pIf[cnt.num_if];
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync epd = (PVUSBDESCENDPOINTEX)&ifd[cnt.num_id];
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.bLength = cfg->bLength;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.bDescriptorType = cfg->bDescriptorType;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.wTotalLength = 0; /* Auto Calculated */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.bNumInterfaces = (uint8_t)cnt.num_if;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.bConfigurationValue = cfg->bConfigurationValue;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.iConfiguration = cfg->iConfiguration;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.bmAttributes = cfg->bmAttributes;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.MaxPower = cfg->MaxPower;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for(i=0; i < 4; i++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for(x=0; x < 32; x++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( cnt.idmap[i] & (1 << x) )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( !copy_interface(pIf++, (i << 6) | x, &ifd, &epd, (uint8_t *)descs, tot_len) ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("copy_interface(%d,,) failed\n", pIf - 1));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync goto err;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync free_desc(descs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return true;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncerr:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: config%u: Corrupted configuration descriptor\n", idx));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync free_desc(descs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Edit out masked interface descriptors.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @param pProxyDev The proxy device
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic void usbProxyDevEditOutMaskedIfs(PUSBPROXYDEV pProxyDev)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync unsigned cRemoved = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCCONFIGEX paCfgs = pProxyDev->paCfgDescs;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iCfg = 0; iCfg < pProxyDev->DevDesc.bNumConfigurations; iCfg++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber < 32
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && ((1 << paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber) & pProxyDev->fMaskedIfs))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: removing interface #%d (iIf=%d iAlt=%d) on config #%d (iCfg=%d)\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber, iIf, iAlt, paCfgs[iCfg].Core.bConfigurationValue, iCfg));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cRemoved++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync paCfgs[iCfg].Core.bNumInterfaces--;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync unsigned cToCopy = paCfgs[iCfg].Core.bNumInterfaces - iIf;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (cToCopy)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memmove(&paIfs[iIf], &paIfs[iIf + 1], sizeof(paIfs[0]) * cToCopy);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memset(&paIfs[iIf + cToCopy], '\0', sizeof(paIfs[0]));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: edited out %d interface(s).\n", cRemoved));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbReset
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code to reset the device.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pProxyDev->fMaskedIfs)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyDevReset: pProxyDev=%s - ignoring reset request fMaskedIfs=%#x\n", pUsbIns->pszName, pProxyDev->fMaskedIfs));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyDevReset: pProxyDev=%s\n", pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return pProxyDev->pOps->pfnReset(pProxyDev, fResetOnLinux);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(PCPDMUSBDESCCACHE) usbProxyDevGetDescriptorCache(PPDMUSBINS pUsbIns)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return &pThis->DescCache;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbSetConfiguration
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Release claimed interfaces, tell the OS+device about the config change, claim the new interfaces.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyDevSetConfiguration: pProxyDev=%s iActiveCfg=%d bConfigurationValue=%d\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUsbIns->pszName, pProxyDev->iActiveCfg, bConfigurationValue));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Release the current config.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pvOldCfgDesc)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCVUSBDESCCONFIGEX pOldCfgDesc = (PCVUSBDESCCONFIGEX)pvOldCfgDesc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCVUSBINTERFACESTATE pOldIfState = (PCVUSBINTERFACESTATE)pvOldIfState;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned i = 0; i < pOldCfgDesc->Core.bNumInterfaces; i++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pOldIfState[i].pCurIfDesc)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->pOps->pfnReleaseInterface(pProxyDev, pOldIfState[i].pCurIfDesc->Core.bInterfaceNumber);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Do the actual SET_CONFIGURE.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * The mess here is because most backends will already have selected a
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * configuration and there are a bunch of devices which will freak out
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * if we do SET_CONFIGURE twice with the same value. (PalmOne, TrekStor USB-StickGO, ..)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * After open and reset the backend should use the members iActiveCfg and cIgnoreSetConfigs
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to indicate the new configuration state and what to do on the next SET_CONFIGURATION call.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( pProxyDev->iActiveCfg != bConfigurationValue
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || ( bConfigurationValue == 0
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && pProxyDev->iActiveCfg != -1 /* this test doesn't make sense, we know it's 0 */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && pProxyDev->cIgnoreSetConfigs >= 2)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || !pProxyDev->cIgnoreSetConfigs)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->cIgnoreSetConfigs = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!pProxyDev->pOps->pfnSetConfig(pProxyDev, bConfigurationValue))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->iActiveCfg = -1;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VERR_GENERAL_FAILURE;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->iActiveCfg = bConfigurationValue;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else if (pProxyDev->cIgnoreSetConfigs > 0)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->cIgnoreSetConfigs--;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Claim the interfaces.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCVUSBDESCCONFIGEX pNewCfgDesc = (PCVUSBDESCCONFIGEX)pvNewCfgDesc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Assert(pNewCfgDesc->Core.bConfigurationValue == bConfigurationValue);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iIf = 0; iIf < pNewCfgDesc->Core.bNumInterfaces; iIf++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCVUSBINTERFACE pIf = &pNewCfgDesc->paIfs[iIf];
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (uint32_t iAlt = 0; iAlt < pIf->cSettings; iAlt++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pIf->paSettings[iAlt].Core.bAlternateSetting != 0)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync continue;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->pOps->pfnClaimInterface(pProxyDev, pIf->paSettings[iAlt].Core.bInterfaceNumber);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* ignore failures - the backend deals with that and does the necessary logging. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbSetInterface
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code to select alternate interface settings.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyDevSetInterface: pProxyDev=%s bInterfaceNumber=%d bAlternateSetting=%d\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUsbIns->pszName, bInterfaceNumber, bAlternateSetting));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo this is fishy, pfnSetInterface returns true/false from what I can see... */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pProxyDev->pOps->pfnSetInterface(pProxyDev, bInterfaceNumber, bAlternateSetting) < 0)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VERR_GENERAL_FAILURE;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code to clear the endpoint.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyDevClearHaltedEndpoint: pProxyDev=%s uEndpoint=%u\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUsbIns->pszName, uEndpoint));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!pProxyDev->pOps->pfnClearHaltedEndpoint(pProxyDev, uEndpoint))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VERR_GENERAL_FAILURE;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUrbQueue
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevUrbQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!pProxyDev->pOps->pfnUrbQueue(pUrb))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return pProxyDev->fDetached
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ? VERR_VUSB_DEVICE_NOT_ATTACHED
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync : VERR_VUSB_FAILED_TO_QUEUE_URB;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUrbCancel
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->pOps->pfnUrbCancel(pUrb);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUrbReap
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(PVUSBURB) usbProxyDevUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBURB pUrb = pProxyDev->pOps->pfnUrbReap(pProxyDev, cMillies);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( pUrb
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && pUrb->enmState == VUSBURBSTATE_CANCELLED
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && pUrb->enmStatus == VUSBSTATUS_OK)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUrb->enmStatus = VUSBSTATUS_DNR;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return pUrb;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/** @copydoc PDMUSBREG::pfnDestruct */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(void) usbProxyDestruct(PPDMUSBINS pUsbIns)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyDestruct: destroying pProxyDev=%s\n", pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* close it. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pThis->fOpened)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->pOps->pfnClose(pThis);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->fOpened = false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* free the config descriptors. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pThis->paCfgDescs)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync RTMemFree((void *)pThis->paCfgDescs[i].paIfs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo bugref{2693} cleanup */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync RTMemFree(pThis->paCfgDescs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->paCfgDescs = NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* free dev */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (&g_szDummyName[0] != pUsbIns->pszName)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync RTStrFree(pUsbIns->pszName);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUsbIns->pszName = NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Helper function used by usbProxyConstruct when
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * reading a filter from CFG.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @returns VBox status code.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @param pFilter The filter.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @param enmFieldIdx The filter field indext.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @param pNode The CFGM node.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @param pszExact The exact value name.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @param pszExpr The expression value name.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic int usbProxyQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, PCFGMNODE pNode, const char *pszExact, const char *pszExpr)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync char szTmp[256];
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* try exact first */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint16_t u16;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int rc = CFGMR3QueryU16(pNode, pszExact, &u16);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (RT_SUCCESS(rc))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExact(pFilter, enmFieldIdx, u16, true);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertRCReturn(rc, rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* make sure only the exact attribute is present. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync szTmp[0] = '\0';
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogRel(("usbProxyConstruct: %s: Both %s and %s are present!\n", szTmp, pszExact, pszExpr));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VERR_INVALID_PARAMETER;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync szTmp[0] = '\0';
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExact, rc));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return rc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* expression? */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (RT_SUCCESS(rc))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExpression(pFilter, enmFieldIdx, szTmp, true);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertRCReturn(rc, rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync szTmp[0] = '\0';
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExpr, rc));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return rc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/** @copydoc PDMUSBREG::pfnConstruct */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyConstruct: pUsbIns=%p iInstance=%d\n", pUsbIns, iInstance));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Initialize the instance data.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->pUsbIns = pUsbIns;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->pUsbIns->pszName = g_szDummyName;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->iActiveCfg = -1;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->fMaskedIfs = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->fOpened = false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->fInited = false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Read the basic configuration.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync char szAddress[1024];
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int rc = CFGMR3QueryString(pCfg, "Address", szAddress, sizeof(szAddress));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertRCReturn(rc, rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync bool fRemote;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfg, "Remote", &fRemote);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertRCReturn(rc, rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync void *pvBackend;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryPtr(pCfg, "pvBackend", &pvBackend);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertRCReturn(rc, rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Select backend and open the device.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!fRemote)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->pOps = &g_USBProxyDeviceHost;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#ifdef VBOX_WITH_VRDP
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->pOps = &g_USBProxyDeviceVRDP;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VERR_NOT_SUPPORTED;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#endif
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = pThis->pOps->pfnOpen(pThis, szAddress, pvBackend);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (RT_FAILURE(rc))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return rc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->fOpened = true;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Get the device descriptor and format the device name (for logging).
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!usbProxyGetDeviceDesc(pThis, &pThis->DevDesc))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyConstruct: usbProxyGetDeviceDesc failed\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VERR_READ_ERROR;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync RTStrAPrintf(&pUsbIns->pszName, "%p[proxy %04x:%04x]", pThis, pThis->DevDesc.idVendor, pThis->DevDesc.idProduct); /** @todo append the user comment */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertReturn(pUsbIns->pszName, VERR_NO_MEMORY);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Get config descriptors.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync size_t cbConfigs = pThis->DevDesc.bNumConfigurations * sizeof(pThis->paCfgDescs[0]);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->paCfgDescs = (PVUSBDESCCONFIGEX)RTMemAllocZ(cbConfigs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertReturn(pThis->paCfgDescs, VERR_NO_MEMORY);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync unsigned i;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!copy_config(pThis, i, (PVUSBDESCCONFIGEX)&pThis->paCfgDescs[i]))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (i < pThis->DevDesc.bNumConfigurations)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyConstruct: copy_config failed, i=%d\n", i));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VERR_READ_ERROR;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Pickup best matching global configuration for this device.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * The global configuration is organized like this:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * GlobalConfig/Whatever/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * |- idVendor = 300
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * |- idProduct = 300
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * - Config/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * The first level contains filter attributes which we stuff into a USBFILTER
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * structure and match against the device info that's available. The highest
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * ranked match is will be used. If nothing is found, the values will be
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * queried from the GlobalConfig node (simplifies code and might actually
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * be useful).
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCFGMNODE pCfgGlobalDev = pCfgGlobal;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgGlobal);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pCur)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Create a device filter from the device configuration
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * descriptor ++. No strings currently.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync USBFILTER Device;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync USBFilterInit(&Device, USBFILTERTYPE_CAPTURE);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExact(&Device, USBFILTERIDX_VENDOR_ID, pThis->DevDesc.idVendor, true); AssertRC(rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExact(&Device, USBFILTERIDX_PRODUCT_ID, pThis->DevDesc.idProduct, true); AssertRC(rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_REV, pThis->DevDesc.bcdDevice, true); AssertRC(rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_CLASS, pThis->DevDesc.bDeviceClass, true); AssertRC(rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_SUB_CLASS, pThis->DevDesc.bDeviceSubClass, true); AssertRC(rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_PROTOCOL, pThis->DevDesc.bDeviceProtocol, true); AssertRC(rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo manufacturer, product and serial strings */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int iBestMatchRate = -1;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCFGMNODE pBestMatch = NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (pCur = CFGMR3GetFirstChild(pCfgGlobal); pCur; pCur = CFGMR3GetNextChild(pCur))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Construct a filter from the attributes in the node.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync USBFILTER Filter;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* numeric */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_VENDOR_ID, pCur, "idVendor", "idVendorExpr"))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_PRODUCT_ID, pCur, "idProduct", "idProcutExpr"))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_REV, pCur, "bcdDevice", "bcdDeviceExpr"))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_CLASS, pCur, "bDeviceClass", "bDeviceClassExpr"))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pCur, "bDeviceSubClass", "bDeviceSubClassExpr"))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pCur, "bDeviceProtocol", "bDeviceProtocolExpr")))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync continue; /* skip it */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* strings */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo manufacturer, product and serial strings */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* ignore unknown config values, but not without bitching. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!CFGMR3AreValuesValid(pCur,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "idVendor\0idVendorExpr\0"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "idProduct\0idProductExpr\0"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "bcdDevice\0bcdDeviceExpr\0"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "bDeviceClass\0bDeviceClassExpr\0"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "bDeviceSubClass\0bDeviceSubClassExpr\0"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "bDeviceProtocol\0bDeviceProtocolExpr\0"))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogRel(("usbProxyConstruct: Unknown value(s) in config filter (ignored)!\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Try match it and on match see if it has is a higher rate hit
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * than the previous match. Quit if its a 100% match.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int iRate = USBFilterMatchRated(&Filter, &Device);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (iRate > iBestMatchRate)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pBestMatch = pCur;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync iBestMatchRate = iRate;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (iRate >= 100)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pBestMatch)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pCfgGlobalDev = CFGMR3GetChild(pBestMatch, "Config");
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pCfgGlobalDev)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pCfgGlobalDev = pCfgGlobal;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Query the rest of the configuration using the global as fallback.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryU32(pCfg, "MaskedIfs", &pThis->fMaskedIfs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryU32(pCfgGlobalDev, "MaskedIfs", &pThis->fMaskedIfs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->fMaskedIfs = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertRCReturn(rc, rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync bool fForce11Device;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfg, "Force11Device", &fForce11Device);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11Device", &fForce11Device);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync fForce11Device = false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertRCReturn(rc, rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync bool fForce11PacketSize;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfg, "Force11PacketSize", &fForce11PacketSize);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11PacketSize", &fForce11PacketSize);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync fForce11PacketSize = false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertRCReturn(rc, rc);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * If we're masking interfaces, edit the descriptors.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync bool fEdited = pThis->fMaskedIfs != 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pThis->fMaskedIfs)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevEditOutMaskedIfs(pThis);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Do 2.0 -> 1.1 device edits if requested to do so.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( fForce11PacketSize
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && pThis->DevDesc.bcdUSB >= 0x0200)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB 1.1 defines the max for control, interrupt and bulk to be 64 bytes.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * While isochronous has a max of 1023 bytes.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCENDPOINTEX paEps = (PVUSBDESCENDPOINTEX)paIfs[iIf].paSettings[iAlt].paEndpoints;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iEp = 0; iEp < paIfs[iIf].paSettings[iAlt].Core.bNumEndpoints; iEp++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync const uint16_t cbMax = (paEps[iEp].Core.bmAttributes & 3) == 1 /* isoc */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ? 1023
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync : 64;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (paEps[iEp].Core.wMaxPacketSize > cbMax)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: pProxyDev=%s correcting wMaxPacketSize from %#x to %#x (mainly for vista)\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUsbIns->pszName, paEps[iEp].Core.wMaxPacketSize, cbMax));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync paEps[iEp].Core.wMaxPacketSize = cbMax;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync fEdited = true;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( fForce11Device
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && pThis->DevDesc.bcdUSB == 0x0200)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Discourages windows from helping you find a 2.0 port.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: %s correcting USB version 2.0 to 1.1 (to avoid Windows warning)\n", pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->DevDesc.bcdUSB = 0x110;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync fEdited = true;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Init the PDM/VUSB descriptor cache.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->DescCache.pDevice = &pThis->DevDesc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->DescCache.paConfigs = pThis->paCfgDescs;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->DescCache.paLanguages = NULL;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->DescCache.cLanguages = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->DescCache.fUseCachedDescriptors = fEdited;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->DescCache.fUseCachedStringsDescriptors = false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Call the backend if it wishes to do some more initializing
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * after we've read the config and descriptors.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pThis->pOps->pfnInit)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = pThis->pOps->pfnInit(pThis);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (RT_FAILURE(rc))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return rc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->fInited = true;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * We're good!
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: created pProxyDev=%s address '%s' fMaskedIfs=%#x (rc=%Rrc)\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUsbIns->pszName, szAddress, pThis->fMaskedIfs, rc));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * The USB proxy device registration record.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncconst PDMUSBREG g_UsbDevProxy =
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* u32Version */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PDM_USBREG_VERSION,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* szName */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "USBProxy",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pszDescription */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "USB Proxy Device.",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* fFlags */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync 0,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* cMaxInstances */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ~0,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* cbInstance */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync sizeof(USBPROXYDEV),
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnConstruct */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyConstruct,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnDestruct */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDestruct,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMInitComplete */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMPowerOn */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMReset */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMSuspend */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMResume */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMPowerOff */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnHotPlugged */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnHotUnplugged */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnDriverAttach */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnDriverDetach */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnQueryInterface */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbReset */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevReset,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbGetDescriptorCache */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevGetDescriptorCache,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbSetConfiguration */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevSetConfiguration,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbSetInterface */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevSetInterface,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbClearHaltedEndpoint */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevClearHaltedEndpoint,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUrbNew */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync NULL,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUrbQueue */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevUrbQueue,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUrbCancel */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevUrbCancel,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUrbReap */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync usbProxyDevUrbReap,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* u32TheEnd */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PDM_USBREG_VERSION
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync};
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync