VirtualBox

Changeset 29846 in vbox for trunk/src


Ignore:
Timestamp:
May 27, 2010 4:25:28 PM (15 years ago)
Author:
vboxsync
Message:

Devices/Serial: update the implementation to 16550A

Location:
trunk/src/VBox/Devices/Serial
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Serial/DevSerial.cpp

    r28800 r29846  
    11/* $Id$ */
    22/** @file
    3  * DevSerial - 16450 UART emulation.
     3 * DevSerial - 16550A UART emulation.
     4 * (taken from hw/serial.c 2010/05/15 with modifications)
    45 */
    56
    67/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     8 * Copyright (C) 2006-2010 Oracle Corporation
    89 *
    910 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1920 * This code is based on:
    2021 *
    21  * QEMU 16450 UART emulation
     22 * QEMU 16550A UART emulation
    2223 *
    2324 * Copyright (c) 2003-2004 Fabrice Bellard
     25 * Copyright (c) 2008 Citrix Systems, Inc.
    2426 *
    2527 * Permission is hereby granted, free of charge, to any person obtaining a copy
     
    4042 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    4143 * THE SOFTWARE.
    42  *
    4344 */
    4445
     
    6869#define SERIAL_SAVED_STATE_VERSION  3
    6970
    70 #define UART_LCR_DLAB               0x80        /* Divisor latch access bit */
    71 
    72 #define UART_IER_MSI                0x08        /* Enable Modem status interrupt */
    73 #define UART_IER_RLSI               0x04        /* Enable receiver line status interrupt */
    74 #define UART_IER_THRI               0x02        /* Enable Transmitter holding register int. */
    75 #define UART_IER_RDI                0x01        /* Enable receiver data interrupt */
    76 
    77 #define UART_IIR_NO_INT             0x01        /* No interrupts pending */
    78 #define UART_IIR_ID                     0x06    /* Mask for the interrupt ID */
    79 
    80 #define UART_IIR_MSI                0x00        /* Modem status interrupt */
    81 #define UART_IIR_THRI               0x02        /* Transmitter holding register empty */
    82 #define UART_IIR_RDI                0x04        /* Receiver data interrupt */
    83 #define UART_IIR_RLSI               0x06        /* Receiver line status interrupt */
     71#define UART_LCR_DLAB       0x80        /* Divisor latch access bit */
     72
     73#define UART_IER_MSI        0x08        /* Enable Modem status interrupt */
     74#define UART_IER_RLSI       0x04        /* Enable receiver line status interrupt */
     75#define UART_IER_THRI       0x02        /* Enable Transmitter holding register int. */
     76#define UART_IER_RDI        0x01        /* Enable receiver data interrupt */
     77
     78#define UART_IIR_NO_INT     0x01        /* No interrupts pending */
     79#define UART_IIR_ID         0x06        /* Mask for the interrupt ID */
     80
     81#define UART_IIR_MSI        0x00        /* Modem status interrupt */
     82#define UART_IIR_THRI       0x02        /* Transmitter holding register empty */
     83#define UART_IIR_RDI        0x04        /* Receiver data interrupt */
     84#define UART_IIR_RLSI       0x06        /* Receiver line status interrupt */
     85#define UART_IIR_CTI        0x0C        /* Character Timeout Indication */
     86
     87#define UART_IIR_FENF       0x80        /* Fifo enabled, but not functionning */
     88#define UART_IIR_FE         0xC0        /* Fifo enabled */
    8489
    8590/*
    8691 * These are the definitions for the Modem Control Register
    8792 */
    88 #define UART_MCR_LOOP               0x10        /* Enable loopback test mode */
    89 #define UART_MCR_OUT2               0x08        /* Out2 complement */
    90 #define UART_MCR_OUT1               0x04        /* Out1 complement */
    91 #define UART_MCR_RTS                0x02        /* RTS complement */
    92 #define UART_MCR_DTR                0x01        /* DTR complement */
     93#define UART_MCR_LOOP       0x10        /* Enable loopback test mode */
     94#define UART_MCR_OUT2       0x08        /* Out2 complement */
     95#define UART_MCR_OUT1       0x04        /* Out1 complement */
     96#define UART_MCR_RTS        0x02        /* RTS complement */
     97#define UART_MCR_DTR        0x01        /* DTR complement */
    9398
    9499/*
    95100 * These are the definitions for the Modem Status Register
    96101 */
    97 #define UART_MSR_DCD                0x80        /* Data Carrier Detect */
    98 #define UART_MSR_RI                     0x40    /* Ring Indicator */
    99 #define UART_MSR_DSR                0x20        /* Data Set Ready */
    100 #define UART_MSR_CTS                0x10        /* Clear to Send */
    101 #define UART_MSR_DDCD               0x08        /* Delta DCD */
    102 #define UART_MSR_TERI               0x04        /* Trailing edge ring indicator */
    103 #define UART_MSR_DDSR               0x02        /* Delta DSR */
    104 #define UART_MSR_DCTS               0x01        /* Delta CTS */
    105 #define UART_MSR_ANY_DELTA          0x0F        /* Any of the delta bits! */
    106 
    107 #define UART_LSR_TEMT               0x40        /* Transmitter empty */
    108 #define UART_LSR_THRE               0x20        /* Transmit-hold-register empty */
    109 #define UART_LSR_BI                     0x10    /* Break interrupt indicator */
    110 #define UART_LSR_FE                     0x08    /* Frame error indicator */
    111 #define UART_LSR_PE                     0x04    /* Parity error indicator */
    112 #define UART_LSR_OE                     0x02    /* Overrun error indicator */
    113 #define UART_LSR_DR                     0x01    /* Receiver data ready */
    114 
     102#define UART_MSR_DCD        0x80        /* Data Carrier Detect */
     103#define UART_MSR_RI         0x40        /* Ring Indicator */
     104#define UART_MSR_DSR        0x20        /* Data Set Ready */
     105#define UART_MSR_CTS        0x10        /* Clear to Send */
     106#define UART_MSR_DDCD       0x08        /* Delta DCD */
     107#define UART_MSR_TERI       0x04        /* Trailing edge ring indicator */
     108#define UART_MSR_DDSR       0x02        /* Delta DSR */
     109#define UART_MSR_DCTS       0x01        /* Delta CTS */
     110#define UART_MSR_ANY_DELTA  0x0F        /* Any of the delta bits! */
     111
     112#define UART_LSR_TEMT       0x40        /* Transmitter empty */
     113#define UART_LSR_THRE       0x20        /* Transmit-hold-register empty */
     114#define UART_LSR_BI         0x10        /* Break interrupt indicator */
     115#define UART_LSR_FE         0x08        /* Frame error indicator */
     116#define UART_LSR_PE         0x04        /* Parity error indicator */
     117#define UART_LSR_OE         0x02        /* Overrun error indicator */
     118#define UART_LSR_DR         0x01        /* Receiver data ready */
     119#define UART_LSR_INT_ANY    0x1E        /* Any of the lsr-interrupt-triggering status bits */
     120
     121/*
     122 * Interrupt trigger levels.
     123 * The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher.
     124 */
     125#define UART_FCR_ITL_1      0x00        /* 1 byte ITL */
     126#define UART_FCR_ITL_2      0x40        /* 4 bytes ITL */
     127#define UART_FCR_ITL_3      0x80        /* 8 bytes ITL */
     128#define UART_FCR_ITL_4      0xC0        /* 14 bytes ITL */
     129
     130#define UART_FCR_DMS        0x08        /* DMA Mode Select */
     131#define UART_FCR_XFR        0x04        /* XMIT Fifo Reset */
     132#define UART_FCR_RFR        0x02        /* RCVR Fifo Reset */
     133#define UART_FCR_FE         0x01        /* FIFO Enable */
     134
     135#define UART_FIFO_LENGTH    16          /* 16550A Fifo Length */
     136
     137#define XMIT_FIFO           0
     138#define RECV_FIFO           1
     139#define MAX_XMIT_RETRY      8
    115140
    116141/*******************************************************************************
    117142*   Structures and Typedefs                                                    *
    118143*******************************************************************************/
     144
     145struct SerialFifo
     146{
     147    uint8_t data[UART_FIFO_LENGTH];
     148    uint8_t count;
     149    uint8_t itl;
     150    uint8_t tail;
     151    uint8_t head;
     152};
     153
    119154/**
    120155 * Serial device.
     
    127162    /** Access critical section. */
    128163    PDMCRITSECT                     CritSect;
    129 
    130164    /** Pointer to the device instance - R3 Ptr. */
    131165    PPDMDEVINSR3                    pDevInsR3;
     
    134168    /** Pointer to the device instance - RC Ptr. */
    135169    PPDMDEVINSRC                    pDevInsRC;
    136     RTRCPTR                         Alignment0; /**< Alignment. */
     170    /** Alignment. */
     171    RTRCPTR                         Alignment0;
    137172    /** LUN\#0: The base interface. */
    138173    PDMIBASE                        IBase;
     
    142177    R3PTRTYPE(PPDMIBASE)            pDrvBase;
    143178    /** Pointer to the attached character driver. */
    144     R3PTRTYPE(PPDMICHARCONNECTOR)            pDrvChar;
    145 
     179    R3PTRTYPE(PPDMICHARCONNECTOR)   pDrvChar;
     180
     181    RTSEMEVENT                      ReceiveSem;
     182    PTMTIMERR3                      fifo_timeout_timer;
     183    PTMTIMERR3                      transmit_timerR3;
     184    PTMTIMERR0                      transmit_timerR0; /* currently not used */
     185    PTMTIMERRC                      transmit_timerRC; /* currently not used */
     186    RTRCPTR                         Alignment1;
     187    SerialFifo                      recv_fifo;
     188    SerialFifo                      xmit_fifo;
     189
     190    uint32_t                        base;
    146191    uint16_t                        divider;
    147     uint16_t                        auAlignment[3];
    148     uint8_t                         rbr; /* receive register */
    149     uint8_t                         ier;
    150     uint8_t                         iir; /* read only */
    151     uint8_t                         lcr;
    152     uint8_t                         mcr;
    153     uint8_t                         lsr; /* read only */
    154     uint8_t                         msr; /* read only */
    155     uint8_t                         scr;
     192    uint16_t                        Alignment2[1];
     193    uint8_t                         rbr; /**< receive register */
     194    uint8_t                         thr; /**< transmit holding register */
     195    uint8_t                         tsr; /**< transmit shift register */
     196    uint8_t                         ier; /**< interrupt enable register */
     197    uint8_t                         iir; /**< interrupt itentification register, R/O */
     198    uint8_t                         lcr; /**< line control register */
     199    uint8_t                         mcr; /**< modem control register */
     200    uint8_t                         lsr; /**< line status register, R/O */
     201    uint8_t                         msr; /**< modem status register, R/O */
     202    uint8_t                         scr; /**< scratch register */
     203    uint8_t                         fcr; /**< fifo control register */
     204    uint8_t                         fcr_vmstate;
    156205    /* NOTE: this hidden state is necessary for tx irq generation as
    157206       it can be reset while reading iir */
    158207    int                             thr_ipending;
     208    int                             timeout_ipending;
    159209    int                             irq;
     210    int                             last_break_enable;
     211    /** Counter for retrying xmit */
     212    int                             tsr_retry;
    160213    bool                            msr_changed;
    161 
    162214    bool                            fGCEnabled;
    163215    bool                            fR0Enabled;
    164216    bool                            fYieldOnLSRRead;
    165     bool                            afAlignment[4];
    166 
    167     RTSEMEVENT                      ReceiveSem;
    168     int                             last_break_enable;
    169     uint32_t                        base;
     217    bool volatile                   fRecvWaiting;
     218    bool                            Alignment3[3];
     219    /** Time it takes to transmit a character */
     220    uint64_t                        char_transmit_time;
    170221
    171222#ifdef VBOX_SERIAL_PCI
     
    194245#ifdef IN_RING3
    195246
     247static int serial_can_receive(SerialState *s);
     248static void serial_receive(void *opaque, const uint8_t *buf, int size);
     249
     250static void fifo_clear(SerialState *s, int fifo)
     251{
     252    SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
     253    memset(f->data, 0, UART_FIFO_LENGTH);
     254    f->count = 0;
     255    f->head = 0;
     256    f->tail = 0;
     257}
     258
     259static int fifo_put(SerialState *s, int fifo, uint8_t chr)
     260{
     261    SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
     262
     263    /* Receive overruns do not overwrite FIFO contents. */
     264    if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH)
     265    {
     266        f->data[f->head++] = chr;
     267        if (f->head == UART_FIFO_LENGTH)
     268            f->head = 0;
     269    }
     270
     271    if (f->count < UART_FIFO_LENGTH)
     272        f->count++;
     273    else if (fifo == RECV_FIFO)
     274        s->lsr |= UART_LSR_OE;
     275
     276    return 1;
     277}
     278
     279static uint8_t fifo_get(SerialState *s, int fifo)
     280{
     281    SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
     282    uint8_t c;
     283
     284    if (f->count == 0)
     285        return 0;
     286
     287    c = f->data[f->tail++];
     288    if (f->tail == UART_FIFO_LENGTH)
     289        f->tail = 0;
     290    f->count--;
     291
     292    return c;
     293}
     294
    196295static void serial_update_irq(SerialState *s)
    197296{
    198     if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
    199         s->iir = UART_IIR_RDI;
    200     } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
    201         s->iir = UART_IIR_THRI;
    202     } else if (s->msr_changed && (s->ier & UART_IER_RLSI)) {
    203         s->iir = UART_IIR_RLSI;
    204     } else if (s->lsr & UART_LSR_BI) {
    205         s->iir = 0; /* No special status bit */
    206     } else {
    207         s->iir = UART_IIR_NO_INT;
    208     }
    209     if (s->iir != UART_IIR_NO_INT) {
     297    uint8_t tmp_iir = UART_IIR_NO_INT;
     298
     299    if (   (s->ier & UART_IER_RLSI)
     300        && (s->lsr & UART_LSR_INT_ANY)) {
     301        tmp_iir = UART_IIR_RLSI;
     302    } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) {
     303        /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
     304         * this is not in the specification but is observed on existing
     305         * hardware. */
     306        tmp_iir = UART_IIR_CTI;
     307    } else if (   (s->ier & UART_IER_RDI)
     308               && (s->lsr & UART_LSR_DR)
     309               && (   !(s->fcr & UART_FCR_FE)
     310                   || s->recv_fifo.count >= s->recv_fifo.itl)) {
     311        tmp_iir = UART_IIR_RDI;
     312    } else if (   (s->ier & UART_IER_THRI)
     313               && s->thr_ipending) {
     314        tmp_iir = UART_IIR_THRI;
     315    } else if (   (s->ier & UART_IER_MSI)
     316               && (s->msr & UART_MSR_ANY_DELTA)) {
     317        tmp_iir = UART_IIR_MSI;
     318    }
     319    s->iir = tmp_iir | (s->iir & 0xF0);
     320
     321    /** XXX only call the SetIrq function if the state really changes! */
     322    if (tmp_iir != UART_IIR_NO_INT) {
    210323        Log(("serial_update_irq %d 1\n", s->irq));
    211324# ifdef VBOX_SERIAL_PCI
     
    226339static void serial_update_parameters(SerialState *s)
    227340{
    228     int speed, parity, data_bits, stop_bits;
    229 
     341    int speed, parity, data_bits, stop_bits, frame_size;
     342
     343    if (s->divider == 0)
     344        return;
     345
     346    frame_size = 1;
    230347    if (s->lcr & 0x08) {
     348        frame_size++;
    231349        if (s->lcr & 0x10)
    232350            parity = 'E';
     
    240358    else
    241359        stop_bits = 1;
     360
    242361    data_bits = (s->lcr & 0x03) + 5;
    243     if (s->divider == 0)
    244         return;
     362    frame_size += data_bits + stop_bits;
    245363    speed = 115200 / s->divider;
     364    s->char_transmit_time = (TMTimerGetFreq(CTX_SUFF(s->transmit_timer)) / speed) * frame_size;
    246365    Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
     366
    247367    if (RT_LIKELY(s->pDrvChar))
    248368        s->pDrvChar->pfnSetParameters(s->pDrvChar, speed, parity, data_bits, stop_bits);
    249369}
    250370
     371static void serial_xmit(void *opaque)
     372{
     373    SerialState *s = (SerialState*)opaque;
     374    uint64_t new_xmit_ts = TMTimerGet(CTX_SUFF(s->transmit_timer));
     375
     376    if (s->tsr_retry <= 0) {
     377        if (s->fcr & UART_FCR_FE) {
     378            s->tsr = fifo_get(s, XMIT_FIFO);
     379            if (!s->xmit_fifo.count)
     380                s->lsr |= UART_LSR_THRE;
     381        } else {
     382            s->tsr = s->thr;
     383            s->lsr |= UART_LSR_THRE;
     384        }
     385    }
     386
     387    if (s->mcr & UART_MCR_LOOP) {
     388        /* in loopback mode, say that we just received a char */
     389        serial_receive(s, &s->tsr, 1);
     390    } else if (   RT_LIKELY(s->pDrvChar)
     391               && RT_FAILURE(s->pDrvChar->pfnWrite(s->pDrvChar, &s->tsr, 1))) {
     392        if ((s->tsr_retry >= 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
     393            s->tsr_retry++;
     394            TMTimerSet(CTX_SUFF(s->transmit_timer), new_xmit_ts + s->char_transmit_time);
     395            return;
     396        } else {
     397            /* drop this character. */
     398            s->tsr_retry = 0;
     399        }
     400    }
     401    else {
     402        s->tsr_retry = 0;
     403    }
     404
     405    if (!(s->lsr & UART_LSR_THRE))
     406        TMTimerSet(CTX_SUFF(s->transmit_timer),
     407                   TMTimerGet(CTX_SUFF(s->transmit_timer)) + s->char_transmit_time);
     408
     409    if (s->lsr & UART_LSR_THRE) {
     410        s->lsr |= UART_LSR_TEMT;
     411        s->thr_ipending = 1;
     412        serial_update_irq(s);
     413    }
     414}
     415
    251416#endif /* IN_RING3 */
    252417
    253 static int serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
    254 {
    255     SerialState *s = (SerialState *)opaque;
    256     unsigned char ch;
    257 
     418static int serial_ioport_write(SerialState *s, uint32_t addr, uint32_t val)
     419{
    258420    addr &= 7;
    259     LogFlow(("serial: write addr=0x%02x val=0x%02x\n", addr, val));
    260421
    261422#ifndef IN_RING3
    262     NOREF(ch);
    263423    NOREF(s);
    264424    return VINF_IOM_HC_IOPORT_WRITE;
     
    270430            s->divider = (s->divider & 0xff00) | val;
    271431            serial_update_parameters(s);
    272 #if 0 /* disabled because this causes regressions */
    273         } else if (s->lsr & UART_LSR_THRE) {
    274             s->thr_ipending = 0;
    275             ch = val;
    276             if (RT_LIKELY(s->pDrvChar))
    277             {
    278                 Log(("serial_ioport_write: write 0x%X\n", ch));
    279                 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
    280                 AssertRC(rc);
     432        } else {
     433            s->thr = (uint8_t) val;
     434            if (s->fcr & UART_FCR_FE) {
     435                fifo_put(s, XMIT_FIFO, s->thr);
     436                s->thr_ipending = 0;
     437                s->lsr &= ~UART_LSR_TEMT;
     438                s->lsr &= ~UART_LSR_THRE;
     439                serial_update_irq(s);
     440            } else {
     441                s->thr_ipending = 0;
     442                s->lsr &= ~UART_LSR_THRE;
     443                serial_update_irq(s);
    281444            }
    282             s->thr_ipending = 1;
    283             serial_update_irq(s);
    284         } else
    285             Log(("serial: THR not EMPTY!\n"));
    286 #else
    287         } else {
    288             s->thr_ipending = 0;
    289             s->lsr &= ~UART_LSR_THRE;
    290             serial_update_irq(s);
    291             ch = val;
    292             if (RT_LIKELY(s->pDrvChar))
    293             {
    294                 Log(("serial_ioport_write: write 0x%X\n", ch));
    295                 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
    296                 AssertRC(rc);
    297             }
    298             s->thr_ipending = 1;
    299             s->lsr |= UART_LSR_THRE;
    300             s->lsr |= UART_LSR_TEMT;
    301             serial_update_irq(s);
    302         }
    303 #endif
     445            serial_xmit(s);
     446        }
    304447        break;
    305448    case 1:
     
    311454            if (s->lsr & UART_LSR_THRE) {
    312455                s->thr_ipending = 1;
     456                serial_update_irq(s);
    313457            }
    314             serial_update_irq(s);
    315458        }
    316459        break;
    317460    case 2:
     461        val = val & 0xFF;
     462
     463        if (s->fcr == val)
     464            break;
     465
     466        /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
     467        if ((val ^ s->fcr) & UART_FCR_FE)
     468            val |= UART_FCR_XFR | UART_FCR_RFR;
     469
     470        /* FIFO clear */
     471        if (val & UART_FCR_RFR) {
     472            TMTimerStop(s->fifo_timeout_timer);
     473            s->timeout_ipending = 0;
     474            fifo_clear(s, RECV_FIFO);
     475        }
     476        if (val & UART_FCR_XFR) {
     477            fifo_clear(s, XMIT_FIFO);
     478        }
     479
     480        if (val & UART_FCR_FE) {
     481            s->iir |= UART_IIR_FE;
     482            /* Set RECV_FIFO trigger Level */
     483            switch (val & 0xC0) {
     484            case UART_FCR_ITL_1:
     485                s->recv_fifo.itl = 1;
     486                break;
     487            case UART_FCR_ITL_2:
     488                s->recv_fifo.itl = 4;
     489                break;
     490            case UART_FCR_ITL_3:
     491                s->recv_fifo.itl = 8;
     492                break;
     493            case UART_FCR_ITL_4:
     494                s->recv_fifo.itl = 14;
     495                break;
     496            }
     497        } else
     498            s->iir &= ~UART_IIR_FE;
     499
     500        /* Set fcr - or at least the bits in it that are supposed to "stick" */
     501        s->fcr = val & 0xC9;
     502        serial_update_irq(s);
    318503        break;
    319504    case 3:
    320505        {
    321506            int break_enable;
    322             if (s->lcr != val)
    323             {
    324                 s->lcr = val;
    325                 serial_update_parameters(s);
    326             }
     507            s->lcr = val;
     508            serial_update_parameters(s);
    327509            break_enable = (val >> 6) & 1;
    328510            if (break_enable != s->last_break_enable) {
     
    341523        if (RT_LIKELY(s->pDrvChar))
    342524        {
    343             int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar, !!(s->mcr & UART_MCR_RTS), !!(s->mcr & UART_MCR_DTR));
     525            int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar,
     526                                                   !!(s->mcr & UART_MCR_RTS),
     527                                                   !!(s->mcr & UART_MCR_DTR));
    344528            AssertRC(rc);
    345529        }
     
    369553    case 0:
    370554        if (s->lcr & UART_LCR_DLAB) {
     555            /* DLAB == 1: divisor latch (LS) */
    371556            ret = s->divider & 0xff;
    372557        } else {
     
    374559            *pRC = VINF_IOM_HC_IOPORT_READ;
    375560#else
    376             Log(("serial_io_port_read: read 0x%X\n", s->rbr));
    377             ret = s->rbr;
    378             s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
     561            if (s->fcr & UART_FCR_FE) {
     562                ret = fifo_get(s, RECV_FIFO);
     563                if (s->recv_fifo.count == 0)
     564                    s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
     565                else
     566                    TMTimerSet(s->fifo_timeout_timer,
     567                               TMTimerGet(s->fifo_timeout_timer) + s->char_transmit_time * 4);
     568                s->timeout_ipending = 0;
     569            } else {
     570                Log(("serial_io_port_read: read 0x%X\n", s->rbr));
     571                ret = s->rbr;
     572                s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
     573            }
    379574            serial_update_irq(s);
     575            if (s->fRecvWaiting)
    380576            {
     577                s->fRecvWaiting = false;
    381578                int rc = RTSemEventSignal(s->ReceiveSem);
    382579                AssertRC(rc);
     
    387584    case 1:
    388585        if (s->lcr & UART_LCR_DLAB) {
     586            /* DLAB == 1: divisor latch (MS) */
    389587            ret = (s->divider >> 8) & 0xff;
    390588        } else {
     
    397595#else
    398596        ret = s->iir;
    399         /* reset THR pending bit */
    400         if ((ret & 0x7) == UART_IIR_THRI)
     597        if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
    401598            s->thr_ipending = 0;
     599            serial_update_irq(s);
     600        }
    402601        /* reset msr changed bit */
    403602        s->msr_changed = false;
    404         serial_update_irq(s);
    405603#endif
    406604        break;
     
    423621        }
    424622        ret = s->lsr;
     623        /* Clear break and overrun interrupts */
     624        if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
     625#ifndef IN_RING3
     626            *pRC = VINF_IOM_HC_IOPORT_READ;
     627#else
     628            s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
     629            serial_update_irq(s);
     630#endif
     631        }
    425632        break;
    426633    case 6:
     
    433640        } else {
    434641            ret = s->msr;
    435             /* Reset delta bits. */
    436             s->msr &= ~UART_MSR_ANY_DELTA;
     642            /* Clear delta bits & msr int after read, if they were set */
     643            if (s->msr & UART_MSR_ANY_DELTA) {
     644#ifndef IN_RING3
     645                *pRC = VINF_IOM_HC_IOPORT_READ;
     646#else
     647                s->msr &= 0xF0;
     648                serial_update_irq(s);
     649#endif
     650            }
    437651        }
    438652        break;
     
    441655        break;
    442656    }
    443     LogFlow(("serial: read addr=0x%02x val=0x%02x\n", addr, ret));
    444657    return ret;
    445658}
     
    447660#ifdef IN_RING3
    448661
     662static int serial_can_receive(SerialState *s)
     663{
     664    if (s->fcr & UART_FCR_FE) {
     665        if (s->recv_fifo.count < UART_FIFO_LENGTH)
     666            return (s->recv_fifo.count <= s->recv_fifo.itl)
     667                ? s->recv_fifo.itl - s->recv_fifo.count : 1;
     668        else
     669            return 0;
     670    } else {
     671        return !(s->lsr & UART_LSR_DR);
     672    }
     673}
     674
     675static void serial_receive(void *opaque, const uint8_t *buf, int size)
     676{
     677    SerialState *s = (SerialState*)opaque;
     678    if (s->fcr & UART_FCR_FE) {
     679        int i;
     680        for (i = 0; i < size; i++) {
     681            fifo_put(s, RECV_FIFO, buf[i]);
     682        }
     683        s->lsr |= UART_LSR_DR;
     684        /* call the timeout receive callback in 4 char transmit time */
     685        TMTimerSet(s->fifo_timeout_timer, TMTimerGet(s->fifo_timeout_timer) + s->char_transmit_time * 4);
     686    } else {
     687        if (s->lsr & UART_LSR_DR)
     688            s->lsr |= UART_LSR_OE;
     689        s->rbr = buf[0];
     690        s->lsr |= UART_LSR_DR;
     691    }
     692    serial_update_irq(s);
     693}
     694
     695/** @copydoc PDMICHARPORT::pfnNotifyRead */
    449696static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
    450697{
    451698    SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
    452     int rc;
    453 
    454     Assert(*pcbRead != 0);
     699    const uint8_t *pu8Buf = (const uint8_t*)pvBuf;
     700    size_t cbRead = *pcbRead;
    455701
    456702    PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
    457     if (pThis->lsr & UART_LSR_DR)
    458     {
    459         /* If a character is still in the read queue, then wait for it to be emptied. */
    460         PDMCritSectLeave(&pThis->CritSect);
    461         rc = RTSemEventWait(pThis->ReceiveSem, 250);
    462         if (RT_FAILURE(rc))
    463             return rc;
    464 
    465         PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
    466     }
    467 
    468     if (!(pThis->lsr & UART_LSR_DR))
    469     {
    470         pThis->rbr = *(const char *)pvBuf;
    471         pThis->lsr |= UART_LSR_DR;
    472         serial_update_irq(pThis);
    473         *pcbRead = 1;
    474         rc = VINF_SUCCESS;
    475     }
    476     else
    477         rc = VERR_TIMEOUT;
    478 
     703    for (; cbRead > 0; cbRead--, pu8Buf++)
     704    {
     705        if (!serial_can_receive(pThis))
     706        {
     707            /* If we cannot receive then wait for not more than 250ms. If we still
     708             * cannot receive then the new character will either overwrite rbr
     709             * or it will be dropped at fifo_put(). */
     710            pThis->fRecvWaiting = true;
     711            PDMCritSectLeave(&pThis->CritSect);
     712            int rc = RTSemEventWait(pThis->ReceiveSem, 250);
     713            PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
     714        }
     715        serial_receive(pThis, &pu8Buf[0], 1);
     716    }
    479717    PDMCritSectLeave(&pThis->CritSect);
    480 
    481     return rc;
    482 }
    483 
     718    return VINF_SUCCESS;
     719}
     720
     721/** @copydoc PDMICHARPORT::pfnNotifyStatusLinesChanged */
    484722static DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines)
    485723{
     
    520758}
    521759
     760/** @copydoc PDMICHARPORT::pfnNotifyBufferFull */
    522761static DECLCALLBACK(int) serialNotifyBufferFull(PPDMICHARPORT pInterface, bool fFull)
    523762{
    524 #if 0
    525     SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
    526     PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
    527     if (fFull)
    528     {
    529         pThis->lsr &= ~UART_LSR_THRE;
    530     }
    531     else
    532     {
    533         pThis->thr_ipending = 1;
    534         pThis->lsr |= UART_LSR_THRE;
    535         pThis->lsr |= UART_LSR_TEMT;
    536     }
    537     serial_update_irq(pThis);
    538     PDMCritSectLeave(&pThis->CritSect);
    539 #endif
    540763    return VINF_SUCCESS;
    541764}
    542765
     766/** @copydoc PDMICHARPORT::pfnNotifyBreak */
    543767static DECLCALLBACK(int) serialNotifyBreak(PPDMICHARPORT pInterface)
    544768{
     
    555779
    556780    return VINF_SUCCESS;
     781}
     782
     783/**
     784 * Fifo timer functions.
     785 */
     786static DECLCALLBACK(void) serialFifoTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     787{
     788    SerialState *s = (SerialState*)pvUser;
     789    if (s->recv_fifo.count)
     790    {
     791        s->timeout_ipending = 1;
     792        serial_update_irq(s);
     793    }
     794}
     795
     796/**
     797 * Transmit timer function.
     798 * Just retry to transmit a character.
     799 *
     800 * @param   pTimer      The timer handle.
     801 * @param   pDevIns     The device instance.
     802 * @param   pvUser      The user pointer.
     803 */
     804static DECLCALLBACK(void) serialTransmitTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     805{
     806    SerialState *s = (SerialState*)pvUser;
     807    serial_xmit(s);
     808}
     809
     810/**
     811 * Reset the serial device.
     812 *
     813 * @param   pDevIns     The device instance.
     814 */
     815static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
     816{
     817    SerialState *s = PDMINS_2_DATA(pDevIns, SerialState *);
     818
     819    s->rbr = 0;
     820    s->ier = 0;
     821    s->iir = UART_IIR_NO_INT;
     822    s->lcr = 0;
     823    s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
     824    s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
     825    /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
     826    s->divider = 0x0C;
     827    s->mcr = UART_MCR_OUT2;
     828    s->scr = 0;
     829    s->tsr_retry = 0;
     830    s->char_transmit_time = (TMTimerGetFreq(CTX_SUFF(s->transmit_timer)) / 9600) * 10;
     831
     832    fifo_clear(s, RECV_FIFO);
     833    fifo_clear(s, XMIT_FIFO);
     834
     835    s->thr_ipending = 0;
     836    s->last_break_enable = 0;
     837# ifdef VBOX_SERIAL_PCI
     838        PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0);
     839# else /* !VBOX_SERIAL_PCI */
     840        PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
     841# endif /* !VBOX_SERIAL_PCI */
    557842}
    558843
     
    701986    if (    pThis->irq  != iIrq
    702987        ||  pThis->base != IOBase)
    703         return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
     988        return SSMR3SetCfgError(pSSM, RT_SRC_POS,
     989                                N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
    704990                                iIrq, IOBase, pThis->irq, pThis->base);
    705991
     
    7351021static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
    7361022{
    737     SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
    738     pThis->pDevInsRC   = PDMDEVINS_2_RCPTR(pDevIns);
     1023    SerialState *pThis      = PDMINS_2_DATA(pDevIns, SerialState *);
     1024    pThis->pDevInsRC        = PDMDEVINS_2_RCPTR(pDevIns);
     1025    pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
    7391026}
    7401027
     
    7661053
    7671054/**
    768  * @interface_method_impl{PDMIBASE,pfnQueryInterface}
     1055 * @interface_method_impl{PDMIBASE, pfnQueryInterface}
    7691056 */
    7701057static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
     
    7991086
    8001087/**
    801  * @interface_method_impl{PDMDEVREG,pfnConstruct}
    802  */
    803 static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns,
    804                                          int iInstance,
    805                                          PCFGMNODE pCfg)
     1088 * @interface_method_impl{PDMDEVREG, pfnConstruct}
     1089 */
     1090static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
    8061091{
    8071092    int            rc;
     
    8201105    pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
    8211106    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    822 
    823     pThis->lsr = UART_LSR_TEMT | UART_LSR_THRE;
    824     pThis->iir = UART_IIR_NO_INT;
    825     pThis->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
    8261107
    8271108    /* IBase */
     
    9211202    rc = RTSemEventCreate(&pThis->ReceiveSem);
    9221203    AssertRC(rc);
     1204
     1205    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialFifoTimer, pThis,
     1206                                TMTIMER_FLAGS_NO_CRIT_SECT, "Serial Fifo Timer",
     1207                                &pThis->fifo_timeout_timer);
     1208    AssertRC(rc);
     1209
     1210    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialTransmitTimer, pThis,
     1211                                TMTIMER_FLAGS_NO_CRIT_SECT, "Serial Transmit Timer",
     1212                                &pThis->transmit_timerR3);
     1213    AssertRC(rc);
     1214    pThis->transmit_timerR0 = TMTimerR0Ptr(pThis->transmit_timerR3);
     1215    pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
     1216
     1217    serialReset(pDevIns);
    9231218
    9241219#ifdef VBOX_SERIAL_PCI
     
    10361331    NULL,
    10371332    /* pfnReset */
    1038     NULL,
     1333    serialReset,
    10391334    /* pfnSuspend */
    10401335    NULL,
     
    10581353#endif /* IN_RING3 */
    10591354
    1060 
    10611355#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
  • trunk/src/VBox/Devices/Serial/DrvChar.cpp

    r28800 r29846  
    55 * Converts synchronous calls (PDMICHARCONNECTOR::pfnWrite, PDMISTREAM::pfnRead)
    66 * into asynchronous ones.
     7 *
     8 * Note that we don't use a send buffer here to be able to handle
     9 * dropping of bytes for xmit at device level.
    710 */
    811
     
    3740*   Defined Constants And Macros                                               *
    3841*******************************************************************************/
    39 /** Size of the send fifo queue (in bytes) */
    40 #define CHAR_MAX_SEND_QUEUE             0x80
    41 #define CHAR_MAX_SEND_QUEUE_MASK        0x7f
    42 
    4342/** Converts a pointer to DRVCHAR::ICharConnector to a PDRVCHAR. */
    4443#define PDMICHAR_2_DRVCHAR(pInterface)  RT_FROM_MEMBER(pInterface, DRVCHAR, ICharConnector)
     
    7372
    7473    /** Internal send FIFO queue */
    75     uint8_t                     aSendQueue[CHAR_MAX_SEND_QUEUE];
    76     uint32_t volatile           iSendQueueHead;
    77     uint32_t                    iSendQueueTail;
    78     uint32_t volatile           cEntries;
     74    uint8_t volatile            u8SendByte;
     75    bool volatile               fSending;
     76    uint8_t                     Alignment[2];
    7977
    8078    /** Read/write statistics */
     
    115113    for (uint32_t i = 0; i < cbWrite; i++)
    116114    {
    117         uint32_t iOld = pThis->iSendQueueHead;
    118         uint32_t iNew = (iOld + 1) & CHAR_MAX_SEND_QUEUE_MASK;
    119 
    120         pThis->aSendQueue[iOld] = pbBuffer[i];
    121 
     115        if (ASMAtomicXchgBool(&pThis->fSending, true))
     116            return VERR_BUFFER_OVERFLOW;
     117
     118        pThis->u8SendByte = pbBuffer[i];
     119        RTSemEventSignal(pThis->SendSem);
    122120        STAM_COUNTER_INC(&pThis->StatBytesWritten);
    123         ASMAtomicXchgU32(&pThis->iSendQueueHead, iNew);
    124         ASMAtomicIncU32(&pThis->cEntries);
    125         if (pThis->cEntries > CHAR_MAX_SEND_QUEUE_MASK / 2)
    126             pThis->pDrvCharPort->pfnNotifyBufferFull(pThis->pDrvCharPort, true /*fFull*/);
    127     }
    128     RTSemEventSignal(pThis->SendSem);
     121    }
    129122    return VINF_SUCCESS;
    130123}
     
    153146    PDRVCHAR pThis = (PDRVCHAR)pvUser;
    154147
     148    int rc = VINF_SUCCESS;
    155149    while (!pThis->fShutdown)
    156150    {
    157         int rc = RTSemEventWait(pThis->SendSem, RT_INDEFINITE_WAIT);
    158         if (RT_FAILURE(rc))
     151        RTMSINTERVAL cMillies = (rc == VERR_TIMEOUT) ? 50 : RT_INDEFINITE_WAIT;
     152        rc = RTSemEventWait(pThis->SendSem, cMillies);
     153        if (    RT_FAILURE(rc)
     154             && rc != VERR_TIMEOUT)
    159155            break;
    160156
     
    166162            break;
    167163
    168         while (   pThis->iSendQueueTail != pThis->iSendQueueHead
    169                && !pThis->fShutdown)
     164        size_t cbProcessed = 1;
     165        uint8_t ch = pThis->u8SendByte;
     166        rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &ch, &cbProcessed);
     167        if (RT_SUCCESS(rc))
    170168        {
    171             size_t cbProcessed = 1;
    172 
    173             rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &pThis->aSendQueue[pThis->iSendQueueTail], &cbProcessed);
    174             pThis->pDrvCharPort->pfnNotifyBufferFull(pThis->pDrvCharPort, false /*fFull*/);
    175             if (RT_SUCCESS(rc))
    176             {
    177                 Assert(cbProcessed);
    178                 pThis->iSendQueueTail++;
    179                 pThis->iSendQueueTail &= CHAR_MAX_SEND_QUEUE_MASK;
    180                 ASMAtomicDecU32(&pThis->cEntries);
    181             }
    182             else if (rc == VERR_TIMEOUT)
    183             {
    184                 /* Normal case, just means that the stream didn't accept a new
    185                  * character before the timeout elapsed. Just retry. */
    186                 rc = VINF_SUCCESS;
    187             }
    188             else
    189             {
    190                 LogFlow(("Write failed with %Rrc; skipping\n", rc));
    191                 break;
    192             }
     169            ASMAtomicXchgBool(&pThis->fSending, false);
     170            Assert(cbProcessed == 1);
     171        }
     172        else if (rc == VERR_TIMEOUT)
     173        {
     174            /* Normal case, just means that the stream didn't accept a new
     175             * character before the timeout elapsed. Just retry. */
     176            rc = VINF_SUCCESS;
     177        }
     178        else
     179        {
     180            LogRel(("Write failed with %Rrc; skipping\n", rc));
     181            break;
    193182        }
    194183    }
     
    462451    PDM_DRVREG_VERSION
    463452};
    464 
Note: See TracChangeset for help on using the changeset viewer.

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