VirtualBox

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

Last change on this file since 4284 was 4277, checked in by vboxsync, 17 years ago

don't save path/server in disconnected mode

File size: 14.6 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * 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 "Logging.h"
22
23#include <iprt/string.h>
24#include <iprt/cpputils.h>
25
26// constructor / destructor
27/////////////////////////////////////////////////////////////////////////////
28
29DEFINE_EMPTY_CTOR_DTOR (SerialPort)
30
31HRESULT SerialPort::FinalConstruct()
32{
33 return S_OK;
34}
35
36void SerialPort::FinalRelease()
37{
38 uninit();
39}
40
41// public initializer/uninitializer for internal purposes only
42/////////////////////////////////////////////////////////////////////////////
43
44/**
45 * Initializes the Serial Port object.
46 *
47 * @param aParent Handle of the parent object.
48 */
49HRESULT SerialPort::init (Machine *aParent, ULONG aSlot)
50{
51 LogFlowThisFunc (("aParent=%p, aSlot=%d\n", aParent, aSlot));
52
53 ComAssertRet (aParent, E_INVALIDARG);
54
55 /* Enclose the state transition NotReady->InInit->Ready */
56 AutoInitSpan autoInitSpan (this);
57 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
58
59 unconst (mParent) = aParent;
60 /* mPeer is left null */
61
62 mData.allocate();
63
64 /* initialize data */
65 mData->mSlot = aSlot;
66
67 /* Confirm a successful initialization */
68 autoInitSpan.setSucceeded();
69
70 return S_OK;
71}
72
73/**
74 * Initializes the Serial Port object given another serial port object
75 * (a kind of copy constructor). This object shares data with
76 * the object passed as an argument.
77 *
78 * @note This object must be destroyed before the original object
79 * it shares data with is destroyed.
80 *
81 * @note Locks @a aThat object for reading.
82 */
83HRESULT SerialPort::init (Machine *aParent, SerialPort *aThat)
84{
85 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
86
87 ComAssertRet (aParent && aThat, E_INVALIDARG);
88
89 /* Enclose the state transition NotReady->InInit->Ready */
90 AutoInitSpan autoInitSpan (this);
91 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
92
93 unconst (mParent) = aParent;
94 unconst (mPeer) = aThat;
95
96 AutoCaller thatCaller (aThat);
97 AssertComRCReturnRC (thatCaller.rc());
98
99 AutoReaderLock thatLock (aThat);
100 mData.share (aThat->mData);
101
102 /* Confirm a successful initialization */
103 autoInitSpan.setSucceeded();
104
105 return S_OK;
106}
107
108/**
109 * Initializes the guest object given another guest object
110 * (a kind of copy constructor). This object makes a private copy of data
111 * of the original object passed as an argument.
112 *
113 * @note Locks @a aThat object for reading.
114 */
115HRESULT SerialPort::initCopy (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_UNEXPECTED);
124
125 unconst (mParent) = aParent;
126 /* mPeer is left null */
127
128 AutoCaller thatCaller (aThat);
129 AssertComRCReturnRC (thatCaller.rc());
130
131 AutoReaderLock thatLock (aThat);
132 mData.attachCopy (aThat->mData);
133
134 /* Confirm a successful initialization */
135 autoInitSpan.setSucceeded();
136
137 return S_OK;
138}
139
140/**
141 * Uninitializes the instance and sets the ready flag to FALSE.
142 * Called either from FinalRelease() or by the parent when it gets destroyed.
143 */
144void SerialPort::uninit()
145{
146 LogFlowThisFunc (("\n"));
147
148 /* Enclose the state transition Ready->InUninit->NotReady */
149 AutoUninitSpan autoUninitSpan (this);
150 if (autoUninitSpan.uninitDone())
151 return;
152
153 mData.free();
154
155 unconst (mPeer).setNull();
156 unconst (mParent).setNull();
157}
158
159// public methods only for internal purposes
160////////////////////////////////////////////////////////////////////////////////
161
162/**
163 * @note Locks this object for writing.
164 */
165bool SerialPort::rollback()
166{
167 /* sanity */
168 AutoCaller autoCaller (this);
169 AssertComRCReturn (autoCaller.rc(), false);
170
171 AutoLock alock (this);
172
173 bool changed = false;
174
175 if (mData.isBackedUp())
176 {
177 /* we need to check all data to see whether anything will be changed
178 * after rollback */
179 changed = mData.hasActualChanges();
180 mData.rollback();
181 }
182
183 return changed;
184}
185
186/**
187 * @note Locks this object for writing, together with the peer object (also
188 * for writing) if there is one.
189 */
190void SerialPort::commit()
191{
192 /* sanity */
193 AutoCaller autoCaller (this);
194 AssertComRCReturnVoid (autoCaller.rc());
195
196 /* sanity too */
197 AutoCaller thatCaller (mPeer);
198 AssertComRCReturnVoid (thatCaller.rc());
199
200 /* lock both for writing since we modify both */
201 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer));
202
203 if (mData.isBackedUp())
204 {
205 mData.commit();
206 if (mPeer)
207 {
208 /* attach new data to the peer and reshare it */
209 mPeer->mData.attach (mData);
210 }
211 }
212}
213
214/**
215 * @note Locks this object for writing, together with the peer object
216 * represented by @a aThat (locked for reading).
217 */
218void SerialPort::copyFrom (SerialPort *aThat)
219{
220 AssertReturnVoid (aThat != NULL);
221
222 /* sanity */
223 AutoCaller autoCaller (this);
224 AssertComRCReturnVoid (autoCaller.rc());
225
226 /* sanity too */
227 AutoCaller thatCaller (mPeer);
228 AssertComRCReturnVoid (thatCaller.rc());
229
230 /* peer is not modified, lock it for reading */
231 AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
232
233 /* this will back up current data */
234 mData.assignCopy (aThat->mData);
235}
236
237HRESULT SerialPort::loadSettings (CFGNODE aNode, ULONG aSlot)
238{
239 LogFlowThisFunc (("aMachine=%p\n", aNode));
240
241 AssertReturn (aNode, E_FAIL);
242
243 AutoCaller autoCaller (this);
244 AssertComRCReturnRC (autoCaller.rc());
245
246 AutoLock alock (this);
247
248 CFGNODE portNode = NULL;
249 CFGLDRGetChildNode (aNode, "Port", aSlot, &portNode);
250
251 /* slot number (required) */
252 /* slot unicity is guaranteed by XML Schema */
253 uint32_t uSlot = 0;
254 CFGLDRQueryUInt32 (portNode, "slot", &uSlot);
255 /* enabled (required) */
256 bool fEnabled = false;
257 CFGLDRQueryBool (portNode, "enabled", &fEnabled);
258 Bstr mode;
259 uint32_t uIOBase;
260 /* I/O base (required) */
261 CFGLDRQueryUInt32 (portNode, "IOBase", &uIOBase);
262 /* IRQ (required) */
263 uint32_t uIRQ;
264 CFGLDRQueryUInt32 (portNode, "IRQ", &uIRQ);
265 /* host mode (required) */
266 CFGLDRQueryBSTR (portNode, "HostMode", mode.asOutParam());
267 if (mode == L"HostPipe")
268 mData->mHostMode = SerialHostMode_HostPipe;
269 else if (mode == L"HostDevice")
270 mData->mHostMode = SerialHostMode_HostDevice;
271 else
272 mData->mHostMode = SerialHostMode_Disconnected;
273 /* name of the pipe (required) */
274 Bstr path;
275 int rc = CFGLDRQueryBSTR(portNode, "path", path.asOutParam());
276 /* backward compatibility */
277 if (rc == VERR_CFG_NO_VALUE)
278 CFGLDRQueryBSTR(portNode, "pipe", path.asOutParam());
279 bool fServer = true;
280 CFGLDRQueryBool (portNode, "server", &fServer);
281
282 mData->mEnabled = fEnabled;
283 mData->mSlot = uSlot;
284 mData->mIOBase = uIOBase;
285 mData->mIRQ = uIRQ;
286 mData->mPath = path;
287 mData->mServer = fServer;
288
289 return S_OK;
290}
291
292HRESULT SerialPort::saveSettings (CFGNODE aNode)
293{
294 AssertReturn (aNode, E_FAIL);
295
296 AutoCaller autoCaller (this);
297 CheckComRCReturnRC (autoCaller.rc());
298
299 AutoReaderLock alock (this);
300
301 CFGNODE portNode = 0;
302 int vrc = CFGLDRAppendChildNode (aNode, "Port", &portNode);
303 ComAssertRCRet (vrc, E_FAIL);
304
305 const char *mode;
306 switch (mData->mHostMode)
307 {
308 default:
309 case SerialHostMode_Disconnected:
310 mode = "Disconnected";
311 break;
312 case SerialHostMode_HostPipe:
313 mode = "HostPipe";
314 break;
315 case SerialHostMode_HostDevice:
316 mode = "HostDevice";
317 break;
318 }
319 CFGLDRSetUInt32 (portNode, "slot", mData->mSlot);
320 CFGLDRSetBool (portNode, "enabled", !!mData->mEnabled);
321 if (mData->mEnabled)
322 {
323 CFGLDRSetUInt32 (portNode, "IOBase", mData->mIOBase);
324 CFGLDRSetUInt32 (portNode, "IRQ", mData->mIRQ);
325 CFGLDRSetString (portNode, "HostMode", mode);
326 if (mData->mHostMode != SerialHostMode_Disconnected)
327 {
328 CFGLDRSetBSTR (portNode, "path", mData->mPath);
329 if (mData->mHostMode == SerialHostMode_HostPipe)
330 CFGLDRSetBool (portNode, "server", !!mData->mServer);
331 }
332 }
333
334 return S_OK;
335}
336
337// ISerialPort properties
338/////////////////////////////////////////////////////////////////////////////
339
340STDMETHODIMP SerialPort::COMGETTER(Enabled) (BOOL *aEnabled)
341{
342 if (!aEnabled)
343 return E_POINTER;
344
345 AutoCaller autoCaller (this);
346 CheckComRCReturnRC (autoCaller.rc());
347
348 AutoReaderLock alock (this);
349
350 *aEnabled = mData->mEnabled;
351
352 return S_OK;
353}
354
355STDMETHODIMP SerialPort::COMSETTER(Enabled) (BOOL aEnabled)
356{
357 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
358
359 AutoCaller autoCaller (this);
360 CheckComRCReturnRC (autoCaller.rc());
361
362 /* the machine needs to be mutable */
363 Machine::AutoMutableStateDependency adep (mParent);
364 CheckComRCReturnRC (adep.rc());
365
366 AutoLock alock (this);
367
368 if (mData->mEnabled != aEnabled)
369 {
370 mData.backup();
371 mData->mEnabled = aEnabled;
372
373 /* leave the lock before informing callbacks */
374 alock.unlock();
375
376 mParent->onSerialPortChange (this);
377 }
378
379 return S_OK;
380}
381
382STDMETHODIMP SerialPort::COMGETTER(HostMode) (SerialHostMode_T *aHostMode)
383{
384 if (!aHostMode)
385 return E_POINTER;
386
387 AutoCaller autoCaller (this);
388 CheckComRCReturnRC (autoCaller.rc());
389
390 AutoReaderLock alock (this);
391
392 *aHostMode = mData->mHostMode;
393
394 return S_OK;
395}
396
397STDMETHODIMP SerialPort::COMSETTER(HostMode) (SerialHostMode_T aHostMode)
398{
399 AutoCaller autoCaller (this);
400 CheckComRCReturnRC (autoCaller.rc());
401
402 /* the machine needs to be mutable */
403 Machine::AutoMutableStateDependency adep (mParent);
404 CheckComRCReturnRC (adep.rc());
405
406 AutoLock alock (this);
407
408 HRESULT rc = S_OK;
409 bool emitChangeEvent = false;
410
411 if (mData->mHostMode != aHostMode)
412 {
413 mData.backup();
414 mData->mHostMode = aHostMode;
415 emitChangeEvent = true;
416 }
417
418 if (emitChangeEvent)
419 {
420 /* leave the lock before informing callbacks */
421 alock.unlock();
422
423 mParent->onSerialPortChange (this);
424 }
425
426 return rc;
427}
428
429STDMETHODIMP SerialPort::COMGETTER(Slot) (ULONG *aSlot)
430{
431 if (!aSlot)
432 return E_POINTER;
433
434 AutoCaller autoCaller (this);
435 CheckComRCReturnRC (autoCaller.rc());
436
437 AutoReaderLock alock (this);
438
439 *aSlot = mData->mSlot;
440
441 return S_OK;
442}
443
444STDMETHODIMP SerialPort::COMGETTER(IRQ) (ULONG *aIRQ)
445{
446 if (!aIRQ)
447 return E_POINTER;
448
449 AutoCaller autoCaller (this);
450 CheckComRCReturnRC (autoCaller.rc());
451
452 AutoReaderLock alock (this);
453
454 *aIRQ = mData->mIRQ;
455
456 return S_OK;
457}
458
459STDMETHODIMP SerialPort::COMSETTER(IRQ)(ULONG aIRQ)
460{
461 AutoCaller autoCaller (this);
462 CheckComRCReturnRC (autoCaller.rc());
463
464 /* the machine needs to be mutable */
465 Machine::AutoMutableStateDependency adep (mParent);
466 CheckComRCReturnRC (adep.rc());
467
468 AutoLock alock (this);
469
470 HRESULT rc = S_OK;
471 bool emitChangeEvent = false;
472
473 if (mData->mIRQ != aIRQ)
474 {
475 mData.backup();
476 mData->mIRQ = aIRQ;
477 emitChangeEvent = true;
478 }
479
480 if (emitChangeEvent)
481 {
482 /* leave the lock before informing callbacks */
483 alock.unlock();
484
485 mParent->onSerialPortChange (this);
486 }
487
488 return rc;
489}
490
491STDMETHODIMP SerialPort::COMGETTER(IOBase) (ULONG *aIOBase)
492{
493 if (!aIOBase)
494 return E_POINTER;
495
496 AutoCaller autoCaller (this);
497 CheckComRCReturnRC (autoCaller.rc());
498
499 AutoReaderLock alock (this);
500
501 *aIOBase = mData->mIOBase;
502
503 return S_OK;
504}
505
506STDMETHODIMP SerialPort::COMSETTER(IOBase)(ULONG aIOBase)
507{
508 AutoCaller autoCaller (this);
509 CheckComRCReturnRC (autoCaller.rc());
510
511 /* the machine needs to be mutable */
512 Machine::AutoMutableStateDependency adep (mParent);
513 CheckComRCReturnRC (adep.rc());
514
515 AutoLock alock (this);
516
517 HRESULT rc = S_OK;
518 bool emitChangeEvent = false;
519
520 if (mData->mIOBase != aIOBase)
521 {
522 mData.backup();
523 mData->mIOBase = aIOBase;
524 emitChangeEvent = true;
525 }
526
527 if (emitChangeEvent)
528 {
529 /* leave the lock before informing callbacks */
530 alock.unlock();
531
532 mParent->onSerialPortChange (this);
533 }
534
535 return rc;
536}
537
538STDMETHODIMP SerialPort::COMGETTER(Path) (BSTR *aPath)
539{
540 if (!aPath)
541 return E_POINTER;
542
543 AutoCaller autoCaller (this);
544 CheckComRCReturnRC (autoCaller.rc());
545
546 AutoReaderLock alock (this);
547
548 mData->mPath.cloneTo (aPath);
549
550 return S_OK;
551}
552
553STDMETHODIMP SerialPort::COMSETTER(Path) (INPTR BSTR aPath)
554{
555 if (!aPath || *aPath == 0)
556 return E_INVALIDARG;
557
558 AutoCaller autoCaller (this);
559 CheckComRCReturnRC (autoCaller.rc());
560
561 /* the machine needs to be mutable */
562 Machine::AutoMutableStateDependency adep (mParent);
563 CheckComRCReturnRC (adep.rc());
564
565 AutoLock alock (this);
566
567 if (mData->mPath != aPath)
568 {
569 mData.backup();
570 mData->mPath = aPath;
571
572 /* leave the lock before informing callbacks */
573 alock.unlock();
574
575 return mParent->onSerialPortChange (this);
576 }
577
578 return S_OK;
579}
580
581STDMETHODIMP SerialPort::COMGETTER(Server) (BOOL *aServer)
582{
583 if (!aServer)
584 return E_POINTER;
585
586 AutoCaller autoCaller (this);
587 CheckComRCReturnRC (autoCaller.rc());
588
589 AutoReaderLock alock (this);
590
591 *aServer = mData->mServer;
592
593 return S_OK;
594}
595
596STDMETHODIMP SerialPort::COMSETTER(Server) (BOOL aServer)
597{
598 LogFlowThisFunc (("aServer=%RTbool\n", aServer));
599
600 AutoCaller autoCaller (this);
601 CheckComRCReturnRC (autoCaller.rc());
602
603 /* the machine needs to be mutable */
604 Machine::AutoMutableStateDependency adep (mParent);
605 CheckComRCReturnRC (adep.rc());
606
607 AutoLock alock (this);
608
609 if (mData->mServer != aServer)
610 {
611 mData.backup();
612 mData->mServer = aServer;
613
614 /* leave the lock before informing callbacks */
615 alock.unlock();
616
617 mParent->onSerialPortChange (this);
618 }
619
620 return S_OK;
621}
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