VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DevSerial.cpp@ 34497

Last change on this file since 34497 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.6 KB
Line 
1/* $Id: DevSerial.cpp 33540 2010-10-28 09:27:05Z vboxsync $ */
2/** @file
3 * DevSerial - 16550A UART emulation.
4 * (taken from hw/serial.c 2010/05/15 with modifications)
5 */
6
7/*
8 * Copyright (C) 2006-2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*
20 * This code is based on:
21 *
22 * QEMU 16550A UART emulation
23 *
24 * Copyright (c) 2003-2004 Fabrice Bellard
25 * Copyright (c) 2008 Citrix Systems, Inc.
26 *
27 * Permission is hereby granted, free of charge, to any person obtaining a copy
28 * of this software and associated documentation files (the "Software"), to deal
29 * in the Software without restriction, including without limitation the rights
30 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31 * copies of the Software, and to permit persons to whom the Software is
32 * furnished to do so, subject to the following conditions:
33 *
34 * The above copyright notice and this permission notice shall be included in
35 * all copies or substantial portions of the Software.
36 *
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
40 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43 * THE SOFTWARE.
44 */
45
46/*******************************************************************************
47* Header Files *
48*******************************************************************************/
49#define LOG_GROUP LOG_GROUP_DEV_SERIAL
50#include <VBox/pdmdev.h>
51#include <iprt/assert.h>
52#include <iprt/uuid.h>
53#include <iprt/string.h>
54#include <iprt/semaphore.h>
55#include <iprt/critsect.h>
56
57#include "../Builtins.h"
58
59#undef VBOX_SERIAL_PCI /* The PCI variant has lots of problems: wrong IRQ line and wrong IO base assigned. */
60
61#ifdef VBOX_SERIAL_PCI
62# include <VBox/pci.h>
63#endif /* VBOX_SERIAL_PCI */
64
65
66/*******************************************************************************
67* Defined Constants And Macros *
68*******************************************************************************/
69#define SERIAL_SAVED_STATE_VERSION_16450 3
70#define SERIAL_SAVED_STATE_VERSION 4
71
72#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
73
74#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
75#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
76#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
77#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
78
79#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
80#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
81
82#define UART_IIR_MSI 0x00 /* Modem status interrupt */
83#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
84#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
85#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
86#define UART_IIR_CTI 0x0C /* Character Timeout Indication */
87
88#define UART_IIR_FENF 0x80 /* Fifo enabled, but not functioning */
89#define UART_IIR_FE 0xC0 /* Fifo enabled */
90
91/*
92 * These are the definitions for the Modem Control Register
93 */
94#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
95#define UART_MCR_OUT2 0x08 /* Out2 complement */
96#define UART_MCR_OUT1 0x04 /* Out1 complement */
97#define UART_MCR_RTS 0x02 /* RTS complement */
98#define UART_MCR_DTR 0x01 /* DTR complement */
99
100/*
101 * These are the definitions for the Modem Status Register
102 */
103#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
104#define UART_MSR_RI 0x40 /* Ring Indicator */
105#define UART_MSR_DSR 0x20 /* Data Set Ready */
106#define UART_MSR_CTS 0x10 /* Clear to Send */
107#define UART_MSR_DDCD 0x08 /* Delta DCD */
108#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
109#define UART_MSR_DDSR 0x02 /* Delta DSR */
110#define UART_MSR_DCTS 0x01 /* Delta CTS */
111#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
112
113#define UART_LSR_TEMT 0x40 /* Transmitter empty */
114#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
115#define UART_LSR_BI 0x10 /* Break interrupt indicator */
116#define UART_LSR_FE 0x08 /* Frame error indicator */
117#define UART_LSR_PE 0x04 /* Parity error indicator */
118#define UART_LSR_OE 0x02 /* Overrun error indicator */
119#define UART_LSR_DR 0x01 /* Receiver data ready */
120#define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */
121
122/*
123 * Interrupt trigger levels.
124 * The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher.
125 */
126#define UART_FCR_ITL_1 0x00 /* 1 byte ITL */
127#define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */
128#define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */
129#define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */
130
131#define UART_FCR_DMS 0x08 /* DMA Mode Select */
132#define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */
133#define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */
134#define UART_FCR_FE 0x01 /* FIFO Enable */
135
136#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */
137
138#define XMIT_FIFO 0
139#define RECV_FIFO 1
140#define MAX_XMIT_RETRY 8
141
142/*******************************************************************************
143* Structures and Typedefs *
144*******************************************************************************/
145
146struct SerialFifo
147{
148 uint8_t data[UART_FIFO_LENGTH];
149 uint8_t count;
150 uint8_t itl;
151 uint8_t tail;
152 uint8_t head;
153};
154
155/**
156 * Serial device.
157 *
158 * @implements PDMIBASE
159 * @implements PDMICHARPORT
160 */
161struct SerialState
162{
163 /** Access critical section. */
164 PDMCRITSECT CritSect;
165 /** Pointer to the device instance - R3 Ptr. */
166 PPDMDEVINSR3 pDevInsR3;
167 /** Pointer to the device instance - R0 Ptr. */
168 PPDMDEVINSR0 pDevInsR0;
169 /** Pointer to the device instance - RC Ptr. */
170 PPDMDEVINSRC pDevInsRC;
171 /** Alignment. */
172 RTRCPTR Alignment0;
173 /** LUN\#0: The base interface. */
174 PDMIBASE IBase;
175 /** LUN\#0: The character port interface. */
176 PDMICHARPORT ICharPort;
177 /** Pointer to the attached base driver. */
178 R3PTRTYPE(PPDMIBASE) pDrvBase;
179 /** Pointer to the attached character driver. */
180 R3PTRTYPE(PPDMICHARCONNECTOR) pDrvChar;
181
182 RTSEMEVENT ReceiveSem;
183 PTMTIMERR3 fifo_timeout_timer;
184 PTMTIMERR3 transmit_timerR3;
185 PTMTIMERR0 transmit_timerR0; /* currently not used */
186 PTMTIMERRC transmit_timerRC; /* currently not used */
187 RTRCPTR Alignment1;
188 SerialFifo recv_fifo;
189 SerialFifo xmit_fifo;
190
191 uint32_t base;
192 uint16_t divider;
193 uint16_t Alignment2[1];
194 uint8_t rbr; /**< receive register */
195 uint8_t thr; /**< transmit holding register */
196 uint8_t tsr; /**< transmit shift register */
197 uint8_t ier; /**< interrupt enable register */
198 uint8_t iir; /**< interrupt identification register, R/O */
199 uint8_t lcr; /**< line control register */
200 uint8_t mcr; /**< modem control register */
201 uint8_t lsr; /**< line status register, R/O */
202 uint8_t msr; /**< modem status register, R/O */
203 uint8_t scr; /**< scratch register */
204 uint8_t fcr; /**< fifo control register */
205 uint8_t fcr_vmstate;
206 /* NOTE: this hidden state is necessary for tx irq generation as
207 it can be reset while reading iir */
208 int thr_ipending;
209 int timeout_ipending;
210 int irq;
211 int last_break_enable;
212 /** Counter for retrying xmit */
213 int tsr_retry;
214 bool msr_changed;
215 bool fGCEnabled;
216 bool fR0Enabled;
217 bool fYieldOnLSRRead;
218 bool volatile fRecvWaiting;
219 bool f16550AEnabled;
220 bool Alignment3[2];
221 /** Time it takes to transmit a character */
222 uint64_t char_transmit_time;
223
224#ifdef VBOX_SERIAL_PCI
225 PCIDEVICE dev;
226#endif /* VBOX_SERIAL_PCI */
227};
228
229#ifndef VBOX_DEVICE_STRUCT_TESTCASE
230
231
232#ifdef VBOX_SERIAL_PCI
233#define PCIDEV_2_SERIALSTATE(pPciDev) ( (SerialState *)((uintptr_t)(pPciDev) - RT_OFFSETOF(SerialState, dev)) )
234#endif /* VBOX_SERIAL_PCI */
235#define PDMIBASE_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, IBase)) )
236#define PDMICHARPORT_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, ICharPort)) )
237
238
239/*******************************************************************************
240* Internal Functions *
241*******************************************************************************/
242RT_C_DECLS_BEGIN
243PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
244PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
245RT_C_DECLS_END
246
247#ifdef IN_RING3
248
249static int serial_can_receive(SerialState *s);
250static void serial_receive(void *opaque, const uint8_t *buf, int size);
251
252static void fifo_clear(SerialState *s, int fifo)
253{
254 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
255 memset(f->data, 0, UART_FIFO_LENGTH);
256 f->count = 0;
257 f->head = 0;
258 f->tail = 0;
259}
260
261static int fifo_put(SerialState *s, int fifo, uint8_t chr)
262{
263 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
264
265 /* Receive overruns do not overwrite FIFO contents. */
266 if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH)
267 {
268 f->data[f->head++] = chr;
269 if (f->head == UART_FIFO_LENGTH)
270 f->head = 0;
271 }
272
273 if (f->count < UART_FIFO_LENGTH)
274 f->count++;
275 else if (fifo == RECV_FIFO)
276 s->lsr |= UART_LSR_OE;
277
278 return 1;
279}
280
281static uint8_t fifo_get(SerialState *s, int fifo)
282{
283 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
284 uint8_t c;
285
286 if (f->count == 0)
287 return 0;
288
289 c = f->data[f->tail++];
290 if (f->tail == UART_FIFO_LENGTH)
291 f->tail = 0;
292 f->count--;
293
294 return c;
295}
296
297static void serial_update_irq(SerialState *s)
298{
299 uint8_t tmp_iir = UART_IIR_NO_INT;
300
301 if ( (s->ier & UART_IER_RLSI)
302 && (s->lsr & UART_LSR_INT_ANY)) {
303 tmp_iir = UART_IIR_RLSI;
304 } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) {
305 /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
306 * this is not in the specification but is observed on existing
307 * hardware. */
308 tmp_iir = UART_IIR_CTI;
309 } else if ( (s->ier & UART_IER_RDI)
310 && (s->lsr & UART_LSR_DR)
311 && ( !(s->fcr & UART_FCR_FE)
312 || s->recv_fifo.count >= s->recv_fifo.itl)) {
313 tmp_iir = UART_IIR_RDI;
314 } else if ( (s->ier & UART_IER_THRI)
315 && s->thr_ipending) {
316 tmp_iir = UART_IIR_THRI;
317 } else if ( (s->ier & UART_IER_MSI)
318 && (s->msr & UART_MSR_ANY_DELTA)) {
319 tmp_iir = UART_IIR_MSI;
320 }
321 s->iir = tmp_iir | (s->iir & 0xF0);
322
323 /** XXX only call the SetIrq function if the state really changes! */
324 if (tmp_iir != UART_IIR_NO_INT) {
325 Log(("serial_update_irq %d 1\n", s->irq));
326# ifdef VBOX_SERIAL_PCI
327 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 1);
328# else /* !VBOX_SERIAL_PCI */
329 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 1);
330# endif /* !VBOX_SERIAL_PCI */
331 } else {
332 Log(("serial_update_irq %d 0\n", s->irq));
333# ifdef VBOX_SERIAL_PCI
334 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0);
335# else /* !VBOX_SERIAL_PCI */
336 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
337# endif /* !VBOX_SERIAL_PCI */
338 }
339}
340
341static void serial_update_parameters(SerialState *s)
342{
343 int speed, parity, data_bits, stop_bits, frame_size;
344
345 if (s->divider == 0)
346 return;
347
348 frame_size = 1;
349 if (s->lcr & 0x08) {
350 frame_size++;
351 if (s->lcr & 0x10)
352 parity = 'E';
353 else
354 parity = 'O';
355 } else {
356 parity = 'N';
357 }
358 if (s->lcr & 0x04)
359 stop_bits = 2;
360 else
361 stop_bits = 1;
362
363 data_bits = (s->lcr & 0x03) + 5;
364 frame_size += data_bits + stop_bits;
365 speed = 115200 / s->divider;
366 s->char_transmit_time = (TMTimerGetFreq(CTX_SUFF(s->transmit_timer)) / speed) * frame_size;
367 Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
368
369 if (RT_LIKELY(s->pDrvChar))
370 s->pDrvChar->pfnSetParameters(s->pDrvChar, speed, parity, data_bits, stop_bits);
371}
372
373static void serial_xmit(void *opaque)
374{
375 SerialState *s = (SerialState*)opaque;
376 uint64_t new_xmit_ts = TMTimerGet(CTX_SUFF(s->transmit_timer));
377
378 if (s->tsr_retry <= 0) {
379 if (s->fcr & UART_FCR_FE) {
380 s->tsr = fifo_get(s, XMIT_FIFO);
381 if (!s->xmit_fifo.count)
382 s->lsr |= UART_LSR_THRE;
383 } else {
384 s->tsr = s->thr;
385 s->lsr |= UART_LSR_THRE;
386 }
387 }
388
389 if (s->mcr & UART_MCR_LOOP) {
390 /* in loopback mode, say that we just received a char */
391 serial_receive(s, &s->tsr, 1);
392 } else if ( RT_LIKELY(s->pDrvChar)
393 && RT_FAILURE(s->pDrvChar->pfnWrite(s->pDrvChar, &s->tsr, 1))) {
394 if ((s->tsr_retry >= 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
395 s->tsr_retry++;
396 TMTimerSet(CTX_SUFF(s->transmit_timer), new_xmit_ts + s->char_transmit_time);
397 return;
398 } else {
399 /* drop this character. */
400 s->tsr_retry = 0;
401 }
402 }
403 else {
404 s->tsr_retry = 0;
405 }
406
407 if (!(s->lsr & UART_LSR_THRE))
408 TMTimerSet(CTX_SUFF(s->transmit_timer),
409 TMTimerGet(CTX_SUFF(s->transmit_timer)) + s->char_transmit_time);
410
411 if (s->lsr & UART_LSR_THRE) {
412 s->lsr |= UART_LSR_TEMT;
413 s->thr_ipending = 1;
414 serial_update_irq(s);
415 }
416}
417
418#endif /* IN_RING3 */
419
420static int serial_ioport_write(SerialState *s, uint32_t addr, uint32_t val)
421{
422 addr &= 7;
423
424#ifndef IN_RING3
425 NOREF(s);
426 return VINF_IOM_HC_IOPORT_WRITE;
427#else
428 switch(addr) {
429 default:
430 case 0:
431 if (s->lcr & UART_LCR_DLAB) {
432 s->divider = (s->divider & 0xff00) | val;
433 serial_update_parameters(s);
434 } else {
435 s->thr = (uint8_t) val;
436 if (s->fcr & UART_FCR_FE) {
437 fifo_put(s, XMIT_FIFO, s->thr);
438 s->thr_ipending = 0;
439 s->lsr &= ~UART_LSR_TEMT;
440 s->lsr &= ~UART_LSR_THRE;
441 serial_update_irq(s);
442 } else {
443 s->thr_ipending = 0;
444 s->lsr &= ~UART_LSR_THRE;
445 serial_update_irq(s);
446 }
447 serial_xmit(s);
448 }
449 break;
450 case 1:
451 if (s->lcr & UART_LCR_DLAB) {
452 s->divider = (s->divider & 0x00ff) | (val << 8);
453 serial_update_parameters(s);
454 } else {
455 s->ier = val & 0x0f;
456 if (s->lsr & UART_LSR_THRE) {
457 s->thr_ipending = 1;
458 serial_update_irq(s);
459 }
460 }
461 break;
462 case 2:
463 if (!s->f16550AEnabled)
464 break;
465
466 val = val & 0xFF;
467
468 if (s->fcr == val)
469 break;
470
471 /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
472 if ((val ^ s->fcr) & UART_FCR_FE)
473 val |= UART_FCR_XFR | UART_FCR_RFR;
474
475 /* FIFO clear */
476 if (val & UART_FCR_RFR) {
477 TMTimerStop(s->fifo_timeout_timer);
478 s->timeout_ipending = 0;
479 fifo_clear(s, RECV_FIFO);
480 }
481 if (val & UART_FCR_XFR) {
482 fifo_clear(s, XMIT_FIFO);
483 }
484
485 if (val & UART_FCR_FE) {
486 s->iir |= UART_IIR_FE;
487 /* Set RECV_FIFO trigger Level */
488 switch (val & 0xC0) {
489 case UART_FCR_ITL_1:
490 s->recv_fifo.itl = 1;
491 break;
492 case UART_FCR_ITL_2:
493 s->recv_fifo.itl = 4;
494 break;
495 case UART_FCR_ITL_3:
496 s->recv_fifo.itl = 8;
497 break;
498 case UART_FCR_ITL_4:
499 s->recv_fifo.itl = 14;
500 break;
501 }
502 } else
503 s->iir &= ~UART_IIR_FE;
504
505 /* Set fcr - or at least the bits in it that are supposed to "stick" */
506 s->fcr = val & 0xC9;
507 serial_update_irq(s);
508 break;
509 case 3:
510 {
511 int break_enable;
512 s->lcr = val;
513 serial_update_parameters(s);
514 break_enable = (val >> 6) & 1;
515 if (break_enable != s->last_break_enable) {
516 s->last_break_enable = break_enable;
517 if (RT_LIKELY(s->pDrvChar))
518 {
519 Log(("serial_ioport_write: Set break %d\n", break_enable));
520 int rc = s->pDrvChar->pfnSetBreak(s->pDrvChar, !!break_enable);
521 AssertRC(rc);
522 }
523 }
524 }
525 break;
526 case 4:
527 s->mcr = val & 0x1f;
528 if (RT_LIKELY(s->pDrvChar))
529 {
530 int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar,
531 !!(s->mcr & UART_MCR_RTS),
532 !!(s->mcr & UART_MCR_DTR));
533 AssertRC(rc);
534 }
535 break;
536 case 5:
537 break;
538 case 6:
539 break;
540 case 7:
541 s->scr = val;
542 break;
543 }
544 return VINF_SUCCESS;
545#endif
546}
547
548static uint32_t serial_ioport_read(void *opaque, uint32_t addr, int *pRC)
549{
550 SerialState *s = (SerialState *)opaque;
551 uint32_t ret = ~0U;
552
553 *pRC = VINF_SUCCESS;
554
555 addr &= 7;
556 switch(addr) {
557 default:
558 case 0:
559 if (s->lcr & UART_LCR_DLAB) {
560 /* DLAB == 1: divisor latch (LS) */
561 ret = s->divider & 0xff;
562 } else {
563#ifndef IN_RING3
564 *pRC = VINF_IOM_HC_IOPORT_READ;
565#else
566 if (s->fcr & UART_FCR_FE) {
567 ret = fifo_get(s, RECV_FIFO);
568 if (s->recv_fifo.count == 0)
569 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
570 else
571 TMTimerSet(s->fifo_timeout_timer,
572 TMTimerGet(s->fifo_timeout_timer) + s->char_transmit_time * 4);
573 s->timeout_ipending = 0;
574 } else {
575 Log(("serial_io_port_read: read 0x%X\n", s->rbr));
576 ret = s->rbr;
577 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
578 }
579 serial_update_irq(s);
580 if (s->fRecvWaiting)
581 {
582 s->fRecvWaiting = false;
583 int rc = RTSemEventSignal(s->ReceiveSem);
584 AssertRC(rc);
585 }
586#endif
587 }
588 break;
589 case 1:
590 if (s->lcr & UART_LCR_DLAB) {
591 /* DLAB == 1: divisor latch (MS) */
592 ret = (s->divider >> 8) & 0xff;
593 } else {
594 ret = s->ier;
595 }
596 break;
597 case 2:
598#ifndef IN_RING3
599 *pRC = VINF_IOM_HC_IOPORT_READ;
600#else
601 ret = s->iir;
602 if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
603 s->thr_ipending = 0;
604 serial_update_irq(s);
605 }
606 /* reset msr changed bit */
607 s->msr_changed = false;
608#endif
609 break;
610 case 3:
611 ret = s->lcr;
612 break;
613 case 4:
614 ret = s->mcr;
615 break;
616 case 5:
617 if ((s->lsr & UART_LSR_DR) == 0 && s->fYieldOnLSRRead)
618 {
619 /* No data available and yielding is enabled, so yield in ring3. */
620#ifndef IN_RING3
621 *pRC = VINF_IOM_HC_IOPORT_READ;
622 break;
623#else
624 RTThreadYield ();
625#endif
626 }
627 ret = s->lsr;
628 /* Clear break and overrun interrupts */
629 if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
630#ifndef IN_RING3
631 *pRC = VINF_IOM_HC_IOPORT_READ;
632#else
633 s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
634 serial_update_irq(s);
635#endif
636 }
637 break;
638 case 6:
639 if (s->mcr & UART_MCR_LOOP) {
640 /* in loopback, the modem output pins are connected to the
641 inputs */
642 ret = (s->mcr & 0x0c) << 4;
643 ret |= (s->mcr & 0x02) << 3;
644 ret |= (s->mcr & 0x01) << 5;
645 } else {
646 ret = s->msr;
647 /* Clear delta bits & msr int after read, if they were set */
648 if (s->msr & UART_MSR_ANY_DELTA) {
649#ifndef IN_RING3
650 *pRC = VINF_IOM_HC_IOPORT_READ;
651#else
652 s->msr &= 0xF0;
653 serial_update_irq(s);
654#endif
655 }
656 }
657 break;
658 case 7:
659 ret = s->scr;
660 break;
661 }
662 return ret;
663}
664
665#ifdef IN_RING3
666
667static int serial_can_receive(SerialState *s)
668{
669 if (s->fcr & UART_FCR_FE) {
670 if (s->recv_fifo.count < UART_FIFO_LENGTH)
671 return (s->recv_fifo.count <= s->recv_fifo.itl)
672 ? s->recv_fifo.itl - s->recv_fifo.count : 1;
673 else
674 return 0;
675 } else {
676 return !(s->lsr & UART_LSR_DR);
677 }
678}
679
680static void serial_receive(void *opaque, const uint8_t *buf, int size)
681{
682 SerialState *s = (SerialState*)opaque;
683 if (s->fcr & UART_FCR_FE) {
684 int i;
685 for (i = 0; i < size; i++) {
686 fifo_put(s, RECV_FIFO, buf[i]);
687 }
688 s->lsr |= UART_LSR_DR;
689 /* call the timeout receive callback in 4 char transmit time */
690 TMTimerSet(s->fifo_timeout_timer, TMTimerGet(s->fifo_timeout_timer) + s->char_transmit_time * 4);
691 } else {
692 if (s->lsr & UART_LSR_DR)
693 s->lsr |= UART_LSR_OE;
694 s->rbr = buf[0];
695 s->lsr |= UART_LSR_DR;
696 }
697 serial_update_irq(s);
698}
699
700/** @copydoc PDMICHARPORT::pfnNotifyRead */
701static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
702{
703 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
704 const uint8_t *pu8Buf = (const uint8_t*)pvBuf;
705 size_t cbRead = *pcbRead;
706
707 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
708 for (; cbRead > 0; cbRead--, pu8Buf++)
709 {
710 if (!serial_can_receive(pThis))
711 {
712 /* If we cannot receive then wait for not more than 250ms. If we still
713 * cannot receive then the new character will either overwrite rbr
714 * or it will be dropped at fifo_put(). */
715 pThis->fRecvWaiting = true;
716 PDMCritSectLeave(&pThis->CritSect);
717 int rc = RTSemEventWait(pThis->ReceiveSem, 250);
718 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
719 }
720 serial_receive(pThis, &pu8Buf[0], 1);
721 }
722 PDMCritSectLeave(&pThis->CritSect);
723 return VINF_SUCCESS;
724}
725
726/** @copydoc PDMICHARPORT::pfnNotifyStatusLinesChanged */
727static DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines)
728{
729 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
730 uint8_t newMsr = 0;
731
732 Log(("%s: pInterface=%p newStatusLines=%u\n", __FUNCTION__, pInterface, newStatusLines));
733
734 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
735
736 /* Set new states. */
737 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DCD)
738 newMsr |= UART_MSR_DCD;
739 if (newStatusLines & PDMICHARPORT_STATUS_LINES_RI)
740 newMsr |= UART_MSR_RI;
741 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DSR)
742 newMsr |= UART_MSR_DSR;
743 if (newStatusLines & PDMICHARPORT_STATUS_LINES_CTS)
744 newMsr |= UART_MSR_CTS;
745
746 /* Compare the old and the new states and set the delta bits accordingly. */
747 if ((newMsr & UART_MSR_DCD) != (pThis->msr & UART_MSR_DCD))
748 newMsr |= UART_MSR_DDCD;
749 if ((newMsr & UART_MSR_RI) == 1 && (pThis->msr & UART_MSR_RI) == 0)
750 newMsr |= UART_MSR_TERI;
751 if ((newMsr & UART_MSR_DSR) != (pThis->msr & UART_MSR_DSR))
752 newMsr |= UART_MSR_DDSR;
753 if ((newMsr & UART_MSR_CTS) != (pThis->msr & UART_MSR_CTS))
754 newMsr |= UART_MSR_DCTS;
755
756 pThis->msr = newMsr;
757 pThis->msr_changed = true;
758 serial_update_irq(pThis);
759
760 PDMCritSectLeave(&pThis->CritSect);
761
762 return VINF_SUCCESS;
763}
764
765/** @copydoc PDMICHARPORT::pfnNotifyBufferFull */
766static DECLCALLBACK(int) serialNotifyBufferFull(PPDMICHARPORT pInterface, bool fFull)
767{
768 return VINF_SUCCESS;
769}
770
771/** @copydoc PDMICHARPORT::pfnNotifyBreak */
772static DECLCALLBACK(int) serialNotifyBreak(PPDMICHARPORT pInterface)
773{
774 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
775
776 Log(("%s: pInterface=%p\n", __FUNCTION__, pInterface));
777
778 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
779
780 pThis->lsr |= UART_LSR_BI;
781 serial_update_irq(pThis);
782
783 PDMCritSectLeave(&pThis->CritSect);
784
785 return VINF_SUCCESS;
786}
787
788/**
789 * Fifo timer functions.
790 */
791static DECLCALLBACK(void) serialFifoTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
792{
793 SerialState *s = (SerialState*)pvUser;
794 if (s->recv_fifo.count)
795 {
796 s->timeout_ipending = 1;
797 serial_update_irq(s);
798 }
799}
800
801/**
802 * Transmit timer function.
803 * Just retry to transmit a character.
804 *
805 * @param pTimer The timer handle.
806 * @param pDevIns The device instance.
807 * @param pvUser The user pointer.
808 */
809static DECLCALLBACK(void) serialTransmitTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
810{
811 SerialState *s = (SerialState*)pvUser;
812 serial_xmit(s);
813}
814
815/**
816 * Reset the serial device.
817 *
818 * @param pDevIns The device instance.
819 */
820static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
821{
822 SerialState *s = PDMINS_2_DATA(pDevIns, SerialState *);
823
824 s->rbr = 0;
825 s->ier = 0;
826 s->iir = UART_IIR_NO_INT;
827 s->lcr = 0;
828 s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
829 s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
830 /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
831 s->divider = 0x0C;
832 s->mcr = UART_MCR_OUT2;
833 s->scr = 0;
834 s->tsr_retry = 0;
835 s->char_transmit_time = (TMTimerGetFreq(CTX_SUFF(s->transmit_timer)) / 9600) * 10;
836
837 fifo_clear(s, RECV_FIFO);
838 fifo_clear(s, XMIT_FIFO);
839
840 s->thr_ipending = 0;
841 s->last_break_enable = 0;
842# ifdef VBOX_SERIAL_PCI
843 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0);
844# else /* !VBOX_SERIAL_PCI */
845 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
846# endif /* !VBOX_SERIAL_PCI */
847}
848
849#endif /* IN_RING3 */
850
851/**
852 * Port I/O Handler for OUT operations.
853 *
854 * @returns VBox status code.
855 *
856 * @param pDevIns The device instance.
857 * @param pvUser User argument.
858 * @param Port Port number used for the IN operation.
859 * @param u32 The value to output.
860 * @param cb The value size in bytes.
861 */
862PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
863 RTIOPORT Port, uint32_t u32, unsigned cb)
864{
865 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
866 int rc = VINF_SUCCESS;
867
868 if (cb == 1)
869 {
870 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
871 if (rc == VINF_SUCCESS)
872 {
873 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
874 rc = serial_ioport_write(pThis, Port, u32);
875 PDMCritSectLeave(&pThis->CritSect);
876 }
877 }
878 else
879 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
880
881 return rc;
882}
883
884/**
885 * Port I/O Handler for IN operations.
886 *
887 * @returns VBox status code.
888 *
889 * @param pDevIns The device instance.
890 * @param pvUser User argument.
891 * @param Port Port number used for the IN operation.
892 * @param u32 The value to output.
893 * @param cb The value size in bytes.
894 */
895PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
896 RTIOPORT Port, uint32_t *pu32, unsigned cb)
897{
898 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
899 int rc = VINF_SUCCESS;
900
901 if (cb == 1)
902 {
903 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
904 if (rc == VINF_SUCCESS)
905 {
906 *pu32 = serial_ioport_read(pThis, Port, &rc);
907 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
908 PDMCritSectLeave(&pThis->CritSect);
909 }
910 }
911 else
912 rc = VERR_IOM_IOPORT_UNUSED;
913
914 return rc;
915}
916
917#ifdef IN_RING3
918
919/**
920 * @copydoc FNSSMDEVLIVEEXEC
921 */
922static DECLCALLBACK(int) serialLiveExec(PPDMDEVINS pDevIns,
923 PSSMHANDLE pSSM,
924 uint32_t uPass)
925{
926 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
927 SSMR3PutS32(pSSM, pThis->irq);
928 SSMR3PutU32(pSSM, pThis->base);
929 return VINF_SSM_DONT_CALL_AGAIN;
930}
931
932/**
933 * @copydoc FNSSMDEVSAVEEXEC
934 */
935static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
936 PSSMHANDLE pSSM)
937{
938 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
939
940 SSMR3PutU16(pSSM, pThis->divider);
941 SSMR3PutU8(pSSM, pThis->rbr);
942 SSMR3PutU8(pSSM, pThis->ier);
943 SSMR3PutU8(pSSM, pThis->lcr);
944 SSMR3PutU8(pSSM, pThis->mcr);
945 SSMR3PutU8(pSSM, pThis->lsr);
946 SSMR3PutU8(pSSM, pThis->msr);
947 SSMR3PutU8(pSSM, pThis->scr);
948 SSMR3PutU8(pSSM, pThis->fcr); /* 16550A */
949 SSMR3PutS32(pSSM, pThis->thr_ipending);
950 SSMR3PutS32(pSSM, pThis->irq);
951 SSMR3PutS32(pSSM, pThis->last_break_enable);
952 SSMR3PutU32(pSSM, pThis->base);
953 SSMR3PutBool(pSSM, pThis->msr_changed);
954
955 /* Don't store:
956 * - the content of the FIFO
957 * - tsr_retry
958 */
959
960 return SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
961}
962
963/**
964 * @copydoc FNSSMDEVLOADEXEC
965 */
966static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
967 PSSMHANDLE pSSM,
968 uint32_t uVersion,
969 uint32_t uPass)
970{
971 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
972
973 if (uVersion == SERIAL_SAVED_STATE_VERSION_16450)
974 {
975 pThis->f16550AEnabled = false;
976 LogRel(("Serial#%d: falling back to 16450 mode from load state\n", pDevIns->iInstance));
977 }
978 else
979 AssertMsgReturn(uVersion == SERIAL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
980
981 if (uPass == SSM_PASS_FINAL)
982 {
983 SSMR3GetU16(pSSM, &pThis->divider);
984 SSMR3GetU8(pSSM, &pThis->rbr);
985 SSMR3GetU8(pSSM, &pThis->ier);
986 SSMR3GetU8(pSSM, &pThis->lcr);
987 SSMR3GetU8(pSSM, &pThis->mcr);
988 SSMR3GetU8(pSSM, &pThis->lsr);
989 SSMR3GetU8(pSSM, &pThis->msr);
990 SSMR3GetU8(pSSM, &pThis->scr);
991 if (uVersion > SERIAL_SAVED_STATE_VERSION_16450)
992 {
993 SSMR3GetU8(pSSM, &pThis->fcr);
994 }
995 SSMR3GetS32(pSSM, &pThis->thr_ipending);
996 }
997
998 int32_t iIrq;
999 SSMR3GetS32(pSSM, &iIrq);
1000
1001 if (uPass == SSM_PASS_FINAL)
1002 SSMR3GetS32(pSSM, &pThis->last_break_enable);
1003
1004 uint32_t IOBase;
1005 int rc = SSMR3GetU32(pSSM, &IOBase);
1006 AssertRCReturn(rc, rc);
1007
1008 if ( pThis->irq != iIrq
1009 || pThis->base != IOBase)
1010 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1011 N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
1012 iIrq, IOBase, pThis->irq, pThis->base);
1013
1014 if (uPass == SSM_PASS_FINAL)
1015 {
1016 SSMR3GetBool(pSSM, &pThis->msr_changed);
1017
1018 uint32_t u32;
1019 rc = SSMR3GetU32(pSSM, &u32);
1020 if (RT_FAILURE(rc))
1021 return rc;
1022 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1023
1024 if ( (pThis->lsr & UART_LSR_DR)
1025 || pThis->fRecvWaiting)
1026 {
1027 pThis->fRecvWaiting = false;
1028 rc = RTSemEventSignal(pThis->ReceiveSem);
1029 AssertRC(rc);
1030 }
1031
1032 /* this isn't strictly necessary but cannot hurt... */
1033 pThis->pDevInsR3 = pDevIns;
1034 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1035 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1036 }
1037
1038 return VINF_SUCCESS;
1039}
1040
1041
1042/**
1043 * @copydoc FNPDMDEVRELOCATE
1044 */
1045static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1046{
1047 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
1048 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1049 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
1050}
1051
1052#ifdef VBOX_SERIAL_PCI
1053
1054static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1055{
1056 SerialState *pThis = PCIDEV_2_SERIALSTATE(pPciDev);
1057 int rc = VINF_SUCCESS;
1058
1059 Assert(enmType == PCI_ADDRESS_SPACE_IO);
1060 Assert(iRegion == 0);
1061 Assert(cb == 8);
1062 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
1063
1064 pThis->base = (RTIOPORT)GCPhysAddress;
1065 LogRel(("Serial#%d: mapping I/O at %#06x\n", pThis->pDevIns->iInstance, pThis->base));
1066
1067 /*
1068 * Register our port IO handlers.
1069 */
1070 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
1071 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
1072 AssertRC(rc);
1073 return rc;
1074}
1075
1076#endif /* VBOX_SERIAL_PCI */
1077
1078/**
1079 * @interface_method_impl{PDMIBASE, pfnQueryInterface}
1080 */
1081static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1082{
1083 SerialState *pThis = PDMIBASE_2_SERIALSTATE(pInterface);
1084 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
1085 PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARPORT, &pThis->ICharPort);
1086 return NULL;
1087}
1088
1089/**
1090 * Destruct a device instance.
1091 *
1092 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1093 * resources can be freed correctly.
1094 *
1095 * @returns VBox status.
1096 * @param pDevIns The device instance data.
1097 */
1098static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
1099{
1100 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
1101 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1102
1103 RTSemEventDestroy(pThis->ReceiveSem);
1104 pThis->ReceiveSem = NIL_RTSEMEVENT;
1105
1106 PDMR3CritSectDelete(&pThis->CritSect);
1107 return VINF_SUCCESS;
1108}
1109
1110
1111/**
1112 * @interface_method_impl{PDMDEVREG, pfnConstruct}
1113 */
1114static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1115{
1116 int rc;
1117 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState*);
1118 uint16_t io_base;
1119 uint8_t irq_lvl;
1120
1121 Assert(iInstance < 4);
1122 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1123
1124 /*
1125 * Initialize the instance data.
1126 * (Do this early or the destructor might choke on something!)
1127 */
1128 pThis->pDevInsR3 = pDevIns;
1129 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1130 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1131
1132 /* IBase */
1133 pThis->IBase.pfnQueryInterface = serialQueryInterface;
1134
1135 /* ICharPort */
1136 pThis->ICharPort.pfnNotifyRead = serialNotifyRead;
1137 pThis->ICharPort.pfnNotifyStatusLinesChanged = serialNotifyStatusLinesChanged;
1138 pThis->ICharPort.pfnNotifyBufferFull = serialNotifyBufferFull;
1139 pThis->ICharPort.pfnNotifyBreak = serialNotifyBreak;
1140
1141#ifdef VBOX_SERIAL_PCI
1142 /* the PCI device */
1143 pThis->dev.config[0x00] = 0xee; /* Vendor: ??? */
1144 pThis->dev.config[0x01] = 0x80;
1145 pThis->dev.config[0x02] = 0x01; /* Device: ??? */
1146 pThis->dev.config[0x03] = 0x01;
1147 pThis->dev.config[0x04] = PCI_COMMAND_IOACCESS;
1148 pThis->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
1149 pThis->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
1150 pThis->dev.config[0x0b] = 0x07; /* Class: Communication controller */
1151 pThis->dev.config[0x0e] = 0x00; /* Header type: standard */
1152 pThis->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
1153 pThis->dev.config[0x3d] = 1; /* interrupt pin 0 */
1154#endif /* VBOX_SERIAL_PCI */
1155
1156 /*
1157 * Validate and read the configuration.
1158 */
1159 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
1160 "IOBase\0"
1161 "GCEnabled\0"
1162 "R0Enabled\0"
1163 "YieldOnLSRRead\0"
1164 "Enable16550A\0"
1165 ))
1166 {
1167 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
1168 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1169 }
1170
1171 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
1172 if (RT_FAILURE(rc))
1173 return PDMDEV_SET_ERROR(pDevIns, rc,
1174 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
1175
1176 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
1177 if (RT_FAILURE(rc))
1178 return PDMDEV_SET_ERROR(pDevIns, rc,
1179 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
1180
1181 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
1182 if (RT_FAILURE(rc))
1183 return PDMDEV_SET_ERROR(pDevIns, rc,
1184 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
1185
1186 rc = CFGMR3QueryU8(pCfg, "IRQ", &irq_lvl);
1187 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1188 {
1189 /* Provide sensible defaults. */
1190 if (iInstance == 0)
1191 irq_lvl = 4;
1192 else if (iInstance == 1)
1193 irq_lvl = 3;
1194 else
1195 AssertReleaseFailed(); /* irq_lvl is undefined. */
1196 }
1197 else if (RT_FAILURE(rc))
1198 return PDMDEV_SET_ERROR(pDevIns, rc,
1199 N_("Configuration error: Failed to get the \"IRQ\" value"));
1200
1201 rc = CFGMR3QueryU16(pCfg, "IOBase", &io_base);
1202 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1203 {
1204 if (iInstance == 0)
1205 io_base = 0x3f8;
1206 else if (iInstance == 1)
1207 io_base = 0x2f8;
1208 else
1209 AssertReleaseFailed(); /* io_base is undefined */
1210 }
1211 else if (RT_FAILURE(rc))
1212 return PDMDEV_SET_ERROR(pDevIns, rc,
1213 N_("Configuration error: Failed to get the \"IOBase\" value"));
1214
1215 Log(("DevSerial: instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
1216
1217 rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
1218 if (RT_FAILURE(rc))
1219 return PDMDEV_SET_ERROR(pDevIns, rc,
1220 N_("Configuration error: Failed to get the \"Enable16550A\" value"));
1221
1222 pThis->irq = irq_lvl;
1223#ifdef VBOX_SERIAL_PCI
1224 pThis->base = -1;
1225#else
1226 pThis->base = io_base;
1227#endif
1228
1229 LogRel(("Serial#%d: emulating %s\n", pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450"));
1230
1231 /*
1232 * Initialize critical section and the semaphore.
1233 * This must of course be done before attaching drivers or anything else which can call us back..
1234 */
1235 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
1236 if (RT_FAILURE(rc))
1237 return rc;
1238
1239 rc = RTSemEventCreate(&pThis->ReceiveSem);
1240 AssertRC(rc);
1241
1242 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialFifoTimer, pThis,
1243 TMTIMER_FLAGS_NO_CRIT_SECT, "Serial Fifo Timer",
1244 &pThis->fifo_timeout_timer);
1245 AssertRC(rc);
1246
1247 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialTransmitTimer, pThis,
1248 TMTIMER_FLAGS_NO_CRIT_SECT, "Serial Transmit Timer",
1249 &pThis->transmit_timerR3);
1250 AssertRC(rc);
1251 pThis->transmit_timerR0 = TMTimerR0Ptr(pThis->transmit_timerR3);
1252 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
1253
1254 serialReset(pDevIns);
1255
1256#ifdef VBOX_SERIAL_PCI
1257 /*
1258 * Register the PCI Device and region.
1259 */
1260 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
1261 if (RT_FAILURE(rc))
1262 return rc;
1263 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
1264 if (RT_FAILURE(rc))
1265 return rc;
1266
1267#else /* !VBOX_SERIAL_PCI */
1268 /*
1269 * Register the I/O ports.
1270 */
1271 pThis->base = io_base;
1272 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
1273 serialIOPortWrite, serialIOPortRead,
1274 NULL, NULL, "SERIAL");
1275 if (RT_FAILURE(rc))
1276 return rc;
1277
1278 if (pThis->fGCEnabled)
1279 {
1280 rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
1281 "serialIOPortRead", NULL, NULL, "Serial");
1282 if (RT_FAILURE(rc))
1283 return rc;
1284 }
1285
1286 if (pThis->fR0Enabled)
1287 {
1288 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
1289 "serialIOPortRead", NULL, NULL, "Serial");
1290 if (RT_FAILURE(rc))
1291 return rc;
1292 }
1293#endif /* !VBOX_SERIAL_PCI */
1294
1295 /*
1296 * Saved state.
1297 */
1298 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
1299 serialLiveExec, serialSaveExec, serialLoadExec);
1300 if (RT_FAILURE(rc))
1301 return rc;
1302
1303 /*
1304 * Attach the char driver and get the interfaces.
1305 * For now no run-time changes are supported.
1306 */
1307 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
1308 if (RT_SUCCESS(rc))
1309 {
1310 pThis->pDrvChar = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMICHARCONNECTOR);
1311 if (!pThis->pDrvChar)
1312 {
1313 AssertLogRelMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
1314 return VERR_PDM_MISSING_INTERFACE;
1315 }
1316 /** @todo provide read notification interface!!!! */
1317 }
1318 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1319 {
1320 pThis->pDrvBase = NULL;
1321 pThis->pDrvChar = NULL;
1322 LogRel(("Serial%d: no unit\n", iInstance));
1323 }
1324 else
1325 {
1326 AssertLogRelMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1327 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1328 return rc;
1329 }
1330
1331 return VINF_SUCCESS;
1332}
1333
1334
1335/**
1336 * The device registration structure.
1337 */
1338const PDMDEVREG g_DeviceSerialPort =
1339{
1340 /* u32Version */
1341 PDM_DEVREG_VERSION,
1342 /* szName */
1343 "serial",
1344 /* szRCMod */
1345 "VBoxDDGC.gc",
1346 /* szR0Mod */
1347 "VBoxDDR0.r0",
1348 /* pszDescription */
1349 "Serial Communication Port",
1350 /* fFlags */
1351 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1352 /* fClass */
1353 PDM_DEVREG_CLASS_SERIAL,
1354 /* cMaxInstances */
1355 UINT32_MAX,
1356 /* cbInstance */
1357 sizeof(SerialState),
1358 /* pfnConstruct */
1359 serialConstruct,
1360 /* pfnDestruct */
1361 serialDestruct,
1362 /* pfnRelocate */
1363 serialRelocate,
1364 /* pfnIOCtl */
1365 NULL,
1366 /* pfnPowerOn */
1367 NULL,
1368 /* pfnReset */
1369 serialReset,
1370 /* pfnSuspend */
1371 NULL,
1372 /* pfnResume */
1373 NULL,
1374 /* pfnAttach */
1375 NULL,
1376 /* pfnDetach */
1377 NULL,
1378 /* pfnQueryInterface. */
1379 NULL,
1380 /* pfnInitComplete */
1381 NULL,
1382 /* pfnPowerOff */
1383 NULL,
1384 /* pfnSoftReset */
1385 NULL,
1386 /* u32VersionEnd */
1387 PDM_DEVREG_VERSION
1388};
1389#endif /* IN_RING3 */
1390
1391#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