VirtualBox

source: vbox/trunk/src/VBox/Main/SATAControllerImpl.cpp@ 16524

Last change on this file since 16524 was 14972, checked in by vboxsync, 16 years ago

#3285: Improve error handling API to include unique error numbers

The mega commit that implements Main-wide usage of new CheckCom*
macros, mostly CheckComArgNotNull, CheckComArgStrNotEmptyOrNull,
CheckComArgOutSafeArrayPointerValid, CheckComArgExpr.
Note that some methods incorrectly returned E_INVALIDARG where they
should have returned E_POINTER and vice versa. If any higher level
function tests these, they will behave differently now...

Special thanks to: vi macros, making it easy to semi-automatically
find and replace several hundred instances of if (!aName) ...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 13.3 KB
Line 
1/* $Id: SATAControllerImpl.cpp 14972 2008-12-04 12:10:37Z vboxsync $ */
2
3/** @file
4 *
5 * Implementation of ISATAController.
6 */
7
8/*
9 * Copyright (C) 2008 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24
25
26#include "SATAControllerImpl.h"
27#include "MachineImpl.h"
28#include "VirtualBoxImpl.h"
29#include "Logging.h"
30
31#include <iprt/string.h>
32#include <iprt/cpputils.h>
33#include <VBox/err.h>
34
35#include <algorithm>
36
37// defines
38/////////////////////////////////////////////////////////////////////////////
39
40// constructor / destructor
41/////////////////////////////////////////////////////////////////////////////
42
43DEFINE_EMPTY_CTOR_DTOR (SATAController)
44
45HRESULT SATAController::FinalConstruct()
46{
47 return S_OK;
48}
49
50void SATAController::FinalRelease()
51{
52 uninit();
53}
54
55// public initializer/uninitializer for internal purposes only
56/////////////////////////////////////////////////////////////////////////////
57
58/**
59 * Initializes the SATA controller object.
60 *
61 * @returns COM result indicator.
62 * @param aParent Pointer to our parent object.
63 */
64HRESULT SATAController::init (Machine *aParent)
65{
66 LogFlowThisFunc (("aParent=%p\n", aParent));
67
68 ComAssertRet (aParent, E_INVALIDARG);
69
70 /* Enclose the state transition NotReady->InInit->Ready */
71 AutoInitSpan autoInitSpan (this);
72 AssertReturn (autoInitSpan.isOk(), E_FAIL);
73
74 unconst (mParent) = aParent;
75 /* mPeer is left null */
76
77 mData.allocate();
78
79 /* Confirm a successful initialization */
80 autoInitSpan.setSucceeded();
81
82 return S_OK;
83}
84
85
86/**
87 * Initializes the SATA controller object given another SATA controller object
88 * (a kind of copy constructor). This object shares data with
89 * the object passed as an argument.
90 *
91 * @returns COM result indicator.
92 * @param aParent Pointer to our parent object.
93 * @param aPeer The object to share.
94 *
95 * @note This object must be destroyed before the original object
96 * it shares data with is destroyed.
97 */
98HRESULT SATAController::init (Machine *aParent, SATAController *aPeer)
99{
100 LogFlowThisFunc (("aParent=%p, aPeer=%p\n", aParent, aPeer));
101
102 ComAssertRet (aParent && aPeer, E_INVALIDARG);
103
104 /* Enclose the state transition NotReady->InInit->Ready */
105 AutoInitSpan autoInitSpan (this);
106 AssertReturn (autoInitSpan.isOk(), E_FAIL);
107
108 unconst (mParent) = aParent;
109 unconst (mPeer) = aPeer;
110
111 AutoWriteLock thatlock (aPeer);
112 mData.share (aPeer->mData);
113
114 /* Confirm a successful initialization */
115 autoInitSpan.setSucceeded();
116
117 return S_OK;
118}
119
120
121/**
122 * Initializes the SATA controller object given another guest object
123 * (a kind of copy constructor). This object makes a private copy of data
124 * of the original object passed as an argument.
125 */
126HRESULT SATAController::initCopy (Machine *aParent, SATAController *aPeer)
127{
128 LogFlowThisFunc (("aParent=%p, aPeer=%p\n", aParent, aPeer));
129
130 ComAssertRet (aParent && aPeer, E_INVALIDARG);
131
132 /* Enclose the state transition NotReady->InInit->Ready */
133 AutoInitSpan autoInitSpan (this);
134 AssertReturn (autoInitSpan.isOk(), E_FAIL);
135
136 unconst (mParent) = aParent;
137 /* mPeer is left null */
138
139 AutoWriteLock thatlock (aPeer);
140 mData.attachCopy (aPeer->mData);
141
142 /* Confirm a successful initialization */
143 autoInitSpan.setSucceeded();
144
145 return S_OK;
146}
147
148
149/**
150 * Uninitializes the instance and sets the ready flag to FALSE.
151 * Called either from FinalRelease() or by the parent when it gets destroyed.
152 */
153void SATAController::uninit()
154{
155 LogFlowThisFunc (("\n"));
156
157 /* Enclose the state transition Ready->InUninit->NotReady */
158 AutoUninitSpan autoUninitSpan (this);
159 if (autoUninitSpan.uninitDone())
160 return;
161
162 /* uninit all filters (including those still referenced by clients) */
163 uninitDependentChildren();
164
165 mData.free();
166
167 unconst (mPeer).setNull();
168 unconst (mParent).setNull();
169}
170
171
172// ISATAController properties
173/////////////////////////////////////////////////////////////////////////////
174
175STDMETHODIMP SATAController::COMGETTER(Enabled) (BOOL *aEnabled)
176{
177 CheckComArgOutPointerValid(aEnabled);
178
179 AutoCaller autoCaller (this);
180 CheckComRCReturnRC (autoCaller.rc());
181
182 AutoReadLock alock (this);
183
184 *aEnabled = mData->mEnabled;
185
186 return S_OK;
187}
188
189
190STDMETHODIMP SATAController::COMSETTER(Enabled) (BOOL aEnabled)
191{
192 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
193
194 AutoCaller autoCaller (this);
195 CheckComRCReturnRC (autoCaller.rc());
196
197 /* the machine needs to be mutable */
198 Machine::AutoMutableStateDependency adep (mParent);
199 CheckComRCReturnRC (adep.rc());
200
201 AutoWriteLock alock (this);
202
203 if (mData->mEnabled != aEnabled)
204 {
205 mData.backup();
206 mData->mEnabled = aEnabled;
207
208 /* leave the lock for safety */
209 alock.leave();
210
211 mParent->onSATAControllerChange();
212 }
213
214 return S_OK;
215}
216
217STDMETHODIMP SATAController::COMGETTER(PortCount) (ULONG *aPortCount)
218{
219 CheckComArgOutPointerValid(aPortCount);
220
221 AutoCaller autoCaller (this);
222 CheckComRCReturnRC (autoCaller.rc());
223
224 AutoReadLock alock (this);
225
226 *aPortCount = mData->mPortCount;
227
228 return S_OK;
229}
230
231
232STDMETHODIMP SATAController::COMSETTER(PortCount) (ULONG aPortCount)
233{
234 LogFlowThisFunc (("aPortCount=%u\n", aPortCount));
235
236 /* We support a maximum of 30 channels. */
237 if ((aPortCount < 1) || (aPortCount > 30))
238 return setError (E_INVALIDARG,
239 tr ("Invalid port count: %lu (must be in range [%lu, %lu])"),
240 aPortCount, 1, 30);
241
242 AutoCaller autoCaller (this);
243 CheckComRCReturnRC (autoCaller.rc());
244
245 /* the machine needs to be mutable */
246 Machine::AutoMutableStateDependency adep (mParent);
247 CheckComRCReturnRC (adep.rc());
248
249 AutoWriteLock alock (this);
250
251 if (mData->mPortCount != aPortCount)
252 {
253 mData.backup();
254 mData->mPortCount = aPortCount;
255
256 /* leave the lock for safety */
257 alock.leave();
258
259 mParent->onSATAControllerChange();
260 }
261
262 return S_OK;
263}
264
265// ISATAController methods
266/////////////////////////////////////////////////////////////////////////////
267
268STDMETHODIMP SATAController::GetIDEEmulationPort(LONG DevicePosition, LONG *aPortNumber)
269{
270 CheckComArgOutPointerValid(aPortNumber);
271
272 AutoCaller autoCaller (this);
273 CheckComRCReturnRC (autoCaller.rc());
274
275 switch (DevicePosition)
276 {
277 case 0:
278 *aPortNumber = mData->mPortIde0Master;
279 break;
280 case 1:
281 *aPortNumber = mData->mPortIde0Slave;
282 break;
283 case 2:
284 *aPortNumber = mData->mPortIde1Master;
285 break;
286 case 3:
287 *aPortNumber = mData->mPortIde1Slave;
288 break;
289 default:
290 return E_INVALIDARG;
291 }
292
293 return S_OK;
294}
295
296STDMETHODIMP SATAController::SetIDEEmulationPort(LONG DevicePosition, LONG aPortNumber)
297{
298 if ((aPortNumber < 0) || (aPortNumber >= 30))
299 return setError (E_INVALIDARG,
300 tr ("Invalid port number: %l (must be in range [%lu, %lu])"),
301 aPortNumber, 0, 29);
302
303 AutoCaller autoCaller (this);
304 CheckComRCReturnRC (autoCaller.rc());
305
306 /* the machine needs to be mutable */
307 Machine::AutoMutableStateDependency adep (mParent);
308 CheckComRCReturnRC (adep.rc());
309 AutoWriteLock alock (this);
310
311 switch (DevicePosition)
312 {
313 case 0:
314 mData->mPortIde0Master = aPortNumber;
315 break;
316 case 1:
317 mData->mPortIde0Slave = aPortNumber;
318 break;
319 case 2:
320 mData->mPortIde1Master = aPortNumber;
321 break;
322 case 3:
323 mData->mPortIde1Slave = aPortNumber;
324 break;
325 default:
326 return E_INVALIDARG;
327 }
328
329 return S_OK;
330}
331
332// public methods only for internal purposes
333/////////////////////////////////////////////////////////////////////////////
334
335/**
336 * Loads settings from the given machine node.
337 * May be called once right after this object creation.
338 *
339 * @param aMachineNode <Machine> node.
340 *
341 * @note Locks this object for writing.
342 */
343HRESULT SATAController::loadSettings (const settings::Key &aMachineNode)
344{
345 using namespace settings;
346
347 AssertReturn (!aMachineNode.isNull(), E_FAIL);
348
349 AutoCaller autoCaller (this);
350 AssertComRCReturnRC (autoCaller.rc());
351
352 AutoWriteLock alock (this);
353
354 /* SATA Controller node (required) */
355 Key controller = aMachineNode.key ("SATAController");
356
357 /* enabled (required) */
358 mData->mEnabled = controller.value <bool> ("enabled");
359
360 /* number of useable ports */
361 mData->mPortCount = controller.valueOr <ULONG> ("PortCount", 30);
362
363 /* ide emulation settings (optional, default to 0,1,2,3 respectively) */
364 mData->mPortIde0Master = controller.value <ULONG> ("IDE0MasterEmulationPort");
365 mData->mPortIde0Slave = controller.value <ULONG> ("IDE0SlaveEmulationPort");
366 mData->mPortIde1Master = controller.value <ULONG> ("IDE1MasterEmulationPort");
367 mData->mPortIde1Slave = controller.value <ULONG> ("IDE1SlaveEmulationPort");
368
369 return S_OK;
370}
371
372/**
373 * Saves settings to the given machine node.
374 *
375 * @param aMachineNode <Machine> node.
376 *
377 * @note Locks this object for reading.
378 */
379HRESULT SATAController::saveSettings (settings::Key &aMachineNode)
380{
381 using namespace settings;
382
383 AssertReturn (!aMachineNode.isNull(), E_FAIL);
384
385 AutoCaller autoCaller (this);
386 CheckComRCReturnRC (autoCaller.rc());
387
388 AutoReadLock alock (this);
389
390 /* first, delete the entry */
391 Key controller = aMachineNode.findKey ("SATAController");
392 if (!controller.isNull())
393 controller.zap();
394 /* then, recreate it */
395 controller = aMachineNode.createKey ("SATAController");
396
397 /* enabled */
398 controller.setValue <bool> ("enabled", !!mData->mEnabled);
399
400 /* number of useable ports */
401 controller.setValue <ULONG> ("PortCount", mData->mPortCount);
402
403 /* ide emulation settings */
404 controller.setValue <ULONG> ("IDE0MasterEmulationPort", mData->mPortIde0Master);
405 controller.setValue <ULONG> ("IDE0SlaveEmulationPort", mData->mPortIde0Slave);
406 controller.setValue <ULONG> ("IDE1MasterEmulationPort", mData->mPortIde1Master);
407 controller.setValue <ULONG> ("IDE1SlaveEmulationPort", mData->mPortIde1Slave);
408
409 return S_OK;
410}
411
412/** @note Locks objects for reading! */
413bool SATAController::isModified()
414{
415 AutoCaller autoCaller (this);
416 AssertComRCReturn (autoCaller.rc(), false);
417
418 AutoReadLock alock (this);
419
420 if (mData.isBackedUp())
421 return true;
422
423 return false;
424}
425
426/** @note Locks objects for reading! */
427bool SATAController::isReallyModified()
428{
429 AutoCaller autoCaller (this);
430 AssertComRCReturn (autoCaller.rc(), false);
431
432 AutoReadLock alock (this);
433
434 if (mData.hasActualChanges())
435 return true;
436
437 return false;
438}
439
440/** @note Locks objects for writing! */
441bool SATAController::rollback()
442{
443 AutoCaller autoCaller (this);
444 AssertComRCReturn (autoCaller.rc(), false);
445
446 /* we need the machine state */
447 Machine::AutoAnyStateDependency adep (mParent);
448 AssertComRCReturn (adep.rc(), false);
449
450 AutoWriteLock alock (this);
451
452 bool dataChanged = false;
453
454 if (mData.isBackedUp())
455 {
456 /* we need to check all data to see whether anything will be changed
457 * after rollback */
458 dataChanged = mData.hasActualChanges();
459 mData.rollback();
460 }
461
462 return dataChanged;
463}
464
465/**
466 * @note Locks this object for writing, together with the peer object (also
467 * for writing) if there is one.
468 */
469void SATAController::commit()
470{
471 /* sanity */
472 AutoCaller autoCaller (this);
473 AssertComRCReturnVoid (autoCaller.rc());
474
475 /* sanity too */
476 AutoCaller peerCaller (mPeer);
477 AssertComRCReturnVoid (peerCaller.rc());
478
479 /* lock both for writing since we modify both (mPeer is "master" so locked
480 * first) */
481 AutoMultiWriteLock2 alock (mPeer, this);
482
483 if (mData.isBackedUp())
484 {
485 mData.commit();
486 if (mPeer)
487 {
488 // attach new data to the peer and reshare it
489 AutoWriteLock peerlock (mPeer);
490 mPeer->mData.attach (mData);
491 }
492 }
493}
494
495/**
496 * @note Locks this object for writing, together with the peer object
497 * represented by @a aThat (locked for reading).
498 */
499void SATAController::copyFrom (SATAController *aThat)
500{
501 AssertReturnVoid (aThat != NULL);
502
503 /* sanity */
504 AutoCaller autoCaller (this);
505 AssertComRCReturnVoid (autoCaller.rc());
506
507 /* sanity too */
508 AutoCaller thatCaller (aThat);
509 AssertComRCReturnVoid (thatCaller.rc());
510
511 /* peer is not modified, lock it for reading (aThat is "master" so locked
512 * first) */
513 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
514
515 /* this will back up current data */
516 mData.assignCopy (aThat->mData);
517}
518
519// private methods
520/////////////////////////////////////////////////////////////////////////////
521/* 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