VirtualBox

Changeset 72083 in vbox for trunk/src/VBox


Ignore:
Timestamp:
May 2, 2018 6:04:29 PM (7 years ago)
Author:
vboxsync
Message:

Devices/Serial: Updates to the new emulation

File:
1 edited

Legend:

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

    r72078 r72083  
    165165# define UART_REG_MSR_RI                     RT_BIT(6)
    166166/** Data Carrier Detect. */
    167 # define UART_REG_MSSR_DCD                   RT_BIT(7)
     167# define UART_REG_MSR_DCD                    RT_BIT(7)
    168168
    169169/** The SCR register index (from the base of the port range). */
     
    243243#ifndef VBOX_DEVICE_STRUCT_TESTCASE
    244244
     245
     246/*********************************************************************************************************************************
     247*   Global Variables                                                                                                             *
     248*********************************************************************************************************************************/
     249#ifdef IN_RING3
     250/**
     251 * String versions of the parity enum.
     252 */
     253static const char *s_aszParity[] =
     254{
     255    "INVALID",
     256    "NONE",
     257    "EVEN",
     258    "ODD",
     259    "MARK",
     260    "SPACE",
     261    "INVALID"
     262};
     263
     264
     265/**
     266 * String versions of the stop bits enum.
     267 */
     268static const char *s_aszStopBits[] =
     269{
     270    "INVALID",
     271    "1",
     272    "1.5",
     273    "2",
     274    "INVALID"
     275};
     276#endif
     277
     278
     279/*********************************************************************************************************************************
     280*   Internal Functions                                                                                                           *
     281*********************************************************************************************************************************/
     282
     283
     284/**
     285 * Updates the IRQ state based on the current device state.
     286 *
     287 * @returns nothing.
     288 * @param   pThis               The serial port instance.
     289 */
     290static void serialIrqUpdate(PDEVSERIAL pThis)
     291{
     292    RT_NOREF(pThis);
     293}
     294
     295
     296#ifdef IN_RING3
     297/**
     298 * Updates the serial port parameters of the attached driver with the current configuration.
     299 *
     300 * @returns nothing.
     301 * @param   pThis               The serial port instance.
     302 */
     303static void serialParamsUpdate(PDEVSERIAL pThis)
     304{
     305    if (   pThis->uRegDivisor != 0
     306        && pThis->pDrvSerial)
     307    {
     308        uint32_t uBps = 115200 / pThis->uRegDivisor; /* This is for PC compatible serial port with a 1.8432 MHz crystal. */
     309        unsigned cDataBits = UART_REG_LCR_WLS_GET(pThis->uRegLcr) + 5;
     310        PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE;
     311        PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE;
     312
     313        if (pThis->uRegLcr & UART_REG_LCR_STB)
     314        {
     315            enmStopBits = cDataBits == 5 ? PDMSERIALSTOPBITS_ONEPOINTFIVE : PDMSERIALSTOPBITS_TWO;
     316        }
     317
     318        if (pThis->uRegLcr & UART_REG_LCR_PEN)
     319        {
     320            /* Select the correct parity mode based on the even and stick parity bits. */
     321            switch (pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK))
     322            {
     323                case 0:
     324                    enmParity = PDMSERIALPARITY_ODD;
     325                    break;
     326                case UART_REG_LCR_EPS:
     327                    enmParity = PDMSERIALPARITY_EVEN;
     328                    break;
     329                case UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK:
     330                    enmParity = PDMSERIALPARITY_SPACE;
     331                    break;
     332                case UART_REG_LCR_PAR_STICK:
     333                    enmParity = PDMSERIALPARITY_MARK;
     334                    break;
     335                default:
     336                    /* We should never get here as all cases where caught earlier. */
     337                    AssertMsgFailed(("This shouldn't happen at all: %#x\n",
     338                                     pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK)));
     339            }
     340        }
     341
     342        LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n",
     343                     uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits]));
     344
     345        int rc = pThis->pDrvSerial->pfnChgParams(pThis->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits);
     346        if (RT_FAILURE(rc))
     347            LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n",
     348                           pThis->pDevInsR3->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc));
     349    }
     350}
     351
     352
     353/**
     354 * Updates the internal device state with the given PDM status line states.
     355 *
     356 * @returns nothing.
     357 * @param   pThis               The serial port instance.
     358 * @param   fStsLines           The PDM status line states.
     359 */
     360static void serialStsLinesUpdate(PDEVSERIAL pThis, uint32_t fStsLines)
     361{
     362    uint8_t uRegMsrNew = 0; /* The new MSR value. */
     363
     364    if (fStsLines & PDMISERIALPORT_STS_LINE_DCD)
     365        uRegMsrNew |= UART_REG_MSR_DCD;
     366    if (fStsLines & PDMISERIALPORT_STS_LINE_RI)
     367        uRegMsrNew |= UART_REG_MSR_RI;
     368    if (fStsLines & PDMISERIALPORT_STS_LINE_DSR)
     369        uRegMsrNew |= UART_REG_MSR_DSR;
     370    if (fStsLines & PDMISERIALPORT_STS_LINE_CTS)
     371        uRegMsrNew |= UART_REG_MSR_CTS;
     372
     373    /* Compare current and new states and set remaining bits accordingly. */
     374    if ((uRegMsrNew & UART_REG_MSR_CTS) != (pThis->uRegMsr & UART_REG_MSR_CTS))
     375        uRegMsrNew |= UART_REG_MSR_DCTS;
     376    if ((uRegMsrNew & UART_REG_MSR_DSR) != (pThis->uRegMsr & UART_REG_MSR_DSR))
     377        uRegMsrNew |= UART_REG_MSR_DDSR;
     378    if ((uRegMsrNew & UART_REG_MSR_RI) != 0 && (pThis->uRegMsr & UART_REG_MSR_RI) == 0)
     379        uRegMsrNew |= UART_REG_MSR_TERI;
     380    if ((uRegMsrNew & UART_REG_MSR_DCD) != (pThis->uRegMsr & UART_REG_MSR_DCD))
     381        uRegMsrNew |= UART_REG_MSR_DDCD;
     382
     383    pThis->uRegMsr = uRegMsrNew;
     384
     385    serialIrqUpdate(pThis);
     386}
     387#endif
     388
     389
     390/**
     391 * Write handler for the THR/DLL register (depending on the DLAB bit in LCR).
     392 *
     393 * @returns VBox status code.
     394 * @param   pThis               The serial port instance.
     395 * @param   uVal                The value to write.
     396 */
     397DECLINLINE(int) serialRegThrDllWrite(PDEVSERIAL pThis, uint8_t uVal)
     398{
     399    int rc = VINF_SUCCESS;
     400
     401    /* A set DLAB causes a write to the lower 8bits of the divisor latch. */
     402    if (pThis->uRegLcr & UART_REG_LCR_DLAB)
     403    {
     404        if (uVal != (pThis->uRegDivisor & 0xff))
     405        {
     406#ifndef IN_RING3
     407            rc = VINF_IOM_R3_IOPORT_WRITE;
     408#else
     409            pThis->uRegDivisor = (pThis->uRegDivisor & 0xff00) | uVal;
     410            serialParamsUpdate(pThis);
     411#endif
     412        }
     413    }
     414    else
     415    {
     416        /** @todo Data transfer (depending on FIFO). */
     417    }
     418
     419    return rc;
     420}
     421
     422
     423/**
     424 * Write handler for the IER/DLM register (depending on the DLAB bit in LCR).
     425 *
     426 * @returns VBox status code.
     427 * @param   pThis               The serial port instance.
     428 * @param   uVal                The value to write.
     429 */
     430DECLINLINE(int) serialRegIerDlmWrite(PDEVSERIAL pThis, uint8_t uVal)
     431{
     432    int rc = VINF_SUCCESS;
     433
     434    /* A set DLAB causes a write to the higher 8bits of the divisor latch. */
     435    if (pThis->uRegLcr & UART_REG_LCR_DLAB)
     436    {
     437        if (uVal != (pThis->uRegDivisor & 0xff00) >> 8)
     438        {
     439#ifndef IN_RING3
     440            rc = VINF_IOM_R3_IOPORT_WRITE;
     441#else
     442            pThis->uRegDivisor = (pThis->uRegDivisor & 0xff) | (uVal << 8);
     443            serialParamsUpdate(pThis);
     444#endif
     445        }
     446    }
     447    else
     448    {
     449        pThis->uRegIer = uVal & UART_REG_IER_MASK_WR;
     450        serialIrqUpdate(pThis);
     451    }
     452
     453    return rc;
     454}
     455
     456
     457/**
     458 * Write handler for the FCR register.
     459 *
     460 * @returns VBox status code.
     461 * @param   pThis               The serial port instance.
     462 * @param   uVal                The value to write.
     463 */
     464DECLINLINE(int) serialRegFcrWrite(PDEVSERIAL pThis, uint8_t uVal)
     465{
     466    int rc = VINF_SUCCESS;
     467
     468    RT_NOREF(uVal);
     469    if (pThis->f16550AEnabled)
     470    {
     471        /** @todo */
     472    }
     473
     474    return rc;
     475}
     476
     477
     478/**
     479 * Write handler for the LCR register.
     480 *
     481 * @returns VBox status code.
     482 * @param   pThis               The serial port instance.
     483 * @param   uVal                The value to write.
     484 */
     485DECLINLINE(int) serialRegLcrWrite(PDEVSERIAL pThis, uint8_t uVal)
     486{
     487    int rc = VINF_SUCCESS;
     488
     489    /* Any change except the DLAB bit causes a switch to R3. */
     490    if ((pThis->uRegLcr & ~UART_REG_LCR_DLAB) != (uVal & ~UART_REG_LCR_DLAB))
     491    {
     492#ifndef IN_RING3
     493        rc = VINF_IOM_R3_IOPORT_WRITE;
     494#else
     495        /* Check whether the BREAK bit changed before updating the LCR value. */
     496        bool fBrkEn = RT_BOOL(uVal & UART_REG_LCR_BRK_SET);
     497        bool fBrkChg = fBrkEn != RT_BOOL(pThis->uRegLcr & UART_REG_LCR_BRK_SET);
     498        pThis->uRegLcr = uVal;
     499        serialParamsUpdate(pThis);
     500
     501        if (   fBrkChg
     502            && pThis->pDrvSerial)
     503            pThis->pDrvSerial->pfnChgBrk(pThis->pDrvSerial, fBrkEn);
     504#endif
     505    }
     506    else
     507        pThis->uRegLcr = uVal;
     508
     509    return rc;
     510}
     511
     512
     513/**
     514 * Write handler for the MCR register.
     515 *
     516 * @returns VBox status code.
     517 * @param   pThis               The serial port instance.
     518 * @param   uVal                The value to write.
     519 */
     520DECLINLINE(int) serialRegMcrWrite(PDEVSERIAL pThis, uint8_t uVal)
     521{
     522    int rc = VINF_SUCCESS;
     523
     524    uVal &= UART_REG_MCR_MASK_WR;
     525    if (pThis->uRegMcr != uVal)
     526    {
     527#ifndef IN_RING3
     528        rc = VINF_IOM_R3_IOPORT_WRITE;
     529#else
     530        /** @todo Loopback mode handling (setting RTS, DTR to high looping everything to MSR). */
     531        pThis->uRegMcr = uVal;
     532        if (pThis->pDrvSerial)
     533            pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial,
     534                                                RT_BOOL(uVal & UART_REG_MCR_RTS),
     535                                                RT_BOOL(uVal & UART_REG_MCR_DTR));
     536#endif
     537    }
     538
     539    return rc;
     540}
     541
     542
     543/**
     544 * Read handler for the RBR/DLL register (depending on the DLAB bit in LCR).
     545 *
     546 * @returns VBox status code.
     547 * @param   pThis               The serial port instance.
     548 * @param   puVal               Where to store the read value on success.
     549 */
     550DECLINLINE(int) serialRegRbrDllRead(PDEVSERIAL pThis, uint32_t *puVal)
     551{
     552    int rc = VINF_SUCCESS;
     553
     554    /* A set DLAB causes a read from the lower 8bits of the divisor latch. */
     555    if (pThis->uRegLcr & UART_REG_LCR_DLAB)
     556        *puVal = pThis->uRegDivisor & 0xff;
     557    else
     558    {
     559        /** @todo Data transfer (depending on FIFO). */
     560    }
     561
     562    return rc;
     563}
     564
     565
     566/**
     567 * Read handler for the IER/DLM register (depending on the DLAB bit in LCR).
     568 *
     569 * @returns VBox status code.
     570 * @param   pThis               The serial port instance.
     571 * @param   puVal               Where to store the read value on success.
     572 */
     573DECLINLINE(int) serialRegIerDlmRead(PDEVSERIAL pThis, uint32_t *puVal)
     574{
     575    int rc = VINF_SUCCESS;
     576
     577    /* A set DLAB causes a read from the upper 8bits of the divisor latch. */
     578    if (pThis->uRegLcr & UART_REG_LCR_DLAB)
     579        *puVal = (pThis->uRegDivisor & 0xff00) >> 8;
     580    else
     581        *puVal = pThis->uRegIer;
     582
     583    return rc;
     584}
     585
     586
     587/**
     588 * Read handler for the IIR register.
     589 *
     590 * @returns VBox status code.
     591 * @param   pThis               The serial port instance.
     592 * @param   puVal               Where to store the read value on success.
     593 */
     594DECLINLINE(int) serialRegIirRead(PDEVSERIAL pThis, uint32_t *puVal)
     595{
     596    int rc = VINF_SUCCESS;
     597
     598    RT_NOREF(pThis, puVal);
     599
     600    return rc;
     601}
     602
     603
     604/**
     605 * Read handler for the LSR register.
     606 *
     607 * @returns VBox status code.
     608 * @param   pThis               The serial port instance.
     609 * @param   puVal               Where to store the read value on success.
     610 */
     611DECLINLINE(int) serialRegLsrRead(PDEVSERIAL pThis, uint32_t *puVal)
     612{
     613    int rc = VINF_SUCCESS;
     614
     615    RT_NOREF(pThis, puVal);
     616
     617    return rc;
     618}
     619
     620
     621/**
     622 * Read handler for the MSR register.
     623 *
     624 * @returns VBox status code.
     625 * @param   pThis               The serial port instance.
     626 * @param   puVal               Where to store the read value on success.
     627 */
     628DECLINLINE(int) serialRegMsrRead(PDEVSERIAL pThis, uint32_t *puVal)
     629{
     630    int rc = VINF_SUCCESS;
     631
     632    RT_NOREF(pThis, puVal);
     633
     634    return rc;
     635}
     636
     637
    245638/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
    246639
     
    257650
    258651    int rc = VINF_SUCCESS;
     652    uint8_t uVal = (uint8_t)u32;
    259653    switch (uPort & 0x7)
    260654    {
    261655        case UART_REG_THR_DLL_INDEX:
     656            rc = serialRegThrDllWrite(pThis, uVal);
    262657            break;
    263658        case UART_REG_IER_DLM_INDEX:
     659            rc = serialRegIerDlmWrite(pThis, uVal);
    264660            break;
    265661        case UART_REG_FCR_INDEX:
     662            rc = serialRegFcrWrite(pThis, uVal);
    266663            break;
    267664        case UART_REG_LCR_INDEX:
     665            rc = serialRegLcrWrite(pThis, uVal);
    268666            break;
    269667        case UART_REG_MCR_INDEX:
     668            rc = serialRegMcrWrite(pThis, uVal);
    270669            break;
    271670        case UART_REG_SCR_INDEX:
     
    296695    {
    297696        case UART_REG_RBR_DLL_INDEX:
     697            rc = serialRegRbrDllRead(pThis, pu32);
    298698            break;
    299699        case UART_REG_IER_DLM_INDEX:
     700            rc = serialRegIerDlmRead(pThis, pu32);
    300701            break;
    301702        case UART_REG_IIR_INDEX:
     703            rc = serialRegIirRead(pThis, pu32);
    302704            break;
    303705        case UART_REG_LCR_INDEX:
     706            *pu32 = pThis->uRegLcr;
    304707            break;
    305708        case UART_REG_MCR_INDEX:
     709            *pu32 = pThis->uRegMcr;
    306710            break;
    307711        case UART_REG_LSR_INDEX:
     712            rc = serialRegLsrRead(pThis, pu32);
    308713            break;
    309714        case UART_REG_MSR_INDEX:
     715            rc = serialRegMsrRead(pThis, pu32);
    310716            break;
    311717        case UART_REG_SCR_INDEX:
     
    350756
    351757    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    352     /** @todo */
    353     RT_NOREF(fNewStatusLines);
     758    serialStsLinesUpdate(pThis, fNewStatusLines);
    354759    PDMCritSectLeave(&pThis->CritSect);
    355     return VERR_NOT_IMPLEMENTED;
     760    return VINF_SUCCESS;
    356761}
    357762
     
    401806{
    402807    PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    403     RT_NOREF(pThis);
     808
     809    pThis->uRegDivisor = 0x0c; /* Default to 9600 Baud. */
     810    pThis->uRegRbr     = 0;
     811    pThis->uRegThr     = 0;
     812    pThis->uRegIer     = 0;
     813    pThis->uRegIir     = UART_REG_IIR_IP_NO_INT;
     814    pThis->uRegFcr     = 0;
     815    pThis->uRegLcr     = 0; /* 5 data bits, no parity, 1 stop bit. */
     816    pThis->uRegMcr     = 0;
     817    pThis->uRegLsr     = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
     818    pThis->uRegMsr     = 0; /* Updated below. */
     819    pThis->uRegScr     = 0;
     820
     821    /** @todo Clear FIFOs. */
     822    serialParamsUpdate(pThis);
     823    serialIrqUpdate(pThis);
     824
     825    if (pThis->pDrvSerial)
     826    {
     827        uint32_t fStsLines = 0;
     828        int rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
     829        if (RT_SUCCESS(rc))
     830            serialStsLinesUpdate(pThis, fStsLines);
     831        else
     832            LogRel(("Serial#%d: Failed to query status line status with %Rrc during reset\n",
     833                    pThis->pDevInsR3->iInstance, rc));
     834    }
    404835}
    405836
     
    428859        pThis->pDrvSerial = NULL;
    429860        rc = VINF_SUCCESS;
    430         LogRel(("Serial%d: no unit\n", pDevIns->iInstance));
     861        LogRel(("Serial#%d: no unit\n", pDevIns->iInstance));
    431862    }
    432863    else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
    433         LogRel(("Serial%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
     864        LogRel(("Serial#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
    434865
    435866   return rc;
     
    547978            uIoBase = 0x2f8;
    548979        else
    549             AssertReleaseFailed(); /* io_base is undefined */
     980            AssertReleaseFailed(); /* uIoBase is undefined */
    550981    }
    551982    else if (RT_FAILURE(rc))
     
    5731004     *       calling back into the device.
    5741005     */
    575     rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%u", iInstance);
     1006    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
    5761007    AssertRCReturn(rc, rc);
    5771008
     
    6311062        pThis->pDrvBase   = NULL;
    6321063        pThis->pDrvSerial = NULL;
    633         LogRel(("Serial%d: no unit\n", iInstance));
     1064        LogRel(("Serial#%d: no unit\n", iInstance));
    6341065    }
    6351066    else
    6361067    {
    637         AssertLogRelMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
     1068        AssertLogRelMsgFailed(("Serial#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
    6381069        /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
    6391070        return rc;
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