VirtualBox

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

Last change on this file since 26156 was 26156, checked in by vboxsync, 15 years ago

Main: get rid of isReallyChanged() voodoo in Machine and subclasses; instead check in the XML classes whether things really changed via operator==; documentation, cleanup

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