VirtualBox

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

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

tabs

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