VirtualBox

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

Last change on this file since 97046 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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