VirtualBox

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

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

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