VirtualBox

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

Last change on this file since 35717 was 35717, checked in by vboxsync, 14 years ago

dev/serial: better char lost handling

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.0 KB
Line 
1/* $Id: DevSerial.cpp 35717 2011-01-25 17:01:58Z vboxsync $ */
2/** @file
3 * DevSerial - 16550A UART emulation.
4 * (taken from hw/serial.c 2010/05/15 with modifications)
5 */
6
7/*
8 * Copyright (C) 2006-2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. 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/*
20 * This code is based on:
21 *
22 * QEMU 16550A UART emulation
23 *
24 * Copyright (c) 2003-2004 Fabrice Bellard
25 * Copyright (c) 2008 Citrix Systems, Inc.
26 *
27 * Permission is hereby granted, free of charge, to any person obtaining a copy
28 * of this software and associated documentation files (the "Software"), to deal
29 * in the Software without restriction, including without limitation the rights
30 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31 * copies of the Software, and to permit persons to whom the Software is
32 * furnished to do so, subject to the following conditions:
33 *
34 * The above copyright notice and this permission notice shall be included in
35 * all copies or substantial portions of the Software.
36 *
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
40 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43 * THE SOFTWARE.
44 */
45
46/*******************************************************************************
47* Header Files *
48*******************************************************************************/
49#define LOG_GROUP LOG_GROUP_DEV_SERIAL
50#include <VBox/vmm/pdmdev.h>
51#include <iprt/assert.h>
52#include <iprt/uuid.h>
53#include <iprt/string.h>
54#include <iprt/semaphore.h>
55#include <iprt/critsect.h>
56
57#include "VBoxDD.h"
58
59#undef VBOX_SERIAL_PCI /* The PCI variant has lots of problems: wrong IRQ line and wrong IO base assigned. */
60
61#ifdef VBOX_SERIAL_PCI
62# include <VBox/pci.h>
63#endif /* VBOX_SERIAL_PCI */
64
65
66/*******************************************************************************
67* Defined Constants And Macros *
68*******************************************************************************/
69#define SERIAL_SAVED_STATE_VERSION_16450 3
70#define SERIAL_SAVED_STATE_VERSION 4
71
72#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
73
74#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
75#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
76#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
77#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
78
79#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
80#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
81
82#define UART_IIR_MSI 0x00 /* Modem status interrupt */
83#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
84#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
85#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
86#define UART_IIR_CTI 0x0C /* Character Timeout Indication */
87
88#define UART_IIR_FENF 0x80 /* Fifo enabled, but not functioning */
89#define UART_IIR_FE 0xC0 /* Fifo enabled */
90
91/*
92 * These are the definitions for the Modem Control Register
93 */
94#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
95#define UART_MCR_OUT2 0x08 /* Out2 complement */
96#define UART_MCR_OUT1 0x04 /* Out1 complement */
97#define UART_MCR_RTS 0x02 /* RTS complement */
98#define UART_MCR_DTR 0x01 /* DTR complement */
99
100/*
101 * These are the definitions for the Modem Status Register
102 */
103#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
104#define UART_MSR_RI 0x40 /* Ring Indicator */
105#define UART_MSR_DSR 0x20 /* Data Set Ready */
106#define UART_MSR_CTS 0x10 /* Clear to Send */
107#define UART_MSR_DDCD 0x08 /* Delta DCD */
108#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
109#define UART_MSR_DDSR 0x02 /* Delta DSR */
110#define UART_MSR_DCTS 0x01 /* Delta CTS */
111#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
112
113#define UART_LSR_TEMT 0x40 /* Transmitter empty */
114#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
115#define UART_LSR_BI 0x10 /* Break interrupt indicator */
116#define UART_LSR_FE 0x08 /* Frame error indicator */
117#define UART_LSR_PE 0x04 /* Parity error indicator */
118#define UART_LSR_OE 0x02 /* Overrun error indicator */
119#define UART_LSR_DR 0x01 /* Receiver data ready */
120#define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */
121
122/*
123 * Interrupt trigger levels.
124 * The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher.
125 */
126#define UART_FCR_ITL_1 0x00 /* 1 byte ITL */
127#define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */
128#define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */
129#define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */
130
131#define UART_FCR_DMS 0x08 /* DMA Mode Select */
132#define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */
133#define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */
134#define UART_FCR_FE 0x01 /* FIFO Enable */
135
136#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */
137
138#define XMIT_FIFO 0
139#define RECV_FIFO 1
140#define MAX_XMIT_RETRY 16
141
142/*******************************************************************************
143* Structures and Typedefs *
144*******************************************************************************/
145
146struct SerialFifo
147{
148 uint8_t data[UART_FIFO_LENGTH];
149 uint8_t count;
150 uint8_t itl;
151 uint8_t tail;
152 uint8_t head;
153};
154
155/**
156 * Serial device.
157 *
158 * @implements PDMIBASE
159 * @implements PDMICHARPORT
160 */
161struct SerialState
162{
163 /** Access critical section. */
164 PDMCRITSECT CritSect;
165 /** Pointer to the device instance - R3 Ptr. */
166 PPDMDEVINSR3 pDevInsR3;
167 /** Pointer to the device instance - R0 Ptr. */
168 PPDMDEVINSR0 pDevInsR0;
169 /** Pointer to the device instance - RC Ptr. */
170 PPDMDEVINSRC pDevInsRC;
171 /** Alignment. */
172 RTRCPTR Alignment0;
173 /** LUN\#0: The base interface. */
174 PDMIBASE IBase;
175 /** LUN\#0: The character port interface. */
176 PDMICHARPORT ICharPort;
177 /** Pointer to the attached base driver. */
178 R3PTRTYPE(PPDMIBASE) pDrvBase;
179 /** Pointer to the attached character driver. */
180 R3PTRTYPE(PPDMICHARCONNECTOR) pDrvChar;
181
182 RTSEMEVENT ReceiveSem;
183 PTMTIMERR3 fifo_timeout_timer;
184 PTMTIMERR3 transmit_timerR3;
185 PTMTIMERR0 transmit_timerR0; /* currently not used */
186 PTMTIMERRC transmit_timerRC; /* currently not used */
187 RTRCPTR Alignment1;
188 SerialFifo recv_fifo;
189 SerialFifo xmit_fifo;
190
191 uint32_t base;
192 uint16_t divider;
193 uint16_t Alignment2[1];
194 uint8_t rbr; /**< receive register */
195 uint8_t thr; /**< transmit holding register */
196 uint8_t tsr; /**< transmit shift register */
197 uint8_t ier; /**< interrupt enable register */
198 uint8_t iir; /**< interrupt identification register, R/O */
199 uint8_t lcr; /**< line control register */
200 uint8_t mcr; /**< modem control register */
201 uint8_t lsr; /**< line status register, R/O */
202 uint8_t msr; /**< modem status register, R/O */
203 uint8_t scr; /**< scratch register */
204 uint8_t fcr; /**< fifo control register */
205 uint8_t fcr_vmstate;
206 /* NOTE: this hidden state is necessary for tx irq generation as
207 it can be reset while reading iir */
208 int thr_ipending;
209 int timeout_ipending;
210 int irq;
211 int last_break_enable;
212 /** Counter for retrying xmit */
213 int tsr_retry;
214 bool msr_changed;
215 bool fGCEnabled;
216 bool fR0Enabled;
217 bool fYieldOnLSRRead;
218 bool volatile fRecvWaiting;
219 bool f16550AEnabled;
220 bool Alignment3[2];
221 /** Time it takes to transmit a character */
222 uint64_t char_transmit_time;
223
224#ifdef VBOX_SERIAL_PCI
225 PCIDEVICE dev;
226#endif /* VBOX_SERIAL_PCI */
227};
228
229#ifndef VBOX_DEVICE_STRUCT_TESTCASE
230
231
232#ifdef VBOX_SERIAL_PCI
233#define PCIDEV_2_SERIALSTATE(pPciDev) ( (SerialState *)((uintptr_t)(pPciDev) - RT_OFFSETOF(SerialState, dev)) )
234#endif /* VBOX_SERIAL_PCI */
235#define PDMIBASE_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, IBase)) )
236#define PDMICHARPORT_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, ICharPort)) )
237
238
239/*******************************************************************************
240* Internal Functions *
241*******************************************************************************/
242RT_C_DECLS_BEGIN
243PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
244PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
245RT_C_DECLS_END
246
247#ifdef IN_RING3
248
249static int serial_can_receive(SerialState *s);
250static void serial_receive(void *opaque, const uint8_t *buf, int size);
251
252static void fifo_clear(SerialState *s, int fifo)
253{
254 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
255 memset(f->data, 0, UART_FIFO_LENGTH);
256 f->count = 0;
257 f->head = 0;
258 f->tail = 0;
259}
260
261static int fifo_put(SerialState *s, int fifo, uint8_t chr)
262{
263 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
264
265 /* Receive overruns do not overwrite FIFO contents. */
266 if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH)
267 {
268 f->data[f->head++] = chr;
269 if (f->head == UART_FIFO_LENGTH)
270 f->head = 0;
271 }
272
273 if (f->count < UART_FIFO_LENGTH)
274 f->count++;
275 else if (fifo == XMIT_FIFO) /* need to at least adjust tail to maintain pipe state consistency */
276 ++f->tail;
277 else if (fifo == RECV_FIFO)
278 s->lsr |= UART_LSR_OE;
279
280 return 1;
281}
282
283static uint8_t fifo_get(SerialState *s, int fifo)
284{
285 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
286 uint8_t c;
287
288 if (f->count == 0)
289 return 0;
290
291 c = f->data[f->tail++];
292 if (f->tail == UART_FIFO_LENGTH)
293 f->tail = 0;
294 f->count--;
295
296 return c;
297}
298
299static void serial_update_irq(SerialState *s)
300{
301 uint8_t tmp_iir = UART_IIR_NO_INT;
302
303 if ( (s->ier & UART_IER_RLSI)
304 && (s->lsr & UART_LSR_INT_ANY)) {
305 tmp_iir = UART_IIR_RLSI;
306 } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) {
307 /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
308 * this is not in the specification but is observed on existing
309 * hardware. */
310 tmp_iir = UART_IIR_CTI;
311 } else if ( (s->ier & UART_IER_RDI)
312 && (s->lsr & UART_LSR_DR)
313 && ( !(s->fcr & UART_FCR_FE)
314 || s->recv_fifo.count >= s->recv_fifo.itl)) {
315 tmp_iir = UART_IIR_RDI;
316 } else if ( (s->ier & UART_IER_THRI)
317 && s->thr_ipending) {
318 tmp_iir = UART_IIR_THRI;
319 } else if ( (s->ier & UART_IER_MSI)
320 && (s->msr & UART_MSR_ANY_DELTA)) {
321 tmp_iir = UART_IIR_MSI;
322 }
323 s->iir = tmp_iir | (s->iir & 0xF0);
324
325 /** XXX only call the SetIrq function if the state really changes! */
326 if (tmp_iir != UART_IIR_NO_INT) {
327 Log(("serial_update_irq %d 1\n", s->irq));
328# ifdef VBOX_SERIAL_PCI
329 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 1);
330# else /* !VBOX_SERIAL_PCI */
331 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 1);
332# endif /* !VBOX_SERIAL_PCI */
333 } else {
334 Log(("serial_update_irq %d 0\n", s->irq));
335# ifdef VBOX_SERIAL_PCI
336 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0);
337# else /* !VBOX_SERIAL_PCI */
338 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
339# endif /* !VBOX_SERIAL_PCI */
340 }
341}
342
343static void serial_update_parameters(SerialState *s)
344{
345 int speed, parity, data_bits, stop_bits, frame_size;
346
347 if (s->divider == 0)
348 return;
349
350 frame_size = 1;
351 if (s->lcr & 0x08) {
352 frame_size++;
353 if (s->lcr & 0x10)
354 parity = 'E';
355 else
356 parity = 'O';
357 } else {
358 parity = 'N';
359 }
360 if (s->lcr & 0x04)
361 stop_bits = 2;
362 else
363 stop_bits = 1;
364
365 data_bits = (s->lcr & 0x03) + 5;
366 frame_size += data_bits + stop_bits;
367 speed = 115200 / s->divider;
368 s->char_transmit_time = (TMTimerGetFreq(CTX_SUFF(s->transmit_timer)) / speed) * frame_size;
369 Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
370
371 if (RT_LIKELY(s->pDrvChar))
372 s->pDrvChar->pfnSetParameters(s->pDrvChar, speed, parity, data_bits, stop_bits);
373}
374
375static void serial_xmit(void *opaque, bool bRetryXmit)
376{
377 SerialState *s = (SerialState*)opaque;
378
379 if (s->tsr_retry <= 0) {
380 if (s->fcr & UART_FCR_FE) {
381 s->tsr = fifo_get(s, XMIT_FIFO);
382 if (!s->xmit_fifo.count)
383 s->lsr |= UART_LSR_THRE;
384 } else {
385 s->tsr = s->thr;
386 s->lsr |= UART_LSR_THRE;
387 }
388 }
389
390 if (s->mcr & UART_MCR_LOOP) {
391 /* in loopback mode, say that we just received a char */
392 serial_receive(s, &s->tsr, 1);
393 } else if ( RT_LIKELY(s->pDrvChar)
394 && RT_FAILURE(s->pDrvChar->pfnWrite(s->pDrvChar, &s->tsr, 1))) {
395 if ((s->tsr_retry >= 0) && ((!bRetryXmit) || (s->tsr_retry <= MAX_XMIT_RETRY))) {
396 if (!s->tsr_retry)
397 s->tsr_retry = 1; /* make sure the retry state is always set */
398 else if (bRetryXmit) /* do not increase the retry count if the retry is actually caused by next char write */
399 s->tsr_retry++;
400
401 TMTimerSet(CTX_SUFF(s->transmit_timer), TMTimerGet(CTX_SUFF(s->transmit_timer)) + s->char_transmit_time * 4);
402 return;
403 } else {
404 /* drop this character. */
405 s->tsr_retry = 0;
406 }
407 }
408 else {
409 s->tsr_retry = 0;
410 }
411
412 if (!(s->lsr & UART_LSR_THRE))
413 TMTimerSet(CTX_SUFF(s->transmit_timer),
414 TMTimerGet(CTX_SUFF(s->transmit_timer)) + s->char_transmit_time);
415
416 if (s->lsr & UART_LSR_THRE) {
417 s->lsr |= UART_LSR_TEMT;
418 s->thr_ipending = 1;
419 serial_update_irq(s);
420 }
421}
422
423#endif /* IN_RING3 */
424
425static int serial_ioport_write(SerialState *s, uint32_t addr, uint32_t val)
426{
427 addr &= 7;
428
429#ifndef IN_RING3
430 NOREF(s);
431 return VINF_IOM_HC_IOPORT_WRITE;
432#else
433 switch(addr) {
434 default:
435 case 0:
436 if (s->lcr & UART_LCR_DLAB) {
437 s->divider = (s->divider & 0xff00) | val;
438 serial_update_parameters(s);
439 } else {
440 s->thr = (uint8_t) val;
441 if (s->fcr & UART_FCR_FE) {
442 fifo_put(s, XMIT_FIFO, s->thr);
443 s->thr_ipending = 0;
444 s->lsr &= ~UART_LSR_TEMT;
445 s->lsr &= ~UART_LSR_THRE;
446 serial_update_irq(s);
447 } else {
448 s->thr_ipending = 0;
449 s->lsr &= ~UART_LSR_THRE;
450 serial_update_irq(s);
451 }
452 serial_xmit(s, false);
453 }
454 break;
455 case 1:
456 if (s->lcr & UART_LCR_DLAB) {
457 s->divider = (s->divider & 0x00ff) | (val << 8);
458 serial_update_parameters(s);
459 } else {
460 s->ier = val & 0x0f;
461 if (s->lsr & UART_LSR_THRE) {
462 s->thr_ipending = 1;
463 serial_update_irq(s);
464 }
465 }
466 break;
467 case 2:
468 if (!s->f16550AEnabled)
469 break;
470
471 val = val & 0xFF;
472
473 if (s->fcr == val)
474 break;
475
476 /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
477 if ((val ^ s->fcr) & UART_FCR_FE)
478 val |= UART_FCR_XFR | UART_FCR_RFR;
479
480 /* FIFO clear */
481 if (val & UART_FCR_RFR) {
482 TMTimerStop(s->fifo_timeout_timer);
483 s->timeout_ipending = 0;
484 fifo_clear(s, RECV_FIFO);
485 }
486 if (val & UART_FCR_XFR) {
487 fifo_clear(s, XMIT_FIFO);
488 }
489
490 if (val & UART_FCR_FE) {
491 s->iir |= UART_IIR_FE;
492 /* Set RECV_FIFO trigger Level */
493 switch (val & 0xC0) {
494 case UART_FCR_ITL_1:
495 s->recv_fifo.itl = 1;
496 break;
497 case UART_FCR_ITL_2:
498 s->recv_fifo.itl = 4;
499 break;
500 case UART_FCR_ITL_3:
501 s->recv_fifo.itl = 8;
502 break;
503 case UART_FCR_ITL_4:
504 s->recv_fifo.itl = 14;
505 break;
506 }
507 } else
508 s->iir &= ~UART_IIR_FE;
509
510 /* Set fcr - or at least the bits in it that are supposed to "stick" */
511 s->fcr = val & 0xC9;
512 serial_update_irq(s);
513 break;
514 case 3:
515 {
516 int break_enable;
517 s->lcr = val;
518 serial_update_parameters(s);
519 break_enable = (val >> 6) & 1;
520 if (break_enable != s->last_break_enable) {
521 s->last_break_enable = break_enable;
522 if (RT_LIKELY(s->pDrvChar))
523 {
524 Log(("serial_ioport_write: Set break %d\n", break_enable));
525 int rc = s->pDrvChar->pfnSetBreak(s->pDrvChar, !!break_enable);
526 AssertRC(rc);
527 }
528 }
529 }
530 break;
531 case 4:
532 s->mcr = val & 0x1f;
533 if (RT_LIKELY(s->pDrvChar))
534 {
535 int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar,
536 !!(s->mcr & UART_MCR_RTS),
537 !!(s->mcr & UART_MCR_DTR));
538 AssertRC(rc);
539 }
540 break;
541 case 5:
542 break;
543 case 6:
544 break;
545 case 7:
546 s->scr = val;
547 break;
548 }
549 return VINF_SUCCESS;
550#endif
551}
552
553static uint32_t serial_ioport_read(void *opaque, uint32_t addr, int *pRC)
554{
555 SerialState *s = (SerialState *)opaque;
556 uint32_t ret = ~0U;
557
558 *pRC = VINF_SUCCESS;
559
560 addr &= 7;
561 switch(addr) {
562 default:
563 case 0:
564 if (s->lcr & UART_LCR_DLAB) {
565 /* DLAB == 1: divisor latch (LS) */
566 ret = s->divider & 0xff;
567 } else {
568#ifndef IN_RING3
569 *pRC = VINF_IOM_HC_IOPORT_READ;
570#else
571 if (s->fcr & UART_FCR_FE) {
572 ret = fifo_get(s, RECV_FIFO);
573 if (s->recv_fifo.count == 0)
574 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
575 else
576 TMTimerSet(s->fifo_timeout_timer,
577 TMTimerGet(s->fifo_timeout_timer) + s->char_transmit_time * 4);
578 s->timeout_ipending = 0;
579 } else {
580 Log(("serial_io_port_read: read 0x%X\n", s->rbr));
581 ret = s->rbr;
582 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
583 }
584 serial_update_irq(s);
585 if (s->fRecvWaiting)
586 {
587 s->fRecvWaiting = false;
588 int rc = RTSemEventSignal(s->ReceiveSem);
589 AssertRC(rc);
590 }
591#endif
592 }
593 break;
594 case 1:
595 if (s->lcr & UART_LCR_DLAB) {
596 /* DLAB == 1: divisor latch (MS) */
597 ret = (s->divider >> 8) & 0xff;
598 } else {
599 ret = s->ier;
600 }
601 break;
602 case 2:
603#ifndef IN_RING3
604 *pRC = VINF_IOM_HC_IOPORT_READ;
605#else
606 ret = s->iir;
607 if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
608 s->thr_ipending = 0;
609 serial_update_irq(s);
610 }
611 /* reset msr changed bit */
612 s->msr_changed = false;
613#endif
614 break;
615 case 3:
616 ret = s->lcr;
617 break;
618 case 4:
619 ret = s->mcr;
620 break;
621 case 5:
622 if ((s->lsr & UART_LSR_DR) == 0 && s->fYieldOnLSRRead)
623 {
624 /* No data available and yielding is enabled, so yield in ring3. */
625#ifndef IN_RING3
626 *pRC = VINF_IOM_HC_IOPORT_READ;
627 break;
628#else
629 RTThreadYield ();
630#endif
631 }
632 ret = s->lsr;
633 /* Clear break and overrun interrupts */
634 if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
635#ifndef IN_RING3
636 *pRC = VINF_IOM_HC_IOPORT_READ;
637#else
638 s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
639 serial_update_irq(s);
640#endif
641 }
642 break;
643 case 6:
644 if (s->mcr & UART_MCR_LOOP) {
645 /* in loopback, the modem output pins are connected to the
646 inputs */
647 ret = (s->mcr & 0x0c) << 4;
648 ret |= (s->mcr & 0x02) << 3;
649 ret |= (s->mcr & 0x01) << 5;
650 } else {
651 ret = s->msr;
652 /* Clear delta bits & msr int after read, if they were set */
653 if (s->msr & UART_MSR_ANY_DELTA) {
654#ifndef IN_RING3
655 *pRC = VINF_IOM_HC_IOPORT_READ;
656#else
657 s->msr &= 0xF0;
658 serial_update_irq(s);
659#endif
660 }
661 }
662 break;
663 case 7:
664 ret = s->scr;
665 break;
666 }
667 return ret;
668}
669
670#ifdef IN_RING3
671
672static int serial_can_receive(SerialState *s)
673{
674 if (s->fcr & UART_FCR_FE) {
675 if (s->recv_fifo.count < UART_FIFO_LENGTH)
676 return (s->recv_fifo.count <= s->recv_fifo.itl)
677 ? s->recv_fifo.itl - s->recv_fifo.count : 1;
678 else
679 return 0;
680 } else {
681 return !(s->lsr & UART_LSR_DR);
682 }
683}
684
685static void serial_receive(void *opaque, const uint8_t *buf, int size)
686{
687 SerialState *s = (SerialState*)opaque;
688 if (s->fcr & UART_FCR_FE) {
689 int i;
690 for (i = 0; i < size; i++) {
691 fifo_put(s, RECV_FIFO, buf[i]);
692 }
693 s->lsr |= UART_LSR_DR;
694 /* call the timeout receive callback in 4 char transmit time */
695 TMTimerSet(s->fifo_timeout_timer, TMTimerGet(s->fifo_timeout_timer) + s->char_transmit_time * 4);
696 } else {
697 if (s->lsr & UART_LSR_DR)
698 s->lsr |= UART_LSR_OE;
699 s->rbr = buf[0];
700 s->lsr |= UART_LSR_DR;
701 }
702 serial_update_irq(s);
703}
704
705/** @copydoc PDMICHARPORT::pfnNotifyRead */
706static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
707{
708 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
709 const uint8_t *pu8Buf = (const uint8_t*)pvBuf;
710 size_t cbRead = *pcbRead;
711
712 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
713 for (; cbRead > 0; cbRead--, pu8Buf++)
714 {
715 if (!serial_can_receive(pThis))
716 {
717 /* If we cannot receive then wait for not more than 250ms. If we still
718 * cannot receive then the new character will either overwrite rbr
719 * or it will be dropped at fifo_put(). */
720 pThis->fRecvWaiting = true;
721 PDMCritSectLeave(&pThis->CritSect);
722 int rc = RTSemEventWait(pThis->ReceiveSem, 250);
723 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
724 }
725 serial_receive(pThis, &pu8Buf[0], 1);
726 }
727 PDMCritSectLeave(&pThis->CritSect);
728 return VINF_SUCCESS;
729}
730
731/** @copydoc PDMICHARPORT::pfnNotifyStatusLinesChanged */
732static DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines)
733{
734 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
735 uint8_t newMsr = 0;
736
737 Log(("%s: pInterface=%p newStatusLines=%u\n", __FUNCTION__, pInterface, newStatusLines));
738
739 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
740
741 /* Set new states. */
742 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DCD)
743 newMsr |= UART_MSR_DCD;
744 if (newStatusLines & PDMICHARPORT_STATUS_LINES_RI)
745 newMsr |= UART_MSR_RI;
746 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DSR)
747 newMsr |= UART_MSR_DSR;
748 if (newStatusLines & PDMICHARPORT_STATUS_LINES_CTS)
749 newMsr |= UART_MSR_CTS;
750
751 /* Compare the old and the new states and set the delta bits accordingly. */
752 if ((newMsr & UART_MSR_DCD) != (pThis->msr & UART_MSR_DCD))
753 newMsr |= UART_MSR_DDCD;
754 if ((newMsr & UART_MSR_RI) == 1 && (pThis->msr & UART_MSR_RI) == 0)
755 newMsr |= UART_MSR_TERI;
756 if ((newMsr & UART_MSR_DSR) != (pThis->msr & UART_MSR_DSR))
757 newMsr |= UART_MSR_DDSR;
758 if ((newMsr & UART_MSR_CTS) != (pThis->msr & UART_MSR_CTS))
759 newMsr |= UART_MSR_DCTS;
760
761 pThis->msr = newMsr;
762 pThis->msr_changed = true;
763 serial_update_irq(pThis);
764
765 PDMCritSectLeave(&pThis->CritSect);
766
767 return VINF_SUCCESS;
768}
769
770/** @copydoc PDMICHARPORT::pfnNotifyBufferFull */
771static DECLCALLBACK(int) serialNotifyBufferFull(PPDMICHARPORT pInterface, bool fFull)
772{
773 return VINF_SUCCESS;
774}
775
776/** @copydoc PDMICHARPORT::pfnNotifyBreak */
777static DECLCALLBACK(int) serialNotifyBreak(PPDMICHARPORT pInterface)
778{
779 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
780
781 Log(("%s: pInterface=%p\n", __FUNCTION__, pInterface));
782
783 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
784
785 pThis->lsr |= UART_LSR_BI;
786 serial_update_irq(pThis);
787
788 PDMCritSectLeave(&pThis->CritSect);
789
790 return VINF_SUCCESS;
791}
792
793/**
794 * Fifo timer functions.
795 */
796static DECLCALLBACK(void) serialFifoTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
797{
798 SerialState *s = (SerialState*)pvUser;
799 if (s->recv_fifo.count)
800 {
801 s->timeout_ipending = 1;
802 serial_update_irq(s);
803 }
804}
805
806/**
807 * Transmit timer function.
808 * Just retry to transmit a character.
809 *
810 * @param pTimer The timer handle.
811 * @param pDevIns The device instance.
812 * @param pvUser The user pointer.
813 */
814static DECLCALLBACK(void) serialTransmitTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
815{
816 SerialState *s = (SerialState*)pvUser;
817 serial_xmit(s, true);
818}
819
820/**
821 * Reset the serial device.
822 *
823 * @param pDevIns The device instance.
824 */
825static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
826{
827 SerialState *s = PDMINS_2_DATA(pDevIns, SerialState *);
828
829 s->rbr = 0;
830 s->ier = 0;
831 s->iir = UART_IIR_NO_INT;
832 s->lcr = 0;
833 s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
834 s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
835 /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
836 s->divider = 0x0C;
837 s->mcr = UART_MCR_OUT2;
838 s->scr = 0;
839 s->tsr_retry = 0;
840 s->char_transmit_time = (TMTimerGetFreq(CTX_SUFF(s->transmit_timer)) / 9600) * 10;
841
842 fifo_clear(s, RECV_FIFO);
843 fifo_clear(s, XMIT_FIFO);
844
845 s->thr_ipending = 0;
846 s->last_break_enable = 0;
847# ifdef VBOX_SERIAL_PCI
848 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0);
849# else /* !VBOX_SERIAL_PCI */
850 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
851# endif /* !VBOX_SERIAL_PCI */
852}
853
854#endif /* IN_RING3 */
855
856/**
857 * Port I/O Handler for OUT operations.
858 *
859 * @returns VBox status code.
860 *
861 * @param pDevIns The device instance.
862 * @param pvUser User argument.
863 * @param Port Port number used for the IN operation.
864 * @param u32 The value to output.
865 * @param cb The value size in bytes.
866 */
867PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
868 RTIOPORT Port, uint32_t u32, unsigned cb)
869{
870 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
871 int rc = VINF_SUCCESS;
872
873 if (cb == 1)
874 {
875 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
876 if (rc == VINF_SUCCESS)
877 {
878 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
879 rc = serial_ioport_write(pThis, Port, u32);
880 PDMCritSectLeave(&pThis->CritSect);
881 }
882 }
883 else
884 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
885
886 return rc;
887}
888
889/**
890 * Port I/O Handler for IN operations.
891 *
892 * @returns VBox status code.
893 *
894 * @param pDevIns The device instance.
895 * @param pvUser User argument.
896 * @param Port Port number used for the IN operation.
897 * @param u32 The value to output.
898 * @param cb The value size in bytes.
899 */
900PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
901 RTIOPORT Port, uint32_t *pu32, unsigned cb)
902{
903 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
904 int rc = VINF_SUCCESS;
905
906 if (cb == 1)
907 {
908 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
909 if (rc == VINF_SUCCESS)
910 {
911 *pu32 = serial_ioport_read(pThis, Port, &rc);
912 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
913 PDMCritSectLeave(&pThis->CritSect);
914 }
915 }
916 else
917 rc = VERR_IOM_IOPORT_UNUSED;
918
919 return rc;
920}
921
922#ifdef IN_RING3
923
924/**
925 * @copydoc FNSSMDEVLIVEEXEC
926 */
927static DECLCALLBACK(int) serialLiveExec(PPDMDEVINS pDevIns,
928 PSSMHANDLE pSSM,
929 uint32_t uPass)
930{
931 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
932 SSMR3PutS32(pSSM, pThis->irq);
933 SSMR3PutU32(pSSM, pThis->base);
934 return VINF_SSM_DONT_CALL_AGAIN;
935}
936
937/**
938 * @copydoc FNSSMDEVSAVEEXEC
939 */
940static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
941 PSSMHANDLE pSSM)
942{
943 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
944
945 SSMR3PutU16(pSSM, pThis->divider);
946 SSMR3PutU8(pSSM, pThis->rbr);
947 SSMR3PutU8(pSSM, pThis->ier);
948 SSMR3PutU8(pSSM, pThis->lcr);
949 SSMR3PutU8(pSSM, pThis->mcr);
950 SSMR3PutU8(pSSM, pThis->lsr);
951 SSMR3PutU8(pSSM, pThis->msr);
952 SSMR3PutU8(pSSM, pThis->scr);
953 SSMR3PutU8(pSSM, pThis->fcr); /* 16550A */
954 SSMR3PutS32(pSSM, pThis->thr_ipending);
955 SSMR3PutS32(pSSM, pThis->irq);
956 SSMR3PutS32(pSSM, pThis->last_break_enable);
957 SSMR3PutU32(pSSM, pThis->base);
958 SSMR3PutBool(pSSM, pThis->msr_changed);
959
960 /* Don't store:
961 * - the content of the FIFO
962 * - tsr_retry
963 */
964
965 return SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
966}
967
968/**
969 * @copydoc FNSSMDEVLOADEXEC
970 */
971static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
972 PSSMHANDLE pSSM,
973 uint32_t uVersion,
974 uint32_t uPass)
975{
976 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
977
978 if (uVersion == SERIAL_SAVED_STATE_VERSION_16450)
979 {
980 pThis->f16550AEnabled = false;
981 LogRel(("Serial#%d: falling back to 16450 mode from load state\n", pDevIns->iInstance));
982 }
983 else
984 AssertMsgReturn(uVersion == SERIAL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
985
986 if (uPass == SSM_PASS_FINAL)
987 {
988 SSMR3GetU16(pSSM, &pThis->divider);
989 SSMR3GetU8(pSSM, &pThis->rbr);
990 SSMR3GetU8(pSSM, &pThis->ier);
991 SSMR3GetU8(pSSM, &pThis->lcr);
992 SSMR3GetU8(pSSM, &pThis->mcr);
993 SSMR3GetU8(pSSM, &pThis->lsr);
994 SSMR3GetU8(pSSM, &pThis->msr);
995 SSMR3GetU8(pSSM, &pThis->scr);
996 if (uVersion > SERIAL_SAVED_STATE_VERSION_16450)
997 {
998 SSMR3GetU8(pSSM, &pThis->fcr);
999 }
1000 SSMR3GetS32(pSSM, &pThis->thr_ipending);
1001 }
1002
1003 int32_t iIrq;
1004 SSMR3GetS32(pSSM, &iIrq);
1005
1006 if (uPass == SSM_PASS_FINAL)
1007 SSMR3GetS32(pSSM, &pThis->last_break_enable);
1008
1009 uint32_t IOBase;
1010 int rc = SSMR3GetU32(pSSM, &IOBase);
1011 AssertRCReturn(rc, rc);
1012
1013 if ( pThis->irq != iIrq
1014 || pThis->base != IOBase)
1015 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1016 N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
1017 iIrq, IOBase, pThis->irq, pThis->base);
1018
1019 if (uPass == SSM_PASS_FINAL)
1020 {
1021 SSMR3GetBool(pSSM, &pThis->msr_changed);
1022
1023 uint32_t u32;
1024 rc = SSMR3GetU32(pSSM, &u32);
1025 if (RT_FAILURE(rc))
1026 return rc;
1027 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1028
1029 if ( (pThis->lsr & UART_LSR_DR)
1030 || pThis->fRecvWaiting)
1031 {
1032 pThis->fRecvWaiting = false;
1033 rc = RTSemEventSignal(pThis->ReceiveSem);
1034 AssertRC(rc);
1035 }
1036
1037 /* this isn't strictly necessary but cannot hurt... */
1038 pThis->pDevInsR3 = pDevIns;
1039 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1040 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1041 }
1042
1043 return VINF_SUCCESS;
1044}
1045
1046
1047/**
1048 * @copydoc FNPDMDEVRELOCATE
1049 */
1050static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1051{
1052 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
1053 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1054 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
1055}
1056
1057#ifdef VBOX_SERIAL_PCI
1058
1059static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1060{
1061 SerialState *pThis = PCIDEV_2_SERIALSTATE(pPciDev);
1062 int rc = VINF_SUCCESS;
1063
1064 Assert(enmType == PCI_ADDRESS_SPACE_IO);
1065 Assert(iRegion == 0);
1066 Assert(cb == 8);
1067 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
1068
1069 pThis->base = (RTIOPORT)GCPhysAddress;
1070 LogRel(("Serial#%d: mapping I/O at %#06x\n", pThis->pDevIns->iInstance, pThis->base));
1071
1072 /*
1073 * Register our port IO handlers.
1074 */
1075 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
1076 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
1077 AssertRC(rc);
1078 return rc;
1079}
1080
1081#endif /* VBOX_SERIAL_PCI */
1082
1083/**
1084 * @interface_method_impl{PDMIBASE, pfnQueryInterface}
1085 */
1086static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1087{
1088 SerialState *pThis = PDMIBASE_2_SERIALSTATE(pInterface);
1089 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
1090 PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARPORT, &pThis->ICharPort);
1091 return NULL;
1092}
1093
1094/**
1095 * Destruct a device instance.
1096 *
1097 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1098 * resources can be freed correctly.
1099 *
1100 * @returns VBox status.
1101 * @param pDevIns The device instance data.
1102 */
1103static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
1104{
1105 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
1106 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1107
1108 RTSemEventDestroy(pThis->ReceiveSem);
1109 pThis->ReceiveSem = NIL_RTSEMEVENT;
1110
1111 PDMR3CritSectDelete(&pThis->CritSect);
1112 return VINF_SUCCESS;
1113}
1114
1115
1116/**
1117 * @interface_method_impl{PDMDEVREG, pfnConstruct}
1118 */
1119static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1120{
1121 int rc;
1122 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState*);
1123 uint16_t io_base;
1124 uint8_t irq_lvl;
1125
1126 Assert(iInstance < 4);
1127 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1128
1129 /*
1130 * Initialize the instance data.
1131 * (Do this early or the destructor might choke on something!)
1132 */
1133 pThis->pDevInsR3 = pDevIns;
1134 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1135 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1136
1137 /* IBase */
1138 pThis->IBase.pfnQueryInterface = serialQueryInterface;
1139
1140 /* ICharPort */
1141 pThis->ICharPort.pfnNotifyRead = serialNotifyRead;
1142 pThis->ICharPort.pfnNotifyStatusLinesChanged = serialNotifyStatusLinesChanged;
1143 pThis->ICharPort.pfnNotifyBufferFull = serialNotifyBufferFull;
1144 pThis->ICharPort.pfnNotifyBreak = serialNotifyBreak;
1145
1146#ifdef VBOX_SERIAL_PCI
1147 /* the PCI device */
1148 pThis->dev.config[0x00] = 0xee; /* Vendor: ??? */
1149 pThis->dev.config[0x01] = 0x80;
1150 pThis->dev.config[0x02] = 0x01; /* Device: ??? */
1151 pThis->dev.config[0x03] = 0x01;
1152 pThis->dev.config[0x04] = PCI_COMMAND_IOACCESS;
1153 pThis->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
1154 pThis->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
1155 pThis->dev.config[0x0b] = 0x07; /* Class: Communication controller */
1156 pThis->dev.config[0x0e] = 0x00; /* Header type: standard */
1157 pThis->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
1158 pThis->dev.config[0x3d] = 1; /* interrupt pin 0 */
1159#endif /* VBOX_SERIAL_PCI */
1160
1161 /*
1162 * Validate and read the configuration.
1163 */
1164 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
1165 "IOBase\0"
1166 "GCEnabled\0"
1167 "R0Enabled\0"
1168 "YieldOnLSRRead\0"
1169 "Enable16550A\0"
1170 ))
1171 {
1172 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
1173 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1174 }
1175
1176 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
1177 if (RT_FAILURE(rc))
1178 return PDMDEV_SET_ERROR(pDevIns, rc,
1179 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
1180
1181 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
1182 if (RT_FAILURE(rc))
1183 return PDMDEV_SET_ERROR(pDevIns, rc,
1184 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
1185
1186 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
1187 if (RT_FAILURE(rc))
1188 return PDMDEV_SET_ERROR(pDevIns, rc,
1189 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
1190
1191 rc = CFGMR3QueryU8(pCfg, "IRQ", &irq_lvl);
1192 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1193 {
1194 /* Provide sensible defaults. */
1195 if (iInstance == 0)
1196 irq_lvl = 4;
1197 else if (iInstance == 1)
1198 irq_lvl = 3;
1199 else
1200 AssertReleaseFailed(); /* irq_lvl is undefined. */
1201 }
1202 else if (RT_FAILURE(rc))
1203 return PDMDEV_SET_ERROR(pDevIns, rc,
1204 N_("Configuration error: Failed to get the \"IRQ\" value"));
1205
1206 rc = CFGMR3QueryU16(pCfg, "IOBase", &io_base);
1207 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1208 {
1209 if (iInstance == 0)
1210 io_base = 0x3f8;
1211 else if (iInstance == 1)
1212 io_base = 0x2f8;
1213 else
1214 AssertReleaseFailed(); /* io_base is undefined */
1215 }
1216 else if (RT_FAILURE(rc))
1217 return PDMDEV_SET_ERROR(pDevIns, rc,
1218 N_("Configuration error: Failed to get the \"IOBase\" value"));
1219
1220 Log(("DevSerial: instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
1221
1222 rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
1223 if (RT_FAILURE(rc))
1224 return PDMDEV_SET_ERROR(pDevIns, rc,
1225 N_("Configuration error: Failed to get the \"Enable16550A\" value"));
1226
1227 pThis->irq = irq_lvl;
1228#ifdef VBOX_SERIAL_PCI
1229 pThis->base = -1;
1230#else
1231 pThis->base = io_base;
1232#endif
1233
1234 LogRel(("Serial#%d: emulating %s\n", pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450"));
1235
1236 /*
1237 * Initialize critical section and the semaphore.
1238 * This must of course be done before attaching drivers or anything else which can call us back..
1239 */
1240 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
1241 if (RT_FAILURE(rc))
1242 return rc;
1243
1244 rc = RTSemEventCreate(&pThis->ReceiveSem);
1245 AssertRC(rc);
1246
1247 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialFifoTimer, pThis,
1248 TMTIMER_FLAGS_NO_CRIT_SECT, "Serial Fifo Timer",
1249 &pThis->fifo_timeout_timer);
1250 AssertRC(rc);
1251
1252 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialTransmitTimer, pThis,
1253 TMTIMER_FLAGS_NO_CRIT_SECT, "Serial Transmit Timer",
1254 &pThis->transmit_timerR3);
1255 AssertRC(rc);
1256 pThis->transmit_timerR0 = TMTimerR0Ptr(pThis->transmit_timerR3);
1257 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
1258
1259 serialReset(pDevIns);
1260
1261#ifdef VBOX_SERIAL_PCI
1262 /*
1263 * Register the PCI Device and region.
1264 */
1265 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
1266 if (RT_FAILURE(rc))
1267 return rc;
1268 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
1269 if (RT_FAILURE(rc))
1270 return rc;
1271
1272#else /* !VBOX_SERIAL_PCI */
1273 /*
1274 * Register the I/O ports.
1275 */
1276 pThis->base = io_base;
1277 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
1278 serialIOPortWrite, serialIOPortRead,
1279 NULL, NULL, "SERIAL");
1280 if (RT_FAILURE(rc))
1281 return rc;
1282
1283 if (pThis->fGCEnabled)
1284 {
1285 rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
1286 "serialIOPortRead", NULL, NULL, "Serial");
1287 if (RT_FAILURE(rc))
1288 return rc;
1289 }
1290
1291 if (pThis->fR0Enabled)
1292 {
1293 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
1294 "serialIOPortRead", NULL, NULL, "Serial");
1295 if (RT_FAILURE(rc))
1296 return rc;
1297 }
1298#endif /* !VBOX_SERIAL_PCI */
1299
1300 /*
1301 * Saved state.
1302 */
1303 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
1304 serialLiveExec, serialSaveExec, serialLoadExec);
1305 if (RT_FAILURE(rc))
1306 return rc;
1307
1308 /*
1309 * Attach the char driver and get the interfaces.
1310 * For now no run-time changes are supported.
1311 */
1312 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
1313 if (RT_SUCCESS(rc))
1314 {
1315 pThis->pDrvChar = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMICHARCONNECTOR);
1316 if (!pThis->pDrvChar)
1317 {
1318 AssertLogRelMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
1319 return VERR_PDM_MISSING_INTERFACE;
1320 }
1321 /** @todo provide read notification interface!!!! */
1322 }
1323 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1324 {
1325 pThis->pDrvBase = NULL;
1326 pThis->pDrvChar = NULL;
1327 LogRel(("Serial%d: no unit\n", iInstance));
1328 }
1329 else
1330 {
1331 AssertLogRelMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1332 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1333 return rc;
1334 }
1335
1336 return VINF_SUCCESS;
1337}
1338
1339
1340/**
1341 * The device registration structure.
1342 */
1343const PDMDEVREG g_DeviceSerialPort =
1344{
1345 /* u32Version */
1346 PDM_DEVREG_VERSION,
1347 /* szName */
1348 "serial",
1349 /* szRCMod */
1350 "VBoxDDGC.gc",
1351 /* szR0Mod */
1352 "VBoxDDR0.r0",
1353 /* pszDescription */
1354 "Serial Communication Port",
1355 /* fFlags */
1356 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1357 /* fClass */
1358 PDM_DEVREG_CLASS_SERIAL,
1359 /* cMaxInstances */
1360 UINT32_MAX,
1361 /* cbInstance */
1362 sizeof(SerialState),
1363 /* pfnConstruct */
1364 serialConstruct,
1365 /* pfnDestruct */
1366 serialDestruct,
1367 /* pfnRelocate */
1368 serialRelocate,
1369 /* pfnIOCtl */
1370 NULL,
1371 /* pfnPowerOn */
1372 NULL,
1373 /* pfnReset */
1374 serialReset,
1375 /* pfnSuspend */
1376 NULL,
1377 /* pfnResume */
1378 NULL,
1379 /* pfnAttach */
1380 NULL,
1381 /* pfnDetach */
1382 NULL,
1383 /* pfnQueryInterface. */
1384 NULL,
1385 /* pfnInitComplete */
1386 NULL,
1387 /* pfnPowerOff */
1388 NULL,
1389 /* pfnSoftReset */
1390 NULL,
1391 /* u32VersionEnd */
1392 PDM_DEVREG_VERSION
1393};
1394#endif /* IN_RING3 */
1395
1396#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette