VirtualBox

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

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

Devices/Serial: Remove giving the amount of available data to write from the UART core and let the drivers figure it out themselves when querying the data to write. Avoids unnecessary trips to R3 when the FIFO is enabled if the guest keeps the FIFO filled. Some other smaller fixes

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