VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

  • 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 28800 2010-04-27 08:22:32Z 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 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) = NULL;
186 unconst(m->pMachine) = NULL;
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 because the port path is empty or null"),
228 m->bd->ulSlot);
229
230 m->bd.backup();
231 m->bd->fEnabled = !!aEnabled;
232
233 m->fModified = true;
234 // leave the lock before informing callbacks
235 alock.release();
236
237 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
238 m->pMachine->setModified(Machine::IsModified_ParallelPorts);
239 mlock.release();
240
241 m->pMachine->onParallelPortChange(this);
242 }
243
244 return S_OK;
245}
246
247STDMETHODIMP ParallelPort::COMGETTER(Slot) (ULONG *aSlot)
248{
249 CheckComArgOutPointerValid(aSlot);
250
251 AutoCaller autoCaller(this);
252 if (FAILED(autoCaller.rc())) return autoCaller.rc();
253
254 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
255
256 *aSlot = m->bd->ulSlot;
257
258 return S_OK;
259}
260
261STDMETHODIMP ParallelPort::COMGETTER(IRQ) (ULONG *aIRQ)
262{
263 CheckComArgOutPointerValid(aIRQ);
264
265 AutoCaller autoCaller(this);
266 if (FAILED(autoCaller.rc())) return autoCaller.rc();
267
268 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
269
270 *aIRQ = m->bd->ulIRQ;
271
272 return S_OK;
273}
274
275STDMETHODIMP ParallelPort::COMSETTER(IRQ)(ULONG aIRQ)
276{
277 /* check IRQ limits
278 * (when changing this, make sure it corresponds to XML schema */
279 if (aIRQ > 255)
280 return setError(E_INVALIDARG,
281 tr("Invalid IRQ number of the parallel port %d: %lu (must be in range [0, %lu])"),
282 m->bd->ulSlot, aIRQ, 255);
283
284 AutoCaller autoCaller(this);
285 if (FAILED(autoCaller.rc())) return autoCaller.rc();
286
287 /* the machine needs to be mutable */
288 AutoMutableStateDependency adep(m->pMachine);
289 if (FAILED(adep.rc())) return adep.rc();
290
291 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
292
293 if (m->bd->ulIRQ != aIRQ)
294 {
295 m->bd.backup();
296 m->bd->ulIRQ = aIRQ;
297
298 m->fModified = true;
299 // leave the lock before informing callbacks
300 alock.release();
301
302 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
303 m->pMachine->setModified(Machine::IsModified_ParallelPorts);
304 mlock.release();
305
306 m->pMachine->onParallelPortChange(this);
307 }
308
309 return S_OK;
310}
311
312STDMETHODIMP ParallelPort::COMGETTER(IOBase) (ULONG *aIOBase)
313{
314 CheckComArgOutPointerValid(aIOBase);
315
316 AutoCaller autoCaller(this);
317 if (FAILED(autoCaller.rc())) return autoCaller.rc();
318
319 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
320
321 *aIOBase = m->bd->ulIOBase;
322
323 return S_OK;
324}
325
326STDMETHODIMP ParallelPort::COMSETTER(IOBase)(ULONG aIOBase)
327{
328 /* check IOBase limits
329 * (when changing this, make sure it corresponds to XML schema */
330 if (aIOBase > 0xFFFF)
331 return setError(E_INVALIDARG,
332 tr("Invalid I/O port base address of the parallel port %d: %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 if (m->bd->ulIOBase != aIOBase)
345 {
346 m->bd.backup();
347 m->bd->ulIOBase = aIOBase;
348
349 m->fModified = true;
350 // leave the lock before informing callbacks
351 alock.release();
352
353 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
354 m->pMachine->setModified(Machine::IsModified_ParallelPorts);
355 mlock.release();
356
357 m->pMachine->onParallelPortChange(this);
358 }
359
360 return S_OK;
361}
362
363STDMETHODIMP ParallelPort::COMGETTER(Path) (BSTR *aPath)
364{
365 CheckComArgOutPointerValid(aPath);
366
367 AutoCaller autoCaller(this);
368 if (FAILED(autoCaller.rc())) return autoCaller.rc();
369
370 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
371
372 m->bd->strPath.cloneTo(aPath);
373
374 return S_OK;
375}
376
377STDMETHODIMP ParallelPort::COMSETTER(Path) (IN_BSTR aPath)
378{
379 AutoCaller autoCaller(this);
380 if (FAILED(autoCaller.rc())) return autoCaller.rc();
381
382 /* the machine needs to be mutable */
383 AutoMutableStateDependency adep(m->pMachine);
384 if (FAILED(adep.rc())) return adep.rc();
385
386 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
387
388 Utf8Str str(aPath);
389 if (str != m->bd->strPath)
390 {
391 HRESULT rc = checkSetPath(str);
392 if (FAILED(rc)) return rc;
393
394 m->bd.backup();
395 m->bd->strPath = str;
396
397 m->fModified = true;
398 // leave the lock before informing callbacks
399 alock.release();
400
401 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
402 m->pMachine->setModified(Machine::IsModified_ParallelPorts);
403 mlock.release();
404
405 return m->pMachine->onParallelPortChange(this);
406 }
407
408 return S_OK;
409}
410
411// public methods only for internal purposes
412////////////////////////////////////////////////////////////////////////////////
413
414/**
415 * Loads settings from the given port node.
416 * May be called once right after this object creation.
417 *
418 * @param aPortNode <Port> node.
419 *
420 * @note Locks this object for writing.
421 */
422HRESULT ParallelPort::loadSettings(const settings::ParallelPort &data)
423{
424 AutoCaller autoCaller(this);
425 AssertComRCReturnRC(autoCaller.rc());
426
427 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
428
429 // simply copy
430 *m->bd.data() = data;
431
432 return S_OK;
433}
434
435/**
436 * Saves settings to the given port node.
437 *
438 * Note that the given Port node is comletely empty on input.
439 *
440 * @param aPortNode <Port> node.
441 *
442 * @note Locks this object for reading.
443 */
444HRESULT ParallelPort::saveSettings(settings::ParallelPort &data)
445{
446 AutoCaller autoCaller(this);
447 AssertComRCReturnRC(autoCaller.rc());
448
449 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
450
451 // simply copy
452 data = *m->bd.data();
453
454 return S_OK;
455}
456
457/**
458 * Returns true if any setter method has modified settings of this instance.
459 * @return
460 */
461bool ParallelPort::isModified()
462{
463 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
464 return m->fModified;
465}
466
467/**
468 * @note Locks this object for writing.
469 */
470void ParallelPort::rollback()
471{
472 /* sanity */
473 AutoCaller autoCaller(this);
474 AssertComRCReturnVoid(autoCaller.rc());
475
476 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
477
478 m->bd.rollback();
479}
480
481/**
482 * @note Locks this object for writing, together with the peer object (also
483 * for writing) if there is one.
484 */
485void ParallelPort::commit()
486{
487 /* sanity */
488 AutoCaller autoCaller(this);
489 AssertComRCReturnVoid (autoCaller.rc());
490
491 /* sanity too */
492 AutoCaller peerCaller (m->pPeer);
493 AssertComRCReturnVoid (peerCaller.rc());
494
495 /* lock both for writing since we modify both (m->pPeer is "master" so locked
496 * first) */
497 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
498
499 if (m->bd.isBackedUp())
500 {
501 m->bd.commit();
502 if (m->pPeer)
503 {
504 /* attach new data to the peer and reshare it */
505 m->pPeer->m->bd.attach(m->bd);
506 }
507 }
508}
509
510/**
511 * @note Locks this object for writing, together with the peer object
512 * represented by @a aThat (locked for reading).
513 */
514void ParallelPort::copyFrom(ParallelPort *aThat)
515{
516 AssertReturnVoid (aThat != NULL);
517
518 /* sanity */
519 AutoCaller autoCaller(this);
520 AssertComRCReturnVoid (autoCaller.rc());
521
522 /* sanity too */
523 AutoCaller thatCaller (aThat);
524 AssertComRCReturnVoid (thatCaller.rc());
525
526 /* peer is not modified, lock it for reading (aThat is "master" so locked
527 * first) */
528 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
529 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
530
531 /* this will back up current data */
532 m->bd.assignCopy(aThat->m->bd);
533}
534
535/**
536 * Validates COMSETTER(Path) arguments.
537 */
538HRESULT ParallelPort::checkSetPath(const Utf8Str &str)
539{
540 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
541
542 if ( m->bd->fEnabled
543 && str.isEmpty()
544 )
545 return setError(E_INVALIDARG,
546 tr("Path of the parallel port %d may not be empty or null "
547 "when the port is enabled"),
548 m->bd->ulSlot);
549
550 return S_OK;
551}
552
553
554/* 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