VirtualBox

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

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