VirtualBox

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

Last change on this file since 54971 was 54971, checked in by vboxsync, 10 years ago

Main/AudioAdapter+BandwidthControl+Machine+NetworkAdapter+ParallelPort+SerialPort+StorageController+USBDeviceFilter+USBDeviceFilters: Adjust rules when settings can be changed to allow as much as possible. Some changes restored the old rules (a previous change made the definition more restrictive), but many now allow changing settings when VM is saved or even at runtime when it is safe. Will resolve many complaints, especially when the GUI also is adapted accordingly.

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