USBProxyDevice.cpp revision ad48e47654d22f79b025dc4b21cb162cb123801a
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USBProxy - USB device proxy.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Copyright (C) 2006-2007 Oracle Corporation
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* Header Files *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync*******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/*******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync* Global Variables *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync*******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/** A dummy name used early during the construction phase to avoid log crashes. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/* Synchronously obtain a standard USB descriptor for a device, used in order
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to grab configuration descriptors when we first add the device
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic void *GetStdDescSync(PUSBPROXYDEV pProxyDev, uint8_t iDescType, uint8_t iIdx, uint16_t LangId, uint16_t cbHint)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("GetStdDescSync: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Setup a MSG URB, queue and reap it.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertCompile(RT_SIZEOFMEMB(VUSBURB, abData) >= _4K);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cbHint = RT_MIN(cbHint, sizeof(Urb.abData) - sizeof(VUSBSETUP));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pSetup->bmRequestType = VUSB_DIR_TO_HOST | VUSB_REQ_STANDARD | VUSB_TO_DEVICE;
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 pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, RT_INDEFINITE_WAIT);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: pfnUrbReap failed, pUrbReaped=%p\n", pUrbReaped));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: Urb.enmStatus=%d\n", Urb.enmStatus));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Check the length, config descriptors have total_length field
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: Urb.cbData=%#x (min 4)\n", Urb.cbData));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: Urb.cbData=%#x (min 1)\n", Urb.cbData));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("GetStdDescSync: got Urb.cbData=%u, cbDesc=%u cbHint=%u\n", Urb.cbData, cbDesc, cbHint));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Fine, we got everything return a heap duplicate of the descriptor.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Frees a descriptor returned by GetStdDescSync().
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Get and a device descriptor and byteswap it appropriately.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic bool usbProxyGetDeviceDesc(PUSBPROXYDEV pProxyDev, PVUSBDESCDEVICE pOut)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Get the descriptor from the device.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBDESCDEVICE pIn = (PVUSBDESCDEVICE)GetStdDescSync(pProxyDev, VUSB_DT_DEVICE, 0, 0, VUSB_DT_DEVICE_MIN_LEN);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyGetDeviceDesc: pProxyDev=%s: GetStdDescSync failed\n", pProxyDev->pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: pProxyDev=%s: Corrupted device descriptor. bLength=%d\n", pProxyDev->pUsbIns->pszName, pIn->bLength));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Convert it.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pOut->bNumConfigurations = pIn->bNumConfigurations;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return true;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Count the numbers and types of each kind of descriptor that we need to
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * copy out of the config descriptor
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** bitmap (128 bits) */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic int count_descriptors(struct desc_counts *cnt, uint8_t *buf, size_t len)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (tmp = buf + cfg->bLength; ((tmp + 1) < end) && *tmp; tmp += *tmp)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync switch ( type ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* count interfaces */
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync/* Given the pointer to an interface or endpoint descriptor, find any following
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync * non-standard (vendor or class) descriptors.
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsyncstatic const void *collect_stray_bits(uint8_t *this_desc, uint8_t *end, uint16_t *cbExtra)
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync Assert(*(this_desc + 1) == VUSB_DT_INTERFACE || *(this_desc + 1) == VUSB_DT_ENDPOINT);
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync /* Skip the current interface/endpoint descriptor. */
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync /* Loop until we find another descriptor we understand. */
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync for (tmp = buf; ((tmp + 1) < end) && *tmp; tmp += *tmp)
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync if (type == VUSB_DT_INTERFACE || type == VUSB_DT_ENDPOINT)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/* Setup a vusb_interface structure given some preallocated structures
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to use, (we counted them already)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic int copy_interface(PVUSBINTERFACE pIf, uint8_t ifnum,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (tmp = buf, state = 0; ((tmp + 1) < end) && *tmp; tmp += *tmp)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync switch ( type ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Ignoring this interface */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /* Check we didn't see this alternate setting already
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * because that will break stuff
b7bd5d53fc66113d06f6b3667129864edc780ef8vboxsync /* Point to additional interface descriptor bytes, if any. */
b7bd5d53fc66113d06f6b3667129864edc780ef8vboxsync AssertCompile(sizeof(cur_if->Core) == VUSB_DT_INTERFACE_MIN_LEN);
b7bd5d53fc66113d06f6b3667129864edc780ef8vboxsync if (cur_if->Core.bLength - VUSB_DT_INTERFACE_MIN_LEN > 0)
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync cur_if->pvClass = collect_stray_bits(tmp, end, &cur_if->cbClass);
b7bd5d53fc66113d06f6b3667129864edc780ef8vboxsync /* Point to additional endpoint descriptor bytes, if any. */
b7bd5d53fc66113d06f6b3667129864edc780ef8vboxsync AssertCompile(sizeof(cur_ep->Core) == VUSB_DT_ENDPOINT_MIN_LEN);
b7bd5d53fc66113d06f6b3667129864edc780ef8vboxsync if (cur_ep->Core.bLength - VUSB_DT_ENDPOINT_MIN_LEN > 0)
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync cur_ep->pvClass = collect_stray_bits(tmp, end, &cur_ep->cbClass);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync cur_ep->Core.wMaxPacketSize = RT_LE2H_U16(cur_ep->Core.wMaxPacketSize);
078ef5fdcdacfd0daaa71705a453b93ebfb91925vboxsync /* Skip unknown descriptors. */
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.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic bool copy_config(PUSBPROXYDEV pProxyDev, uint8_t idx, PVUSBDESCCONFIGEX out)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync descs = GetStdDescSync(pProxyDev, VUSB_DT_CONFIG, idx, 0, VUSB_DT_CONFIG_MIN_LEN);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( !count_descriptors(&cnt, (uint8_t *)descs, tot_len) ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: config%u: bNumInterfaces %u != %u\n",
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 out->paIfs = (PCVUSBINTERFACE)RTMemAllocZ(cbIface);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
b7bd5d53fc66113d06f6b3667129864edc780ef8vboxsync /* Stash a pointer to the raw config descriptor; we may need bits of it later. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync out->Core.bConfigurationValue = cfg->bConfigurationValue;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for(i=0; i < 4; i++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for(x=0; x < 32; x++)
a2c4aeff57c6b312f8c5b2f0f25b21c3766b3c33vboxsync if ( !copy_interface(pIf++, (i << 6) | x, &ifd, &epd, (uint8_t *)out->pvOriginal, tot_len) ) {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return true;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: config%u: Corrupted configuration descriptor\n", idx));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Edit out masked interface descriptors.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @param pProxyDev The proxy device
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic void usbProxyDevEditOutMaskedIfs(PUSBPROXYDEV pProxyDev)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync unsigned cRemoved = 0;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iCfg = 0; iCfg < pProxyDev->DevDesc.bNumConfigurations; iCfg++)
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 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 unsigned cToCopy = paCfgs[iCfg].Core.bNumInterfaces - iIf;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memmove(&paIfs[iIf], &paIfs[iIf + 1], sizeof(paIfs[0]) * cToCopy);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync memset(&paIfs[iIf + cToCopy], '\0', sizeof(paIfs[0]));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: edited out %d interface(s).\n", cRemoved));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbReset
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code to reset the device.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyDevReset: pProxyDev=%s - ignoring reset request fMaskedIfs=%#x\n", pUsbIns->pszName, pProxyDev->fMaskedIfs));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyDevReset: pProxyDev=%s\n", pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return pProxyDev->pOps->pfnReset(pProxyDev, fResetOnLinux);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(PCPDMUSBDESCCACHE) usbProxyDevGetDescriptorCache(PPDMUSBINS pUsbIns)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbSetConfiguration
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Release claimed interfaces, tell the OS+device about the config change, claim the new interfaces.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
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 * Release the current config.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCVUSBDESCCONFIGEX pOldCfgDesc = (PCVUSBDESCCONFIGEX)pvOldCfgDesc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCVUSBINTERFACESTATE pOldIfState = (PCVUSBINTERFACESTATE)pvOldIfState;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned i = 0; i < pOldCfgDesc->Core.bNumInterfaces; i++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->pOps->pfnReleaseInterface(pProxyDev, pOldIfState[i].pCurIfDesc->Core.bInterfaceNumber);
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 * 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 && pProxyDev->iActiveCfg != -1 /* this test doesn't make sense, we know it's 0 */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!pProxyDev->pOps->pfnSetConfig(pProxyDev, bConfigurationValue))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Claim the interfaces.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PCVUSBDESCCONFIGEX pNewCfgDesc = (PCVUSBDESCCONFIGEX)pvNewCfgDesc;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Assert(pNewCfgDesc->Core.bConfigurationValue == bConfigurationValue);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iIf = 0; iIf < pNewCfgDesc->Core.bNumInterfaces; iIf++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (uint32_t iAlt = 0; iAlt < pIf->cSettings; iAlt++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pIf->paSettings[iAlt].Core.bAlternateSetting != 0)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pProxyDev->pOps->pfnClaimInterface(pProxyDev, pIf->paSettings[iAlt].Core.bInterfaceNumber);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* ignore failures - the backend deals with that and does the necessary logging. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbSetInterface
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code to select alternate interface settings.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyDevSetInterface: pProxyDev=%s bInterfaceNumber=%d bAlternateSetting=%d\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUsbIns->pszName, bInterfaceNumber, bAlternateSetting));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo this is fishy, pfnSetInterface returns true/false from what I can see... */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pProxyDev->pOps->pfnSetInterface(pProxyDev, bInterfaceNumber, bAlternateSetting) < 0)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code to clear the endpoint.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyDevClearHaltedEndpoint: pProxyDev=%s uEndpoint=%u\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!pProxyDev->pOps->pfnClearHaltedEndpoint(pProxyDev, uEndpoint))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUrbQueue
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevUrbQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUrbCancel
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyDevUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * @copydoc PDMUSBREG::pfnUrbReap
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * USB Device Proxy: Call OS specific code.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(PVUSBURB) usbProxyDevUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PVUSBURB pUrb = pProxyDev->pOps->pfnUrbReap(pProxyDev, cMillies);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/** @copydoc PDMUSBREG::pfnDestruct */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(void) usbProxyDestruct(PPDMUSBINS pUsbIns)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyDestruct: destroying pProxyDev=%s\n", pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* close it. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* free the config descriptors. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
b7bd5d53fc66113d06f6b3667129864edc780ef8vboxsync RTMemFree((void *)pThis->paCfgDescs[i].pvOriginal);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* free dev */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Helper function used by usbProxyConstruct when
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * reading a filter from CFG.
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.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic int usbProxyQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, PCFGMNODE pNode, const char *pszExact, const char *pszExpr)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* try exact first */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExact(pFilter, enmFieldIdx, u16, true);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* make sure only the exact attribute is present. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogRel(("usbProxyConstruct: %s: Both %s and %s are present!\n", szTmp, pszExact, pszExpr));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExact, rc));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* expression? */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = USBFilterSetNumExpression(pFilter, enmFieldIdx, szTmp, true);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExpr, rc));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/** @copydoc PDMUSBREG::pfnConstruct */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncstatic DECLCALLBACK(int) usbProxyConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlow(("usbProxyConstruct: pUsbIns=%p iInstance=%d\n", pUsbIns, iInstance));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Initialize the instance data.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Read the basic configuration.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int rc = CFGMR3QueryString(pCfg, "Address", szAddress, sizeof(szAddress));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryPtr(pCfg, "pvBackend", &pvBackend);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Select backend and open the device.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = pThis->pOps->pfnOpen(pThis, szAddress, pvBackend);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Get the device descriptor and format the device name (for logging).
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!usbProxyGetDeviceDesc(pThis, &pThis->DevDesc))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyConstruct: usbProxyGetDeviceDesc failed\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync RTStrAPrintf(&pUsbIns->pszName, "%p[proxy %04x:%04x]", pThis, pThis->DevDesc.idVendor, pThis->DevDesc.idProduct); /** @todo append the user comment */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Get config descriptors.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync size_t cbConfigs = pThis->DevDesc.bNumConfigurations * sizeof(pThis->paCfgDescs[0]);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->paCfgDescs = (PVUSBDESCCONFIGEX)RTMemAllocZ(cbConfigs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync unsigned i;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (!copy_config(pThis, i, (PVUSBDESCCONFIGEX)&pThis->paCfgDescs[i]))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usbProxyConstruct: copy_config failed, i=%d\n", i));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Pickup best matching global configuration for this device.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * The global configuration is organized like this:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * |- idVendor = 300
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * |- idProduct = 300
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * - Config/
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 * Create a device filter from the device configuration
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * descriptor ++. No strings currently.
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 for (pCur = CFGMR3GetFirstChild(pCfgGlobal); pCur; pCur = CFGMR3GetNextChild(pCur))
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Construct a filter from the attributes in the node.
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 /* strings */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo manufacturer, product and serial strings */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* ignore unknown config values, but not without bitching. */
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 * 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 pCfgGlobalDev = CFGMR3GetChild(pBestMatch, "Config");
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Query the rest of the configuration using the global as fallback.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryU32(pCfg, "MaskedIfs", &pThis->fMaskedIfs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryU32(pCfgGlobalDev, "MaskedIfs", &pThis->fMaskedIfs);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfg, "Force11Device", &fForce11Device);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11Device", &fForce11Device);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfg, "Force11PacketSize", &fForce11PacketSize);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11PacketSize", &fForce11PacketSize);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * If we're masking interfaces, edit the descriptors.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Do 2.0 -> 1.1 device edits if requested to do so.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
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 * 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 PVUSBDESCENDPOINTEX paEps = (PVUSBDESCENDPOINTEX)paIfs[iIf].paSettings[iAlt].paEndpoints;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (unsigned iEp = 0; iEp < paIfs[iIf].paSettings[iAlt].Core.bNumEndpoints; iEp++)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync const uint16_t cbMax = (paEps[iEp].Core.bmAttributes & 3) == 1 /* isoc */
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 * Discourages windows from helping you find a 2.0 port.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: %s correcting USB version 2.0 to 1.1 (to avoid Windows warning)\n", pUsbIns->pszName));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Init the PDM/VUSB descriptor cache.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pThis->DescCache.fUseCachedStringsDescriptors = false;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Call the backend if it wishes to do some more initializing
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * after we've read the config and descriptors.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * We're good!
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync Log(("usb-proxy: created pProxyDev=%s address '%s' fMaskedIfs=%#x (rc=%Rrc)\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pUsbIns->pszName, szAddress, pThis->fMaskedIfs, rc));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * The USB proxy device registration record.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* u32Version */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* szName */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "USBProxy",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pszDescription */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync "USB Proxy Device.",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* fFlags */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* cMaxInstances */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* cbInstance */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnConstruct */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnDestruct */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMInitComplete */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMPowerOn */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMReset */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMSuspend */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMResume */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnVMPowerOff */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnHotPlugged */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnHotUnplugged */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnDriverAttach */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnDriverDetach */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnQueryInterface */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbReset */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbGetDescriptorCache */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbSetConfiguration */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbSetInterface */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUsbClearHaltedEndpoint */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUrbNew */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUrbQueue */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUrbCancel */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* pfnUrbReap */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* u32TheEnd */