VirtualBox

Changeset 77411 in vbox


Ignore:
Timestamp:
Feb 21, 2019 3:57:31 PM (6 years ago)
Author:
vboxsync
Message:

Devices/UART: Properly handle loopback mode (feeding the sent data immediately back to the receive side)

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

Legend:

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

    r76553 r77411  
    706706static void uartR3XferReset(PUARTCORE pThis)
    707707{
     708    TMTimerStop(pThis->CTX_SUFF(pTimerRcvFifoTimeout));
     709    TMTimerStop(pThis->CTX_SUFF(pTimerTxUnconnected));
    708710    pThis->uRegLsr = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
    709711    pThis->fThreEmptyPending = false;
     
    779781
    780782/**
     783 * Transmits the given byte.
     784 *
     785 * @returns VBox status code.
     786 * @param   pThis               The serial port instance.
     787 * @param   bVal                Byte to transmit.
     788 */
     789static int uartXmit(PUARTCORE pThis, uint8_t bVal)
     790{
     791    int rc = VINF_SUCCESS;
     792
     793    if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
     794    {
     795#ifndef IN_RING3
     796        if (!uartFifoUsedGet(&pThis->FifoXmit))
     797            rc = VINF_IOM_R3_IOPORT_WRITE;
     798        else
     799        {
     800            uartFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, bVal);
     801            UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
     802        }
     803#else
     804        uartFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, bVal);
     805        UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
     806        pThis->fThreEmptyPending = false;
     807        uartIrqUpdate(pThis);
     808        if (uartFifoUsedGet(&pThis->FifoXmit) == 1)
     809        {
     810            if (   pThis->pDrvSerial
     811                && !(pThis->uRegMcr & UART_REG_MCR_LOOP))
     812            {
     813                int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial);
     814                if (RT_FAILURE(rc2))
     815                    LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", pThis->pDevInsR3->iInstance, rc2));
     816            }
     817            else
     818                TMTimerSetRelative(pThis->CTX_SUFF(pTimerTxUnconnected), pThis->cSymbolXferTicks, NULL);
     819        }
     820#endif
     821    }
     822    else
     823    {
     824        /* Notify the lower driver about available data only if the register was empty before. */
     825        if (pThis->uRegLsr & UART_REG_LSR_THRE)
     826        {
     827#ifndef IN_RING3
     828            rc = VINF_IOM_R3_IOPORT_WRITE;
     829#else
     830            pThis->uRegThr = bVal;
     831            UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
     832            pThis->fThreEmptyPending = false;
     833            uartIrqUpdate(pThis);
     834            if (   pThis->pDrvSerial
     835                && !(pThis->uRegMcr & UART_REG_MCR_LOOP))
     836            {
     837                int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial);
     838                if (RT_FAILURE(rc2))
     839                    LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", pThis->pDevInsR3->iInstance, rc2));
     840            }
     841            else
     842                TMTimerSetRelative(pThis->CTX_SUFF(pTimerTxUnconnected), pThis->cSymbolXferTicks, NULL);
     843#endif
     844        }
     845        else
     846            pThis->uRegThr = bVal;
     847    }
     848
     849    return rc;
     850}
     851
     852
     853/**
    781854 * Write handler for the THR/DLL register (depending on the DLAB bit in LCR).
    782855 *
     
    803876    }
    804877    else
    805     {
    806         if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    807         {
    808 #ifndef IN_RING3
    809             if (!uartFifoUsedGet(&pThis->FifoXmit))
    810                 rc = VINF_IOM_R3_IOPORT_WRITE;
    811             else
    812             {
    813                 uartFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, uVal);
    814                 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
    815             }
    816 #else
    817             uartFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, uVal);
    818             UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
    819             pThis->fThreEmptyPending = false;
    820             uartIrqUpdate(pThis);
    821             if (   pThis->pDrvSerial
    822                 && uartFifoUsedGet(&pThis->FifoXmit) == 1)
    823             {
    824                 int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial);
    825                 if (RT_FAILURE(rc2))
    826                     LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", pThis->pDevInsR3->iInstance, rc2));
    827             }
    828 #endif
    829         }
    830         else
    831         {
    832             /* Notify the lower driver about available data only if the register was empty before. */
    833             if (pThis->uRegLsr & UART_REG_LSR_THRE)
    834             {
    835 #ifndef IN_RING3
    836                 rc = VINF_IOM_R3_IOPORT_WRITE;
    837 #else
    838                 pThis->uRegThr = uVal;
    839                 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
    840                 pThis->fThreEmptyPending = false;
    841                 uartIrqUpdate(pThis);
    842                 if (pThis->pDrvSerial)
    843                 {
    844                     int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial);
    845                     if (RT_FAILURE(rc2))
    846                         LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", pThis->pDevInsR3->iInstance, rc2));
    847                 }
    848                 else
    849                     TMTimerSetRelative(pThis->CTX_SUFF(pTimerTxUnconnected), pThis->cSymbolXferTicks, NULL);
    850 #endif
    851             }
    852             else
    853                 pThis->uRegThr = uVal;
    854         }
    855     }
     878        rc = uartXmit(pThis, uVal);
    856879
    857880    return rc;
     
    14311454    PUARTCORE pThis = (PUARTCORE)pvUser;
    14321455    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    1433     uint8_t bIgnore = 0;
     1456    uint8_t bVal = 0;
    14341457    size_t cbRead = 0;
    1435     uartR3TxQueueCopyFrom(pThis, &bIgnore, sizeof(uint8_t), &cbRead);
     1458    uartR3TxQueueCopyFrom(pThis, &bVal, sizeof(bVal), &cbRead);
     1459    if (pThis->uRegMcr & UART_REG_MCR_LOOP)
     1460    {
     1461        /* Loopback mode is active, feed in the data at the receiving end. */
     1462        uint32_t cbAvailOld = ASMAtomicAddU32(&pThis->cbAvailRdr, 1);
     1463        if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
     1464        {
     1465            PUARTFIFO pFifo = &pThis->FifoRecv;
     1466            if (uartFifoFreeGet(pFifo) > 0)
     1467            {
     1468                pFifo->abBuf[pFifo->offWrite] = bVal;
     1469                pFifo->offWrite = (pFifo->offWrite + 1) % pFifo->cbMax;
     1470                pFifo->cbUsed++;
     1471
     1472                UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
     1473                if (pFifo->cbUsed < pFifo->cbItl)
     1474                {
     1475                    pThis->fIrqCtiPending = false;
     1476                    TMTimerSetRelative(pThis->CTX_SUFF(pTimerRcvFifoTimeout), pThis->cSymbolXferTicks * 4, NULL);
     1477                }
     1478                uartIrqUpdate(pThis);
     1479            }
     1480
     1481            ASMAtomicSubU32(&pThis->cbAvailRdr, 1);
     1482        }
     1483        else if (!cbAvailOld)
     1484        {
     1485            pThis->uRegRbr = bVal;
     1486            UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
     1487            uartIrqUpdate(pThis);
     1488        }
     1489    }
    14361490    if (cbRead == 1)
    14371491        TMTimerSetRelative(pThis->CTX_SUFF(pTimerTxUnconnected), pThis->cSymbolXferTicks, NULL);
  • trunk/src/VBox/Devices/Serial/UartCore.h

    r76565 r77411  
    148148    /** R3 timer pointer for the character timeout indication. */
    149149    PTMTIMERR3                      pTimerRcvFifoTimeoutR3;
    150     /** R3 timer pointer for the send loop if no driver is connected. */
     150    /** R3 timer pointer for the send loop if no driver is connected/loopback mode is active. */
    151151    PTMTIMERR3                      pTimerTxUnconnectedR3;
    152152    /** R3 interrupt request callback of the owning device. */
     
    154154    /** R0 timer pointer fo the character timeout indication. */
    155155    PTMTIMERR0                      pTimerRcvFifoTimeoutR0;
    156     /** R0 timer pointer for the send loop if no driver is connected. */
     156    /** R0 timer pointer for the send loop if no driver is connected/loopback mode is active. */
    157157    PTMTIMERR0                      pTimerTxUnconnectedR0;
    158158    /** R0 interrupt request callback of the owning device. */
     
    160160    /** RC timer pointer fo the character timeout indication. */
    161161    PTMTIMERRC                      pTimerRcvFifoTimeoutRC;
    162     /** RC timer pointer for the send loop if no driver is connected. */
     162    /** RC timer pointer for the send loop if no driver is connected/loopback mode is active. */
    163163    PTMTIMERRC                      pTimerTxUnconnectedRC;
    164164    /** RC interrupt request callback of the owning device. */
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