VirtualBox

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

Last change on this file since 37466 was 37466, checked in by vboxsync, 13 years ago

VMM,Devices: Automatically use a per-device lock instead of the giant IOM lock. With exception of the PIC, APIC, IOAPIC and PCI buses which are all using the PDM crit sect, there should be no calls between devices. So, this change should be relatively safe.

  • 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 37466 2011-06-15 12:44:16Z 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 *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.

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