VirtualBox

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

Last change on this file since 17946 was 16560, checked in by vboxsync, 16 years ago

Main: do not include include/VBox/settings.h from other header files but only from implementations that need it (save compile time)

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