VirtualBox

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

Last change on this file since 20961 was 16560, checked in by vboxsync, 16 years ago

Main: do not include include/VBox/settings.h from other header files but only from implementations that need it (save compile time)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.0 KB
Line 
1/* $Id: ParallelPortImpl.cpp 16560 2009-02-06 18:06:04Z 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::Key &aPortNode)
177{
178 using namespace settings;
179
180 AssertReturn (!aPortNode.isNull(), E_FAIL);
181
182 AutoCaller autoCaller (this);
183 AssertComRCReturnRC (autoCaller.rc());
184
185 AutoWriteLock alock (this);
186
187 /* Note: we assume that the default values for attributes of optional
188 * nodes are assigned in the Data::Data() constructor and don't do it
189 * here. It implies that this method may only be called after constructing
190 * a new BIOSSettings object while all its data fields are in the default
191 * values. Exceptions are fields whose creation time defaults don't match
192 * values that should be applied when these fields are not explicitly set
193 * in the settings file (for backwards compatibility reasons). This takes
194 * place when a setting of a newly created object must default to A while
195 * the same setting of an object loaded from the old settings file must
196 * default to B. */
197
198 /* enabled (required) */
199 mData->mEnabled = aPortNode.value <bool> ("enabled");
200 /* I/O base (required) */
201 mData->mIOBase = aPortNode.value <ULONG> ("IOBase");
202 /* IRQ (required) */
203 mData->mIRQ = aPortNode.value <ULONG> ("IRQ");
204 /* device path (optional, defaults to null) */
205 Bstr path = aPortNode.stringValue ("path");
206
207 HRESULT rc = checkSetPath (path);
208 CheckComRCReturnRC (rc);
209 mData->mPath = path;
210
211 return S_OK;
212}
213
214/**
215 * Saves settings to the given port node.
216 *
217 * Note that the given Port node is comletely empty on input.
218 *
219 * @param aPortNode <Port> node.
220 *
221 * @note Locks this object for reading.
222 */
223HRESULT ParallelPort::saveSettings (settings::Key &aPortNode)
224{
225 using namespace settings;
226
227 AssertReturn (!aPortNode.isNull(), E_FAIL);
228
229 AutoCaller autoCaller (this);
230 AssertComRCReturnRC (autoCaller.rc());
231
232 AutoReadLock alock (this);
233
234 aPortNode.setValue <bool> ("enabled", !!mData->mEnabled);
235 aPortNode.setValue <ULONG> ("IOBase", mData->mIOBase, 16);
236 aPortNode.setValue <ULONG> ("IRQ", mData->mIRQ);
237
238 /* 'path' is optional in XML */
239 if (!mData->mPath.isEmpty())
240 aPortNode.setValue <Bstr> ("path", mData->mPath);
241
242 return S_OK;
243}
244
245/**
246 * @note Locks this object for writing.
247 */
248bool ParallelPort::rollback()
249{
250 /* sanity */
251 AutoCaller autoCaller (this);
252 AssertComRCReturn (autoCaller.rc(), false);
253
254 AutoWriteLock alock (this);
255
256 bool changed = false;
257
258 if (mData.isBackedUp())
259 {
260 /* we need to check all data to see whether anything will be changed
261 * after rollback */
262 changed = mData.hasActualChanges();
263 mData.rollback();
264 }
265
266 return changed;
267}
268
269/**
270 * @note Locks this object for writing, together with the peer object (also
271 * for writing) if there is one.
272 */
273void ParallelPort::commit()
274{
275 /* sanity */
276 AutoCaller autoCaller (this);
277 AssertComRCReturnVoid (autoCaller.rc());
278
279 /* sanity too */
280 AutoCaller peerCaller (mPeer);
281 AssertComRCReturnVoid (peerCaller.rc());
282
283 /* lock both for writing since we modify both (mPeer is "master" so locked
284 * first) */
285 AutoMultiWriteLock2 alock (mPeer, this);
286
287 if (mData.isBackedUp())
288 {
289 mData.commit();
290 if (mPeer)
291 {
292 /* attach new data to the peer and reshare it */
293 mPeer->mData.attach (mData);
294 }
295 }
296}
297
298/**
299 * @note Locks this object for writing, together with the peer object
300 * represented by @a aThat (locked for reading).
301 */
302void ParallelPort::copyFrom (ParallelPort *aThat)
303{
304 AssertReturnVoid (aThat != NULL);
305
306 /* sanity */
307 AutoCaller autoCaller (this);
308 AssertComRCReturnVoid (autoCaller.rc());
309
310 /* sanity too */
311 AutoCaller thatCaller (aThat);
312 AssertComRCReturnVoid (thatCaller.rc());
313
314 /* peer is not modified, lock it for reading (aThat is "master" so locked
315 * first) */
316 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
317
318 /* this will back up current data */
319 mData.assignCopy (aThat->mData);
320}
321
322// IParallelPort properties
323/////////////////////////////////////////////////////////////////////////////
324
325STDMETHODIMP ParallelPort::COMGETTER(Enabled) (BOOL *aEnabled)
326{
327 CheckComArgOutPointerValid(aEnabled);
328
329 AutoCaller autoCaller (this);
330 CheckComRCReturnRC (autoCaller.rc());
331
332 AutoReadLock alock (this);
333
334 *aEnabled = mData->mEnabled;
335
336 return S_OK;
337}
338
339STDMETHODIMP ParallelPort::COMSETTER(Enabled) (BOOL aEnabled)
340{
341 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
342
343 AutoCaller autoCaller (this);
344 CheckComRCReturnRC (autoCaller.rc());
345
346 /* the machine needs to be mutable */
347 Machine::AutoMutableStateDependency adep (mParent);
348 CheckComRCReturnRC (adep.rc());
349
350 AutoWriteLock alock (this);
351
352 if (mData->mEnabled != aEnabled)
353 {
354 if (aEnabled &&
355 mData->mPath.isEmpty())
356 return setError (E_INVALIDARG,
357 tr ("Cannot enable the parallel port %d "
358 "because the port path is empty or null"),
359 mData->mSlot);
360
361 mData.backup();
362 mData->mEnabled = aEnabled;
363
364 /* leave the lock before informing callbacks */
365 alock.unlock();
366
367 mParent->onParallelPortChange (this);
368 }
369
370 return S_OK;
371}
372
373STDMETHODIMP ParallelPort::COMGETTER(Slot) (ULONG *aSlot)
374{
375 CheckComArgOutPointerValid(aSlot);
376
377 AutoCaller autoCaller (this);
378 CheckComRCReturnRC (autoCaller.rc());
379
380 AutoReadLock alock (this);
381
382 *aSlot = mData->mSlot;
383
384 return S_OK;
385}
386
387STDMETHODIMP ParallelPort::COMGETTER(IRQ) (ULONG *aIRQ)
388{
389 CheckComArgOutPointerValid(aIRQ);
390
391 AutoCaller autoCaller (this);
392 CheckComRCReturnRC (autoCaller.rc());
393
394 AutoReadLock alock (this);
395
396 *aIRQ = mData->mIRQ;
397
398 return S_OK;
399}
400
401STDMETHODIMP ParallelPort::COMSETTER(IRQ)(ULONG aIRQ)
402{
403 /* check IRQ limits
404 * (when changing this, make sure it corresponds to XML schema */
405 if (aIRQ > 255)
406 return setError (E_INVALIDARG,
407 tr ("Invalid IRQ number of the parallel port %d: "
408 "%lu (must be in range [0, %lu])"),
409 mData->mSlot, aIRQ, 255);
410
411 AutoCaller autoCaller (this);
412 CheckComRCReturnRC (autoCaller.rc());
413
414 /* the machine needs to be mutable */
415 Machine::AutoMutableStateDependency adep (mParent);
416 CheckComRCReturnRC (adep.rc());
417
418 AutoWriteLock alock (this);
419
420 HRESULT rc = S_OK;
421 bool emitChangeEvent = false;
422
423 if (mData->mIRQ != aIRQ)
424 {
425 mData.backup();
426 mData->mIRQ = aIRQ;
427 emitChangeEvent = true;
428 }
429
430 if (emitChangeEvent)
431 {
432 /* leave the lock before informing callbacks */
433 alock.unlock();
434
435 mParent->onParallelPortChange (this);
436 }
437
438 return rc;
439}
440
441STDMETHODIMP ParallelPort::COMGETTER(IOBase) (ULONG *aIOBase)
442{
443 CheckComArgOutPointerValid(aIOBase);
444
445 AutoCaller autoCaller (this);
446 CheckComRCReturnRC (autoCaller.rc());
447
448 AutoReadLock alock (this);
449
450 *aIOBase = mData->mIOBase;
451
452 return S_OK;
453}
454
455STDMETHODIMP ParallelPort::COMSETTER(IOBase)(ULONG aIOBase)
456{
457 /* check IOBase limits
458 * (when changing this, make sure it corresponds to XML schema */
459 if (aIOBase > 0xFFFF)
460 return setError (E_INVALIDARG,
461 tr ("Invalid I/O port base address of the parallel port %d: "
462 "%lu (must be in range [0, 0x%X])"),
463 mData->mSlot, aIOBase, 0, 0xFFFF);
464
465 AutoCaller autoCaller (this);
466 CheckComRCReturnRC (autoCaller.rc());
467
468 /* the machine needs to be mutable */
469 Machine::AutoMutableStateDependency adep (mParent);
470 CheckComRCReturnRC (adep.rc());
471
472 AutoWriteLock alock (this);
473
474 HRESULT rc = S_OK;
475 bool emitChangeEvent = false;
476
477 if (mData->mIOBase != aIOBase)
478 {
479 mData.backup();
480 mData->mIOBase = aIOBase;
481 emitChangeEvent = true;
482 }
483
484 if (emitChangeEvent)
485 {
486 /* leave the lock before informing callbacks */
487 alock.unlock();
488
489 mParent->onParallelPortChange (this);
490 }
491
492 return rc;
493}
494
495STDMETHODIMP ParallelPort::COMGETTER(Path) (BSTR *aPath)
496{
497 CheckComArgOutPointerValid(aPath);
498
499 AutoCaller autoCaller (this);
500 CheckComRCReturnRC (autoCaller.rc());
501
502 AutoReadLock alock (this);
503
504 mData->mPath.cloneTo (aPath);
505
506 return S_OK;
507}
508
509/**
510 * Validates COMSETTER(Path) arguments.
511 */
512HRESULT ParallelPort::checkSetPath (CBSTR aPath)
513{
514 AssertReturn (isWriteLockOnCurrentThread(), E_FAIL);
515
516 if (mData->mEnabled &&
517 (aPath == NULL || *aPath == '\0'))
518 return setError (E_INVALIDARG,
519 tr ("Path of the parallel port %d may not be empty or null "
520 "when the port is enabled"),
521 mData->mSlot);
522
523 return S_OK;
524}
525
526STDMETHODIMP ParallelPort::COMSETTER(Path) (IN_BSTR aPath)
527{
528 AutoCaller autoCaller (this);
529 CheckComRCReturnRC (autoCaller.rc());
530
531 /* the machine needs to be mutable */
532 Machine::AutoMutableStateDependency adep (mParent);
533 CheckComRCReturnRC (adep.rc());
534
535 AutoWriteLock alock (this);
536
537 /* we treat empty as null when e.g. saving to XML, do the same here */
538 if (aPath && *aPath == '\0')
539 aPath = NULL;
540
541 if (mData->mPath != aPath)
542 {
543 HRESULT rc = checkSetPath (aPath);
544 CheckComRCReturnRC (rc);
545
546 mData.backup();
547 mData->mPath = aPath;
548
549 /* leave the lock before informing callbacks */
550 alock.unlock();
551
552 return mParent->onParallelPortChange (this);
553 }
554
555 return S_OK;
556}
557/* 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