VirtualBox

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

Last change on this file since 84760 was 84689, checked in by vboxsync, 5 years ago

Devices/Serial/UartCore: Revert part of r137918 and switch the receive FIFO timeout timer back to just virtual because virtual sync timers, hoping that we don't require the precise timing in that path (OpenIndiana 2020 boot menu still works correctly). Also leave the device critical section before calling into the lower drivers pfnDataAvailWrNotify callback to avoid a possible deadlock

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