VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DevSerialNew.cpp@ 72195

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

Devices/Serial/DevSerialNew: Add 16550A FIFO implementation and some updates to loopback handling

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

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