EmulatedUSBImpl.cpp revision 9e06f22a5a8961cd7a7da569d683097b17f04dd1
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync/* $Id$ */
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync/** @file
0887a65d2e1f7d938381bed11e859caed56cb47evboxsync *
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * Emulated USB manager implementation.
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync */
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync/*
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * Copyright (C) 2013 Oracle Corporation
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync *
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * available from http://www.virtualbox.org. This file is free software;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * you can redistribute it and/or modify it under the terms of the GNU
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * General Public License (GPL) as published by the Free Software
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync */
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_MAIN_EMULATEDUSB
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync#include "EmulatedUSBImpl.h"
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync#include "ConsoleImpl.h"
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync#include "Logging.h"
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync#include <VBox/vmm/pdmusb.h>
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync/*
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync * Emulated USB webcam device instance.
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync */
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsynctypedef std::map <Utf8Str, Utf8Str> EUSBSettingsMap;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsynctypedef enum EUSBDEVICESTATUS
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync{
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync EUSBDEVICE_CREATED,
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync EUSBDEVICE_ATTACHING,
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync EUSBDEVICE_ATTACHED
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync} EUSBDEVICESTATUS;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsyncclass EUSBWEBCAM /* : public EUSBDEVICE */
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync{
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync private:
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync int32_t volatile mcRefs;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync EmulatedUSB *mpEmulatedUSB;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync RTUUID mUuid;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync char mszUuid[RTUUID_STR_LENGTH];
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync Utf8Str mPath;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync Utf8Str mSettings;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync EUSBSettingsMap mDevSettings;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync EUSBSettingsMap mDrvSettings;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync static DECLCALLBACK(int) emulatedWebcamAttach(PUVM pUVM, EUSBWEBCAM *pThis);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync static DECLCALLBACK(int) emulatedWebcamDetach(PUVM pUVM, EUSBWEBCAM *pThis);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync HRESULT settingsParse(void);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync ~EUSBWEBCAM()
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync {
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync }
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync public:
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync EUSBWEBCAM()
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync :
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync mcRefs(1),
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync mpEmulatedUSB(NULL),
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync enmStatus(EUSBDEVICE_CREATED)
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync {
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync RT_ZERO(mUuid);
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync RT_ZERO(mszUuid);
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync }
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync int32_t AddRef(void)
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync {
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync return ASMAtomicIncS32(&mcRefs);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync }
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync void Release(void)
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync {
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync int32_t c = ASMAtomicDecS32(&mcRefs);
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync if (c == 0)
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync {
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync delete this;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync }
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync }
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync HRESULT Initialize(Console *pConsole,
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync EmulatedUSB *pEmulatedUSB,
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync const com::Utf8Str *aPath,
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync const com::Utf8Str *aSettings);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync HRESULT Attach(Console *pConsole,
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync PUVM pUVM);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync HRESULT Detach(Console *pConsole,
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync PUVM pUVM);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync bool HasId(const char *pszId) { return RTStrCmp(pszId, mszUuid) == 0;}
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync EUSBDEVICESTATUS enmStatus;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync};
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync/* static */ DECLCALLBACK(int) EUSBWEBCAM::emulatedWebcamAttach(PUVM pUVM, EUSBWEBCAM *pThis)
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync{
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync EUSBSettingsMap::const_iterator it;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync PCFGMNODE pInstance = CFGMR3CreateTree(pUVM);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync PCFGMNODE pConfig;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync CFGMR3InsertNode(pInstance, "Config", &pConfig);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync for (it = pThis->mDevSettings.begin(); it != pThis->mDevSettings.end(); ++it)
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync CFGMR3InsertString(pConfig, it->first.c_str(), it->second.c_str());
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync PCFGMNODE pEUSB;
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync CFGMR3InsertNode(pConfig, "EmulatedUSB", &pEUSB);
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync CFGMR3InsertString(pEUSB, "Id", pThis->mszUuid);
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync CFGMR3InsertInteger(pEUSB, "pfnCallback", (uintptr_t)EmulatedUSB::eusbCallback);
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync CFGMR3InsertInteger(pEUSB, "pvCallback", (uintptr_t)pThis->mpEmulatedUSB);
003bed4b86e46315aaef143a73c95eb8eee7fe78vboxsync
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync PCFGMNODE pLunL0;
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync CFGMR3InsertNode(pInstance, "LUN#0", &pLunL0);
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync CFGMR3InsertString(pLunL0, "Driver", "HostWebcam");
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync CFGMR3InsertNode(pLunL0, "Config", &pConfig);
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync CFGMR3InsertString(pConfig, "DevicePath", pThis->mPath.c_str());
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync for (it = pThis->mDrvSettings.begin(); it != pThis->mDrvSettings.end(); ++it)
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync CFGMR3InsertString(pConfig, it->first.c_str(), it->second.c_str());
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync int rc = PDMR3UsbCreateEmulatedDevice(pUVM, "Webcam", pInstance, &pThis->mUuid);
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync LogRelFlowFunc(("PDMR3UsbCreateEmulatedDevice %Rrc\n", rc));
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync if (RT_FAILURE(rc) && pInstance)
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync CFGMR3RemoveNode(pInstance);
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync return rc;
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync}
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync/* static */ DECLCALLBACK(int) EUSBWEBCAM::emulatedWebcamDetach(PUVM pUVM, EUSBWEBCAM *pThis)
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync{
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync return PDMR3UsbDetachDevice(pUVM, &pThis->mUuid);
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync}
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsyncHRESULT EUSBWEBCAM::Initialize(Console *pConsole,
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync EmulatedUSB *pEmulatedUSB,
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync const com::Utf8Str *aPath,
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync const com::Utf8Str *aSettings)
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync{
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync HRESULT hrc = S_OK;
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync int vrc = RTUuidCreate(&mUuid);
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync if (RT_SUCCESS(vrc))
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync {
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync RTStrPrintf(mszUuid, sizeof(mszUuid), "%RTuuid", &mUuid);
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync hrc = mPath.assignEx(*aPath);
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync if (SUCCEEDED(hrc))
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync {
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync hrc = mSettings.assignEx(*aSettings);
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync }
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync if (SUCCEEDED(hrc))
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync {
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync hrc = settingsParse();
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync if (SUCCEEDED(hrc))
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync {
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync mpEmulatedUSB = pEmulatedUSB;
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync }
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync }
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync }
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync if (SUCCEEDED(hrc) && RT_FAILURE(vrc))
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync {
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync LogFlowThisFunc(("%Rrc\n", vrc));
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync hrc = pConsole->setError(VBOX_E_IPRT_ERROR,
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync "Init emulated USB webcam (%Rrc)", vrc);
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync }
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync return hrc;
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync}
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync
4ab3529cde8c5258f459eeb71a532d1ba522111avboxsyncHRESULT EUSBWEBCAM::settingsParse(void)
4ab3529cde8c5258f459eeb71a532d1ba522111avboxsync{
4ab3529cde8c5258f459eeb71a532d1ba522111avboxsync HRESULT hrc = S_OK;
4ab3529cde8c5258f459eeb71a532d1ba522111avboxsync
4ab3529cde8c5258f459eeb71a532d1ba522111avboxsync return hrc;
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync}
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsyncHRESULT EUSBWEBCAM::Attach(Console *pConsole,
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync PUVM pUVM)
939ffd583b0105c9cfab3570932faa41e0ccd563vboxsync{
HRESULT hrc = S_OK;
int vrc = VMR3ReqCallWaitU(pUVM, 0 /* idDstCpu (saved state, see #6232) */,
(PFNRT)emulatedWebcamAttach, 2,
pUVM, this);
if (SUCCEEDED(hrc) && RT_FAILURE(vrc))
{
LogFlowThisFunc(("%Rrc\n", vrc));
hrc = pConsole->setError(VBOX_E_IPRT_ERROR,
"Attach emulated USB webcam (%Rrc)", vrc);
}
return hrc;
}
HRESULT EUSBWEBCAM::Detach(Console *pConsole,
PUVM pUVM)
{
HRESULT hrc = S_OK;
int vrc = VMR3ReqCallWaitU(pUVM, 0 /* idDstCpu (saved state, see #6232) */,
(PFNRT)emulatedWebcamDetach, 2,
pUVM, this);
if (SUCCEEDED(hrc) && RT_FAILURE(vrc))
{
LogFlowThisFunc(("%Rrc\n", vrc));
hrc = pConsole->setError(VBOX_E_IPRT_ERROR,
"Detach emulated USB webcam (%Rrc)", vrc);
}
return hrc;
}
/*
* EmulatedUSB implementation.
*/
DEFINE_EMPTY_CTOR_DTOR(EmulatedUSB)
HRESULT EmulatedUSB::FinalConstruct()
{
return BaseFinalConstruct();
}
void EmulatedUSB::FinalRelease()
{
uninit();
BaseFinalRelease();
}
/*
* Initializes the instance.
*
* @param pConsole The owner.
*/
HRESULT EmulatedUSB::init(ComObjPtr<Console> pConsole)
{
LogFlowThisFunc(("\n"));
ComAssertRet(!pConsole.isNull(), E_INVALIDARG);
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
AssertReturn(autoInitSpan.isOk(), E_FAIL);
m.pConsole = pConsole;
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
return S_OK;
}
/*
* Uninitializes the instance.
* Called either from FinalRelease() or by the parent when it gets destroyed.
*/
void EmulatedUSB::uninit()
{
LogFlowThisFunc(("\n"));
m.pConsole.setNull();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
WebcamsMap::iterator it = m.webcams.begin();
while (it != m.webcams.end())
{
EUSBWEBCAM *p = it->second;
m.webcams.erase(it++);
p->Release();
}
alock.release();
/* Enclose the state transition Ready->InUninit->NotReady */
AutoUninitSpan autoUninitSpan(this);
if (autoUninitSpan.uninitDone())
return;
}
HRESULT EmulatedUSB::getWebcams(std::vector<com::Utf8Str> &aWebcams)
{
HRESULT hrc = S_OK;
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
try
{
aWebcams.resize(m.webcams.size());
}
catch (std::bad_alloc &)
{
hrc = E_OUTOFMEMORY;
}
catch (...)
{
hrc = E_FAIL;
}
if (SUCCEEDED(hrc))
{
size_t i;
WebcamsMap::const_iterator it;
for (i = 0, it = m.webcams.begin(); it != m.webcams.end(); ++it)
aWebcams[i++] = it->first;
}
return hrc;
}
static const Utf8Str s_pathDefault(".0");
HRESULT EmulatedUSB::webcamAttach(const com::Utf8Str &aPath,
const com::Utf8Str &aSettings)
{
HRESULT hrc = S_OK;
const Utf8Str &path = aPath.isEmpty() || aPath == "."? s_pathDefault: aPath;
Console::SafeVMPtr ptrVM(m.pConsole);
if (ptrVM.isOk())
{
EUSBWEBCAM *p = new EUSBWEBCAM();
if (p)
{
hrc = p->Initialize(m.pConsole, this, &path, &aSettings);
if (SUCCEEDED(hrc))
{
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
WebcamsMap::const_iterator it = m.webcams.find(path);
if (it == m.webcams.end())
{
p->AddRef();
try
{
m.webcams[path] = p;
}
catch (std::bad_alloc &)
{
hrc = E_OUTOFMEMORY;
}
catch (...)
{
hrc = E_FAIL;
}
p->enmStatus = EUSBDEVICE_ATTACHING;
}
else
{
hrc = E_FAIL;
}
}
if (SUCCEEDED(hrc))
{
hrc = p->Attach(m.pConsole, ptrVM.rawUVM());
}
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
if (SUCCEEDED(hrc))
{
p->enmStatus = EUSBDEVICE_ATTACHED;
}
else
{
if (p->enmStatus != EUSBDEVICE_CREATED)
{
m.webcams.erase(path);
}
}
alock.release();
p->Release();
}
else
{
hrc = E_OUTOFMEMORY;
}
}
else
{
hrc = VBOX_E_INVALID_VM_STATE;
}
return hrc;
}
HRESULT EmulatedUSB::webcamDetach(const com::Utf8Str &aPath)
{
HRESULT hrc = S_OK;
const Utf8Str &path = aPath.isEmpty() || aPath == "."? s_pathDefault: aPath;
Console::SafeVMPtr ptrVM(m.pConsole);
if (ptrVM.isOk())
{
EUSBWEBCAM *p = NULL;
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
WebcamsMap::iterator it = m.webcams.find(path);
if (it != m.webcams.end())
{
if (it->second->enmStatus == EUSBDEVICE_ATTACHED)
{
p = it->second;
m.webcams.erase(it);
}
}
alock.release();
if (p)
{
hrc = p->Detach(m.pConsole, ptrVM.rawUVM());
p->Release();
}
else
{
hrc = E_INVALIDARG;
}
}
else
{
hrc = VBOX_E_INVALID_VM_STATE;
}
return hrc;
}
/* static */ DECLCALLBACK(int) EmulatedUSB::eusbCallbackEMT(EmulatedUSB *pThis, char *pszId, uint32_t iEvent,
void *pvData, uint32_t cbData)
{
LogRelFlowFunc(("id %s event %d, data %p %d\n", pszId, iEvent, pvData, cbData));
NOREF(cbData);
int rc = VINF_SUCCESS;
if (iEvent == 0)
{
com::Utf8Str path;
HRESULT hr = pThis->webcamPathFromId(&path, pszId);
if (SUCCEEDED(hr))
{
hr = pThis->webcamDetach(path);
if (FAILED(hr))
{
rc = VERR_INVALID_STATE;
}
}
else
{
rc = VERR_NOT_FOUND;
}
}
else
{
rc = VERR_INVALID_PARAMETER;
}
RTMemFree(pszId);
RTMemFree(pvData);
LogRelFlowFunc(("rc %Rrc\n", rc));
return rc;
}
/* static */ DECLCALLBACK(int) EmulatedUSB::eusbCallback(void *pv, const char *pszId, uint32_t iEvent,
const void *pvData, uint32_t cbData)
{
/* Make a copy of parameters, forward to EMT and leave the callback to not hold any lock in the device. */
int rc = VINF_SUCCESS;
void *pvIdCopy = NULL;
void *pvDataCopy = NULL;
if (cbData > 0)
{
pvDataCopy = RTMemDup(pvData, cbData);
if (!pvDataCopy)
{
rc = VERR_NO_MEMORY;
}
}
if (RT_SUCCESS(rc))
{
pvIdCopy = RTMemDup(pszId, strlen(pszId) + 1);
if (!pvIdCopy)
{
rc = VERR_NO_MEMORY;
}
}
if (RT_SUCCESS(rc))
{
EmulatedUSB *pThis = (EmulatedUSB *)pv;
Console::SafeVMPtr ptrVM(pThis->m.pConsole);
if (ptrVM.isOk())
{
/* No wait. */
rc = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), 0 /* idDstCpu */,
(PFNRT)EmulatedUSB::eusbCallbackEMT, 5,
pThis, pvIdCopy, iEvent, pvDataCopy, cbData);
}
else
{
rc = VERR_INVALID_STATE;
}
}
if (RT_FAILURE(rc))
{
RTMemFree(pvIdCopy);
RTMemFree(pvDataCopy);
}
return rc;
}
HRESULT EmulatedUSB::webcamPathFromId(com::Utf8Str *pPath, const char *pszId)
{
HRESULT hr = S_OK;
Console::SafeVMPtr ptrVM(m.pConsole);
if (ptrVM.isOk())
{
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
WebcamsMap::const_iterator it;
for (it = m.webcams.begin(); it != m.webcams.end(); ++it)
{
EUSBWEBCAM *p = it->second;
if (p->HasId(pszId))
{
*pPath = it->first;
break;
}
}
if (it == m.webcams.end())
{
hr = E_FAIL;
}
alock.release();
}
else
{
hr = VBOX_E_INVALID_VM_STATE;
}
return hr;
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */