VirtualBox

source: vbox/trunk/src/VBox/Main/ParallelPortImpl.cpp@ 25184

Last change on this file since 25184 was 25149, checked in by vboxsync, 15 years ago

Main: cleanup: remove all CheckComRC* macros (no functional change)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 KB
Line 
1/* $Id: ParallelPortImpl.cpp 25149 2009-12-02 14:34:47Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "ParallelPortImpl.h"
23#include "MachineImpl.h"
24#include "VirtualBoxImpl.h"
25#include "Logging.h"
26
27#include <iprt/string.h>
28#include <iprt/cpputils.h>
29
30#include <VBox/settings.h>
31
32// constructor / destructor
33/////////////////////////////////////////////////////////////////////////////
34
35DEFINE_EMPTY_CTOR_DTOR (ParallelPort)
36
37HRESULT ParallelPort::FinalConstruct()
38{
39 return S_OK;
40}
41
42void ParallelPort::FinalRelease()
43{
44 uninit();
45}
46
47// public initializer/uninitializer for internal purposes only
48/////////////////////////////////////////////////////////////////////////////
49
50/**
51 * Initializes the Parallel Port object.
52 *
53 * @param aParent Handle of the parent object.
54 */
55HRESULT ParallelPort::init (Machine *aParent, ULONG aSlot)
56{
57 LogFlowThisFunc(("aParent=%p, aSlot=%d\n", aParent, aSlot));
58
59 ComAssertRet (aParent, E_INVALIDARG);
60
61 /* Enclose the state transition NotReady->InInit->Ready */
62 AutoInitSpan autoInitSpan(this);
63 AssertReturn(autoInitSpan.isOk(), E_FAIL);
64
65 unconst(mParent) = aParent;
66 /* mPeer is left null */
67
68 mData.allocate();
69
70 /* initialize data */
71 mData->mSlot = aSlot;
72
73 /* Confirm a successful initialization */
74 autoInitSpan.setSucceeded();
75
76 return S_OK;
77}
78
79/**
80 * Initializes the Parallel Port object given another serial port object
81 * (a kind of copy constructor). This object shares data with
82 * the object passed as an argument.
83 *
84 * @note This object must be destroyed before the original object
85 * it shares data with is destroyed.
86 *
87 * @note Locks @a aThat object for reading.
88 */
89HRESULT ParallelPort::init (Machine *aParent, ParallelPort *aThat)
90{
91 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
92
93 ComAssertRet (aParent && aThat, E_INVALIDARG);
94
95 /* Enclose the state transition NotReady->InInit->Ready */
96 AutoInitSpan autoInitSpan(this);
97 AssertReturn(autoInitSpan.isOk(), E_FAIL);
98
99 unconst(mParent) = aParent;
100 unconst(mPeer) = aThat;
101
102 AutoCaller thatCaller (aThat);
103 AssertComRCReturnRC(thatCaller.rc());
104
105 AutoReadLock thatLock (aThat);
106 mData.share (aThat->mData);
107
108 /* Confirm a successful initialization */
109 autoInitSpan.setSucceeded();
110
111 return S_OK;
112}
113
114/**
115 * Initializes the guest object given another guest object
116 * (a kind of copy constructor). This object makes a private copy of data
117 * of the original object passed as an argument.
118 *
119 * @note Locks @a aThat object for reading.
120 */
121HRESULT ParallelPort::initCopy (Machine *aParent, ParallelPort *aThat)
122{
123 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
124
125 ComAssertRet (aParent && aThat, E_INVALIDARG);
126
127 /* Enclose the state transition NotReady->InInit->Ready */
128 AutoInitSpan autoInitSpan(this);
129 AssertReturn(autoInitSpan.isOk(), E_FAIL);
130
131 unconst(mParent) = aParent;
132 /* mPeer is left null */
133
134 AutoCaller thatCaller (aThat);
135 AssertComRCReturnRC(thatCaller.rc());
136
137 AutoReadLock thatLock (aThat);
138 mData.attachCopy (aThat->mData);
139
140 /* Confirm a successful initialization */
141 autoInitSpan.setSucceeded();
142
143 return S_OK;
144}
145
146/**
147 * Uninitializes the instance and sets the ready flag to FALSE.
148 * Called either from FinalRelease() or by the parent when it gets destroyed.
149 */
150void ParallelPort::uninit()
151{
152 LogFlowThisFunc(("\n"));
153
154 /* Enclose the state transition Ready->InUninit->NotReady */
155 AutoUninitSpan autoUninitSpan(this);
156 if (autoUninitSpan.uninitDone())
157 return;
158
159 mData.free();
160
161 unconst(mPeer).setNull();
162 unconst(mParent).setNull();
163}
164
165// public methods only for internal purposes
166////////////////////////////////////////////////////////////////////////////////
167
168/**
169 * Loads settings from the given port node.
170 * May be called once right after this object creation.
171 *
172 * @param aPortNode <Port> node.
173 *
174 * @note Locks this object for writing.
175 */
176HRESULT ParallelPort::loadSettings(const settings::ParallelPort &data)
177{
178 AutoCaller autoCaller(this);
179 AssertComRCReturnRC(autoCaller.rc());
180
181 AutoWriteLock alock(this);
182
183 /* Note: we assume that the default values for attributes of optional
184 * nodes are assigned in the Data::Data() constructor and don't do it
185 * here. It implies that this method may only be called after constructing
186 * a new BIOSSettings object while all its data fields are in the default
187 * values. Exceptions are fields whose creation time defaults don't match
188 * values that should be applied when these fields are not explicitly set
189 * in the settings file (for backwards compatibility reasons). This takes
190 * place when a setting of a newly created object must default to A while
191 * the same setting of an object loaded from the old settings file must
192 * default to B. */
193
194 /* enabled (required) */
195 mData->mEnabled = data.fEnabled;
196 /* I/O base (required) */
197 mData->mIOBase = data.ulIOBase;
198 /* IRQ (required) */
199 mData->mIRQ = data.ulIRQ;
200 /* device path (optional, defaults to null) */
201 Bstr path(data.strPath);
202 HRESULT rc = checkSetPath (path);
203 if (FAILED(rc)) return rc;
204 mData->mPath = path;
205
206 return S_OK;
207}
208
209/**
210 * Saves settings to the given port node.
211 *
212 * Note that the given Port node is comletely empty on input.
213 *
214 * @param aPortNode <Port> node.
215 *
216 * @note Locks this object for reading.
217 */
218HRESULT ParallelPort::saveSettings(settings::ParallelPort &data)
219{
220 AutoCaller autoCaller(this);
221 AssertComRCReturnRC(autoCaller.rc());
222
223 AutoReadLock alock(this);
224
225 data.fEnabled = !!mData->mEnabled;
226 data.ulIOBase = mData->mIOBase;
227 data.ulIRQ = mData->mIRQ;
228 data.strPath = mData->mPath;
229
230 return S_OK;
231}
232
233/**
234 * @note Locks this object for writing.
235 */
236bool ParallelPort::rollback()
237{
238 /* sanity */
239 AutoCaller autoCaller(this);
240 AssertComRCReturn (autoCaller.rc(), false);
241
242 AutoWriteLock alock(this);
243
244 bool changed = false;
245
246 if (mData.isBackedUp())
247 {
248 /* we need to check all data to see whether anything will be changed
249 * after rollback */
250 changed = mData.hasActualChanges();
251 mData.rollback();
252 }
253
254 return changed;
255}
256
257/**
258 * @note Locks this object for writing, together with the peer object (also
259 * for writing) if there is one.
260 */
261void ParallelPort::commit()
262{
263 /* sanity */
264 AutoCaller autoCaller(this);
265 AssertComRCReturnVoid (autoCaller.rc());
266
267 /* sanity too */
268 AutoCaller peerCaller (mPeer);
269 AssertComRCReturnVoid (peerCaller.rc());
270
271 /* lock both for writing since we modify both (mPeer is "master" so locked
272 * first) */
273 AutoMultiWriteLock2 alock (mPeer, this);
274
275 if (mData.isBackedUp())
276 {
277 mData.commit();
278 if (mPeer)
279 {
280 /* attach new data to the peer and reshare it */
281 mPeer->mData.attach (mData);
282 }
283 }
284}
285
286/**
287 * @note Locks this object for writing, together with the peer object
288 * represented by @a aThat (locked for reading).
289 */
290void ParallelPort::copyFrom (ParallelPort *aThat)
291{
292 AssertReturnVoid (aThat != NULL);
293
294 /* sanity */
295 AutoCaller autoCaller(this);
296 AssertComRCReturnVoid (autoCaller.rc());
297
298 /* sanity too */
299 AutoCaller thatCaller (aThat);
300 AssertComRCReturnVoid (thatCaller.rc());
301
302 /* peer is not modified, lock it for reading (aThat is "master" so locked
303 * first) */
304 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
305
306 /* this will back up current data */
307 mData.assignCopy (aThat->mData);
308}
309
310// IParallelPort properties
311/////////////////////////////////////////////////////////////////////////////
312
313STDMETHODIMP ParallelPort::COMGETTER(Enabled) (BOOL *aEnabled)
314{
315 CheckComArgOutPointerValid(aEnabled);
316
317 AutoCaller autoCaller(this);
318 if (FAILED(autoCaller.rc())) return autoCaller.rc();
319
320 AutoReadLock alock(this);
321
322 *aEnabled = mData->mEnabled;
323
324 return S_OK;
325}
326
327STDMETHODIMP ParallelPort::COMSETTER(Enabled) (BOOL aEnabled)
328{
329 LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled));
330
331 AutoCaller autoCaller(this);
332 if (FAILED(autoCaller.rc())) return autoCaller.rc();
333
334 /* the machine needs to be mutable */
335 Machine::AutoMutableStateDependency adep(mParent);
336 if (FAILED(adep.rc())) return adep.rc();
337
338 AutoWriteLock alock(this);
339
340 if (mData->mEnabled != aEnabled)
341 {
342 if (aEnabled &&
343 mData->mPath.isEmpty())
344 return setError (E_INVALIDARG,
345 tr ("Cannot enable the parallel port %d "
346 "because the port path is empty or null"),
347 mData->mSlot);
348
349 mData.backup();
350 mData->mEnabled = aEnabled;
351
352 /* leave the lock before informing callbacks */
353 alock.unlock();
354
355 mParent->onParallelPortChange (this);
356 }
357
358 return S_OK;
359}
360
361STDMETHODIMP ParallelPort::COMGETTER(Slot) (ULONG *aSlot)
362{
363 CheckComArgOutPointerValid(aSlot);
364
365 AutoCaller autoCaller(this);
366 if (FAILED(autoCaller.rc())) return autoCaller.rc();
367
368 AutoReadLock alock(this);
369
370 *aSlot = mData->mSlot;
371
372 return S_OK;
373}
374
375STDMETHODIMP ParallelPort::COMGETTER(IRQ) (ULONG *aIRQ)
376{
377 CheckComArgOutPointerValid(aIRQ);
378
379 AutoCaller autoCaller(this);
380 if (FAILED(autoCaller.rc())) return autoCaller.rc();
381
382 AutoReadLock alock(this);
383
384 *aIRQ = mData->mIRQ;
385
386 return S_OK;
387}
388
389STDMETHODIMP ParallelPort::COMSETTER(IRQ)(ULONG aIRQ)
390{
391 /* check IRQ limits
392 * (when changing this, make sure it corresponds to XML schema */
393 if (aIRQ > 255)
394 return setError (E_INVALIDARG,
395 tr ("Invalid IRQ number of the parallel port %d: "
396 "%lu (must be in range [0, %lu])"),
397 mData->mSlot, aIRQ, 255);
398
399 AutoCaller autoCaller(this);
400 if (FAILED(autoCaller.rc())) return autoCaller.rc();
401
402 /* the machine needs to be mutable */
403 Machine::AutoMutableStateDependency adep(mParent);
404 if (FAILED(adep.rc())) return adep.rc();
405
406 AutoWriteLock alock(this);
407
408 HRESULT rc = S_OK;
409 bool emitChangeEvent = false;
410
411 if (mData->mIRQ != aIRQ)
412 {
413 mData.backup();
414 mData->mIRQ = aIRQ;
415 emitChangeEvent = true;
416 }
417
418 if (emitChangeEvent)
419 {
420 /* leave the lock before informing callbacks */
421 alock.unlock();
422
423 mParent->onParallelPortChange (this);
424 }
425
426 return rc;
427}
428
429STDMETHODIMP ParallelPort::COMGETTER(IOBase) (ULONG *aIOBase)
430{
431 CheckComArgOutPointerValid(aIOBase);
432
433 AutoCaller autoCaller(this);
434 if (FAILED(autoCaller.rc())) return autoCaller.rc();
435
436 AutoReadLock alock(this);
437
438 *aIOBase = mData->mIOBase;
439
440 return S_OK;
441}
442
443STDMETHODIMP ParallelPort::COMSETTER(IOBase)(ULONG aIOBase)
444{
445 /* check IOBase limits
446 * (when changing this, make sure it corresponds to XML schema */
447 if (aIOBase > 0xFFFF)
448 return setError (E_INVALIDARG,
449 tr ("Invalid I/O port base address of the parallel port %d: "
450 "%lu (must be in range [0, 0x%X])"),
451 mData->mSlot, aIOBase, 0, 0xFFFF);
452
453 AutoCaller autoCaller(this);
454 if (FAILED(autoCaller.rc())) return autoCaller.rc();
455
456 /* the machine needs to be mutable */
457 Machine::AutoMutableStateDependency adep(mParent);
458 if (FAILED(adep.rc())) return adep.rc();
459
460 AutoWriteLock alock(this);
461
462 HRESULT rc = S_OK;
463 bool emitChangeEvent = false;
464
465 if (mData->mIOBase != aIOBase)
466 {
467 mData.backup();
468 mData->mIOBase = aIOBase;
469 emitChangeEvent = true;
470 }
471
472 if (emitChangeEvent)
473 {
474 /* leave the lock before informing callbacks */
475 alock.unlock();
476
477 mParent->onParallelPortChange (this);
478 }
479
480 return rc;
481}
482
483STDMETHODIMP ParallelPort::COMGETTER(Path) (BSTR *aPath)
484{
485 CheckComArgOutPointerValid(aPath);
486
487 AutoCaller autoCaller(this);
488 if (FAILED(autoCaller.rc())) return autoCaller.rc();
489
490 AutoReadLock alock(this);
491
492 mData->mPath.cloneTo(aPath);
493
494 return S_OK;
495}
496
497/**
498 * Validates COMSETTER(Path) arguments.
499 */
500HRESULT ParallelPort::checkSetPath (CBSTR aPath)
501{
502 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
503
504 if (mData->mEnabled &&
505 (aPath == NULL || *aPath == '\0'))
506 return setError (E_INVALIDARG,
507 tr ("Path of the parallel port %d may not be empty or null "
508 "when the port is enabled"),
509 mData->mSlot);
510
511 return S_OK;
512}
513
514STDMETHODIMP ParallelPort::COMSETTER(Path) (IN_BSTR aPath)
515{
516 AutoCaller autoCaller(this);
517 if (FAILED(autoCaller.rc())) return autoCaller.rc();
518
519 /* the machine needs to be mutable */
520 Machine::AutoMutableStateDependency adep(mParent);
521 if (FAILED(adep.rc())) return adep.rc();
522
523 AutoWriteLock alock(this);
524
525 /* we treat empty as null when e.g. saving to XML, do the same here */
526 if (aPath && *aPath == '\0')
527 aPath = NULL;
528
529 if (mData->mPath != aPath)
530 {
531 HRESULT rc = checkSetPath (aPath);
532 if (FAILED(rc)) return rc;
533
534 mData.backup();
535 mData->mPath = aPath;
536
537 /* leave the lock before informing callbacks */
538 alock.unlock();
539
540 return mParent->onParallelPortChange (this);
541 }
542
543 return S_OK;
544}
545/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use