VirtualBox

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

Last change on this file since 73243 was 73243, checked in by vboxsync, 7 years ago

Devices/Serial: Add missing implementation for character timeout indication when the FIFO is enabled, add 16750 implementation which provides 64byte FIFOs, additional number of bug fixes

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

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