VirtualBox

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

Last change on this file was 98262, checked in by vboxsync, 16 months ago

Main: rc() -> hrc()/vrc(). bugref:10223

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

© 2023 Oracle
ContactPrivacy policyTerms of Use