VirtualBox

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

Last change on this file since 40754 was 40280, checked in by vboxsync, 12 years ago

Corrected a bunch of HC and GC uses in status codes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.8 KB
Line 
1/* $Id: DevSerial.cpp 40280 2012-02-28 19:47:00Z 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_R3_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_R3_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_R3_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_R3_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_R3_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_R3_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 *pThis = (SerialState *)pvUser;
830 Assert(PDMCritSectIsOwner(&pThis->CritSect));
831 if (pThis->recv_fifo.count)
832 {
833 pThis->timeout_ipending = 1;
834 serial_update_irq(pThis);
835 }
836}
837
838/**
839 * Transmit timer function.
840 * Just retry to transmit a character.
841 *
842 * @param pTimer The timer handle.
843 * @param pDevIns The device instance.
844 * @param pvUser The user pointer.
845 */
846static DECLCALLBACK(void) serialTransmitTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
847{
848 SerialState *pThis = (SerialState *)pvUser;
849 Assert(PDMCritSectIsOwner(&pThis->CritSect));
850 serial_xmit(pThis, true);
851}
852
853/**
854 * Reset the serial device.
855 *
856 * @param pDevIns The device instance.
857 */
858static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
859{
860 SerialState *s = PDMINS_2_DATA(pDevIns, SerialState *);
861
862 s->rbr = 0;
863 s->ier = 0;
864 s->iir = UART_IIR_NO_INT;
865 s->lcr = 0;
866 s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
867 s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
868 /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
869 s->divider = 0x0C;
870 s->mcr = UART_MCR_OUT2;
871 s->scr = 0;
872 s->tsr_retry = 0;
873 uint64_t tf = TMTimerGetFreq(CTX_SUFF(s->transmit_timer));
874 s->char_transmit_time = (tf / 9600) * 10;
875 serial_tsr_retry_update_parameters(s, tf);
876
877 fifo_clear(s, RECV_FIFO);
878 fifo_clear(s, XMIT_FIFO);
879
880 s->thr_ipending = 0;
881 s->last_break_enable = 0;
882# ifdef VBOX_SERIAL_PCI
883 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0);
884# else /* !VBOX_SERIAL_PCI */
885 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
886# endif /* !VBOX_SERIAL_PCI */
887}
888
889#endif /* IN_RING3 */
890
891/**
892 * Port I/O Handler for OUT operations.
893 *
894 * @returns VBox status code.
895 *
896 * @param pDevIns The device instance.
897 * @param pvUser User argument.
898 * @param Port Port number used for the IN operation.
899 * @param u32 The value to output.
900 * @param cb The value size in bytes.
901 */
902PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
903 RTIOPORT Port, uint32_t u32, unsigned cb)
904{
905 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
906 int rc;
907 Assert(PDMCritSectIsOwner(&pThis->CritSect));
908
909 if (cb == 1)
910 {
911 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
912 rc = serial_ioport_write(pThis, Port, u32);
913 }
914 else
915 {
916 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
917 rc = VINF_SUCCESS;
918 }
919
920 return rc;
921}
922
923/**
924 * Port I/O Handler for IN operations.
925 *
926 * @returns VBox status code.
927 *
928 * @param pDevIns The device instance.
929 * @param pvUser User argument.
930 * @param Port Port number used for the IN operation.
931 * @param u32 The value to output.
932 * @param cb The value size in bytes.
933 */
934PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
935 RTIOPORT Port, uint32_t *pu32, unsigned cb)
936{
937 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
938 int rc;
939 Assert(PDMCritSectIsOwner(&pThis->CritSect));
940
941 if (cb == 1)
942 {
943 *pu32 = serial_ioport_read(pThis, Port, &rc);
944 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
945 }
946 else
947 rc = VERR_IOM_IOPORT_UNUSED;
948
949 return rc;
950}
951
952#ifdef IN_RING3
953
954/**
955 * @copydoc FNSSMDEVLIVEEXEC
956 */
957static DECLCALLBACK(int) serialLiveExec(PPDMDEVINS pDevIns,
958 PSSMHANDLE pSSM,
959 uint32_t uPass)
960{
961 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
962 SSMR3PutS32(pSSM, pThis->irq);
963 SSMR3PutU32(pSSM, pThis->base);
964 return VINF_SSM_DONT_CALL_AGAIN;
965}
966
967/**
968 * @copydoc FNSSMDEVSAVEEXEC
969 */
970static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
971 PSSMHANDLE pSSM)
972{
973 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
974
975 SSMR3PutU16(pSSM, pThis->divider);
976 SSMR3PutU8(pSSM, pThis->rbr);
977 SSMR3PutU8(pSSM, pThis->ier);
978 SSMR3PutU8(pSSM, pThis->lcr);
979 SSMR3PutU8(pSSM, pThis->mcr);
980 SSMR3PutU8(pSSM, pThis->lsr);
981 SSMR3PutU8(pSSM, pThis->msr);
982 SSMR3PutU8(pSSM, pThis->scr);
983 SSMR3PutU8(pSSM, pThis->fcr); /* 16550A */
984 SSMR3PutS32(pSSM, pThis->thr_ipending);
985 SSMR3PutS32(pSSM, pThis->irq);
986 SSMR3PutS32(pSSM, pThis->last_break_enable);
987 SSMR3PutU32(pSSM, pThis->base);
988 SSMR3PutBool(pSSM, pThis->msr_changed);
989
990 /* Don't store:
991 * - the content of the FIFO
992 * - tsr_retry
993 */
994
995 return SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
996}
997
998/**
999 * @copydoc FNSSMDEVLOADEXEC
1000 */
1001static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
1002 PSSMHANDLE pSSM,
1003 uint32_t uVersion,
1004 uint32_t uPass)
1005{
1006 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
1007
1008 if (uVersion == SERIAL_SAVED_STATE_VERSION_16450)
1009 {
1010 pThis->f16550AEnabled = false;
1011 LogRel(("Serial#%d: falling back to 16450 mode from load state\n", pDevIns->iInstance));
1012 }
1013 else
1014 AssertMsgReturn(uVersion == SERIAL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1015
1016 if (uPass == SSM_PASS_FINAL)
1017 {
1018 SSMR3GetU16(pSSM, &pThis->divider);
1019 SSMR3GetU8(pSSM, &pThis->rbr);
1020 SSMR3GetU8(pSSM, &pThis->ier);
1021 SSMR3GetU8(pSSM, &pThis->lcr);
1022 SSMR3GetU8(pSSM, &pThis->mcr);
1023 SSMR3GetU8(pSSM, &pThis->lsr);
1024 SSMR3GetU8(pSSM, &pThis->msr);
1025 SSMR3GetU8(pSSM, &pThis->scr);
1026 if (uVersion > SERIAL_SAVED_STATE_VERSION_16450)
1027 {
1028 SSMR3GetU8(pSSM, &pThis->fcr);
1029 }
1030 SSMR3GetS32(pSSM, &pThis->thr_ipending);
1031 }
1032
1033 int32_t iIrq;
1034 SSMR3GetS32(pSSM, &iIrq);
1035
1036 if (uPass == SSM_PASS_FINAL)
1037 SSMR3GetS32(pSSM, &pThis->last_break_enable);
1038
1039 uint32_t IOBase;
1040 int rc = SSMR3GetU32(pSSM, &IOBase);
1041 AssertRCReturn(rc, rc);
1042
1043 if ( pThis->irq != iIrq
1044 || pThis->base != IOBase)
1045 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1046 N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
1047 iIrq, IOBase, pThis->irq, pThis->base);
1048
1049 if (uPass == SSM_PASS_FINAL)
1050 {
1051 SSMR3GetBool(pSSM, &pThis->msr_changed);
1052
1053 uint32_t u32;
1054 rc = SSMR3GetU32(pSSM, &u32);
1055 if (RT_FAILURE(rc))
1056 return rc;
1057 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1058
1059 if ( (pThis->lsr & UART_LSR_DR)
1060 || pThis->fRecvWaiting)
1061 {
1062 pThis->fRecvWaiting = false;
1063 rc = RTSemEventSignal(pThis->ReceiveSem);
1064 AssertRC(rc);
1065 }
1066
1067 /* this isn't strictly necessary but cannot hurt... */
1068 pThis->pDevInsR3 = pDevIns;
1069 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1070 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1071 }
1072
1073 return VINF_SUCCESS;
1074}
1075
1076
1077/**
1078 * @copydoc FNPDMDEVRELOCATE
1079 */
1080static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1081{
1082 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
1083 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1084 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
1085}
1086
1087#ifdef VBOX_SERIAL_PCI
1088
1089static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1090{
1091 SerialState *pThis = PCIDEV_2_SERIALSTATE(pPciDev);
1092 int rc = VINF_SUCCESS;
1093
1094 Assert(enmType == PCI_ADDRESS_SPACE_IO);
1095 Assert(iRegion == 0);
1096 Assert(cb == 8);
1097 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
1098
1099 pThis->base = (RTIOPORT)GCPhysAddress;
1100 LogRel(("Serial#%d: mapping I/O at %#06x\n", pThis->pDevIns->iInstance, pThis->base));
1101
1102 /*
1103 * Register our port IO handlers.
1104 */
1105 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
1106 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
1107 AssertRC(rc);
1108 return rc;
1109}
1110
1111#endif /* VBOX_SERIAL_PCI */
1112
1113/**
1114 * @interface_method_impl{PDMIBASE, pfnQueryInterface}
1115 */
1116static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1117{
1118 SerialState *pThis = PDMIBASE_2_SERIALSTATE(pInterface);
1119 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
1120 PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARPORT, &pThis->ICharPort);
1121 return NULL;
1122}
1123
1124/**
1125 * Destruct a device instance.
1126 *
1127 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1128 * resources can be freed correctly.
1129 *
1130 * @returns VBox status.
1131 * @param pDevIns The device instance data.
1132 */
1133static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
1134{
1135 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
1136 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1137
1138 RTSemEventDestroy(pThis->ReceiveSem);
1139 pThis->ReceiveSem = NIL_RTSEMEVENT;
1140
1141 PDMR3CritSectDelete(&pThis->CritSect);
1142 return VINF_SUCCESS;
1143}
1144
1145
1146/**
1147 * @interface_method_impl{PDMDEVREG, pfnConstruct}
1148 */
1149static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1150{
1151 int rc;
1152 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState*);
1153 uint16_t io_base;
1154 uint8_t irq_lvl;
1155
1156 Assert(iInstance < 4);
1157 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1158
1159 /*
1160 * Initialize the instance data.
1161 * (Do this early or the destructor might choke on something!)
1162 */
1163 pThis->pDevInsR3 = pDevIns;
1164 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1165 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1166
1167 /* IBase */
1168 pThis->IBase.pfnQueryInterface = serialQueryInterface;
1169
1170 /* ICharPort */
1171 pThis->ICharPort.pfnNotifyRead = serialNotifyRead;
1172 pThis->ICharPort.pfnNotifyStatusLinesChanged = serialNotifyStatusLinesChanged;
1173 pThis->ICharPort.pfnNotifyBufferFull = serialNotifyBufferFull;
1174 pThis->ICharPort.pfnNotifyBreak = serialNotifyBreak;
1175
1176#ifdef VBOX_SERIAL_PCI
1177 /* the PCI device */
1178 pThis->dev.config[0x00] = 0xee; /* Vendor: ??? */
1179 pThis->dev.config[0x01] = 0x80;
1180 pThis->dev.config[0x02] = 0x01; /* Device: ??? */
1181 pThis->dev.config[0x03] = 0x01;
1182 pThis->dev.config[0x04] = PCI_COMMAND_IOACCESS;
1183 pThis->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
1184 pThis->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
1185 pThis->dev.config[0x0b] = 0x07; /* Class: Communication controller */
1186 pThis->dev.config[0x0e] = 0x00; /* Header type: standard */
1187 pThis->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
1188 pThis->dev.config[0x3d] = 1; /* interrupt pin 0 */
1189#endif /* VBOX_SERIAL_PCI */
1190
1191 /*
1192 * Validate and read the configuration.
1193 */
1194 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
1195 "IOBase\0"
1196 "GCEnabled\0"
1197 "R0Enabled\0"
1198 "YieldOnLSRRead\0"
1199 "Enable16550A\0"
1200 ))
1201 {
1202 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
1203 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1204 }
1205
1206 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
1207 if (RT_FAILURE(rc))
1208 return PDMDEV_SET_ERROR(pDevIns, rc,
1209 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
1210
1211 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
1212 if (RT_FAILURE(rc))
1213 return PDMDEV_SET_ERROR(pDevIns, rc,
1214 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
1215
1216 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
1217 if (RT_FAILURE(rc))
1218 return PDMDEV_SET_ERROR(pDevIns, rc,
1219 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
1220
1221 rc = CFGMR3QueryU8(pCfg, "IRQ", &irq_lvl);
1222 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1223 {
1224 /* Provide sensible defaults. */
1225 if (iInstance == 0)
1226 irq_lvl = 4;
1227 else if (iInstance == 1)
1228 irq_lvl = 3;
1229 else
1230 AssertReleaseFailed(); /* irq_lvl is undefined. */
1231 }
1232 else if (RT_FAILURE(rc))
1233 return PDMDEV_SET_ERROR(pDevIns, rc,
1234 N_("Configuration error: Failed to get the \"IRQ\" value"));
1235
1236 rc = CFGMR3QueryU16(pCfg, "IOBase", &io_base);
1237 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1238 {
1239 if (iInstance == 0)
1240 io_base = 0x3f8;
1241 else if (iInstance == 1)
1242 io_base = 0x2f8;
1243 else
1244 AssertReleaseFailed(); /* io_base is undefined */
1245 }
1246 else if (RT_FAILURE(rc))
1247 return PDMDEV_SET_ERROR(pDevIns, rc,
1248 N_("Configuration error: Failed to get the \"IOBase\" value"));
1249
1250 Log(("DevSerial: instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
1251
1252 rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
1253 if (RT_FAILURE(rc))
1254 return PDMDEV_SET_ERROR(pDevIns, rc,
1255 N_("Configuration error: Failed to get the \"Enable16550A\" value"));
1256
1257 pThis->irq = irq_lvl;
1258#ifdef VBOX_SERIAL_PCI
1259 pThis->base = -1;
1260#else
1261 pThis->base = io_base;
1262#endif
1263
1264 LogRel(("Serial#%d: emulating %s\n", pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450"));
1265
1266 /*
1267 * Initialize critical section and the semaphore. Change the default
1268 * critical section to ours so that TM and IOM will enter it before
1269 * calling us.
1270 *
1271 * Note! This must of be done BEFORE creating timers, registering I/O ports
1272 * and other things which might pick up the default CS or end up
1273 * calling back into the device.
1274 */
1275 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%u", iInstance);
1276 AssertRCReturn(rc, rc);
1277
1278 rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
1279 AssertRCReturn(rc, rc);
1280
1281 rc = RTSemEventCreate(&pThis->ReceiveSem);
1282 AssertRCReturn(rc, rc);
1283
1284 /*
1285 * Create the timers.
1286 */
1287 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialFifoTimer, pThis,
1288 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "Serial Fifo Timer",
1289 &pThis->fifo_timeout_timer);
1290 AssertRCReturn(rc, rc);
1291
1292 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialTransmitTimer, pThis,
1293 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "Serial Transmit Timer",
1294 &pThis->transmit_timerR3);
1295 AssertRCReturn(rc, rc);
1296 pThis->transmit_timerR0 = TMTimerR0Ptr(pThis->transmit_timerR3);
1297 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
1298
1299 serialReset(pDevIns);
1300
1301#ifdef VBOX_SERIAL_PCI
1302 /*
1303 * Register the PCI Device and region.
1304 */
1305 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
1306 if (RT_FAILURE(rc))
1307 return rc;
1308 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
1309 if (RT_FAILURE(rc))
1310 return rc;
1311
1312#else /* !VBOX_SERIAL_PCI */
1313 /*
1314 * Register the I/O ports.
1315 */
1316 pThis->base = io_base;
1317 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
1318 serialIOPortWrite, serialIOPortRead,
1319 NULL, NULL, "SERIAL");
1320 if (RT_FAILURE(rc))
1321 return rc;
1322
1323 if (pThis->fGCEnabled)
1324 {
1325 rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
1326 "serialIOPortRead", NULL, NULL, "Serial");
1327 if (RT_FAILURE(rc))
1328 return rc;
1329 }
1330
1331 if (pThis->fR0Enabled)
1332 {
1333 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
1334 "serialIOPortRead", NULL, NULL, "Serial");
1335 if (RT_FAILURE(rc))
1336 return rc;
1337 }
1338#endif /* !VBOX_SERIAL_PCI */
1339
1340 /*
1341 * Saved state.
1342 */
1343 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
1344 serialLiveExec, serialSaveExec, serialLoadExec);
1345 if (RT_FAILURE(rc))
1346 return rc;
1347
1348 /*
1349 * Attach the char driver and get the interfaces.
1350 * For now no run-time changes are supported.
1351 */
1352 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
1353 if (RT_SUCCESS(rc))
1354 {
1355 pThis->pDrvChar = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMICHARCONNECTOR);
1356 if (!pThis->pDrvChar)
1357 {
1358 AssertLogRelMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
1359 return VERR_PDM_MISSING_INTERFACE;
1360 }
1361 /** @todo provide read notification interface!!!! */
1362 }
1363 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1364 {
1365 pThis->pDrvBase = NULL;
1366 pThis->pDrvChar = NULL;
1367 LogRel(("Serial%d: no unit\n", iInstance));
1368 }
1369 else
1370 {
1371 AssertLogRelMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1372 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1373 return rc;
1374 }
1375
1376 return VINF_SUCCESS;
1377}
1378
1379
1380/**
1381 * The device registration structure.
1382 */
1383const PDMDEVREG g_DeviceSerialPort =
1384{
1385 /* u32Version */
1386 PDM_DEVREG_VERSION,
1387 /* szName */
1388 "serial",
1389 /* szRCMod */
1390 "VBoxDDGC.gc",
1391 /* szR0Mod */
1392 "VBoxDDR0.r0",
1393 /* pszDescription */
1394 "Serial Communication Port",
1395 /* fFlags */
1396 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1397 /* fClass */
1398 PDM_DEVREG_CLASS_SERIAL,
1399 /* cMaxInstances */
1400 UINT32_MAX,
1401 /* cbInstance */
1402 sizeof(SerialState),
1403 /* pfnConstruct */
1404 serialConstruct,
1405 /* pfnDestruct */
1406 serialDestruct,
1407 /* pfnRelocate */
1408 serialRelocate,
1409 /* pfnIOCtl */
1410 NULL,
1411 /* pfnPowerOn */
1412 NULL,
1413 /* pfnReset */
1414 serialReset,
1415 /* pfnSuspend */
1416 NULL,
1417 /* pfnResume */
1418 NULL,
1419 /* pfnAttach */
1420 NULL,
1421 /* pfnDetach */
1422 NULL,
1423 /* pfnQueryInterface. */
1424 NULL,
1425 /* pfnInitComplete */
1426 NULL,
1427 /* pfnPowerOff */
1428 NULL,
1429 /* pfnSoftReset */
1430 NULL,
1431 /* u32VersionEnd */
1432 PDM_DEVREG_VERSION
1433};
1434#endif /* IN_RING3 */
1435
1436#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use