VirtualBox

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

Last change on this file since 5935 was 5806, checked in by vboxsync, 17 years ago

Main: Fixed: Always save values of unused attributes of serial ports to preserve user's settings for later use.

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