VirtualBox

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

Last change on this file since 61497 was 58132, checked in by vboxsync, 9 years ago

*: Doxygen fixes.

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