USBProxyServiceWindows.cpp revision b52c24239bed9dc9f284d829b6059073afcb1894
1N/A/* $Id$ */
1N/A/** @file
1N/A * VirtualBox USB Proxy Service, Windows Specialization.
1N/A */
1N/A
1N/A/*
1N/A * Copyright (C) 2006-2010 Oracle Corporation
1N/A *
1N/A * This file is part of VirtualBox Open Source Edition (OSE), as
1N/A * available from http://www.virtualbox.org. This file is free software;
1N/A * you can redistribute it and/or modify it under the terms of the GNU
1N/A * General Public License (GPL) as published by the Free Software
1N/A * Foundation, in version 2 as it comes in the "COPYING" file of the
1N/A * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1N/A * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1N/A */
1N/A
1N/A
1N/A/*******************************************************************************
1N/A* Header Files *
1N/A*******************************************************************************/
1N/A#include "USBProxyService.h"
1N/A#include "Logging.h"
1N/A
1N/A#include <VBox/usb.h>
1N/A#include <VBox/err.h>
1N/A
1N/A#include <iprt/string.h>
1N/A#include <iprt/alloc.h>
1N/A#include <iprt/assert.h>
1N/A#include <iprt/file.h>
1N/A#include <iprt/err.h>
1N/A
1N/A#include <VBox/usblib.h>
1N/A
1N/A
1N/A/**
1N/A * Initialize data members.
1N/A */
1N/AUSBProxyServiceWindows::USBProxyServiceWindows(Host *aHost)
1N/A : USBProxyService(aHost), mhEventInterrupt(INVALID_HANDLE_VALUE)
1N/A{
1N/A LogFlowThisFunc(("aHost=%p\n", aHost));
1N/A}
1N/A
1N/A
1N/A/**
1N/A * Initializes the object (called right after construction).
1N/A *
1N/A * @returns S_OK on success and non-fatal failures, some COM error otherwise.
1N/A */
1N/AHRESULT USBProxyServiceWindows::init(void)
1N/A{
1N/A /*
1N/A * Call the superclass method first.
1N/A */
1N/A HRESULT hrc = USBProxyService::init();
1N/A AssertComRCReturn(hrc, hrc);
1N/A
1N/A /*
1N/A * Create the semaphore (considered fatal).
1N/A */
1N/A mhEventInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
1N/A AssertReturn(mhEventInterrupt != INVALID_HANDLE_VALUE, E_FAIL);
1N/A
1N/A /*
1N/A * Initalize the USB lib and stuff.
1N/A */
1N/A int rc = USBLibInit();
1N/A if (RT_SUCCESS(rc))
1N/A {
1N/A /*
1N/A * Start the poller thread.
1N/A */
1N/A rc = start();
1N/A if (RT_SUCCESS(rc))
1N/A {
1N/A LogFlowThisFunc(("returns successfully\n"));
1N/A return S_OK;
1N/A }
1N/A
1N/A USBLibTerm();
1N/A }
1N/A
1N/A CloseHandle(mhEventInterrupt);
1N/A mhEventInterrupt = INVALID_HANDLE_VALUE;
1N/A
1N/A LogFlowThisFunc(("returns failure!!! (rc=%Rrc)\n", rc));
1N/A mLastError = rc;
1N/A return S_OK;
1N/A}
1N/A
1N/A
1N/A/**
1N/A * Stop all service threads and free the device chain.
1N/A */
1N/AUSBProxyServiceWindows::~USBProxyServiceWindows()
1N/A{
1N/A LogFlowThisFunc(("\n"));
1N/A
1N/A /*
1N/A * Stop the service.
1N/A */
1N/A if (isActive())
1N/A stop();
1N/A
1N/A if (mhEventInterrupt != INVALID_HANDLE_VALUE)
1N/A CloseHandle(mhEventInterrupt);
1N/A mhEventInterrupt = INVALID_HANDLE_VALUE;
1N/A
1N/A /*
1N/A * Terminate the library...
1N/A */
1N/A int rc = USBLibTerm();
1N/A AssertRC(rc);
1N/A}
1N/A
1N/A
1N/Avoid *USBProxyServiceWindows::insertFilter(PCUSBFILTER aFilter)
1N/A{
1N/A AssertReturn(aFilter, NULL);
1N/A
1N/A LogFlow(("USBProxyServiceWindows::insertFilter()\n"));
1N/A
1N/A void *pvId = USBLibAddFilter(aFilter);
1N/A
1N/A LogFlow(("USBProxyServiceWindows::insertFilter(): returning pvId=%p\n", pvId));
1N/A
1N/A return pvId;
1N/A}
1N/A
1N/A
1N/Avoid USBProxyServiceWindows::removeFilter(void *aID)
1N/A{
1N/A LogFlow(("USBProxyServiceWindows::removeFilter(): id=%p\n", aID));
1N/A
1N/A AssertReturnVoid(aID);
1N/A
1N/A USBLibRemoveFilter(aID);
1N/A}
1N/A
1N/A
1N/Aint USBProxyServiceWindows::captureDevice(HostUSBDevice *aDevice)
1N/A{
1N/A AssertReturn(aDevice, VERR_GENERAL_FAILURE);
1N/A AssertReturn(aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
1N/A Assert(aDevice->getUnistate() == kHostUSBDeviceState_Capturing);
1N/A
1N/A/** @todo pass up a one-shot filter like on darwin? */
1N/A USHORT vendorId, productId, revision;
1N/A
1N/A HRESULT rc;
1N/A
1N/A rc = aDevice->COMGETTER(VendorId)(&vendorId);
1N/A AssertComRCReturn(rc, VERR_INTERNAL_ERROR);
1N/A
1N/A rc = aDevice->COMGETTER(ProductId)(&productId);
1N/A AssertComRCReturn(rc, VERR_INTERNAL_ERROR);
1N/A
1N/A rc = aDevice->COMGETTER(Revision)(&revision);
1N/A AssertComRCReturn(rc, VERR_INTERNAL_ERROR);
1N/A
1N/A return USBLibCaptureDevice(vendorId, productId, revision);
1N/A}
1N/A
1N/A
1N/Aint USBProxyServiceWindows::releaseDevice(HostUSBDevice *aDevice)
1N/A{
1N/A AssertReturn(aDevice, VERR_GENERAL_FAILURE);
1N/A AssertReturn(aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
1N/A Assert(aDevice->getUnistate() == kHostUSBDeviceState_ReleasingToHost);
1N/A
1N/A/** @todo pass up a one-shot filter like on darwin? */
1N/A USHORT vendorId, productId, revision;
1N/A HRESULT rc;
1N/A
1N/A rc = aDevice->COMGETTER(VendorId)(&vendorId);
1N/A AssertComRCReturn(rc, VERR_INTERNAL_ERROR);
1N/A
1N/A rc = aDevice->COMGETTER(ProductId)(&productId);
1N/A AssertComRCReturn(rc, VERR_INTERNAL_ERROR);
1N/A
1N/A rc = aDevice->COMGETTER(Revision)(&revision);
1N/A AssertComRCReturn(rc, VERR_INTERNAL_ERROR);
1N/A
1N/A Log(("USBProxyServiceWindows::releaseDevice\n"));
1N/A return USBLibReleaseDevice(vendorId, productId, revision);
1N/A}
1N/A
1N/A
1N/Abool USBProxyServiceWindows::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1N/A{
1N/A /* Nothing special here so far, so fall back on parent */
1N/A return USBProxyService::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
1N/A
1N/A/// @todo remove?
1N/A#if 0
1N/A AssertReturn(aDevice, false);
1N/A AssertReturn(aDevice->isWriteLockOnCurrentThread(), false);
1N/A
1N/A /*
1N/A * We're only called in the 'existing device' state, so if there is a pending async
1N/A * operation we can check if it completed here and suppress state changes if it hasn't.
1N/A */
1N/A /* TESTME */
1N/A if (aDevice->isStatePending())
1N/A {
1N/A bool fRc = aDevice->updateState(aUSBDevice);
1N/A if (fRc)
1N/A {
1N/A if (aDevice->state() != aDevice->pendingState())
1N/A fRc = false;
1N/A }
1N/A return fRc;
1N/A }
1N/A
1N/A /* fall back on parent. */
1N/A return USBProxyService::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
1N/A#endif
1N/A}
1N/A
1N/A
1N/Aint USBProxyServiceWindows::wait(unsigned aMillies)
1N/A{
1N/A DWORD rc;
1N/A
1N/A /* Not going to do something fancy where we block in the filter
1N/A * driver and are woken up when the state has changed.
1N/A * Would be better, but this is good enough.
1N/A */
1N/A do
1N/A {
1N/A rc = WaitForSingleObject(mhEventInterrupt, RT_MIN(aMillies, 100));
if (rc == WAIT_OBJECT_0)
return VINF_SUCCESS;
/** @todo handle WAIT_FAILED here */
if (USBLibHasPendingDeviceChanges() == true)
{
Log(("wait thread detected usb change\n"));
return VINF_SUCCESS;
}
if (aMillies > 100)
aMillies -= 100;
}
while (aMillies > 100);
return VERR_TIMEOUT;
}
int USBProxyServiceWindows::interruptWait(void)
{
SetEvent(mhEventInterrupt);
return VINF_SUCCESS;
}
/**
* Gets a list of all devices the VM can grab
*/
PUSBDEVICE USBProxyServiceWindows::getDevices(void)
{
PUSBDEVICE pDevices = NULL;
uint32_t cDevices = 0;
Log(("USBProxyServiceWindows::getDevices\n"));
USBLibGetDevices(&pDevices, &cDevices);
return pDevices;
}