VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/USBControllerImpl.cpp@ 47376

Last change on this file since 47376 was 47376, checked in by vboxsync, 12 years ago

Main/USB: USB Controller implementation rework. Moved filter handling into a separate interface

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* $Id: USBControllerImpl.cpp 47376 2013-07-24 15:13:52Z vboxsync $ */
2/** @file
3 * Implementation of IUSBController.
4 */
5
6/*
7 * Copyright (C) 2005-2013 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 "USBControllerImpl.h"
19
20#include "Global.h"
21#include "MachineImpl.h"
22#include "VirtualBoxImpl.h"
23#include "HostImpl.h"
24
25#include <iprt/string.h>
26#include <iprt/cpp/utils.h>
27
28#include <VBox/err.h>
29#include <VBox/settings.h>
30#include <VBox/com/array.h>
31
32#include <algorithm>
33
34#include "AutoStateDep.h"
35#include "AutoCaller.h"
36#include "Logging.h"
37
38// defines
39/////////////////////////////////////////////////////////////////////////////
40
41struct BackupableUSBData
42{
43 BackupableUSBData()
44 : fEnabled(false),
45 fEnabledEHCI(false)
46 { }
47
48 BOOL fEnabled;
49 BOOL fEnabledEHCI;
50};
51
52struct USBController::Data
53{
54 Data(Machine *pMachine)
55 : pParent(pMachine)
56 { }
57
58 ~Data()
59 {};
60
61 Machine * const pParent;
62
63 // peer machine's USB controller
64 const ComObjPtr<USBController> pPeer;
65
66 Backupable<BackupableUSBData> bd;
67};
68
69
70
71// constructor / destructor
72/////////////////////////////////////////////////////////////////////////////
73
74DEFINE_EMPTY_CTOR_DTOR(USBController)
75
76HRESULT USBController::FinalConstruct()
77{
78 return BaseFinalConstruct();
79}
80
81void USBController::FinalRelease()
82{
83 uninit();
84 BaseFinalRelease();
85}
86
87// public initializer/uninitializer for internal purposes only
88/////////////////////////////////////////////////////////////////////////////
89
90/**
91 * Initializes the USB controller object.
92 *
93 * @returns COM result indicator.
94 * @param aParent Pointer to our parent object.
95 */
96HRESULT USBController::init(Machine *aParent)
97{
98 LogFlowThisFunc(("aParent=%p\n", aParent));
99
100 ComAssertRet(aParent, E_INVALIDARG);
101
102 /* Enclose the state transition NotReady->InInit->Ready */
103 AutoInitSpan autoInitSpan(this);
104 AssertReturn(autoInitSpan.isOk(), E_FAIL);
105
106 m = new Data(aParent);
107
108 /* mPeer is left null */
109
110 m->bd.allocate();
111
112 /* Confirm a successful initialization */
113 autoInitSpan.setSucceeded();
114
115 return S_OK;
116}
117
118/**
119 * Initializes the USB controller object given another USB controller object
120 * (a kind of copy constructor). This object shares data with
121 * the object passed as an argument.
122 *
123 * @returns COM result indicator.
124 * @param aParent Pointer to our parent object.
125 * @param aPeer The object to share.
126 *
127 * @note This object must be destroyed before the original object
128 * it shares data with is destroyed.
129 */
130HRESULT USBController::init(Machine *aParent, USBController *aPeer)
131{
132 LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer));
133
134 ComAssertRet(aParent && aPeer, E_INVALIDARG);
135
136 /* Enclose the state transition NotReady->InInit->Ready */
137 AutoInitSpan autoInitSpan(this);
138 AssertReturn(autoInitSpan.isOk(), E_FAIL);
139
140 m = new Data(aParent);
141
142 unconst(m->pPeer) = aPeer;
143
144 AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS);
145 m->bd.share(aPeer->m->bd);
146
147 /* Confirm a successful initialization */
148 autoInitSpan.setSucceeded();
149
150 return S_OK;
151}
152
153
154/**
155 * Initializes the USB controller object given another guest object
156 * (a kind of copy constructor). This object makes a private copy of data
157 * of the original object passed as an argument.
158 */
159HRESULT USBController::initCopy(Machine *aParent, USBController *aPeer)
160{
161 LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer));
162
163 ComAssertRet(aParent && aPeer, E_INVALIDARG);
164
165 /* Enclose the state transition NotReady->InInit->Ready */
166 AutoInitSpan autoInitSpan(this);
167 AssertReturn(autoInitSpan.isOk(), E_FAIL);
168
169 m = new Data(aParent);
170
171 /* mPeer is left null */
172
173 AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS);
174 m->bd.attachCopy(aPeer->m->bd);
175
176 /* Confirm a successful initialization */
177 autoInitSpan.setSucceeded();
178
179 return S_OK;
180}
181
182
183/**
184 * Uninitializes the instance and sets the ready flag to FALSE.
185 * Called either from FinalRelease() or by the parent when it gets destroyed.
186 */
187void USBController::uninit()
188{
189 LogFlowThisFunc(("\n"));
190
191 /* Enclose the state transition Ready->InUninit->NotReady */
192 AutoUninitSpan autoUninitSpan(this);
193 if (autoUninitSpan.uninitDone())
194 return;
195
196 m->bd.free();
197
198 unconst(m->pPeer) = NULL;
199 unconst(m->pParent) = NULL;
200
201 delete m;
202 m = NULL;
203}
204
205
206// IUSBController properties
207/////////////////////////////////////////////////////////////////////////////
208
209STDMETHODIMP USBController::COMGETTER(Enabled)(BOOL *aEnabled)
210{
211 CheckComArgOutPointerValid(aEnabled);
212
213 AutoCaller autoCaller(this);
214 if (FAILED(autoCaller.rc())) return autoCaller.rc();
215
216 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
217
218 *aEnabled = m->bd->fEnabled;
219
220 return S_OK;
221}
222
223
224STDMETHODIMP USBController::COMSETTER(Enabled)(BOOL aEnabled)
225{
226 LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled));
227
228 AutoCaller autoCaller(this);
229 if (FAILED(autoCaller.rc())) return autoCaller.rc();
230
231 /* the machine needs to be mutable */
232 AutoMutableStateDependency adep(m->pParent);
233 if (FAILED(adep.rc())) return adep.rc();
234
235 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
236
237 if (m->bd->fEnabled != aEnabled)
238 {
239 m->bd.backup();
240 m->bd->fEnabled = aEnabled;
241
242 // leave the lock for safety
243 alock.release();
244
245 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
246 m->pParent->setModified(Machine::IsModified_USB);
247 mlock.release();
248
249 m->pParent->onUSBControllerChange();
250 }
251
252 return S_OK;
253}
254
255STDMETHODIMP USBController::COMGETTER(EnabledEHCI)(BOOL *aEnabled)
256{
257 CheckComArgOutPointerValid(aEnabled);
258
259 AutoCaller autoCaller(this);
260 if (FAILED(autoCaller.rc())) return autoCaller.rc();
261
262 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
263
264 *aEnabled = m->bd->fEnabledEHCI;
265
266 return S_OK;
267}
268
269STDMETHODIMP USBController::COMSETTER(EnabledEHCI)(BOOL aEnabled)
270{
271 LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled));
272
273 AutoCaller autoCaller(this);
274 if (FAILED(autoCaller.rc())) return autoCaller.rc();
275
276 /* the machine needs to be mutable */
277 AutoMutableStateDependency adep(m->pParent);
278 if (FAILED(adep.rc())) return adep.rc();
279
280 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
281
282 if (m->bd->fEnabledEHCI != aEnabled)
283 {
284 m->bd.backup();
285 m->bd->fEnabledEHCI = aEnabled;
286
287 // leave the lock for safety
288 alock.release();
289
290 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
291 m->pParent->setModified(Machine::IsModified_USB);
292 mlock.release();
293
294 m->pParent->onUSBControllerChange();
295 }
296
297 return S_OK;
298}
299
300STDMETHODIMP USBController::COMGETTER(ProxyAvailable)(BOOL *aEnabled)
301{
302 CheckComArgOutPointerValid(aEnabled);
303
304 AutoCaller autoCaller(this);
305 if (FAILED(autoCaller.rc())) return autoCaller.rc();
306
307 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
308
309#ifdef VBOX_WITH_USB
310 *aEnabled = true;
311#else
312 *aEnabled = false;
313#endif
314
315 return S_OK;
316}
317
318STDMETHODIMP USBController::COMGETTER(USBStandard)(USHORT *aUSBStandard)
319{
320 CheckComArgOutPointerValid(aUSBStandard);
321
322 AutoCaller autoCaller(this);
323 if (FAILED(autoCaller.rc())) return autoCaller.rc();
324
325 /* not accessing data -- no need to lock */
326
327 /** @todo This is no longer correct */
328 *aUSBStandard = 0x0101;
329
330 return S_OK;
331}
332
333// public methods only for internal purposes
334/////////////////////////////////////////////////////////////////////////////
335
336/**
337 * Loads settings from the given machine node.
338 * May be called once right after this object creation.
339 *
340 * @param aMachineNode <Machine> node.
341 *
342 * @note Does not lock "this" as Machine::loadHardware, which calls this, does not lock either.
343 */
344HRESULT USBController::loadSettings(const settings::USBController &data)
345{
346 AutoCaller autoCaller(this);
347 AssertComRCReturnRC(autoCaller.rc());
348
349 /* Note: we assume that the default values for attributes of optional
350 * nodes are assigned in the Data::Data() constructor and don't do it
351 * here. It implies that this method may only be called after constructing
352 * a new BIOSSettings object while all its data fields are in the default
353 * values. Exceptions are fields whose creation time defaults don't match
354 * values that should be applied when these fields are not explicitly set
355 * in the settings file (for backwards compatibility reasons). This takes
356 * place when a setting of a newly created object must default to A while
357 * the same setting of an object loaded from the old settings file must
358 * default to B. */
359
360 m->bd->fEnabled = data.fEnabled;
361 m->bd->fEnabledEHCI = data.fEnabledEHCI;
362
363 return S_OK;
364}
365
366/**
367 * Saves settings to the given machine node.
368 *
369 * @param aMachineNode <Machine> node.
370 *
371 * @note Locks this object for reading.
372 */
373HRESULT USBController::saveSettings(settings::USBController &data)
374{
375 AutoCaller autoCaller(this);
376 if (FAILED(autoCaller.rc())) return autoCaller.rc();
377
378 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
379
380 data.fEnabled = !!m->bd->fEnabled;
381 data.fEnabledEHCI = !!m->bd->fEnabledEHCI;
382
383 return S_OK;
384}
385
386/** @note Locks objects for writing! */
387void USBController::rollback()
388{
389 AutoCaller autoCaller(this);
390 AssertComRCReturnVoid(autoCaller.rc());
391
392 /* we need the machine state */
393 AutoAnyStateDependency adep(m->pParent);
394 AssertComRCReturnVoid(adep.rc());
395
396 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
397
398 m->bd.rollback();
399}
400
401/**
402 * @note Locks this object for writing, together with the peer object (also
403 * for writing) if there is one.
404 */
405void USBController::commit()
406{
407 /* sanity */
408 AutoCaller autoCaller(this);
409 AssertComRCReturnVoid(autoCaller.rc());
410
411 /* sanity too */
412 AutoCaller peerCaller(m->pPeer);
413 AssertComRCReturnVoid(peerCaller.rc());
414
415 /* lock both for writing since we modify both (mPeer is "master" so locked
416 * first) */
417 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
418
419 if (m->bd.isBackedUp())
420 {
421 m->bd.commit();
422 if (m->pPeer)
423 {
424 /* attach new data to the peer and reshare it */
425 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
426 m->pPeer->m->bd.attach(m->bd);
427 }
428 }
429}
430
431/**
432 * @note Locks this object for writing, together with the peer object
433 * represented by @a aThat (locked for reading).
434 */
435void USBController::copyFrom(USBController *aThat)
436{
437 AssertReturnVoid(aThat != NULL);
438
439 /* sanity */
440 AutoCaller autoCaller(this);
441 AssertComRCReturnVoid(autoCaller.rc());
442
443 /* sanity too */
444 AutoCaller thatCaller(aThat);
445 AssertComRCReturnVoid(thatCaller.rc());
446
447 /* even more sanity */
448 AutoAnyStateDependency adep(m->pParent);
449 AssertComRCReturnVoid(adep.rc());
450 /* Machine::copyFrom() may not be called when the VM is running */
451 AssertReturnVoid(!Global::IsOnline(adep.machineState()));
452
453 /* peer is not modified, lock it for reading (aThat is "master" so locked
454 * first) */
455 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
456 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
457
458 /* this will back up current data */
459 m->bd.assignCopy(aThat->m->bd);
460}
461
462// private methods
463/////////////////////////////////////////////////////////////////////////////
464/* 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