VirtualBox

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

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

Main: Cleaned up the long standing const BSTR = const (OLECHAR *) on WIn32 vs (const PRunichar) * on XPCOM clash. Cleaned up BSTR/GUID macros (IN_BSTR replaces INPTR BSTR, IN_GUID replaces INPTR GUIDPARAM, OUT_GUID replaces GUIDPARAMOUT).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.0 KB
Line 
1/* $Id: ParallelPortImpl.cpp 15051 2008-12-05 17:20:00Z 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 CheckComArgOutPointerValid(aEnabled);
326
327 AutoCaller autoCaller (this);
328 CheckComRCReturnRC (autoCaller.rc());
329
330 AutoReadLock alock (this);
331
332 *aEnabled = mData->mEnabled;
333
334 return S_OK;
335}
336
337STDMETHODIMP ParallelPort::COMSETTER(Enabled) (BOOL aEnabled)
338{
339 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
340
341 AutoCaller autoCaller (this);
342 CheckComRCReturnRC (autoCaller.rc());
343
344 /* the machine needs to be mutable */
345 Machine::AutoMutableStateDependency adep (mParent);
346 CheckComRCReturnRC (adep.rc());
347
348 AutoWriteLock alock (this);
349
350 if (mData->mEnabled != aEnabled)
351 {
352 if (aEnabled &&
353 mData->mPath.isEmpty())
354 return setError (E_INVALIDARG,
355 tr ("Cannot enable the parallel port %d "
356 "because the port path is empty or null"),
357 mData->mSlot);
358
359 mData.backup();
360 mData->mEnabled = aEnabled;
361
362 /* leave the lock before informing callbacks */
363 alock.unlock();
364
365 mParent->onParallelPortChange (this);
366 }
367
368 return S_OK;
369}
370
371STDMETHODIMP ParallelPort::COMGETTER(Slot) (ULONG *aSlot)
372{
373 CheckComArgOutPointerValid(aSlot);
374
375 AutoCaller autoCaller (this);
376 CheckComRCReturnRC (autoCaller.rc());
377
378 AutoReadLock alock (this);
379
380 *aSlot = mData->mSlot;
381
382 return S_OK;
383}
384
385STDMETHODIMP ParallelPort::COMGETTER(IRQ) (ULONG *aIRQ)
386{
387 CheckComArgOutPointerValid(aIRQ);
388
389 AutoCaller autoCaller (this);
390 CheckComRCReturnRC (autoCaller.rc());
391
392 AutoReadLock alock (this);
393
394 *aIRQ = mData->mIRQ;
395
396 return S_OK;
397}
398
399STDMETHODIMP ParallelPort::COMSETTER(IRQ)(ULONG aIRQ)
400{
401 /* check IRQ limits
402 * (when changing this, make sure it corresponds to XML schema */
403 if (aIRQ > 255)
404 return setError (E_INVALIDARG,
405 tr ("Invalid IRQ number of the parallel port %d: "
406 "%lu (must be in range [0, %lu])"),
407 mData->mSlot, aIRQ, 255);
408
409 AutoCaller autoCaller (this);
410 CheckComRCReturnRC (autoCaller.rc());
411
412 /* the machine needs to be mutable */
413 Machine::AutoMutableStateDependency adep (mParent);
414 CheckComRCReturnRC (adep.rc());
415
416 AutoWriteLock alock (this);
417
418 HRESULT rc = S_OK;
419 bool emitChangeEvent = false;
420
421 if (mData->mIRQ != aIRQ)
422 {
423 mData.backup();
424 mData->mIRQ = aIRQ;
425 emitChangeEvent = true;
426 }
427
428 if (emitChangeEvent)
429 {
430 /* leave the lock before informing callbacks */
431 alock.unlock();
432
433 mParent->onParallelPortChange (this);
434 }
435
436 return rc;
437}
438
439STDMETHODIMP ParallelPort::COMGETTER(IOBase) (ULONG *aIOBase)
440{
441 CheckComArgOutPointerValid(aIOBase);
442
443 AutoCaller autoCaller (this);
444 CheckComRCReturnRC (autoCaller.rc());
445
446 AutoReadLock 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 AutoWriteLock 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 CheckComArgOutPointerValid(aPath);
496
497 AutoCaller autoCaller (this);
498 CheckComRCReturnRC (autoCaller.rc());
499
500 AutoReadLock alock (this);
501
502 mData->mPath.cloneTo (aPath);
503
504 return S_OK;
505}
506
507/**
508 * Validates COMSETTER(Path) arguments.
509 */
510HRESULT ParallelPort::checkSetPath (CBSTR aPath)
511{
512 AssertReturn (isWriteLockOnCurrentThread(), E_FAIL);
513
514 if (mData->mEnabled &&
515 (aPath == NULL || *aPath == '\0'))
516 return setError (E_INVALIDARG,
517 tr ("Path of the parallel port %d may not be empty or null "
518 "when the port is enabled"),
519 mData->mSlot);
520
521 return S_OK;
522}
523
524STDMETHODIMP ParallelPort::COMSETTER(Path) (IN_BSTR aPath)
525{
526 AutoCaller autoCaller (this);
527 CheckComRCReturnRC (autoCaller.rc());
528
529 /* the machine needs to be mutable */
530 Machine::AutoMutableStateDependency adep (mParent);
531 CheckComRCReturnRC (adep.rc());
532
533 AutoWriteLock alock (this);
534
535 /* we treat empty as null when e.g. saving to XML, do the same here */
536 if (aPath && *aPath == '\0')
537 aPath = NULL;
538
539 if (mData->mPath != aPath)
540 {
541 HRESULT rc = checkSetPath (aPath);
542 CheckComRCReturnRC (rc);
543
544 mData.backup();
545 mData->mPath = aPath;
546
547 /* leave the lock before informing callbacks */
548 alock.unlock();
549
550 return mParent->onParallelPortChange (this);
551 }
552
553 return S_OK;
554}
555/* 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