VUSBDevice.cpp revision a3cc5474f3cdd349476201c13a2a1c60484ffbb2
9ad572a3ac0fd3845a9abecfbf41e8db9b3a5cf0vboxsync/* $Id$ */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/** @file
adf2bcd2e5d07d5a11553b88e147c1f4b2249bffvboxsync * Virtual USB - Device.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/*
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync * Copyright (C) 2006-2007 Oracle Corporation
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * available from http://www.virtualbox.org. This file is free software;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * you can redistribute it and/or modify it under the terms of the GNU
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * General Public License (GPL) as published by the Free Software
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/*******************************************************************************
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync* Header Files *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync*******************************************************************************/
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#define LOG_GROUP LOG_GROUP_DRV_VUSB
70bb61ea2f96e80150e807529ce5df435607706bvboxsync#include <VBox/vmm/pdm.h>
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#include <VBox/vmm/vmapi.h>
23179f1443b03947d85eccc81cbc6b5153a4abf3vboxsync#include <VBox/err.h>
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#include <VBox/log.h>
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#include <iprt/alloc.h>
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#include <iprt/time.h>
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#include <iprt/thread.h>
edefdc20eedaf9ef5b1293e56ba9b8cca7b5c740vboxsync#include <iprt/semaphore.h>
edefdc20eedaf9ef5b1293e56ba9b8cca7b5c740vboxsync#include <iprt/string.h>
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#include <iprt/assert.h>
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#include <iprt/asm.h>
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#include "VUSBInternal.h"
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/** Asserts that the give device state is valid. */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync#define VUSBDEV_ASSERT_VALID_STATE(enmState) \
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync AssertMsg((enmState) > VUSB_DEVICE_STATE_INVALID && (enmState) < VUSB_DEVICE_STATE_DESTROYED, ("enmState=%#x\n", enmState));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/*******************************************************************************
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync* Structures and Typedefs *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync*******************************************************************************/
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/**
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Argument package of vusbDevResetThread().
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsynctypedef struct vusb_reset_args
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync{
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync /** Pointer to the device which is being reset. */
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync PVUSBDEV pDev;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /** Can reset on linux. */
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync bool fResetOnLinux;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /** The reset return code. */
b304856b23107864c9c594a80cebca6006623f31vboxsync int rc;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /** Pointer to the completion callback. */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync PFNVUSBRESETDONE pfnDone;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /** User argument to pfnDone. */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync void *pvUser;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync} VUSBRESETARGS, *PVUSBRESETARGS;
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
5e0d1b28833a92e30446e95ced085bce4d794067vboxsync/*******************************************************************************
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync* Global Variables *
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync*******************************************************************************/
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync/** Default message pipe. */
c33fc49611f2444dade533488bf431e29eb88bcdvboxsyncconst VUSBDESCENDPOINTEX g_Endpoint0 =
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync{
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync {
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* .bLength = */ VUSB_DT_ENDPOINT_MIN_LEN,
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync /* .bEndpointAddress = */ 0,
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync /* .bmAttributes = */ 0,
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync /* .wMaxPacketSize = */ 64,
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync /* .bInterval = */ 0
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync },
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync NULL
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync};
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
9353e321b583ed6f2b42414257a5212885575b5cvboxsync/** Default configuration. */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncconst VUSBDESCCONFIGEX g_Config0 =
9353e321b583ed6f2b42414257a5212885575b5cvboxsync{
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync {
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* .bLength = */ VUSB_DT_CONFIG_MIN_LEN,
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* .bDescriptorType = */ VUSB_DT_CONFIG,
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* .WTotalLength = */ 0, /* (auto-calculated) */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* .bNumInterfaces = */ 0,
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* .bConfigurationValue =*/ 0,
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* .iConfiguration = */ 0,
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* .bmAttributes = */ 0x80,
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync /* .MaxPower = */ 14
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync },
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync NULL,
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync NULL
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync};
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsyncstatic PCVUSBDESCCONFIGEX vusbDevFindCfgDesc(PVUSBDEV pDev, int iCfg)
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync{
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync if (iCfg == 0)
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync return &g_Config0;
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync for (unsigned i = 0; i < pDev->pDescCache->pDevice->bNumConfigurations; i++)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if (pDev->pDescCache->paConfigs[i].Core.bConfigurationValue == iCfg)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return &pDev->pDescCache->paConfigs[i];
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return NULL;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync}
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsyncstatic PVUSBINTERFACESTATE vusbDevFindIfState(PVUSBDEV pDev, int iIf)
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync{
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync for (unsigned i = 0; i < pDev->pCurCfgDesc->Core.bNumInterfaces; i++)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if (pDev->paIfStates[i].pIf->paSettings[0].Core.bInterfaceNumber == iIf)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return &pDev->paIfStates[i];
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return NULL;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync}
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsyncstatic PCVUSBDESCINTERFACEEX vusbDevFindAltIfDesc(PVUSBDEV pDev, PCVUSBINTERFACESTATE pIfState, int iAlt)
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync{
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync for (uint32_t i = 0; i < pIfState->pIf->cSettings; i++)
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync if (pIfState->pIf->paSettings[i].Core.bAlternateSetting == iAlt)
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync return &pIfState->pIf->paSettings[i];
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync return NULL;
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync}
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsyncvoid vusbDevMapEndpoint(PVUSBDEV pDev, PCVUSBDESCENDPOINTEX pEndPtDesc)
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync{
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync uint8_t i8Addr = pEndPtDesc->Core.bEndpointAddress & 0xF;
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync PVUSBPIPE pPipe = &pDev->aPipes[i8Addr];
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync LogFlow(("vusbDevMapEndpoint: pDev=%p[%s] pEndPtDesc=%p{.bEndpointAddress=%#x, .bmAttributes=%#x} p=%p stage %s->SETUP\n",
19cb1f8699e352d590c4946caee33863a5157241vboxsync pDev, pDev->pUsbIns->pszName, pEndPtDesc, pEndPtDesc->Core.bEndpointAddress, pEndPtDesc->Core.bmAttributes,
19cb1f8699e352d590c4946caee33863a5157241vboxsync pPipe, g_apszCtlStates[pPipe->pCtrl ? pPipe->pCtrl->enmStage : 3]));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync pPipe->ReadAheadThread = NIL_RTTHREAD;
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync if ((pEndPtDesc->Core.bmAttributes & 0x3) == 0)
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync {
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync Log(("vusb: map message pipe on address %u\n", i8Addr));
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync pPipe->in = pEndPtDesc;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync pPipe->out = pEndPtDesc;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync }
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync else if (pEndPtDesc->Core.bEndpointAddress & 0x80)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync Log(("vusb: map input pipe on address %u\n", i8Addr));
3933885bc0c2c93436d858a14564c6179ec72872vboxsync pPipe->in = pEndPtDesc;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync /*
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * For high-speed isochronous input endpoints, spin off a read-ahead buffering thread.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if ((pEndPtDesc->Core.bmAttributes & 0x03) == 1)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vusbReadAheadStart(pDev, pPipe);
cc74f15083bf80fbc96723a89faa06c15d0dead8vboxsync#endif
a72b5355eb89aafe6bfcc8912cf02645d7cccceavboxsync }
a72b5355eb89aafe6bfcc8912cf02645d7cccceavboxsync else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
6e25221ce8ef8e656d1e15eb7ec5cf8ae758ceb2vboxsync Log(("vusb: map output pipe on address %u\n", i8Addr));
3933885bc0c2c93436d858a14564c6179ec72872vboxsync pPipe->out = pEndPtDesc;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (pPipe->pCtrl)
9ca017ceee656f9d33f2cb6652e401b5f17fcfb7vboxsync {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vusbMsgFreeExtraData(pPipe->pCtrl);
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync pPipe->pCtrl = NULL;
9601ea695ea96905d6f5d484facd272732365c40vboxsync }
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync}
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic void unmap_endpoint(PVUSBDEV pDev, PCVUSBDESCENDPOINTEX pEndPtDesc)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync{
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync uint8_t EndPt = pEndPtDesc->Core.bEndpointAddress & 0xF;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync PVUSBPIPE pPipe = &pDev->aPipes[EndPt];
ad9e5a61fea617d40d07390ff1737277d6aef869vboxsync LogFlow(("unmap_endpoint: pDev=%p[%s] pEndPtDesc=%p{.bEndpointAddress=%#x, .bmAttributes=%#x} p=%p stage %s->SETUP\n",
23d9dbdaf1b83107abf9882246a4a46933f733efvboxsync pDev, pDev->pUsbIns->pszName, pEndPtDesc, pEndPtDesc->Core.bEndpointAddress, pEndPtDesc->Core.bmAttributes,
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync pPipe, g_apszCtlStates[pPipe->pCtrl ? pPipe->pCtrl->enmStage : 3]));
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync if ((pEndPtDesc->Core.bmAttributes & 0x3) == 0)
dbabc9de5bf52ce5eb77cf82b038e9a6166c5a04vboxsync {
4090390866c02d5d0ad061151cdb298b9a173e86vboxsync Log(("vusb: unmap MSG pipe from address %u (%#x)\n", EndPt, pEndPtDesc->Core.bEndpointAddress));
4090390866c02d5d0ad061151cdb298b9a173e86vboxsync pPipe->in = NULL;
40dce69ff1c2949a489337922f30f1021d62d864vboxsync pPipe->out = NULL;
40dce69ff1c2949a489337922f30f1021d62d864vboxsync }
40dce69ff1c2949a489337922f30f1021d62d864vboxsync else if (pEndPtDesc->Core.bEndpointAddress & 0x80)
40dce69ff1c2949a489337922f30f1021d62d864vboxsync {
40dce69ff1c2949a489337922f30f1021d62d864vboxsync Log(("vusb: unmap IN pipe from address %u (%#x)\n", EndPt, pEndPtDesc->Core.bEndpointAddress));
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync pPipe->in = NULL;
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync /* If there was a read-ahead thread associated with this endpoint, tell it to go away. */
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync if (pPipe->pvReadAheadArgs)
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync {
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync Log(("vusb: and tell read-ahead thread for the endpoint to terminate\n"));
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync vusbReadAheadStop(pPipe->pvReadAheadArgs);
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync }
7708252d252a55417a6a817041e4356797e34255vboxsync }
7708252d252a55417a6a817041e4356797e34255vboxsync else
7708252d252a55417a6a817041e4356797e34255vboxsync {
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync Log(("vusb: unmap OUT pipe from address %u (%#x)\n", EndPt, pEndPtDesc->Core.bEndpointAddress));
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync pPipe->out = NULL;
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync }
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync if (pPipe->pCtrl)
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync {
f2dbf051efd73ff79892d4cec2b466139f962a40vboxsync vusbMsgFreeExtraData(pPipe->pCtrl);
5d57bcb78f1f3f918bd3daf709b551b8c2d30485vboxsync pPipe->pCtrl = NULL;
cccc6ee5f7156cfcdf13acca545cf65124d9ed44vboxsync }
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync}
904810c4c6668233349b025cc58013cb7c11c701vboxsync
904810c4c6668233349b025cc58013cb7c11c701vboxsyncstatic void map_interface(PVUSBDEV pDev, PCVUSBDESCINTERFACEEX pIfDesc)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync{
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("map_interface: pDev=%p[%s] pIfDesc=%p:{.iInterface=%d, .bAlternateSetting=%d}\n",
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev, pDev->pUsbIns->pszName, pIfDesc, pIfDesc->Core.iInterface, pIfDesc->Core.bAlternateSetting));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync for (unsigned i = 0; i < pIfDesc->Core.bNumEndpoints; i++)
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync {
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync if ((pIfDesc->paEndpoints[i].Core.bEndpointAddress & 0xF) == VUSB_PIPE_DEFAULT)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync Log(("vusb: Endpoint 0x%x on interface %u.%u tried to override the default message pipe!!!\n",
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync pIfDesc->paEndpoints[i].Core.bEndpointAddress, pIfDesc->Core.bInterfaceNumber, pIfDesc->Core.bAlternateSetting));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync else
b304856b23107864c9c594a80cebca6006623f31vboxsync vusbDevMapEndpoint(pDev, &pIfDesc->paEndpoints[i]);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync }
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync}
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsyncbool vusbDevDoSelectConfig(PVUSBDEV pDev, PCVUSBDESCCONFIGEX pCfgDesc)
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync{
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync LogFlow(("vusbDevDoSelectConfig: pDev=%p[%s] pCfgDesc=%p:{.iConfiguration=%d}\n",
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync pDev, pDev->pUsbIns->pszName, pCfgDesc, pCfgDesc->Core.iConfiguration));
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync /*
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync * Clean up all pipes and interfaces.
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync */
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync unsigned i;
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync for (i = 0; i < VUSB_PIPE_MAX; i++)
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync {
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync if (i != VUSB_PIPE_DEFAULT)
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync {
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync vusbMsgFreeExtraData(pDev->aPipes[i].pCtrl);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync memset(&pDev->aPipes[i], 0, sizeof(pDev->aPipes[i]));
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync }
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync }
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync memset(pDev->paIfStates, 0, pCfgDesc->Core.bNumInterfaces * sizeof(pDev->paIfStates[0]));
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync /*
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * Map in the default setting for every interface.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync */
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync for (i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
9353e321b583ed6f2b42414257a5212885575b5cvboxsync {
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync PCVUSBINTERFACE pIf;
9353e321b583ed6f2b42414257a5212885575b5cvboxsync struct vusb_interface_state *pIfState;
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync pIf = &pCfgDesc->paIfs[i];
fc5f879e9508f333e20b37c63db9189a33059308vboxsync pIfState = &pDev->paIfStates[i];
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync pIfState->pIf = pIf;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
1c6ec9a3a329da6f61978a372e509cd233f0d9f9vboxsync /*
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync * Find the 0 setting, if it is not present we just use
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * the lowest numbered one.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync for (uint32_t j = 0; j < pIf->cSettings; j++)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync {
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if ( !pIfState->pCurIfDesc
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync || pIf->paSettings[j].Core.bAlternateSetting < pIfState->pCurIfDesc->Core.bAlternateSetting)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync pIfState->pCurIfDesc = &pIf->paSettings[j];
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if (pIfState->pCurIfDesc->Core.bAlternateSetting == 0)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync break;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync }
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if (pIfState->pCurIfDesc)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync map_interface(pDev, pIfState->pCurIfDesc);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync }
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync pDev->pCurCfgDesc = pCfgDesc;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if (pCfgDesc->Core.bmAttributes & 0x40)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync pDev->u16Status |= (1 << VUSB_DEV_SELF_POWERED);
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync else
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync pDev->u16Status &= ~(1 << VUSB_DEV_SELF_POWERED);
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return true;
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync}
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync/**
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * Standard device request: SET_CONFIGURATION
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @returns success indicator.
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync */
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsyncstatic bool vusbDevStdReqSetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync{
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync unsigned iCfg = pSetup->wValue & 0xff;
95cb8e789c1eed6f2bb3195d0b996feee11d548evboxsync
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync {
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync Log(("vusb: error: %s: SET_CONFIGURATION - invalid request (dir) !!!\n", pDev->pUsbIns->pszName, iCfg));
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync return false;
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync }
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync /*
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync * Check that the device is in a valid state.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * (The caller has already checked that it's not being reset.)
19cb1f8699e352d590c4946caee33863a5157241vboxsync */
19cb1f8699e352d590c4946caee33863a5157241vboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if (enmState == VUSB_DEVICE_STATE_DEFAULT)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync {
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync LogFlow(("vusbDevStdReqSetConfig: %s: default dev state !!?\n", pDev->pUsbIns->pszName));
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync return false;
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync }
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync PCVUSBDESCCONFIGEX pNewCfgDesc = vusbDevFindCfgDesc(pDev, iCfg);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if (!pNewCfgDesc)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync {
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync Log(("vusb: error: %s: config %i not found !!!\n", pDev->pUsbIns->pszName, iCfg));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync return false;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (iCfg == 0)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync pDev->enmState = VUSB_DEVICE_STATE_ADDRESS;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync pDev->enmState = VUSB_DEVICE_STATE_CONFIGURED;
060f7ec6ae5c99df18341ef2e1f3e91f4b0c89f1vboxsync if (pDev->pUsbIns->pReg->pfnUsbSetConfiguration)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
cc74f15083bf80fbc96723a89faa06c15d0dead8vboxsync int rc = pDev->pUsbIns->pReg->pfnUsbSetConfiguration(pDev->pUsbIns, pNewCfgDesc->Core.bConfigurationValue,
a72b5355eb89aafe6bfcc8912cf02645d7cccceavboxsync pDev->pCurCfgDesc, pDev->paIfStates, pNewCfgDesc);
a72b5355eb89aafe6bfcc8912cf02645d7cccceavboxsync if (RT_FAILURE(rc))
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
6e25221ce8ef8e656d1e15eb7ec5cf8ae758ceb2vboxsync Log(("vusb: error: %s: failed to set config %i (%Rrc) !!!\n", pDev->pUsbIns->pszName, iCfg, rc));
3933885bc0c2c93436d858a14564c6179ec72872vboxsync return false;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
060f7ec6ae5c99df18341ef2e1f3e91f4b0c89f1vboxsync Log(("vusb: %p[%s]: SET_CONFIGURATION: Selected config %u\n", pDev, pDev->pUsbIns->pszName, iCfg));
9ca017ceee656f9d33f2cb6652e401b5f17fcfb7vboxsync return vusbDevDoSelectConfig(pDev, pNewCfgDesc);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync}
9601ea695ea96905d6f5d484facd272732365c40vboxsync
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync/**
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * Standard device request: GET_CONFIGURATION
f106b549ead77cab51ff1e2c116060aaabb90d5evboxsync * @returns success indicator.
f106b549ead77cab51ff1e2c116060aaabb90d5evboxsync */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic bool vusbDevStdReqGetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync{
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
23d9dbdaf1b83107abf9882246a4a46933f733efvboxsync {
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync Log(("vusb: error: %s: GET_CONFIGURATION - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync return false;
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync }
ad9e5a61fea617d40d07390ff1737277d6aef869vboxsync
dbabc9de5bf52ce5eb77cf82b038e9a6166c5a04vboxsync /*
4090390866c02d5d0ad061151cdb298b9a173e86vboxsync * Check that the device is in a valid state.
4090390866c02d5d0ad061151cdb298b9a173e86vboxsync * (The caller has already checked that it's not being reset.)
40dce69ff1c2949a489337922f30f1021d62d864vboxsync */
40dce69ff1c2949a489337922f30f1021d62d864vboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
40dce69ff1c2949a489337922f30f1021d62d864vboxsync if ( enmState != VUSB_DEVICE_STATE_CONFIGURED
40dce69ff1c2949a489337922f30f1021d62d864vboxsync && enmState != VUSB_DEVICE_STATE_ADDRESS)
40dce69ff1c2949a489337922f30f1021d62d864vboxsync {
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync LogFlow(("vusbDevStdReqGetConfig: error: %s: invalid device state %d!!!\n", pDev->pUsbIns->pszName, enmState));
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync return false;
f57758f0bcf995d350d64a7c059ac93573144c05vboxsync }
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync
f57758f0bcf995d350d64a7c059ac93573144c05vboxsync if (*pcbBuf < 1)
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync {
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync LogFlow(("vusbDevStdReqGetConfig: %s: no space for data!\n", pDev->pUsbIns->pszName));
5d57bcb78f1f3f918bd3daf709b551b8c2d30485vboxsync return true;
cccc6ee5f7156cfcdf13acca545cf65124d9ed44vboxsync }
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync uint8_t iCfg;
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync if (pDev->enmState == VUSB_DEVICE_STATE_ADDRESS)
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync iCfg = 0;
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync else
505ddd00252720bfb5569fcb17bfda53dc141e3bvboxsync iCfg = pDev->pCurCfgDesc->Core.bConfigurationValue;
505ddd00252720bfb5569fcb17bfda53dc141e3bvboxsync
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync *pbBuf = iCfg;
7708252d252a55417a6a817041e4356797e34255vboxsync *pcbBuf = 1;
7708252d252a55417a6a817041e4356797e34255vboxsync LogFlow(("vusbDevStdReqGetConfig: %s: returns iCfg=%d\n", pDev->pUsbIns->pszName, iCfg));
7708252d252a55417a6a817041e4356797e34255vboxsync return true;
904810c4c6668233349b025cc58013cb7c11c701vboxsync}
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Standard device request: GET_INTERFACE
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @returns success indicator.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync */
3933885bc0c2c93436d858a14564c6179ec72872vboxsyncstatic bool vusbDevStdReqGetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync{
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_INTERFACE)
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync {
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync Log(("vusb: error: %s: GET_INTERFACE - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync return false;
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync }
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /*
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync * Check that the device is in a valid state.
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync * (The caller has already checked that it's not being reset.)
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync {
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync LogFlow(("vusbDevStdReqGetInterface: error: %s: invalid device state %d!!!\n", pDev->pUsbIns->pszName, enmState));
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync return false;
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync }
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync if (*pcbBuf < 1)
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync {
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync LogFlow(("vusbDevStdReqGetInterface: %s: no space for data!\n", pDev->pUsbIns->pszName));
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync return true;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync for (unsigned i = 0; i < pDev->pCurCfgDesc->Core.bNumInterfaces; i++)
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync {
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync PCVUSBDESCINTERFACEEX pIfDesc = pDev->paIfStates[i].pCurIfDesc;
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync if ( pIfDesc
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync && pSetup->wIndex == pIfDesc->Core.bInterfaceNumber)
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync {
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync *pbBuf = pIfDesc->Core.bAlternateSetting;
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync *pcbBuf = 1;
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync Log(("vusb: %s: GET_INTERFACE: %u.%u\n", pDev->pUsbIns->pszName, pIfDesc->Core.bInterfaceNumber, *pbBuf));
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync return true;
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync }
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync }
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync Log(("vusb: error: %s: GET_INTERFACE - unknown iface %u !!!\n", pDev->pUsbIns->pszName, pSetup->wIndex));
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync return false;
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync}
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync/**
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync * Standard device request: SET_INTERFACE
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync * @returns success indicator.
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync */
48890ac9b4b339e0341e826b5c26ce6408729987vboxsyncstatic bool vusbDevStdReqSetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync{
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_INTERFACE)
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync {
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync Log(("vusb: error: %s: SET_INTERFACE - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync return false;
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync }
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync /*
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync * Check that the device is in a valid state.
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync * (The caller has already checked that it's not being reset.)
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync */
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync {
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync LogFlow(("vusbDevStdReqSetInterface: error: %s: invalid device state %d !!!\n", pDev->pUsbIns->pszName, enmState));
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync return false;
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync }
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync /*
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * Find the interface.
e446ce644a0cdc723be5146be1659f1206599c24vboxsync */
e446ce644a0cdc723be5146be1659f1206599c24vboxsync uint8_t iIf = pSetup->wIndex;
e446ce644a0cdc723be5146be1659f1206599c24vboxsync PVUSBINTERFACESTATE pIfState = vusbDevFindIfState(pDev, iIf);
e446ce644a0cdc723be5146be1659f1206599c24vboxsync if (!pIfState)
e446ce644a0cdc723be5146be1659f1206599c24vboxsync {
e446ce644a0cdc723be5146be1659f1206599c24vboxsync LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find interface %u !!!\n", pDev->pUsbIns->pszName, iIf));
e446ce644a0cdc723be5146be1659f1206599c24vboxsync return false;
e446ce644a0cdc723be5146be1659f1206599c24vboxsync }
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync uint8_t iAlt = pSetup->wValue;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync PCVUSBDESCINTERFACEEX pIfDesc = vusbDevFindAltIfDesc(pDev, pIfState, iAlt);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (!pIfDesc)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find alt interface %u.%u !!!\n", pDev->pUsbIns->pszName, iIf, iAlt));
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync return false;
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync }
c970e7d40b648d5c8f3e2b060692e670d85997d1vboxsync
c970e7d40b648d5c8f3e2b060692e670d85997d1vboxsync if (pDev->pUsbIns->pReg->pfnUsbSetInterface)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync int rc = pDev->pUsbIns->pReg->pfnUsbSetInterface(pDev->pUsbIns, iIf, iAlt);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync if (RT_FAILURE(rc))
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find alt interface %u.%u (%Rrc)\n", pDev->pUsbIns->pszName, iIf, iAlt, rc));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync return false;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync }
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync }
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync for (unsigned i = 0; i < pIfState->pCurIfDesc->Core.bNumEndpoints; i++)
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync unmap_endpoint(pDev, &pIfState->pCurIfDesc->paEndpoints[i]);
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync Log(("vusb: SET_INTERFACE: Selected %u.%u\n", iIf, iAlt));
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync map_interface(pDev, pIfDesc);
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsync pIfState->pCurIfDesc = pIfDesc;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return true;
f4e792b5d6ee04e9d93499b747cce21510c3cdb3vboxsync}
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/**
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Standard device request: SET_ADDRESS
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync * @returns success indicator.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncstatic bool vusbDevStdReqSetAddress(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync{
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync Log(("vusb: error: %s: SET_ADDRESS - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return false;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync }
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /*
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Check that the device is in a valid state.
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync * (The caller has already checked that it's not being reset.)
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync */
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync if ( enmState != VUSB_DEVICE_STATE_DEFAULT
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync && enmState != VUSB_DEVICE_STATE_ADDRESS)
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync {
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync LogFlow(("vusbDevStdReqSetAddress: error: %s: invalid device state %d !!!\n", pDev->pUsbIns->pszName, enmState));
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync return false;
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync }
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync pDev->u8NewAddress = pSetup->wValue;
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync return true;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync}
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync/**
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Standard device request: CLEAR_FEATURE
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @returns success indicator.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync *
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @remark This is only called for VUSB_TO_ENDPOINT && ep == 0 && wValue == ENDPOINT_HALT.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * All other cases of CLEAR_FEATURE is handled in the normal async/sync manner.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync */
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsyncstatic bool vusbDevStdReqClearFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync{
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync case VUSB_TO_DEVICE:
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Log(("vusb: ClearFeature: dev(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync break;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync case VUSB_TO_INTERFACE:
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync Log(("vusb: ClearFeature: iface(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync break;
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync case VUSB_TO_ENDPOINT:
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync Log(("vusb: ClearFeature: ep(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync if ( !EndPt /* Default control pipe only */
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync && pSetup->wValue == 0 /* ENDPOINT_HALT */
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync && pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint)
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync {
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync int rc = pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint(pDev->pUsbIns, pSetup->wIndex);
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync return RT_SUCCESS(rc);
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync }
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync break;
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync default:
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync AssertMsgFailed(("VUSB_TO_OTHER!\n"));
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync break;
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync }
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync AssertMsgFailed(("Invalid safe check !!!\n"));
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync return false;
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync}
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync/**
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync * Standard device request: SET_FEATURE
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync * @returns success indicator.
cedd207acc51a49839fdf51554fc19539ac68b4dvboxsync */
cedd207acc51a49839fdf51554fc19539ac68b4dvboxsyncstatic bool vusbDevStdReqSetFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync{
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync {
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync case VUSB_TO_DEVICE:
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync Log(("vusb: SetFeature: dev(%u): selector=%u\n",
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync pSetup->wIndex, pSetup->wValue));
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync break;
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync case VUSB_TO_INTERFACE:
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync Log(("vusb: SetFeature: if(%u): selector=%u\n",
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync pSetup->wIndex, pSetup->wValue));
361a7fb527903c8dbfd0cc7dc779f943c6e348f6vboxsync break;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync case VUSB_TO_ENDPOINT:
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync Log(("vusb: SetFeature: ep(%u): selector=%u\n",
6efcf94383d6e48c764c6518cf1b4069ad34e210vboxsync pSetup->wIndex, pSetup->wValue));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync break;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync default:
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync AssertMsgFailed(("VUSB_TO_OTHER!\n"));
b304856b23107864c9c594a80cebca6006623f31vboxsync return false;
b304856b23107864c9c594a80cebca6006623f31vboxsync }
b304856b23107864c9c594a80cebca6006623f31vboxsync AssertMsgFailed(("This stuff is bogus\n"));
b304856b23107864c9c594a80cebca6006623f31vboxsync return false;
b304856b23107864c9c594a80cebca6006623f31vboxsync}
b304856b23107864c9c594a80cebca6006623f31vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic bool vusbDevStdReqGetStatus(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync{
6efcf94383d6e48c764c6518cf1b4069ad34e210vboxsync if (*pcbBuf != 2)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync LogFlow(("vusbDevStdReqGetStatus: %s: buffer is too small! (%d)\n", pDev->pUsbIns->pszName, *pcbBuf));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return false;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync }
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync uint16_t u16Status;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync {
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync case VUSB_TO_DEVICE:
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync u16Status = pDev->u16Status;
3a0bc95d0adf57baefd303e94b8f1b7b31a8f080vboxsync LogFlow(("vusbDevStdReqGetStatus: %s: device status %#x (%d)\n", pDev->pUsbIns->pszName, u16Status, u16Status));
3a0bc95d0adf57baefd303e94b8f1b7b31a8f080vboxsync break;
3a0bc95d0adf57baefd303e94b8f1b7b31a8f080vboxsync case VUSB_TO_INTERFACE:
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync u16Status = 0;
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync LogFlow(("vusbDevStdReqGetStatus: %s: bogus interface status request!!\n", pDev->pUsbIns->pszName));
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync break;
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync case VUSB_TO_ENDPOINT:
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync u16Status = 0;
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync LogFlow(("vusbDevStdReqGetStatus: %s: bogus endpoint status request!!\n", pDev->pUsbIns->pszName));
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync break;
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync default:
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync AssertMsgFailed(("VUSB_TO_OTHER!\n"));
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync return false;
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync }
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync *(uint16_t *)pbBuf = u16Status;
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync return true;
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync}
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Finds a cached string.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @returns Pointer to the cached string if found. NULL if not.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param paLanguages The languages to search.
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync * @param cLanguages The number of languages in the table.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param idLang The language ID.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param iString The string index.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic PCPDMUSBDESCCACHESTRING FindCachedString(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLanguages,
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync uint16_t idLang, uint8_t iString)
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync{
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /** @todo binary lookups! */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync unsigned iCurLang = cLanguages;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync while (iCurLang-- > 0)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync if (paLanguages[iCurLang].idLang == idLang)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
f31ac84c1c57e23801423b5bd184fadabe6456f3vboxsync PCPDMUSBDESCCACHESTRING paStrings = paLanguages[iCurLang].paStrings;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync unsigned iCurStr = paLanguages[iCurLang].cStrings;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync while (iCurStr-- > 0)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (paStrings[iCurStr].idx == iString)
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync return &paStrings[iCurStr];
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync break;
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync }
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync return NULL;
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync}
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
36929067a9d3cba77fd78f1e8fa042ed3a8ae2d6vboxsync/** Macro for copying descriptor data. */
f31ac84c1c57e23801423b5bd184fadabe6456f3vboxsync#define COPY_DATA(pbDst, cbLeft, pvSrc, cbSrc) \
36929067a9d3cba77fd78f1e8fa042ed3a8ae2d6vboxsync do { \
36929067a9d3cba77fd78f1e8fa042ed3a8ae2d6vboxsync uint32_t cbSrc_ = cbSrc; \
36929067a9d3cba77fd78f1e8fa042ed3a8ae2d6vboxsync uint32_t cbCopy = RT_MIN(cbLeft, cbSrc_); \
5e0d1b28833a92e30446e95ced085bce4d794067vboxsync memcpy(pbBuf, pvSrc, cbCopy); \
5e0d1b28833a92e30446e95ced085bce4d794067vboxsync cbLeft -= cbCopy; \
5e0d1b28833a92e30446e95ced085bce4d794067vboxsync if (!cbLeft) \
5e0d1b28833a92e30446e95ced085bce4d794067vboxsync return; \
5e0d1b28833a92e30446e95ced085bce4d794067vboxsync pbBuf += cbCopy; \
5e0d1b28833a92e30446e95ced085bce4d794067vboxsync } while (0)
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync/**
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync * Internal function for reading the language IDs.
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync */
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsyncstatic void ReadCachedStringDesc(PCPDMUSBDESCCACHESTRING pString, uint8_t *pbBuf, uint32_t *pcbBuf)
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync{
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync uint32_t cbLeft = *pcbBuf;
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync RTUTF16 wsz[128]; /* 128-1 => bLength=0xff */
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync PRTUTF16 pwsz = wsz;
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync size_t cwc;
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync int rc = RTStrToUtf16Ex(pString->psz, RT_ELEMENTS(wsz) - 1, &pwsz, RT_ELEMENTS(wsz), &cwc);
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync if (RT_FAILURE(rc))
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync {
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync AssertRC(rc);
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync wsz[0] = 'e';
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync wsz[1] = 'r';
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync wsz[2] = 'r';
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync cwc = 3;
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync }
56343f236d9d7c0e3d2b75e23f0f5575dc77f2e3vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync VUSBDESCSTRING StringDesc;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync StringDesc.bLength = sizeof(StringDesc) + cwc * sizeof(RTUTF16);
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync StringDesc.bDescriptorType = VUSB_DT_STRING;
ab2292e9c32bd271ec91123ef38699a0284b72cbvboxsync COPY_DATA(pbBuf, cbLeft, &StringDesc, sizeof(StringDesc));
ab2292e9c32bd271ec91123ef38699a0284b72cbvboxsync COPY_DATA(pbBuf, cbLeft, wsz, cwc * sizeof(RTUTF16));
ab2292e9c32bd271ec91123ef38699a0284b72cbvboxsync
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync /* updated the size of the output buffer. */
121568d0a1e932e6f6acd49376827a0e593815favboxsync *pcbBuf -= cbLeft;
121568d0a1e932e6f6acd49376827a0e593815favboxsync}
121568d0a1e932e6f6acd49376827a0e593815favboxsync
121568d0a1e932e6f6acd49376827a0e593815favboxsync
121568d0a1e932e6f6acd49376827a0e593815favboxsync/**
121568d0a1e932e6f6acd49376827a0e593815favboxsync * Internal function for reading the language IDs.
121568d0a1e932e6f6acd49376827a0e593815favboxsync */
121568d0a1e932e6f6acd49376827a0e593815favboxsyncstatic void ReadCachedLangIdDesc(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLanguages,
121568d0a1e932e6f6acd49376827a0e593815favboxsync uint8_t *pbBuf, uint32_t *pcbBuf)
121568d0a1e932e6f6acd49376827a0e593815favboxsync{
121568d0a1e932e6f6acd49376827a0e593815favboxsync uint32_t cbLeft = *pcbBuf;
121568d0a1e932e6f6acd49376827a0e593815favboxsync
121568d0a1e932e6f6acd49376827a0e593815favboxsync VUSBDESCLANGID LangIdDesc;
f31ac84c1c57e23801423b5bd184fadabe6456f3vboxsync size_t cbDesc = sizeof(LangIdDesc) + cLanguages * sizeof(paLanguages[0].idLang);
121568d0a1e932e6f6acd49376827a0e593815favboxsync LangIdDesc.bLength = RT_MIN(0xff, cbDesc);
121568d0a1e932e6f6acd49376827a0e593815favboxsync LangIdDesc.bDescriptorType = VUSB_DT_STRING;
121568d0a1e932e6f6acd49376827a0e593815favboxsync COPY_DATA(pbBuf, cbLeft, &LangIdDesc, sizeof(LangIdDesc));
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync unsigned iLanguage = cLanguages;
f31ac84c1c57e23801423b5bd184fadabe6456f3vboxsync while (iLanguage-- > 0)
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync COPY_DATA(pbBuf, cbLeft, &paLanguages[iLanguage].idLang, sizeof(paLanguages[iLanguage].idLang));
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync /* updated the size of the output buffer. */
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync *pcbBuf -= cbLeft;
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync}
f31ac84c1c57e23801423b5bd184fadabe6456f3vboxsync
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync/**
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync * Internal function which performs a descriptor read on the cached descriptors.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsyncstatic void ReadCachedConfigDesc(PCVUSBDESCCONFIGEX pCfgDesc, uint8_t *pbBuf, uint32_t *pcbBuf)
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync{
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync uint32_t cbLeft = *pcbBuf;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/** @todo See @bugref{2693} */
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync /*
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync * Make a copy of the config descriptor and calculate the wTotalLength field.
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync */
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync VUSBDESCCONFIG CfgDesc;
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync memcpy(&CfgDesc, pCfgDesc, VUSB_DT_CONFIG_MIN_LEN);
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync uint32_t cbTotal = pCfgDesc->Core.bLength;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync for (unsigned i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync PCVUSBINTERFACE pIf = &pCfgDesc->paIfs[i];
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync for (uint32_t j = 0; j < pIf->cSettings; j++)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync cbTotal += pIf->paSettings[j].Core.bLength;
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync cbTotal += pIf->paSettings[j].cbClass;
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync for (unsigned k = 0; k < pIf->paSettings[j].Core.bNumEndpoints; k++)
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync {
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync cbTotal += pIf->paSettings[j].paEndpoints[k].Core.bLength;
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync cbTotal += pIf->paSettings[j].paEndpoints[k].cbClass;
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync }
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync }
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync }
6efcf94383d6e48c764c6518cf1b4069ad34e210vboxsync CfgDesc.wTotalLength = RT_H2LE_U16(cbTotal);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /*
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Copy the config descriptor
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync */
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync COPY_DATA(pbBuf, cbLeft, &CfgDesc, VUSB_DT_CONFIG_MIN_LEN);
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync COPY_DATA(pbBuf, cbLeft, pCfgDesc->pvMore, pCfgDesc->Core.bLength - VUSB_DT_CONFIG_MIN_LEN);
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync /*
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync * Copy out all the interfaces for this configuration
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync */
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync for (unsigned i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync {
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync PCVUSBINTERFACE pIf = &pCfgDesc->paIfs[i];
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync for (uint32_t j = 0; j < pIf->cSettings; j++)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync {
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync PCVUSBDESCINTERFACEEX pIfDesc = &pIf->paSettings[j];
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync COPY_DATA(pbBuf, cbLeft, pIfDesc, VUSB_DT_INTERFACE_MIN_LEN);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync COPY_DATA(pbBuf, cbLeft, pIfDesc->pvMore, pIfDesc->Core.bLength - VUSB_DT_INTERFACE_MIN_LEN);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync COPY_DATA(pbBuf, cbLeft, pIfDesc->pvClass, pIfDesc->cbClass);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync /*
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync * Copy out all the endpoints for this interface
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync */
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync for (unsigned k = 0; k < pIfDesc->Core.bNumEndpoints; k++)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync {
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync VUSBDESCENDPOINT EndPtDesc;
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync memcpy(&EndPtDesc, &pIfDesc->paEndpoints[k], VUSB_DT_ENDPOINT_MIN_LEN);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync EndPtDesc.wMaxPacketSize = RT_H2LE_U16(EndPtDesc.wMaxPacketSize);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync
d6f9950e2cf4ba7fd217c083400d9812ff745374vboxsync COPY_DATA(pbBuf, cbLeft, &EndPtDesc, VUSB_DT_ENDPOINT_MIN_LEN);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvMore, EndPtDesc.bLength - VUSB_DT_ENDPOINT_MIN_LEN);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvClass, pIfDesc->paEndpoints[k].cbClass);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync }
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync }
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync }
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync /* updated the size of the output buffer. */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync *pcbBuf -= cbLeft;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync}
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync/**
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * Internal function which performs a descriptor read on the cached descriptors.
ae94ad7e769e467419ab99cab5403bdb39bc544fvboxsync */
ae94ad7e769e467419ab99cab5403bdb39bc544fvboxsyncstatic void ReadCachedDeviceDesc(PCVUSBDESCDEVICE pDevDesc, uint8_t *pbBuf, uint32_t *pcbBuf)
ae94ad7e769e467419ab99cab5403bdb39bc544fvboxsync{
ae94ad7e769e467419ab99cab5403bdb39bc544fvboxsync uint32_t cbLeft = *pcbBuf;
ae94ad7e769e467419ab99cab5403bdb39bc544fvboxsync
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync /*
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * Duplicate the device description and update some fields we keep in cpu type.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync Assert(sizeof(VUSBDESCDEVICE) == 18);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync VUSBDESCDEVICE DevDesc = *pDevDesc;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync DevDesc.bcdUSB = RT_H2LE_U16(DevDesc.bcdUSB);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync DevDesc.idVendor = RT_H2LE_U16(DevDesc.idVendor);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync DevDesc.idProduct = RT_H2LE_U16(DevDesc.idProduct);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync DevDesc.bcdDevice = RT_H2LE_U16(DevDesc.bcdDevice);
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync
6efcf94383d6e48c764c6518cf1b4069ad34e210vboxsync COPY_DATA(pbBuf, cbLeft, &DevDesc, sizeof(DevDesc));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync COPY_DATA(pbBuf, cbLeft, pDevDesc + 1, pDevDesc->bLength - sizeof(DevDesc));
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* updated the size of the output buffer. */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync *pcbBuf -= cbLeft;
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync}
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync#undef COPY_DATA
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * Standard device request: GET_DESCRIPTOR
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @returns success indicator.
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync * @remark not really used yet as we consider GET_DESCRIPTOR 'safe'.
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync */
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsyncstatic bool vusbDevStdReqGetDescriptor(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync{
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_DEVICE)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync switch (pSetup->wValue >> 8)
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync {
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync case VUSB_DT_DEVICE:
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync ReadCachedDeviceDesc(pDev->pDescCache->pDevice, pbBuf, pcbBuf);
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of device descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return true;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync case VUSB_DT_CONFIG:
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync unsigned int iIndex = (pSetup->wValue & 0xff);
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync if (iIndex >= pDev->pDescCache->pDevice->bNumConfigurations)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync LogFlow(("vusbDevStdReqGetDescriptor: %s: iIndex=%p >= bNumConfigurations=%d !!!\n",
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync pDev->pUsbIns->pszName, iIndex, pDev->pDescCache->pDevice->bNumConfigurations));
fc5f879e9508f333e20b37c63db9189a33059308vboxsync return false;
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync }
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync ReadCachedConfigDesc(&pDev->pDescCache->paConfigs[iIndex], pbBuf, pcbBuf);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of config descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return true;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync }
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync case VUSB_DT_STRING:
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (pSetup->wIndex == 0)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync ReadCachedLangIdDesc(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages, pbBuf, pcbBuf);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of language ID (string) descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return true;
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync }
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync PCPDMUSBDESCCACHESTRING pString;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync pString = FindCachedString(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages,
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync pSetup->wIndex, pSetup->wValue & 0xff);
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync if (pString)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync {
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync ReadCachedStringDesc(pString, pbBuf, pcbBuf);
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of string descriptors \"%s\"\n",
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync pDev->pUsbIns->pszName, *pcbBuf, pString->psz));
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync return true;
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync }
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync break;
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync }
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync default:
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync break;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync }
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync Log(("vusb: %s: warning: unknown descriptor: type=%u descidx=%u lang=%u len=%u!!!\n",
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->pUsbIns->pszName, pSetup->wValue >> 8, pSetup->wValue & 0xff, pSetup->wIndex, pSetup->wLength));
1c6ec9a3a329da6f61978a372e509cd233f0d9f9vboxsync return false;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync}
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync/**
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Service the standard USB requests.
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync *
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Devices may call this from controlmsg() if you want vusb core to handle your standard
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * request, it's not necessary - you could handle them manually
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @param pDev The device.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param EndPoint The endpoint.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @param pSetup Pointer to the setup request structure.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pvBuf Buffer?
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * @param pcbBuf ?
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsyncbool vusbDevStandardRequest(PVUSBDEV pDev, int EndPoint, PVUSBSETUP pSetup, void *pvBuf, uint32_t *pcbBuf)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync{
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync static bool (* const s_apfnStdReq[VUSB_REQ_MAX])(PVUSBDEV, int, PVUSBSETUP, uint8_t *, uint32_t *) =
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync vusbDevStdReqGetStatus,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync vusbDevStdReqClearFeature,
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync NULL,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync vusbDevStdReqSetFeature,
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync NULL,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync vusbDevStdReqSetAddress,
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync vusbDevStdReqGetDescriptor,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync NULL,
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync vusbDevStdReqGetConfig,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync vusbDevStdReqSetConfig,
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync vusbDevStdReqGetInterface,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync vusbDevStdReqSetInterface,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync NULL /* for iso */
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync };
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /*
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Check that the device is in a valid state.
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync */
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync VUSBDEV_ASSERT_VALID_STATE(enmState);
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync if (enmState == VUSB_DEVICE_STATE_RESET)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
7922c4cd397713a387c9e854e74c31a0d5065365vboxsync LogRel(("VUSB: %s: standard control message ignored, the device is resetting\n", pDev->pUsbIns->pszName));
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync return false;
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync }
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /*
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * Do the request if it's one we want to deal with.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync */
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync if ( pSetup->bRequest >= VUSB_REQ_MAX
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync || !s_apfnStdReq[pSetup->bRequest])
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync {
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync Log(("vusb: warning: standard req not implemented: message %u: val=%u idx=%u len=%u !!!\n",
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync return false;
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync }
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync return s_apfnStdReq[pSetup->bRequest](pDev, EndPoint, pSetup, (uint8_t *)pvBuf, pcbBuf);
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync}
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync/**
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * Add a device to the address hash
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync */
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsyncstatic void vusbDevAddressHash(PVUSBDEV pDev)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync{
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync if (pDev->u8Address == VUSB_INVALID_ADDRESS)
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync return;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync uint8_t u8Hash = vusbHashAddress(pDev->u8Address);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync pDev->pNextHash = pDev->pHub->pRootHub->apAddrHash[u8Hash];
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pHub->pRootHub->apAddrHash[u8Hash] = pDev;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync}
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync * Remove a device from the address hash
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync */
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsyncstatic void vusbDevAddressUnHash(PVUSBDEV pDev)
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync{
67e7d53d62514401efcd0e7a34f5faf772a3fe04vboxsync if (pDev->u8Address == VUSB_INVALID_ADDRESS)
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync return;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync uint8_t u8Hash = vusbHashAddress(pDev->u8Address);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync pDev->u8Address = VUSB_INVALID_ADDRESS;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync PVUSBDEV pCur = pDev->pHub->pRootHub->apAddrHash[u8Hash];
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (pCur == pDev)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* special case, we're at the head */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pHub->pRootHub->apAddrHash[u8Hash] = pDev->pNextHash;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pNextHash = NULL;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync else
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /* search the list */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync PVUSBDEV pPrev;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync for (pPrev = pCur, pCur = pCur->pNextHash;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pCur;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pPrev = pCur, pCur = pCur->pNextHash)
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (pCur == pDev)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pPrev->pNextHash = pCur->pNextHash;
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync pDev->pNextHash = NULL;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync break;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync }
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync}
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Sets the address of a device.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync * Called by status_completion() and vusbDevResetWorker().
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncvoid vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync{
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync LogFlow(("vusbDevSetAddress: pDev=%p[%s]/%i u8Address=%#x\n",
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev, pDev->pUsbIns->pszName, pDev->i16Port, u8Address));
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /*
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Check that the device is in a valid state.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync VUSBDEV_ASSERT_VALID_STATE(enmState);
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync if ( enmState == VUSB_DEVICE_STATE_ATTACHED
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync || enmState == VUSB_DEVICE_STATE_DETACHED)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync LogFlow(("vusbDevSetAddress: %s: fails because %d < POWERED\n", pDev->pUsbIns->pszName, pDev->enmState));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return;
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (enmState == VUSB_DEVICE_STATE_RESET)
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync LogRel(("VUSB: %s: set address ignored, the device is resetting\n", pDev->pUsbIns->pszName));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync }
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync /*
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Ok, get on with it.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync if (pDev->u8Address == u8Address)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync return;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (pDev->u8Address == VUSB_DEFAULT_ADDRESS)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pRh->pDefaultAddress = NULL;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync vusbDevAddressUnHash(pDev);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync if (u8Address == VUSB_DEFAULT_ADDRESS)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (pRh->pDefaultAddress != NULL)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync vusbDevAddressUnHash(pRh->pDefaultAddress);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync pRh->pDefaultAddress->enmState = VUSB_DEVICE_STATE_POWERED;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync Log(("2 DEFAULT ADDRS\n"));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync }
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pRh->pDefaultAddress = pDev;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->enmState = VUSB_DEVICE_STATE_DEFAULT;
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync }
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync else
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync pDev->enmState = VUSB_DEVICE_STATE_ADDRESS;
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync
67e7d53d62514401efcd0e7a34f5faf772a3fe04vboxsync pDev->u8Address = u8Address;
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync vusbDevAddressHash(pDev);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync Log(("vusb: %p[%s]/%i: Assigned address %u\n",
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync pDev, pDev->pUsbIns->pszName, pDev->i16Port, u8Address));
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync}
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Cancels and completes (with CRC failure) all async URBs pending
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * on a device. This is typically done as part of a reset and
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * before detaching a device.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync *
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param fDetaching If set, we will unconditionally unlink (and leak)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * any URBs which isn't reaped.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncstatic void vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync{
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /*
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync * Iterate the URBs and cancel them.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync PVUSBURB pUrb = pRh->pAsyncUrbHead;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync while (pUrb)
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync PVUSBURB pNext = pUrb->VUsb.pNext;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (pUrb->VUsb.pDev == pDev)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync LogFlow(("%s: vusbDevCancelAllUrbs: CANCELING URB\n", pUrb->pszDesc));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync vusbUrbCancel(pUrb, CANCELMODE_FAIL);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync }
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync pUrb = pNext;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /*
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Reap any URBs which became ripe during cancel now.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync unsigned cReaped;
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync do
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync cReaped = 0;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pUrb = pRh->pAsyncUrbHead;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync while (pUrb)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync PVUSBURB pNext = pUrb->VUsb.pNext;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (pUrb->VUsb.pDev == pDev)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync PVUSBURB pRipe = NULL;
e214bb78026c1d64078b34ca9504d3f5abbc52efvboxsync if (pUrb->enmState == VUSBURBSTATE_REAPED)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pRipe = pUrb;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync else if (pUrb->enmState == VUSBURBSTATE_CANCELLED)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync#ifdef RT_OS_WINDOWS /** @todo Windows doesn't do cancelling, thus this kludge to prevent really bad
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * things from happening if we leave a pending URB behinds. */
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, fDetaching ? 1500 : 0 /*ms*/);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync#else
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, fDetaching ? 10 : 0 /*ms*/);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync#endif
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync else
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync AssertMsgFailed(("pUrb=%p enmState=%d\n", pUrb, pUrb->enmState));
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync if (pRipe)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (pRipe == pNext)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pNext = pNext->VUsb.pNext;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync vusbUrbRipe(pRipe);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync cReaped++;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync }
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pUrb = pNext;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync }
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync } while (cReaped > 0);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync /*
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * If we're detaching, we'll have to orphan any leftover URBs.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (fDetaching)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pUrb = pRh->pAsyncUrbHead;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync while (pUrb)
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync PVUSBURB pNext = pUrb->VUsb.pNext;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (pUrb->VUsb.pDev == pDev)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync {
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync AssertMsgFailed(("%s: Leaking left over URB! state=%d pDev=%p[%s]\n",
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pUrb->pszDesc, pUrb->enmState, pDev, pDev->pUsbIns->pszName));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync vusbUrbUnlink(pUrb);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync }
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync pUrb = pNext;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync }
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync}
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/**
fc148a6b23d25a87561beaffe0ba06c3ba93bf5avboxsync * Detaches a device from the hub it's attached to.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @returns VBox status code.
794c574111980e7fb3a86847e5495156afa13134vboxsync * @param pDev The device to detach.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @remark This can be called in any state but reset.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsyncint vusbDevDetach(PVUSBDEV pDev)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync{
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("vusbDevDetach: pDev=%p[%s] enmState=%#x\n", pDev, pDev->pUsbIns->pszName, pDev->enmState));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Assert(pDev->enmState != VUSB_DEVICE_STATE_RESET);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync vusbDevCancelAllUrbs(pDev, true);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync vusbDevAddressUnHash(pDev);
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (!pRh)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync AssertMsgFailedReturn(("Not attached!\n"), VERR_VUSB_DEVICE_NOT_ATTACHED);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (pRh->pDefaultAddress == pDev)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync pRh->pDefaultAddress = NULL;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pHub->pOps->pfnDetach(pDev->pHub, pDev);
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync pDev->i16Port = -1;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pHub = NULL;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /* Remove the configuration */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->pCurCfgDesc = NULL;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync for (unsigned i = 0; i < VUSB_PIPE_MAX; i++)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync vusbMsgFreeExtraData(pDev->aPipes[i].pCtrl);
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync memset(pDev->aPipes, 0, sizeof(pDev->aPipes));
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync return VINF_SUCCESS;
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync}
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync/**
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Destroys a device, detaching it from the hub if necessary.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pDev The device.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @thread EMT
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsyncvoid vusbDevDestroy(PVUSBDEV pDev)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync{
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync LogFlow(("vusbDevDestroy: pDev=%p[%s] enmState=%d\n", pDev, pDev->pUsbIns->pszName, pDev->enmState));
d107911787df36a78788a841b73d24da896d02f6vboxsync
d107911787df36a78788a841b73d24da896d02f6vboxsync /*
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Deal with pending async reset.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync if (pDev->enmState == VUSB_DEVICE_STATE_RESET)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync {
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync Assert(pDev->pvResetArgs && pDev->hResetThread != NIL_RTTHREAD);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync int rc = RTThreadWait(pDev->hResetThread, 5000, NULL);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync AssertRC(rc);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (RT_SUCCESS(rc))
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync PVUSBRESETARGS pArgs = (PVUSBRESETARGS)pDev->pvResetArgs;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Assert(pArgs->pDev == pDev);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync RTMemTmpFree(pArgs);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->hResetThread = NIL_RTTHREAD;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pvResetArgs = NULL;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->enmState = VUSB_DEVICE_STATE_DEFAULT; /* anything but reset */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync }
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /*
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Detach and free resources.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (pDev->pHub)
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync vusbDevDetach(pDev);
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync RTMemFree(pDev->paIfStates);
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync pDev->enmState = VUSB_DEVICE_STATE_DESTROYED;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync TMR3TimerDestroy(pDev->pResetTimer);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync}
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/* -=-=-=-=-=- VUSBIDEVICE methods -=-=-=-=-=- */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
794c574111980e7fb3a86847e5495156afa13134vboxsync * Perform the actual reset.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @thread EMT or a VUSB reset thread.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsyncstatic int vusbDevResetWorker(PVUSBDEV pDev, bool fResetOnLinux)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync{
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync int rc = VINF_SUCCESS;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync if (pDev->pUsbIns->pReg->pfnUsbReset)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync rc = pDev->pUsbIns->pReg->pfnUsbReset(pDev->pUsbIns, fResetOnLinux);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("vusbDevResetWorker: %s: returns %Rrc\n", pDev->pUsbIns->pszName, rc));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return rc;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync}
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync/**
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync * The actual reset has been done, do completion on EMT.
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync *
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync * There are several things we have to do now, like set default
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync * config and address, and cleanup the state of control pipes.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * It's possible that the device has a delayed destroy request
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * pending when we get here. This can happen for async resetting.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * We deal with it here, since we're now executing on the EMT
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * thread and the destruction will be properly serialized now.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pDev The device that is being reset.
d107911787df36a78788a841b73d24da896d02f6vboxsync * @param rc The vusbDevResetWorker return code.
d107911787df36a78788a841b73d24da896d02f6vboxsync * @param pfnDone The done callback specified by the caller of vusbDevReset().
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pvUser The user argument for the callback.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncstatic void vusbDevResetDone(PVUSBDEV pDev, int rc, PFNVUSBRESETDONE pfnDone, void *pvUser)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync{
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync Assert(pDev->enmState == VUSB_DEVICE_STATE_RESET);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /*
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * Do control pipe cleanup regardless of state and result.
e446ce644a0cdc723be5146be1659f1206599c24vboxsync */
e446ce644a0cdc723be5146be1659f1206599c24vboxsync for (unsigned i = 0; i < VUSB_PIPE_MAX; i++)
e446ce644a0cdc723be5146be1659f1206599c24vboxsync if (pDev->aPipes[i].pCtrl)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync vusbMsgResetExtraData(pDev->aPipes[i].pCtrl);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /*
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Switch to the default state.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->enmState = VUSB_DEVICE_STATE_DEFAULT;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->u16Status = 0;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync vusbDevDoSelectConfig(pDev, &g_Config0);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (!vusbDevIsRh(pDev))
e446ce644a0cdc723be5146be1659f1206599c24vboxsync vusbDevSetAddress(pDev, VUSB_DEFAULT_ADDRESS);
e446ce644a0cdc723be5146be1659f1206599c24vboxsync if (pfnDone)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pfnDone(&pDev->IDevice, rc, pvUser);
e446ce644a0cdc723be5146be1659f1206599c24vboxsync}
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync * Timer callback for doing reset completion.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pUsbIns The USB device instance.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pTimer The timer instance.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param pvUser The VUSB device data.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @thread EMT
e446ce644a0cdc723be5146be1659f1206599c24vboxsync */
e446ce644a0cdc723be5146be1659f1206599c24vboxsyncstatic DECLCALLBACK(void) vusbDevResetDoneTimer(PPDMUSBINS pUsbIns, PTMTIMER pTimer, void *pvUser)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync{
e446ce644a0cdc723be5146be1659f1206599c24vboxsync PVUSBDEV pDev = (PVUSBDEV)pvUser;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync PVUSBRESETARGS pArgs = (PVUSBRESETARGS)pDev->pvResetArgs;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync AssertPtr(pArgs); Assert(pArgs->pDev == pDev); Assert(pDev->pUsbIns == pUsbIns);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /*
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Release the thread and update the device structure.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync int rc = RTThreadWait(pDev->hResetThread, 2, NULL);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync AssertRC(rc);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pDev->hResetThread = NIL_RTTHREAD;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pDev->pvResetArgs = NULL;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /*
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Reset-done processing and cleanup.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync vusbDevResetDone(pArgs->pDev, pArgs->rc, pArgs->pfnDone, pArgs->pvUser);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync RTMemTmpFree(pArgs);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync}
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync/**
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Thread function for performing an async reset.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync *
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * This will pass the argument packet back to EMT upon completion
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * by means of a one shot timer.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync *
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @returns whatever vusbDevResetWorker() returns.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param Thread This thread.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param pvUser Pointer to a VUSBRESETARGS structure.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsyncstatic DECLCALLBACK(int) vusbDevResetThread(RTTHREAD Thread, void *pvUser)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync{
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync PVUSBRESETARGS pArgs = (PVUSBRESETARGS)pvUser;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync PVUSBDEV pDev = pArgs->pDev;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("vusb: reset thread started\n"));
e446ce644a0cdc723be5146be1659f1206599c24vboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync /*
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Tell EMT that we're in flow and then perform the reset.
e446ce644a0cdc723be5146be1659f1206599c24vboxsync */
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync uint64_t u64EndTS = TMTimerGet(pDev->pResetTimer) + TMTimerFromMilli(pDev->pResetTimer, 10);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync RTThreadUserSignal(Thread);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync int rc = pArgs->rc = vusbDevResetWorker(pDev, pArgs->fResetOnLinux);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /*
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * We use a timer to communicate the result back to EMT.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * This avoids suspend + poweroff issues, and it should give
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * us more accurate scheduling than making this thread sleep.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync int rc2 = TMTimerSet(pDev->pResetTimer, u64EndTS);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync AssertReleaseRC(rc2);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync LogFlow(("vusb: reset thread exiting, rc=%Rrc\n", rc));
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync return rc;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync}
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync/**
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Resets a device.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync *
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync * Since a device reset shall take at least 10ms from the guest point of view,
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * it must be performed asynchronously. We create a thread which performs this
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync * operation and ensures it will take at least 10ms.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * At times - like init - a synchronous reset is required, this can be done
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * by passing NULL for pfnDone.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync *
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @returns VBox status code.
6c1f3eb64096421b9ba7272f297bac6ff3d29fe7vboxsync *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pDev Pointer to the VUSB device interface.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param fResetOnLinux Whether it's safe to reset the device(s) on a linux
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * host system. See discussion of logical reconnects elsewhere.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pfnDone Pointer to the completion routine. If NULL a synchronous
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * reset is preformed not respecting the 10ms.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @param pVM Pointer to the VM handle for performing the done function
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * on the EMT thread.
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * @thread EMT
e446ce644a0cdc723be5146be1659f1206599c24vboxsync */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncDECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
e446ce644a0cdc723be5146be1659f1206599c24vboxsync{
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync PVUSBDEV pDev = (PVUSBDEV)pDevice;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Assert(!pfnDone || pVM);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("vusb: reset: [%s]/%i\n", pDev->pUsbIns->pszName, pDev->i16Port));
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /*
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Only one reset operation at a time.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync VUSBDEV_ASSERT_VALID_STATE(enmState);
e446ce644a0cdc723be5146be1659f1206599c24vboxsync if (enmState == VUSB_DEVICE_STATE_RESET)
e446ce644a0cdc723be5146be1659f1206599c24vboxsync {
f8df398d066204e2bf0ba209ea3554fc113fb484vboxsync LogRel(("VUSB: %s: reset request is ignored, the device is already resetting!\n", pDev->pUsbIns->pszName));
e446ce644a0cdc723be5146be1659f1206599c24vboxsync return VERR_VUSB_DEVICE_IS_RESETTING;
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync }
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync pDev->enmState = VUSB_DEVICE_STATE_RESET;
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync /*
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync * First, cancel all async URBs.
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync */
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync vusbDevCancelAllUrbs(pDev, false);
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync /* Async or sync? */
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync if (pfnDone)
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync {
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync /*
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync * Async fashion.
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync */
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync PVUSBRESETARGS pArgs = (PVUSBRESETARGS)RTMemTmpAlloc(sizeof(*pArgs));
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync if (pArgs)
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync {
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync pDev->pvResetArgs = pArgs;
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync pArgs->pDev = pDev;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync pArgs->fResetOnLinux = fResetOnLinux;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync pArgs->rc = VERR_INTERNAL_ERROR;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync pArgs->pfnDone = pfnDone;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync pArgs->pvUser = pvUser;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync int rc = RTThreadCreate(&pDev->hResetThread, vusbDevResetThread, pArgs, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "USBRESET");
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync if (RT_SUCCESS(rc))
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync {
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync /* give the thread a chance to get started. */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync RTThreadUserWait(pDev->hResetThread, 2);
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync return rc;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync }
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync pDev->pvResetArgs = NULL;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync pDev->hResetThread = NIL_RTTHREAD;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync RTMemTmpFree(pArgs);
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync }
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync /* fall back to sync on failure */
e446ce644a0cdc723be5146be1659f1206599c24vboxsync }
e446ce644a0cdc723be5146be1659f1206599c24vboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync /*
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync * Sync fashion.
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync */
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync int rc = vusbDevResetWorker(pDev, fResetOnLinux);
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync vusbDevResetDone(pDev, rc, pfnDone, pvUser);
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync return rc;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync}
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync/**
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * Powers on the device.
e446ce644a0cdc723be5146be1659f1206599c24vboxsync *
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * @returns VBox status code.
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * @param pInterface Pointer to the device interface structure.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync */
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsyncDECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync{
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync PVUSBDEV pDev = (PVUSBDEV)pInterface;
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync LogFlow(("vusbDevPowerOn: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync /*
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * Check that the device is in a valid state.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync */
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync VUSBDEV_ASSERT_VALID_STATE(enmState);
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync if (enmState == VUSB_DEVICE_STATE_DETACHED)
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync {
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync Log(("vusb: warning: attempt to power on detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync return VERR_VUSB_DEVICE_NOT_ATTACHED;
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync }
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync if (enmState == VUSB_DEVICE_STATE_RESET)
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync {
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync LogRel(("VUSB: %s: power on ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync return VERR_VUSB_DEVICE_IS_RESETTING;
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync }
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync /*
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * Do the job.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync */
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync if (enmState == VUSB_DEVICE_STATE_ATTACHED)
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync pDev->enmState = VUSB_DEVICE_STATE_POWERED;
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return VINF_SUCCESS;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync}
e446ce644a0cdc723be5146be1659f1206599c24vboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync/**
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * Powers off the device.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync *
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @returns VBox status code.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pInterface Pointer to the device interface structure.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsyncDECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync{
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync PVUSBDEV pDev = (PVUSBDEV)pInterface;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync LogFlow(("vusbDevPowerOff: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /*
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Check that the device is in a valid state.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync VUSBDEV_ASSERT_VALID_STATE(enmState);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync if (enmState == VUSB_DEVICE_STATE_DETACHED)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync Log(("vusb: warning: attempt to power off detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync return VERR_VUSB_DEVICE_NOT_ATTACHED;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync }
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync if (enmState == VUSB_DEVICE_STATE_RESET)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync return VERR_VUSB_DEVICE_IS_RESETTING;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync }
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /*
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * If it's a root hub, we will have to cancel all URBs and reap them.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync if (vusbDevIsRh(pDev))
14650dbf3041b8fcb092b55cf673bd6f392390c2vboxsync {
04c6e2bf4c47aa33be5ee50ac468b1b86b7125b4vboxsync PVUSBROOTHUB pRh = (PVUSBROOTHUB)pDev;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync VUSBIRhCancelAllUrbs(&pRh->IRhConnector);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync VUSBIRhReapAsyncUrbs(&pRh->IRhConnector, 0);
14650dbf3041b8fcb092b55cf673bd6f392390c2vboxsync }
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync pDev->enmState = VUSB_DEVICE_STATE_ATTACHED;
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync return VINF_SUCCESS;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync}
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync/**
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync * Get the state of the device.
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync *
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync * @returns Device state.
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync * @param pInterface Pointer to the device interface structure.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsyncDECLCALLBACK(VUSBDEVICESTATE) vusbDevGetState(PVUSBIDEVICE pInterface)
6c1f3eb64096421b9ba7272f297bac6ff3d29fe7vboxsync{
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync return ((PVUSBDEV)pInterface)->enmState;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync}
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/**
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * The maximum number of interfaces the device can have in all of it's configuration.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync *
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * @returns Number of interfaces.
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * @param pDev The device.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
e446ce644a0cdc723be5146be1659f1206599c24vboxsyncsize_t vusbDevMaxInterfaces(PVUSBDEV pDev)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync{
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync uint8_t cMax = 0;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync unsigned i = pDev->pDescCache->pDevice->bNumConfigurations;
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync while (i-- > 0)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync {
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (pDev->pDescCache->paConfigs[i].Core.bNumInterfaces > cMax)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync cMax = pDev->pDescCache->paConfigs[i].Core.bNumInterfaces;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync }
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync return cMax;
e446ce644a0cdc723be5146be1659f1206599c24vboxsync}
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync/**
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Initialize a new VUSB device.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync *
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @returns VBox status code.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @param pDev The VUSB device to initialize.
9bb98d54790a98dad0ad6d9bdc5d319b6fdf0bffvboxsync * @param pUsbIns Pointer to the PDM USB Device instance.
56349fc0a23f96f82208016f8f59f8377bb284b1vboxsync */
9bb98d54790a98dad0ad6d9bdc5d319b6fdf0bffvboxsyncint vusbDevInit(PVUSBDEV pDev, PPDMUSBINS pUsbIns)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync{
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /*
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Initialize the device data members.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * (All that are Non-Zero at least.)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync Assert(!pDev->IDevice.pfnReset);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->IDevice.pfnReset = vusbDevReset;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync Assert(!pDev->IDevice.pfnPowerOn);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->IDevice.pfnPowerOn = vusbDevPowerOn;
e446ce644a0cdc723be5146be1659f1206599c24vboxsync Assert(!pDev->IDevice.pfnPowerOff);
e446ce644a0cdc723be5146be1659f1206599c24vboxsync pDev->IDevice.pfnPowerOff = vusbDevPowerOff;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Assert(!pDev->IDevice.pfnGetState);
e446ce644a0cdc723be5146be1659f1206599c24vboxsync pDev->IDevice.pfnGetState = vusbDevGetState;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pDev->pUsbIns = pUsbIns;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pNext = NULL;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pNextHash = NULL;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pDev->pHub = NULL;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->u8Address = VUSB_INVALID_ADDRESS;
56349fc0a23f96f82208016f8f59f8377bb284b1vboxsync pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->i16Port = -1;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->u16Status = 0;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->pDescCache = NULL;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pDev->pCurCfgDesc = NULL;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->paIfStates = NULL;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync memset(&pDev->aPipes[0], 0, sizeof(pDev->aPipes));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->hResetThread = NIL_RTTHREAD;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pDev->pvResetArgs = NULL;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pDev->pResetTimer = NULL;
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync /*
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * Create the reset timer.
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync */
e446ce644a0cdc723be5146be1659f1206599c24vboxsync int rc = PDMUsbHlpTMTimerCreate(pUsbIns, TMCLOCK_VIRTUAL, vusbDevResetDoneTimer, pDev, 0 /*fFlags*/,
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync "USB Device Reset Timer", &pDev->pResetTimer);
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync AssertRCReturn(rc, rc);
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync /*
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * Get the descriptor cache from the device. (shall cannot fail)
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync */
56349fc0a23f96f82208016f8f59f8377bb284b1vboxsync pDev->pDescCache = pUsbIns->pReg->pfnUsbGetDescriptorCache(pUsbIns);
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync Assert(pDev->pDescCache);
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync#ifdef VBOX_STRICT
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync if (pDev->pDescCache->fUseCachedStringsDescriptors)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync int32_t iPrevId = -1;
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync for (unsigned iLang = 0; iLang < pDev->pDescCache->cLanguages; iLang++)
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync Assert((int32_t)pDev->pDescCache->paLanguages[iLang].idLang > iPrevId);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync iPrevId = pDev->pDescCache->paLanguages[iLang].idLang;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync int32_t idxPrevStr = -1;
e446ce644a0cdc723be5146be1659f1206599c24vboxsync PCPDMUSBDESCCACHESTRING paStrings = pDev->pDescCache->paLanguages[iLang].paStrings;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync unsigned cStrings = pDev->pDescCache->paLanguages[iLang].cStrings;
e446ce644a0cdc723be5146be1659f1206599c24vboxsync for (unsigned iStr = 0; iStr < cStrings; iStr++)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync Assert((int32_t)paStrings[iStr].idx > idxPrevStr);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync idxPrevStr = paStrings[iStr].idx;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync size_t cch = strlen(paStrings[iStr].psz);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync Assert(cch <= 127);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync }
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync }
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync }
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync#endif
e446ce644a0cdc723be5146be1659f1206599c24vboxsync
e446ce644a0cdc723be5146be1659f1206599c24vboxsync /*
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync * Allocate memory for the interface states.
e446ce644a0cdc723be5146be1659f1206599c24vboxsync */
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync size_t cbIface = vusbDevMaxInterfaces(pDev) * sizeof(*pDev->paIfStates);
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync pDev->paIfStates = (PVUSBINTERFACESTATE)RTMemAllocZ(cbIface);
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync AssertMsgReturn(pDev->paIfStates, ("RTMemAllocZ(%d) failed\n", cbIface), VERR_NO_MEMORY);
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync return VINF_SUCCESS;
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync}
4b9a9888c020ed3508c8ac3a5b47842d6aa3f8d2vboxsync
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync/*
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Local Variables:
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * mode: c
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * c-file-style: "bsd"
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * c-basic-offset: 4
e446ce644a0cdc723be5146be1659f1206599c24vboxsync * tab-width: 4
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * indent-tabs-mode: s
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * End:
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync */
e446ce644a0cdc723be5146be1659f1206599c24vboxsync
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync