VirtualBox

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

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