VirtualBox

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

Last change on this file since 27166 was 27059, checked in by vboxsync, 15 years ago

Main: windows warnings

  • 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: %lu (must be in range [0, %lu])"),
353 m->bd->ulSlot, aIRQ, 255);
354
355 AutoCaller autoCaller(this);
356 if (FAILED(autoCaller.rc())) return autoCaller.rc();
357
358 /* the machine needs to be mutable */
359 AutoMutableStateDependency adep(m->pMachine);
360 if (FAILED(adep.rc())) return adep.rc();
361
362 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
363
364 if (m->bd->ulIRQ != aIRQ)
365 {
366 m->bd.backup();
367 m->bd->ulIRQ = aIRQ;
368
369 m->fModified = true;
370 // leave the lock before informing callbacks
371 alock.release();
372
373 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
374 m->pMachine->setModified(Machine::IsModified_SerialPorts);
375 mlock.release();
376
377 m->pMachine->onSerialPortChange(this);
378 }
379
380 return S_OK;
381}
382
383STDMETHODIMP SerialPort::COMGETTER(IOBase) (ULONG *aIOBase)
384{
385 CheckComArgOutPointerValid(aIOBase);
386
387 AutoCaller autoCaller(this);
388 if (FAILED(autoCaller.rc())) return autoCaller.rc();
389
390 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
391
392 *aIOBase = m->bd->ulIOBase;
393
394 return S_OK;
395}
396
397STDMETHODIMP SerialPort::COMSETTER(IOBase)(ULONG aIOBase)
398{
399 /* check IOBase limits
400 * (when changing this, make sure it corresponds to XML schema */
401 if (aIOBase > 0xFFFF)
402 return setError(E_INVALIDARG,
403 tr("Invalid I/O port base address of the serial port %d: %lu (must be in range [0, 0x%X])"),
404 m->bd->ulSlot, aIOBase, 0, 0xFFFF);
405
406 AutoCaller autoCaller(this);
407 if (FAILED(autoCaller.rc())) return autoCaller.rc();
408
409 /* the machine needs to be mutable */
410 AutoMutableStateDependency adep(m->pMachine);
411 if (FAILED(adep.rc())) return adep.rc();
412
413 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
414
415 HRESULT rc = S_OK;
416
417 if (m->bd->ulIOBase != aIOBase)
418 {
419 m->bd.backup();
420 m->bd->ulIOBase = aIOBase;
421
422 m->fModified = true;
423 // leave the lock before informing callbacks
424 alock.release();
425
426 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
427 m->pMachine->setModified(Machine::IsModified_SerialPorts);
428 mlock.release();
429
430 m->pMachine->onSerialPortChange(this);
431 }
432
433 return rc;
434}
435
436STDMETHODIMP SerialPort::COMGETTER(Path) (BSTR *aPath)
437{
438 CheckComArgOutPointerValid(aPath);
439
440 AutoCaller autoCaller(this);
441 if (FAILED(autoCaller.rc())) return autoCaller.rc();
442
443 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
444
445 m->bd->strPath.cloneTo(aPath);
446
447 return S_OK;
448}
449
450STDMETHODIMP SerialPort::COMSETTER(Path) (IN_BSTR aPath)
451{
452 AutoCaller autoCaller(this);
453 if (FAILED(autoCaller.rc())) return autoCaller.rc();
454
455 /* the machine needs to be mutable */
456 AutoMutableStateDependency adep(m->pMachine);
457 if (FAILED(adep.rc())) return adep.rc();
458
459 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
460
461 /* we treat empty as null when e.g. saving to XML, do the same here */
462 if (aPath && *aPath == '\0')
463 aPath = NULL;
464
465 Utf8Str str(aPath);
466 if (str != m->bd->strPath)
467 {
468 HRESULT rc = checkSetPath(str);
469 if (FAILED(rc)) return rc;
470
471 m->bd.backup();
472 m->bd->strPath = str;
473
474 m->fModified = true;
475 // leave the lock before informing callbacks
476 alock.release();
477
478 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
479 m->pMachine->setModified(Machine::IsModified_SerialPorts);
480 mlock.release();
481
482 m->pMachine->onSerialPortChange(this);
483 }
484
485 return S_OK;
486}
487
488STDMETHODIMP SerialPort::COMGETTER(Server) (BOOL *aServer)
489{
490 CheckComArgOutPointerValid(aServer);
491
492 AutoCaller autoCaller(this);
493 if (FAILED(autoCaller.rc())) return autoCaller.rc();
494
495 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
496
497 *aServer = m->bd->fServer;
498
499 return S_OK;
500}
501
502STDMETHODIMP SerialPort::COMSETTER(Server) (BOOL aServer)
503{
504 AutoCaller autoCaller(this);
505 if (FAILED(autoCaller.rc())) return autoCaller.rc();
506
507 /* the machine needs to be mutable */
508 AutoMutableStateDependency adep(m->pMachine);
509 if (FAILED(adep.rc())) return adep.rc();
510
511 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
512
513 if (m->bd->fServer != !!aServer)
514 {
515 m->bd.backup();
516 m->bd->fServer = !!aServer;
517
518 m->fModified = true;
519 // leave the lock before informing callbacks
520 alock.release();
521
522 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
523 m->pMachine->setModified(Machine::IsModified_SerialPorts);
524 mlock.release();
525
526 m->pMachine->onSerialPortChange(this);
527 }
528
529 return S_OK;
530}
531
532// public methods only for internal purposes
533////////////////////////////////////////////////////////////////////////////////
534
535/**
536 * Loads settings from the given port node.
537 * May be called once right after this object creation.
538 *
539 * @param aPortNode <Port> node.
540 *
541 * @note Locks this object for writing.
542 */
543HRESULT SerialPort::loadSettings(const settings::SerialPort &data)
544{
545 AutoCaller autoCaller(this);
546 AssertComRCReturnRC(autoCaller.rc());
547
548 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
549
550 // simply copy
551 *m->bd.data() = data;
552
553 return S_OK;
554}
555
556/**
557 * Saves the port settings to the given port node.
558 *
559 * Note that the given Port node is comletely empty on input.
560 *
561 * @param aPortNode <Port> node.
562 *
563 * @note Locks this object for reading.
564 */
565HRESULT SerialPort::saveSettings(settings::SerialPort &data)
566{
567 AutoCaller autoCaller(this);
568 AssertComRCReturnRC(autoCaller.rc());
569
570 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
571
572 // simply copy
573 data = *m->bd.data();
574
575 return S_OK;
576}
577
578/**
579 * Returns true if any setter method has modified settings of this instance.
580 * @return
581 */
582bool SerialPort::isModified()
583{
584 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
585 return m->fModified;
586}
587
588/**
589 * @note Locks this object for writing.
590 */
591void SerialPort::rollback()
592{
593 /* sanity */
594 AutoCaller autoCaller(this);
595 AssertComRCReturnVoid(autoCaller.rc());
596
597 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
598
599 m->bd.rollback();
600}
601
602/**
603 * @note Locks this object for writing, together with the peer object (also
604 * for writing) if there is one.
605 */
606void SerialPort::commit()
607{
608 /* sanity */
609 AutoCaller autoCaller(this);
610 AssertComRCReturnVoid (autoCaller.rc());
611
612 /* sanity too */
613 AutoCaller peerCaller(m->pPeer);
614 AssertComRCReturnVoid(peerCaller.rc());
615
616 /* lock both for writing since we modify both (pPeer is "master" so locked
617 * first) */
618 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
619
620 if (m->bd.isBackedUp())
621 {
622 m->bd.commit();
623 if (m->pPeer)
624 {
625 /* attach new data to the peer and reshare it */
626 m->pPeer->m->bd.attach(m->bd);
627 }
628 }
629}
630
631/**
632 * @note Locks this object for writing, together with the peer object
633 * represented by @a aThat (locked for reading).
634 */
635void SerialPort::copyFrom (SerialPort *aThat)
636{
637 AssertReturnVoid (aThat != NULL);
638
639 /* sanity */
640 AutoCaller autoCaller(this);
641 AssertComRCReturnVoid (autoCaller.rc());
642
643 /* sanity too */
644 AutoCaller thatCaller (aThat);
645 AssertComRCReturnVoid (thatCaller.rc());
646
647 /* peer is not modified, lock it for reading (aThat is "master" so locked
648 * first) */
649 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
650 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
651
652 /* this will back up current data */
653 m->bd.assignCopy (aThat->m->bd);
654}
655
656void SerialPort::applyDefaults (GuestOSType *aOsType)
657{
658 AssertReturnVoid (aOsType != NULL);
659
660 /* sanity */
661 AutoCaller autoCaller(this);
662 AssertComRCReturnVoid (autoCaller.rc());
663
664 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
665
666 uint32_t numSerialEnabled = aOsType->numSerialEnabled();
667
668 /* Enable port if requested */
669 if (m->bd->ulSlot < numSerialEnabled)
670 {
671 m->bd->fEnabled = true;
672 }
673}
674
675/**
676 * Validates COMSETTER(Path) arguments.
677 */
678HRESULT SerialPort::checkSetPath(const Utf8Str &str)
679{
680 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
681
682 if ( ( m->bd->portMode == PortMode_HostDevice
683 || m->bd->portMode == PortMode_HostPipe
684 || m->bd->portMode == PortMode_RawFile
685 ) && str.isEmpty()
686 )
687 return setError(E_INVALIDARG,
688 tr("Path of the serial port %d may not be empty or null in "
689 "host pipe or host device mode"),
690 m->bd->ulSlot);
691
692 return S_OK;
693}
694
695/* 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