VirtualBox

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

Last change on this file since 90441 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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