VirtualBox

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

Last change on this file since 69162 was 64393, checked in by vboxsync, 8 years ago

PDMPCIDEV: s/config/abConfig/ everywhere, removing the legacy alias.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.1 KB
Line 
1/* $Id: DevSerial.cpp 64393 2016-10-24 14:42:05Z 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-2016 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 PDMPCIDEV 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#ifndef IN_RING3
446 NOREF(pThis); RT_NOREF_PV(addr); RT_NOREF_PV(val);
447 return VINF_IOM_R3_IOPORT_WRITE;
448#else
449 addr &= 7;
450 switch(addr) {
451 default:
452 case 0:
453 if (pThis->lcr & UART_LCR_DLAB) {
454 pThis->divider = (pThis->divider & 0xff00) | val;
455 serial_update_parameters(pThis);
456 } else {
457 pThis->thr = (uint8_t) val;
458 if (pThis->fcr & UART_FCR_FE) {
459 fifo_put(pThis, XMIT_FIFO, pThis->thr);
460 pThis->thr_ipending = 0;
461 pThis->lsr &= ~UART_LSR_TEMT;
462 pThis->lsr &= ~UART_LSR_THRE;
463 serial_update_irq(pThis);
464 } else {
465 pThis->thr_ipending = 0;
466 pThis->lsr &= ~UART_LSR_THRE;
467 serial_update_irq(pThis);
468 }
469 serial_xmit(pThis, false);
470 }
471 break;
472 case 1:
473 if (pThis->lcr & UART_LCR_DLAB) {
474 pThis->divider = (pThis->divider & 0x00ff) | (val << 8);
475 serial_update_parameters(pThis);
476 } else {
477 pThis->ier = val & 0x0f;
478 if (pThis->lsr & UART_LSR_THRE) {
479 pThis->thr_ipending = 1;
480 serial_update_irq(pThis);
481 }
482 }
483 break;
484 case 2:
485 if (!pThis->f16550AEnabled)
486 break;
487
488 val = val & 0xFF;
489
490 if (pThis->fcr == val)
491 break;
492
493 /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
494 if ((val ^ pThis->fcr) & UART_FCR_FE)
495 val |= UART_FCR_XFR | UART_FCR_RFR;
496
497 /* FIFO clear */
498 if (val & UART_FCR_RFR) {
499 TMTimerStop(pThis->fifo_timeout_timer);
500 pThis->timeout_ipending = 0;
501 fifo_clear(pThis, RECV_FIFO);
502 }
503 if (val & UART_FCR_XFR) {
504 fifo_clear(pThis, XMIT_FIFO);
505 }
506
507 if (val & UART_FCR_FE) {
508 pThis->iir |= UART_IIR_FE;
509 /* Set RECV_FIFO trigger Level */
510 switch (val & 0xC0) {
511 case UART_FCR_ITL_1:
512 pThis->recv_fifo.itl = 1;
513 break;
514 case UART_FCR_ITL_2:
515 pThis->recv_fifo.itl = 4;
516 break;
517 case UART_FCR_ITL_3:
518 pThis->recv_fifo.itl = 8;
519 break;
520 case UART_FCR_ITL_4:
521 pThis->recv_fifo.itl = 14;
522 break;
523 }
524 } else
525 pThis->iir &= ~UART_IIR_FE;
526
527 /* Set fcr - or at least the bits in it that are supposed to "stick" */
528 pThis->fcr = val & 0xC9;
529 serial_update_irq(pThis);
530 break;
531 case 3:
532 {
533 int break_enable;
534 pThis->lcr = val;
535 serial_update_parameters(pThis);
536 break_enable = (val >> 6) & 1;
537 if (break_enable != pThis->last_break_enable) {
538 pThis->last_break_enable = break_enable;
539 if (RT_LIKELY(pThis->pDrvChar))
540 {
541 Log(("serial_ioport_write: Set break %d\n", break_enable));
542 int rc = pThis->pDrvChar->pfnSetBreak(pThis->pDrvChar, !!break_enable);
543 AssertRC(rc);
544 }
545 }
546 }
547 break;
548 case 4:
549 pThis->mcr = val & 0x1f;
550 if (RT_LIKELY(pThis->pDrvChar))
551 {
552 int rc = pThis->pDrvChar->pfnSetModemLines(pThis->pDrvChar,
553 !!(pThis->mcr & UART_MCR_RTS),
554 !!(pThis->mcr & UART_MCR_DTR));
555 AssertRC(rc);
556 }
557 break;
558 case 5:
559 break;
560 case 6:
561 break;
562 case 7:
563 pThis->scr = val;
564 break;
565 }
566 return VINF_SUCCESS;
567#endif
568}
569
570static uint32_t serial_ioport_read(PDEVSERIAL pThis, uint32_t addr, int *pRC)
571{
572 uint32_t ret = ~0U;
573
574 *pRC = VINF_SUCCESS;
575
576 addr &= 7;
577 switch(addr) {
578 default:
579 case 0:
580 if (pThis->lcr & UART_LCR_DLAB) {
581 /* DLAB == 1: divisor latch (LS) */
582 ret = pThis->divider & 0xff;
583 } else {
584#ifndef IN_RING3
585 *pRC = VINF_IOM_R3_IOPORT_READ;
586#else
587 if (pThis->fcr & UART_FCR_FE) {
588 ret = fifo_get(pThis, RECV_FIFO);
589 if (pThis->recv_fifo.count == 0)
590 pThis->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
591 else
592 TMTimerSet(pThis->fifo_timeout_timer,
593 TMTimerGet(pThis->fifo_timeout_timer) + pThis->char_transmit_time * 4);
594 pThis->timeout_ipending = 0;
595 } else {
596 Log(("serial_io_port_read: read 0x%X\n", pThis->rbr));
597 ret = pThis->rbr;
598 pThis->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
599 }
600 serial_update_irq(pThis);
601 if (pThis->fRecvWaiting)
602 {
603 pThis->fRecvWaiting = false;
604 int rc = RTSemEventSignal(pThis->ReceiveSem);
605 AssertRC(rc);
606 }
607#endif
608 }
609 break;
610 case 1:
611 if (pThis->lcr & UART_LCR_DLAB) {
612 /* DLAB == 1: divisor latch (MS) */
613 ret = (pThis->divider >> 8) & 0xff;
614 } else {
615 ret = pThis->ier;
616 }
617 break;
618 case 2:
619#ifndef IN_RING3
620 *pRC = VINF_IOM_R3_IOPORT_READ;
621#else
622 ret = pThis->iir;
623 if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
624 pThis->thr_ipending = 0;
625 serial_update_irq(pThis);
626 }
627 /* reset msr changed bit */
628 pThis->msr_changed = false;
629#endif
630 break;
631 case 3:
632 ret = pThis->lcr;
633 break;
634 case 4:
635 ret = pThis->mcr;
636 break;
637 case 5:
638 if ((pThis->lsr & UART_LSR_DR) == 0 && pThis->fYieldOnLSRRead)
639 {
640 /* No data available and yielding is enabled, so yield in ring3. */
641#ifndef IN_RING3
642 *pRC = VINF_IOM_R3_IOPORT_READ;
643 break;
644#else
645 RTThreadYield ();
646#endif
647 }
648 ret = pThis->lsr;
649 /* Clear break and overrun interrupts */
650 if (pThis->lsr & (UART_LSR_BI|UART_LSR_OE)) {
651#ifndef IN_RING3
652 *pRC = VINF_IOM_R3_IOPORT_READ;
653#else
654 pThis->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
655 serial_update_irq(pThis);
656#endif
657 }
658 break;
659 case 6:
660 if (pThis->mcr & UART_MCR_LOOP) {
661 /* in loopback, the modem output pins are connected to the
662 inputs */
663 ret = (pThis->mcr & 0x0c) << 4;
664 ret |= (pThis->mcr & 0x02) << 3;
665 ret |= (pThis->mcr & 0x01) << 5;
666 } else {
667 ret = pThis->msr;
668 /* Clear delta bits & msr int after read, if they were set */
669 if (pThis->msr & UART_MSR_ANY_DELTA) {
670#ifndef IN_RING3
671 *pRC = VINF_IOM_R3_IOPORT_READ;
672#else
673 pThis->msr &= 0xF0;
674 serial_update_irq(pThis);
675#endif
676 }
677 }
678 break;
679 case 7:
680 ret = pThis->scr;
681 break;
682 }
683 return ret;
684}
685
686#ifdef IN_RING3
687
688static int serial_can_receive(PDEVSERIAL pThis)
689{
690 if (pThis->fcr & UART_FCR_FE) {
691 if (pThis->recv_fifo.count < UART_FIFO_LENGTH)
692 return (pThis->recv_fifo.count <= pThis->recv_fifo.itl)
693 ? pThis->recv_fifo.itl - pThis->recv_fifo.count : 1;
694 else
695 return 0;
696 } else {
697 return !(pThis->lsr & UART_LSR_DR);
698 }
699}
700
701static void serial_receive(PDEVSERIAL pThis, const uint8_t *buf, int size)
702{
703 if (pThis->fcr & UART_FCR_FE) {
704 int i;
705 for (i = 0; i < size; i++) {
706 fifo_put(pThis, RECV_FIFO, buf[i]);
707 }
708 pThis->lsr |= UART_LSR_DR;
709 /* call the timeout receive callback in 4 char transmit time */
710 TMTimerSet(pThis->fifo_timeout_timer, TMTimerGet(pThis->fifo_timeout_timer) + pThis->char_transmit_time * 4);
711 } else {
712 if (pThis->lsr & UART_LSR_DR)
713 pThis->lsr |= UART_LSR_OE;
714 pThis->rbr = buf[0];
715 pThis->lsr |= UART_LSR_DR;
716 }
717 serial_update_irq(pThis);
718}
719
720
721/**
722 * @interface_method_impl{PDMICHARPORT,pfnNotifyRead}
723 */
724static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
725{
726 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ICharPort);
727 const uint8_t *pu8Buf = (const uint8_t*)pvBuf;
728 size_t cbRead = *pcbRead;
729
730 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
731 for (; cbRead > 0; cbRead--, pu8Buf++)
732 {
733 if (!serial_can_receive(pThis))
734 {
735 /* If we cannot receive then wait for not more than 250ms. If we still
736 * cannot receive then the new character will either overwrite rbr
737 * or it will be dropped at fifo_put(). */
738 pThis->fRecvWaiting = true;
739 PDMCritSectLeave(&pThis->CritSect);
740 RTSemEventWait(pThis->ReceiveSem, 250);
741 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
742 }
743 serial_receive(pThis, &pu8Buf[0], 1);
744 }
745 PDMCritSectLeave(&pThis->CritSect);
746 return VINF_SUCCESS;
747}
748
749/**
750 * @@interface_method_impl{PDMICHARPORT,pfnNotifyStatusLinesChanged}
751 */
752static DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines)
753{
754 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ICharPort);
755 uint8_t newMsr = 0;
756
757 Log(("%s: pInterface=%p newStatusLines=%u\n", __FUNCTION__, pInterface, newStatusLines));
758
759 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
760
761 /* Set new states. */
762 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DCD)
763 newMsr |= UART_MSR_DCD;
764 if (newStatusLines & PDMICHARPORT_STATUS_LINES_RI)
765 newMsr |= UART_MSR_RI;
766 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DSR)
767 newMsr |= UART_MSR_DSR;
768 if (newStatusLines & PDMICHARPORT_STATUS_LINES_CTS)
769 newMsr |= UART_MSR_CTS;
770
771 /* Compare the old and the new states and set the delta bits accordingly. */
772 if ((newMsr & UART_MSR_DCD) != (pThis->msr & UART_MSR_DCD))
773 newMsr |= UART_MSR_DDCD;
774 if ((newMsr & UART_MSR_RI) != 0 && (pThis->msr & UART_MSR_RI) == 0)
775 newMsr |= UART_MSR_TERI;
776 if ((newMsr & UART_MSR_DSR) != (pThis->msr & UART_MSR_DSR))
777 newMsr |= UART_MSR_DDSR;
778 if ((newMsr & UART_MSR_CTS) != (pThis->msr & UART_MSR_CTS))
779 newMsr |= UART_MSR_DCTS;
780
781 pThis->msr = newMsr;
782 pThis->msr_changed = true;
783 serial_update_irq(pThis);
784
785 PDMCritSectLeave(&pThis->CritSect);
786
787 return VINF_SUCCESS;
788}
789
790
791/**
792 * @interface_method_impl{PDMICHARPORT,pfnNotifyBufferFull}
793 */
794static DECLCALLBACK(int) serialNotifyBufferFull(PPDMICHARPORT pInterface, bool fFull)
795{
796 RT_NOREF(pInterface, fFull);
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 RT_NOREF(pDevIns, pTimer);
829 PDEVSERIAL pThis = (PDEVSERIAL)pvUser;
830 Assert(PDMCritSectIsOwner(&pThis->CritSect));
831 if (pThis->recv_fifo.count)
832 {
833 pThis->timeout_ipending = 1;
834 serial_update_irq(pThis);
835 }
836}
837
838/**
839 * @callback_method_impl{FNTMTIMERDEV, Transmit timer function.}
840 *
841 * Just retry to transmit a character.
842 */
843static DECLCALLBACK(void) serialTransmitTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
844{
845 RT_NOREF(pDevIns, pTimer);
846 PDEVSERIAL pThis = (PDEVSERIAL)pvUser;
847 Assert(PDMCritSectIsOwner(&pThis->CritSect));
848 serial_xmit(pThis, true);
849}
850
851#endif /* IN_RING3 */
852
853/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
854
855/**
856 * @callback_method_impl{FNIOMIOPORTOUT}
857 */
858PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
859{
860 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
861 int rc;
862 Assert(PDMCritSectIsOwner(&pThis->CritSect));
863 RT_NOREF_PV(pvUser);
864
865 if (cb == 1)
866 {
867 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, uPort, u32));
868 rc = serial_ioport_write(pThis, uPort, u32);
869 }
870 else
871 {
872 AssertMsgFailed(("uPort=%#x cb=%d u32=%#x\n", uPort, cb, u32));
873 rc = VINF_SUCCESS;
874 }
875
876 return rc;
877}
878
879
880/**
881 * @callback_method_impl{FNIOMIOPORTIN}
882 */
883PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
884{
885 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
886 int rc;
887 Assert(PDMCritSectIsOwner(&pThis->CritSect));
888 RT_NOREF_PV(pvUser);
889
890 if (cb == 1)
891 {
892 *pu32 = serial_ioport_read(pThis, uPort, &rc);
893 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, uPort, *pu32));
894 }
895 else
896 rc = VERR_IOM_IOPORT_UNUSED;
897
898 return rc;
899}
900
901#ifdef IN_RING3
902
903/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
904
905/**
906 * @callback_method_impl{FNSSMDEVLIVEEXEC}
907 */
908static DECLCALLBACK(int) serialLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
909{
910 RT_NOREF(uPass);
911 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
912 SSMR3PutS32(pSSM, pThis->irq);
913 SSMR3PutU32(pSSM, pThis->base);
914 return VINF_SSM_DONT_CALL_AGAIN;
915}
916
917
918/**
919 * @callback_method_impl{FNSSMDEVSAVEEXEC}
920 */
921static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
922{
923 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
924
925 SSMR3PutU16(pSSM, pThis->divider);
926 SSMR3PutU8(pSSM, pThis->rbr);
927 SSMR3PutU8(pSSM, pThis->ier);
928 SSMR3PutU8(pSSM, pThis->lcr);
929 SSMR3PutU8(pSSM, pThis->mcr);
930 SSMR3PutU8(pSSM, pThis->lsr);
931 SSMR3PutU8(pSSM, pThis->msr);
932 SSMR3PutU8(pSSM, pThis->scr);
933 SSMR3PutU8(pSSM, pThis->fcr); /* 16550A */
934 SSMR3PutS32(pSSM, pThis->thr_ipending);
935 SSMR3PutS32(pSSM, pThis->irq);
936 SSMR3PutS32(pSSM, pThis->last_break_enable);
937 SSMR3PutU32(pSSM, pThis->base);
938 SSMR3PutBool(pSSM, pThis->msr_changed);
939
940 /* Version 5, safe everything that might be of importance. Much better than
941 missing relevant bits! */
942 SSMR3PutU8(pSSM, pThis->thr);
943 SSMR3PutU8(pSSM, pThis->tsr);
944 SSMR3PutU8(pSSM, pThis->iir);
945 SSMR3PutS32(pSSM, pThis->timeout_ipending);
946 TMR3TimerSave(pThis->fifo_timeout_timer, pSSM);
947 TMR3TimerSave(pThis->transmit_timerR3, pSSM);
948 SSMR3PutU8(pSSM, pThis->recv_fifo.itl);
949 SSMR3PutU8(pSSM, pThis->xmit_fifo.itl);
950
951 /* Don't store:
952 * - the content of the FIFO
953 * - tsr_retry
954 */
955
956 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
957}
958
959
960/**
961 * @callback_method_impl{FNSSMDEVLOADEXEC}
962 */
963static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
964{
965 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
966 int32_t iIrq;
967 uint32_t IOBase;
968
969 AssertMsgReturn(uVersion >= SERIAL_SAVED_STATE_VERSION_16450, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
970
971 if (uPass != SSM_PASS_FINAL)
972 {
973 SSMR3GetS32(pSSM, &iIrq);
974 int rc = SSMR3GetU32(pSSM, &IOBase);
975 AssertRCReturn(rc, rc);
976 }
977 else
978 {
979 if (uVersion == SERIAL_SAVED_STATE_VERSION_16450)
980 {
981 pThis->f16550AEnabled = false;
982 LogRel(("Serial#%d: falling back to 16450 mode from load state\n", pDevIns->iInstance));
983 }
984
985 SSMR3GetU16(pSSM, &pThis->divider);
986 SSMR3GetU8(pSSM, &pThis->rbr);
987 SSMR3GetU8(pSSM, &pThis->ier);
988 SSMR3GetU8(pSSM, &pThis->lcr);
989 SSMR3GetU8(pSSM, &pThis->mcr);
990 SSMR3GetU8(pSSM, &pThis->lsr);
991 SSMR3GetU8(pSSM, &pThis->msr);
992 SSMR3GetU8(pSSM, &pThis->scr);
993 if (uVersion > SERIAL_SAVED_STATE_VERSION_16450)
994 SSMR3GetU8(pSSM, &pThis->fcr);
995 SSMR3GetS32(pSSM, &pThis->thr_ipending);
996 SSMR3GetS32(pSSM, &iIrq);
997 SSMR3GetS32(pSSM, &pThis->last_break_enable);
998 SSMR3GetU32(pSSM, &IOBase);
999 SSMR3GetBool(pSSM, &pThis->msr_changed);
1000
1001 if (uVersion > SERIAL_SAVED_STATE_VERSION_MISSING_BITS)
1002 {
1003 SSMR3GetU8(pSSM, &pThis->thr);
1004 SSMR3GetU8(pSSM, &pThis->tsr);
1005 SSMR3GetU8(pSSM, &pThis->iir);
1006 SSMR3GetS32(pSSM, &pThis->timeout_ipending);
1007 TMR3TimerLoad(pThis->fifo_timeout_timer, pSSM);
1008 TMR3TimerLoad(pThis->transmit_timerR3, pSSM);
1009 SSMR3GetU8(pSSM, &pThis->recv_fifo.itl);
1010 SSMR3GetU8(pSSM, &pThis->xmit_fifo.itl);
1011 }
1012
1013 /* the marker. */
1014 uint32_t u32;
1015 int rc = SSMR3GetU32(pSSM, &u32);
1016 if (RT_FAILURE(rc))
1017 return rc;
1018 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1019
1020 if ( (pThis->lsr & UART_LSR_DR)
1021 || pThis->fRecvWaiting)
1022 {
1023 pThis->fRecvWaiting = false;
1024 rc = RTSemEventSignal(pThis->ReceiveSem);
1025 AssertRC(rc);
1026 }
1027
1028 /* this isn't strictly necessary but cannot hurt... */
1029 pThis->pDevInsR3 = pDevIns;
1030 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1031 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1032 }
1033
1034 /*
1035 * Check the config.
1036 */
1037 if ( pThis->irq != iIrq
1038 || pThis->base != IOBase)
1039 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1040 N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
1041 iIrq, IOBase, pThis->irq, pThis->base);
1042
1043 return VINF_SUCCESS;
1044}
1045
1046
1047#ifdef VBOX_SERIAL_PCI
1048/* -=-=-=-=-=-=-=-=- PCI Device Callback(s) -=-=-=-=-=-=-=-=- */
1049
1050/**
1051 * @callback_method_impl{FNPCIIOREGIONMAP}
1052 */
1053static DECLCALLBACK(int) serialIOPortRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
1054 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
1055{
1056 PDEVSERIAL pThis = RT_FROM_MEMBER(pPciDev, DEVSERIAL, PciDev);
1057 int rc = VINF_SUCCESS;
1058
1059 Assert(enmType == PCI_ADDRESS_SPACE_IO);
1060 Assert(iRegion == 0);
1061 Assert(cb == 8);
1062 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
1063
1064 pThis->base = (RTIOPORT)GCPhysAddress;
1065 LogRel(("Serial#%d: mapping I/O at %#06x\n", pThis->pDevIns->iInstance, pThis->base));
1066
1067 /*
1068 * Register our port IO handlers.
1069 */
1070 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
1071 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
1072 AssertRC(rc);
1073 return rc;
1074}
1075
1076#endif /* VBOX_SERIAL_PCI */
1077
1078
1079/* -=-=-=-=-=-=-=-=- PDMIBASE on LUN#1 -=-=-=-=-=-=-=-=- */
1080
1081/**
1082 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1083 */
1084static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1085{
1086 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, IBase);
1087 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
1088 PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARPORT, &pThis->ICharPort);
1089 return NULL;
1090}
1091
1092
1093/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
1094
1095/**
1096 * @interface_method_impl{PDMDEVREG,pfnRelocate}
1097 */
1098static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1099{
1100 RT_NOREF(offDelta);
1101 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1102 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1103 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
1104}
1105
1106
1107/**
1108 * @interface_method_impl{PDMDEVREG,pfnReset}
1109 */
1110static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
1111{
1112 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1113
1114 pThis->rbr = 0;
1115 pThis->ier = 0;
1116 pThis->iir = UART_IIR_NO_INT;
1117 pThis->lcr = 0;
1118 pThis->lsr = UART_LSR_TEMT | UART_LSR_THRE;
1119 pThis->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
1120 /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
1121 pThis->divider = 0x0C;
1122 pThis->mcr = UART_MCR_OUT2;
1123 pThis->scr = 0;
1124 pThis->tsr_retry = 0;
1125 uint64_t tf = TMTimerGetFreq(CTX_SUFF(pThis->transmit_timer));
1126 pThis->char_transmit_time = (tf / 9600) * 10;
1127 serial_tsr_retry_update_parameters(pThis, tf);
1128
1129 fifo_clear(pThis, RECV_FIFO);
1130 fifo_clear(pThis, XMIT_FIFO);
1131
1132 pThis->thr_ipending = 0;
1133 pThis->last_break_enable = 0;
1134# ifdef VBOX_SERIAL_PCI
1135 PDMDevHlpPCISetIrqNoWait(pThis->CTX_SUFF(pDevIns), 0, 0);
1136# else /* !VBOX_SERIAL_PCI */
1137 PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->irq, 0);
1138# endif /* !VBOX_SERIAL_PCI */
1139}
1140
1141
1142/**
1143 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1144 */
1145static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
1146{
1147 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1148 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1149
1150 RTSemEventDestroy(pThis->ReceiveSem);
1151 pThis->ReceiveSem = NIL_RTSEMEVENT;
1152
1153 PDMR3CritSectDelete(&pThis->CritSect);
1154 return VINF_SUCCESS;
1155}
1156
1157
1158/**
1159 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1160 */
1161static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1162{
1163 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1164 int rc;
1165 uint16_t io_base;
1166 uint8_t irq_lvl;
1167
1168 Assert(iInstance < 4);
1169 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1170
1171 /*
1172 * Initialize the instance data.
1173 * (Do this early or the destructor might choke on something!)
1174 */
1175 pThis->pDevInsR3 = pDevIns;
1176 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1177 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1178 pThis->ReceiveSem = NIL_RTSEMEVENT;
1179
1180 /* IBase */
1181 pThis->IBase.pfnQueryInterface = serialQueryInterface;
1182
1183 /* ICharPort */
1184 pThis->ICharPort.pfnNotifyRead = serialNotifyRead;
1185 pThis->ICharPort.pfnNotifyStatusLinesChanged = serialNotifyStatusLinesChanged;
1186 pThis->ICharPort.pfnNotifyBufferFull = serialNotifyBufferFull;
1187 pThis->ICharPort.pfnNotifyBreak = serialNotifyBreak;
1188
1189#ifdef VBOX_SERIAL_PCI
1190 /* the PCI device */
1191 pThis->PciDev.abConfig[0x00] = 0xee; /* Vendor: ??? */
1192 pThis->PciDev.abConfig[0x01] = 0x80;
1193 pThis->PciDev.abConfig[0x02] = 0x01; /* Device: ??? */
1194 pThis->PciDev.abConfig[0x03] = 0x01;
1195 pThis->PciDev.abConfig[0x04] = PCI_COMMAND_IOACCESS;
1196 pThis->PciDev.abConfig[0x09] = 0x01; /* Programming interface: 16450 */
1197 pThis->PciDev.abConfig[0x0a] = 0x00; /* Subclass: Serial controller */
1198 pThis->PciDev.abConfig[0x0b] = 0x07; /* Class: Communication controller */
1199 pThis->PciDev.abConfig[0x0e] = 0x00; /* Header type: standard */
1200 pThis->PciDev.abConfig[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
1201 pThis->PciDev.abConfig[0x3d] = 1; /* interrupt pin 0 */
1202#endif /* VBOX_SERIAL_PCI */
1203
1204 /*
1205 * Validate and read the configuration.
1206 */
1207 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
1208 "IOBase\0"
1209 "GCEnabled\0"
1210 "R0Enabled\0"
1211 "YieldOnLSRRead\0"
1212 "Enable16550A\0"
1213 ))
1214 {
1215 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
1216 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1217 }
1218
1219 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
1220 if (RT_FAILURE(rc))
1221 return PDMDEV_SET_ERROR(pDevIns, rc,
1222 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
1223
1224 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
1225 if (RT_FAILURE(rc))
1226 return PDMDEV_SET_ERROR(pDevIns, rc,
1227 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
1228
1229 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
1230 if (RT_FAILURE(rc))
1231 return PDMDEV_SET_ERROR(pDevIns, rc,
1232 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
1233
1234 rc = CFGMR3QueryU8(pCfg, "IRQ", &irq_lvl);
1235 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1236 {
1237 /* Provide sensible defaults. */
1238 if (iInstance == 0)
1239 irq_lvl = 4;
1240 else if (iInstance == 1)
1241 irq_lvl = 3;
1242 else
1243 AssertReleaseFailed(); /* irq_lvl is undefined. */
1244 }
1245 else if (RT_FAILURE(rc))
1246 return PDMDEV_SET_ERROR(pDevIns, rc,
1247 N_("Configuration error: Failed to get the \"IRQ\" value"));
1248
1249 rc = CFGMR3QueryU16(pCfg, "IOBase", &io_base);
1250 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1251 {
1252 if (iInstance == 0)
1253 io_base = 0x3f8;
1254 else if (iInstance == 1)
1255 io_base = 0x2f8;
1256 else
1257 AssertReleaseFailed(); /* io_base is undefined */
1258 }
1259 else if (RT_FAILURE(rc))
1260 return PDMDEV_SET_ERROR(pDevIns, rc,
1261 N_("Configuration error: Failed to get the \"IOBase\" value"));
1262
1263 Log(("DevSerial: instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
1264
1265 rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
1266 if (RT_FAILURE(rc))
1267 return PDMDEV_SET_ERROR(pDevIns, rc,
1268 N_("Configuration error: Failed to get the \"Enable16550A\" value"));
1269
1270 pThis->irq = irq_lvl;
1271#ifdef VBOX_SERIAL_PCI
1272 pThis->base = -1;
1273#else
1274 pThis->base = io_base;
1275#endif
1276
1277 LogRel(("Serial#%d: emulating %s\n", pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450"));
1278
1279 /*
1280 * Initialize critical section and the semaphore. Change the default
1281 * critical section to ours so that TM and IOM will enter it before
1282 * calling us.
1283 *
1284 * Note! This must of be done BEFORE creating timers, registering I/O ports
1285 * and other things which might pick up the default CS or end up
1286 * calling back into the device.
1287 */
1288 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%u", iInstance);
1289 AssertRCReturn(rc, rc);
1290
1291 rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
1292 AssertRCReturn(rc, rc);
1293
1294 rc = RTSemEventCreate(&pThis->ReceiveSem);
1295 AssertRCReturn(rc, rc);
1296
1297 /*
1298 * Create the timers.
1299 */
1300 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialFifoTimer, pThis,
1301 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "Serial Fifo Timer",
1302 &pThis->fifo_timeout_timer);
1303 AssertRCReturn(rc, rc);
1304
1305 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialTransmitTimer, pThis,
1306 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "Serial Transmit Timer",
1307 &pThis->transmit_timerR3);
1308 AssertRCReturn(rc, rc);
1309 pThis->transmit_timerR0 = TMTimerR0Ptr(pThis->transmit_timerR3);
1310 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
1311
1312 serialReset(pDevIns);
1313
1314#ifdef VBOX_SERIAL_PCI
1315 /*
1316 * Register the PCI Device and region.
1317 */
1318 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
1319 if (RT_FAILURE(rc))
1320 return rc;
1321 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
1322 if (RT_FAILURE(rc))
1323 return rc;
1324
1325#else /* !VBOX_SERIAL_PCI */
1326 /*
1327 * Register the I/O ports.
1328 */
1329 pThis->base = io_base;
1330 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
1331 serialIOPortWrite, serialIOPortRead,
1332 NULL, NULL, "SERIAL");
1333 if (RT_FAILURE(rc))
1334 return rc;
1335
1336 if (pThis->fGCEnabled)
1337 {
1338 rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
1339 "serialIOPortRead", NULL, NULL, "Serial");
1340 if (RT_FAILURE(rc))
1341 return rc;
1342 }
1343
1344 if (pThis->fR0Enabled)
1345 {
1346 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
1347 "serialIOPortRead", NULL, NULL, "Serial");
1348 if (RT_FAILURE(rc))
1349 return rc;
1350 }
1351#endif /* !VBOX_SERIAL_PCI */
1352
1353 /*
1354 * Saved state.
1355 */
1356 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
1357 serialLiveExec, serialSaveExec, serialLoadExec);
1358 if (RT_FAILURE(rc))
1359 return rc;
1360
1361 /*
1362 * Attach the char driver and get the interfaces.
1363 * For now no run-time changes are supported.
1364 */
1365 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
1366 if (RT_SUCCESS(rc))
1367 {
1368 pThis->pDrvChar = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMICHARCONNECTOR);
1369 if (!pThis->pDrvChar)
1370 {
1371 AssertLogRelMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
1372 return VERR_PDM_MISSING_INTERFACE;
1373 }
1374 /** @todo provide read notification interface!!!! */
1375 }
1376 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1377 {
1378 pThis->pDrvBase = NULL;
1379 pThis->pDrvChar = NULL;
1380 LogRel(("Serial%d: no unit\n", iInstance));
1381 }
1382 else
1383 {
1384 AssertLogRelMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1385 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1386 return rc;
1387 }
1388
1389 return VINF_SUCCESS;
1390}
1391
1392
1393/**
1394 * The device registration structure.
1395 */
1396const PDMDEVREG g_DeviceSerialPort =
1397{
1398 /* u32Version */
1399 PDM_DEVREG_VERSION,
1400 /* szName */
1401 "serial",
1402 /* szRCMod */
1403 "VBoxDDRC.rc",
1404 /* szR0Mod */
1405 "VBoxDDR0.r0",
1406 /* pszDescription */
1407 "Serial Communication Port",
1408 /* fFlags */
1409 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1410 /* fClass */
1411 PDM_DEVREG_CLASS_SERIAL,
1412 /* cMaxInstances */
1413 UINT32_MAX,
1414 /* cbInstance */
1415 sizeof(DEVSERIAL),
1416 /* pfnConstruct */
1417 serialConstruct,
1418 /* pfnDestruct */
1419 serialDestruct,
1420 /* pfnRelocate */
1421 serialRelocate,
1422 /* pfnMemSetup */
1423 NULL,
1424 /* pfnPowerOn */
1425 NULL,
1426 /* pfnReset */
1427 serialReset,
1428 /* pfnSuspend */
1429 NULL,
1430 /* pfnResume */
1431 NULL,
1432 /* pfnAttach */
1433 NULL,
1434 /* pfnDetach */
1435 NULL,
1436 /* pfnQueryInterface. */
1437 NULL,
1438 /* pfnInitComplete */
1439 NULL,
1440 /* pfnPowerOff */
1441 NULL,
1442 /* pfnSoftReset */
1443 NULL,
1444 /* u32VersionEnd */
1445 PDM_DEVREG_VERSION
1446};
1447#endif /* IN_RING3 */
1448
1449#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