VirtualBox

source: vbox/trunk/src/VBox/Main/USBControllerImpl.cpp@ 3090

Last change on this file since 3090 was 3007, checked in by vboxsync, 18 years ago

Moved the template code out of cdefs.h, partly because it didn't belong there but mostly because it was at the end of the file and would screw up any attempts made by the object cache at avoid recompiling on cdefs.h changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.3 KB
Line 
1/** @file
2 *
3 * Implementation of IUSBController.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23
24#include "USBControllerImpl.h"
25#include "MachineImpl.h"
26#include "VirtualBoxImpl.h"
27#include "HostImpl.h"
28#include "USBDeviceImpl.h"
29#include "HostUSBDeviceImpl.h"
30#include "Logging.h"
31
32#include "USBProxyService.h"
33
34#include <iprt/string.h>
35#include <iprt/cpputils.h>
36#include <VBox/err.h>
37
38#include <algorithm>
39
40// defines
41/////////////////////////////////////////////////////////////////////////////
42
43// constructor / destructor
44/////////////////////////////////////////////////////////////////////////////
45
46DEFINE_EMPTY_CTOR_DTOR (USBController)
47
48HRESULT USBController::FinalConstruct()
49{
50 return S_OK;
51}
52
53void USBController::FinalRelease()
54{
55 uninit();
56}
57
58// public initializer/uninitializer for internal purposes only
59/////////////////////////////////////////////////////////////////////////////
60
61/**
62 * Initializes the USB controller object.
63 *
64 * @returns COM result indicator.
65 * @param aParent Pointer to our parent object.
66 */
67HRESULT USBController::init (Machine *aParent)
68{
69 LogFlowThisFunc (("aParent=%p\n", aParent));
70
71 ComAssertRet (aParent, E_INVALIDARG);
72
73 /* Enclose the state transition NotReady->InInit->Ready */
74 AutoInitSpan autoInitSpan (this);
75 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
76
77 unconst (mParent) = aParent;
78 /* mPeer is left null */
79
80 mData.allocate();
81 mDeviceFilters.allocate();
82
83 /* Confirm a successful initialization */
84 autoInitSpan.setSucceeded();
85
86 return S_OK;
87}
88
89
90/**
91 * Initializes the USB controller object given another USB controller object
92 * (a kind of copy constructor). This object shares data with
93 * the object passed as an argument.
94 *
95 * @returns COM result indicator.
96 * @param aParent Pointer to our parent object.
97 * @param aPeer The object to share.
98 *
99 * @note This object must be destroyed before the original object
100 * it shares data with is destroyed.
101 */
102HRESULT USBController::init (Machine *aParent, USBController *aPeer)
103{
104 LogFlowThisFunc (("aParent=%p, aPeer=%p\n", aParent, aPeer));
105
106 ComAssertRet (aParent && aPeer, E_INVALIDARG);
107
108 /* Enclose the state transition NotReady->InInit->Ready */
109 AutoInitSpan autoInitSpan (this);
110 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
111
112 unconst (mParent) = aParent;
113 unconst (mPeer) = aPeer;
114
115 AutoLock thatlock (aPeer);
116 mData.share (aPeer->mData);
117
118 /* create copies of all filters */
119 mDeviceFilters.allocate();
120 DeviceFilterList::const_iterator it = aPeer->mDeviceFilters->begin();
121 while (it != aPeer->mDeviceFilters->end())
122 {
123 ComObjPtr <USBDeviceFilter> filter;
124 filter.createObject();
125 filter->init (this, *it);
126 mDeviceFilters->push_back (filter);
127 ++ it;
128 }
129
130 /* Confirm a successful initialization */
131 autoInitSpan.setSucceeded();
132
133 return S_OK;
134}
135
136
137/**
138 * Initializes the USB controller object given another guest object
139 * (a kind of copy constructor). This object makes a private copy of data
140 * of the original object passed as an argument.
141 */
142HRESULT USBController::initCopy (Machine *aParent, USBController *aPeer)
143{
144 LogFlowThisFunc (("aParent=%p, aPeer=%p\n", aParent, aPeer));
145
146 ComAssertRet (aParent && aPeer, E_INVALIDARG);
147
148 /* Enclose the state transition NotReady->InInit->Ready */
149 AutoInitSpan autoInitSpan (this);
150 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
151
152 unconst (mParent) = aParent;
153 /* mPeer is left null */
154
155 AutoLock thatlock (aPeer);
156 mData.attachCopy (aPeer->mData);
157
158 /* create private copies of all filters */
159 mDeviceFilters.allocate();
160 DeviceFilterList::const_iterator it = aPeer->mDeviceFilters->begin();
161 while (it != aPeer->mDeviceFilters->end())
162 {
163 ComObjPtr <USBDeviceFilter> filter;
164 filter.createObject();
165 filter->initCopy (this, *it);
166 mDeviceFilters->push_back (filter);
167 ++ it;
168 }
169
170 /* Confirm a successful initialization */
171 autoInitSpan.setSucceeded();
172
173 return S_OK;
174}
175
176
177/**
178 * Uninitializes the instance and sets the ready flag to FALSE.
179 * Called either from FinalRelease() or by the parent when it gets destroyed.
180 */
181void USBController::uninit()
182{
183 LogFlowThisFunc (("\n"));
184
185 /* Enclose the state transition Ready->InUninit->NotReady */
186 AutoUninitSpan autoUninitSpan (this);
187 if (autoUninitSpan.uninitDone())
188 return;
189
190 /* uninit all filters (including those still referenced by clients) */
191 uninitDependentChildren();
192
193 mDeviceFilters.free();
194 mData.free();
195
196 unconst (mPeer).setNull();
197 unconst (mParent).setNull();
198}
199
200
201// IUSBController properties
202/////////////////////////////////////////////////////////////////////////////
203
204STDMETHODIMP USBController::COMGETTER(Enabled) (BOOL *aEnabled)
205{
206 if (!aEnabled)
207 return E_POINTER;
208
209 AutoCaller autoCaller (this);
210 CheckComRCReturnRC (autoCaller.rc());
211
212 AutoReaderLock alock (this);
213
214 *aEnabled = mData->mEnabled;
215
216 LogFlowThisFunc (("returns %RTbool\n", *aEnabled));
217
218 return S_OK;
219}
220
221
222STDMETHODIMP USBController::COMSETTER(Enabled) (BOOL aEnabled)
223{
224 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
225
226 AutoCaller autoCaller (this);
227 CheckComRCReturnRC (autoCaller.rc());
228
229 AutoLock alock (this);
230
231 CHECK_MACHINE_MUTABILITY (mParent);
232
233 if (mData->mEnabled != aEnabled)
234 {
235 mData.backup();
236 mData->mEnabled = aEnabled;
237
238 /* leave the lock for safety */
239 alock.leave();
240
241 mParent->onUSBControllerChange();
242 }
243
244 return S_OK;
245}
246
247STDMETHODIMP USBController::COMGETTER(USBStandard) (USHORT *aUSBStandard)
248{
249 if (!aUSBStandard)
250 return E_POINTER;
251
252 AutoCaller autoCaller (this);
253 CheckComRCReturnRC (autoCaller.rc());
254
255 /* not accessing data -- no need to lock */
256
257 *aUSBStandard = 0x0101;
258
259 LogFlowThisFunc (("returns %04hX\n", *aUSBStandard));
260
261 return S_OK;
262}
263
264STDMETHODIMP USBController::COMGETTER(DeviceFilters) (IUSBDeviceFilterCollection **aDevicesFilters)
265{
266 if (!aDevicesFilters)
267 return E_POINTER;
268
269 AutoCaller autoCaller (this);
270 CheckComRCReturnRC (autoCaller.rc());
271
272 AutoReaderLock alock (this);
273
274 ComObjPtr <USBDeviceFilterCollection> collection;
275 collection.createObject();
276 collection->init (*mDeviceFilters.data());
277 collection.queryInterfaceTo (aDevicesFilters);
278
279 return S_OK;
280}
281
282// IUSBController methods
283/////////////////////////////////////////////////////////////////////////////
284
285STDMETHODIMP USBController::CreateDeviceFilter (INPTR BSTR aName,
286 IUSBDeviceFilter **aFilter)
287{
288 if (!aFilter)
289 return E_POINTER;
290
291 if (!aName || *aName == 0)
292 return E_INVALIDARG;
293
294 AutoCaller autoCaller (this);
295 CheckComRCReturnRC (autoCaller.rc());
296
297 AutoLock alock (this);
298
299 CHECK_MACHINE_MUTABILITY (mParent);
300
301 ComObjPtr <USBDeviceFilter> filter;
302 filter.createObject();
303 HRESULT rc = filter->init (this, aName);
304 ComAssertComRCRetRC (rc);
305 rc = filter.queryInterfaceTo (aFilter);
306 AssertComRCReturnRC (rc);
307
308 return S_OK;
309}
310
311STDMETHODIMP USBController::InsertDeviceFilter (ULONG aPosition,
312 IUSBDeviceFilter *aFilter)
313{
314 if (!aFilter)
315 return E_INVALIDARG;
316
317 AutoCaller autoCaller (this);
318 CheckComRCReturnRC (autoCaller.rc());
319
320 /* the machine needs to be mutable */
321 Machine::AutoStateDependency <Machine::MutableStateDep> adep (mParent);
322 CheckComRCReturnRC (adep.rc());
323
324 AutoLock alock (this);
325
326 ComObjPtr <USBDeviceFilter> filter = getDependentChild (aFilter);
327 if (!filter)
328 return setError (E_INVALIDARG,
329 tr ("The given USB device filter is not created within "
330 "this VirtualBox instance"));
331
332 if (filter->mInList)
333 return setError (E_INVALIDARG,
334 tr ("The given USB device filter is already in the list"));
335
336 /* backup the list before modification */
337 mDeviceFilters.backup();
338
339 /* iterate to the position... */
340 DeviceFilterList::iterator it;
341 if (aPosition < mDeviceFilters->size())
342 {
343 it = mDeviceFilters->begin();
344 std::advance (it, aPosition);
345 }
346 else
347 it = mDeviceFilters->end();
348 /* ...and insert */
349 mDeviceFilters->insert (it, filter);
350 filter->mInList = true;
351
352 /// @todo After rewriting Win32 USB support, no more necessary;
353 // a candidate for removal.
354#if 0
355 /* notify the proxy (only when the filter is active) */
356 if (filter->data().mActive)
357#else
358 /* notify the proxy (only when it makes sense) */
359 if (filter->data().mActive && adep.machineState() >= MachineState_Running)
360#endif
361 {
362 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
363 ComAssertRet (service, E_FAIL);
364
365 ComAssertRet (filter->id() == NULL, E_FAIL);
366 filter->id() = service->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
367 }
368
369 return S_OK;
370}
371
372STDMETHODIMP USBController::RemoveDeviceFilter (ULONG aPosition,
373 IUSBDeviceFilter **aFilter)
374{
375 if (!aFilter)
376 return E_POINTER;
377
378 AutoCaller autoCaller (this);
379 CheckComRCReturnRC (autoCaller.rc());
380
381 /* the machine needs to be mutable */
382 Machine::AutoStateDependency <Machine::MutableStateDep> adep (mParent);
383 CheckComRCReturnRC (adep.rc());
384
385 AutoLock alock (this);
386
387 if (!mDeviceFilters->size())
388 return setError (E_INVALIDARG,
389 tr ("The USB device filter list is empty"));
390
391 if (aPosition >= mDeviceFilters->size())
392 return setError (E_INVALIDARG,
393 tr ("Invalid position: %lu (must be in range [0, %lu])"),
394 aPosition, mDeviceFilters->size() - 1);
395
396 /* backup the list before modification */
397 mDeviceFilters.backup();
398
399 ComObjPtr <USBDeviceFilter> filter;
400 {
401 /* iterate to the position... */
402 DeviceFilterList::iterator it = mDeviceFilters->begin();
403 std::advance (it, aPosition);
404 /* ...get an element from there... */
405 filter = *it;
406 /* ...and remove */
407 filter->mInList = false;
408 mDeviceFilters->erase (it);
409 }
410
411 /* cancel sharing (make an independent copy of data) */
412 filter->unshare();
413
414 filter.queryInterfaceTo (aFilter);
415
416 /// @todo After rewriting Win32 USB support, no more necessary;
417 // a candidate for removal.
418#if 0
419 /* notify the proxy (only when the filter is active) */
420 if (filter->data().mActive)
421#else
422 /* notify the proxy (only when it makes sense) */
423 if (filter->data().mActive && adep.machineState() >= MachineState_Running)
424#endif
425 {
426 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
427 ComAssertRet (service, E_FAIL);
428
429 ComAssertRet (filter->id() != NULL, E_FAIL);
430 service->removeFilter (filter->id());
431 filter->id() = NULL;
432 }
433
434 return S_OK;
435}
436
437// public methods only for internal purposes
438/////////////////////////////////////////////////////////////////////////////
439
440/**
441 * Loads settings from the configuration node.
442 *
443 * @note Locks objects for reading!
444 */
445HRESULT USBController::loadSettings (CFGNODE aMachine)
446{
447 ComAssertRet (aMachine, E_FAIL);
448
449 AutoCaller autoCaller (this);
450 CheckComRCReturnRC (autoCaller.rc());
451
452 AutoLock alock (this);
453
454 CFGNODE controller = NULL;
455 CFGLDRGetChildNode (aMachine, "USBController", 0, &controller);
456 Assert (controller);
457
458 /* enabled */
459 bool enabled;
460 CFGLDRQueryBool (controller, "enabled", &enabled);
461 mData->mEnabled = enabled;
462
463 HRESULT rc = S_OK;
464
465 unsigned filterCount = 0;
466 CFGLDRCountChildren (controller, "DeviceFilter", &filterCount);
467 for (unsigned i = 0; i < filterCount && SUCCEEDED (rc); i++)
468 {
469 CFGNODE filter = NULL;
470 CFGLDRGetChildNode (controller, "DeviceFilter", i, &filter);
471 Assert (filter);
472
473 Bstr name;
474 CFGLDRQueryBSTR (filter, "name", name.asOutParam());
475 bool active;
476 CFGLDRQueryBool (filter, "active", &active);
477
478 Bstr vendorId;
479 CFGLDRQueryBSTR (filter, "vendorid", vendorId.asOutParam());
480 Bstr productId;
481 CFGLDRQueryBSTR (filter, "productid", productId.asOutParam());
482 Bstr revision;
483 CFGLDRQueryBSTR (filter, "revision", revision.asOutParam());
484 Bstr manufacturer;
485 CFGLDRQueryBSTR (filter, "manufacturer", manufacturer.asOutParam());
486 Bstr product;
487 CFGLDRQueryBSTR (filter, "product", product.asOutParam());
488 Bstr serialNumber;
489 CFGLDRQueryBSTR (filter, "serialnumber", serialNumber.asOutParam());
490 Bstr port;
491 CFGLDRQueryBSTR (filter, "port", port.asOutParam());
492 Bstr remote;
493 CFGLDRQueryBSTR (filter, "remote", remote.asOutParam());
494
495 ComObjPtr <USBDeviceFilter> filterObj;
496 filterObj.createObject();
497 rc = filterObj->init (this,
498 name, active, vendorId, productId, revision,
499 manufacturer, product, serialNumber,
500 port, remote);
501 /* error info is set by init() when appropriate */
502 if (SUCCEEDED (rc))
503 {
504 mDeviceFilters->push_back (filterObj);
505 filterObj->mInList = true;
506 }
507
508 CFGLDRReleaseNode (filter);
509 }
510
511 CFGLDRReleaseNode (controller);
512
513 return rc;
514}
515
516/**
517 * Saves settings to the configuration node.
518 *
519 * @note Locks objects for reading!
520 */
521HRESULT USBController::saveSettings (CFGNODE aMachine)
522{
523 ComAssertRet (aMachine, E_FAIL);
524
525 AutoCaller autoCaller (this);
526 CheckComRCReturnRC (autoCaller.rc());
527
528 AutoReaderLock alock (this);
529
530 /* first, delete the entry */
531 CFGNODE controller = NULL;
532 int vrc = CFGLDRGetChildNode (aMachine, "USBController", 0, &controller);
533 if (VBOX_SUCCESS (vrc))
534 {
535 vrc = CFGLDRDeleteNode (controller);
536 ComAssertRCRet (vrc, E_FAIL);
537 }
538 /* then, recreate it */
539 vrc = CFGLDRCreateChildNode (aMachine, "USBController", &controller);
540 ComAssertRCRet (vrc, E_FAIL);
541
542 /* enabled */
543 CFGLDRSetBool (controller, "enabled", !!mData->mEnabled);
544
545 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
546 while (it != mDeviceFilters->end())
547 {
548 AutoLock filterLock (*it);
549 const USBDeviceFilter::Data &data = (*it)->data();
550
551 CFGNODE filter = NULL;
552 CFGLDRAppendChildNode (controller, "DeviceFilter", &filter);
553
554 CFGLDRSetBSTR (filter, "name", data.mName);
555 CFGLDRSetBool (filter, "active", !!data.mActive);
556
557 /* all are optional */
558 if (data.mVendorId.string())
559 CFGLDRSetBSTR (filter, "vendorid", data.mVendorId.string());
560 if (data.mProductId.string())
561 CFGLDRSetBSTR (filter, "productid", data.mProductId.string());
562 if (data.mRevision.string())
563 CFGLDRSetBSTR (filter, "revision", data.mRevision.string());
564 if (data.mManufacturer.string())
565 CFGLDRSetBSTR (filter, "manufacturer", data.mManufacturer.string());
566 if (data.mProduct.string())
567 CFGLDRSetBSTR (filter, "product", data.mProduct.string());
568 if (data.mSerialNumber.string())
569 CFGLDRSetBSTR (filter, "serialnumber", data.mSerialNumber.string());
570 if (data.mPort.string())
571 CFGLDRSetBSTR (filter, "port", data.mPort.string());
572 if (data.mRemote.string())
573 CFGLDRSetBSTR (filter, "remote", data.mRemote.string());
574
575 CFGLDRReleaseNode (filter);
576
577 ++ it;
578 }
579
580 CFGLDRReleaseNode (controller);
581
582 return S_OK;
583}
584
585/** @note Locks objects for reading! */
586bool USBController::isModified()
587{
588 AutoCaller autoCaller (this);
589 AssertComRCReturn (autoCaller.rc(), false);
590
591 AutoReaderLock alock (this);
592
593 if (mData.isBackedUp() || mDeviceFilters.isBackedUp())
594 return true;
595
596 /* see whether any of filters has changed its data */
597 for (DeviceFilterList::const_iterator
598 it = mDeviceFilters->begin();
599 it != mDeviceFilters->end();
600 ++ it)
601 {
602 if ((*it)->isModified())
603 return true;
604 }
605
606 return false;
607}
608
609/** @note Locks objects for reading! */
610bool USBController::isReallyModified()
611{
612 AutoCaller autoCaller (this);
613 AssertComRCReturn (autoCaller.rc(), false);
614
615 AutoReaderLock alock (this);
616
617 if (mData.hasActualChanges())
618 return true;
619
620 if (!mDeviceFilters.isBackedUp())
621 {
622 /* see whether any of filters has changed its data */
623 for (DeviceFilterList::const_iterator
624 it = mDeviceFilters->begin();
625 it != mDeviceFilters->end();
626 ++ it)
627 {
628 if ((*it)->isReallyModified())
629 return true;
630 }
631
632 return false;
633 }
634
635 if (mDeviceFilters->size() != mDeviceFilters.backedUpData()->size())
636 return true;
637
638 if (mDeviceFilters->size() == 0)
639 return false;
640
641 /* Make copies to speed up comparison */
642 DeviceFilterList devices = *mDeviceFilters.data();
643 DeviceFilterList backDevices = *mDeviceFilters.backedUpData();
644
645 DeviceFilterList::iterator it = devices.begin();
646 while (it != devices.end())
647 {
648 bool found = false;
649 DeviceFilterList::iterator thatIt = backDevices.begin();
650 while (thatIt != backDevices.end())
651 {
652 if ((*it)->data() == (*thatIt)->data())
653 {
654 backDevices.erase (thatIt);
655 found = true;
656 break;
657 }
658 else
659 ++ thatIt;
660 }
661 if (found)
662 it = devices.erase (it);
663 else
664 return false;
665 }
666
667 Assert (devices.size() == 0 && backDevices.size() == 0);
668
669 return false;
670}
671
672/** @note Locks objects for writing! */
673bool USBController::rollback()
674{
675 AutoCaller autoCaller (this);
676 AssertComRCReturn (autoCaller.rc(), false);
677
678 /* we need the machine state */
679 Machine::AutoStateDependency <Machine::MutableStateDep> adep (mParent);
680 AssertComRCReturn (adep.rc(), false);
681
682 AutoLock alock (this);
683
684 bool dataChanged = false;
685
686 if (mData.isBackedUp())
687 {
688 /* we need to check all data to see whether anything will be changed
689 * after rollback */
690 dataChanged = mData.hasActualChanges();
691 mData.rollback();
692 }
693
694 if (mDeviceFilters.isBackedUp())
695 {
696 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
697 ComAssertRet (service, false);
698
699 /* uninitialize all new filters (absent in the backed up list) */
700 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
701 DeviceFilterList *backedList = mDeviceFilters.backedUpData();
702 while (it != mDeviceFilters->end())
703 {
704 if (std::find (backedList->begin(), backedList->end(), *it) ==
705 backedList->end())
706 {
707 /// @todo After rewriting Win32 USB support, no more necessary;
708 // a candidate for removal.
709#if 0
710 /* notify the proxy (only when the filter is active) */
711 if ((*it)->data().mActive)
712#else
713 /* notify the proxy (only when it makes sense) */
714 if ((*it)->data().mActive &&
715 adep.machineState() >= MachineState_Running)
716#endif
717 {
718 USBDeviceFilter *filter = *it;
719 ComAssertRet (filter->id() != NULL, false);
720 service->removeFilter (filter->id());
721 filter->id() = NULL;
722 }
723
724 (*it)->uninit();
725 }
726 ++ it;
727 }
728
729 /// @todo After rewriting Win32 USB support, no more necessary;
730 // a candidate for removal.
731#if 0
732#else
733 if (adep.machineState() >= MachineState_Running)
734#endif
735 {
736 /* find all removed old filters (absent in the new list)
737 * and insert them back to the USB proxy */
738 it = backedList->begin();
739 while (it != backedList->end())
740 {
741 if (std::find (mDeviceFilters->begin(), mDeviceFilters->end(), *it) ==
742 mDeviceFilters->end())
743 {
744 /* notify the proxy (only when necessary) */
745 if ((*it)->data().mActive)
746 {
747 USBDeviceFilter *flt = *it; /* resolve ambiguity */
748 ComAssertRet (flt->id() == NULL, false);
749 flt->id() = service->insertFilter
750 (ComPtr <IUSBDeviceFilter> (flt));
751 }
752 }
753 ++ it;
754 }
755 }
756
757 /* restore the list */
758 mDeviceFilters.rollback();
759 }
760
761 /* here we don't depend on the machine state any more */
762 adep.release();
763
764 /* rollback any changes to filters after restoring the list */
765 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
766 while (it != mDeviceFilters->end())
767 {
768 if ((*it)->isModified())
769 {
770 (*it)->rollback();
771 /* call this to notify the USB proxy about changes */
772 onDeviceFilterChange (*it);
773 }
774 ++ it;
775 }
776
777 return dataChanged;
778}
779
780/** @note Locks objects for writing! */
781void USBController::commit()
782{
783 AutoCaller autoCaller (this);
784 AssertComRCReturnVoid (autoCaller.rc());
785
786 AutoLock alock (this);
787
788 if (mData.isBackedUp())
789 {
790 mData.commit();
791 if (mPeer)
792 {
793 // attach new data to the peer and reshare it
794 AutoLock peerlock (mPeer);
795 mPeer->mData.attach (mData);
796 }
797 }
798
799 bool commitFilters = false;
800
801 if (mDeviceFilters.isBackedUp())
802 {
803 mDeviceFilters.commit();
804
805 // apply changes to peer
806 if (mPeer)
807 {
808 AutoLock peerlock (mPeer);
809 // commit all changes to new filters (this will reshare data with
810 // peers for those who have peers)
811 DeviceFilterList *newList = new DeviceFilterList();
812 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
813 while (it != mDeviceFilters->end())
814 {
815 (*it)->commit();
816
817 // look if this filter has a peer filter
818 ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
819 if (!peer)
820 {
821 // no peer means the filter is a newly created one;
822 // create a peer owning data this filter share it with
823 peer.createObject();
824 peer->init (mPeer, *it, true /* aReshare */);
825 }
826 else
827 {
828 // remove peer from the old list
829 mPeer->mDeviceFilters->remove (peer);
830 }
831 // and add it to the new list
832 newList->push_back (peer);
833
834 ++ it;
835 }
836
837 // uninit old peer's filters that are left
838 it = mPeer->mDeviceFilters->begin();
839 while (it != mPeer->mDeviceFilters->end())
840 {
841 (*it)->uninit();
842 ++ it;
843 }
844
845 // attach new list of filters to our peer
846 mPeer->mDeviceFilters.attach (newList);
847 }
848 else
849 {
850 // we have no peer (our parent is the newly created machine);
851 // just commit changes to filters
852 commitFilters = true;
853 }
854 }
855 else
856 {
857 // the list of filters itself is not changed,
858 // just commit changes to filters themselves
859 commitFilters = true;
860 }
861
862 if (commitFilters)
863 {
864 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
865 while (it != mDeviceFilters->end())
866 {
867 (*it)->commit();
868 ++ it;
869 }
870 }
871}
872
873/** @note Locks object for writing and that object for reading! */
874void USBController::copyFrom (USBController *aThat)
875{
876 AutoCaller autoCaller (this);
877 AssertComRCReturnVoid (autoCaller.rc());
878
879 AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
880
881 if (mParent->isRegistered())
882 {
883 /* reuse onMachineRegistered to tell USB proxy to remove all current
884 filters */
885 HRESULT rc = onMachineRegistered (FALSE);
886 AssertComRCReturn (rc, (void) 0);
887 }
888
889 /* this will back up current data */
890 mData.assignCopy (aThat->mData);
891
892 /* create private copies of all filters */
893 mDeviceFilters.backup();
894 mDeviceFilters->clear();
895 for (DeviceFilterList::const_iterator it = aThat->mDeviceFilters->begin();
896 it != aThat->mDeviceFilters->end();
897 ++ it)
898 {
899 ComObjPtr <USBDeviceFilter> filter;
900 filter.createObject();
901 filter->initCopy (this, *it);
902 mDeviceFilters->push_back (filter);
903 }
904
905 if (mParent->isRegistered())
906 {
907 /* reuse onMachineRegistered to tell USB proxy to insert all current
908 filters */
909 HRESULT rc = onMachineRegistered (TRUE);
910 AssertComRCReturn (rc, (void) 0);
911 }
912}
913
914/**
915 * Called by VirtualBox when it changes the registered state
916 * of the machine this USB controller belongs to.
917 *
918 * @param aRegistered new registered state of the machine
919 *
920 * @note Locks nothing.
921 */
922HRESULT USBController::onMachineRegistered (BOOL aRegistered)
923{
924 AutoCaller autoCaller (this);
925 AssertComRCReturnRC (autoCaller.rc());
926
927 /// @todo After rewriting Win32 USB support, no more necessary;
928 // a candidate for removal.
929#if 0
930 notifyProxy (!!aRegistered);
931#endif
932
933 return S_OK;
934}
935
936/**
937 * Called by setter methods of all USB device filters.
938 *
939 * @note Locks nothing.
940 */
941HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter,
942 BOOL aActiveChanged /* = FALSE */)
943{
944 AutoCaller autoCaller (this);
945 AssertComRCReturnRC (autoCaller.rc());
946
947 /// @todo After rewriting Win32 USB support, no more necessary;
948 // a candidate for removal.
949#if 0
950#else
951 /* we need the machine state */
952 Machine::AutoStateDependency <Machine::MutableStateDep> adep (mParent);
953 AssertComRCReturnRC (adep.rc());
954
955 /* nothing to do if the machine isn't running */
956 if (adep.machineState() < MachineState_Running)
957 return S_OK;
958#endif
959
960 /* we don't modify our data fields -- no need to lock */
961
962 if (aFilter->mInList && mParent->isRegistered())
963 {
964 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
965 ComAssertRet (service, E_FAIL);
966
967 if (aActiveChanged)
968 {
969 /* insert/remove the filter from the proxy */
970 if (aFilter->data().mActive)
971 {
972 ComAssertRet (aFilter->id() == NULL, E_FAIL);
973 aFilter->id() = service->insertFilter
974 (ComPtr <IUSBDeviceFilter> (aFilter));
975 }
976 else
977 {
978 ComAssertRet (aFilter->id() != NULL, E_FAIL);
979 service->removeFilter (aFilter->id());
980 aFilter->id() = NULL;
981 }
982 }
983 else
984 {
985 if (aFilter->data().mActive)
986 {
987 /* update the filter in the proxy */
988 ComAssertRet (aFilter->id() != NULL, E_FAIL);
989 service->removeFilter (aFilter->id());
990 aFilter->id() = service->insertFilter
991 (ComPtr <IUSBDeviceFilter> (aFilter));
992 }
993 }
994 }
995
996 return S_OK;
997}
998
999/**
1000 * Returns true if the given USB device matches to at least one of
1001 * this controller's USB device filters.
1002 *
1003 * A HostUSBDevice specific version.
1004 *
1005 * @note Locks this object for reading.
1006 */
1007bool USBController::hasMatchingFilter (ComObjPtr <HostUSBDevice> &aDevice)
1008{
1009 AutoCaller autoCaller (this);
1010 AssertComRCReturn (autoCaller.rc(), false);
1011
1012 AutoReaderLock alock (this);
1013
1014 /* Disabled USB controllers cannot actually work with USB devices */
1015 if (!mData->mEnabled)
1016 return false;
1017
1018 bool match = false;
1019
1020 /* apply self filters */
1021 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1022 !match && it != mDeviceFilters->end();
1023 ++ it)
1024 {
1025 AutoLock filterLock (*it);
1026 match = aDevice->isMatch ((*it)->data());
1027 }
1028
1029 return match;
1030}
1031
1032/**
1033 * Returns true if the given USB device matches to at least one of
1034 * this controller's USB device filters.
1035 *
1036 * A generic version that accepts any IUSBDevice on input.
1037 *
1038 * @note
1039 * This method MUST correlate with HostUSBDevice::isMatch()
1040 * in the sense of the device matching logic.
1041 *
1042 * @note Locks this object for reading.
1043 */
1044bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice)
1045{
1046 LogFlowThisFuncEnter();
1047
1048 AutoCaller autoCaller (this);
1049 AssertComRCReturn (autoCaller.rc(), false);
1050
1051 AutoReaderLock alock (this);
1052
1053 /* Disabled USB controllers cannot actually work with USB devices */
1054 if (!mData->mEnabled)
1055 return false;
1056
1057 HRESULT rc = S_OK;
1058
1059 /* query fields */
1060
1061 USHORT vendorId = 0;
1062 rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
1063 ComAssertComRCRet (rc, false);
1064 ComAssertRet (vendorId, false);
1065
1066 USHORT productId = 0;
1067 rc = aUSBDevice->COMGETTER(ProductId) (&productId);
1068 ComAssertComRCRet (rc, false);
1069 ComAssertRet (productId, false);
1070
1071 USHORT revision;
1072 rc = aUSBDevice->COMGETTER(Revision) (&revision);
1073 ComAssertComRCRet (rc, false);
1074
1075 Bstr manufacturer;
1076 rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
1077 ComAssertComRCRet (rc, false);
1078
1079 Bstr product;
1080 rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
1081 ComAssertComRCRet (rc, false);
1082
1083 Bstr serialNumber;
1084 rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
1085 ComAssertComRCRet (rc, false);
1086
1087 Bstr address;
1088 rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
1089 ComAssertComRCRet (rc, false);
1090
1091 USHORT port = 0;
1092 rc = aUSBDevice->COMGETTER(Port)(&port);
1093 ComAssertComRCRet (rc, false);
1094
1095 BOOL remote = FALSE;
1096 rc = aUSBDevice->COMGETTER(Remote)(&remote);
1097 ComAssertComRCRet (rc, false);
1098 ComAssertRet (remote == TRUE, false);
1099
1100 bool match = false;
1101
1102 /* apply self filters */
1103 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1104 it != mDeviceFilters->end();
1105 ++ it)
1106 {
1107 AutoLock filterLock (*it);
1108 const USBDeviceFilter::Data &aData = (*it)->data();
1109
1110 if (!aData.mActive)
1111 continue;
1112 if (!aData.mVendorId.isMatch (vendorId))
1113 continue;
1114 if (!aData.mProductId.isMatch (productId))
1115 continue;
1116 if (!aData.mRevision.isMatch (revision))
1117 continue;
1118
1119#if !defined (__WIN__)
1120 /* these filters are temporarily ignored on Win32 */
1121 if (!aData.mManufacturer.isMatch (manufacturer))
1122 continue;
1123 if (!aData.mProduct.isMatch (product))
1124 continue;
1125 if (!aData.mSerialNumber.isMatch (serialNumber))
1126 continue;
1127 if (!aData.mPort.isMatch (port))
1128 continue;
1129#endif
1130
1131 if (!aData.mRemote.isMatch (remote))
1132 continue;
1133
1134 match = true;
1135 break;
1136 }
1137
1138 LogFlowThisFunc (("returns: %d\n", match));
1139 LogFlowThisFuncLeave();
1140
1141 return match;
1142}
1143
1144/**
1145 * Notifies the proxy service about all filters as requested by the
1146 * @a aInsertFilters argument.
1147 *
1148 * @param aInsertFilters @c true to insert filters, @c false to remove.
1149 *
1150 * @note Locks this object for reading.
1151 */
1152HRESULT USBController::notifyProxy (bool aInsertFilters)
1153{
1154 LogFlowThisFunc (("aInsertFilters=%RTbool\n", aInsertFilters));
1155
1156 AutoCaller autoCaller (this);
1157 AssertComRCReturn (autoCaller.rc(), false);
1158
1159 AutoReaderLock alock (this);
1160
1161 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1162 AssertReturn (service, E_FAIL);
1163
1164 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1165 while (it != mDeviceFilters->end())
1166 {
1167 USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
1168
1169 /* notify the proxy (only if the filter is active) */
1170 if (flt->data().mActive)
1171 {
1172 if (aInsertFilters)
1173 {
1174 AssertReturn (flt->id() == NULL, E_FAIL);
1175 flt->id() = service->insertFilter
1176 (ComPtr <IUSBDeviceFilter> (flt));
1177 }
1178 else
1179 {
1180 /* It's possible that the given filter was not inserted the proxy
1181 * when this method gets called (as a result of an early VM
1182 * process crash for example. So, don't assert that ID != NULL. */
1183 if (flt->id() != NULL)
1184 {
1185 service->removeFilter (flt->id());
1186 flt->id() = NULL;
1187 }
1188 }
1189 }
1190 ++ it;
1191 }
1192
1193 return S_OK;
1194}
1195
1196// private methods
1197/////////////////////////////////////////////////////////////////////////////
1198
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