VirtualBox

source: vbox/trunk/src/VBox/Main/SerialPortImpl.cpp@ 26173

Last change on this file since 26173 was 26171, checked in by vboxsync, 15 years ago

Main: get rid of Backupable<>::hasActualChanges and the operator== in all the machine data structures which it required; nuke obsolete Shareable.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.8 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "SerialPortImpl.h"
23#include "MachineImpl.h"
24#include "VirtualBoxImpl.h"
25#include "GuestOSTypeImpl.h"
26
27#include <iprt/string.h>
28#include <iprt/cpp/utils.h>
29
30#include <VBox/settings.h>
31
32#include "AutoStateDep.h"
33#include "AutoCaller.h"
34#include "Logging.h"
35
36////////////////////////////////////////////////////////////////////////////////
37//
38// SerialPort private data definition
39//
40////////////////////////////////////////////////////////////////////////////////
41
42struct SerialPort::Data
43{
44 Data()
45 : fModified(false)
46 { }
47
48 bool fModified;
49
50 const ComObjPtr<Machine, ComWeakRef> pMachine;
51 const ComObjPtr<SerialPort> pPeer;
52
53 Backupable<settings::SerialPort> bd;
54};
55
56// constructor / destructor
57/////////////////////////////////////////////////////////////////////////////
58
59DEFINE_EMPTY_CTOR_DTOR (SerialPort)
60
61HRESULT SerialPort::FinalConstruct()
62{
63 return S_OK;
64}
65
66void SerialPort::FinalRelease()
67{
68 uninit();
69}
70
71// public initializer/uninitializer for internal purposes only
72/////////////////////////////////////////////////////////////////////////////
73
74/**
75 * Initializes the Serial Port object.
76 *
77 * @param aParent Handle of the parent object.
78 */
79HRESULT SerialPort::init(Machine *aParent, ULONG aSlot)
80{
81 LogFlowThisFunc(("aParent=%p, aSlot=%d\n", aParent, aSlot));
82
83 ComAssertRet (aParent, E_INVALIDARG);
84
85 /* Enclose the state transition NotReady->InInit->Ready */
86 AutoInitSpan autoInitSpan(this);
87 AssertReturn(autoInitSpan.isOk(), E_FAIL);
88
89 m = new Data();
90
91 unconst(m->pMachine) = aParent;
92 /* m->pPeer is left null */
93
94 m->bd.allocate();
95
96 /* initialize data */
97 m->bd->ulSlot = aSlot;
98
99 /* Confirm a successful initialization */
100 autoInitSpan.setSucceeded();
101
102 return S_OK;
103}
104
105/**
106 * Initializes the Serial Port object given another serial port object
107 * (a kind of copy constructor). This object shares data with
108 * the object passed as an argument.
109 *
110 * @note This object must be destroyed before the original object
111 * it shares data with is destroyed.
112 *
113 * @note Locks @a aThat object for reading.
114 */
115HRESULT SerialPort::init(Machine *aParent, SerialPort *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_FAIL);
124
125 m = new Data();
126
127 unconst(m->pMachine) = aParent;
128 unconst(m->pPeer) = aThat;
129
130 AutoCaller thatCaller (aThat);
131 AssertComRCReturnRC(thatCaller.rc());
132
133 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
134 m->bd.share (aThat->m->bd);
135
136 /* Confirm a successful initialization */
137 autoInitSpan.setSucceeded();
138
139 return S_OK;
140}
141
142/**
143 * Initializes the guest object given another guest object
144 * (a kind of copy constructor). This object makes a private copy of data
145 * of the original object passed as an argument.
146 *
147 * @note Locks @a aThat object for reading.
148 */
149HRESULT SerialPort::initCopy(Machine *aParent, SerialPort *aThat)
150{
151 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
152
153 ComAssertRet (aParent && aThat, E_INVALIDARG);
154
155 /* Enclose the state transition NotReady->InInit->Ready */
156 AutoInitSpan autoInitSpan(this);
157 AssertReturn(autoInitSpan.isOk(), E_FAIL);
158
159 m = new Data();
160
161 unconst(m->pMachine) = aParent;
162 /* pPeer is left null */
163
164 AutoCaller thatCaller (aThat);
165 AssertComRCReturnRC(thatCaller.rc());
166
167 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
168 m->bd.attachCopy (aThat->m->bd);
169
170 /* Confirm a successful initialization */
171 autoInitSpan.setSucceeded();
172
173 return S_OK;
174}
175
176/**
177 * Uninitializes the instance and sets the ready flag to FALSE.
178 * Called either from FinalRelease() or by the parent when it gets destroyed.
179 */
180void SerialPort::uninit()
181{
182 LogFlowThisFunc(("\n"));
183
184 /* Enclose the state transition Ready->InUninit->NotReady */
185 AutoUninitSpan autoUninitSpan(this);
186 if (autoUninitSpan.uninitDone())
187 return;
188
189 m->bd.free();
190
191 unconst(m->pPeer).setNull();
192 unconst(m->pMachine).setNull();
193
194 delete m;
195 m = NULL;
196}
197
198// ISerialPort properties
199/////////////////////////////////////////////////////////////////////////////
200
201STDMETHODIMP SerialPort::COMGETTER(Enabled) (BOOL *aEnabled)
202{
203 CheckComArgOutPointerValid(aEnabled);
204
205 AutoCaller autoCaller(this);
206 if (FAILED(autoCaller.rc())) return autoCaller.rc();
207
208 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
209
210 *aEnabled = m->bd->fEnabled;
211
212 return S_OK;
213}
214
215STDMETHODIMP SerialPort::COMSETTER(Enabled) (BOOL aEnabled)
216{
217 LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled));
218
219 AutoCaller autoCaller(this);
220 if (FAILED(autoCaller.rc())) return autoCaller.rc();
221
222 /* the machine needs to be mutable */
223 AutoMutableStateDependency adep(m->pMachine);
224 if (FAILED(adep.rc())) return adep.rc();
225
226 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
227
228 if (m->bd->fEnabled != aEnabled)
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_SerialPorts);
239 mlock.release();
240
241 m->pMachine->onSerialPortChange(this);
242 }
243
244 return S_OK;
245}
246
247STDMETHODIMP SerialPort::COMGETTER(HostMode) (PortMode_T *aHostMode)
248{
249 CheckComArgOutPointerValid(aHostMode);
250
251 AutoCaller autoCaller(this);
252 if (FAILED(autoCaller.rc())) return autoCaller.rc();
253
254 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
255
256 *aHostMode = m->bd->portMode;
257
258 return S_OK;
259}
260
261STDMETHODIMP SerialPort::COMSETTER(HostMode) (PortMode_T aHostMode)
262{
263 AutoCaller autoCaller(this);
264 if (FAILED(autoCaller.rc())) return autoCaller.rc();
265
266 /* the machine needs to be mutable */
267 AutoMutableStateDependency adep(m->pMachine);
268 if (FAILED(adep.rc())) return adep.rc();
269
270 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
271
272 if (m->bd->portMode != aHostMode)
273 {
274 switch (aHostMode)
275 {
276 case PortMode_RawFile:
277 if (m->bd->strPath.isEmpty())
278 return setError(E_INVALIDARG,
279 tr("Cannot set the raw file mode of the serial port %d "
280 "because the file path is empty or null"),
281 m->bd->ulSlot);
282 break;
283 case PortMode_HostPipe:
284 if (m->bd->strPath.isEmpty())
285 return setError(E_INVALIDARG,
286 tr("Cannot set the host pipe mode of the serial port %d "
287 "because the pipe path is empty or null"),
288 m->bd->ulSlot);
289 break;
290 case PortMode_HostDevice:
291 if (m->bd->strPath.isEmpty())
292 return setError(E_INVALIDARG,
293 tr("Cannot set the host device mode of the serial port %d "
294 "because the device path is empty or null"),
295 m->bd->ulSlot);
296 break;
297 case PortMode_Disconnected:
298 break;
299 }
300
301 m->bd.backup();
302 m->bd->portMode = aHostMode;
303
304 m->fModified = true;
305 // leave the lock before informing callbacks
306 alock.release();
307
308 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
309 m->pMachine->setModified(Machine::IsModified_SerialPorts);
310 mlock.release();
311
312 m->pMachine->onSerialPortChange(this);
313 }
314
315 return S_OK;
316}
317
318STDMETHODIMP SerialPort::COMGETTER(Slot) (ULONG *aSlot)
319{
320 CheckComArgOutPointerValid(aSlot);
321
322 AutoCaller autoCaller(this);
323 if (FAILED(autoCaller.rc())) return autoCaller.rc();
324
325 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
326
327 *aSlot = m->bd->ulSlot;
328
329 return S_OK;
330}
331
332STDMETHODIMP SerialPort::COMGETTER(IRQ) (ULONG *aIRQ)
333{
334 CheckComArgOutPointerValid(aIRQ);
335
336 AutoCaller autoCaller(this);
337 if (FAILED(autoCaller.rc())) return autoCaller.rc();
338
339 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
340
341 *aIRQ = m->bd->ulIRQ;
342
343 return S_OK;
344}
345
346STDMETHODIMP SerialPort::COMSETTER(IRQ)(ULONG aIRQ)
347{
348 /* check IRQ limits
349 * (when changing this, make sure it corresponds to XML schema */
350 if (aIRQ > 255)
351 return setError (E_INVALIDARG,
352 tr ("Invalid IRQ number of the serial port %d: "
353 "%lu (must be in range [0, %lu])"),
354 m->bd->ulSlot, aIRQ, 255);
355
356 AutoCaller autoCaller(this);
357 if (FAILED(autoCaller.rc())) return autoCaller.rc();
358
359 /* the machine needs to be mutable */
360 AutoMutableStateDependency adep(m->pMachine);
361 if (FAILED(adep.rc())) return adep.rc();
362
363 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
364
365 if (m->bd->ulIRQ != aIRQ)
366 {
367 m->bd.backup();
368 m->bd->ulIRQ = aIRQ;
369
370 m->fModified = true;
371 // leave the lock before informing callbacks
372 alock.release();
373
374 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
375 m->pMachine->setModified(Machine::IsModified_SerialPorts);
376 mlock.release();
377
378 m->pMachine->onSerialPortChange(this);
379 }
380
381 return S_OK;
382}
383
384STDMETHODIMP SerialPort::COMGETTER(IOBase) (ULONG *aIOBase)
385{
386 CheckComArgOutPointerValid(aIOBase);
387
388 AutoCaller autoCaller(this);
389 if (FAILED(autoCaller.rc())) return autoCaller.rc();
390
391 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
392
393 *aIOBase = m->bd->ulIOBase;
394
395 return S_OK;
396}
397
398STDMETHODIMP SerialPort::COMSETTER(IOBase)(ULONG aIOBase)
399{
400 /* check IOBase limits
401 * (when changing this, make sure it corresponds to XML schema */
402 if (aIOBase > 0xFFFF)
403 return setError (E_INVALIDARG,
404 tr ("Invalid I/O port base address of the serial port %d: "
405 "%lu (must be in range [0, 0x%X])"),
406 m->bd->ulSlot, aIOBase, 0, 0xFFFF);
407
408 AutoCaller autoCaller(this);
409 if (FAILED(autoCaller.rc())) return autoCaller.rc();
410
411 /* the machine needs to be mutable */
412 AutoMutableStateDependency adep(m->pMachine);
413 if (FAILED(adep.rc())) return adep.rc();
414
415 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
416
417 HRESULT rc = S_OK;
418
419 if (m->bd->ulIOBase != aIOBase)
420 {
421 m->bd.backup();
422 m->bd->ulIOBase = aIOBase;
423
424 m->fModified = true;
425 // leave the lock before informing callbacks
426 alock.release();
427
428 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
429 m->pMachine->setModified(Machine::IsModified_SerialPorts);
430 mlock.release();
431
432 m->pMachine->onSerialPortChange(this);
433 }
434
435 return rc;
436}
437
438STDMETHODIMP SerialPort::COMGETTER(Path) (BSTR *aPath)
439{
440 CheckComArgOutPointerValid(aPath);
441
442 AutoCaller autoCaller(this);
443 if (FAILED(autoCaller.rc())) return autoCaller.rc();
444
445 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
446
447 m->bd->strPath.cloneTo(aPath);
448
449 return S_OK;
450}
451
452STDMETHODIMP SerialPort::COMSETTER(Path) (IN_BSTR aPath)
453{
454 AutoCaller autoCaller(this);
455 if (FAILED(autoCaller.rc())) return autoCaller.rc();
456
457 /* the machine needs to be mutable */
458 AutoMutableStateDependency adep(m->pMachine);
459 if (FAILED(adep.rc())) return adep.rc();
460
461 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
462
463 /* we treat empty as null when e.g. saving to XML, do the same here */
464 if (aPath && *aPath == '\0')
465 aPath = NULL;
466
467 Utf8Str str(aPath);
468 if (str != m->bd->strPath)
469 {
470 HRESULT rc = checkSetPath(str);
471 if (FAILED(rc)) return rc;
472
473 m->bd.backup();
474 m->bd->strPath = str;
475
476 m->fModified = true;
477 // leave the lock before informing callbacks
478 alock.release();
479
480 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
481 m->pMachine->setModified(Machine::IsModified_SerialPorts);
482 mlock.release();
483
484 m->pMachine->onSerialPortChange(this);
485 }
486
487 return S_OK;
488}
489
490STDMETHODIMP SerialPort::COMGETTER(Server) (BOOL *aServer)
491{
492 CheckComArgOutPointerValid(aServer);
493
494 AutoCaller autoCaller(this);
495 if (FAILED(autoCaller.rc())) return autoCaller.rc();
496
497 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
498
499 *aServer = m->bd->fServer;
500
501 return S_OK;
502}
503
504STDMETHODIMP SerialPort::COMSETTER(Server) (BOOL aServer)
505{
506 AutoCaller autoCaller(this);
507 if (FAILED(autoCaller.rc())) return autoCaller.rc();
508
509 /* the machine needs to be mutable */
510 AutoMutableStateDependency adep(m->pMachine);
511 if (FAILED(adep.rc())) return adep.rc();
512
513 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
514
515 if (m->bd->fServer != aServer)
516 {
517 m->bd.backup();
518 m->bd->fServer = aServer;
519
520 m->fModified = true;
521 // leave the lock before informing callbacks
522 alock.release();
523
524 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
525 m->pMachine->setModified(Machine::IsModified_SerialPorts);
526 mlock.release();
527
528 m->pMachine->onSerialPortChange(this);
529 }
530
531 return S_OK;
532}
533
534// public methods only for internal purposes
535////////////////////////////////////////////////////////////////////////////////
536
537/**
538 * Loads settings from the given port node.
539 * May be called once right after this object creation.
540 *
541 * @param aPortNode <Port> node.
542 *
543 * @note Locks this object for writing.
544 */
545HRESULT SerialPort::loadSettings(const settings::SerialPort &data)
546{
547 AutoCaller autoCaller(this);
548 AssertComRCReturnRC(autoCaller.rc());
549
550 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
551
552 // simply copy
553 *m->bd.data() = data;
554
555 return S_OK;
556}
557
558/**
559 * Saves the port settings to the given port node.
560 *
561 * Note that the given Port node is comletely empty on input.
562 *
563 * @param aPortNode <Port> node.
564 *
565 * @note Locks this object for reading.
566 */
567HRESULT SerialPort::saveSettings(settings::SerialPort &data)
568{
569 AutoCaller autoCaller(this);
570 AssertComRCReturnRC(autoCaller.rc());
571
572 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
573
574 // simply copy
575 data = *m->bd.data();
576
577 return S_OK;
578}
579
580/**
581 * Returns true if any setter method has modified settings of this instance.
582 * @return
583 */
584bool SerialPort::isModified()
585{
586 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
587 return m->fModified;
588}
589
590/**
591 * @note Locks this object for writing.
592 */
593void SerialPort::rollback()
594{
595 /* sanity */
596 AutoCaller autoCaller(this);
597 AssertComRCReturnVoid(autoCaller.rc());
598
599 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
600
601 m->bd.rollback();
602}
603
604/**
605 * @note Locks this object for writing, together with the peer object (also
606 * for writing) if there is one.
607 */
608void SerialPort::commit()
609{
610 /* sanity */
611 AutoCaller autoCaller(this);
612 AssertComRCReturnVoid (autoCaller.rc());
613
614 /* sanity too */
615 AutoCaller peerCaller(m->pPeer);
616 AssertComRCReturnVoid(peerCaller.rc());
617
618 /* lock both for writing since we modify both (pPeer is "master" so locked
619 * first) */
620 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
621
622 if (m->bd.isBackedUp())
623 {
624 m->bd.commit();
625 if (m->pPeer)
626 {
627 /* attach new data to the peer and reshare it */
628 m->pPeer->m->bd.attach(m->bd);
629 }
630 }
631}
632
633/**
634 * @note Locks this object for writing, together with the peer object
635 * represented by @a aThat (locked for reading).
636 */
637void SerialPort::copyFrom (SerialPort *aThat)
638{
639 AssertReturnVoid (aThat != NULL);
640
641 /* sanity */
642 AutoCaller autoCaller(this);
643 AssertComRCReturnVoid (autoCaller.rc());
644
645 /* sanity too */
646 AutoCaller thatCaller (aThat);
647 AssertComRCReturnVoid (thatCaller.rc());
648
649 /* peer is not modified, lock it for reading (aThat is "master" so locked
650 * first) */
651 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
652 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
653
654 /* this will back up current data */
655 m->bd.assignCopy (aThat->m->bd);
656}
657
658void SerialPort::applyDefaults (GuestOSType *aOsType)
659{
660 AssertReturnVoid (aOsType != NULL);
661
662 /* sanity */
663 AutoCaller autoCaller(this);
664 AssertComRCReturnVoid (autoCaller.rc());
665
666 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
667
668 uint32_t numSerialEnabled = aOsType->numSerialEnabled();
669
670 /* Enable port if requested */
671 if (m->bd->ulSlot < numSerialEnabled)
672 {
673 m->bd->fEnabled = true;
674 }
675}
676
677/**
678 * Validates COMSETTER(Path) arguments.
679 */
680HRESULT SerialPort::checkSetPath(const Utf8Str &str)
681{
682 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
683
684 if ( ( m->bd->portMode == PortMode_HostDevice
685 || m->bd->portMode == PortMode_HostPipe
686 || m->bd->portMode == PortMode_RawFile
687 ) && str.isEmpty()
688 )
689 return setError(E_INVALIDARG,
690 tr("Path of the serial port %d may not be empty or null in "
691 "host pipe or host device mode"),
692 m->bd->ulSlot);
693
694 return S_OK;
695}
696
697/* 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