VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DevSerial.cpp@ 26187

Last change on this file since 26187 was 26173, checked in by vboxsync, 15 years ago

PDM: s/pCfgHandle/pCfg/g - part 2.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.6 KB
Line 
1/* $Id: DevSerial.cpp 26173 2010-02-02 21:11:09Z vboxsync $ */
2/** @file
3 * DevSerial - 16450 UART emulation.
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/*
23 * This code is based on:
24 *
25 * QEMU 16450 UART emulation
26 *
27 * Copyright (c) 2003-2004 Fabrice Bellard
28 *
29 * Permission is hereby granted, free of charge, to any person obtaining a copy
30 * of this software and associated documentation files (the "Software"), to deal
31 * in the Software without restriction, including without limitation the rights
32 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33 * copies of the Software, and to permit persons to whom the Software is
34 * furnished to do so, subject to the following conditions:
35 *
36 * The above copyright notice and this permission notice shall be included in
37 * all copies or substantial portions of the Software.
38 *
39 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
42 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45 * THE SOFTWARE.
46 *
47 */
48
49/*******************************************************************************
50* Header Files *
51*******************************************************************************/
52#define LOG_GROUP LOG_GROUP_DEV_SERIAL
53#include <VBox/pdmdev.h>
54#include <iprt/assert.h>
55#include <iprt/uuid.h>
56#include <iprt/string.h>
57#include <iprt/semaphore.h>
58#include <iprt/critsect.h>
59
60#include "../Builtins.h"
61
62#undef VBOX_SERIAL_PCI /* The PCI variant has lots of problems: wrong IRQ line and wrong IO base assigned. */
63
64#ifdef VBOX_SERIAL_PCI
65# include <VBox/pci.h>
66#endif /* VBOX_SERIAL_PCI */
67
68
69/*******************************************************************************
70* Defined Constants And Macros *
71*******************************************************************************/
72#define SERIAL_SAVED_STATE_VERSION 3
73
74#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
75
76#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
77#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
78#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
79#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
80
81#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
82#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
83
84#define UART_IIR_MSI 0x00 /* Modem status interrupt */
85#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
86#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
87#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
88
89/*
90 * These are the definitions for the Modem Control Register
91 */
92#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
93#define UART_MCR_OUT2 0x08 /* Out2 complement */
94#define UART_MCR_OUT1 0x04 /* Out1 complement */
95#define UART_MCR_RTS 0x02 /* RTS complement */
96#define UART_MCR_DTR 0x01 /* DTR complement */
97
98/*
99 * These are the definitions for the Modem Status Register
100 */
101#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
102#define UART_MSR_RI 0x40 /* Ring Indicator */
103#define UART_MSR_DSR 0x20 /* Data Set Ready */
104#define UART_MSR_CTS 0x10 /* Clear to Send */
105#define UART_MSR_DDCD 0x08 /* Delta DCD */
106#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
107#define UART_MSR_DDSR 0x02 /* Delta DSR */
108#define UART_MSR_DCTS 0x01 /* Delta CTS */
109#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
110
111#define UART_LSR_TEMT 0x40 /* Transmitter empty */
112#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
113#define UART_LSR_BI 0x10 /* Break interrupt indicator */
114#define UART_LSR_FE 0x08 /* Frame error indicator */
115#define UART_LSR_PE 0x04 /* Parity error indicator */
116#define UART_LSR_OE 0x02 /* Overrun error indicator */
117#define UART_LSR_DR 0x01 /* Receiver data ready */
118
119
120/*******************************************************************************
121* Structures and Typedefs *
122*******************************************************************************/
123/**
124 * Serial device.
125 *
126 * @implements PDMIBASE
127 * @implements PDMICHARPORT
128 */
129struct SerialState
130{
131 /** Access critical section. */
132 PDMCRITSECT CritSect;
133
134 /** Pointer to the device instance - R3 Ptr. */
135 PPDMDEVINSR3 pDevInsR3;
136 /** Pointer to the device instance - R0 Ptr. */
137 PPDMDEVINSR0 pDevInsR0;
138 /** Pointer to the device instance - RC Ptr. */
139 PPDMDEVINSRC pDevInsRC;
140 RTRCPTR Alignment0; /**< Alignment. */
141 /** LUN\#0: The base interface. */
142 PDMIBASE IBase;
143 /** LUN\#0: The character port interface. */
144 PDMICHARPORT ICharPort;
145 /** Pointer to the attached base driver. */
146 R3PTRTYPE(PPDMIBASE) pDrvBase;
147 /** Pointer to the attached character driver. */
148 R3PTRTYPE(PPDMICHARCONNECTOR) pDrvChar;
149
150 uint16_t divider;
151 uint16_t auAlignment[3];
152 uint8_t rbr; /* receive register */
153 uint8_t ier;
154 uint8_t iir; /* read only */
155 uint8_t lcr;
156 uint8_t mcr;
157 uint8_t lsr; /* read only */
158 uint8_t msr; /* read only */
159 uint8_t scr;
160 /* NOTE: this hidden state is necessary for tx irq generation as
161 it can be reset while reading iir */
162 int thr_ipending;
163 int irq;
164 bool msr_changed;
165
166 bool fGCEnabled;
167 bool fR0Enabled;
168 bool fYieldOnLSRRead;
169 bool afAlignment[4];
170
171 RTSEMEVENT ReceiveSem;
172 int last_break_enable;
173 uint32_t base;
174
175#ifdef VBOX_SERIAL_PCI
176 PCIDEVICE dev;
177#endif /* VBOX_SERIAL_PCI */
178};
179
180#ifndef VBOX_DEVICE_STRUCT_TESTCASE
181
182
183#ifdef VBOX_SERIAL_PCI
184#define PCIDEV_2_SERIALSTATE(pPciDev) ( (SerialState *)((uintptr_t)(pPciDev) - RT_OFFSETOF(SerialState, dev)) )
185#endif /* VBOX_SERIAL_PCI */
186#define PDMIBASE_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, IBase)) )
187#define PDMICHARPORT_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, ICharPort)) )
188
189
190/*******************************************************************************
191* Internal Functions *
192*******************************************************************************/
193RT_C_DECLS_BEGIN
194PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
195PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
196RT_C_DECLS_END
197
198#ifdef IN_RING3
199
200static void serial_update_irq(SerialState *s)
201{
202 if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
203 s->iir = UART_IIR_RDI;
204 } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
205 s->iir = UART_IIR_THRI;
206 } else if (s->msr_changed && (s->ier & UART_IER_RLSI)) {
207 s->iir = UART_IIR_RLSI;
208 } else if (s->lsr & UART_LSR_BI) {
209 s->iir = 0; /* No special status bit */
210 } else {
211 s->iir = UART_IIR_NO_INT;
212 }
213 if (s->iir != UART_IIR_NO_INT) {
214 Log(("serial_update_irq %d 1\n", s->irq));
215# ifdef VBOX_SERIAL_PCI
216 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 1);
217# else /* !VBOX_SERIAL_PCI */
218 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 1);
219# endif /* !VBOX_SERIAL_PCI */
220 } else {
221 Log(("serial_update_irq %d 0\n", s->irq));
222# ifdef VBOX_SERIAL_PCI
223 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0);
224# else /* !VBOX_SERIAL_PCI */
225 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
226# endif /* !VBOX_SERIAL_PCI */
227 }
228}
229
230static void serial_update_parameters(SerialState *s)
231{
232 int speed, parity, data_bits, stop_bits;
233
234 if (s->lcr & 0x08) {
235 if (s->lcr & 0x10)
236 parity = 'E';
237 else
238 parity = 'O';
239 } else {
240 parity = 'N';
241 }
242 if (s->lcr & 0x04)
243 stop_bits = 2;
244 else
245 stop_bits = 1;
246 data_bits = (s->lcr & 0x03) + 5;
247 if (s->divider == 0)
248 return;
249 speed = 115200 / s->divider;
250 Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
251 if (RT_LIKELY(s->pDrvChar))
252 s->pDrvChar->pfnSetParameters(s->pDrvChar, speed, parity, data_bits, stop_bits);
253}
254
255#endif /* IN_RING3 */
256
257static int serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
258{
259 SerialState *s = (SerialState *)opaque;
260 unsigned char ch;
261
262 addr &= 7;
263 LogFlow(("serial: write addr=0x%02x val=0x%02x\n", addr, val));
264
265#ifndef IN_RING3
266 NOREF(ch);
267 NOREF(s);
268 return VINF_IOM_HC_IOPORT_WRITE;
269#else
270 switch(addr) {
271 default:
272 case 0:
273 if (s->lcr & UART_LCR_DLAB) {
274 s->divider = (s->divider & 0xff00) | val;
275 serial_update_parameters(s);
276 } else {
277 s->thr_ipending = 0;
278 s->lsr &= ~UART_LSR_THRE;
279 serial_update_irq(s);
280 ch = val;
281 if (RT_LIKELY(s->pDrvChar))
282 {
283 Log(("serial_io_port_write: write 0x%X\n", ch));
284 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
285 AssertRC(rc);
286 }
287 s->thr_ipending = 1;
288 s->lsr |= UART_LSR_THRE;
289 s->lsr |= UART_LSR_TEMT;
290 serial_update_irq(s);
291 }
292 break;
293 case 1:
294 if (s->lcr & UART_LCR_DLAB) {
295 s->divider = (s->divider & 0x00ff) | (val << 8);
296 serial_update_parameters(s);
297 } else {
298 s->ier = val & 0x0f;
299 if (s->lsr & UART_LSR_THRE) {
300 s->thr_ipending = 1;
301 }
302 serial_update_irq(s);
303 }
304 break;
305 case 2:
306 break;
307 case 3:
308 {
309 int break_enable;
310 if (s->lcr != val)
311 {
312 s->lcr = val;
313 serial_update_parameters(s);
314 }
315 break_enable = (val >> 6) & 1;
316 if (break_enable != s->last_break_enable) {
317 s->last_break_enable = break_enable;
318 if (RT_LIKELY(s->pDrvChar))
319 {
320 Log(("serial_io_port_write: Set break %d\n", break_enable));
321 int rc = s->pDrvChar->pfnSetBreak(s->pDrvChar, !!break_enable);
322 AssertRC(rc);
323 }
324 }
325 }
326 break;
327 case 4:
328 s->mcr = val & 0x1f;
329 if (RT_LIKELY(s->pDrvChar))
330 {
331 int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar, !!(s->mcr & UART_MCR_RTS), !!(s->mcr & UART_MCR_DTR));
332 AssertRC(rc);
333 }
334 break;
335 case 5:
336 break;
337 case 6:
338 break;
339 case 7:
340 s->scr = val;
341 break;
342 }
343 return VINF_SUCCESS;
344#endif
345}
346
347static uint32_t serial_ioport_read(void *opaque, uint32_t addr, int *pRC)
348{
349 SerialState *s = (SerialState *)opaque;
350 uint32_t ret = ~0U;
351
352 *pRC = VINF_SUCCESS;
353
354 addr &= 7;
355 switch(addr) {
356 default:
357 case 0:
358 if (s->lcr & UART_LCR_DLAB) {
359 ret = s->divider & 0xff;
360 } else {
361#ifndef IN_RING3
362 *pRC = VINF_IOM_HC_IOPORT_READ;
363#else
364 Log(("serial_io_port_read: read 0x%X\n", s->rbr));
365 ret = s->rbr;
366 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
367 serial_update_irq(s);
368 {
369 int rc = RTSemEventSignal(s->ReceiveSem);
370 AssertRC(rc);
371 }
372#endif
373 }
374 break;
375 case 1:
376 if (s->lcr & UART_LCR_DLAB) {
377 ret = (s->divider >> 8) & 0xff;
378 } else {
379 ret = s->ier;
380 }
381 break;
382 case 2:
383#ifndef IN_RING3
384 *pRC = VINF_IOM_HC_IOPORT_READ;
385#else
386 ret = s->iir;
387 /* reset THR pending bit */
388 if ((ret & 0x7) == UART_IIR_THRI)
389 s->thr_ipending = 0;
390 /* reset msr changed bit */
391 s->msr_changed = false;
392 serial_update_irq(s);
393#endif
394 break;
395 case 3:
396 ret = s->lcr;
397 break;
398 case 4:
399 ret = s->mcr;
400 break;
401 case 5:
402 if ((s->lsr & UART_LSR_DR) == 0 && s->fYieldOnLSRRead)
403 {
404 /* No data available and yielding is enabled, so yield in ring3. */
405#ifndef IN_RING3
406 *pRC = VINF_IOM_HC_IOPORT_READ;
407 break;
408#else
409 RTThreadYield ();
410#endif
411 }
412 ret = s->lsr;
413 break;
414 case 6:
415 if (s->mcr & UART_MCR_LOOP) {
416 /* in loopback, the modem output pins are connected to the
417 inputs */
418 ret = (s->mcr & 0x0c) << 4;
419 ret |= (s->mcr & 0x02) << 3;
420 ret |= (s->mcr & 0x01) << 5;
421 } else {
422 ret = s->msr;
423 /* Reset delta bits. */
424 s->msr &= ~UART_MSR_ANY_DELTA;
425 }
426 break;
427 case 7:
428 ret = s->scr;
429 break;
430 }
431 LogFlow(("serial: read addr=0x%02x val=0x%02x\n", addr, ret));
432 return ret;
433}
434
435#ifdef IN_RING3
436
437static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
438{
439 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
440 int rc;
441
442 Assert(*pcbRead != 0);
443
444 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
445 if (pThis->lsr & UART_LSR_DR)
446 {
447 /* If a character is still in the read queue, then wait for it to be emptied. */
448 PDMCritSectLeave(&pThis->CritSect);
449 rc = RTSemEventWait(pThis->ReceiveSem, 250);
450 if (RT_FAILURE(rc))
451 return rc;
452
453 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
454 }
455
456 if (!(pThis->lsr & UART_LSR_DR))
457 {
458 pThis->rbr = *(const char *)pvBuf;
459 pThis->lsr |= UART_LSR_DR;
460 serial_update_irq(pThis);
461 *pcbRead = 1;
462 rc = VINF_SUCCESS;
463 }
464 else
465 rc = VERR_TIMEOUT;
466
467 PDMCritSectLeave(&pThis->CritSect);
468
469 return rc;
470}
471
472static DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines)
473{
474 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
475 uint8_t newMsr = 0;
476
477 Log(("%s: pInterface=%p newStatusLines=%u\n", __FUNCTION__, pInterface, newStatusLines));
478
479 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
480
481 /* Set new states. */
482 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DCD)
483 newMsr |= UART_MSR_DCD;
484 if (newStatusLines & PDMICHARPORT_STATUS_LINES_RI)
485 newMsr |= UART_MSR_RI;
486 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DSR)
487 newMsr |= UART_MSR_DSR;
488 if (newStatusLines & PDMICHARPORT_STATUS_LINES_CTS)
489 newMsr |= UART_MSR_CTS;
490
491 /* Compare the old and the new states and set the delta bits accordingly. */
492 if ((newMsr & UART_MSR_DCD) != (pThis->msr & UART_MSR_DCD))
493 newMsr |= UART_MSR_DDCD;
494 if ((newMsr & UART_MSR_RI) == 1 && (pThis->msr & UART_MSR_RI) == 0)
495 newMsr |= UART_MSR_TERI;
496 if ((newMsr & UART_MSR_DSR) != (pThis->msr & UART_MSR_DSR))
497 newMsr |= UART_MSR_DDSR;
498 if ((newMsr & UART_MSR_CTS) != (pThis->msr & UART_MSR_CTS))
499 newMsr |= UART_MSR_DCTS;
500
501 pThis->msr = newMsr;
502 pThis->msr_changed = true;
503 serial_update_irq(pThis);
504
505 PDMCritSectLeave(&pThis->CritSect);
506
507 return VINF_SUCCESS;
508}
509
510static DECLCALLBACK(int) serialNotifyBreak(PPDMICHARPORT pInterface)
511{
512 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
513
514 Log(("%s: pInterface=%p\n", __FUNCTION__, pInterface));
515
516 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
517
518 pThis->lsr |= UART_LSR_BI;
519 serial_update_irq(pThis);
520
521 PDMCritSectLeave(&pThis->CritSect);
522
523 return VINF_SUCCESS;
524}
525
526#endif /* IN_RING3 */
527
528/**
529 * Port I/O Handler for OUT operations.
530 *
531 * @returns VBox status code.
532 *
533 * @param pDevIns The device instance.
534 * @param pvUser User argument.
535 * @param Port Port number used for the IN operation.
536 * @param u32 The value to output.
537 * @param cb The value size in bytes.
538 */
539PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
540 RTIOPORT Port, uint32_t u32, unsigned cb)
541{
542 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
543 int rc = VINF_SUCCESS;
544
545 if (cb == 1)
546 {
547 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
548 if (rc == VINF_SUCCESS)
549 {
550 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
551 rc = serial_ioport_write(pThis, Port, u32);
552 PDMCritSectLeave(&pThis->CritSect);
553 }
554 }
555 else
556 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
557
558 return rc;
559}
560
561/**
562 * Port I/O Handler for IN operations.
563 *
564 * @returns VBox status code.
565 *
566 * @param pDevIns The device instance.
567 * @param pvUser User argument.
568 * @param Port Port number used for the IN operation.
569 * @param u32 The value to output.
570 * @param cb The value size in bytes.
571 */
572PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
573 RTIOPORT Port, uint32_t *pu32, unsigned cb)
574{
575 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
576 int rc = VINF_SUCCESS;
577
578 if (cb == 1)
579 {
580 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
581 if (rc == VINF_SUCCESS)
582 {
583 *pu32 = serial_ioport_read(pThis, Port, &rc);
584 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
585 PDMCritSectLeave(&pThis->CritSect);
586 }
587 }
588 else
589 rc = VERR_IOM_IOPORT_UNUSED;
590
591 return rc;
592}
593
594#ifdef IN_RING3
595
596/**
597 * @copydoc FNSSMDEVLIVEEXEC
598 */
599static DECLCALLBACK(int) serialLiveExec(PPDMDEVINS pDevIns,
600 PSSMHANDLE pSSM,
601 uint32_t uPass)
602{
603 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
604 SSMR3PutS32(pSSM, pThis->irq);
605 SSMR3PutU32(pSSM, pThis->base);
606 return VINF_SSM_DONT_CALL_AGAIN;
607}
608
609/**
610 * @copydoc FNSSMDEVSAVEEXEC
611 */
612static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
613 PSSMHANDLE pSSM)
614{
615 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
616
617 SSMR3PutU16(pSSM, pThis->divider);
618 SSMR3PutU8(pSSM, pThis->rbr);
619 SSMR3PutU8(pSSM, pThis->ier);
620 SSMR3PutU8(pSSM, pThis->lcr);
621 SSMR3PutU8(pSSM, pThis->mcr);
622 SSMR3PutU8(pSSM, pThis->lsr);
623 SSMR3PutU8(pSSM, pThis->msr);
624 SSMR3PutU8(pSSM, pThis->scr);
625 SSMR3PutS32(pSSM, pThis->thr_ipending);
626 SSMR3PutS32(pSSM, pThis->irq);
627 SSMR3PutS32(pSSM, pThis->last_break_enable);
628 SSMR3PutU32(pSSM, pThis->base);
629 SSMR3PutBool(pSSM, pThis->msr_changed);
630 return SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
631}
632
633/**
634 * @copydoc FNSSMDEVLOADEXEC
635 */
636static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
637 PSSMHANDLE pSSM,
638 uint32_t uVersion,
639 uint32_t uPass)
640{
641 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
642
643 AssertMsgReturn(uVersion == SERIAL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
644
645 if (uPass == SSM_PASS_FINAL)
646 {
647 SSMR3GetU16(pSSM, &pThis->divider);
648 SSMR3GetU8(pSSM, &pThis->rbr);
649 SSMR3GetU8(pSSM, &pThis->ier);
650 SSMR3GetU8(pSSM, &pThis->lcr);
651 SSMR3GetU8(pSSM, &pThis->mcr);
652 SSMR3GetU8(pSSM, &pThis->lsr);
653 SSMR3GetU8(pSSM, &pThis->msr);
654 SSMR3GetU8(pSSM, &pThis->scr);
655 SSMR3GetS32(pSSM, &pThis->thr_ipending);
656 }
657
658 int32_t iIrq;
659 SSMR3GetS32(pSSM, &iIrq);
660
661 if (uPass == SSM_PASS_FINAL)
662 SSMR3GetS32(pSSM, &pThis->last_break_enable);
663
664 uint32_t IOBase;
665 int rc = SSMR3GetU32(pSSM, &IOBase);
666 AssertRCReturn(rc, rc);
667
668 if ( pThis->irq != iIrq
669 || pThis->base != IOBase)
670 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
671 iIrq, IOBase, pThis->irq, pThis->base);
672
673 if (uPass == SSM_PASS_FINAL)
674 {
675 SSMR3GetBool(pSSM, &pThis->msr_changed);
676
677 uint32_t u32;
678 rc = SSMR3GetU32(pSSM, &u32);
679 if (RT_FAILURE(rc))
680 return rc;
681 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
682
683 if (pThis->lsr & UART_LSR_DR)
684 {
685 rc = RTSemEventSignal(pThis->ReceiveSem);
686 AssertRC(rc);
687 }
688
689 /* this isn't strictly necessary but cannot hurt... */
690 pThis->pDevInsR3 = pDevIns;
691 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
692 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
693 }
694
695 return VINF_SUCCESS;
696}
697
698
699/**
700 * @copydoc FNPDMDEVRELOCATE
701 */
702static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
703{
704 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
705 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
706}
707
708#ifdef VBOX_SERIAL_PCI
709
710static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
711{
712 SerialState *pThis = PCIDEV_2_SERIALSTATE(pPciDev);
713 int rc = VINF_SUCCESS;
714
715 Assert(enmType == PCI_ADDRESS_SPACE_IO);
716 Assert(iRegion == 0);
717 Assert(cb == 8);
718 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
719
720 pThis->base = (RTIOPORT)GCPhysAddress;
721 LogRel(("Serial#%d: mapping I/O at %#06x\n", pThis->pDevIns->iInstance, pThis->base));
722
723 /*
724 * Register our port IO handlers.
725 */
726 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
727 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
728 AssertRC(rc);
729 return rc;
730}
731
732#endif /* VBOX_SERIAL_PCI */
733
734/**
735 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
736 */
737static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
738{
739 SerialState *pThis = PDMIBASE_2_SERIALSTATE(pInterface);
740 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
741 PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARPORT, &pThis->ICharPort);
742 return NULL;
743}
744
745/**
746 * Destruct a device instance.
747 *
748 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
749 * resources can be freed correctly.
750 *
751 * @returns VBox status.
752 * @param pDevIns The device instance data.
753 */
754static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
755{
756 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
757 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
758
759 RTSemEventDestroy(pThis->ReceiveSem);
760 pThis->ReceiveSem = NIL_RTSEMEVENT;
761
762 PDMR3CritSectDelete(&pThis->CritSect);
763 return VINF_SUCCESS;
764}
765
766
767/**
768 * @interface_method_impl{PDMDEVREG,pfnConstruct}
769 */
770static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns,
771 int iInstance,
772 PCFGMNODE pCfg)
773{
774 int rc;
775 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState*);
776 uint16_t io_base;
777 uint8_t irq_lvl;
778
779 Assert(iInstance < 4);
780 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
781
782 /*
783 * Initialize the instance data.
784 * (Do this early or the destructor might choke on something!)
785 */
786 pThis->pDevInsR3 = pDevIns;
787 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
788 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
789
790 pThis->lsr = UART_LSR_TEMT | UART_LSR_THRE;
791 pThis->iir = UART_IIR_NO_INT;
792 pThis->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
793
794 /* IBase */
795 pThis->IBase.pfnQueryInterface = serialQueryInterface;
796
797 /* ICharPort */
798 pThis->ICharPort.pfnNotifyRead = serialNotifyRead;
799 pThis->ICharPort.pfnNotifyStatusLinesChanged = serialNotifyStatusLinesChanged;
800 pThis->ICharPort.pfnNotifyBreak = serialNotifyBreak;
801
802#ifdef VBOX_SERIAL_PCI
803 /* the PCI device */
804 pThis->dev.config[0x00] = 0xee; /* Vendor: ??? */
805 pThis->dev.config[0x01] = 0x80;
806 pThis->dev.config[0x02] = 0x01; /* Device: ??? */
807 pThis->dev.config[0x03] = 0x01;
808 pThis->dev.config[0x04] = PCI_COMMAND_IOACCESS;
809 pThis->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
810 pThis->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
811 pThis->dev.config[0x0b] = 0x07; /* Class: Communication controller */
812 pThis->dev.config[0x0e] = 0x00; /* Header type: standard */
813 pThis->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
814 pThis->dev.config[0x3d] = 1; /* interrupt pin 0 */
815#endif /* VBOX_SERIAL_PCI */
816
817 /*
818 * Validate and read the configuration.
819 */
820 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0" "YieldOnLSRRead\0"))
821 {
822 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
823 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
824 }
825
826 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
827 if (RT_FAILURE(rc))
828 return PDMDEV_SET_ERROR(pDevIns, rc,
829 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
830
831 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
832 if (RT_FAILURE(rc))
833 return PDMDEV_SET_ERROR(pDevIns, rc,
834 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
835
836 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
837 if (RT_FAILURE(rc))
838 return PDMDEV_SET_ERROR(pDevIns, rc,
839 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
840
841 rc = CFGMR3QueryU8(pCfg, "IRQ", &irq_lvl);
842 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
843 {
844 /* Provide sensible defaults. */
845 if (iInstance == 0)
846 irq_lvl = 4;
847 else if (iInstance == 1)
848 irq_lvl = 3;
849 else
850 AssertReleaseFailed(); /* irq_lvl is undefined. */
851 }
852 else if (RT_FAILURE(rc))
853 return PDMDEV_SET_ERROR(pDevIns, rc,
854 N_("Configuration error: Failed to get the \"IRQ\" value"));
855
856 rc = CFGMR3QueryU16(pCfg, "IOBase", &io_base);
857 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
858 {
859 if (iInstance == 0)
860 io_base = 0x3f8;
861 else if (iInstance == 1)
862 io_base = 0x2f8;
863 else
864 AssertReleaseFailed(); /* io_base is undefined */
865 }
866 else if (RT_FAILURE(rc))
867 return PDMDEV_SET_ERROR(pDevIns, rc,
868 N_("Configuration error: Failed to get the \"IOBase\" value"));
869
870 Log(("DevSerial: instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
871
872 pThis->irq = irq_lvl;
873#ifdef VBOX_SERIAL_PCI
874 pThis->base = -1;
875#else
876 pThis->base = io_base;
877#endif
878
879 /*
880 * Initialize critical section and the semaphore.
881 * This must of course be done before attaching drivers or anything else which can call us back..
882 */
883 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
884 if (RT_FAILURE(rc))
885 return rc;
886
887 rc = RTSemEventCreate(&pThis->ReceiveSem);
888 AssertRC(rc);
889
890#ifdef VBOX_SERIAL_PCI
891 /*
892 * Register the PCI Device and region.
893 */
894 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
895 if (RT_FAILURE(rc))
896 return rc;
897 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
898 if (RT_FAILURE(rc))
899 return rc;
900
901#else /* !VBOX_SERIAL_PCI */
902 /*
903 * Register the I/O ports.
904 */
905 pThis->base = io_base;
906 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
907 serialIOPortWrite, serialIOPortRead,
908 NULL, NULL, "SERIAL");
909 if (RT_FAILURE(rc))
910 return rc;
911
912 if (pThis->fGCEnabled)
913 {
914 rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
915 "serialIOPortRead", NULL, NULL, "Serial");
916 if (RT_FAILURE(rc))
917 return rc;
918 }
919
920
921 if (pThis->fR0Enabled)
922 {
923 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
924 "serialIOPortRead", NULL, NULL, "Serial");
925 if (RT_FAILURE(rc))
926 return rc;
927 }
928#endif /* !VBOX_SERIAL_PCI */
929
930 /*
931 * Saved state.
932 */
933 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
934 serialLiveExec, serialSaveExec, serialLoadExec);
935 if (RT_FAILURE(rc))
936 return rc;
937
938 /*
939 * Attach the char driver and get the interfaces.
940 * For now no run-time changes are supported.
941 */
942 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
943 if (RT_SUCCESS(rc))
944 {
945 pThis->pDrvChar = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMICHARCONNECTOR);
946 if (!pThis->pDrvChar)
947 {
948 AssertLogRelMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
949 return VERR_PDM_MISSING_INTERFACE;
950 }
951 /** @todo provide read notification interface!!!! */
952 }
953 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
954 {
955 pThis->pDrvBase = NULL;
956 pThis->pDrvChar = NULL;
957 LogRel(("Serial%d: no unit\n", iInstance));
958 }
959 else
960 {
961 AssertLogRelMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
962 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
963 return rc;
964 }
965
966 return VINF_SUCCESS;
967}
968
969
970/**
971 * The device registration structure.
972 */
973const PDMDEVREG g_DeviceSerialPort =
974{
975 /* u32Version */
976 PDM_DEVREG_VERSION,
977 /* szName */
978 "serial",
979 /* szRCMod */
980 "VBoxDDGC.gc",
981 /* szR0Mod */
982 "VBoxDDR0.r0",
983 /* pszDescription */
984 "Serial Communication Port",
985 /* fFlags */
986 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
987 /* fClass */
988 PDM_DEVREG_CLASS_SERIAL,
989 /* cMaxInstances */
990 UINT32_MAX,
991 /* cbInstance */
992 sizeof(SerialState),
993 /* pfnConstruct */
994 serialConstruct,
995 /* pfnDestruct */
996 serialDestruct,
997 /* pfnRelocate */
998 serialRelocate,
999 /* pfnIOCtl */
1000 NULL,
1001 /* pfnPowerOn */
1002 NULL,
1003 /* pfnReset */
1004 NULL,
1005 /* pfnSuspend */
1006 NULL,
1007 /* pfnResume */
1008 NULL,
1009 /* pfnAttach */
1010 NULL,
1011 /* pfnDetach */
1012 NULL,
1013 /* pfnQueryInterface. */
1014 NULL,
1015 /* pfnInitComplete */
1016 NULL,
1017 /* pfnPowerOff */
1018 NULL,
1019 /* pfnSoftReset */
1020 NULL,
1021 /* u32VersionEnd */
1022 PDM_DEVREG_VERSION
1023};
1024#endif /* IN_RING3 */
1025
1026
1027#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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