VirtualBox

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

Last change on this file since 35727 was 35725, checked in by vboxsync, 14 years ago

linux burn fix

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

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