VirtualBox

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

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

Added vim modelines to aid following coding guidelines, like no tabs,
similar to what is already in the xidl file.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.0 KB
Line 
1/* $Id: ParallelPortImpl.cpp 14772 2008-11-28 12:41:22Z 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_FAIL);
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_FAIL);
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_FAIL);
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/* 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