VirtualBox

Changeset 72118 in vbox for trunk/src/VBox


Ignore:
Timestamp:
May 4, 2018 4:44:34 PM (7 years ago)
Author:
vboxsync
Message:

Serial/DevSerialNew.cpp: Updates, sending data seems to work

File:
1 edited

Legend:

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

    r72083 r72118  
    6767/** Receiver Line Status interrupt. */
    6868#  define UART_REG_IIR_ID_RCL                0x3
    69 /** Received Data Avalable interrupt. */
     69/** Received Data Available interrupt. */
    7070#  define UART_REG_IIR_ID_RDA                0x2
    7171/** Character Timeou Indicator interrupt. */
     
    7777/** FIFOs enabled. */
    7878# define UART_REG_IIR_FIFOS_EN               0xc0
     79/** Bits relevant for checking whether the interrupt status has changed. */
     80# define UART_REG_IIR_CHANGED_MASK           0x0f
    7981
    8082/** The FCR register index (from the base of the port range). */
     
    147149/** Error in receiver FIFO. */
    148150# define UART_REG_LSR_RCV_FIFO_ERR           RT_BIT(7)
     151/** The bits to check in this register when checking for the RCL interrupt. */
     152# define UART_REG_LSR_BITS_IIR_RCL           0x1e
    149153
    150154/** The MSR register index (from the base of the port range). */
     
    166170/** Data Carrier Detect. */
    167171# define UART_REG_MSR_DCD                    RT_BIT(7)
     172/** The bits to check in this register when checking for the MS interrupt. */
     173# define UART_REG_MSR_BITS_IIR_MS            0x0f
    168174
    169175/** The SCR register index (from the base of the port range). */
    170176#define UART_REG_SCR_INDEX                   7
     177
     178/** Set the specified bits in the given register. */
     179#define UART_REG_SET(a_Reg, a_Set)           ((a_Reg) |= (a_Set))
     180/** Clear the specified bits in the given register. */
     181#define UART_REG_CLR(a_Reg, a_Clr)           ((a_Reg) &= ~(a_Clr))
    171182
    172183
     
    237248    uint8_t                         uRegScr;
    238249
     250    /** Number of bytes available for reading from the layer below. */
     251    volatile uint32_t               cbAvailRdr;
     252
    239253} DEVSERIAL;
    240254/** Pointer to the serial device state. */
     
    290304static void serialIrqUpdate(PDEVSERIAL pThis)
    291305{
    292     RT_NOREF(pThis);
     306    /*
     307     * The interrupt uses a priority scheme, only the interrupt with the
     308     * highest priority is indicated in the interrupt identification register.
     309     *
     310     * The priorities are as follows (high to low):
     311     *      * Receiver line status
     312     *      * Received data available
     313     *      * Character timeout indication (only in FIFO mode).
     314     *      * Transmitter holding register empty
     315     *      * Modem status change.
     316     */
     317    uint8_t uRegIirNew = UART_REG_IIR_IP_NO_INT;
     318    if (   (pThis->uRegLsr & UART_REG_LSR_BITS_IIR_RCL)
     319        && (pThis->uRegIer & UART_REG_IER_ELSI))
     320        uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_RCL);
     321    else if (   (pThis->uRegLsr & UART_REG_LSR_DR)
     322             && (pThis->uRegIer & UART_REG_IER_ERBFI))
     323        uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_RDA);
     324    else if (   (pThis->uRegLsr & UART_REG_LSR_THRE)
     325             && (pThis->uRegIer & UART_REG_IER_ETBEI))
     326        uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_THRE);
     327    else if (   (pThis->uRegMsr & UART_REG_MSR_BITS_IIR_MS)
     328             && (pThis->uRegIer & UART_REG_IER_EDSSI))
     329        uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_MSR_BITS_IIR_MS);
     330
     331    /** @todo Character timeout indication for FIFO mode. */
     332
     333    LogFlowFunc(("uRegIirNew=%#x uRegIir=%#x\n", uRegIirNew, pThis->uRegIir));
     334
     335    /* Change interrupt only if the interrupt status really changed from the previous value. */
     336    if (uRegIirNew != (pThis->uRegIir & UART_REG_IIR_CHANGED_MASK))
     337    {
     338        if (uRegIirNew == UART_REG_IIR_IP_NO_INT)
     339            PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->uIrq, 0);
     340        else
     341            PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->uIrq, 1);
     342    }
     343
     344    if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
     345        uRegIirNew |= UART_REG_IIR_FIFOS_EN;
     346
     347    pThis->uRegIir = uRegIirNew;
    293348}
    294349
     
    301356 * @param   pThis               The serial port instance.
    302357 */
    303 static void serialParamsUpdate(PDEVSERIAL pThis)
     358static void serialR3ParamsUpdate(PDEVSERIAL pThis)
    304359{
    305360    if (   pThis->uRegDivisor != 0
     
    358413 * @param   fStsLines           The PDM status line states.
    359414 */
    360 static void serialStsLinesUpdate(PDEVSERIAL pThis, uint32_t fStsLines)
     415static void serialR3StsLinesUpdate(PDEVSERIAL pThis, uint32_t fStsLines)
    361416{
    362417    uint8_t uRegMsrNew = 0; /* The new MSR value. */
     
    408463#else
    409464            pThis->uRegDivisor = (pThis->uRegDivisor & 0xff00) | uVal;
    410             serialParamsUpdate(pThis);
     465            serialR3ParamsUpdate(pThis);
    411466#endif
    412467        }
     
    414469    else
    415470    {
    416         /** @todo Data transfer (depending on FIFO). */
     471        if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
     472        {
     473            /** @todo FIFO handling. */
     474        }
     475        else
     476        {
     477            /* Notify the lower driver about available data only if the register was empty before. */
     478            if (pThis->uRegLsr & UART_REG_LSR_THRE)
     479            {
     480#ifndef IN_RING3
     481                rc = VINF_IOM_R3_IOPORT_WRITE;
     482#else
     483                pThis->uRegThr = uVal;
     484                UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE);
     485                if (pThis->pDrvSerial)
     486                {
     487                    int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial, 1);
     488                    if (RT_FAILURE(rc2))
     489                        LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", rc2));
     490                }
     491#endif
     492            }
     493            else
     494                pThis->uRegThr = uVal;
     495        }
    417496    }
    418497
     
    441520#else
    442521            pThis->uRegDivisor = (pThis->uRegDivisor & 0xff) | (uVal << 8);
    443             serialParamsUpdate(pThis);
     522            serialR3ParamsUpdate(pThis);
    444523#endif
    445524        }
     
    497576        bool fBrkChg = fBrkEn != RT_BOOL(pThis->uRegLcr & UART_REG_LCR_BRK_SET);
    498577        pThis->uRegLcr = uVal;
    499         serialParamsUpdate(pThis);
     578        serialR3ParamsUpdate(pThis);
    500579
    501580        if (   fBrkChg
     
    557636    else
    558637    {
    559         /** @todo Data transfer (depending on FIFO). */
     638        *puVal = pThis->uRegRbr;
     639
     640        if (pThis->uRegLsr & UART_REG_LSR_DR)
     641        {
     642            uint32_t cbAvail = ASMAtomicDecU32(&pThis->cbAvailRdr);
     643            if (!cbAvail)
     644            {
     645                UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
     646                serialIrqUpdate(pThis);
     647            }
     648            else
     649            {
     650#ifndef IN_RING3
     651                /* Restore state and go back to R3. */
     652                ASMAtomicIncU32(&pThis->cbAvailRdr);
     653                rc = VINF_IOM_R3_IOPORT_READ;
     654#else
     655                /* Fetch new data and keep the DR bit set. */
     656                AssertPtr(pThis->pDrvSerial);
     657                size_t cbRead = 0;
     658                int rc2 = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pThis->uRegRbr, 1, &cbRead);
     659                AssertMsg(RT_SUCCESS(rc2) && cbRead == 1, ("This shouldn't fail and always return one byte!\n"));
     660                serialIrqUpdate(pThis);
     661#endif
     662            }
     663        }
    560664    }
    561665
     
    594698DECLINLINE(int) serialRegIirRead(PDEVSERIAL pThis, uint32_t *puVal)
    595699{
    596     int rc = VINF_SUCCESS;
    597 
    598     RT_NOREF(pThis, puVal);
    599 
    600     return rc;
     700    *puVal = pThis->uRegIir;
     701    return VINF_SUCCESS;
    601702}
    602703
     
    613714    int rc = VINF_SUCCESS;
    614715
    615     RT_NOREF(pThis, puVal);
     716    /* Yield if configured and there is no data available. */
     717    if (   !(pThis->uRegLsr & UART_REG_LSR_DR)
     718        && pThis->fYieldOnLSRRead)
     719    {
     720#ifndef IN_RING3
     721        return VINF_IOM_R3_IOPORT_READ;
     722#else
     723        RTThreadYield();
     724#endif
     725    }
     726
     727    *puVal = pThis->uRegLsr;
     728    /*
     729     * Reading this register clears the Overrun (OE), Parity (PE) and Framing (FE) error
     730     * as well as the Break Interrupt (BI).
     731     */
     732    UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_BITS_IIR_RCL);
     733    serialIrqUpdate(pThis);
    616734
    617735    return rc;
     
    628746DECLINLINE(int) serialRegMsrRead(PDEVSERIAL pThis, uint32_t *puVal)
    629747{
    630     int rc = VINF_SUCCESS;
    631 
    632     RT_NOREF(pThis, puVal);
    633 
    634     return rc;
     748    *puVal = pThis->uRegMsr;
     749
     750    /** @todo Loopback handling. */
     751    /* Clear any of the delta bits. */
     752    UART_REG_CLR(pThis->uRegMsr, UART_REG_MSR_BITS_IIR_MS);
     753    serialIrqUpdate(pThis);
     754    return VINF_SUCCESS;
    635755}
    636756
     
    647767    RT_NOREF_PV(pvUser);
    648768
     769    LogFlowFunc(("pDevIns=%#p pvUser=%#p uPort=%RTiop u32=%#x cb=%u\n",
     770                 pDevIns, pvUser, uPort, u32, cb));
     771
    649772    AssertMsgReturn(cb == 1, ("uPort=%#x cb=%d u32=%#x\n", uPort, cb, u32), VINF_SUCCESS);
    650773
     
    675798    }
    676799
     800    LogFlowFunc(("-> %Rrc\n", rc));
    677801    return rc;
    678802}
     
    722846    }
    723847
     848    LogFlowFunc(("pDevIns=%#p pvUser=%#p uPort=%RTiop u32=%#x cb=%u -> %Rrc\n",
     849                 pDevIns, pvUser, uPort, *pu32, cb, rc));
    724850    return rc;
    725851}
     
    730856/* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
    731857
    732 static DECLCALLBACK(int) serialDataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
     858
     859/**
     860 * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
     861 */
     862static DECLCALLBACK(int) serialR3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
    733863{
    734864    PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    735865
     866    AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
     867
     868    uint32_t cbAvailOld = ASMAtomicAddU32(&pThis->cbAvailRdr, (uint32_t)cbAvail);
     869    if (!cbAvailOld)
     870    {
     871        PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
     872        size_t cbRead = 0;
     873        int rc = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pThis->uRegRbr, 1, &cbRead);
     874        AssertMsg(RT_SUCCESS(rc) && cbRead == 1, ("This shouldn't fail and always return one byte!\n"));
     875        UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
     876        serialIrqUpdate(pThis);
     877        PDMCritSectLeave(&pThis->CritSect);
     878    }
     879    return VINF_SUCCESS;
     880}
     881
     882
     883/**
     884 * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
     885 */
     886static DECLCALLBACK(int) serialR3DataSentNotify(PPDMISERIALPORT pInterface)
     887{
     888    PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
     889
     890    /* Set the transmitter empty bit because everything was sent. */
    736891    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    737     RT_NOREF(cbAvail);
    738     PDMCritSectLeave(&pThis->CritSect);
    739     return VERR_NOT_IMPLEMENTED;
    740 }
    741 
    742 static DECLCALLBACK(int) serialReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
    743 {
    744     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    745 
    746     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    747     /** @todo */
    748     RT_NOREF(pvBuf, cbRead, pcbRead);
    749     PDMCritSectLeave(&pThis->CritSect);
    750     return VERR_NOT_IMPLEMENTED;
    751 }
    752 
    753 static DECLCALLBACK(int) serialNotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
    754 {
    755     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    756 
    757     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    758     serialStsLinesUpdate(pThis, fNewStatusLines);
     892    UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_TEMT);
     893    serialIrqUpdate(pThis);
    759894    PDMCritSectLeave(&pThis->CritSect);
    760895    return VINF_SUCCESS;
    761896}
    762897
    763 static DECLCALLBACK(int) serialNotifyBrk(PPDMISERIALPORT pInterface)
     898
     899/**
     900 * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
     901 */
     902static DECLCALLBACK(int) serialR3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
    764903{
    765904    PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    766905
     906    AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
     907
    767908    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    768     /** @todo */
     909    if (!(pThis->uRegLsr & UART_REG_LSR_THRE))
     910    {
     911        /** @todo FIFO mode. */
     912        *(uint8_t *)pvBuf = pThis->uRegThr;
     913        *pcbRead = 1;
     914        UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_THRE);
     915        UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_TEMT);
     916        serialIrqUpdate(pThis);
     917    }
     918    else
     919    {
     920        AssertMsgFailed(("There is no data to read!\n"));
     921        *pcbRead = 0;
     922    }
     923
    769924    PDMCritSectLeave(&pThis->CritSect);
    770     return VERR_NOT_IMPLEMENTED;
     925    return VINF_SUCCESS;
     926}
     927
     928
     929/**
     930 * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
     931 */
     932static DECLCALLBACK(int) serialR3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
     933{
     934    PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
     935
     936    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
     937    serialR3StsLinesUpdate(pThis, fNewStatusLines);
     938    PDMCritSectLeave(&pThis->CritSect);
     939    return VINF_SUCCESS;
     940}
     941
     942
     943/**
     944 * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
     945 */
     946static DECLCALLBACK(int) serialR3NotifyBrk(PPDMISERIALPORT pInterface)
     947{
     948    PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
     949
     950    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
     951    UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_BI);
     952    serialIrqUpdate(pThis);
     953    PDMCritSectLeave(&pThis->CritSect);
     954    return VINF_SUCCESS;
    771955}
    772956
     
    8201004
    8211005    /** @todo Clear FIFOs. */
    822     serialParamsUpdate(pThis);
     1006    serialR3ParamsUpdate(pThis);
    8231007    serialIrqUpdate(pThis);
    8241008
    8251009    if (pThis->pDrvSerial)
    8261010    {
     1011        /* Set the modem lines to reflect the current state. */
     1012        int rc = pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial, false /*fRts*/, false /*fDtr*/);
     1013        if (RT_FAILURE(rc))
     1014            LogRel(("Serial#%d: Failed to set modem lines with %Rrc during reset\n",
     1015                    pThis->pDevInsR3->iInstance, rc));
     1016
    8271017        uint32_t fStsLines = 0;
    828         int rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
     1018        rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
    8291019        if (RT_SUCCESS(rc))
    830             serialStsLinesUpdate(pThis, fStsLines);
     1020            serialR3StsLinesUpdate(pThis, fStsLines);
    8311021        else
    8321022            LogRel(("Serial#%d: Failed to query status line status with %Rrc during reset\n",
     
    9181108
    9191109    /* ISerialPort */
    920     pThis->ISerialPort.pfnDataAvailRdrNotify    = serialDataAvailRdrNotify;
    921     pThis->ISerialPort.pfnReadWr                = serialReadWr;
    922     pThis->ISerialPort.pfnNotifyStsLinesChanged = serialNotifyStsLinesChanged;
    923     pThis->ISerialPort.pfnNotifyBrk             = serialNotifyBrk;
     1110    pThis->ISerialPort.pfnDataAvailRdrNotify    = serialR3DataAvailRdrNotify;
     1111    pThis->ISerialPort.pfnDataSentNotify        = serialR3DataSentNotify;
     1112    pThis->ISerialPort.pfnReadWr                = serialR3ReadWr;
     1113    pThis->ISerialPort.pfnNotifyStsLinesChanged = serialR3NotifyStsLinesChanged;
     1114    pThis->ISerialPort.pfnNotifyBrk             = serialR3NotifyBrk;
    9241115
    9251116    /*
     
    9841175                                N_("Configuration error: Failed to get the \"IOBase\" value"));
    9851176
    986     rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
     1177    rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, false);
    9871178    if (RT_FAILURE(rc))
    9881179        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    10711262    }
    10721263
     1264    serialR3Reset(pDevIns);
    10731265    return VINF_SUCCESS;
    10741266}
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