VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/ParallelPortImpl.cpp@ 36975

Last change on this file since 36975 was 35638, checked in by vboxsync, 14 years ago

Main. QT/FE: fix long standing COM issue

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