VirtualBox

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

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

Ported s2 branch (r37120:38456).

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