VirtualBox

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

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

SerialPortImpl: fixed regression from r91125.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 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 if (aPath != m->bd->strPath)
403 {
404 HRESULT rc = i_checkSetPath(aPath);
405 if (FAILED(rc)) return rc;
406
407 m->bd.backup();
408 m->bd->strPath = aPath;
409
410 m->fModified = true;
411 // leave the lock before informing callbacks
412 alock.release();
413
414 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
415 m->pMachine->setModified(Machine::IsModified_SerialPorts);
416 mlock.release();
417
418 m->pMachine->onSerialPortChange(this);
419 }
420
421 return S_OK;
422}
423
424HRESULT SerialPort::getServer(BOOL *aServer)
425{
426 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
427
428 *aServer = m->bd->fServer;
429
430 return S_OK;
431}
432
433HRESULT SerialPort::setServer(BOOL aServer)
434{
435 /* the machine needs to be mutable */
436 AutoMutableStateDependency adep(m->pMachine);
437 if (FAILED(adep.rc())) return adep.rc();
438
439 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
440
441 if (m->bd->fServer != !!aServer)
442 {
443 m->bd.backup();
444 m->bd->fServer = !!aServer;
445
446 m->fModified = true;
447 // leave the lock before informing callbacks
448 alock.release();
449
450 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
451 m->pMachine->setModified(Machine::IsModified_SerialPorts);
452 mlock.release();
453
454 m->pMachine->onSerialPortChange(this);
455 }
456
457 return S_OK;
458}
459
460// public methods only for internal purposes
461////////////////////////////////////////////////////////////////////////////////
462
463/**
464 * Loads settings from the given port node.
465 * May be called once right after this object creation.
466 *
467 * @param aPortNode <Port> node.
468 *
469 * @note Locks this object for writing.
470 */
471HRESULT SerialPort::i_loadSettings(const settings::SerialPort &data)
472{
473
474 AutoCaller autoCaller(this);
475 AssertComRCReturnRC(autoCaller.rc());
476
477 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
478
479 // simply copy
480 *m->bd.data() = data;
481
482 return S_OK;
483}
484
485/**
486 * Saves the port settings to the given port node.
487 *
488 * Note that the given Port node is completely empty on input.
489 *
490 * @param aPortNode <Port> node.
491 *
492 * @note Locks this object for reading.
493 */
494HRESULT SerialPort::i_saveSettings(settings::SerialPort &data)
495{
496 AutoCaller autoCaller(this);
497 AssertComRCReturnRC(autoCaller.rc());
498
499 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
500
501 // simply copy
502 data = *m->bd.data();
503
504 return S_OK;
505}
506
507/**
508 * Returns true if any setter method has modified settings of this instance.
509 * @return
510 */
511bool SerialPort::i_isModified()
512{
513 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
514 return m->fModified;
515}
516
517/**
518 * @note Locks this object for writing.
519 */
520void SerialPort::i_rollback()
521{
522 /* sanity */
523 AutoCaller autoCaller(this);
524 AssertComRCReturnVoid(autoCaller.rc());
525
526 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
527
528 m->bd.rollback();
529}
530
531/**
532 * @note Locks this object for writing, together with the peer object (also
533 * for writing) if there is one.
534 */
535void SerialPort::i_commit()
536{
537 /* sanity */
538 AutoCaller autoCaller(this);
539 AssertComRCReturnVoid (autoCaller.rc());
540
541 /* sanity too */
542 AutoCaller peerCaller(m->pPeer);
543 AssertComRCReturnVoid(peerCaller.rc());
544
545 /* lock both for writing since we modify both (pPeer is "master" so locked
546 * first) */
547 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
548
549 if (m->bd.isBackedUp())
550 {
551 m->bd.commit();
552 if (m->pPeer)
553 {
554 /* attach new data to the peer and reshare it */
555 m->pPeer->m->bd.attach(m->bd);
556 }
557 }
558}
559
560/**
561 * @note Locks this object for writing, together with the peer object
562 * represented by @a aThat (locked for reading).
563 */
564void SerialPort::i_copyFrom (SerialPort *aThat)
565{
566 AssertReturnVoid (aThat != NULL);
567
568 /* sanity */
569 AutoCaller autoCaller(this);
570 AssertComRCReturnVoid (autoCaller.rc());
571
572 /* sanity too */
573 AutoCaller thatCaller (aThat);
574 AssertComRCReturnVoid (thatCaller.rc());
575
576 /* peer is not modified, lock it for reading (aThat is "master" so locked
577 * first) */
578 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
579 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
580
581 /* this will back up current data */
582 m->bd.assignCopy (aThat->m->bd);
583}
584
585void SerialPort::i_applyDefaults (GuestOSType *aOsType)
586{
587 AssertReturnVoid (aOsType != NULL);
588
589 /* sanity */
590 AutoCaller autoCaller(this);
591 AssertComRCReturnVoid (autoCaller.rc());
592
593 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
594
595 /* Set some more defaults.
596 * Note that the default value for COM1 (slot 0) is set in the constructor
597 * of bd. So slot 0 is correct already. */
598 switch (m->bd->ulSlot)
599 {
600 case 1:
601 {
602 m->bd->ulIOBase = 0x2F8;
603 m->bd->ulIRQ = 3;
604 break;
605 }
606 case 2:
607 {
608 m->bd->ulIOBase = 0x3e8;
609 m->bd->ulIRQ = 4;
610 break;
611 }
612 case 3:
613 {
614 m->bd->ulIOBase = 0x2e8;
615 m->bd->ulIRQ = 3;
616 break;
617 }
618 default: break;
619 }
620
621 uint32_t numSerialEnabled = aOsType->i_numSerialEnabled();
622
623 /* Enable port if requested */
624 if (m->bd->ulSlot < numSerialEnabled)
625 {
626 m->bd->fEnabled = true;
627 }
628}
629
630/**
631 * Validates COMSETTER(Path) arguments.
632 */
633HRESULT SerialPort::i_checkSetPath(const Utf8Str &str)
634{
635 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
636
637 if ( ( m->bd->portMode == PortMode_HostDevice
638 || m->bd->portMode == PortMode_HostPipe
639 || m->bd->portMode == PortMode_RawFile
640 ) && str.isEmpty()
641 )
642 return setError(E_INVALIDARG,
643 tr("Path of the serial port %d may not be empty or null in "
644 "host pipe or host device mode"),
645 m->bd->ulSlot);
646
647 return S_OK;
648}
649
650/* 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