VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/USBProxyService.cpp@ 60089

Last change on this file since 60089 was 60089, checked in by vboxsync, 9 years ago

Main,VBoxManage: Add API to IHost for adding and removing USB device sources in addition to the default host one (only USB/IP backend supported so far which will be used in the future for automatic USB testing). Add support for it in VBoxManage

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.5 KB
Line 
1/* $Id: USBProxyService.cpp 60089 2016-03-18 10:51:02Z vboxsync $ */
2/** @file
3 * VirtualBox USB Proxy Service (base) class.
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "USBProxyService.h"
19#include "HostUSBDeviceImpl.h"
20#include "HostImpl.h"
21#include "MachineImpl.h"
22#include "VirtualBoxImpl.h"
23
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <VBox/com/array.h>
28#include <VBox/err.h>
29#include <iprt/asm.h>
30#include <iprt/semaphore.h>
31#include <iprt/thread.h>
32#include <iprt/mem.h>
33#include <iprt/string.h>
34
35/** Pair of a USB proxy backend and the opaque filter data assigned by the backend. */
36typedef std::pair<ComObjPtr<USBProxyBackend> , void *> USBFilterPair;
37/** List of USB filter pairs. */
38typedef std::list<USBFilterPair> USBFilterList;
39
40/**
41 * Data for a USB device filter.
42 */
43struct USBFilterData
44{
45 USBFilterData()
46 : llUsbFilters()
47 { }
48
49 USBFilterList llUsbFilters;
50};
51
52/**
53 * Initialize data members.
54 */
55USBProxyService::USBProxyService(Host *aHost)
56 : mHost(aHost), mDevices(), mBackends()
57{
58 LogFlowThisFunc(("aHost=%p\n", aHost));
59}
60
61
62/**
63 * Stub needed as long as the class isn't virtual
64 */
65HRESULT USBProxyService::init(void)
66{
67# if defined(RT_OS_DARWIN)
68 ComObjPtr<USBProxyBackendDarwin> UsbProxyBackendHost;
69# elif defined(RT_OS_LINUX)
70 ComObjPtr<USBProxyBackendLinux> UsbProxyBackendHost;
71# elif defined(RT_OS_OS2)
72 ComObjPtr<USBProxyBackendOs2> UsbProxyBackendHost;
73# elif defined(RT_OS_SOLARIS)
74 ComObjPtr<USBProxyBackendSolaris> UsbProxyBackendHost;
75# elif defined(RT_OS_WINDOWS)
76 ComObjPtr<USBProxyBackendWindows> UsbProxyBackendHost;
77# elif defined(RT_OS_FREEBSD)
78 ComObjPtr<USBProxyBackendFreeBSD> UsbProxyBackendHost;
79# else
80 ComObjPtr<USBProxyBackend> UsbProxyBackendHost;
81# endif
82 UsbProxyBackendHost.createObject();
83 int vrc = UsbProxyBackendHost->init(this, Utf8Str("host"), Utf8Str(""));
84 if (RT_FAILURE(vrc))
85 {
86 mLastError = vrc;
87 }
88 else
89 mBackends.push_back(static_cast<ComObjPtr<USBProxyBackend> >(UsbProxyBackendHost));
90
91 return S_OK;
92}
93
94
95/**
96 * Empty destructor.
97 */
98USBProxyService::~USBProxyService()
99{
100 LogFlowThisFunc(("\n"));
101 while (!mBackends.empty())
102 mBackends.pop_front();
103
104 mDevices.clear();
105 mBackends.clear();
106 mHost = NULL;
107}
108
109
110/**
111 * Query if the service is active and working.
112 *
113 * @returns true if the service is up running.
114 * @returns false if the service isn't running.
115 */
116bool USBProxyService::isActive(void)
117{
118 return mBackends.size() > 0;
119}
120
121
122/**
123 * Get last error.
124 * Can be used to check why the proxy !isActive() upon construction.
125 *
126 * @returns VBox status code.
127 */
128int USBProxyService::getLastError(void)
129{
130 return mLastError;
131}
132
133
134/**
135 * We're using the Host object lock.
136 *
137 * This is just a temporary measure until all the USB refactoring is
138 * done, probably... For now it help avoiding deadlocks we don't have
139 * time to fix.
140 *
141 * @returns Lock handle.
142 */
143RWLockHandle *USBProxyService::lockHandle() const
144{
145 return mHost->lockHandle();
146}
147
148
149void *USBProxyService::insertFilter(PCUSBFILTER aFilter)
150{
151 USBFilterData *pFilterData = new USBFilterData();
152
153 for (USBProxyBackendList::iterator it = mBackends.begin();
154 it != mBackends.end();
155 ++it)
156 {
157 USBProxyBackend *pUsbProxyBackend = *it;
158 void *pvId = pUsbProxyBackend->insertFilter(aFilter);
159
160 pFilterData->llUsbFilters.push_back(USBFilterPair(pUsbProxyBackend, pvId));
161 }
162
163 return pFilterData;
164}
165
166void USBProxyService::removeFilter(void *aId)
167{
168 USBFilterData *pFilterData = (USBFilterData *)aId;
169
170 for (USBFilterList::iterator it = pFilterData->llUsbFilters.begin();
171 it != pFilterData->llUsbFilters.end();
172 ++it)
173 {
174 USBProxyBackend *pUsbProxyBackend = it->first;
175 pUsbProxyBackend->removeFilter(it->second);
176 }
177
178 pFilterData->llUsbFilters.clear();
179 delete pFilterData;
180}
181
182/**
183 * Gets the collection of USB devices, slave of Host::USBDevices.
184 *
185 * This is an interface for the HostImpl::USBDevices property getter.
186 *
187 *
188 * @param aUSBDevices Where to store the pointer to the collection.
189 *
190 * @returns COM status code.
191 *
192 * @remarks The caller must own the write lock of the host object.
193 */
194HRESULT USBProxyService::getDeviceCollection(std::vector<ComPtr<IHostUSBDevice> > &aUSBDevices)
195{
196 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
197
198 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
199
200 aUSBDevices.resize(mDevices.size());
201 size_t i = 0;
202 for (HostUSBDeviceList::const_iterator it = mDevices.begin(); it != mDevices.end(); ++it, ++i)
203 aUSBDevices[i] = *it;
204
205 return S_OK;
206}
207
208
209HRESULT USBProxyService::addUSBDeviceSource(const com::Utf8Str &aBackend, const com::Utf8Str &aId, const com::Utf8Str &aAddress,
210 const std::vector<com::Utf8Str> &aPropertyNames, const std::vector<com::Utf8Str> &aPropertyValues)
211{
212 HRESULT hrc = S_OK;
213
214 /* Check whether the ID is used first. */
215 for (USBProxyBackendList::iterator it = mBackends.begin();
216 it != mBackends.end();
217 ++it)
218 {
219 USBProxyBackend *pUsbProxyBackend = *it;
220
221 if (aId.equals(pUsbProxyBackend->i_getId()))
222 return setError(VBOX_E_OBJECT_IN_USE,
223 tr("The USB device source \"%s\" exists already"), aId.c_str());
224 }
225
226 /* Create appropriate proxy backend. */
227 if (aBackend.equalsIgnoreCase("USBIP"))
228 {
229 ComObjPtr<USBProxyBackendUsbIp> UsbProxyBackend;
230
231 UsbProxyBackend.createObject();
232 int vrc = UsbProxyBackend->init(this, aId, aAddress);
233 if (RT_FAILURE(vrc))
234 hrc = setError(E_FAIL,
235 tr("Creating the USB device source \"%s\" using backend \"%s\" failed with %Rrc"),
236 aId.c_str(), aBackend.c_str(), vrc);
237 else
238 mBackends.push_back(static_cast<ComObjPtr<USBProxyBackend> >(UsbProxyBackend));
239 }
240 else
241 hrc = setError(VBOX_E_OBJECT_NOT_FOUND,
242 tr("The USB backend \"%s\" is not supported"), aBackend.c_str());
243
244 return hrc;
245}
246
247HRESULT USBProxyService::removeUSBDeviceSource(const com::Utf8Str &aId)
248{
249 for (USBProxyBackendList::iterator it = mBackends.begin();
250 it != mBackends.end();
251 ++it)
252 {
253 ComObjPtr<USBProxyBackend> UsbProxyBackend = *it;
254
255 if (aId.equals(UsbProxyBackend->i_getId()))
256 {
257 mBackends.erase(it);
258 UsbProxyBackend->uninit();
259 return S_OK;
260 }
261 }
262
263 return setError(VBOX_E_OBJECT_NOT_FOUND,
264 tr("The USB device source \"%s\" could not be found"), aId.c_str());
265}
266
267/**
268 * Request capture of a specific device.
269 *
270 * This is in an interface for SessionMachine::CaptureUSBDevice(), which is
271 * an internal worker used by Console::AttachUSBDevice() from the VM process.
272 *
273 * When the request is completed, SessionMachine::onUSBDeviceAttach() will
274 * be called for the given machine object.
275 *
276 *
277 * @param aMachine The machine to attach the device to.
278 * @param aId The UUID of the USB device to capture and attach.
279 *
280 * @returns COM status code and error info.
281 *
282 * @remarks This method may operate synchronously as well as asynchronously. In the
283 * former case it will temporarily abandon locks because of IPC.
284 */
285HRESULT USBProxyService::captureDeviceForVM(SessionMachine *aMachine, IN_GUID aId, const com::Utf8Str &aCaptureFilename)
286{
287 ComAssertRet(aMachine, E_INVALIDARG);
288 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
289
290 /*
291 * Translate the device id into a device object.
292 */
293 ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId);
294 if (pHostDevice.isNull())
295 return setError(E_INVALIDARG,
296 tr("The USB device with UUID {%RTuuid} is not currently attached to the host"), Guid(aId).raw());
297
298 /*
299 * Try to capture the device
300 */
301 alock.release();
302 return pHostDevice->i_requestCaptureForVM(aMachine, true /* aSetError */, aCaptureFilename);
303}
304
305
306/**
307 * Notification from VM process about USB device detaching progress.
308 *
309 * This is in an interface for SessionMachine::DetachUSBDevice(), which is
310 * an internal worker used by Console::DetachUSBDevice() from the VM process.
311 *
312 * @param aMachine The machine which is sending the notification.
313 * @param aId The UUID of the USB device is concerns.
314 * @param aDone \a false for the pre-action notification (necessary
315 * for advancing the device state to avoid confusing
316 * the guest).
317 * \a true for the post-action notification. The device
318 * will be subjected to all filters except those of
319 * of \a Machine.
320 *
321 * @returns COM status code.
322 *
323 * @remarks When \a aDone is \a true this method may end up doing IPC to other
324 * VMs when running filters. In these cases it will temporarily
325 * abandon its locks.
326 */
327HRESULT USBProxyService::detachDeviceFromVM(SessionMachine *aMachine, IN_GUID aId, bool aDone)
328{
329 LogFlowThisFunc(("aMachine=%p{%s} aId={%RTuuid} aDone=%RTbool\n",
330 aMachine,
331 aMachine->i_getName().c_str(),
332 Guid(aId).raw(),
333 aDone));
334
335 // get a list of all running machines while we're outside the lock
336 // (getOpenedMachines requests locks which are incompatible with the lock of the machines list)
337 SessionMachinesList llOpenedMachines;
338 mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
339
340 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
341
342 ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId);
343 ComAssertRet(!pHostDevice.isNull(), E_FAIL);
344 AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
345
346 /*
347 * Work the state machine.
348 */
349 LogFlowThisFunc(("id={%RTuuid} state=%s aDone=%RTbool name={%s}\n",
350 pHostDevice->i_getId().raw(), pHostDevice->i_getStateName(), aDone, pHostDevice->i_getName().c_str()));
351 bool fRunFilters = false;
352 HRESULT hrc = pHostDevice->i_onDetachFromVM(aMachine, aDone, &fRunFilters);
353
354 /*
355 * Run filters if necessary.
356 */
357 if ( SUCCEEDED(hrc)
358 && fRunFilters)
359 {
360 USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
361 Assert(aDone && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy && pHostDevice->i_getMachine().isNull());
362 devLock.release();
363 alock.release();
364 HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
365 ComAssertComRC(hrc2);
366 }
367 return hrc;
368}
369
370
371/**
372 * Apply filters for the machine to all eligible USB devices.
373 *
374 * This is in an interface for SessionMachine::CaptureUSBDevice(), which
375 * is an internal worker used by Console::AutoCaptureUSBDevices() from the
376 * VM process at VM startup.
377 *
378 * Matching devices will be attached to the VM and may result IPC back
379 * to the VM process via SessionMachine::onUSBDeviceAttach() depending
380 * on whether the device needs to be captured or not. If capture is
381 * required, SessionMachine::onUSBDeviceAttach() will be called
382 * asynchronously by the USB proxy service thread.
383 *
384 * @param aMachine The machine to capture devices for.
385 *
386 * @returns COM status code, perhaps with error info.
387 *
388 * @remarks Temporarily locks this object, the machine object and some USB
389 * device, and the called methods will lock similar objects.
390 */
391HRESULT USBProxyService::autoCaptureDevicesForVM(SessionMachine *aMachine)
392{
393 LogFlowThisFunc(("aMachine=%p{%s}\n",
394 aMachine,
395 aMachine->i_getName().c_str()));
396
397 /*
398 * Make a copy of the list because we cannot hold the lock protecting it.
399 * (This will not make copies of any HostUSBDevice objects, only reference them.)
400 */
401 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
402 HostUSBDeviceList ListCopy = mDevices;
403 alock.release();
404
405 for (HostUSBDeviceList::iterator it = ListCopy.begin();
406 it != ListCopy.end();
407 ++it)
408 {
409 ComObjPtr<HostUSBDevice> pHostDevice = *it;
410 AutoReadLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
411 if ( pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
412 || pHostDevice->i_getUnistate() == kHostUSBDeviceState_Unused
413 || pHostDevice->i_getUnistate() == kHostUSBDeviceState_Capturable)
414 {
415 USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
416 devLock.release();
417 pUsbProxyBackend->runMachineFilters(aMachine, pHostDevice);
418 }
419 }
420
421 return S_OK;
422}
423
424
425/**
426 * Detach all USB devices currently attached to a VM.
427 *
428 * This is in an interface for SessionMachine::DetachAllUSBDevices(), which
429 * is an internal worker used by Console::powerDown() from the VM process
430 * at VM startup, and SessionMachine::uninit() at VM abend.
431 *
432 * This is, like #detachDeviceFromVM(), normally a two stage journey
433 * where \a aDone indicates where we are. In addition we may be called
434 * to clean up VMs that have abended, in which case there will be no
435 * preparatory call. Filters will be applied to the devices in the final
436 * call with the risk that we have to do some IPC when attaching them
437 * to other VMs.
438 *
439 * @param aMachine The machine to detach devices from.
440 *
441 * @returns COM status code, perhaps with error info.
442 *
443 * @remarks Write locks the host object and may temporarily abandon
444 * its locks to perform IPC.
445 */
446HRESULT USBProxyService::detachAllDevicesFromVM(SessionMachine *aMachine, bool aDone, bool aAbnormal)
447{
448 // get a list of all running machines while we're outside the lock
449 // (getOpenedMachines requests locks which are incompatible with the host object lock)
450 SessionMachinesList llOpenedMachines;
451 mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
452
453 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
454
455 /*
456 * Make a copy of the device list (not the HostUSBDevice objects, just
457 * the list) since we may end up performing IPC and temporarily have
458 * to abandon locks when applying filters.
459 */
460 HostUSBDeviceList ListCopy = mDevices;
461
462 for (HostUSBDeviceList::iterator it = ListCopy.begin();
463 it != ListCopy.end();
464 ++it)
465 {
466 ComObjPtr<HostUSBDevice> pHostDevice = *it;
467 AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
468 if (pHostDevice->i_getMachine() == aMachine)
469 {
470 /*
471 * Same procedure as in detachUSBDevice().
472 */
473 bool fRunFilters = false;
474 HRESULT hrc = pHostDevice->i_onDetachFromVM(aMachine, aDone, &fRunFilters, aAbnormal);
475 if ( SUCCEEDED(hrc)
476 && fRunFilters)
477 {
478 USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
479 Assert( aDone
480 && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
481 && pHostDevice->i_getMachine().isNull());
482 devLock.release();
483 alock.release();
484 HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
485 ComAssertComRC(hrc2);
486 alock.acquire();
487 }
488 }
489 }
490
491 return S_OK;
492}
493
494
495// Internals
496/////////////////////////////////////////////////////////////////////////////
497
498
499/**
500 * Sort a list of USB devices.
501 *
502 * @returns Pointer to the head of the sorted doubly linked list.
503 * @param aDevices Head pointer (can be both singly and doubly linked list).
504 */
505static PUSBDEVICE sortDevices(PUSBDEVICE pDevices)
506{
507 PUSBDEVICE pHead = NULL;
508 PUSBDEVICE pTail = NULL;
509 while (pDevices)
510 {
511 /* unlink head */
512 PUSBDEVICE pDev = pDevices;
513 pDevices = pDev->pNext;
514 if (pDevices)
515 pDevices->pPrev = NULL;
516
517 /* find location. */
518 PUSBDEVICE pCur = pTail;
519 while ( pCur
520 && HostUSBDevice::i_compare(pCur, pDev) > 0)
521 pCur = pCur->pPrev;
522
523 /* insert (after pCur) */
524 pDev->pPrev = pCur;
525 if (pCur)
526 {
527 pDev->pNext = pCur->pNext;
528 pCur->pNext = pDev;
529 if (pDev->pNext)
530 pDev->pNext->pPrev = pDev;
531 else
532 pTail = pDev;
533 }
534 else
535 {
536 pDev->pNext = pHead;
537 if (pHead)
538 pHead->pPrev = pDev;
539 else
540 pTail = pDev;
541 pHead = pDev;
542 }
543 }
544
545 LogFlowFuncLeave();
546 return pHead;
547}
548
549
550/**
551 * Process any relevant changes in the attached USB devices.
552 *
553 * This is called from any available USB proxy backends service thread when they discover
554 * a change.
555 */
556void USBProxyService::i_updateDeviceList(USBProxyBackend *pUsbProxyBackend, PUSBDEVICE pDevices)
557{
558 LogFlowThisFunc(("\n"));
559
560 pDevices = sortDevices(pDevices);
561
562 // get a list of all running machines while we're outside the lock
563 // (getOpenedMachines requests higher priority locks)
564 SessionMachinesList llOpenedMachines;
565 mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
566
567 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
568
569 /*
570 * Compare previous list with the new list of devices
571 * and merge in any changes while notifying Host.
572 */
573 HostUSBDeviceList::iterator it = this->mDevices.begin();
574 while ( it != mDevices.end()
575 || pDevices)
576 {
577 ComObjPtr<HostUSBDevice> pHostDevice;
578
579 if (it != mDevices.end())
580 pHostDevice = *it;
581
582 /*
583 * Assert that the object is still alive (we still reference it in
584 * the collection and we're the only one who calls uninit() on it.
585 */
586 AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
587 AssertComRC(devCaller.rc());
588
589 /*
590 * Lock the device object since we will read/write its
591 * properties. All Host callbacks also imply the object is locked.
592 */
593 AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
594 COMMA_LOCKVAL_SRC_POS);
595
596 /* Skip all devices not belonging to the same backend. */
597 if ( !pHostDevice.isNull()
598 && pHostDevice->i_getUsbProxyBackend() != pUsbProxyBackend)
599 {
600 ++it;
601 continue;
602 }
603
604 /*
605 * Compare.
606 */
607 int iDiff;
608 if (pHostDevice.isNull())
609 iDiff = 1;
610 else
611 {
612 if (!pDevices)
613 iDiff = -1;
614 else
615 iDiff = pHostDevice->i_compare(pDevices);
616 }
617 if (!iDiff)
618 {
619 /*
620 * The device still there, update the state and move on. The PUSBDEVICE
621 * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
622 */
623 PUSBDEVICE pCur = pDevices;
624 pDevices = pDevices->pNext;
625 pCur->pPrev = pCur->pNext = NULL;
626
627 bool fRunFilters = false;
628 SessionMachine *pIgnoreMachine = NULL;
629 devLock.release();
630 alock.release();
631 if (pUsbProxyBackend->updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
632 pUsbProxyBackend->deviceChanged(pHostDevice,
633 (fRunFilters ? &llOpenedMachines : NULL),
634 pIgnoreMachine);
635 alock.acquire();
636 ++it;
637 }
638 else
639 {
640 if (iDiff > 0)
641 {
642 /*
643 * Head of pDevices was attached.
644 */
645 PUSBDEVICE pNew = pDevices;
646 pDevices = pDevices->pNext;
647 pNew->pPrev = pNew->pNext = NULL;
648
649 ComObjPtr<HostUSBDevice> NewObj;
650 NewObj.createObject();
651 NewObj->init(pNew, pUsbProxyBackend);
652 Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
653 (HostUSBDevice *)NewObj,
654 NewObj->i_getName().c_str(),
655 NewObj->i_getStateName(),
656 pNew,
657 pNew->idVendor,
658 pNew->idProduct,
659 pNew->pszProduct,
660 pNew->pszManufacturer));
661
662 mDevices.insert(it, NewObj);
663
664 devLock.release();
665 alock.release();
666 pUsbProxyBackend->deviceAdded(NewObj, llOpenedMachines, pNew);
667 alock.acquire();
668 }
669 else
670 {
671 /*
672 * Check if the device was actually detached or logically detached
673 * as the result of a re-enumeration.
674 */
675 if (!pHostDevice->i_wasActuallyDetached())
676 ++it;
677 else
678 {
679 it = mDevices.erase(it);
680 devLock.release();
681 alock.release();
682 pUsbProxyBackend->deviceRemoved(pHostDevice);
683 Log(("USBProxyService::processChanges: detached %p {%s}\n",
684 (HostUSBDevice *)pHostDevice,
685 pHostDevice->i_getName().c_str()));
686
687 /* from now on, the object is no more valid,
688 * uninitialize to avoid abuse */
689 devCaller.release();
690 pHostDevice->uninit();
691 alock.acquire();
692 }
693 }
694 }
695 } /* while */
696
697 LogFlowThisFunc(("returns void\n"));
698}
699
700
701/**
702 * Returns the global USB filter list stored in the Host object.
703 *
704 * @returns nothing.
705 * @param pGlobalFilters Where to store the global filter list on success.
706 */
707void USBProxyService::i_getUSBFilters(USBDeviceFilterList *pGlobalFilters)
708{
709 mHost->i_getUSBFilters(pGlobalFilters);
710}
711
712
713/**
714 * Searches the list of devices (mDevices) for the given device.
715 *
716 *
717 * @returns Smart pointer to the device on success, NULL otherwise.
718 * @param aId The UUID of the device we're looking for.
719 */
720ComObjPtr<HostUSBDevice> USBProxyService::findDeviceById(IN_GUID aId)
721{
722 Guid Id(aId);
723 ComObjPtr<HostUSBDevice> Dev;
724 for (HostUSBDeviceList::iterator it = mDevices.begin();
725 it != mDevices.end();
726 ++it)
727 if ((*it)->i_getId() == Id)
728 {
729 Dev = (*it);
730 break;
731 }
732
733 return Dev;
734}
735
736/*static*/
737HRESULT USBProxyService::setError(HRESULT aResultCode, const char *aText, ...)
738{
739 va_list va;
740 va_start(va, aText);
741 HRESULT rc = VirtualBoxBase::setErrorInternal(aResultCode,
742 COM_IIDOF(IHost),
743 "USBProxyService",
744 Utf8StrFmt(aText, va),
745 false /* aWarning*/,
746 true /* aLogIt*/);
747 va_end(va);
748 return rc;
749}
750
751/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette