VirtualBox

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

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

DevSerialNew,DrvHostSerialNew: Some bugfixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.8 KB
Line 
1/* $Id: DevSerialNew.cpp 72132 2018-05-06 19:40:10Z 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/** Mask of writeable bits. */
97# define UART_REG_FCR_MASK_WR 0xcf
98
99/** The LCR register index (from the base of the port range). */
100#define UART_REG_LCR_INDEX 3
101/** Word Length Select Mask. */
102# define UART_REG_LCR_WLS_MASK 0x3
103/** Returns the WLS value form the given LCR register value. */
104# define UART_REG_LCR_WLS_GET(a_Lcr) ((a_Lcr) & UART_REG_LCR_WLS_MASK)
105/** Number of stop bits. */
106# define UART_REG_LCR_STB RT_BIT(2)
107/** Parity Enable. */
108# define UART_REG_LCR_PEN RT_BIT(3)
109/** Even Parity. */
110# define UART_REG_LCR_EPS RT_BIT(4)
111/** Stick parity. */
112# define UART_REG_LCR_PAR_STICK RT_BIT(5)
113/** Set Break. */
114# define UART_REG_LCR_BRK_SET RT_BIT(6)
115/** Divisor Latch Access Bit. */
116# define UART_REG_LCR_DLAB RT_BIT(7)
117
118/** The MCR register index (from the base of the port range). */
119#define UART_REG_MCR_INDEX 4
120/** Data Terminal Ready. */
121# define UART_REG_MCR_DTR RT_BIT(0)
122/** Request To Send. */
123# define UART_REG_MCR_RTS RT_BIT(1)
124/** Out1. */
125# define UART_REG_MCR_OUT1 RT_BIT(2)
126/** Out2. */
127# define UART_REG_MCR_OUT2 RT_BIT(3)
128/** Loopback connection. */
129# define UART_REG_MCR_LOOP RT_BIT(4)
130/** Mask of writeable bits. */
131# define UART_REG_MCR_MASK_WR 0x1f
132
133/** The LSR register index (from the base of the port range). */
134#define UART_REG_LSR_INDEX 5
135/** Data Ready. */
136# define UART_REG_LSR_DR RT_BIT(0)
137/** Overrun Error. */
138# define UART_REG_LSR_OE RT_BIT(1)
139/** Parity Error. */
140# define UART_REG_LSR_PE RT_BIT(2)
141/** Framing Error. */
142# define UART_REG_LSR_FE RT_BIT(3)
143/** Break Interrupt. */
144# define UART_REG_LSR_BI RT_BIT(4)
145/** Transmitter Holding Register. */
146# define UART_REG_LSR_THRE RT_BIT(5)
147/** Transmitter Empty. */
148# define UART_REG_LSR_TEMT RT_BIT(6)
149/** Error in receiver FIFO. */
150# define UART_REG_LSR_RCV_FIFO_ERR RT_BIT(7)
151/** The bits to check in this register when checking for the RCL interrupt. */
152# define UART_REG_LSR_BITS_IIR_RCL 0x1e
153
154/** The MSR register index (from the base of the port range). */
155#define UART_REG_MSR_INDEX 6
156/** Delta Clear to Send. */
157# define UART_REG_MSR_DCTS RT_BIT(0)
158/** Delta Data Set Ready. */
159# define UART_REG_MSR_DDSR RT_BIT(1)
160/** Trailing Edge Ring Indicator. */
161# define UART_REG_MSR_TERI RT_BIT(2)
162/** Delta Data Carrier Detect. */
163# define UART_REG_MSR_DDCD RT_BIT(3)
164/** Clear to Send. */
165# define UART_REG_MSR_CTS RT_BIT(4)
166/** Data Set Ready. */
167# define UART_REG_MSR_DSR RT_BIT(5)
168/** Ring Indicator. */
169# define UART_REG_MSR_RI RT_BIT(6)
170/** Data Carrier Detect. */
171# define UART_REG_MSR_DCD RT_BIT(7)
172/** The bits to check in this register when checking for the MS interrupt. */
173# define UART_REG_MSR_BITS_IIR_MS 0x0f
174
175/** The SCR register index (from the base of the port range). */
176#define UART_REG_SCR_INDEX 7
177
178/** Set the specified bits in the given register. */
179#define UART_REG_SET(a_Reg, a_Set) ((a_Reg) |= (a_Set))
180/** Clear the specified bits in the given register. */
181#define UART_REG_CLR(a_Reg, a_Clr) ((a_Reg) &= ~(a_Clr))
182
183
184/*********************************************************************************************************************************
185* Structures and Typedefs *
186*********************************************************************************************************************************/
187
188/**
189 * Serial device.
190 *
191 * @implements PDMIBASE
192 * @implements PDMISERIALPORT
193 */
194typedef struct DEVSERIAL
195{
196 /** Access critical section. */
197 PDMCRITSECT CritSect;
198 /** Pointer to the device instance - R3 Ptr. */
199 PPDMDEVINSR3 pDevInsR3;
200 /** Pointer to the device instance - R0 Ptr. */
201 PPDMDEVINSR0 pDevInsR0;
202 /** Pointer to the device instance - RC Ptr. */
203 PPDMDEVINSRC pDevInsRC;
204 /** Alignment. */
205 RTRCPTR Alignment0;
206 /** LUN\#0: The base interface. */
207 PDMIBASE IBase;
208 /** LUN\#0: The serial port interface. */
209 PDMISERIALPORT ISerialPort;
210 /** Pointer to the attached base driver. */
211 R3PTRTYPE(PPDMIBASE) pDrvBase;
212 /** Pointer to the attached serial driver. */
213 R3PTRTYPE(PPDMISERIALCONNECTOR) pDrvSerial;
214 /** Flag whether the R0 portion of this device is enabled. */
215 bool fR0Enabled;
216 /** Flag whether the RC portion of this device is enabled. */
217 bool fRCEnabled;
218 /** Flag whether an 16550A (with FIFO) or a plain 16450 is emulated. */
219 bool f16550AEnabled;
220 /** Flag whether to yield on an guest LSR read. */
221 bool fYieldOnLSRRead;
222 /** The IRQ value. */
223 uint8_t uIrq;
224 /** The base I/O port the device is registered at. */
225 RTIOPORT PortBase;
226
227 /** The divisor register (DLAB = 1). */
228 uint16_t uRegDivisor;
229 /** The Receiver Buffer Register (RBR, DLAB = 0). */
230 uint8_t uRegRbr;
231 /** The Transmitter Holding Register (THR, DLAB = 0). */
232 uint8_t uRegThr;
233 /** The Interrupt Enable Register (IER). */
234 uint8_t uRegIer;
235 /** The Interrupt Identification Register (IIR). */
236 uint8_t uRegIir;
237 /** The FIFO Control Register (FCR). */
238 uint8_t uRegFcr;
239 /** The Line Control Register (LCR). */
240 uint8_t uRegLcr;
241 /** The Modem Control Register (MCR). */
242 uint8_t uRegMcr;
243 /** The Line Status Register (LSR). */
244 uint8_t uRegLsr;
245 /** The Modem Status Register (MSR). */
246 uint8_t uRegMsr;
247 /** The Scratch Register (SCR). */
248 uint8_t uRegScr;
249
250 /** Number of bytes available for reading from the layer below. */
251 volatile uint32_t cbAvailRdr;
252
253} DEVSERIAL;
254/** Pointer to the serial device state. */
255typedef DEVSERIAL *PDEVSERIAL;
256
257#ifndef VBOX_DEVICE_STRUCT_TESTCASE
258
259
260/*********************************************************************************************************************************
261* Global Variables *
262*********************************************************************************************************************************/
263#ifdef IN_RING3
264/**
265 * String versions of the parity enum.
266 */
267static const char *s_aszParity[] =
268{
269 "INVALID",
270 "NONE",
271 "EVEN",
272 "ODD",
273 "MARK",
274 "SPACE",
275 "INVALID"
276};
277
278
279/**
280 * String versions of the stop bits enum.
281 */
282static const char *s_aszStopBits[] =
283{
284 "INVALID",
285 "1",
286 "1.5",
287 "2",
288 "INVALID"
289};
290#endif
291
292
293/*********************************************************************************************************************************
294* Internal Functions *
295*********************************************************************************************************************************/
296
297
298/**
299 * Updates the IRQ state based on the current device state.
300 *
301 * @returns nothing.
302 * @param pThis The serial port instance.
303 */
304static void serialIrqUpdate(PDEVSERIAL pThis)
305{
306 LogFlowFunc(("pThis=%#p\n", pThis));
307
308 /*
309 * The interrupt uses a priority scheme, only the interrupt with the
310 * highest priority is indicated in the interrupt identification register.
311 *
312 * The priorities are as follows (high to low):
313 * * Receiver line status
314 * * Received data available
315 * * Character timeout indication (only in FIFO mode).
316 * * Transmitter holding register empty
317 * * Modem status change.
318 */
319 uint8_t uRegIirNew = UART_REG_IIR_IP_NO_INT;
320 if ( (pThis->uRegLsr & UART_REG_LSR_BITS_IIR_RCL)
321 && (pThis->uRegIer & UART_REG_IER_ELSI))
322 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_RCL);
323 else if ( (pThis->uRegLsr & UART_REG_LSR_DR)
324 && (pThis->uRegIer & UART_REG_IER_ERBFI))
325 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_RDA);
326 else if ( (pThis->uRegLsr & UART_REG_LSR_THRE)
327 && (pThis->uRegIer & UART_REG_IER_ETBEI))
328 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_THRE);
329 else if ( (pThis->uRegMsr & UART_REG_MSR_BITS_IIR_MS)
330 && (pThis->uRegIer & UART_REG_IER_EDSSI))
331 uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_MS);
332
333 /** @todo Character timeout indication for FIFO mode. */
334
335 LogFlowFunc((" uRegIirNew=%#x uRegIir=%#x\n", uRegIirNew, pThis->uRegIir));
336
337 /* Change interrupt only if the interrupt status really changed from the previous value. */
338 if (uRegIirNew != (pThis->uRegIir & UART_REG_IIR_CHANGED_MASK))
339 {
340 LogFlow((" Interrupt source changed from %#x -> %#x (IRQ %d -> %d)\n",
341 pThis->uRegIir, uRegIirNew,
342 pThis->uRegIir == UART_REG_IIR_IP_NO_INT ? 0 : 1,
343 uRegIirNew == UART_REG_IIR_IP_NO_INT ? 0 : 1));
344 if (uRegIirNew == UART_REG_IIR_IP_NO_INT)
345 PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->uIrq, 0);
346 else
347 PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->uIrq, 1);
348 }
349 else
350 LogFlow((" No change in interrupt source\n"));
351
352 if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
353 uRegIirNew |= UART_REG_IIR_FIFOS_EN;
354
355 pThis->uRegIir = uRegIirNew;
356}
357
358
359#ifdef IN_RING3
360/**
361 * Updates the serial port parameters of the attached driver with the current configuration.
362 *
363 * @returns nothing.
364 * @param pThis The serial port instance.
365 */
366static void serialR3ParamsUpdate(PDEVSERIAL pThis)
367{
368 if ( pThis->uRegDivisor != 0
369 && pThis->pDrvSerial)
370 {
371 uint32_t uBps = 115200 / pThis->uRegDivisor; /* This is for PC compatible serial port with a 1.8432 MHz crystal. */
372 unsigned cDataBits = UART_REG_LCR_WLS_GET(pThis->uRegLcr) + 5;
373 PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE;
374 PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE;
375
376 if (pThis->uRegLcr & UART_REG_LCR_STB)
377 {
378 enmStopBits = cDataBits == 5 ? PDMSERIALSTOPBITS_ONEPOINTFIVE : PDMSERIALSTOPBITS_TWO;
379 }
380
381 if (pThis->uRegLcr & UART_REG_LCR_PEN)
382 {
383 /* Select the correct parity mode based on the even and stick parity bits. */
384 switch (pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK))
385 {
386 case 0:
387 enmParity = PDMSERIALPARITY_ODD;
388 break;
389 case UART_REG_LCR_EPS:
390 enmParity = PDMSERIALPARITY_EVEN;
391 break;
392 case UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK:
393 enmParity = PDMSERIALPARITY_SPACE;
394 break;
395 case UART_REG_LCR_PAR_STICK:
396 enmParity = PDMSERIALPARITY_MARK;
397 break;
398 default:
399 /* We should never get here as all cases where caught earlier. */
400 AssertMsgFailed(("This shouldn't happen at all: %#x\n",
401 pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK)));
402 }
403 }
404
405 LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n",
406 uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits]));
407
408 int rc = pThis->pDrvSerial->pfnChgParams(pThis->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits);
409 if (RT_FAILURE(rc))
410 LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n",
411 pThis->pDevInsR3->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc));
412 }
413}
414
415
416/**
417 * Updates the internal device state with the given PDM status line states.
418 *
419 * @returns nothing.
420 * @param pThis The serial port instance.
421 * @param fStsLines The PDM status line states.
422 */
423static void serialR3StsLinesUpdate(PDEVSERIAL pThis, uint32_t fStsLines)
424{
425 uint8_t uRegMsrNew = 0; /* The new MSR value. */
426
427 if (fStsLines & PDMISERIALPORT_STS_LINE_DCD)
428 uRegMsrNew |= UART_REG_MSR_DCD;
429 if (fStsLines & PDMISERIALPORT_STS_LINE_RI)
430 uRegMsrNew |= UART_REG_MSR_RI;
431 if (fStsLines & PDMISERIALPORT_STS_LINE_DSR)
432 uRegMsrNew |= UART_REG_MSR_DSR;
433 if (fStsLines & PDMISERIALPORT_STS_LINE_CTS)
434 uRegMsrNew |= UART_REG_MSR_CTS;
435
436 /* Compare current and new states and set remaining bits accordingly. */
437 if ((uRegMsrNew & UART_REG_MSR_CTS) != (pThis->uRegMsr & UART_REG_MSR_CTS))
438 uRegMsrNew |= UART_REG_MSR_DCTS;
439 if ((uRegMsrNew & UART_REG_MSR_DSR) != (pThis->uRegMsr & UART_REG_MSR_DSR))
440 uRegMsrNew |= UART_REG_MSR_DDSR;
441 if ((uRegMsrNew & UART_REG_MSR_RI) != 0 && (pThis->uRegMsr & UART_REG_MSR_RI) == 0)
442 uRegMsrNew |= UART_REG_MSR_TERI;
443 if ((uRegMsrNew & UART_REG_MSR_DCD) != (pThis->uRegMsr & UART_REG_MSR_DCD))
444 uRegMsrNew |= UART_REG_MSR_DDCD;
445
446 pThis->uRegMsr = uRegMsrNew;
447
448 serialIrqUpdate(pThis);
449}
450#endif
451
452
453/**
454 * Write handler for the THR/DLL register (depending on the DLAB bit in LCR).
455 *
456 * @returns VBox status code.
457 * @param pThis The serial port instance.
458 * @param uVal The value to write.
459 */
460DECLINLINE(int) serialRegThrDllWrite(PDEVSERIAL pThis, uint8_t uVal)
461{
462 int rc = VINF_SUCCESS;
463
464 /* A set DLAB causes a write to the lower 8bits of the divisor latch. */
465 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
466 {
467 if (uVal != (pThis->uRegDivisor & 0xff))
468 {
469#ifndef IN_RING3
470 rc = VINF_IOM_R3_IOPORT_WRITE;
471#else
472 pThis->uRegDivisor = (pThis->uRegDivisor & 0xff00) | uVal;
473 serialR3ParamsUpdate(pThis);
474#endif
475 }
476 }
477 else
478 {
479 if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
480 {
481 /** @todo FIFO handling. */
482 }
483 else
484 {
485 /* Notify the lower driver about available data only if the register was empty before. */
486 if (pThis->uRegLsr & UART_REG_LSR_THRE)
487 {
488#ifndef IN_RING3
489 rc = VINF_IOM_R3_IOPORT_WRITE;
490#else
491 pThis->uRegThr = uVal;
492 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
493 if (pThis->pDrvSerial)
494 {
495 int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial, 1);
496 if (RT_FAILURE(rc2))
497 LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", rc2));
498 }
499#endif
500 }
501 else
502 pThis->uRegThr = uVal;
503 }
504 }
505
506 return rc;
507}
508
509
510/**
511 * Write handler for the IER/DLM register (depending on the DLAB bit in LCR).
512 *
513 * @returns VBox status code.
514 * @param pThis The serial port instance.
515 * @param uVal The value to write.
516 */
517DECLINLINE(int) serialRegIerDlmWrite(PDEVSERIAL pThis, uint8_t uVal)
518{
519 int rc = VINF_SUCCESS;
520
521 /* A set DLAB causes a write to the higher 8bits of the divisor latch. */
522 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
523 {
524 if (uVal != (pThis->uRegDivisor & 0xff00) >> 8)
525 {
526#ifndef IN_RING3
527 rc = VINF_IOM_R3_IOPORT_WRITE;
528#else
529 pThis->uRegDivisor = (pThis->uRegDivisor & 0xff) | (uVal << 8);
530 serialR3ParamsUpdate(pThis);
531#endif
532 }
533 }
534 else
535 {
536 pThis->uRegIer = uVal & UART_REG_IER_MASK_WR;
537 serialIrqUpdate(pThis);
538 }
539
540 return rc;
541}
542
543
544/**
545 * Write handler for the FCR register.
546 *
547 * @returns VBox status code.
548 * @param pThis The serial port instance.
549 * @param uVal The value to write.
550 */
551DECLINLINE(int) serialRegFcrWrite(PDEVSERIAL pThis, uint8_t uVal)
552{
553 int rc = VINF_SUCCESS;
554
555 RT_NOREF(uVal);
556 if (pThis->f16550AEnabled)
557 {
558 /** @todo */
559 }
560
561 return rc;
562}
563
564
565/**
566 * Write handler for the LCR register.
567 *
568 * @returns VBox status code.
569 * @param pThis The serial port instance.
570 * @param uVal The value to write.
571 */
572DECLINLINE(int) serialRegLcrWrite(PDEVSERIAL pThis, uint8_t uVal)
573{
574 int rc = VINF_SUCCESS;
575
576 /* Any change except the DLAB bit causes a switch to R3. */
577 if ((pThis->uRegLcr & ~UART_REG_LCR_DLAB) != (uVal & ~UART_REG_LCR_DLAB))
578 {
579#ifndef IN_RING3
580 rc = VINF_IOM_R3_IOPORT_WRITE;
581#else
582 /* Check whether the BREAK bit changed before updating the LCR value. */
583 bool fBrkEn = RT_BOOL(uVal & UART_REG_LCR_BRK_SET);
584 bool fBrkChg = fBrkEn != RT_BOOL(pThis->uRegLcr & UART_REG_LCR_BRK_SET);
585 pThis->uRegLcr = uVal;
586 serialR3ParamsUpdate(pThis);
587
588 if ( fBrkChg
589 && pThis->pDrvSerial)
590 pThis->pDrvSerial->pfnChgBrk(pThis->pDrvSerial, fBrkEn);
591#endif
592 }
593 else
594 pThis->uRegLcr = uVal;
595
596 return rc;
597}
598
599
600/**
601 * Write handler for the MCR register.
602 *
603 * @returns VBox status code.
604 * @param pThis The serial port instance.
605 * @param uVal The value to write.
606 */
607DECLINLINE(int) serialRegMcrWrite(PDEVSERIAL pThis, uint8_t uVal)
608{
609 int rc = VINF_SUCCESS;
610
611 uVal &= UART_REG_MCR_MASK_WR;
612 if (pThis->uRegMcr != uVal)
613 {
614#ifndef IN_RING3
615 rc = VINF_IOM_R3_IOPORT_WRITE;
616#else
617 /** @todo Loopback mode handling (setting RTS, DTR to high looping everything to MSR). */
618 pThis->uRegMcr = uVal;
619 if (pThis->pDrvSerial)
620 pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial,
621 RT_BOOL(uVal & UART_REG_MCR_RTS),
622 RT_BOOL(uVal & UART_REG_MCR_DTR));
623#endif
624 }
625
626 return rc;
627}
628
629
630/**
631 * Read handler for the RBR/DLL register (depending on the DLAB bit in LCR).
632 *
633 * @returns VBox status code.
634 * @param pThis The serial port instance.
635 * @param puVal Where to store the read value on success.
636 */
637DECLINLINE(int) serialRegRbrDllRead(PDEVSERIAL pThis, uint32_t *puVal)
638{
639 int rc = VINF_SUCCESS;
640
641 /* A set DLAB causes a read from the lower 8bits of the divisor latch. */
642 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
643 *puVal = pThis->uRegDivisor & 0xff;
644 else
645 {
646 *puVal = pThis->uRegRbr;
647
648 if (pThis->uRegLsr & UART_REG_LSR_DR)
649 {
650 uint32_t cbAvail = ASMAtomicDecU32(&pThis->cbAvailRdr);
651 if (!cbAvail)
652 {
653 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
654 serialIrqUpdate(pThis);
655 }
656 else
657 {
658#ifndef IN_RING3
659 /* Restore state and go back to R3. */
660 ASMAtomicIncU32(&pThis->cbAvailRdr);
661 rc = VINF_IOM_R3_IOPORT_READ;
662#else
663 /* Fetch new data and keep the DR bit set. */
664 AssertPtr(pThis->pDrvSerial);
665 size_t cbRead = 0;
666 int rc2 = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pThis->uRegRbr, 1, &cbRead);
667 AssertMsg(RT_SUCCESS(rc2) && cbRead == 1, ("This shouldn't fail and always return one byte!\n"));
668 serialIrqUpdate(pThis);
669#endif
670 }
671 }
672 }
673
674 return rc;
675}
676
677
678/**
679 * Read handler for the IER/DLM register (depending on the DLAB bit in LCR).
680 *
681 * @returns VBox status code.
682 * @param pThis The serial port instance.
683 * @param puVal Where to store the read value on success.
684 */
685DECLINLINE(int) serialRegIerDlmRead(PDEVSERIAL pThis, uint32_t *puVal)
686{
687 int rc = VINF_SUCCESS;
688
689 /* A set DLAB causes a read from the upper 8bits of the divisor latch. */
690 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
691 *puVal = (pThis->uRegDivisor & 0xff00) >> 8;
692 else
693 *puVal = pThis->uRegIer;
694
695 return rc;
696}
697
698
699/**
700 * Read handler for the IIR register.
701 *
702 * @returns VBox status code.
703 * @param pThis The serial port instance.
704 * @param puVal Where to store the read value on success.
705 */
706DECLINLINE(int) serialRegIirRead(PDEVSERIAL pThis, uint32_t *puVal)
707{
708 *puVal = pThis->uRegIir;
709 return VINF_SUCCESS;
710}
711
712
713/**
714 * Read handler for the LSR register.
715 *
716 * @returns VBox status code.
717 * @param pThis The serial port instance.
718 * @param puVal Where to store the read value on success.
719 */
720DECLINLINE(int) serialRegLsrRead(PDEVSERIAL pThis, uint32_t *puVal)
721{
722 int rc = VINF_SUCCESS;
723
724 /* Yield if configured and there is no data available. */
725 if ( !(pThis->uRegLsr & UART_REG_LSR_DR)
726 && pThis->fYieldOnLSRRead)
727 {
728#ifndef IN_RING3
729 return VINF_IOM_R3_IOPORT_READ;
730#else
731 RTThreadYield();
732#endif
733 }
734
735 *puVal = pThis->uRegLsr;
736 /*
737 * Reading this register clears the Overrun (OE), Parity (PE) and Framing (FE) error
738 * as well as the Break Interrupt (BI).
739 */
740 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_BITS_IIR_RCL);
741 serialIrqUpdate(pThis);
742
743 return rc;
744}
745
746
747/**
748 * Read handler for the MSR register.
749 *
750 * @returns VBox status code.
751 * @param pThis The serial port instance.
752 * @param puVal Where to store the read value on success.
753 */
754DECLINLINE(int) serialRegMsrRead(PDEVSERIAL pThis, uint32_t *puVal)
755{
756 *puVal = pThis->uRegMsr;
757
758 /** @todo Loopback handling. */
759 /* Clear any of the delta bits. */
760 UART_REG_CLR(pThis->uRegMsr, UART_REG_MSR_BITS_IIR_MS);
761 serialIrqUpdate(pThis);
762 return VINF_SUCCESS;
763}
764
765
766#ifdef LOG_ENABLED
767/**
768 * Converts the register index into a sensible memnonic.
769 *
770 * @returns Register memnonic.
771 * @param pThis The serial port instance.
772 * @param idxReg Register index.
773 * @param fWrite Flag whether the register gets written.
774 */
775DECLINLINE(const char *) serialRegIdx2Str(PDEVSERIAL pThis, uint8_t idxReg, bool fWrite)
776{
777 const char *psz = "INV";
778
779 switch (idxReg)
780 {
781 /*case UART_REG_THR_DLL_INDEX:*/
782 case UART_REG_RBR_DLL_INDEX:
783 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
784 psz = "DLL";
785 else if (fWrite)
786 psz = "THR";
787 else
788 psz = "RBR";
789 break;
790 case UART_REG_IER_DLM_INDEX:
791 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
792 psz = "DLM";
793 else
794 psz = "IER";
795 break;
796 /*case UART_REG_IIR_INDEX:*/
797 case UART_REG_FCR_INDEX:
798 if (fWrite)
799 psz = "FCR";
800 else
801 psz = "IIR";
802 break;
803 case UART_REG_LCR_INDEX:
804 psz = "LCR";
805 break;
806 case UART_REG_MCR_INDEX:
807 psz = "MCR";
808 break;
809 case UART_REG_LSR_INDEX:
810 psz = "LSR";
811 break;
812 case UART_REG_MSR_INDEX:
813 psz = "MSR";
814 break;
815 case UART_REG_SCR_INDEX:
816 psz = "SCR";
817 break;
818 }
819
820 return psz;
821}
822#endif
823
824/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
825
826/**
827 * @callback_method_impl{FNIOMIOPORTOUT}
828 */
829PDMBOTHCBDECL(int) serialIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
830{
831 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
832 Assert(PDMCritSectIsOwner(&pThis->CritSect));
833 RT_NOREF_PV(pvUser);
834
835 uint8_t idxReg = uPort & 0x7;
836 LogFlowFunc(("pDevIns=%#p pvUser=%#p uPort=%RTiop{%s} u32=%#x cb=%u\n",
837 pDevIns, pvUser, uPort, serialRegIdx2Str(pThis, idxReg, true /*fWrite*/), u32, cb));
838
839 AssertMsgReturn(cb == 1, ("uPort=%#x cb=%d u32=%#x\n", uPort, cb, u32), VINF_SUCCESS);
840
841 int rc = VINF_SUCCESS;
842 uint8_t uVal = (uint8_t)u32;
843 switch (idxReg)
844 {
845 case UART_REG_THR_DLL_INDEX:
846 rc = serialRegThrDllWrite(pThis, uVal);
847 break;
848 case UART_REG_IER_DLM_INDEX:
849 rc = serialRegIerDlmWrite(pThis, uVal);
850 break;
851 case UART_REG_FCR_INDEX:
852 rc = serialRegFcrWrite(pThis, uVal);
853 break;
854 case UART_REG_LCR_INDEX:
855 rc = serialRegLcrWrite(pThis, uVal);
856 break;
857 case UART_REG_MCR_INDEX:
858 rc = serialRegMcrWrite(pThis, uVal);
859 break;
860 case UART_REG_SCR_INDEX:
861 pThis->uRegScr = u32;
862 break;
863 default:
864 break;
865 }
866
867 LogFlowFunc(("-> %Rrc\n", rc));
868 return rc;
869}
870
871
872/**
873 * @callback_method_impl{FNIOMIOPORTIN}
874 */
875PDMBOTHCBDECL(int) serialIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
876{
877 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
878 Assert(PDMCritSectIsOwner(&pThis->CritSect));
879 RT_NOREF_PV(pvUser);
880
881 if (cb != 1)
882 return VERR_IOM_IOPORT_UNUSED;
883
884 uint8_t idxReg = uPort & 0x7;
885 int rc = VINF_SUCCESS;
886 switch (idxReg)
887 {
888 case UART_REG_RBR_DLL_INDEX:
889 rc = serialRegRbrDllRead(pThis, pu32);
890 break;
891 case UART_REG_IER_DLM_INDEX:
892 rc = serialRegIerDlmRead(pThis, pu32);
893 break;
894 case UART_REG_IIR_INDEX:
895 rc = serialRegIirRead(pThis, pu32);
896 break;
897 case UART_REG_LCR_INDEX:
898 *pu32 = pThis->uRegLcr;
899 break;
900 case UART_REG_MCR_INDEX:
901 *pu32 = pThis->uRegMcr;
902 break;
903 case UART_REG_LSR_INDEX:
904 rc = serialRegLsrRead(pThis, pu32);
905 break;
906 case UART_REG_MSR_INDEX:
907 rc = serialRegMsrRead(pThis, pu32);
908 break;
909 case UART_REG_SCR_INDEX:
910 *pu32 = pThis->uRegScr;
911 break;
912 default:
913 rc = VERR_IOM_IOPORT_UNUSED;
914 }
915
916 LogFlowFunc(("pDevIns=%#p pvUser=%#p uPort=%RTiop{%s} u32=%#x cb=%u -> %Rrc\n",
917 pDevIns, pvUser, uPort, serialRegIdx2Str(pThis, idxReg, false /*fWrite*/), *pu32, cb, rc));
918 return rc;
919}
920
921
922#ifdef IN_RING3
923
924/* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
925
926
927/**
928 * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
929 */
930static DECLCALLBACK(int) serialR3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
931{
932 LogFlowFunc(("pInterface=%#p cbAvail=%zu\n", pInterface, cbAvail));
933 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
934
935 AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
936
937 uint32_t cbAvailOld = ASMAtomicAddU32(&pThis->cbAvailRdr, (uint32_t)cbAvail);
938 if (!cbAvailOld)
939 {
940 LogFlow((" cbAvailRdr=0 -> cbAvailRdr=%zu\n", cbAvail));
941 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
942 size_t cbRead = 0;
943 int rc = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pThis->uRegRbr, 1, &cbRead);
944 AssertMsg(RT_SUCCESS(rc) && cbRead == 1, ("This shouldn't fail and always return one byte!\n"));
945 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
946 serialIrqUpdate(pThis);
947 PDMCritSectLeave(&pThis->CritSect);
948 }
949 else
950 LogFlow((" cbAvailOld=%zu\n", cbAvailOld));
951 return VINF_SUCCESS;
952}
953
954
955/**
956 * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
957 */
958static DECLCALLBACK(int) serialR3DataSentNotify(PPDMISERIALPORT pInterface)
959{
960 LogFlowFunc(("pInterface=%#p\n", pInterface));
961 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
962
963 /* Set the transmitter empty bit because everything was sent. */
964 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
965 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_TEMT);
966 serialIrqUpdate(pThis);
967 PDMCritSectLeave(&pThis->CritSect);
968 return VINF_SUCCESS;
969}
970
971
972/**
973 * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
974 */
975static DECLCALLBACK(int) serialR3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
976{
977 LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
978 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
979
980 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
981
982 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
983 if (!(pThis->uRegLsr & UART_REG_LSR_THRE))
984 {
985 /** @todo FIFO mode. */
986 *(uint8_t *)pvBuf = pThis->uRegThr;
987 *pcbRead = 1;
988 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_THRE);
989 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_TEMT);
990 serialIrqUpdate(pThis);
991 }
992 else
993 {
994 AssertMsgFailed(("There is no data to read!\n"));
995 *pcbRead = 0;
996 }
997
998 LogFlowFunc(("-> VINF_SUCCESS{*pcbRead=%zu}\n", *pcbRead));
999 PDMCritSectLeave(&pThis->CritSect);
1000 return VINF_SUCCESS;
1001}
1002
1003
1004/**
1005 * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
1006 */
1007static DECLCALLBACK(int) serialR3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
1008{
1009 LogFlowFunc(("pInterface=%#p fNewStatusLines=%#x\n", pInterface, fNewStatusLines));
1010 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
1011
1012 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
1013 serialR3StsLinesUpdate(pThis, fNewStatusLines);
1014 PDMCritSectLeave(&pThis->CritSect);
1015 return VINF_SUCCESS;
1016}
1017
1018
1019/**
1020 * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
1021 */
1022static DECLCALLBACK(int) serialR3NotifyBrk(PPDMISERIALPORT pInterface)
1023{
1024 LogFlowFunc(("pInterface=%#p\n", pInterface));
1025 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
1026
1027 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
1028 UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_BI);
1029 serialIrqUpdate(pThis);
1030 PDMCritSectLeave(&pThis->CritSect);
1031 return VINF_SUCCESS;
1032}
1033
1034
1035/* -=-=-=-=-=-=-=-=- PDMIBASE on LUN#0 -=-=-=-=-=-=-=-=- */
1036
1037/**
1038 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1039 */
1040static DECLCALLBACK(void *) serialR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1041{
1042 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, IBase);
1043 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
1044 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThis->ISerialPort);
1045 return NULL;
1046}
1047
1048
1049/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
1050
1051/**
1052 * @interface_method_impl{PDMDEVREG,pfnRelocate}
1053 */
1054static DECLCALLBACK(void) serialR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1055{
1056 RT_NOREF(offDelta);
1057 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1058
1059 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1060}
1061
1062
1063/**
1064 * @interface_method_impl{PDMDEVREG,pfnReset}
1065 */
1066static DECLCALLBACK(void) serialR3Reset(PPDMDEVINS pDevIns)
1067{
1068 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1069
1070 pThis->uRegDivisor = 0x0c; /* Default to 9600 Baud. */
1071 pThis->uRegRbr = 0;
1072 pThis->uRegThr = 0;
1073 pThis->uRegIer = 0;
1074 pThis->uRegIir = UART_REG_IIR_IP_NO_INT;
1075 pThis->uRegFcr = 0;
1076 pThis->uRegLcr = 0; /* 5 data bits, no parity, 1 stop bit. */
1077 pThis->uRegMcr = 0;
1078 pThis->uRegLsr = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
1079 pThis->uRegMsr = 0; /* Updated below. */
1080 pThis->uRegScr = 0;
1081
1082 /** @todo Clear FIFOs. */
1083 serialR3ParamsUpdate(pThis);
1084 serialIrqUpdate(pThis);
1085
1086 if (pThis->pDrvSerial)
1087 {
1088 /* Set the modem lines to reflect the current state. */
1089 int rc = pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial, false /*fRts*/, false /*fDtr*/);
1090 if (RT_FAILURE(rc))
1091 LogRel(("Serial#%d: Failed to set modem lines with %Rrc during reset\n",
1092 pThis->pDevInsR3->iInstance, rc));
1093
1094 uint32_t fStsLines = 0;
1095 rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
1096 if (RT_SUCCESS(rc))
1097 serialR3StsLinesUpdate(pThis, fStsLines);
1098 else
1099 LogRel(("Serial#%d: Failed to query status line status with %Rrc during reset\n",
1100 pThis->pDevInsR3->iInstance, rc));
1101 }
1102}
1103
1104
1105/**
1106 * @interface_method_impl{PDMDEVREG,pfnAttach}
1107 */
1108static DECLCALLBACK(int) serialR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1109{
1110 RT_NOREF(iLUN, fFlags);
1111 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1112
1113 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
1114 if (RT_SUCCESS(rc))
1115 {
1116 pThis->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMISERIALCONNECTOR);
1117 if (!pThis->pDrvSerial)
1118 {
1119 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pDevIns->iInstance));
1120 return VERR_PDM_MISSING_INTERFACE;
1121 }
1122 }
1123 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1124 {
1125 pThis->pDrvBase = NULL;
1126 pThis->pDrvSerial = NULL;
1127 rc = VINF_SUCCESS;
1128 LogRel(("Serial#%d: no unit\n", pDevIns->iInstance));
1129 }
1130 else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1131 LogRel(("Serial#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
1132
1133 return rc;
1134}
1135
1136
1137/**
1138 * @interface_method_impl{PDMDEVREG,pfnDetach}
1139 */
1140static DECLCALLBACK(void) serialR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1141{
1142 RT_NOREF(iLUN, fFlags);
1143 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1144
1145 /* Zero out important members. */
1146 pThis->pDrvBase = NULL;
1147 pThis->pDrvSerial = NULL;
1148}
1149
1150
1151/**
1152 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1153 */
1154static DECLCALLBACK(int) serialR3Destruct(PPDMDEVINS pDevIns)
1155{
1156 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1157 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1158
1159 PDMR3CritSectDelete(&pThis->CritSect);
1160 return VINF_SUCCESS;
1161}
1162
1163
1164/**
1165 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1166 */
1167static DECLCALLBACK(int) serialR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1168{
1169 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
1170 int rc = VINF_SUCCESS;
1171
1172 Assert(iInstance < 4);
1173 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1174
1175 /*
1176 * Initialize the instance data.
1177 * (Do this early or the destructor might choke on something!)
1178 */
1179 pThis->pDevInsR3 = pDevIns;
1180 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1181 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1182
1183 /* IBase */
1184 pThis->IBase.pfnQueryInterface = serialR3QueryInterface;
1185
1186 /* ISerialPort */
1187 pThis->ISerialPort.pfnDataAvailRdrNotify = serialR3DataAvailRdrNotify;
1188 pThis->ISerialPort.pfnDataSentNotify = serialR3DataSentNotify;
1189 pThis->ISerialPort.pfnReadWr = serialR3ReadWr;
1190 pThis->ISerialPort.pfnNotifyStsLinesChanged = serialR3NotifyStsLinesChanged;
1191 pThis->ISerialPort.pfnNotifyBrk = serialR3NotifyBrk;
1192
1193 /*
1194 * Validate and read the configuration.
1195 */
1196 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
1197 "IOBase\0"
1198 "GCEnabled\0"
1199 "R0Enabled\0"
1200 "YieldOnLSRRead\0"
1201 "Enable16550A\0"
1202 ))
1203 {
1204 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
1205 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1206 }
1207
1208 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fRCEnabled, true);
1209 if (RT_FAILURE(rc))
1210 return PDMDEV_SET_ERROR(pDevIns, rc,
1211 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
1212
1213 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
1214 if (RT_FAILURE(rc))
1215 return PDMDEV_SET_ERROR(pDevIns, rc,
1216 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
1217
1218 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
1219 if (RT_FAILURE(rc))
1220 return PDMDEV_SET_ERROR(pDevIns, rc,
1221 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
1222
1223 uint8_t uIrq = 0;
1224 rc = CFGMR3QueryU8(pCfg, "IRQ", &uIrq);
1225 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1226 {
1227 /* Provide sensible defaults. */
1228 if (iInstance == 0)
1229 uIrq = 4;
1230 else if (iInstance == 1)
1231 uIrq = 3;
1232 else
1233 AssertReleaseFailed(); /* irq_lvl is undefined. */
1234 }
1235 else if (RT_FAILURE(rc))
1236 return PDMDEV_SET_ERROR(pDevIns, rc,
1237 N_("Configuration error: Failed to get the \"IRQ\" value"));
1238
1239 uint16_t uIoBase = 0;
1240 rc = CFGMR3QueryU16(pCfg, "IOBase", &uIoBase);
1241 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1242 {
1243 if (iInstance == 0)
1244 uIoBase = 0x3f8;
1245 else if (iInstance == 1)
1246 uIoBase = 0x2f8;
1247 else
1248 AssertReleaseFailed(); /* uIoBase is undefined */
1249 }
1250 else if (RT_FAILURE(rc))
1251 return PDMDEV_SET_ERROR(pDevIns, rc,
1252 N_("Configuration error: Failed to get the \"IOBase\" value"));
1253
1254 rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, false);
1255 if (RT_FAILURE(rc))
1256 return PDMDEV_SET_ERROR(pDevIns, rc,
1257 N_("Configuration error: Failed to get the \"Enable16550A\" value"));
1258
1259 pThis->uIrq = uIrq;
1260 pThis->PortBase = uIoBase;
1261
1262 LogRel(("Serial#%d: emulating %s (IOBase: %04x IRQ: %u)\n",
1263 pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450", uIoBase, uIrq));
1264
1265 /*
1266 * Initialize critical section and the semaphore. Change the default
1267 * critical section to ours so that TM and IOM will enter it before
1268 * calling us.
1269 *
1270 * Note! This must of be done BEFORE creating timers, registering I/O ports
1271 * and other things which might pick up the default CS or end up
1272 * calling back into the device.
1273 */
1274 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
1275 AssertRCReturn(rc, rc);
1276
1277 rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
1278 AssertRCReturn(rc, rc);
1279
1280 /*
1281 * Register the I/O ports.
1282 */
1283 rc = PDMDevHlpIOPortRegister(pDevIns, uIoBase, 8, 0,
1284 serialIoPortWrite, serialIoPortRead,
1285 NULL, NULL, "SERIAL");
1286 if (RT_FAILURE(rc))
1287 return rc;
1288
1289 if (pThis->fRCEnabled)
1290 {
1291 rc = PDMDevHlpIOPortRegisterRC(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
1292 "serialIoPortRead", NULL, NULL, "SERIAL");
1293 if (RT_FAILURE(rc))
1294 return rc;
1295 }
1296
1297 if (pThis->fR0Enabled)
1298 {
1299 rc = PDMDevHlpIOPortRegisterR0(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
1300 "serialIoPortRead", NULL, NULL, "SERIAL");
1301 if (RT_FAILURE(rc))
1302 return rc;
1303 }
1304
1305#if 0 /** @todo Later */
1306 /*
1307 * Saved state.
1308 */
1309 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
1310 serialR3LiveExec, serialR3SaveExec, serialR3LoadExec);
1311 if (RT_FAILURE(rc))
1312 return rc;
1313#endif
1314
1315 /*
1316 * Attach the char driver and get the interfaces.
1317 */
1318 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial");
1319 if (RT_SUCCESS(rc))
1320 {
1321 pThis->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMISERIALCONNECTOR);
1322 if (!pThis->pDrvSerial)
1323 {
1324 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iInstance));
1325 return VERR_PDM_MISSING_INTERFACE;
1326 }
1327 }
1328 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1329 {
1330 pThis->pDrvBase = NULL;
1331 pThis->pDrvSerial = NULL;
1332 LogRel(("Serial#%d: no unit\n", iInstance));
1333 }
1334 else
1335 {
1336 AssertLogRelMsgFailed(("Serial#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1337 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1338 return rc;
1339 }
1340
1341 serialR3Reset(pDevIns);
1342 return VINF_SUCCESS;
1343}
1344
1345
1346/**
1347 * The device registration structure.
1348 */
1349const PDMDEVREG g_DeviceSerialPort =
1350{
1351 /* u32Version */
1352 PDM_DEVREG_VERSION,
1353 /* szName */
1354 "serial",
1355 /* szRCMod */
1356 "VBoxDDRC.rc",
1357 /* szR0Mod */
1358 "VBoxDDR0.r0",
1359 /* pszDescription */
1360 "Serial Communication Port",
1361 /* fFlags */
1362 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1363 /* fClass */
1364 PDM_DEVREG_CLASS_SERIAL,
1365 /* cMaxInstances */
1366 UINT32_MAX,
1367 /* cbInstance */
1368 sizeof(DEVSERIAL),
1369 /* pfnConstruct */
1370 serialR3Construct,
1371 /* pfnDestruct */
1372 serialR3Destruct,
1373 /* pfnRelocate */
1374 serialR3Relocate,
1375 /* pfnMemSetup */
1376 NULL,
1377 /* pfnPowerOn */
1378 NULL,
1379 /* pfnReset */
1380 serialR3Reset,
1381 /* pfnSuspend */
1382 NULL,
1383 /* pfnResume */
1384 NULL,
1385 /* pfnAttach */
1386 serialR3Attach,
1387 /* pfnDetach */
1388 serialR3Detach,
1389 /* pfnQueryInterface. */
1390 NULL,
1391 /* pfnInitComplete */
1392 NULL,
1393 /* pfnPowerOff */
1394 NULL,
1395 /* pfnSoftReset */
1396 NULL,
1397 /* u32VersionEnd */
1398 PDM_DEVREG_VERSION
1399};
1400#endif /* IN_RING3 */
1401
1402#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