VirtualBox

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

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

Main/Machine+USBController+StorageController: Mix of deleting useless functionality, fixing of missing sanity checks and adding some additional functionality. The removed functionality is the possibility to specify patters of guest properties which will trigger notifications, which wasn't useful as it is per VM, sabotaging other API clients (e.g. the VM process assumes it gets the notifications it needs). The storage controller setters were lacking a lot of state and consistency sanity checking, which is now fixed. Both the USB and storage controllers can now be renamed (no API client uses this functionality though), all with very pessimistic assumptions (only when the VM is powered off).

  • 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 56035 2015-05-22 16:03:35Z vboxsync $ */
2/** @file
3 * Implementation of IUSBController.
4 */
5
6/*
7 * Copyright (C) 2005-2015 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 : enmType(USBControllerType_Null)
45 { }
46
47 Utf8Str strName;
48 USBControllerType_T enmType;
49};
50
51struct USBController::Data
52{
53 Data(Machine *pMachine)
54 : pParent(pMachine)
55 { }
56
57 ~Data()
58 {};
59
60 Machine * const pParent;
61
62 // peer machine's USB controller
63 const ComObjPtr<USBController> pPeer;
64
65 Backupable<BackupableUSBData> bd;
66};
67
68
69
70// constructor / destructor
71/////////////////////////////////////////////////////////////////////////////
72
73DEFINE_EMPTY_CTOR_DTOR(USBController)
74
75HRESULT USBController::FinalConstruct()
76{
77 return BaseFinalConstruct();
78}
79
80void USBController::FinalRelease()
81{
82 uninit();
83 BaseFinalRelease();
84}
85
86// public initializer/uninitializer for internal purposes only
87/////////////////////////////////////////////////////////////////////////////
88
89/**
90 * Initializes the USB controller object.
91 *
92 * @returns COM result indicator.
93 * @param aParent Pointer to our parent object.
94 * @param aName The name of the USB controller.
95 * @param enmType The USB controller type.
96 */
97HRESULT USBController::init(Machine *aParent, const Utf8Str &aName, USBControllerType_T enmType)
98{
99 LogFlowThisFunc(("aParent=%p aName=\"%s\"\n", aParent, aName.c_str()));
100
101 ComAssertRet(aParent && !aName.isEmpty(), E_INVALIDARG);
102 if ( (enmType <= USBControllerType_Null)
103 || (enmType > USBControllerType_XHCI))
104 return setError(E_INVALIDARG,
105 tr("Invalid USB controller type"));
106
107 /* Enclose the state transition NotReady->InInit->Ready */
108 AutoInitSpan autoInitSpan(this);
109 AssertReturn(autoInitSpan.isOk(), E_FAIL);
110
111 m = new Data(aParent);
112
113 /* mPeer is left null */
114
115 m->bd.allocate();
116 m->bd->strName = aName;
117 m->bd->enmType = enmType;
118
119 /* Confirm a successful initialization */
120 autoInitSpan.setSucceeded();
121
122 return S_OK;
123}
124
125/**
126 * Initializes the USB controller object given another USB controller object
127 * (a kind of copy constructor). This object shares data with
128 * the object passed as an argument.
129 *
130 * @returns COM result indicator.
131 * @param aParent Pointer to our parent object.
132 * @param aPeer The object to share.
133 * @param aReshare
134 * When false, the original object will remain a data owner.
135 * Otherwise, data ownership will be transferred from the original
136 * object to this one.
137 *
138 * @note This object must be destroyed before the original object
139 * it shares data with is destroyed.
140 *
141 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
142 * reading if @a aReshare is false.
143 */
144HRESULT USBController::init(Machine *aParent, USBController *aPeer,
145 bool fReshare /* = false */)
146{
147 LogFlowThisFunc(("aParent=%p, aPeer=%p, fReshare=%RTbool\n",
148 aParent, aPeer, fReshare));
149
150 ComAssertRet(aParent && aPeer, E_INVALIDARG);
151
152 /* Enclose the state transition NotReady->InInit->Ready */
153 AutoInitSpan autoInitSpan(this);
154 AssertReturn(autoInitSpan.isOk(), E_FAIL);
155
156 m = new Data(aParent);
157
158 /* sanity */
159 AutoCaller peerCaller(aPeer);
160 AssertComRCReturnRC(peerCaller.rc());
161
162 if (fReshare)
163 {
164 AutoWriteLock peerLock(aPeer COMMA_LOCKVAL_SRC_POS);
165
166 unconst(aPeer->m->pPeer) = this;
167 m->bd.attach (aPeer->m->bd);
168 }
169 else
170 {
171 unconst(m->pPeer) = aPeer;
172
173 AutoReadLock peerLock(aPeer COMMA_LOCKVAL_SRC_POS);
174 m->bd.share (aPeer->m->bd);
175 }
176
177 /* Confirm a successful initialization */
178 autoInitSpan.setSucceeded();
179
180 return S_OK;
181}
182
183
184/**
185 * Initializes the USB controller object given another guest object
186 * (a kind of copy constructor). This object makes a private copy of data
187 * of the original object passed as an argument.
188 */
189HRESULT USBController::initCopy(Machine *aParent, USBController *aPeer)
190{
191 LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer));
192
193 ComAssertRet(aParent && aPeer, E_INVALIDARG);
194
195 /* Enclose the state transition NotReady->InInit->Ready */
196 AutoInitSpan autoInitSpan(this);
197 AssertReturn(autoInitSpan.isOk(), E_FAIL);
198
199 m = new Data(aParent);
200
201 /* mPeer is left null */
202
203 AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS);
204 m->bd.attachCopy(aPeer->m->bd);
205
206 /* Confirm a successful initialization */
207 autoInitSpan.setSucceeded();
208
209 return S_OK;
210}
211
212
213/**
214 * Uninitializes the instance and sets the ready flag to FALSE.
215 * Called either from FinalRelease() or by the parent when it gets destroyed.
216 */
217void USBController::uninit()
218{
219 LogFlowThisFunc(("\n"));
220
221 /* Enclose the state transition Ready->InUninit->NotReady */
222 AutoUninitSpan autoUninitSpan(this);
223 if (autoUninitSpan.uninitDone())
224 return;
225
226 m->bd.free();
227
228 unconst(m->pPeer) = NULL;
229 unconst(m->pParent) = NULL;
230
231 delete m;
232 m = NULL;
233}
234
235
236// Wrapped IUSBController properties
237/////////////////////////////////////////////////////////////////////////////
238HRESULT USBController::getName(com::Utf8Str &aName)
239{
240 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
241
242 aName = m->bd->strName;
243
244 return S_OK;
245}
246
247HRESULT USBController::setName(const com::Utf8Str &aName)
248{
249 /* the machine needs to be mutable */
250 AutoMutableStateDependency adep(m->pParent);
251 if (FAILED(adep.rc())) return adep.rc();
252
253 AutoMultiWriteLock2 alock(m->pParent, this COMMA_LOCKVAL_SRC_POS);
254
255 if (m->bd->strName != aName)
256 {
257 ComObjPtr<USBController> ctrl;
258 HRESULT rc = m->pParent->i_getUSBControllerByName(aName, ctrl, false /* aSetError */);
259 if (SUCCEEDED(rc))
260 return setError(VBOX_E_OBJECT_IN_USE,
261 tr("USB controller named '%s' already exists"),
262 aName.c_str());
263
264 m->bd.backup();
265 m->bd->strName = aName;
266
267 m->pParent->i_setModified(Machine::IsModified_USB);
268 alock.release();
269
270 m->pParent->i_onUSBControllerChange();
271 }
272
273 return S_OK;
274}
275
276HRESULT USBController::getType(USBControllerType_T *aType)
277{
278 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
279
280 *aType = m->bd->enmType;
281
282 return S_OK;
283}
284
285HRESULT USBController::setType(USBControllerType_T aType)
286{
287 /* the machine needs to be mutable */
288 AutoMutableStateDependency adep(m->pParent);
289 if (FAILED(adep.rc())) return adep.rc();
290
291 AutoMultiWriteLock2 alock(m->pParent, this COMMA_LOCKVAL_SRC_POS);
292
293 if (m->bd->enmType != aType)
294 {
295 m->bd.backup();
296 m->bd->enmType = aType;
297
298 m->pParent->i_setModified(Machine::IsModified_USB);
299 alock.release();
300
301 m->pParent->i_onUSBControllerChange();
302 }
303
304 return S_OK;
305}
306
307HRESULT USBController::getUSBStandard(USHORT *aUSBStandard)
308{
309 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
310
311 switch (m->bd->enmType)
312 {
313 case USBControllerType_OHCI:
314 *aUSBStandard = 0x0101;
315 break;
316 case USBControllerType_EHCI:
317 *aUSBStandard = 0x0200;
318 break;
319 case USBControllerType_XHCI:
320 *aUSBStandard = 0x0200;
321 break;
322 default:
323 AssertMsgFailedReturn(("Invalid controller type %d\n", m->bd->enmType),
324 E_FAIL);
325 }
326
327 return S_OK;
328}
329
330// public methods only for internal purposes
331/////////////////////////////////////////////////////////////////////////////
332
333/** @note Locks objects for writing! */
334void USBController::i_rollback()
335{
336 AutoCaller autoCaller(this);
337 AssertComRCReturnVoid(autoCaller.rc());
338
339 /* we need the machine state */
340 AutoAnyStateDependency adep(m->pParent);
341 AssertComRCReturnVoid(adep.rc());
342
343 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
344
345 m->bd.rollback();
346}
347
348/**
349 * @note Locks this object for writing, together with the peer object (also
350 * for writing) if there is one.
351 */
352void USBController::i_commit()
353{
354 /* sanity */
355 AutoCaller autoCaller(this);
356 AssertComRCReturnVoid(autoCaller.rc());
357
358 /* sanity too */
359 AutoCaller peerCaller(m->pPeer);
360 AssertComRCReturnVoid(peerCaller.rc());
361
362 /* lock both for writing since we modify both (mPeer is "master" so locked
363 * first) */
364 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
365
366 if (m->bd.isBackedUp())
367 {
368 m->bd.commit();
369 if (m->pPeer)
370 {
371 /* attach new data to the peer and reshare it */
372 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
373 m->pPeer->m->bd.attach(m->bd);
374 }
375 }
376}
377
378/**
379 * @note Locks this object for writing, together with the peer object
380 * represented by @a aThat (locked for reading).
381 */
382void USBController::i_copyFrom(USBController *aThat)
383{
384 AssertReturnVoid(aThat != NULL);
385
386 /* sanity */
387 AutoCaller autoCaller(this);
388 AssertComRCReturnVoid(autoCaller.rc());
389
390 /* sanity too */
391 AutoCaller thatCaller(aThat);
392 AssertComRCReturnVoid(thatCaller.rc());
393
394 /* even more sanity */
395 AutoAnyStateDependency adep(m->pParent);
396 AssertComRCReturnVoid(adep.rc());
397 /* Machine::copyFrom() may not be called when the VM is running */
398 AssertReturnVoid(!Global::IsOnline(adep.machineState()));
399
400 /* peer is not modified, lock it for reading (aThat is "master" so locked
401 * first) */
402 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
403 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
404
405 /* this will back up current data */
406 m->bd.assignCopy(aThat->m->bd);
407}
408
409/**
410 * Cancels sharing (if any) by making an independent copy of data.
411 * This operation also resets this object's peer to NULL.
412 *
413 * @note Locks this object for writing, together with the peer object
414 * represented by @a aThat (locked for reading).
415 */
416void USBController::i_unshare()
417{
418 /* sanity */
419 AutoCaller autoCaller(this);
420 AssertComRCReturnVoid (autoCaller.rc());
421
422 /* sanity too */
423 AutoCaller peerCaller (m->pPeer);
424 AssertComRCReturnVoid (peerCaller.rc());
425
426 /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
427 * first) */
428 AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
429 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
430
431 if (m->bd.isShared())
432 {
433 if (!m->bd.isBackedUp())
434 m->bd.backup();
435
436 m->bd.commit();
437 }
438
439 unconst(m->pPeer) = NULL;
440}
441
442const Utf8Str &USBController::i_getName() const
443{
444 return m->bd->strName;
445}
446
447const USBControllerType_T &USBController::i_getControllerType() const
448{
449 return m->bd->enmType;
450}
451
452ComObjPtr<USBController> USBController::i_getPeer()
453{
454 return m->pPeer;
455}
456
457/////////////////////////////////////////////////////////////////////////////
458/* 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