VirtualBox

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

最後變更 在這個檔案從60089是 60089,由 vboxsync 提交於 9 年 前

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

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 22.9 KB
 
1/* $Id: USBProxyBackend.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.alldomusa.eu.org. 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 "USBProxyBackend.h"
19#include "USBProxyService.h"
20#include "HostUSBDeviceImpl.h"
21#include "HostImpl.h"
22#include "MachineImpl.h"
23#include "VirtualBoxImpl.h"
24
25#include "AutoCaller.h"
26#include "Logging.h"
27
28#include <VBox/com/array.h>
29#include <VBox/err.h>
30#include <iprt/asm.h>
31#include <iprt/semaphore.h>
32#include <iprt/thread.h>
33#include <iprt/mem.h>
34#include <iprt/string.h>
35#include <iprt/cpp/utils.h>
36
37
38/**
39 * Empty constructor.
40 */
41USBProxyBackend::USBProxyBackend()
42{
43 LogFlowThisFunc(("\n"));
44}
45
46
47/**
48 * Empty destructor.
49 */
50USBProxyBackend::~USBProxyBackend()
51{
52}
53
54
55HRESULT USBProxyBackend::FinalConstruct()
56{
57 return BaseFinalConstruct();
58}
59
60void USBProxyBackend::FinalRelease()
61{
62 uninit();
63 BaseFinalRelease();
64}
65
66/**
67 * Stub needed as long as the class isn't virtual
68 */
69int USBProxyBackend::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress)
70{
71 NOREF(strAddress);
72
73 m_pUsbProxyService = pUsbProxyService;
74 mThread = NIL_RTTHREAD;
75 mTerminate = false;
76 unconst(m_strId) = strId;
77 m_cRefs = 0;
78
79 return VINF_SUCCESS;
80}
81
82
83void USBProxyBackend::uninit()
84{
85 LogFlowThisFunc(("\n"));
86 Assert(mThread == NIL_RTTHREAD);
87 mTerminate = true;
88 m_pUsbProxyService = NULL;
89}
90
91/**
92 * Query if the service is active and working.
93 *
94 * @returns true if the service is up running.
95 * @returns false if the service isn't running.
96 */
97bool USBProxyBackend::isActive(void)
98{
99 return mThread != NIL_RTTHREAD;
100}
101
102
103/**
104 * Returns the ID of the instance.
105 *
106 * @returns ID string for the instance.
107 */
108const com::Utf8Str &USBProxyBackend::i_getId()
109{
110 return m_strId;
111}
112
113
114/**
115 * Returns the current reference counter for the backend.
116 */
117uint32_t USBProxyBackend::i_getRefCount()
118{
119 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
120 return m_cRefs;
121}
122
123
124/**
125 * Runs all the filters on the specified device.
126 *
127 * All filters mean global and active VM, with the exception of those
128 * belonging to \a aMachine. If a global ignore filter matched or if
129 * none of the filters matched, the device will be released back to
130 * the host.
131 *
132 * The device calling us here will be in the HeldByProxy, Unused, or
133 * Capturable state. The caller is aware that locks held might have
134 * to be abandond because of IPC and that the device might be in
135 * almost any state upon return.
136 *
137 *
138 * @returns COM status code (only parameter & state checks will fail).
139 * @param aDevice The USB device to apply filters to.
140 * @param aIgnoreMachine The machine to ignore filters from (we've just
141 * detached the device from this machine).
142 *
143 * @note The caller is expected to own no locks.
144 */
145HRESULT USBProxyBackend::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
146 SessionMachinesList &llOpenedMachines,
147 SessionMachine *aIgnoreMachine)
148{
149 LogFlowThisFunc(("{%s} ignoring=%p\n", aDevice->i_getName().c_str(), aIgnoreMachine));
150
151 /*
152 * Verify preconditions.
153 */
154 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
155 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), E_FAIL);
156
157 /*
158 * Get the lists we'll iterate.
159 */
160 Host::USBDeviceFilterList globalFilters;
161 m_pUsbProxyService->i_getUSBFilters(&globalFilters);
162
163 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
164 AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
165 AssertMsgReturn(aDevice->i_isCapturableOrHeld(), ("{%s} %s\n", aDevice->i_getName().c_str(),
166 aDevice->i_getStateName()), E_FAIL);
167
168 /*
169 * Run global filters filters first.
170 */
171 bool fHoldIt = false;
172 for (Host::USBDeviceFilterList::const_iterator it = globalFilters.begin();
173 it != globalFilters.end();
174 ++it)
175 {
176 AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
177 const HostUSBDeviceFilter::Data &data = (*it)->i_getData();
178 if (aDevice->i_isMatch(data))
179 {
180 USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
181 (*it)->COMGETTER(Action)(&action);
182 if (action == USBDeviceFilterAction_Ignore)
183 {
184 /*
185 * Release the device to the host and we're done.
186 */
187 filterLock.release();
188 devLock.release();
189 alock.release();
190 aDevice->i_requestReleaseToHost();
191 return S_OK;
192 }
193 if (action == USBDeviceFilterAction_Hold)
194 {
195 /*
196 * A device held by the proxy needs to be subjected
197 * to the machine filters.
198 */
199 fHoldIt = true;
200 break;
201 }
202 AssertMsgFailed(("action=%d\n", action));
203 }
204 }
205 globalFilters.clear();
206
207 /*
208 * Run the per-machine filters.
209 */
210 for (SessionMachinesList::const_iterator it = llOpenedMachines.begin();
211 it != llOpenedMachines.end();
212 ++it)
213 {
214 ComObjPtr<SessionMachine> pMachine = *it;
215
216 /* Skip the machine the device was just detached from. */
217 if ( aIgnoreMachine
218 && pMachine == aIgnoreMachine)
219 continue;
220
221 /* runMachineFilters takes care of checking the machine state. */
222 devLock.release();
223 alock.release();
224 if (runMachineFilters(pMachine, aDevice))
225 {
226 LogFlowThisFunc(("{%s} attached to %p\n", aDevice->i_getName().c_str(), (void *)pMachine));
227 return S_OK;
228 }
229 alock.acquire();
230 devLock.acquire();
231 }
232
233 /*
234 * No matching machine, so request hold or release depending
235 * on global filter match.
236 */
237 devLock.release();
238 alock.release();
239 if (fHoldIt)
240 aDevice->i_requestHold();
241 else
242 aDevice->i_requestReleaseToHost();
243 return S_OK;
244}
245
246
247/**
248 * Runs the USB filters of the machine on the device.
249 *
250 * If a match is found we will request capture for VM. This may cause
251 * us to temporary abandon locks while doing IPC.
252 *
253 * @param aMachine Machine whose filters are to be run.
254 * @param aDevice The USB device in question.
255 * @returns @c true if the device has been or is being attached to the VM, @c false otherwise.
256 *
257 * @note Locks several objects temporarily for reading or writing.
258 */
259bool USBProxyBackend::runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice)
260{
261 LogFlowThisFunc(("{%s} aMachine=%p \n", aDevice->i_getName().c_str(), aMachine));
262
263 /*
264 * Validate preconditions.
265 */
266 AssertReturn(aMachine, false);
267 AssertReturn(!isWriteLockOnCurrentThread(), false);
268 AssertReturn(!aMachine->isWriteLockOnCurrentThread(), false);
269 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
270 /* Let HostUSBDevice::requestCaptureToVM() validate the state. */
271
272 /*
273 * Do the job.
274 */
275 ULONG ulMaskedIfs;
276 if (aMachine->i_hasMatchingUSBFilter(aDevice, &ulMaskedIfs))
277 {
278 /* try to capture the device */
279 HRESULT hrc = aDevice->i_requestCaptureForVM(aMachine, false /* aSetError */, Utf8Str(), ulMaskedIfs);
280 return SUCCEEDED(hrc)
281 || hrc == E_UNEXPECTED /* bad device state, give up */;
282 }
283
284 return false;
285}
286
287
288/**
289 * A filter was inserted / loaded.
290 *
291 * @param aFilter Pointer to the inserted filter.
292 * @return ID of the inserted filter
293 */
294void *USBProxyBackend::insertFilter(PCUSBFILTER aFilter)
295{
296 // return non-NULL to fake success.
297 NOREF(aFilter);
298 return (void *)1;
299}
300
301
302/**
303 * A filter was removed.
304 *
305 * @param aId ID of the filter to remove
306 */
307void USBProxyBackend::removeFilter(void *aId)
308{
309 NOREF(aId);
310}
311
312
313/**
314 * A VM is trying to capture a device, do necessary preparations.
315 *
316 * @returns VBox status code.
317 * @param aDevice The device in question.
318 */
319int USBProxyBackend::captureDevice(HostUSBDevice *aDevice)
320{
321 NOREF(aDevice);
322 return VERR_NOT_IMPLEMENTED;
323}
324
325
326/**
327 * Notification that an async captureDevice() operation completed.
328 *
329 * This is used by the proxy to release temporary filters.
330 *
331 * @returns VBox status code.
332 * @param aDevice The device in question.
333 * @param aSuccess Whether it succeeded or failed.
334 */
335void USBProxyBackend::captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
336{
337 NOREF(aDevice);
338 NOREF(aSuccess);
339
340 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
341 incRef();
342}
343
344
345/**
346 * The device is going to be detached from a VM.
347 *
348 * @param aDevice The device in question.
349 *
350 * @todo unused
351 */
352void USBProxyBackend::detachingDevice(HostUSBDevice *aDevice)
353{
354 NOREF(aDevice);
355}
356
357
358/**
359 * A VM is releasing a device back to the host.
360 *
361 * @returns VBox status code.
362 * @param aDevice The device in question.
363 */
364int USBProxyBackend::releaseDevice(HostUSBDevice *aDevice)
365{
366 NOREF(aDevice);
367 return VERR_NOT_IMPLEMENTED;
368}
369
370
371/**
372 * Notification that an async releaseDevice() operation completed.
373 *
374 * This is used by the proxy to release temporary filters.
375 *
376 * @returns VBox status code.
377 * @param aDevice The device in question.
378 * @param aSuccess Whether it succeeded or failed.
379 */
380void USBProxyBackend::releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
381{
382 NOREF(aDevice);
383 NOREF(aSuccess);
384
385 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
386 decRef();
387}
388
389
390// Internals
391/////////////////////////////////////////////////////////////////////////////
392
393
394/**
395 * Starts the service.
396 *
397 * @returns VBox status code.
398 */
399int USBProxyBackend::start(void)
400{
401 int rc = VINF_SUCCESS;
402 if (mThread == NIL_RTTHREAD)
403 {
404 /*
405 * Force update before starting the poller thread.
406 */
407 rc = wait(0);
408 if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED || RT_SUCCESS(rc))
409 {
410 PUSBDEVICE pDevices = getDevices();
411 m_pUsbProxyService->i_updateDeviceList(this, pDevices);
412
413 /*
414 * Create the poller thread which will look for changes.
415 */
416 mTerminate = false;
417 rc = RTThreadCreate(&mThread, USBProxyBackend::serviceThread, this,
418 0, RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "USBPROXY");
419 AssertRC(rc);
420 if (RT_SUCCESS(rc))
421 LogFlowThisFunc(("started mThread=%RTthrd\n", mThread));
422 else
423 mThread = NIL_RTTHREAD;
424 }
425 }
426 else
427 LogFlowThisFunc(("already running, mThread=%RTthrd\n", mThread));
428 return rc;
429}
430
431
432/**
433 * Stops the service.
434 *
435 * @returns VBox status code.
436 */
437int USBProxyBackend::stop(void)
438{
439 int rc = VINF_SUCCESS;
440 if (mThread != NIL_RTTHREAD)
441 {
442 /*
443 * Mark the thread for termination and kick it.
444 */
445 ASMAtomicXchgSize(&mTerminate, true);
446 rc = interruptWait();
447 AssertRC(rc);
448
449 /*
450 * Wait for the thread to finish and then update the state.
451 */
452 rc = RTThreadWait(mThread, 60000, NULL);
453 if (rc == VERR_INVALID_HANDLE)
454 rc = VINF_SUCCESS;
455 if (RT_SUCCESS(rc))
456 {
457 LogFlowThisFunc(("stopped mThread=%RTthrd\n", mThread));
458 mThread = NIL_RTTHREAD;
459 mTerminate = false;
460 }
461 else
462 AssertRC(rc);
463 }
464 else
465 LogFlowThisFunc(("not active\n"));
466
467 /* Make sure there is no device from us in the list anymore. */
468 m_pUsbProxyService->i_updateDeviceList(this, NULL);
469
470 return rc;
471}
472
473
474/**
475 * The service thread created by start().
476 *
477 * @param Thread The thread handle.
478 * @param pvUser Pointer to the USBProxyBackend instance.
479 */
480/*static*/ DECLCALLBACK(int) USBProxyBackend::serviceThread(RTTHREAD /* Thread */, void *pvUser)
481{
482 USBProxyBackend *pThis = (USBProxyBackend *)pvUser;
483 LogFlowFunc(("pThis=%p\n", pThis));
484 pThis->serviceThreadInit();
485 int rc = VINF_SUCCESS;
486
487 /*
488 * Processing loop.
489 */
490 for (;;)
491 {
492 rc = pThis->wait(RT_INDEFINITE_WAIT);
493 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED && rc != VERR_TIMEOUT)
494 break;
495 if (pThis->mTerminate)
496 break;
497
498 PUSBDEVICE pDevices = pThis->getDevices();
499 pThis->m_pUsbProxyService->i_updateDeviceList(pThis, pDevices);
500 }
501
502 pThis->serviceThreadTerm();
503 LogFlowFunc(("returns %Rrc\n", rc));
504 return rc;
505}
506
507
508/**
509 * First call made on the service thread, use it to do
510 * thread initialization.
511 *
512 * The default implementation in USBProxyBackend just a dummy stub.
513 */
514void USBProxyBackend::serviceThreadInit(void)
515{
516}
517
518
519/**
520 * Last call made on the service thread, use it to do
521 * thread termination.
522 */
523void USBProxyBackend::serviceThreadTerm(void)
524{
525}
526
527
528/**
529 * Wait for a change in the USB devices attached to the host.
530 *
531 * The default implementation in USBProxyBackend just a dummy stub.
532 *
533 * @returns VBox status code. VERR_INTERRUPTED and VERR_TIMEOUT are considered
534 * harmless, while all other error status are fatal.
535 * @param aMillies Number of milliseconds to wait.
536 */
537int USBProxyBackend::wait(RTMSINTERVAL aMillies)
538{
539 return RTThreadSleep(RT_MIN(aMillies, 250));
540}
541
542
543/**
544 * Interrupt any wait() call in progress.
545 *
546 * The default implementation in USBProxyBackend just a dummy stub.
547 *
548 * @returns VBox status code.
549 */
550int USBProxyBackend::interruptWait(void)
551{
552 return VERR_NOT_IMPLEMENTED;
553}
554
555
556/**
557 * Get a list of USB device currently attached to the host.
558 *
559 * The default implementation in USBProxyBackend just a dummy stub.
560 *
561 * @returns Pointer to a list of USB devices.
562 * The list nodes are freed individually by calling freeDevice().
563 */
564PUSBDEVICE USBProxyBackend::getDevices(void)
565{
566 return NULL;
567}
568
569
570/**
571 * Performs the required actions when a device has been added.
572 *
573 * This means things like running filters and subsequent capturing and
574 * VM attaching. This may result in IPC and temporary lock abandonment.
575 *
576 * @param aDevice The device in question.
577 * @param aUSBDevice The USB device structure.
578 */
579void USBProxyBackend::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
580 SessionMachinesList &llOpenedMachines,
581 PUSBDEVICE aUSBDevice)
582{
583 /*
584 * Validate preconditions.
585 */
586 AssertReturnVoid(!isWriteLockOnCurrentThread());
587 AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
588 AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
589 LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
590 (HostUSBDevice *)aDevice,
591 aDevice->i_getName().c_str(),
592 aDevice->i_getStateName(),
593 aDevice->i_getId().raw()));
594
595 /*
596 * Run filters on the device.
597 */
598 if (aDevice->i_isCapturableOrHeld())
599 {
600 devLock.release();
601 HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */);
602 AssertComRC(rc);
603 }
604
605 NOREF(aUSBDevice);
606}
607
608
609/**
610 * Remove device notification hook for the OS specific code.
611 *
612 * This is means things like
613 *
614 * @param aDevice The device in question.
615 */
616void USBProxyBackend::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice)
617{
618 /*
619 * Validate preconditions.
620 */
621 AssertReturnVoid(!isWriteLockOnCurrentThread());
622 AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
623 AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
624 LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
625 (HostUSBDevice *)aDevice,
626 aDevice->i_getName().c_str(),
627 aDevice->i_getStateName(),
628 aDevice->i_getId().raw()));
629
630 /*
631 * Detach the device from any machine currently using it,
632 * reset all data and uninitialize the device object.
633 */
634 devLock.release();
635 aDevice->i_onPhysicalDetached();
636}
637
638
639/**
640 * Implement fake capture, ++.
641 *
642 * @returns true if there is a state change.
643 * @param pDevice The device in question.
644 * @param pUSBDevice The USB device structure for the last enumeration.
645 * @param aRunFilters Whether or not to run filters.
646 */
647bool USBProxyBackend::updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
648 SessionMachine **aIgnoreMachine)
649{
650 *aRunFilters = false;
651 *aIgnoreMachine = NULL;
652 AssertReturn(aDevice, false);
653 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
654
655 /*
656 * Just hand it to the device, it knows best what needs to be done.
657 */
658 return aDevice->i_updateStateFake(aUSBDevice, aRunFilters, aIgnoreMachine);
659}
660
661/**
662 * Increments the reference counter.
663 *
664 * @returns New reference count value.
665 */
666uint32_t USBProxyBackend::incRef()
667{
668 Assert(isWriteLockOnCurrentThread());
669
670 return ++m_cRefs;
671}
672
673/**
674 * Decrements the reference counter.
675 *
676 * @returns New reference count value.
677 */
678uint32_t USBProxyBackend::decRef()
679{
680 Assert(isWriteLockOnCurrentThread());
681
682 return --m_cRefs;
683}
684
685/**
686 * Updates the device state.
687 *
688 * This is responsible for calling HostUSBDevice::updateState().
689 *
690 * @returns true if there is a state change.
691 * @param aDevice The device in question.
692 * @param aUSBDevice The USB device structure for the last enumeration.
693 * @param aRunFilters Whether or not to run filters.
694 * @param aIgnoreMachine Machine to ignore when running filters.
695 */
696bool USBProxyBackend::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
697 SessionMachine **aIgnoreMachine)
698{
699 AssertReturn(aDevice, false);
700 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
701
702 return aDevice->i_updateState(aUSBDevice, aRunFilters, aIgnoreMachine);
703}
704
705
706/**
707 * Handle a device which state changed in some significant way.
708 *
709 * This means things like running filters and subsequent capturing and
710 * VM attaching. This may result in IPC and temporary lock abandonment.
711 *
712 * @param aDevice The device.
713 * @param pllOpenedMachines list of running session machines (VirtualBox::getOpenedMachines()); if NULL, we don't run filters
714 * @param aIgnoreMachine Machine to ignore when running filters.
715 */
716void USBProxyBackend::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines,
717 SessionMachine *aIgnoreMachine)
718{
719 /*
720 * Validate preconditions.
721 */
722 AssertReturnVoid(!isWriteLockOnCurrentThread());
723 AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
724 AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
725 LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n",
726 (HostUSBDevice *)aDevice,
727 aDevice->i_getName().c_str(),
728 aDevice->i_getStateName(),
729 aDevice->i_getId().raw(),
730 (pllOpenedMachines != NULL), // used to be "bool aRunFilters"
731 aIgnoreMachine));
732 devLock.release();
733
734 /*
735 * Run filters if requested to do so.
736 */
737 if (pllOpenedMachines)
738 {
739 HRESULT rc = runAllFiltersOnDevice(aDevice, *pllOpenedMachines, aIgnoreMachine);
740 AssertComRC(rc);
741 }
742}
743
744
745
746/**
747 * Free all the members of a USB device returned by getDevice().
748 *
749 * @param pDevice Pointer to the device.
750 */
751/*static*/ void
752USBProxyBackend::freeDeviceMembers(PUSBDEVICE pDevice)
753{
754 RTStrFree((char *)pDevice->pszManufacturer);
755 pDevice->pszManufacturer = NULL;
756 RTStrFree((char *)pDevice->pszProduct);
757 pDevice->pszProduct = NULL;
758 RTStrFree((char *)pDevice->pszSerialNumber);
759 pDevice->pszSerialNumber = NULL;
760
761 RTStrFree((char *)pDevice->pszAddress);
762 pDevice->pszAddress = NULL;
763 RTStrFree((char *)pDevice->pszBackend);
764 pDevice->pszBackend = NULL;
765#ifdef RT_OS_WINDOWS
766 RTStrFree(pDevice->pszAltAddress);
767 pDevice->pszAltAddress = NULL;
768 RTStrFree(pDevice->pszHubName);
769 pDevice->pszHubName = NULL;
770#elif defined(RT_OS_SOLARIS)
771 RTStrFree(pDevice->pszDevicePath);
772 pDevice->pszDevicePath = NULL;
773#endif
774}
775
776
777/**
778 * Free one USB device returned by getDevice().
779 *
780 * @param pDevice Pointer to the device.
781 */
782/*static*/ void
783USBProxyBackend::freeDevice(PUSBDEVICE pDevice)
784{
785 freeDeviceMembers(pDevice);
786 RTMemFree(pDevice);
787}
788
789
790/**
791 * Initializes a filter with the data from the specified device.
792 *
793 * @param aFilter The filter to fill.
794 * @param aDevice The device to fill it with.
795 */
796/*static*/ void
797USBProxyBackend::initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice)
798{
799 PCUSBDEVICE pDev = aDevice->i_getUsbData();
800 int vrc;
801
802 vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_VENDOR_ID, pDev->idVendor, true); AssertRC(vrc);
803 vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_PRODUCT_ID, pDev->idProduct, true); AssertRC(vrc);
804 vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_DEVICE_REV, pDev->bcdDevice, true); AssertRC(vrc);
805 vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_DEVICE_CLASS, pDev->bDeviceClass, true); AssertRC(vrc);
806 vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_DEVICE_SUB_CLASS, pDev->bDeviceSubClass, true); AssertRC(vrc);
807 vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_DEVICE_PROTOCOL, pDev->bDeviceProtocol, true); AssertRC(vrc);
808 vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_PORT, pDev->bPort, false); AssertRC(vrc);
809 vrc = USBFilterSetNumExact(aFilter, USBFILTERIDX_BUS, pDev->bBus, false); AssertRC(vrc);
810 if (pDev->pszSerialNumber)
811 {
812 vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_SERIAL_NUMBER_STR, pDev->pszSerialNumber, true);
813 AssertRC(vrc);
814 }
815 if (pDev->pszProduct)
816 {
817 vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_PRODUCT_STR, pDev->pszProduct, true);
818 AssertRC(vrc);
819 }
820 if (pDev->pszManufacturer)
821 {
822 vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_MANUFACTURER_STR, pDev->pszManufacturer, true);
823 AssertRC(vrc);
824 }
825}
826
827HRESULT USBProxyBackend::getName(com::Utf8Str &aName)
828{
829 /* strId is constant during life time, no need to lock */
830 aName = m_strId;
831 return S_OK;
832}
833
834HRESULT USBProxyBackend::getType(com::Utf8Str &aType)
835{
836 aType = Utf8Str("");
837 return S_OK;
838}
839
840/* vi: set tabstop=4 shiftwidth=4 expandtab: */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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