USBControllerImpl.cpp revision a542e6eab5e0e6e29972dd2d11cecf736af8342a
/** @file
*
* Implementation of IUSBController.
*/
/*
* Copyright (C) 2006 InnoTek Systemberatung GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*/
#include "USBControllerImpl.h"
#include "MachineImpl.h"
#include "VirtualBoxImpl.h"
#include "HostImpl.h"
#include "USBDeviceImpl.h"
#include "HostUSBDeviceImpl.h"
#include "Logging.h"
#include "USBProxyService.h"
#include <algorithm>
// defines
/////////////////////////////////////////////////////////////////////////////
// constructor / destructor
/////////////////////////////////////////////////////////////////////////////
{
return S_OK;
}
void USBController::FinalRelease()
{
if (isReady())
uninit();
}
// public initializer/uninitializer for internal purposes only
/////////////////////////////////////////////////////////////////////////////
/**
* Initializes the USB controller object.
*
* @returns COM result indicator.
* @param a_pParent Pointer to our parent object.
*/
{
// m_Peer is left null
setReady(true);
return S_OK;
}
/**
* Initializes the USB controller object given another USB controller object
* (a kind of copy constructor). This object shares data with
* the object passed as an argument.
*
* @returns COM result indicator.
* @param a_pParent Pointer to our parent object.
* @param a_pPeer The object to share.
*
* @remark This object must be destroyed before the original object
* it shares data with is destroyed.
*/
{
// create copies of all filters
{
++ it;
}
setReady(true);
return S_OK;
}
/**
* Initializes the USB controller object given another guest object
* (a kind of copy constructor). This object makes a private copy of data
* of the original object passed as an argument.
*/
{
// m_Peer is left null
// create private copies of all filters
{
++ it;
}
setReady(true);
return S_OK;
}
/**
* Uninitializes the instance and sets the ready flag to FALSE.
* Called either from FinalRelease() or by the parent when it gets destroyed.
*/
void USBController::uninit()
{
LogFlowMember(("USBController::uninit()\n"));
AssertReturn (isReady(), (void) 0);
// uninit all filters (including those still referenced by clients)
setReady(false);
}
// IUSBController properties
/////////////////////////////////////////////////////////////////////////////
{
if (!a_pfEnabled)
return E_POINTER;
CHECK_READY();
return S_OK;
}
{
CHECK_READY();
{
}
return S_OK;
}
/**
* Get the USB standard version.
*
* @param a_pusUSBStandard Where to store the BCD version word.
*/
{
if (!a_pusUSBStandard)
return E_POINTER;
CHECK_READY();
*a_pusUSBStandard = 0x0101;
LogFlowMember(("USBController::GetUSBStandard: returns 0x0101\n"));
return S_OK;
}
{
if (!aDevicesFilters)
return E_POINTER;
CHECK_READY();
return S_OK;
}
// IUSBController methods
/////////////////////////////////////////////////////////////////////////////
{
if (!aFilter)
return E_POINTER;
return E_INVALIDARG;
CHECK_READY();
return S_OK;
}
{
if (!aFilter)
return E_INVALIDARG;
CHECK_READY();
/* the machine needs to be mutable */
if (!filter)
return setError (E_INVALIDARG,
tr ("The given USB device filter is not created within "
"this VirtualBox instance"));
return setError (E_INVALIDARG,
tr ("The given USB device filter is already in the list"));
/* backup the list before modification */
/* iterate to the position... */
{
}
else
/* ...and insert */
/// @todo After rewriting Win32 USB support, no more necessary;
// a candidate for removal.
#if 0
/* notify the proxy (only when the filter is active) */
#else
/* notify the proxy (only when it makes sense) */
#endif
{
}
return S_OK;
}
{
if (!aFilter)
return E_POINTER;
CHECK_READY();
/* the machine needs to be mutable */
if (!m_DeviceFilters->size())
return setError (E_INVALIDARG,
tr ("The USB device filter list is empty"));
return setError (E_INVALIDARG,
tr ("Invalid position: %lu (must be in range [0, %lu])"),
/* backup the list before modification */
{
/* iterate to the position... */
/* ...get an element from there... */
/* ...and remove */
}
/* cancel sharing (make an independent copy of data) */
/// @todo After rewriting Win32 USB support, no more necessary;
// a candidate for removal.
#if 0
/* notify the proxy (only when the filter is active) */
#else
/* notify the proxy (only when it makes sense) */
#endif
{
}
return S_OK;
}
// public methods only for internal purposes
/////////////////////////////////////////////////////////////////////////////
/** Loads settings from the configuration node */
{
CHECK_READY();
Assert (controller);
// enabled
bool enabled;
unsigned filterCount = 0;
{
bool active;
// error info is set by init() when appropriate
{
}
}
return rc;
}
/** Saves settings to the configuration node */
{
CHECK_READY();
// first, delete the entry
if (VBOX_SUCCESS (vrc))
{
}
// then, recreate it
// enabled
{
// all are optional
++ it;
}
return S_OK;
}
bool USBController::isModified()
{
return true;
/* see whether any of filters has changed its data */
++ it)
{
if ((*it)->isModified())
return true;
}
return false;
}
bool USBController::isReallyModified()
{
if (m_Data.hasActualChanges())
return true;
if (!m_DeviceFilters.isBackedUp())
{
/* see whether any of filters has changed its data */
++ it)
{
if ((*it)->isReallyModified())
return true;
}
return false;
}
return true;
if (m_DeviceFilters->size() == 0)
return false;
/* Make copies to speed up comparison */
{
bool found = false;
{
{
found = true;
break;
}
else
++ thatIt;
}
if (found)
else
return false;
}
return false;
}
bool USBController::rollback()
{
/* we need the machine state */
bool dataChanged = false;
if (m_Data.isBackedUp())
{
/* we need to check all data to see whether anything will be changed
* after rollback */
}
if (m_DeviceFilters.isBackedUp())
{
ComAssertRet (service, false);
/* uninitialize all new filters (absent in the backed up list) */
{
backedList->end())
{
/// @todo After rewriting Win32 USB support, no more necessary;
// a candidate for removal.
#if 0
/* notify the proxy (only when the filter is active) */
#else
/* notify the proxy (only when it makes sense) */
#endif
{
}
}
++ it;
}
/// @todo After rewriting Win32 USB support, no more necessary;
// a candidate for removal.
#if 0
#else
#endif
{
/* find all removed old filters (absent in the new list)
* and insert them back to the USB proxy */
{
m_DeviceFilters->end())
{
/* notify the proxy (only when necessary) */
{
}
}
++ it;
}
}
/* restore the list */
}
/* here we don't depend on the machine state any more */
/* rollback any changes to filters after restoring the list */
{
if ((*it)->isModified())
{
/* call this to notify the USB proxy about changes */
}
++ it;
}
return dataChanged;
}
void USBController::commit()
{
if (m_Data.isBackedUp())
{
if (m_Peer)
{
// attach new data to the peer and reshare it
}
}
bool commitFilters = false;
if (m_DeviceFilters.isBackedUp())
{
// apply changes to peer
if (m_Peer)
{
// commit all changes to new filters (this will reshare data with
// peers for those who have peers)
{
// look if this filter has a peer filter
if (!peer)
{
// no peer means the filter is a newly created one;
// create a peer owning data this filter share it with
peer.createObject();
}
else
{
// remove peer from the old list
}
// and add it to the new list
++ it;
}
// uninit old peer's filters that are left
{
++ it;
}
// attach new list of filters to our peer
}
else
{
// we have no peer (our parent is the newly created machine);
// just commit changes to filters
commitFilters = true;
}
}
else
{
// the list of filters itself is not changed,
// just commit changes to filters themselves
commitFilters = true;
}
if (commitFilters)
{
{
++ it;
}
}
}
{
if (m_Parent->isRegistered())
{
// reuse onMachineRegistered to tell USB proxy to remove all current filters
AssertComRCReturn (rc, (void) 0);
}
// this will back up current data
// create private copies of all filters
m_DeviceFilters->clear();
++ it)
{
}
if (m_Parent->isRegistered())
{
// reuse onMachineRegistered to tell USB proxy to insert all current filters
AssertComRCReturn (rc, (void) 0);
}
}
/**
* Called by VirtualBox when it changes the registered state
* of the machine this USB controller belongs to.
*
* @param aRegistered new registered state of the machine
*/
{
CHECK_READY();
/// @todo After rewriting Win32 USB support, no more necessary;
// a candidate for removal.
#if 0
notifyProxy (!!aRegistered);
#endif
return S_OK;
}
/**
* Called by setter methods of all USB device filters.
*/
{
CHECK_READY();
/// @todo After rewriting Win32 USB support, no more necessary;
// a candidate for removal.
#if 0
#else
/* we need the machine state */
/* nothing to do if the machine isn't running */
return S_OK;
#endif
{
if (aActiveChanged)
{
{
}
else
{
}
}
else
{
{
/* update the filter in the proxy */
}
}
}
return S_OK;
}
/**
* Returns true if the given USB device matches to at least one of
* this controller's USB device filters.
*
* A HostUSBDevice specific version.
*/
{
if (!isReady())
return false;
bool match = false;
// apply self filters
++ it)
{
}
return match;
}
/**
* Returns true if the given USB device matches to at least one of
* this controller's USB device filters.
*
* A generic version that accepts any IUSBDevice on input.
*
* @note
* This method MUST correlate with HostUSBDevice::isMatch()
* in the sense of the device matching logic.
*/
{
LogFlowThisFunc (("\n"));
if (!isReady())
return false;
// query fields
ComAssertComRCRet (rc, false);
ComAssertRet (vendorId, false);
ComAssertComRCRet (rc, false);
ComAssertRet (productId, false);
ComAssertComRCRet (rc, false);
ComAssertComRCRet (rc, false);
ComAssertComRCRet (rc, false);
ComAssertComRCRet (rc, false);
ComAssertComRCRet (rc, false);
ComAssertComRCRet (rc, false);
ComAssertComRCRet (rc, false);
bool match = false;
// apply self filters
++ it)
{
continue;
continue;
continue;
continue;
#if !defined (__WIN__)
// these filters are temporarily ignored on Win32
continue;
continue;
continue;
continue;
#endif
continue;
match = true;
break;
}
return match;
}
{
if (!isReady())
return false;
{
/* notify the proxy (only if the filter is active) */
{
if (aInsertFilters)
{
}
else
{
}
}
++ it;
}
return S_OK;
}
// private methods
/////////////////////////////////////////////////////////////////////////////