VirtualBox

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

Last change on this file since 86186 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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