VirtualBox

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

Last change on this file since 73768 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use