VirtualBox

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

Last change on this file since 28205 was 27607, checked in by vboxsync, 15 years ago

Main: remove templates for 'weak' com pointers which do nothing anyway

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