VirtualBox

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

Last change on this file since 49795 was 49795, checked in by vboxsync, 11 years ago

6813 - stage 3 rev 1

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