VirtualBox

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

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

make scm happy

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