VirtualBox

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

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

Main: Implemented true AutoReaderLock (#2768).

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