VirtualBox

Changeset 34212 in vbox


Ignore:
Timestamp:
Nov 19, 2010 5:14:39 PM (14 years ago)
Author:
vboxsync
Message:

Serial/Linux Host: fix status line notification (ticket #812, thanks Lawrence Rust)

File:
1 edited

Legend:

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

    r33755 r34212  
    370370    tcsetattr(pThis->DeviceFile, TCSANOW, termiosSetup);
    371371    RTMemTmpFree(termiosSetup);
     372
     373#ifdef RT_OS_LINUX
     374    /*
     375     * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
     376     * waiting in ioctl for a modem status change then 8250.c wrongly disables
     377     * modem irqs and so the monitor thread never gets released. The workaround
     378     * is to send a signal after each tcsetattr.
     379     */
     380    LogRel(("POKE\n"));
     381    RTThreadPoke(pThis->pMonitorThread->Thread);
     382#endif
     383
    372384#elif defined(RT_OS_WINDOWS)
    373385    comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB));
     
    914926    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
    915927    int rc = VINF_SUCCESS;
    916     unsigned uStatusLinesToCheck = 0;
    917 
    918     uStatusLinesToCheck = TIOCM_CAR | TIOCM_RNG | TIOCM_LE | TIOCM_CTS;
     928    unsigned long const uStatusLinesToCheck = TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
    919929
    920930    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    921931        return VINF_SUCCESS;
    922932
    923     while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    924     {
    925         uint32_t newStatusLine = 0;
     933    do
     934    {
    926935        unsigned int statusLines;
    927 
    928 # ifdef RT_OS_LINUX
     936       
    929937        /*
    930          * Wait for status line change.
    931          */
    932         rc = ioctl(pThis->DeviceFile, TIOCMIWAIT, uStatusLinesToCheck);
    933         if (pThread->enmState != PDMTHREADSTATE_RUNNING)
    934             break;
    935         if (rc < 0)
    936         {
    937 ioctl_error:
    938             PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
    939                                        N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"),
    940                                        pThis->pszDevicePath, RTErrConvertFromErrno(errno));
    941             break;
    942         }
    943 
    944         rc = ioctl(pThis->DeviceFile, TIOCMGET, &statusLines);
    945         if (rc < 0)
    946             goto ioctl_error;
    947 # else  /* !RT_OS_LINUX */
    948         /*
    949          * Poll for the status line change.
     938         * Get the status line state.
    950939         */
    951940        rc = ioctl(pThis->DeviceFile, TIOCMGET, &statusLines);
     
    957946            break;
    958947        }
    959         if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
    960         {
    961             PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
    962             continue;
    963         }
    964         pThis->fStatusLines = statusLines;
    965 # endif /* !RT_OS_LINUX */
     948
     949        uint32_t newStatusLine = 0;
    966950
    967951        if (statusLines & TIOCM_CAR)
     
    969953        if (statusLines & TIOCM_RNG)
    970954            newStatusLine |= PDMICHARPORT_STATUS_LINES_RI;
    971         if (statusLines & TIOCM_LE)
     955        if (statusLines & TIOCM_DSR)
    972956            newStatusLine |= PDMICHARPORT_STATUS_LINES_DSR;
    973957        if (statusLines & TIOCM_CTS)
    974958            newStatusLine |= PDMICHARPORT_STATUS_LINES_CTS;
    975         rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, newStatusLine);
    976     }
     959        LogRel(("new status line state %x\n", newStatusLine));
     960        pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, newStatusLine);
     961
     962        if (PDMTHREADSTATE_RUNNING != pThread->enmState)
     963            break;
     964
     965# ifdef RT_OS_LINUX
     966        /*
     967         * Wait for status line change.
     968         *
     969         * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
     970         * waiting in ioctl for a modem status change then 8250.c wrongly disables
     971         * modem irqs and so the monitor thread never gets released. The workaround
     972         * is to send a signal after each tcsetattr.
     973         */
     974        ioctl(pThis->DeviceFile, TIOCMIWAIT, uStatusLinesToCheck);
     975        LogRel(("status line change\n"));
     976# else
     977        /* Poll for status line change. */
     978        if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
     979            PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
     980        pThis->fStatusLines = statusLines;
     981# endif
     982    }
     983    while (PDMTHREADSTATE_RUNNING == pThread->enmState);
    977984
    978985    return VINF_SUCCESS;
     
    9931000    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
    9941001    int rc = VINF_SUCCESS;
    995 #  if 0
    996      unsigned int uSerialLineFlags;
    997      unsigned int uSerialLineStatus;
    998      unsigned int uIoctl;
    999 #  endif
    1000 
    1001     /*
    1002      * Linux is a bit difficult as the thread is sleeping in an ioctl call.
    1003      * So there is no way to have a wakeup pipe.
    1004      *
    1005      * 1. That's why we set the serial device into loopback mode and change one of the
    1006      *    modem control bits.
    1007      *    This should make the ioctl call return.
    1008      *
    1009      * 2. We still got reports about long shutdown times. It may be possible
    1010      *    that the loopback mode is not implemented on all devices.
    1011      *    The next possible solution is to close the device file to make the ioctl
    1012      *    return with EBADF and be able to suspend the thread.
    1013      *
    1014      * 3. The second approach doesn't work too, the ioctl doesn't return.
    1015      *    But it seems that the ioctl is interruptible (return code in errno is EINTR).
    1016      */
    1017 
    1018 #  if 0 /* Disabled because it does not work for all. */
    1019     /* Get current status of control lines. */
    1020     rc = ioctl(pThis->DeviceFile, TIOCMGET, &uSerialLineStatus);
    1021     if (rc < 0)
    1022         goto ioctl_error;
    1023 
    1024     uSerialLineFlags = TIOCM_LOOP;
    1025     rc = ioctl(pThis->DeviceFile, TIOCMBIS, &uSerialLineFlags);
    1026     if (rc < 0)
    1027         goto ioctl_error;
    1028 
    1029     /*
    1030      * Change current level on the RTS pin to make the ioctl call return in the
    1031      * monitor thread.
    1032      */
    1033     uIoctl = (uSerialLineStatus & TIOCM_CTS) ? TIOCMBIC : TIOCMBIS;
    1034     uSerialLineFlags = TIOCM_RTS;
    1035 
    1036     rc = ioctl(pThis->DeviceFile, uIoctl, &uSerialLineFlags);
    1037     if (rc < 0)
    1038         goto ioctl_error;
    1039 
    1040     /* Change RTS back to the previous level. */
    1041     uIoctl = (uIoctl == TIOCMBIC) ? TIOCMBIS : TIOCMBIC;
    1042 
    1043     rc = ioctl(pThis->DeviceFile, uIoctl, &uSerialLineFlags);
    1044     if (rc < 0)
    1045         goto ioctl_error;
    1046 
    1047     /*
    1048      * Set serial device into normal state.
    1049      */
    1050     uSerialLineFlags = TIOCM_LOOP;
    1051     rc = ioctl(pThis->DeviceFile, TIOCMBIC, &uSerialLineFlags);
    1052     if (rc >= 0)
    1053         return VINF_SUCCESS;
    1054 
    1055 ioctl_error:
    1056     PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
    1057                                 N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"),
    1058                                 pThis->pszDevicePath, RTErrConvertFromErrno(errno));
    1059 #  endif
    1060 
    1061 #  if 0
    1062     /* Close file to make ioctl return. */
    1063     RTFileClose(pData->DeviceFile);
    1064     /* Open again to make use after suspend possible again. */
    1065     rc = RTFileOpen(&pData->DeviceFile, pData->pszDevicePath, RTFILE_O_OPEN | RTFILE_O_READWRITE);
    1066     AssertMsgRC(rc, ("Opening device file again failed rc=%Rrc\n", rc));
    1067 
    1068     if (RT_FAILURE(rc))
    1069         PDMDrvHlpVMSetRuntimeError(pDrvIns, false, "DrvHostSerialFail",
    1070                                     N_("Opening failed for serial host device '%s' (%Rrc). The device will not work"),
    1071                                     pData->pszDevicePath, rc);
    1072 #  endif
    10731002
    10741003    rc = RTThreadPoke(pThread->Thread);
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