VirtualBox

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

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

Serial: Split out the generic UART functionality into a separate module so it can be reused.

Add a PCI Express 16 port UART controller emulation based on the Oxford Semiconductor OXPCIe958
PCI Express to octa UART controller (supports chaining two of those together in a single device
to get up to 16 UARTs). This somewhat revives the incomplete and never enabled PCI UART controller
in the old code. Linux detects the device and apparently configures all 16 UARTs but data transfers
were not tested and the code is pretty incomplete still.

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

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