VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/UartCore.cpp@ 73777

Last change on this file since 73777 was 73777, checked in by vboxsync, 6 years ago

Devices/Serial/UartCore.cpp: Fix character timeout indication interrupt generation. The timer callback needs to respect the ITL level and we have to start the timer in the receive FIFO fill callback when the amount characters received is below the configured ITL. Should fix I/O hangs with Windows guests.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.5 KB
Line 
1/* $Id: UartCore.cpp 73777 2018-08-20 10:36:51Z vboxsync $ */
2/** @file
3 * UartCore - UART (16550A up to 16950) emulation.
4 *
5 * The documentation for this device was taken from the PC16550D spec from TI.
6 */
7
8/*
9 * Copyright (C) 2018 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP LOG_GROUP_DEV_SERIAL
25#include <VBox/vmm/tm.h>
26#include <iprt/log.h>
27#include <iprt/uuid.h>
28#include <iprt/assert.h>
29
30#include "VBoxDD.h"
31#include "UartCore.h"
32
33
34/*********************************************************************************************************************************
35* Defined Constants And Macros *
36*********************************************************************************************************************************/
37
38/** The RBR/DLL register index (from the base of the port range). */
39#define UART_REG_RBR_DLL_INDEX 0
40
41/** The THR/DLL register index (from the base of the port range). */
42#define UART_REG_THR_DLL_INDEX 0
43
44/** The IER/DLM register index (from the base of the port range). */
45#define UART_REG_IER_DLM_INDEX 1
46/** Enable received data available interrupt */
47# define UART_REG_IER_ERBFI RT_BIT(0)
48/** Enable transmitter holding register empty interrupt */
49# define UART_REG_IER_ETBEI RT_BIT(1)
50/** Enable receiver line status interrupt */
51# define UART_REG_IER_ELSI RT_BIT(2)
52/** Enable modem status interrupt. */
53# define UART_REG_IER_EDSSI RT_BIT(3)
54/** Sleep mode enable. */
55# define UART_REG_IER_SLEEP_MODE_EN RT_BIT(4)
56/** Low power mode enable. */
57# define UART_REG_IER_LP_MODE_EN RT_BIT(5)
58/** Mask of writeable bits. */
59# define UART_REG_IER_MASK_WR 0x0f
60/** Mask of writeable bits for 16750+. */
61# define UART_REG_IER_MASK_WR_16750 0x3f
62
63/** The IIR register index (from the base of the port range). */
64#define UART_REG_IIR_INDEX 2
65/** Interrupt Pending - high means no interrupt pending. */
66# define UART_REG_IIR_IP_NO_INT RT_BIT(0)
67/** Interrupt identification mask. */
68# define UART_REG_IIR_ID_MASK 0x0e
69/** Sets the interrupt identification to the given value. */
70# define UART_REG_IIR_ID_SET(a_Val) (((a_Val) << 1) & UART_REG_IIR_ID_MASK)
71/** Gets the interrupt identification from the given IIR register value. */
72# define UART_REG_IIR_ID_GET(a_Val) (((a_Val) & UART_REG_IIR_ID_MASK) >> 1)
73/** Receiver Line Status interrupt. */
74# define UART_REG_IIR_ID_RCL 0x3
75/** Received Data Available interrupt. */
76# define UART_REG_IIR_ID_RDA 0x2
77/** Character Timeou Indicator interrupt. */
78# define UART_REG_IIR_ID_CTI 0x6
79/** Transmitter Holding Register Empty interrupt. */
80# define UART_REG_IIR_ID_THRE 0x1
81/** Modem Status interrupt. */
82# define UART_REG_IIR_ID_MS 0x0
83/** 64 byte FIFOs enabled (15750+ only). */
84# define UART_REG_IIR_64BYTE_FIFOS_EN RT_BIT(5)
85/** FIFOs enabled. */
86# define UART_REG_IIR_FIFOS_EN 0xc0
87/** Bits relevant for checking whether the interrupt status has changed. */
88# define UART_REG_IIR_CHANGED_MASK 0x0f
89
90/** The FCR register index (from the base of the port range). */
91#define UART_REG_FCR_INDEX 2
92/** Enable the TX/RX FIFOs. */
93# define UART_REG_FCR_FIFO_EN RT_BIT(0)
94/** Reset the receive FIFO. */
95# define UART_REG_FCR_RCV_FIFO_RST RT_BIT(1)
96/** Reset the transmit FIFO. */
97# define UART_REG_FCR_XMIT_FIFO_RST RT_BIT(2)
98/** DMA Mode Select. */
99# define UART_REG_FCR_DMA_MODE_SEL RT_BIT(3)
100/** 64 Byte FIFO enable (15750+ only). */
101# define UART_REG_FCR_64BYTE_FIFO_EN RT_BIT(5)
102/** Receiver level interrupt trigger. */
103# define UART_REG_FCR_RCV_LVL_IRQ_MASK 0xc0
104/** Returns the receive level trigger value from the given FCR register. */
105# define UART_REG_FCR_RCV_LVL_IRQ_GET(a_Fcr) (((a_Fcr) & UART_REG_FCR_RCV_LVL_IRQ_MASK) >> 6)
106/** RCV Interrupt trigger level - 1 byte. */
107# define UART_REG_FCR_RCV_LVL_IRQ_1 0x0
108/** RCV Interrupt trigger level - 4 bytes. */
109# define UART_REG_FCR_RCV_LVL_IRQ_4 0x1
110/** RCV Interrupt trigger level - 8 bytes. */
111# define UART_REG_FCR_RCV_LVL_IRQ_8 0x2
112/** RCV Interrupt trigger level - 14 bytes. */
113# define UART_REG_FCR_RCV_LVL_IRQ_14 0x3
114/** Mask of writeable bits. */
115# define UART_REG_FCR_MASK_WR 0xcf
116/** Mask of sticky bits. */
117# define UART_REG_FCR_MASK_STICKY 0xe9
118
119/** The LCR register index (from the base of the port range). */
120#define UART_REG_LCR_INDEX 3
121/** Word Length Select Mask. */
122# define UART_REG_LCR_WLS_MASK 0x3
123/** Returns the WLS value form the given LCR register value. */
124# define UART_REG_LCR_WLS_GET(a_Lcr) ((a_Lcr) & UART_REG_LCR_WLS_MASK)
125/** Number of stop bits. */
126# define UART_REG_LCR_STB RT_BIT(2)
127/** Parity Enable. */
128# define UART_REG_LCR_PEN RT_BIT(3)
129/** Even Parity. */
130# define UART_REG_LCR_EPS RT_BIT(4)
131/** Stick parity. */
132# define UART_REG_LCR_PAR_STICK RT_BIT(5)
133/** Set Break. */
134# define UART_REG_LCR_BRK_SET RT_BIT(6)
135/** Divisor Latch Access Bit. */
136# define UART_REG_LCR_DLAB RT_BIT(7)
137
138/** The MCR register index (from the base of the port range). */
139#define UART_REG_MCR_INDEX 4
140/** Data Terminal Ready. */
141# define UART_REG_MCR_DTR RT_BIT(0)
142/** Request To Send. */
143# define UART_REG_MCR_RTS RT_BIT(1)
144/** Out1. */
145# define UART_REG_MCR_OUT1 RT_BIT(2)
146/** Out2. */
147# define UART_REG_MCR_OUT2 RT_BIT(3)
148/** Loopback connection. */
149# define UART_REG_MCR_LOOP RT_BIT(4)
150/** Flow Control Enable (15750+ only). */
151# define UART_REG_MCR_AFE RT_BIT(5)
152/** Mask of writeable bits (15450 and 15550A). */
153# define UART_REG_MCR_MASK_WR 0x1f
154/** Mask of writeable bits (15750+). */
155# define UART_REG_MCR_MASK_WR_15750 0x3f
156
157/** The LSR register index (from the base of the port range). */
158#define UART_REG_LSR_INDEX 5
159/** Data Ready. */
160# define UART_REG_LSR_DR RT_BIT(0)
161/** Overrun Error. */
162# define UART_REG_LSR_OE RT_BIT(1)
163/** Parity Error. */
164# define UART_REG_LSR_PE RT_BIT(2)
165/** Framing Error. */
166# define UART_REG_LSR_FE RT_BIT(3)
167/** Break Interrupt. */
168# define UART_REG_LSR_BI RT_BIT(4)
169/** Transmitter Holding Register. */
170# define UART_REG_LSR_THRE RT_BIT(5)
171/** Transmitter Empty. */
172# define UART_REG_LSR_TEMT RT_BIT(6)
173/** Error in receiver FIFO. */
174# define UART_REG_LSR_RCV_FIFO_ERR RT_BIT(7)
175/** The bits to check in this register when checking for the RCL interrupt. */
176# define UART_REG_LSR_BITS_IIR_RCL 0x1e
177
178/** The MSR register index (from the base of the port range). */
179#define UART_REG_MSR_INDEX 6
180/** Delta Clear to Send. */
181# define UART_REG_MSR_DCTS RT_BIT(0)
182/** Delta Data Set Ready. */
183# define UART_REG_MSR_DDSR RT_BIT(1)
184/** Trailing Edge Ring Indicator. */
185# define UART_REG_MSR_TERI RT_BIT(2)
186/** Delta Data Carrier Detect. */
187# define UART_REG_MSR_DDCD RT_BIT(3)
188/** Clear to Send. */
189# define UART_REG_MSR_CTS RT_BIT(4)
190/** Data Set Ready. */
191# define UART_REG_MSR_DSR RT_BIT(5)
192/** Ring Indicator. */
193# define UART_REG_MSR_RI RT_BIT(6)
194/** Data Carrier Detect. */
195# define UART_REG_MSR_DCD RT_BIT(7)
196/** The bits to check in this register when checking for the MS interrupt. */
197# define UART_REG_MSR_BITS_IIR_MS 0x0f
198
199/** The SCR register index (from the base of the port range). */
200#define UART_REG_SCR_INDEX 7
201
202/** Set the specified bits in the given register. */
203#define UART_REG_SET(a_Reg, a_Set) ((a_Reg) |= (a_Set))
204/** Clear the specified bits in the given register. */
205#define UART_REG_CLR(a_Reg, a_Clr) ((a_Reg) &= ~(a_Clr))
206
207
208/*********************************************************************************************************************************
209* Structures and Typedefs *
210*********************************************************************************************************************************/
211
212#ifndef VBOX_DEVICE_STRUCT_TESTCASE
213
214
215/*********************************************************************************************************************************
216* Global Variables *
217*********************************************************************************************************************************/
218
219#ifdef IN_RING3
220/**
221 * FIFO ITL levels.
222 */
223static struct
224{
225 /** ITL level for a 16byte FIFO. */
226 uint8_t cbItl16;
227 /** ITL level for a 64byte FIFO. */
228 uint8_t cbItl64;
229} s_aFifoItl[] =
230{
231 /* cbItl16 cbItl64 */
232 { 1, 1 },
233 { 4, 16 },
234 { 8, 32 },
235 { 14, 56 }
236};
237
238
239/**
240 * String versions of the parity enum.
241 */
242static const char *s_aszParity[] =
243{
244 "INVALID",
245 "NONE",
246 "EVEN",
247 "ODD",
248 "MARK",
249 "SPACE",
250 "INVALID"
251};
252
253
254/**
255 * String versions of the stop bits enum.
256 */
257static const char *s_aszStopBits[] =
258{
259 "INVALID",
260 "1",
261 "1.5",
262 "2",
263 "INVALID"
264};
265#endif
266
267
268/*********************************************************************************************************************************
269* Internal Functions *
270*********************************************************************************************************************************/
271
272
273/**
274 * Updates the IRQ state based on the current device state.
275 *
276 * @returns nothing.
277 * @param pThis The UART core instance.
278 */
279static void uartIrqUpdate(PUARTCORE pThis)
280{
281 LogFlowFunc(("pThis=%#p\n", pThis));
282
283 /*
284 * The interrupt uses a priority scheme, only the interrupt with the
285 * highest priority is indicated in the interrupt identification register.
286 *
287 * The priorities are as follows (high to low):
288 * * Receiver line status
289 * * Received data available
290 * * Character timeout indication (only in FIFO mode).
291 * * Transmitter holding register empty
292 * * Modem status change.
293 */
294 uint8_t uRegIirNew = UART_REG_IIR_IP_NO_INT;
295 if ( (pThis->uRegLsr & UART_REG_LSR_BITS_IIR_RCL)
296 && (pThis->uRegIer & UART_REG_IER_ELSI))
297 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_RCL);
298 else if ( (pThis->uRegIer & UART_REG_IER_ERBFI)
299 && pThis->fIrqCtiPending)
300 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_CTI);
301 else if ( (pThis->uRegLsr & UART_REG_LSR_DR)
302 && (pThis->uRegIer & UART_REG_IER_ERBFI)
303 && ( !(pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
304 || pThis->FifoRecv.cbUsed >= pThis->FifoRecv.cbItl))
305 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_RDA);
306 else if ( (pThis->uRegLsr & UART_REG_LSR_THRE)
307 && pThis->fThreEmptyPending)
308 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_THRE);
309 else if ( (pThis->uRegMsr & UART_REG_MSR_BITS_IIR_MS)
310 && (pThis->uRegIer & UART_REG_IER_EDSSI))
311 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_MS);
312
313 LogFlowFunc((" uRegIirNew=%#x uRegIir=%#x\n", uRegIirNew, pThis->uRegIir));
314
315 /* Change interrupt only if the interrupt status really changed from the previous value. */
316 if (uRegIirNew != (pThis->uRegIir & UART_REG_IIR_CHANGED_MASK))
317 {
318 LogFlow((" Interrupt source changed from %#x -> %#x (IRQ %d -> %d)\n",
319 pThis->uRegIir, uRegIirNew,
320 pThis->uRegIir == UART_REG_IIR_IP_NO_INT ? 0 : 1,
321 uRegIirNew == UART_REG_IIR_IP_NO_INT ? 0 : 1));
322 if (uRegIirNew == UART_REG_IIR_IP_NO_INT)
323 pThis->CTX_SUFF(pfnUartIrqReq)(pThis->CTX_SUFF(pDevIns), pThis, pThis->iLUN, 0);
324 else
325 pThis->CTX_SUFF(pfnUartIrqReq)(pThis->CTX_SUFF(pDevIns), pThis, pThis->iLUN, 1);
326 }
327 else
328 LogFlow((" No change in interrupt source\n"));
329
330 if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
331 uRegIirNew |= UART_REG_IIR_FIFOS_EN;
332 if (pThis->uRegFcr & UART_REG_FCR_64BYTE_FIFO_EN)
333 uRegIirNew |= UART_REG_IIR_64BYTE_FIFOS_EN;
334
335 pThis->uRegIir = uRegIirNew;
336}
337
338
339/**
340 * Returns the amount of bytes stored in the given FIFO.
341 *
342 * @returns Amount of bytes stored in the FIFO.
343 * @param pFifo The FIFO.
344 */
345DECLINLINE(size_t) uartFifoUsedGet(PUARTFIFO pFifo)
346{
347 return pFifo->cbUsed;
348}
349
350
351/**
352 * Puts a new character into the given FIFO.
353 *
354 * @returns Flag whether the FIFO overflowed.
355 * @param pFifo The FIFO to put the data into.
356 * @param fOvrWr Flag whether to overwrite data if the FIFO is full.
357 * @param bData The data to add.
358 */
359DECLINLINE(bool) uartFifoPut(PUARTFIFO pFifo, bool fOvrWr, uint8_t bData)
360{
361 if (fOvrWr || pFifo->cbUsed < pFifo->cbMax)
362 {
363 pFifo->abBuf[pFifo->offWrite] = bData;
364 pFifo->offWrite = (pFifo->offWrite + 1) % pFifo->cbMax;
365 }
366
367 bool fOverFlow = false;
368 if (pFifo->cbUsed < pFifo->cbMax)
369 pFifo->cbUsed++;
370 else
371 {
372 fOverFlow = true;
373 if (fOvrWr) /* Advance the read position to account for the lost character. */
374 pFifo->offRead = (pFifo->offRead + 1) % pFifo->cbMax;
375 }
376
377 return fOverFlow;
378}
379
380
381/**
382 * Returns the next character in the FIFO.
383 *
384 * @return Next byte in the FIFO.
385 * @param pFifo The FIFO to get data from.
386 */
387DECLINLINE(uint8_t) uartFifoGet(PUARTFIFO pFifo)
388{
389 uint8_t bRet = 0;
390
391 if (pFifo->cbUsed)
392 {
393 bRet = pFifo->abBuf[pFifo->offRead];
394 pFifo->offRead = (pFifo->offRead + 1) % pFifo->cbMax;
395 pFifo->cbUsed--;
396 }
397
398 return bRet;
399}
400
401
402#ifdef IN_RING3
403/**
404 * Clears the given FIFO.
405 *
406 * @returns nothing.
407 * @param pFifo The FIFO to clear.
408 */
409DECLINLINE(void) uartFifoClear(PUARTFIFO pFifo)
410{
411 memset(&pFifo->abBuf[0], 0, sizeof(pFifo->abBuf));
412 pFifo->cbUsed = 0;
413 pFifo->offWrite = 0;
414 pFifo->offRead = 0;
415}
416
417
418/**
419 * Returns the amount of free bytes in the given FIFO.
420 *
421 * @returns The amount of bytes free in the given FIFO.
422 * @param pFifo The FIFO.
423 */
424DECLINLINE(size_t) uartFifoFreeGet(PUARTFIFO pFifo)
425{
426 return pFifo->cbMax - pFifo->cbUsed;
427}
428
429
430/**
431 * Tries to copy the requested amount of data from the given FIFO into the provided buffer.
432 *
433 * @returns Amount of bytes actually copied.
434 * @param pFifo The FIFO to copy data from.
435 * @param pvDst Where to copy the data to.
436 * @param cbCopy How much to copy.
437 */
438DECLINLINE(size_t) uartFifoCopyTo(PUARTFIFO pFifo, void *pvDst, size_t cbCopy)
439{
440 size_t cbCopied = 0;
441 uint8_t *pbDst = (uint8_t *)pvDst;
442
443 cbCopy = RT_MIN(cbCopy, pFifo->cbUsed);
444 while (cbCopy)
445 {
446 uint8_t cbThisCopy = (uint8_t)RT_MIN(cbCopy, (uint8_t)(pFifo->cbMax - pFifo->offRead));
447 memcpy(pbDst, &pFifo->abBuf[pFifo->offRead], cbThisCopy);
448
449 pFifo->offRead = (pFifo->offRead + cbThisCopy) % pFifo->cbMax;
450 pFifo->cbUsed -= cbThisCopy;
451 pbDst += cbThisCopy;
452 cbCopied += cbThisCopy;
453 cbCopy -= cbThisCopy;
454 }
455
456 return cbCopied;
457}
458
459
460#if 0 /* unused */
461/**
462 * Tries to copy the requested amount of data from the provided buffer into the given FIFO.
463 *
464 * @returns Amount of bytes actually copied.
465 * @param pFifo The FIFO to copy data to.
466 * @param pvSrc Where to copy the data from.
467 * @param cbCopy How much to copy.
468 */
469DECLINLINE(size_t) uartFifoCopyFrom(PUARTFIFO pFifo, void *pvSrc, size_t cbCopy)
470{
471 size_t cbCopied = 0;
472 uint8_t *pbSrc = (uint8_t *)pvSrc;
473
474 cbCopy = RT_MIN(cbCopy, uartFifoFreeGet(pFifo));
475 while (cbCopy)
476 {
477 uint8_t cbThisCopy = (uint8_t)RT_MIN(cbCopy, (uint8_t)(pFifo->cbMax - pFifo->offWrite));
478 memcpy(&pFifo->abBuf[pFifo->offWrite], pbSrc, cbThisCopy);
479
480 pFifo->offWrite = (pFifo->offWrite + cbThisCopy) % pFifo->cbMax;
481 pFifo->cbUsed += cbThisCopy;
482 pbSrc += cbThisCopy;
483 cbCopied += cbThisCopy;
484 cbCopy -= cbThisCopy;
485 }
486
487 return cbCopied;
488}
489#endif
490
491
492/**
493 * Updates the delta bits for the given MSR register value which has the status line
494 * bits set.
495 *
496 * @returns nothing.
497 * @param pThis The serial port instance.
498 * @param uMsrSts MSR value with the appropriate status bits set.
499 */
500static void uartR3MsrUpdate(PUARTCORE pThis, uint8_t uMsrSts)
501{
502 /* Compare current and new states and set remaining bits accordingly. */
503 if ((uMsrSts & UART_REG_MSR_CTS) != (pThis->uRegMsr & UART_REG_MSR_CTS))
504 uMsrSts |= UART_REG_MSR_DCTS;
505 if ((uMsrSts & UART_REG_MSR_DSR) != (pThis->uRegMsr & UART_REG_MSR_DSR))
506 uMsrSts |= UART_REG_MSR_DDSR;
507 if ((uMsrSts & UART_REG_MSR_RI) != 0 && (pThis->uRegMsr & UART_REG_MSR_RI) == 0)
508 uMsrSts |= UART_REG_MSR_TERI;
509 if ((uMsrSts & UART_REG_MSR_DCD) != (pThis->uRegMsr & UART_REG_MSR_DCD))
510 uMsrSts |= UART_REG_MSR_DDCD;
511
512 pThis->uRegMsr = uMsrSts;
513
514 uartIrqUpdate(pThis);
515}
516
517
518/**
519 * Updates the serial port parameters of the attached driver with the current configuration.
520 *
521 * @returns nothing.
522 * @param pThis The serial port instance.
523 */
524static void uartR3ParamsUpdate(PUARTCORE pThis)
525{
526 if ( pThis->uRegDivisor != 0
527 && pThis->pDrvSerial)
528 {
529 uint32_t uBps = 115200 / pThis->uRegDivisor; /* This is for PC compatible serial port with a 1.8432 MHz crystal. */
530 unsigned cDataBits = UART_REG_LCR_WLS_GET(pThis->uRegLcr) + 5;
531 uint32_t cFrameBits = cDataBits;
532 PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE;
533 PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE;
534
535 if (pThis->uRegLcr & UART_REG_LCR_STB)
536 {
537 enmStopBits = cDataBits == 5 ? PDMSERIALSTOPBITS_ONEPOINTFIVE : PDMSERIALSTOPBITS_TWO;
538 cFrameBits += 2;
539 }
540 else
541 cFrameBits++;
542
543 if (pThis->uRegLcr & UART_REG_LCR_PEN)
544 {
545 /* Select the correct parity mode based on the even and stick parity bits. */
546 switch (pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK))
547 {
548 case 0:
549 enmParity = PDMSERIALPARITY_ODD;
550 break;
551 case UART_REG_LCR_EPS:
552 enmParity = PDMSERIALPARITY_EVEN;
553 break;
554 case UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK:
555 enmParity = PDMSERIALPARITY_SPACE;
556 break;
557 case UART_REG_LCR_PAR_STICK:
558 enmParity = PDMSERIALPARITY_MARK;
559 break;
560 default:
561 /* We should never get here as all cases where caught earlier. */
562 AssertMsgFailed(("This shouldn't happen at all: %#x\n",
563 pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK)));
564 }
565
566 cFrameBits++;
567 }
568
569 uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pTimerRcvFifoTimeout));
570 pThis->cSymbolXferTicks = (uTimerFreq / uBps) * cFrameBits;
571
572 LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n",
573 uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits]));
574
575 int rc = pThis->pDrvSerial->pfnChgParams(pThis->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits);
576 if (RT_FAILURE(rc))
577 LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n",
578 pThis->pDevInsR3->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc));
579
580 /* Changed parameters will flush all receive queues, so there won't be any data to read even if indicated. */
581 ASMAtomicWriteU32(&pThis->cbAvailRdr, 0);
582 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
583 }
584}
585
586
587/**
588 * Updates the internal device state with the given PDM status line states.
589 *
590 * @returns nothing.
591 * @param pThis The serial port instance.
592 * @param fStsLines The PDM status line states.
593 */
594static void uartR3StsLinesUpdate(PUARTCORE pThis, uint32_t fStsLines)
595{
596 uint8_t uRegMsrNew = 0; /* The new MSR value. */
597
598 if (fStsLines & PDMISERIALPORT_STS_LINE_DCD)
599 uRegMsrNew |= UART_REG_MSR_DCD;
600 if (fStsLines & PDMISERIALPORT_STS_LINE_RI)
601 uRegMsrNew |= UART_REG_MSR_RI;
602 if (fStsLines & PDMISERIALPORT_STS_LINE_DSR)
603 uRegMsrNew |= UART_REG_MSR_DSR;
604 if (fStsLines & PDMISERIALPORT_STS_LINE_CTS)
605 uRegMsrNew |= UART_REG_MSR_CTS;
606
607 uartR3MsrUpdate(pThis, uRegMsrNew);
608}
609
610
611/**
612 * Fills up the receive FIFO with as much data as possible.
613 *
614 * @returns nothing.
615 * @param pThis The serial port instance.
616 */
617static void uartR3RecvFifoFill(PUARTCORE pThis)
618{
619 LogFlowFunc(("pThis=%#p\n", pThis));
620
621 PUARTFIFO pFifo = &pThis->FifoRecv;
622 size_t cbFill = RT_MIN(uartFifoFreeGet(pFifo),
623 ASMAtomicReadU32(&pThis->cbAvailRdr));
624 size_t cbFilled = 0;
625
626 while (cbFilled < cbFill)
627 {
628 size_t cbThisRead = cbFill - cbFilled;
629
630 if (pFifo->offRead <= pFifo->offWrite)
631 cbThisRead = RT_MIN(cbThisRead, (uint8_t)(pFifo->cbMax - pFifo->offWrite));
632 else
633 cbThisRead = RT_MIN(cbThisRead, (uint8_t)(pFifo->offRead - pFifo->offWrite));
634
635 size_t cbRead = 0;
636 int rc = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pFifo->abBuf[pFifo->offWrite], cbThisRead, &cbRead);
637 AssertRC(rc); Assert(cbRead <= UINT8_MAX); RT_NOREF(rc);
638
639 pFifo->offWrite = (pFifo->offWrite + (uint8_t)cbRead) % pFifo->cbMax;
640 pFifo->cbUsed += (uint8_t)cbRead;
641 cbFilled += cbRead;
642
643 if (cbRead < cbThisRead)
644 break;
645 }
646
647 if (cbFilled)
648 {
649 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
650 if (pFifo->cbUsed < pFifo->cbItl)
651 {
652 pThis->fIrqCtiPending = false;
653 TMTimerSetRelative(pThis->CTX_SUFF(pTimerRcvFifoTimeout), pThis->cSymbolXferTicks * 4, NULL);
654 }
655 uartIrqUpdate(pThis);
656 }
657
658 Assert(cbFilled <= (size_t)pThis->cbAvailRdr);
659 ASMAtomicSubU32(&pThis->cbAvailRdr, (uint32_t)cbFilled);
660}
661
662
663/**
664 * Fetches a single byte and writes it to RBR.
665 *
666 * @returns nothing.
667 * @param pThis The serial port instance.
668 */
669static void uartR3ByteFetch(PUARTCORE pThis)
670{
671 if (ASMAtomicReadU32(&pThis->cbAvailRdr))
672 {
673 AssertPtr(pThis->pDrvSerial);
674 size_t cbRead = 0;
675 int rc2 = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pThis->uRegRbr, 1, &cbRead);
676 AssertMsg(RT_SUCCESS(rc2) && cbRead == 1, ("This shouldn't fail and always return one byte!\n")); RT_NOREF(rc2);
677 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
678 uartIrqUpdate(pThis);
679 }
680}
681
682
683/**
684 * Fetches a ready data based on the FIFO setting.
685 *
686 * @returns nothing.
687 * @param pThis The serial port instance.
688 */
689static void uartR3DataFetch(PUARTCORE pThis)
690{
691 if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
692 uartR3RecvFifoFill(pThis);
693 else
694 uartR3ByteFetch(pThis);
695}
696
697
698/**
699 * Reset the transmit/receive related bits to the standard values
700 * (after a detach/attach/reset event).
701 *
702 * @returns nothing.
703 * @param pThis The serial port instance.
704 */
705static void uartR3XferReset(PUARTCORE pThis)
706{
707 pThis->uRegLsr = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
708 pThis->fThreEmptyPending = false;
709
710 uartFifoClear(&pThis->FifoXmit);
711 uartFifoClear(&pThis->FifoRecv);
712 uartR3ParamsUpdate(pThis);
713 uartIrqUpdate(pThis);
714
715 if (pThis->pDrvSerial)
716 {
717 /* Set the modem lines to reflect the current state. */
718 int rc = pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial, false /*fRts*/, false /*fDtr*/);
719 if (RT_FAILURE(rc))
720 LogRel(("Serial#%d: Failed to set modem lines with %Rrc during reset\n",
721 pThis->pDevInsR3->iInstance, rc));
722
723 uint32_t fStsLines = 0;
724 rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
725 if (RT_SUCCESS(rc))
726 uartR3StsLinesUpdate(pThis, fStsLines);
727 else
728 LogRel(("Serial#%d: Failed to query status line status with %Rrc during reset\n",
729 pThis->pDevInsR3->iInstance, rc));
730 }
731
732}
733#endif
734
735
736/**
737 * Write handler for the THR/DLL register (depending on the DLAB bit in LCR).
738 *
739 * @returns VBox status code.
740 * @param pThis The serial port instance.
741 * @param uVal The value to write.
742 */
743DECLINLINE(int) uartRegThrDllWrite(PUARTCORE pThis, uint8_t uVal)
744{
745 int rc = VINF_SUCCESS;
746
747 /* A set DLAB causes a write to the lower 8bits of the divisor latch. */
748 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
749 {
750 if (uVal != (pThis->uRegDivisor & 0xff))
751 {
752#ifndef IN_RING3
753 rc = VINF_IOM_R3_IOPORT_WRITE;
754#else
755 pThis->uRegDivisor = (pThis->uRegDivisor & 0xff00) | uVal;
756 uartR3ParamsUpdate(pThis);
757#endif
758 }
759 }
760 else
761 {
762 if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
763 {
764#ifndef IN_RING3
765 if (!uartFifoUsedGet(&pThis->FifoXmit))
766 rc = VINF_IOM_R3_IOPORT_WRITE;
767 else
768 {
769 uartFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, uVal);
770 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
771 }
772#else
773 uartFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, uVal);
774 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
775 pThis->fThreEmptyPending = false;
776 uartIrqUpdate(pThis);
777 if ( pThis->pDrvSerial
778 && uartFifoUsedGet(&pThis->FifoXmit) == 1)
779 {
780 int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial);
781 if (RT_FAILURE(rc2))
782 LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", pThis->pDevInsR3->iInstance, rc2));
783 }
784#endif
785 }
786 else
787 {
788 /* Notify the lower driver about available data only if the register was empty before. */
789 if (pThis->uRegLsr & UART_REG_LSR_THRE)
790 {
791#ifndef IN_RING3
792 rc = VINF_IOM_R3_IOPORT_WRITE;
793#else
794 pThis->uRegThr = uVal;
795 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
796 pThis->fThreEmptyPending = false;
797 uartIrqUpdate(pThis);
798 if (pThis->pDrvSerial)
799 {
800 int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial);
801 if (RT_FAILURE(rc2))
802 LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", pThis->pDevInsR3->iInstance, rc2));
803 }
804#endif
805 }
806 else
807 pThis->uRegThr = uVal;
808 }
809 }
810
811 return rc;
812}
813
814
815/**
816 * Write handler for the IER/DLM register (depending on the DLAB bit in LCR).
817 *
818 * @returns VBox status code.
819 * @param pThis The serial port instance.
820 * @param uVal The value to write.
821 */
822DECLINLINE(int) uartRegIerDlmWrite(PUARTCORE pThis, uint8_t uVal)
823{
824 int rc = VINF_SUCCESS;
825
826 /* A set DLAB causes a write to the higher 8bits of the divisor latch. */
827 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
828 {
829 if (uVal != (pThis->uRegDivisor & 0xff00) >> 8)
830 {
831#ifndef IN_RING3
832 rc = VINF_IOM_R3_IOPORT_WRITE;
833#else
834 pThis->uRegDivisor = (pThis->uRegDivisor & 0xff) | (uVal << 8);
835 uartR3ParamsUpdate(pThis);
836#endif
837 }
838 }
839 else
840 {
841 if (pThis->enmType < UARTTYPE_16750)
842 pThis->uRegIer = uVal & UART_REG_IER_MASK_WR;
843 else
844 pThis->uRegIer = uVal & UART_REG_IER_MASK_WR_16750;
845
846 if (pThis->uRegLsr & UART_REG_LSR_THRE)
847 pThis->fThreEmptyPending = true;
848
849 uartIrqUpdate(pThis);
850 }
851
852 return rc;
853}
854
855
856/**
857 * Write handler for the FCR register.
858 *
859 * @returns VBox status code.
860 * @param pThis The serial port instance.
861 * @param uVal The value to write.
862 */
863DECLINLINE(int) uartRegFcrWrite(PUARTCORE pThis, uint8_t uVal)
864{
865#ifndef IN_RING3
866 RT_NOREF(pThis, uVal);
867 return VINF_IOM_R3_IOPORT_WRITE;
868#else
869 int rc = VINF_SUCCESS;
870 if ( pThis->enmType >= UARTTYPE_16550A
871 && uVal != pThis->uRegFcr)
872 {
873 /* A change in the FIFO enable bit clears both FIFOs automatically. */
874 if ((uVal ^ pThis->uRegFcr) & UART_REG_FCR_FIFO_EN)
875 {
876 uartFifoClear(&pThis->FifoXmit);
877 uartFifoClear(&pThis->FifoRecv);
878
879 /*
880 * If the FIFO is about to be enabled and the DR bit is ready we have an unacknowledged
881 * byte in the RBR register which will be lost so we have to adjust the available bytes.
882 */
883 if ( ASMAtomicReadU32(&pThis->cbAvailRdr) > 0
884 && (uVal & UART_REG_FCR_FIFO_EN))
885 ASMAtomicDecU32(&pThis->cbAvailRdr);
886
887 /* Clear the DR bit too. */
888 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
889 }
890
891 if (rc == VINF_SUCCESS)
892 {
893 if (uVal & UART_REG_FCR_RCV_FIFO_RST)
894 {
895 TMTimerStop(pThis->CTX_SUFF(pTimerRcvFifoTimeout));
896 pThis->fIrqCtiPending = false;
897 uartFifoClear(&pThis->FifoRecv);
898 }
899 if (uVal & UART_REG_FCR_XMIT_FIFO_RST)
900 uartFifoClear(&pThis->FifoXmit);
901
902 /*
903 * The 64byte FIFO enable bit is only changeable for 16750
904 * and if the DLAB bit in LCR is set.
905 */
906 if ( pThis->enmType < UARTTYPE_16750
907 || !(pThis->uRegLcr & UART_REG_LCR_DLAB))
908 uVal &= ~UART_REG_FCR_64BYTE_FIFO_EN;
909 else /* Use previous value. */
910 uVal |= pThis->uRegFcr & UART_REG_FCR_64BYTE_FIFO_EN;
911
912 if (uVal & UART_REG_FCR_64BYTE_FIFO_EN)
913 {
914 pThis->FifoRecv.cbMax = 64;
915 pThis->FifoXmit.cbMax = 64;
916 }
917 else
918 {
919 pThis->FifoRecv.cbMax = 16;
920 pThis->FifoXmit.cbMax = 16;
921 }
922
923 if (uVal & UART_REG_FCR_FIFO_EN)
924 {
925 uint8_t idxItl = UART_REG_FCR_RCV_LVL_IRQ_GET(uVal);
926 if (uVal & UART_REG_FCR_64BYTE_FIFO_EN)
927 pThis->FifoRecv.cbItl = s_aFifoItl[idxItl].cbItl64;
928 else
929 pThis->FifoRecv.cbItl = s_aFifoItl[idxItl].cbItl16;
930 }
931
932 /* The FIFO reset bits are self clearing. */
933 pThis->uRegFcr = uVal & UART_REG_FCR_MASK_STICKY;
934 uartIrqUpdate(pThis);
935 }
936
937 /* Fill in the next data. */
938 if (ASMAtomicReadU32(&pThis->cbAvailRdr))
939 uartR3DataFetch(pThis);
940 }
941
942 return rc;
943#endif
944}
945
946
947/**
948 * Write handler for the LCR register.
949 *
950 * @returns VBox status code.
951 * @param pThis The serial port instance.
952 * @param uVal The value to write.
953 */
954DECLINLINE(int) uartRegLcrWrite(PUARTCORE pThis, uint8_t uVal)
955{
956 int rc = VINF_SUCCESS;
957
958 /* Any change except the DLAB bit causes a switch to R3. */
959 if ((pThis->uRegLcr & ~UART_REG_LCR_DLAB) != (uVal & ~UART_REG_LCR_DLAB))
960 {
961#ifndef IN_RING3
962 rc = VINF_IOM_R3_IOPORT_WRITE;
963#else
964 /* Check whether the BREAK bit changed before updating the LCR value. */
965 bool fBrkEn = RT_BOOL(uVal & UART_REG_LCR_BRK_SET);
966 bool fBrkChg = fBrkEn != RT_BOOL(pThis->uRegLcr & UART_REG_LCR_BRK_SET);
967 pThis->uRegLcr = uVal;
968 uartR3ParamsUpdate(pThis);
969
970 if ( fBrkChg
971 && pThis->pDrvSerial)
972 pThis->pDrvSerial->pfnChgBrk(pThis->pDrvSerial, fBrkEn);
973#endif
974 }
975 else
976 pThis->uRegLcr = uVal;
977
978 return rc;
979}
980
981
982/**
983 * Write handler for the MCR register.
984 *
985 * @returns VBox status code.
986 * @param pThis The serial port instance.
987 * @param uVal The value to write.
988 */
989DECLINLINE(int) uartRegMcrWrite(PUARTCORE pThis, uint8_t uVal)
990{
991 int rc = VINF_SUCCESS;
992
993 if (pThis->enmType < UARTTYPE_16750)
994 uVal &= UART_REG_MCR_MASK_WR;
995 else
996 uVal &= UART_REG_MCR_MASK_WR_15750;
997 if (pThis->uRegMcr != uVal)
998 {
999#ifndef IN_RING3
1000 rc = VINF_IOM_R3_IOPORT_WRITE;
1001#else
1002 /*
1003 * When loopback mode is activated the RTS, DTR, OUT1 and OUT2 lines are
1004 * disconnected and looped back to MSR.
1005 */
1006 if ( (uVal & UART_REG_MCR_LOOP)
1007 && !(pThis->uRegMcr & UART_REG_MCR_LOOP)
1008 && pThis->pDrvSerial)
1009 pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial, false /*fRts*/, false /*fDtr*/);
1010
1011 pThis->uRegMcr = uVal;
1012 if (uVal & UART_REG_MCR_LOOP)
1013 {
1014 uint8_t uRegMsrSts = 0;
1015
1016 if (uVal & UART_REG_MCR_RTS)
1017 uRegMsrSts |= UART_REG_MSR_CTS;
1018 if (uVal & UART_REG_MCR_DTR)
1019 uRegMsrSts |= UART_REG_MSR_DSR;
1020 if (uVal & UART_REG_MCR_OUT1)
1021 uRegMsrSts |= UART_REG_MSR_RI;
1022 if (uVal & UART_REG_MCR_OUT2)
1023 uRegMsrSts |= UART_REG_MSR_DCD;
1024 uartR3MsrUpdate(pThis, uRegMsrSts);
1025 }
1026 else if (pThis->pDrvSerial)
1027 pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial,
1028 RT_BOOL(uVal & UART_REG_MCR_RTS),
1029 RT_BOOL(uVal & UART_REG_MCR_DTR));
1030#endif
1031 }
1032
1033 return rc;
1034}
1035
1036
1037/**
1038 * Read handler for the RBR/DLL register (depending on the DLAB bit in LCR).
1039 *
1040 * @returns VBox status code.
1041 * @param pThis The serial port instance.
1042 * @param puVal Where to store the read value on success.
1043 */
1044DECLINLINE(int) uartRegRbrDllRead(PUARTCORE pThis, uint32_t *puVal)
1045{
1046 int rc = VINF_SUCCESS;
1047
1048 /* A set DLAB causes a read from the lower 8bits of the divisor latch. */
1049 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
1050 *puVal = pThis->uRegDivisor & 0xff;
1051 else
1052 {
1053 if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
1054 {
1055 /*
1056 * Only go back to R3 if there is new data available for the FIFO
1057 * and we would clear the interrupt to fill it up again.
1058 */
1059 if ( pThis->FifoRecv.cbUsed <= pThis->FifoRecv.cbItl
1060 && ASMAtomicReadU32(&pThis->cbAvailRdr) > 0)
1061 {
1062#ifndef IN_RING3
1063 rc = VINF_IOM_R3_IOPORT_READ;
1064#else
1065 uartR3RecvFifoFill(pThis);
1066#endif
1067 }
1068
1069 if (rc == VINF_SUCCESS)
1070 {
1071 *puVal = uartFifoGet(&pThis->FifoRecv);
1072 pThis->fIrqCtiPending = false;
1073 if (!pThis->FifoRecv.cbUsed)
1074 {
1075 TMTimerStop(pThis->CTX_SUFF(pTimerRcvFifoTimeout));
1076 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
1077 }
1078 else if (pThis->FifoRecv.cbUsed < pThis->FifoRecv.cbItl)
1079 TMTimerSetRelative(pThis->CTX_SUFF(pTimerRcvFifoTimeout), pThis->cSymbolXferTicks * 4, NULL);
1080 uartIrqUpdate(pThis);
1081 }
1082 }
1083 else
1084 {
1085 *puVal = pThis->uRegRbr;
1086
1087 if (pThis->uRegLsr & UART_REG_LSR_DR)
1088 {
1089 Assert(pThis->cbAvailRdr);
1090 uint32_t cbAvail = ASMAtomicDecU32(&pThis->cbAvailRdr);
1091 if (!cbAvail)
1092 {
1093 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
1094 uartIrqUpdate(pThis);
1095 }
1096 else
1097 {
1098#ifndef IN_RING3
1099 /* Restore state and go back to R3. */
1100 ASMAtomicIncU32(&pThis->cbAvailRdr);
1101 rc = VINF_IOM_R3_IOPORT_READ;
1102#else
1103 /* Fetch new data and keep the DR bit set. */
1104 uartR3DataFetch(pThis);
1105#endif
1106 }
1107 }
1108 }
1109 }
1110
1111 return rc;
1112}
1113
1114
1115/**
1116 * Read handler for the IER/DLM register (depending on the DLAB bit in LCR).
1117 *
1118 * @returns VBox status code.
1119 * @param pThis The serial port instance.
1120 * @param puVal Where to store the read value on success.
1121 */
1122DECLINLINE(int) uartRegIerDlmRead(PUARTCORE pThis, uint32_t *puVal)
1123{
1124 int rc = VINF_SUCCESS;
1125
1126 /* A set DLAB causes a read from the upper 8bits of the divisor latch. */
1127 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
1128 *puVal = (pThis->uRegDivisor & 0xff00) >> 8;
1129 else
1130 *puVal = pThis->uRegIer;
1131
1132 return rc;
1133}
1134
1135
1136/**
1137 * Read handler for the IIR register.
1138 *
1139 * @returns VBox status code.
1140 * @param pThis The serial port instance.
1141 * @param puVal Where to store the read value on success.
1142 */
1143DECLINLINE(int) uartRegIirRead(PUARTCORE pThis, uint32_t *puVal)
1144{
1145 *puVal = pThis->uRegIir;
1146 /* Reset the THRE empty interrupt id when this gets returned to the guest (see table 3 UART Reset configuration). */
1147 if (UART_REG_IIR_ID_GET(pThis->uRegIir) == UART_REG_IIR_ID_THRE)
1148 {
1149 pThis->fThreEmptyPending = false;
1150 uartIrqUpdate(pThis);
1151 }
1152 return VINF_SUCCESS;
1153}
1154
1155
1156/**
1157 * Read handler for the LSR register.
1158 *
1159 * @returns VBox status code.
1160 * @param pThis The serial port instance.
1161 * @param puVal Where to store the read value on success.
1162 */
1163DECLINLINE(int) uartRegLsrRead(PUARTCORE pThis, uint32_t *puVal)
1164{
1165 int rc = VINF_SUCCESS;
1166
1167 /* Yield if configured and there is no data available. */
1168 if ( !(pThis->uRegLsr & UART_REG_LSR_DR)
1169 && (pThis->fFlags & UART_CORE_YIELD_ON_LSR_READ))
1170 {
1171#ifndef IN_RING3
1172 return VINF_IOM_R3_IOPORT_READ;
1173#else
1174 RTThreadYield();
1175#endif
1176 }
1177
1178 *puVal = pThis->uRegLsr;
1179 /*
1180 * Reading this register clears the Overrun (OE), Parity (PE) and Framing (FE) error
1181 * as well as the Break Interrupt (BI).
1182 */
1183 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_BITS_IIR_RCL);
1184 uartIrqUpdate(pThis);
1185
1186 return rc;
1187}
1188
1189
1190/**
1191 * Read handler for the MSR register.
1192 *
1193 * @returns VBox status code.
1194 * @param pThis The serial port instance.
1195 * @param puVal Where to store the read value on success.
1196 */
1197DECLINLINE(int) uartRegMsrRead(PUARTCORE pThis, uint32_t *puVal)
1198{
1199 *puVal = pThis->uRegMsr;
1200
1201 /* Clear any of the delta bits. */
1202 UART_REG_CLR(pThis->uRegMsr, UART_REG_MSR_BITS_IIR_MS);
1203 uartIrqUpdate(pThis);
1204 return VINF_SUCCESS;
1205}
1206
1207
1208#ifdef LOG_ENABLED
1209/**
1210 * Converts the register index into a sensible memnonic.
1211 *
1212 * @returns Register memnonic.
1213 * @param pThis The serial port instance.
1214 * @param idxReg Register index.
1215 * @param fWrite Flag whether the register gets written.
1216 */
1217DECLINLINE(const char *) uartRegIdx2Str(PUARTCORE pThis, uint8_t idxReg, bool fWrite)
1218{
1219 const char *psz = "INV";
1220
1221 switch (idxReg)
1222 {
1223 /*case UART_REG_THR_DLL_INDEX:*/
1224 case UART_REG_RBR_DLL_INDEX:
1225 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
1226 psz = "DLL";
1227 else if (fWrite)
1228 psz = "THR";
1229 else
1230 psz = "RBR";
1231 break;
1232 case UART_REG_IER_DLM_INDEX:
1233 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
1234 psz = "DLM";
1235 else
1236 psz = "IER";
1237 break;
1238 /*case UART_REG_IIR_INDEX:*/
1239 case UART_REG_FCR_INDEX:
1240 if (fWrite)
1241 psz = "FCR";
1242 else
1243 psz = "IIR";
1244 break;
1245 case UART_REG_LCR_INDEX:
1246 psz = "LCR";
1247 break;
1248 case UART_REG_MCR_INDEX:
1249 psz = "MCR";
1250 break;
1251 case UART_REG_LSR_INDEX:
1252 psz = "LSR";
1253 break;
1254 case UART_REG_MSR_INDEX:
1255 psz = "MSR";
1256 break;
1257 case UART_REG_SCR_INDEX:
1258 psz = "SCR";
1259 break;
1260 }
1261
1262 return psz;
1263}
1264#endif
1265
1266
1267DECLHIDDEN(int) uartRegWrite(PUARTCORE pThis, uint32_t uReg, uint32_t u32, size_t cb)
1268{
1269 AssertMsgReturn(cb == 1, ("uReg=%#x cb=%d u32=%#x\n", uReg, cb, u32), VINF_SUCCESS);
1270
1271 int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
1272 if (rc != VINF_SUCCESS)
1273 return rc;
1274
1275 uint8_t idxReg = uReg & 0x7;
1276 LogFlowFunc(("pThis=%#p uReg=%u{%s} u32=%#x cb=%u\n",
1277 pThis, uReg, uartRegIdx2Str(pThis, idxReg, true /*fWrite*/), u32, cb));
1278
1279 uint8_t uVal = (uint8_t)u32;
1280 switch (idxReg)
1281 {
1282 case UART_REG_THR_DLL_INDEX:
1283 rc = uartRegThrDllWrite(pThis, uVal);
1284 break;
1285 case UART_REG_IER_DLM_INDEX:
1286 rc = uartRegIerDlmWrite(pThis, uVal);
1287 break;
1288 case UART_REG_FCR_INDEX:
1289 rc = uartRegFcrWrite(pThis, uVal);
1290 break;
1291 case UART_REG_LCR_INDEX:
1292 rc = uartRegLcrWrite(pThis, uVal);
1293 break;
1294 case UART_REG_MCR_INDEX:
1295 rc = uartRegMcrWrite(pThis, uVal);
1296 break;
1297 case UART_REG_SCR_INDEX:
1298 pThis->uRegScr = u32;
1299 break;
1300 default:
1301 break;
1302 }
1303
1304 PDMCritSectLeave(&pThis->CritSect);
1305 LogFlowFunc(("-> %Rrc\n", rc));
1306 return rc;
1307}
1308
1309
1310DECLHIDDEN(int) uartRegRead(PUARTCORE pThis, uint32_t uReg, uint32_t *pu32, size_t cb)
1311{
1312 if (cb != 1)
1313 return VERR_IOM_IOPORT_UNUSED;
1314
1315 int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
1316 if (rc != VINF_SUCCESS)
1317 return rc;
1318
1319 uint8_t idxReg = uReg & 0x7;
1320 switch (idxReg)
1321 {
1322 case UART_REG_RBR_DLL_INDEX:
1323 rc = uartRegRbrDllRead(pThis, pu32);
1324 break;
1325 case UART_REG_IER_DLM_INDEX:
1326 rc = uartRegIerDlmRead(pThis, pu32);
1327 break;
1328 case UART_REG_IIR_INDEX:
1329 rc = uartRegIirRead(pThis, pu32);
1330 break;
1331 case UART_REG_LCR_INDEX:
1332 *pu32 = pThis->uRegLcr;
1333 break;
1334 case UART_REG_MCR_INDEX:
1335 *pu32 = pThis->uRegMcr;
1336 break;
1337 case UART_REG_LSR_INDEX:
1338 rc = uartRegLsrRead(pThis, pu32);
1339 break;
1340 case UART_REG_MSR_INDEX:
1341 rc = uartRegMsrRead(pThis, pu32);
1342 break;
1343 case UART_REG_SCR_INDEX:
1344 *pu32 = pThis->uRegScr;
1345 break;
1346 default:
1347 rc = VERR_IOM_IOPORT_UNUSED;
1348 }
1349
1350 PDMCritSectLeave(&pThis->CritSect);
1351 LogFlowFunc(("pThis=%#p uReg=%u{%s} u32=%#x cb=%u -> %Rrc\n",
1352 pThis, uReg, uartRegIdx2Str(pThis, idxReg, false /*fWrite*/), *pu32, cb, rc));
1353 return rc;
1354}
1355
1356
1357#ifdef IN_RING3
1358
1359/* -=-=-=-=-=-=-=-=- Timer callbacks -=-=-=-=-=-=-=-=- */
1360
1361/**
1362 * @callback_method_impl{FNTMTIMERDEV, Fifo timer function.}
1363 */
1364static DECLCALLBACK(void) uartR3RcvFifoTimeoutTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1365{
1366 LogFlowFunc(("pDevIns=%#p pTimer=%#p pvUser=%#p\n", pDevIns, pTimer, pvUser));
1367 RT_NOREF(pDevIns, pTimer);
1368 PUARTCORE pThis = (PUARTCORE)pvUser;
1369 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
1370 if (pThis->FifoRecv.cbUsed < pThis->FifoRecv.cbItl)
1371 {
1372 pThis->fIrqCtiPending = true;
1373 uartIrqUpdate(pThis);
1374 }
1375 PDMCritSectLeave(&pThis->CritSect);
1376}
1377
1378
1379/* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
1380
1381
1382/**
1383 * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
1384 */
1385static DECLCALLBACK(int) uartR3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
1386{
1387 LogFlowFunc(("pInterface=%#p cbAvail=%zu\n", pInterface, cbAvail));
1388 PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
1389
1390 AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
1391
1392 uint32_t cbAvailOld = ASMAtomicAddU32(&pThis->cbAvailRdr, (uint32_t)cbAvail);
1393 LogFlow((" cbAvailRdr=%u -> cbAvailRdr=%u\n", cbAvailOld, cbAvail + cbAvailOld));
1394 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
1395 if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
1396 uartR3RecvFifoFill(pThis);
1397 else if (!cbAvailOld)
1398 {
1399 size_t cbRead = 0;
1400 int rc = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pThis->uRegRbr, 1, &cbRead);
1401 AssertMsg(RT_SUCCESS(rc) && cbRead == 1, ("This shouldn't fail and always return one byte!\n")); RT_NOREF(rc);
1402 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
1403 uartIrqUpdate(pThis);
1404 }
1405 PDMCritSectLeave(&pThis->CritSect);
1406
1407 return VINF_SUCCESS;
1408}
1409
1410
1411/**
1412 * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
1413 */
1414static DECLCALLBACK(int) uartR3DataSentNotify(PPDMISERIALPORT pInterface)
1415{
1416 LogFlowFunc(("pInterface=%#p\n", pInterface));
1417 PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
1418
1419 /* Set the transmitter empty bit because everything was sent. */
1420 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
1421 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_TEMT);
1422 uartIrqUpdate(pThis);
1423 PDMCritSectLeave(&pThis->CritSect);
1424 return VINF_SUCCESS;
1425}
1426
1427
1428/**
1429 * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
1430 */
1431static DECLCALLBACK(int) uartR3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
1432{
1433 LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
1434 PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
1435
1436 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
1437
1438 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
1439 if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
1440 {
1441 *pcbRead = uartFifoCopyTo(&pThis->FifoXmit, pvBuf, cbRead);
1442 if (!pThis->FifoXmit.cbUsed)
1443 {
1444 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_THRE);
1445 pThis->fThreEmptyPending = true;
1446 }
1447 if (*pcbRead)
1448 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_TEMT);
1449 uartIrqUpdate(pThis);
1450 }
1451 else if (!(pThis->uRegLsr & UART_REG_LSR_THRE))
1452 {
1453 *(uint8_t *)pvBuf = pThis->uRegThr;
1454 *pcbRead = 1;
1455 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_THRE);
1456 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_TEMT);
1457 pThis->fThreEmptyPending = true;
1458 uartIrqUpdate(pThis);
1459 }
1460 else
1461 {
1462 /*
1463 * This can happen if there was data in the FIFO when the connection was closed,
1464 * idicate this condition to the lower driver by returning 0 bytes.
1465 */
1466 *pcbRead = 0;
1467 }
1468 PDMCritSectLeave(&pThis->CritSect);
1469
1470 LogFlowFunc(("-> VINF_SUCCESS{*pcbRead=%zu}\n", *pcbRead));
1471 return VINF_SUCCESS;
1472}
1473
1474
1475/**
1476 * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
1477 */
1478static DECLCALLBACK(int) uartR3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
1479{
1480 LogFlowFunc(("pInterface=%#p fNewStatusLines=%#x\n", pInterface, fNewStatusLines));
1481 PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
1482
1483 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
1484 uartR3StsLinesUpdate(pThis, fNewStatusLines);
1485 PDMCritSectLeave(&pThis->CritSect);
1486 return VINF_SUCCESS;
1487}
1488
1489
1490/**
1491 * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
1492 */
1493static DECLCALLBACK(int) uartR3NotifyBrk(PPDMISERIALPORT pInterface)
1494{
1495 LogFlowFunc(("pInterface=%#p\n", pInterface));
1496 PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
1497
1498 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
1499 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_BI);
1500 uartIrqUpdate(pThis);
1501 PDMCritSectLeave(&pThis->CritSect);
1502 return VINF_SUCCESS;
1503}
1504
1505
1506/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
1507
1508/**
1509 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1510 */
1511static DECLCALLBACK(void *) uartR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1512{
1513 PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, IBase);
1514 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
1515 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThis->ISerialPort);
1516 return NULL;
1517}
1518
1519
1520DECLHIDDEN(int) uartR3SaveExec(PUARTCORE pThis, PSSMHANDLE pSSM)
1521{
1522 SSMR3PutU16(pSSM, pThis->uRegDivisor);
1523 SSMR3PutU8(pSSM, pThis->uRegRbr);
1524 SSMR3PutU8(pSSM, pThis->uRegThr);
1525 SSMR3PutU8(pSSM, pThis->uRegIer);
1526 SSMR3PutU8(pSSM, pThis->uRegIir);
1527 SSMR3PutU8(pSSM, pThis->uRegFcr);
1528 SSMR3PutU8(pSSM, pThis->uRegLcr);
1529 SSMR3PutU8(pSSM, pThis->uRegMcr);
1530 SSMR3PutU8(pSSM, pThis->uRegLsr);
1531 SSMR3PutU8(pSSM, pThis->uRegMsr);
1532 SSMR3PutU8(pSSM, pThis->uRegScr);
1533 SSMR3PutBool(pSSM, pThis->fIrqCtiPending);
1534 SSMR3PutBool(pSSM, pThis->fThreEmptyPending);
1535 SSMR3PutU8(pSSM, pThis->FifoXmit.cbMax);
1536 SSMR3PutU8(pSSM, pThis->FifoXmit.cbItl);
1537 SSMR3PutU8(pSSM, pThis->FifoRecv.cbMax);
1538 SSMR3PutU8(pSSM, pThis->FifoRecv.cbItl);
1539
1540 return TMR3TimerSave(pThis->pTimerRcvFifoTimeoutR3, pSSM);
1541}
1542
1543
1544DECLHIDDEN(int) uartR3LoadExec(PUARTCORE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass,
1545 uint8_t *puIrq, RTIOPORT *pPortBase)
1546{
1547 RT_NOREF(uPass);
1548 int rc = VINF_SUCCESS;
1549
1550 if (uVersion > UART_SAVED_STATE_VERSION_LEGACY_CODE)
1551 {
1552 SSMR3GetU16(pSSM, &pThis->uRegDivisor);
1553 SSMR3GetU8(pSSM, &pThis->uRegRbr);
1554 SSMR3GetU8(pSSM, &pThis->uRegThr);
1555 SSMR3GetU8(pSSM, &pThis->uRegIer);
1556 SSMR3GetU8(pSSM, &pThis->uRegIir);
1557 SSMR3GetU8(pSSM, &pThis->uRegFcr);
1558 SSMR3GetU8(pSSM, &pThis->uRegLcr);
1559 SSMR3GetU8(pSSM, &pThis->uRegMcr);
1560 SSMR3GetU8(pSSM, &pThis->uRegLsr);
1561 SSMR3GetU8(pSSM, &pThis->uRegMsr);
1562 SSMR3GetU8(pSSM, &pThis->uRegScr);
1563 SSMR3GetBool(pSSM, &pThis->fIrqCtiPending);
1564 SSMR3GetBool(pSSM, &pThis->fThreEmptyPending);
1565 SSMR3GetU8(pSSM, &pThis->FifoXmit.cbMax);
1566 SSMR3GetU8(pSSM, &pThis->FifoXmit.cbItl);
1567 SSMR3GetU8(pSSM, &pThis->FifoRecv.cbMax);
1568 SSMR3GetU8(pSSM, &pThis->FifoRecv.cbItl);
1569
1570 TMR3TimerLoad(pThis->pTimerRcvFifoTimeoutR3, pSSM);
1571 }
1572 else
1573 {
1574 if (uVersion == UART_SAVED_STATE_VERSION_16450)
1575 {
1576 pThis->enmType = UARTTYPE_16450;
1577 LogRel(("Serial#%d: falling back to 16450 mode from load state\n", pThis->pDevInsR3->iInstance));
1578 }
1579
1580 int uIrq;
1581 int32_t iTmp;
1582 uint32_t PortBase;
1583
1584 SSMR3GetU16(pSSM, &pThis->uRegDivisor);
1585 SSMR3GetU8(pSSM, &pThis->uRegRbr);
1586 SSMR3GetU8(pSSM, &pThis->uRegIer);
1587 SSMR3GetU8(pSSM, &pThis->uRegLcr);
1588 SSMR3GetU8(pSSM, &pThis->uRegMcr);
1589 SSMR3GetU8(pSSM, &pThis->uRegLsr);
1590 SSMR3GetU8(pSSM, &pThis->uRegMsr);
1591 SSMR3GetU8(pSSM, &pThis->uRegScr);
1592 if (uVersion > UART_SAVED_STATE_VERSION_16450)
1593 SSMR3GetU8(pSSM, &pThis->uRegFcr);
1594 SSMR3GetS32(pSSM, &iTmp);
1595 pThis->fThreEmptyPending = RT_BOOL(iTmp);
1596 SSMR3GetS32(pSSM, &uIrq);
1597 SSMR3Skip(pSSM, sizeof(int32_t));
1598 SSMR3GetU32(pSSM, &PortBase);
1599 rc = SSMR3Skip(pSSM, sizeof(int32_t));
1600
1601 if ( RT_SUCCESS(rc)
1602 && uVersion > UART_SAVED_STATE_VERSION_MISSING_BITS)
1603 {
1604 SSMR3GetU8(pSSM, &pThis->uRegThr);
1605 SSMR3Skip(pSSM, sizeof(uint8_t)); /* The old transmit shift register, not used anymore. */
1606 SSMR3GetU8(pSSM, &pThis->uRegIir);
1607
1608 int iTimeoutPending = 0;
1609 SSMR3GetS32(pSSM, &iTimeoutPending);
1610 pThis->fIrqCtiPending = RT_BOOL(iTimeoutPending);
1611
1612 TMR3TimerLoad(pThis->pTimerRcvFifoTimeoutR3, pSSM);
1613 TMR3TimerSkip(pSSM, NULL);
1614 SSMR3GetU8(pSSM, &pThis->FifoRecv.cbItl);
1615 rc = SSMR3GetU8(pSSM, &pThis->FifoRecv.cbItl);
1616 }
1617
1618 if (RT_SUCCESS(rc))
1619 {
1620 AssertPtr(puIrq);
1621 AssertPtr(pPortBase);
1622 *puIrq = (uint8_t)uIrq;
1623 *pPortBase = (RTIOPORT)PortBase;
1624 }
1625 }
1626
1627 return rc;
1628}
1629
1630
1631DECLHIDDEN(int) uartR3LoadDone(PUARTCORE pThis, PSSMHANDLE pSSM)
1632{
1633 RT_NOREF(pSSM);
1634
1635 uartR3ParamsUpdate(pThis);
1636 uartIrqUpdate(pThis);
1637
1638 if (pThis->pDrvSerial)
1639 {
1640 /* Set the modem lines to reflect the current state. */
1641 int rc = pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial,
1642 RT_BOOL(pThis->uRegMcr & UART_REG_MCR_RTS),
1643 RT_BOOL(pThis->uRegMcr & UART_REG_MCR_DTR));
1644 if (RT_FAILURE(rc))
1645 LogRel(("Serial#%d: Failed to set modem lines with %Rrc during saved state load\n",
1646 pThis->pDevInsR3->iInstance, rc));
1647
1648 uint32_t fStsLines = 0;
1649 rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
1650 if (RT_SUCCESS(rc))
1651 uartR3StsLinesUpdate(pThis, fStsLines);
1652 else
1653 LogRel(("Serial#%d: Failed to query status line status with %Rrc during reset\n",
1654 pThis->pDevInsR3->iInstance, rc));
1655 }
1656
1657 return VINF_SUCCESS;
1658}
1659
1660
1661DECLHIDDEN(void) uartR3Relocate(PUARTCORE pThis, RTGCINTPTR offDelta)
1662{
1663 RT_NOREF(offDelta);
1664 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pThis->pDevInsR3);
1665 pThis->pTimerRcvFifoTimeoutRC = TMTimerRCPtr(pThis->pTimerRcvFifoTimeoutR3);
1666}
1667
1668
1669DECLHIDDEN(void) uartR3Reset(PUARTCORE pThis)
1670{
1671 pThis->uRegDivisor = 0x0c; /* Default to 9600 Baud. */
1672 pThis->uRegRbr = 0;
1673 pThis->uRegThr = 0;
1674 pThis->uRegIer = 0;
1675 pThis->uRegIir = UART_REG_IIR_IP_NO_INT;
1676 pThis->uRegFcr = 0;
1677 pThis->uRegLcr = 0; /* 5 data bits, no parity, 1 stop bit. */
1678 pThis->uRegMcr = 0;
1679 pThis->uRegLsr = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
1680 pThis->uRegMsr = 0; /* Updated below. */
1681 pThis->uRegScr = 0;
1682 pThis->fIrqCtiPending = false;
1683 pThis->fThreEmptyPending = true;
1684
1685 /* Standard FIFO size for 15550A. */
1686 pThis->FifoXmit.cbMax = 16;
1687 pThis->FifoRecv.cbMax = 16;
1688 pThis->FifoRecv.cbItl = 1;
1689
1690 uartR3XferReset(pThis);
1691}
1692
1693
1694DECLHIDDEN(int) uartR3Attach(PUARTCORE pThis, unsigned iLUN)
1695{
1696 int rc = PDMDevHlpDriverAttach(pThis->pDevInsR3, iLUN, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
1697 if (RT_SUCCESS(rc))
1698 {
1699 pThis->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMISERIALCONNECTOR);
1700 if (!pThis->pDrvSerial)
1701 {
1702 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pThis->pDevInsR3->iInstance));
1703 return VERR_PDM_MISSING_INTERFACE;
1704 }
1705 uartR3XferReset(pThis);
1706 }
1707 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1708 {
1709 pThis->pDrvBase = NULL;
1710 pThis->pDrvSerial = NULL;
1711 rc = VINF_SUCCESS;
1712 uartR3XferReset(pThis);
1713 LogRel(("Serial#%d: no unit\n", pThis->pDevInsR3->iInstance));
1714 }
1715 else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1716 LogRel(("Serial#%d: Failed to attach to serial driver. rc=%Rrc\n", pThis->pDevInsR3->iInstance, rc));
1717
1718 return rc;
1719}
1720
1721
1722DECLHIDDEN(void) uartR3Detach(PUARTCORE pThis)
1723{
1724 /* Zero out important members. */
1725 pThis->pDrvBase = NULL;
1726 pThis->pDrvSerial = NULL;
1727 uartR3XferReset(pThis);
1728}
1729
1730
1731DECLHIDDEN(void) uartR3Destruct(PUARTCORE pThis)
1732{
1733 PDMR3CritSectDelete(&pThis->CritSect);
1734}
1735
1736
1737DECLHIDDEN(int) uartR3Init(PUARTCORE pThis, PPDMDEVINS pDevInsR3, UARTTYPE enmType, unsigned iLUN, uint32_t fFlags,
1738 R3PTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqR3, R0PTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqR0,
1739 RCPTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqRC)
1740{
1741 int rc = VINF_SUCCESS;
1742
1743 /*
1744 * Initialize the instance data.
1745 * (Do this early or the destructor might choke on something!)
1746 */
1747 pThis->pDevInsR3 = pDevInsR3;
1748 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevInsR3);
1749 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevInsR3);
1750 pThis->iLUN = iLUN;
1751 pThis->enmType = enmType;
1752 pThis->fFlags = fFlags;
1753 pThis->pfnUartIrqReqR3 = pfnUartIrqReqR3;
1754 pThis->pfnUartIrqReqR0 = pfnUartIrqReqR0;
1755 pThis->pfnUartIrqReqRC = pfnUartIrqReqRC;
1756
1757 /* IBase */
1758 pThis->IBase.pfnQueryInterface = uartR3QueryInterface;
1759
1760 /* ISerialPort */
1761 pThis->ISerialPort.pfnDataAvailRdrNotify = uartR3DataAvailRdrNotify;
1762 pThis->ISerialPort.pfnDataSentNotify = uartR3DataSentNotify;
1763 pThis->ISerialPort.pfnReadWr = uartR3ReadWr;
1764 pThis->ISerialPort.pfnNotifyStsLinesChanged = uartR3NotifyStsLinesChanged;
1765 pThis->ISerialPort.pfnNotifyBrk = uartR3NotifyBrk;
1766
1767 rc = PDMDevHlpCritSectInit(pDevInsR3, &pThis->CritSect, RT_SRC_POS, "Uart{%s#%d}#%d",
1768 pDevInsR3->pReg->szName, pDevInsR3->iInstance, iLUN);
1769 AssertRCReturn(rc, rc);
1770
1771 /*
1772 * Attach the char driver and get the interfaces.
1773 */
1774 rc = PDMDevHlpDriverAttach(pDevInsR3, iLUN, &pThis->IBase, &pThis->pDrvBase, "UART");
1775 if (RT_SUCCESS(rc))
1776 {
1777 pThis->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMISERIALCONNECTOR);
1778 if (!pThis->pDrvSerial)
1779 {
1780 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iLUN));
1781 return VERR_PDM_MISSING_INTERFACE;
1782 }
1783 }
1784 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1785 {
1786 pThis->pDrvBase = NULL;
1787 pThis->pDrvSerial = NULL;
1788 LogRel(("Serial#%d: no unit\n", iLUN));
1789 }
1790 else
1791 {
1792 AssertLogRelMsgFailed(("Serial#%d: Failed to attach to char driver. rc=%Rrc\n", iLUN, rc));
1793 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1794 return rc;
1795 }
1796
1797 /*
1798 * Create the receive FIFO character timeout indicator timer.
1799 */
1800 rc = PDMDevHlpTMTimerCreate(pDevInsR3, TMCLOCK_VIRTUAL, uartR3RcvFifoTimeoutTimer, pThis,
1801 TMTIMER_FLAGS_NO_CRIT_SECT, "UART Rcv FIFO Timer",
1802 &pThis->pTimerRcvFifoTimeoutR3);
1803 AssertRCReturn(rc, rc);
1804
1805 rc = TMR3TimerSetCritSect(pThis->pTimerRcvFifoTimeoutR3, &pThis->CritSect);
1806 AssertRCReturn(rc, rc);
1807
1808 pThis->pTimerRcvFifoTimeoutR0 = TMTimerR0Ptr(pThis->pTimerRcvFifoTimeoutR3);
1809 pThis->pTimerRcvFifoTimeoutRC = TMTimerRCPtr(pThis->pTimerRcvFifoTimeoutR3);
1810
1811 uartR3Reset(pThis);
1812 return VINF_SUCCESS;
1813}
1814
1815#endif /* IN_RING3 */
1816
1817#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