VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/SerialPortImpl.cpp@ 57415

Last change on this file since 57415 was 55401, checked in by vboxsync, 10 years ago

added a couple of missing Id headers

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