[48406] | 1 | /* $Id: EmulatedUSBImpl.cpp 98278 2023-01-24 11:55:00Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * Emulated USB manager implementation.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2013-2023 Oracle and/or its affiliates.
|
---|
[48406] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[48406] | 26 | */
|
---|
| 27 |
|
---|
[67914] | 28 | #define LOG_GROUP LOG_GROUP_MAIN_EMULATEDUSB
|
---|
| 29 | #include "LoggingNew.h"
|
---|
[48631] | 30 |
|
---|
[48406] | 31 | #include "EmulatedUSBImpl.h"
|
---|
| 32 | #include "ConsoleImpl.h"
|
---|
| 33 |
|
---|
| 34 | #include <VBox/vmm/pdmusb.h>
|
---|
[93444] | 35 | #include <VBox/vmm/vmmr3vtable.h>
|
---|
[48406] | 36 |
|
---|
| 37 |
|
---|
| 38 | /*
|
---|
| 39 | * Emulated USB webcam device instance.
|
---|
| 40 | */
|
---|
| 41 | typedef std::map <Utf8Str, Utf8Str> EUSBSettingsMap;
|
---|
| 42 |
|
---|
| 43 | typedef enum EUSBDEVICESTATUS
|
---|
| 44 | {
|
---|
| 45 | EUSBDEVICE_CREATED,
|
---|
| 46 | EUSBDEVICE_ATTACHING,
|
---|
| 47 | EUSBDEVICE_ATTACHED
|
---|
| 48 | } EUSBDEVICESTATUS;
|
---|
| 49 |
|
---|
| 50 | class EUSBWEBCAM /* : public EUSBDEVICE */
|
---|
| 51 | {
|
---|
[93444] | 52 | private:
|
---|
| 53 | int32_t volatile mcRefs;
|
---|
[48406] | 54 |
|
---|
[93444] | 55 | EmulatedUSB *mpEmulatedUSB;
|
---|
[48631] | 56 |
|
---|
[93444] | 57 | RTUUID mUuid;
|
---|
| 58 | char mszUuid[RTUUID_STR_LENGTH];
|
---|
[48406] | 59 |
|
---|
[93444] | 60 | Utf8Str mPath;
|
---|
| 61 | Utf8Str mSettings;
|
---|
[48406] | 62 |
|
---|
[93444] | 63 | EUSBSettingsMap mDevSettings;
|
---|
| 64 | EUSBSettingsMap mDrvSettings;
|
---|
[48406] | 65 |
|
---|
[93444] | 66 | void *mpvObject;
|
---|
[49120] | 67 |
|
---|
[93444] | 68 | static DECLCALLBACK(int) emulatedWebcamAttach(PUVM pUVM, PCVMMR3VTABLE pVMM, EUSBWEBCAM *pThis, const char *pszDriver);
|
---|
| 69 | static DECLCALLBACK(int) emulatedWebcamDetach(PUVM pUVM, PCVMMR3VTABLE pVMM, EUSBWEBCAM *pThis);
|
---|
[48406] | 70 |
|
---|
[93444] | 71 | HRESULT settingsParse(void);
|
---|
[48406] | 72 |
|
---|
[93444] | 73 | ~EUSBWEBCAM()
|
---|
| 74 | {
|
---|
| 75 | }
|
---|
[48406] | 76 |
|
---|
[93444] | 77 | public:
|
---|
| 78 | EUSBWEBCAM()
|
---|
| 79 | :
|
---|
| 80 | mcRefs(1),
|
---|
| 81 | mpEmulatedUSB(NULL),
|
---|
| 82 | mpvObject(NULL),
|
---|
| 83 | enmStatus(EUSBDEVICE_CREATED)
|
---|
| 84 | {
|
---|
| 85 | RT_ZERO(mUuid);
|
---|
| 86 | RT_ZERO(mszUuid);
|
---|
| 87 | }
|
---|
[48406] | 88 |
|
---|
[93444] | 89 | int32_t AddRef(void)
|
---|
| 90 | {
|
---|
| 91 | return ASMAtomicIncS32(&mcRefs);
|
---|
| 92 | }
|
---|
[48406] | 93 |
|
---|
[93444] | 94 | void Release(void)
|
---|
| 95 | {
|
---|
| 96 | int32_t c = ASMAtomicDecS32(&mcRefs);
|
---|
| 97 | if (c == 0)
|
---|
[48406] | 98 | {
|
---|
[93444] | 99 | delete this;
|
---|
[48406] | 100 | }
|
---|
[93444] | 101 | }
|
---|
[48406] | 102 |
|
---|
[93444] | 103 | HRESULT Initialize(Console *pConsole,
|
---|
| 104 | EmulatedUSB *pEmulatedUSB,
|
---|
| 105 | const com::Utf8Str *aPath,
|
---|
| 106 | const com::Utf8Str *aSettings,
|
---|
| 107 | void *pvObject);
|
---|
| 108 | HRESULT Attach(Console *pConsole, PUVM pUVM, PCVMMR3VTABLE pVMM, const char *pszDriver);
|
---|
| 109 | HRESULT Detach(Console *pConsole, PUVM pUVM, PCVMMR3VTABLE pVMM);
|
---|
[48406] | 110 |
|
---|
[93444] | 111 | bool HasId(const char *pszId) { return RTStrCmp(pszId, mszUuid) == 0;}
|
---|
[48631] | 112 |
|
---|
[94368] | 113 | void *getObjectPtr() { return mpvObject; }
|
---|
| 114 |
|
---|
[93444] | 115 | EUSBDEVICESTATUS enmStatus;
|
---|
[48406] | 116 | };
|
---|
| 117 |
|
---|
[93444] | 118 |
|
---|
| 119 | static int emulatedWebcamInsertSettings(PCFGMNODE pConfig, PCVMMR3VTABLE pVMM, EUSBSettingsMap *pSettings)
|
---|
[49234] | 120 | {
|
---|
[93444] | 121 | for (EUSBSettingsMap::const_iterator it = pSettings->begin(); it != pSettings->end(); ++it)
|
---|
[49234] | 122 | {
|
---|
| 123 | /* Convert some well known settings for backward compatibility. */
|
---|
[94963] | 124 | int vrc;
|
---|
[49234] | 125 | if ( RTStrCmp(it->first.c_str(), "MaxPayloadTransferSize") == 0
|
---|
| 126 | || RTStrCmp(it->first.c_str(), "MaxFramerate") == 0)
|
---|
| 127 | {
|
---|
| 128 | uint32_t u32 = 0;
|
---|
[94963] | 129 | vrc = RTStrToUInt32Full(it->second.c_str(), 10, &u32);
|
---|
| 130 | if (vrc == VINF_SUCCESS)
|
---|
| 131 | vrc = pVMM->pfnCFGMR3InsertInteger(pConfig, it->first.c_str(), u32);
|
---|
| 132 | else if (RT_SUCCESS(vrc)) /* VWRN_* */
|
---|
| 133 | vrc = VERR_INVALID_PARAMETER;
|
---|
[49234] | 134 | }
|
---|
| 135 | else
|
---|
[94963] | 136 | vrc = pVMM->pfnCFGMR3InsertString(pConfig, it->first.c_str(), it->second.c_str());
|
---|
| 137 | if (RT_FAILURE(vrc))
|
---|
| 138 | return vrc;
|
---|
[49234] | 139 | }
|
---|
| 140 |
|
---|
[93444] | 141 | return VINF_SUCCESS;
|
---|
[49234] | 142 | }
|
---|
| 143 |
|
---|
[93444] | 144 | /*static*/ DECLCALLBACK(int)
|
---|
| 145 | EUSBWEBCAM::emulatedWebcamAttach(PUVM pUVM, PCVMMR3VTABLE pVMM, EUSBWEBCAM *pThis, const char *pszDriver)
|
---|
[48406] | 146 | {
|
---|
[93444] | 147 | PCFGMNODE pInstance = pVMM->pfnCFGMR3CreateTree(pUVM);
|
---|
[48406] | 148 | PCFGMNODE pConfig;
|
---|
[94963] | 149 | int vrc = pVMM->pfnCFGMR3InsertNode(pInstance, "Config", &pConfig);
|
---|
| 150 | AssertRCReturn(vrc, vrc);
|
---|
| 151 | vrc = emulatedWebcamInsertSettings(pConfig, pVMM, &pThis->mDevSettings);
|
---|
| 152 | AssertRCReturn(vrc, vrc);
|
---|
[93444] | 153 |
|
---|
[48631] | 154 | PCFGMNODE pEUSB;
|
---|
[94963] | 155 | vrc = pVMM->pfnCFGMR3InsertNode(pConfig, "EmulatedUSB", &pEUSB);
|
---|
| 156 | AssertRCReturn(vrc, vrc);
|
---|
| 157 | vrc = pVMM->pfnCFGMR3InsertString(pEUSB, "Id", pThis->mszUuid);
|
---|
| 158 | AssertRCReturn(vrc, vrc);
|
---|
[48406] | 159 |
|
---|
| 160 | PCFGMNODE pLunL0;
|
---|
[94963] | 161 | vrc = pVMM->pfnCFGMR3InsertNode(pInstance, "LUN#0", &pLunL0);
|
---|
| 162 | AssertRCReturn(vrc, vrc);
|
---|
| 163 | vrc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", pszDriver);
|
---|
| 164 | AssertRCReturn(vrc, vrc);
|
---|
| 165 | vrc = pVMM->pfnCFGMR3InsertNode(pLunL0, "Config", &pConfig);
|
---|
| 166 | AssertRCReturn(vrc, vrc);
|
---|
| 167 | vrc = pVMM->pfnCFGMR3InsertString(pConfig, "DevicePath", pThis->mPath.c_str());
|
---|
| 168 | AssertRCReturn(vrc, vrc);
|
---|
| 169 | vrc = pVMM->pfnCFGMR3InsertString(pConfig, "Id", pThis->mszUuid);
|
---|
| 170 | AssertRCReturn(vrc, vrc);
|
---|
| 171 | vrc = emulatedWebcamInsertSettings(pConfig, pVMM, &pThis->mDrvSettings);
|
---|
| 172 | AssertRCReturn(vrc, vrc);
|
---|
[48406] | 173 |
|
---|
[48969] | 174 | /* pInstance will be used by PDM and deallocated on error. */
|
---|
[94963] | 175 | vrc = pVMM->pfnPDMR3UsbCreateEmulatedDevice(pUVM, "Webcam", pInstance, &pThis->mUuid, NULL);
|
---|
| 176 | LogRelFlowFunc(("PDMR3UsbCreateEmulatedDevice %Rrc\n", vrc));
|
---|
| 177 | return vrc;
|
---|
[48406] | 178 | }
|
---|
| 179 |
|
---|
[93444] | 180 | /*static*/ DECLCALLBACK(int)
|
---|
| 181 | EUSBWEBCAM::emulatedWebcamDetach(PUVM pUVM, PCVMMR3VTABLE pVMM, EUSBWEBCAM *pThis)
|
---|
[48406] | 182 | {
|
---|
[93444] | 183 | return pVMM->pfnPDMR3UsbDetachDevice(pUVM, &pThis->mUuid);
|
---|
[48406] | 184 | }
|
---|
| 185 |
|
---|
| 186 | HRESULT EUSBWEBCAM::Initialize(Console *pConsole,
|
---|
[48631] | 187 | EmulatedUSB *pEmulatedUSB,
|
---|
[48406] | 188 | const com::Utf8Str *aPath,
|
---|
[49120] | 189 | const com::Utf8Str *aSettings,
|
---|
| 190 | void *pvObject)
|
---|
[48406] | 191 | {
|
---|
| 192 | HRESULT hrc = S_OK;
|
---|
| 193 |
|
---|
| 194 | int vrc = RTUuidCreate(&mUuid);
|
---|
[93444] | 195 | AssertRCReturn(vrc, pConsole->setError(vrc, EmulatedUSB::tr("Init emulated USB webcam (RTUuidCreate -> %Rrc)"), vrc));
|
---|
| 196 |
|
---|
| 197 | RTStrPrintf(mszUuid, sizeof(mszUuid), "%RTuuid", &mUuid);
|
---|
| 198 | hrc = mPath.assignEx(*aPath);
|
---|
| 199 | if (SUCCEEDED(hrc))
|
---|
[48406] | 200 | {
|
---|
[93444] | 201 | hrc = mSettings.assignEx(*aSettings);
|
---|
[48406] | 202 | if (SUCCEEDED(hrc))
|
---|
| 203 | {
|
---|
| 204 | hrc = settingsParse();
|
---|
[48631] | 205 | if (SUCCEEDED(hrc))
|
---|
| 206 | {
|
---|
| 207 | mpEmulatedUSB = pEmulatedUSB;
|
---|
[49120] | 208 | mpvObject = pvObject;
|
---|
[48631] | 209 | }
|
---|
[48406] | 210 | }
|
---|
| 211 | }
|
---|
| 212 |
|
---|
| 213 | return hrc;
|
---|
| 214 | }
|
---|
| 215 |
|
---|
| 216 | HRESULT EUSBWEBCAM::settingsParse(void)
|
---|
| 217 | {
|
---|
[49234] | 218 | HRESULT hr = S_OK;
|
---|
[48406] | 219 |
|
---|
[49234] | 220 | /* Parse mSettings string:
|
---|
| 221 | * "[dev:|drv:]Name1=Value1;[dev:|drv:]Name2=Value2"
|
---|
| 222 | */
|
---|
| 223 | char *pszSrc = mSettings.mutableRaw();
|
---|
| 224 |
|
---|
| 225 | if (pszSrc)
|
---|
| 226 | {
|
---|
| 227 | while (*pszSrc)
|
---|
| 228 | {
|
---|
| 229 | /* Does the setting belong to device of driver. Default is both. */
|
---|
| 230 | bool fDev = true;
|
---|
| 231 | bool fDrv = true;
|
---|
[60935] | 232 | if (RTStrNICmp(pszSrc, RT_STR_TUPLE("drv:")) == 0)
|
---|
[49234] | 233 | {
|
---|
[60935] | 234 | pszSrc += sizeof("drv:")-1;
|
---|
[49234] | 235 | fDev = false;
|
---|
| 236 | }
|
---|
[60935] | 237 | else if (RTStrNICmp(pszSrc, RT_STR_TUPLE("dev:")) == 0)
|
---|
[49234] | 238 | {
|
---|
[60935] | 239 | pszSrc += sizeof("dev:")-1;
|
---|
[49234] | 240 | fDrv = false;
|
---|
| 241 | }
|
---|
| 242 |
|
---|
[93444] | 243 | char *pszEq = strchr(pszSrc, '=');
|
---|
[49234] | 244 | if (!pszEq)
|
---|
| 245 | {
|
---|
| 246 | hr = E_INVALIDARG;
|
---|
| 247 | break;
|
---|
| 248 | }
|
---|
| 249 |
|
---|
[93444] | 250 | char *pszEnd = strchr(pszEq, ';');
|
---|
[49234] | 251 | if (!pszEnd)
|
---|
| 252 | pszEnd = pszEq + strlen(pszEq);
|
---|
| 253 |
|
---|
| 254 | *pszEq = 0;
|
---|
| 255 | char chEnd = *pszEnd;
|
---|
| 256 | *pszEnd = 0;
|
---|
| 257 |
|
---|
| 258 | /* Empty strings not allowed. */
|
---|
| 259 | if (*pszSrc != 0 && pszEq[1] != 0)
|
---|
| 260 | {
|
---|
| 261 | if (fDev)
|
---|
| 262 | mDevSettings[pszSrc] = &pszEq[1];
|
---|
| 263 | if (fDrv)
|
---|
| 264 | mDrvSettings[pszSrc] = &pszEq[1];
|
---|
| 265 | }
|
---|
| 266 |
|
---|
| 267 | *pszEq = '=';
|
---|
| 268 | *pszEnd = chEnd;
|
---|
| 269 |
|
---|
| 270 | pszSrc = pszEnd;
|
---|
| 271 | if (*pszSrc == ';')
|
---|
| 272 | pszSrc++;
|
---|
| 273 | }
|
---|
| 274 |
|
---|
| 275 | if (SUCCEEDED(hr))
|
---|
| 276 | {
|
---|
| 277 | EUSBSettingsMap::const_iterator it;
|
---|
| 278 | for (it = mDevSettings.begin(); it != mDevSettings.end(); ++it)
|
---|
| 279 | LogRelFlowFunc(("[dev:%s] = [%s]\n", it->first.c_str(), it->second.c_str()));
|
---|
| 280 | for (it = mDrvSettings.begin(); it != mDrvSettings.end(); ++it)
|
---|
| 281 | LogRelFlowFunc(("[drv:%s] = [%s]\n", it->first.c_str(), it->second.c_str()));
|
---|
| 282 | }
|
---|
| 283 | }
|
---|
| 284 |
|
---|
| 285 | return hr;
|
---|
[48406] | 286 | }
|
---|
| 287 |
|
---|
[93444] | 288 | HRESULT EUSBWEBCAM::Attach(Console *pConsole, PUVM pUVM, PCVMMR3VTABLE pVMM, const char *pszDriver)
|
---|
[48406] | 289 | {
|
---|
[93444] | 290 | int vrc = pVMM->pfnVMR3ReqCallWaitU(pUVM, 0 /* idDstCpu (saved state, see #6232) */,
|
---|
| 291 | (PFNRT)emulatedWebcamAttach, 4,
|
---|
| 292 | pUVM, pVMM, this, pszDriver);
|
---|
| 293 | if (RT_SUCCESS(vrc))
|
---|
| 294 | return S_OK;
|
---|
| 295 | LogFlowThisFunc(("%Rrc\n", vrc));
|
---|
| 296 | return pConsole->setErrorBoth(VBOX_E_VM_ERROR, vrc, EmulatedUSB::tr("Attach emulated USB webcam (%Rrc)"), vrc);
|
---|
[48406] | 297 | }
|
---|
| 298 |
|
---|
[93444] | 299 | HRESULT EUSBWEBCAM::Detach(Console *pConsole, PUVM pUVM, PCVMMR3VTABLE pVMM)
|
---|
[48406] | 300 | {
|
---|
[93444] | 301 | int vrc = pVMM->pfnVMR3ReqCallWaitU(pUVM, 0 /* idDstCpu (saved state, see #6232) */,
|
---|
| 302 | (PFNRT)emulatedWebcamDetach, 3,
|
---|
| 303 | pUVM, pVMM, this);
|
---|
| 304 | if (RT_SUCCESS(vrc))
|
---|
| 305 | return S_OK;
|
---|
| 306 | LogFlowThisFunc(("%Rrc\n", vrc));
|
---|
| 307 | return pConsole->setErrorBoth(VBOX_E_VM_ERROR, vrc, EmulatedUSB::tr("Detach emulated USB webcam (%Rrc)"), vrc);
|
---|
[48406] | 308 | }
|
---|
| 309 |
|
---|
| 310 |
|
---|
| 311 | /*
|
---|
| 312 | * EmulatedUSB implementation.
|
---|
| 313 | */
|
---|
| 314 | DEFINE_EMPTY_CTOR_DTOR(EmulatedUSB)
|
---|
| 315 |
|
---|
| 316 | HRESULT EmulatedUSB::FinalConstruct()
|
---|
| 317 | {
|
---|
| 318 | return BaseFinalConstruct();
|
---|
| 319 | }
|
---|
| 320 |
|
---|
| 321 | void EmulatedUSB::FinalRelease()
|
---|
| 322 | {
|
---|
| 323 | uninit();
|
---|
| 324 |
|
---|
| 325 | BaseFinalRelease();
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | /*
|
---|
| 329 | * Initializes the instance.
|
---|
| 330 | *
|
---|
| 331 | * @param pConsole The owner.
|
---|
| 332 | */
|
---|
| 333 | HRESULT EmulatedUSB::init(ComObjPtr<Console> pConsole)
|
---|
| 334 | {
|
---|
[48408] | 335 | LogFlowThisFunc(("\n"));
|
---|
[48406] | 336 |
|
---|
| 337 | ComAssertRet(!pConsole.isNull(), E_INVALIDARG);
|
---|
| 338 |
|
---|
| 339 | /* Enclose the state transition NotReady->InInit->Ready */
|
---|
| 340 | AutoInitSpan autoInitSpan(this);
|
---|
| 341 | AssertReturn(autoInitSpan.isOk(), E_FAIL);
|
---|
| 342 |
|
---|
| 343 | m.pConsole = pConsole;
|
---|
| 344 |
|
---|
[94368] | 345 | mEmUsbIf.pvUser = this;
|
---|
| 346 | mEmUsbIf.pfnQueryEmulatedUsbDataById = EmulatedUSB::i_QueryEmulatedUsbDataById;
|
---|
| 347 |
|
---|
[48406] | 348 | /* Confirm a successful initialization */
|
---|
| 349 | autoInitSpan.setSucceeded();
|
---|
| 350 |
|
---|
| 351 | return S_OK;
|
---|
| 352 | }
|
---|
| 353 |
|
---|
| 354 | /*
|
---|
| 355 | * Uninitializes the instance.
|
---|
| 356 | * Called either from FinalRelease() or by the parent when it gets destroyed.
|
---|
| 357 | */
|
---|
| 358 | void EmulatedUSB::uninit()
|
---|
| 359 | {
|
---|
| 360 | LogFlowThisFunc(("\n"));
|
---|
| 361 |
|
---|
| 362 | m.pConsole.setNull();
|
---|
| 363 |
|
---|
| 364 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
[66891] | 365 | for (WebcamsMap::iterator it = m.webcams.begin(); it != m.webcams.end(); ++it)
|
---|
[48406] | 366 | {
|
---|
| 367 | EUSBWEBCAM *p = it->second;
|
---|
[66891] | 368 | if (p)
|
---|
| 369 | {
|
---|
| 370 | it->second = NULL;
|
---|
| 371 | p->Release();
|
---|
| 372 | }
|
---|
[48406] | 373 | }
|
---|
[66891] | 374 | m.webcams.clear();
|
---|
[48406] | 375 | alock.release();
|
---|
| 376 |
|
---|
| 377 | /* Enclose the state transition Ready->InUninit->NotReady */
|
---|
| 378 | AutoUninitSpan autoUninitSpan(this);
|
---|
| 379 | if (autoUninitSpan.uninitDone())
|
---|
| 380 | return;
|
---|
| 381 | }
|
---|
| 382 |
|
---|
| 383 | HRESULT EmulatedUSB::getWebcams(std::vector<com::Utf8Str> &aWebcams)
|
---|
| 384 | {
|
---|
| 385 | HRESULT hrc = S_OK;
|
---|
| 386 |
|
---|
| 387 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 388 |
|
---|
| 389 | try
|
---|
| 390 | {
|
---|
| 391 | aWebcams.resize(m.webcams.size());
|
---|
| 392 | }
|
---|
| 393 | catch (std::bad_alloc &)
|
---|
| 394 | {
|
---|
| 395 | hrc = E_OUTOFMEMORY;
|
---|
| 396 | }
|
---|
| 397 | catch (...)
|
---|
| 398 | {
|
---|
| 399 | hrc = E_FAIL;
|
---|
| 400 | }
|
---|
| 401 |
|
---|
| 402 | if (SUCCEEDED(hrc))
|
---|
| 403 | {
|
---|
| 404 | size_t i;
|
---|
| 405 | WebcamsMap::const_iterator it;
|
---|
| 406 | for (i = 0, it = m.webcams.begin(); it != m.webcams.end(); ++it)
|
---|
| 407 | aWebcams[i++] = it->first;
|
---|
| 408 | }
|
---|
| 409 |
|
---|
| 410 | return hrc;
|
---|
| 411 | }
|
---|
| 412 |
|
---|
[94368] | 413 | PEMULATEDUSBIF EmulatedUSB::i_getEmulatedUsbIf()
|
---|
| 414 | {
|
---|
| 415 | return &mEmUsbIf;
|
---|
| 416 | }
|
---|
| 417 |
|
---|
[48406] | 418 | static const Utf8Str s_pathDefault(".0");
|
---|
| 419 |
|
---|
| 420 | HRESULT EmulatedUSB::webcamAttach(const com::Utf8Str &aPath,
|
---|
| 421 | const com::Utf8Str &aSettings)
|
---|
| 422 | {
|
---|
[50580] | 423 | return i_webcamAttachInternal(aPath, aSettings, "HostWebcam", NULL);
|
---|
[49120] | 424 | }
|
---|
| 425 |
|
---|
[50580] | 426 | HRESULT EmulatedUSB::i_webcamAttachInternal(const com::Utf8Str &aPath,
|
---|
| 427 | const com::Utf8Str &aSettings,
|
---|
| 428 | const char *pszDriver,
|
---|
| 429 | void *pvObject)
|
---|
[49120] | 430 | {
|
---|
[48406] | 431 | HRESULT hrc = S_OK;
|
---|
| 432 |
|
---|
| 433 | const Utf8Str &path = aPath.isEmpty() || aPath == "."? s_pathDefault: aPath;
|
---|
| 434 |
|
---|
| 435 | Console::SafeVMPtr ptrVM(m.pConsole);
|
---|
| 436 | if (ptrVM.isOk())
|
---|
| 437 | {
|
---|
| 438 | EUSBWEBCAM *p = new EUSBWEBCAM();
|
---|
| 439 | if (p)
|
---|
| 440 | {
|
---|
[49120] | 441 | hrc = p->Initialize(m.pConsole, this, &path, &aSettings, pvObject);
|
---|
[48406] | 442 | if (SUCCEEDED(hrc))
|
---|
| 443 | {
|
---|
| 444 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 445 | WebcamsMap::const_iterator it = m.webcams.find(path);
|
---|
| 446 | if (it == m.webcams.end())
|
---|
| 447 | {
|
---|
| 448 | p->AddRef();
|
---|
| 449 | try
|
---|
| 450 | {
|
---|
| 451 | m.webcams[path] = p;
|
---|
| 452 | }
|
---|
| 453 | catch (std::bad_alloc &)
|
---|
| 454 | {
|
---|
| 455 | hrc = E_OUTOFMEMORY;
|
---|
| 456 | }
|
---|
| 457 | catch (...)
|
---|
| 458 | {
|
---|
| 459 | hrc = E_FAIL;
|
---|
| 460 | }
|
---|
| 461 | p->enmStatus = EUSBDEVICE_ATTACHING;
|
---|
| 462 | }
|
---|
| 463 | else
|
---|
| 464 | {
|
---|
| 465 | hrc = E_FAIL;
|
---|
| 466 | }
|
---|
| 467 | }
|
---|
| 468 |
|
---|
| 469 | if (SUCCEEDED(hrc))
|
---|
[93444] | 470 | hrc = p->Attach(m.pConsole, ptrVM.rawUVM(), ptrVM.vtable(), pszDriver);
|
---|
[48406] | 471 |
|
---|
| 472 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 473 | if (SUCCEEDED(hrc))
|
---|
| 474 | p->enmStatus = EUSBDEVICE_ATTACHED;
|
---|
[93444] | 475 | else if (p->enmStatus != EUSBDEVICE_CREATED)
|
---|
| 476 | m.webcams.erase(path);
|
---|
[48406] | 477 | alock.release();
|
---|
| 478 |
|
---|
| 479 | p->Release();
|
---|
| 480 | }
|
---|
| 481 | else
|
---|
| 482 | {
|
---|
| 483 | hrc = E_OUTOFMEMORY;
|
---|
| 484 | }
|
---|
| 485 | }
|
---|
| 486 | else
|
---|
| 487 | {
|
---|
| 488 | hrc = VBOX_E_INVALID_VM_STATE;
|
---|
| 489 | }
|
---|
| 490 |
|
---|
| 491 | return hrc;
|
---|
| 492 | }
|
---|
| 493 |
|
---|
| 494 | HRESULT EmulatedUSB::webcamDetach(const com::Utf8Str &aPath)
|
---|
| 495 | {
|
---|
[50580] | 496 | return i_webcamDetachInternal(aPath);
|
---|
[49120] | 497 | }
|
---|
| 498 |
|
---|
[50580] | 499 | HRESULT EmulatedUSB::i_webcamDetachInternal(const com::Utf8Str &aPath)
|
---|
[49120] | 500 | {
|
---|
[48406] | 501 | HRESULT hrc = S_OK;
|
---|
| 502 |
|
---|
| 503 | const Utf8Str &path = aPath.isEmpty() || aPath == "."? s_pathDefault: aPath;
|
---|
| 504 |
|
---|
| 505 | Console::SafeVMPtr ptrVM(m.pConsole);
|
---|
| 506 | if (ptrVM.isOk())
|
---|
| 507 | {
|
---|
| 508 | EUSBWEBCAM *p = NULL;
|
---|
| 509 |
|
---|
| 510 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 511 | WebcamsMap::iterator it = m.webcams.find(path);
|
---|
| 512 | if (it != m.webcams.end())
|
---|
| 513 | {
|
---|
| 514 | if (it->second->enmStatus == EUSBDEVICE_ATTACHED)
|
---|
| 515 | {
|
---|
| 516 | p = it->second;
|
---|
| 517 | m.webcams.erase(it);
|
---|
| 518 | }
|
---|
| 519 | }
|
---|
| 520 | alock.release();
|
---|
| 521 |
|
---|
| 522 | if (p)
|
---|
| 523 | {
|
---|
[93444] | 524 | hrc = p->Detach(m.pConsole, ptrVM.rawUVM(), ptrVM.vtable());
|
---|
[48406] | 525 | p->Release();
|
---|
| 526 | }
|
---|
[48423] | 527 | else
|
---|
| 528 | {
|
---|
| 529 | hrc = E_INVALIDARG;
|
---|
| 530 | }
|
---|
[48406] | 531 | }
|
---|
| 532 | else
|
---|
| 533 | {
|
---|
| 534 | hrc = VBOX_E_INVALID_VM_STATE;
|
---|
| 535 | }
|
---|
| 536 |
|
---|
| 537 | return hrc;
|
---|
| 538 | }
|
---|
| 539 |
|
---|
[93444] | 540 | /*static*/ DECLCALLBACK(int)
|
---|
| 541 | EmulatedUSB::eusbCallbackEMT(EmulatedUSB *pThis, char *pszId, uint32_t iEvent, void *pvData, uint32_t cbData)
|
---|
[48631] | 542 | {
|
---|
| 543 | LogRelFlowFunc(("id %s event %d, data %p %d\n", pszId, iEvent, pvData, cbData));
|
---|
| 544 |
|
---|
| 545 | NOREF(cbData);
|
---|
| 546 |
|
---|
[94963] | 547 | int vrc = VINF_SUCCESS;
|
---|
[48631] | 548 | if (iEvent == 0)
|
---|
| 549 | {
|
---|
| 550 | com::Utf8Str path;
|
---|
[94963] | 551 | HRESULT hrc = pThis->webcamPathFromId(&path, pszId);
|
---|
| 552 | if (SUCCEEDED(hrc))
|
---|
[48631] | 553 | {
|
---|
[94963] | 554 | hrc = pThis->webcamDetach(path);
|
---|
| 555 | if (FAILED(hrc))
|
---|
[48631] | 556 | {
|
---|
[94963] | 557 | vrc = VERR_INVALID_STATE;
|
---|
[48631] | 558 | }
|
---|
| 559 | }
|
---|
| 560 | else
|
---|
| 561 | {
|
---|
[94963] | 562 | vrc = VERR_NOT_FOUND;
|
---|
[48631] | 563 | }
|
---|
| 564 | }
|
---|
| 565 | else
|
---|
| 566 | {
|
---|
[94963] | 567 | vrc = VERR_INVALID_PARAMETER;
|
---|
[48631] | 568 | }
|
---|
| 569 |
|
---|
| 570 | RTMemFree(pszId);
|
---|
| 571 | RTMemFree(pvData);
|
---|
| 572 |
|
---|
[98278] | 573 | LogRelFlowFunc(("vrc %Rrc\n", vrc));
|
---|
[94963] | 574 | return vrc;
|
---|
[48631] | 575 | }
|
---|
| 576 |
|
---|
[93444] | 577 | /* static */ DECLCALLBACK(int)
|
---|
| 578 | EmulatedUSB::i_eusbCallback(void *pv, const char *pszId, uint32_t iEvent, const void *pvData, uint32_t cbData)
|
---|
[48631] | 579 | {
|
---|
| 580 | /* Make a copy of parameters, forward to EMT and leave the callback to not hold any lock in the device. */
|
---|
[94963] | 581 | int vrc = VINF_SUCCESS;
|
---|
[48631] | 582 | void *pvDataCopy = NULL;
|
---|
| 583 | if (cbData > 0)
|
---|
| 584 | {
|
---|
| 585 | pvDataCopy = RTMemDup(pvData, cbData);
|
---|
| 586 | if (!pvDataCopy)
|
---|
[94963] | 587 | vrc = VERR_NO_MEMORY;
|
---|
[48631] | 588 | }
|
---|
[94963] | 589 | if (RT_SUCCESS(vrc))
|
---|
[48631] | 590 | {
|
---|
[93444] | 591 | void *pvIdCopy = RTMemDup(pszId, strlen(pszId) + 1);
|
---|
| 592 | if (pvIdCopy)
|
---|
[48631] | 593 | {
|
---|
[94963] | 594 | if (RT_SUCCESS(vrc))
|
---|
[93444] | 595 | {
|
---|
| 596 | EmulatedUSB *pThis = (EmulatedUSB *)pv;
|
---|
| 597 | Console::SafeVMPtr ptrVM(pThis->m.pConsole);
|
---|
| 598 | if (ptrVM.isOk())
|
---|
| 599 | {
|
---|
| 600 | /* No wait. */
|
---|
[94963] | 601 | vrc = ptrVM.vtable()->pfnVMR3ReqCallNoWaitU(ptrVM.rawUVM(), 0 /* idDstCpu */,
|
---|
| 602 | (PFNRT)EmulatedUSB::eusbCallbackEMT, 5,
|
---|
| 603 | pThis, pvIdCopy, iEvent, pvDataCopy, cbData);
|
---|
| 604 | if (RT_SUCCESS(vrc))
|
---|
| 605 | return vrc;
|
---|
[93444] | 606 | }
|
---|
| 607 | else
|
---|
[94963] | 608 | vrc = VERR_INVALID_STATE;
|
---|
[93444] | 609 | }
|
---|
| 610 | RTMemFree(pvIdCopy);
|
---|
[48631] | 611 | }
|
---|
| 612 | else
|
---|
[94963] | 613 | vrc = VERR_NO_MEMORY;
|
---|
[48631] | 614 | RTMemFree(pvDataCopy);
|
---|
| 615 | }
|
---|
[94963] | 616 | return vrc;
|
---|
[48631] | 617 | }
|
---|
| 618 |
|
---|
[94368] | 619 | /*static*/
|
---|
| 620 | DECLCALLBACK(int) EmulatedUSB::i_QueryEmulatedUsbDataById(void *pvUser, const char *pszId, void **ppvEmUsbCb, void **ppvEmUsbCbData, void **ppvObject)
|
---|
| 621 | {
|
---|
| 622 | EmulatedUSB *pEmUsb = (EmulatedUSB *)pvUser;
|
---|
| 623 |
|
---|
| 624 | AutoReadLock alock(pEmUsb COMMA_LOCKVAL_SRC_POS);
|
---|
| 625 | WebcamsMap::const_iterator it;
|
---|
| 626 | for (it = pEmUsb->m.webcams.begin(); it != pEmUsb->m.webcams.end(); ++it)
|
---|
| 627 | {
|
---|
| 628 | EUSBWEBCAM *p = it->second;
|
---|
| 629 | if (p->HasId(pszId))
|
---|
| 630 | {
|
---|
| 631 | if (ppvEmUsbCb)
|
---|
| 632 | *ppvEmUsbCb = (void *)EmulatedUSB::i_eusbCallback;
|
---|
| 633 | if (ppvEmUsbCbData)
|
---|
| 634 | *ppvEmUsbCbData = pEmUsb;
|
---|
| 635 | if (ppvObject)
|
---|
| 636 | *ppvObject = p->getObjectPtr();
|
---|
| 637 |
|
---|
| 638 | return VINF_SUCCESS;
|
---|
| 639 | }
|
---|
| 640 | }
|
---|
| 641 |
|
---|
| 642 | return VERR_NOT_FOUND;
|
---|
| 643 | }
|
---|
| 644 |
|
---|
[48631] | 645 | HRESULT EmulatedUSB::webcamPathFromId(com::Utf8Str *pPath, const char *pszId)
|
---|
| 646 | {
|
---|
[94963] | 647 | HRESULT hrc = S_OK;
|
---|
[48631] | 648 |
|
---|
| 649 | Console::SafeVMPtr ptrVM(m.pConsole);
|
---|
| 650 | if (ptrVM.isOk())
|
---|
| 651 | {
|
---|
| 652 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 653 | WebcamsMap::const_iterator it;
|
---|
| 654 | for (it = m.webcams.begin(); it != m.webcams.end(); ++it)
|
---|
| 655 | {
|
---|
| 656 | EUSBWEBCAM *p = it->second;
|
---|
| 657 | if (p->HasId(pszId))
|
---|
| 658 | {
|
---|
| 659 | *pPath = it->first;
|
---|
| 660 | break;
|
---|
| 661 | }
|
---|
| 662 | }
|
---|
| 663 |
|
---|
| 664 | if (it == m.webcams.end())
|
---|
| 665 | {
|
---|
[94963] | 666 | hrc = E_FAIL;
|
---|
[48631] | 667 | }
|
---|
| 668 | alock.release();
|
---|
| 669 | }
|
---|
| 670 | else
|
---|
| 671 | {
|
---|
[94963] | 672 | hrc = VBOX_E_INVALID_VM_STATE;
|
---|
[48631] | 673 | }
|
---|
| 674 |
|
---|
[94963] | 675 | return hrc;
|
---|
[48631] | 676 | }
|
---|
| 677 |
|
---|
[48406] | 678 | /* vi: set tabstop=4 shiftwidth=4 expandtab: */
|
---|