VirtualBox

Changeset 76724 in vbox for trunk/src


Ignore:
Timestamp:
Jan 9, 2019 9:38:28 AM (6 years ago)
Author:
vboxsync
Message:

USB/Linux: Reinstated real device resets, dropped old unused code. (See bugref:9339).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp

    r76553 r76724  
    2020*   Defined Constants And Macros                                                                                                 *
    2121*********************************************************************************************************************************/
    22 /** Define NO_PORT_RESET to skip the slow and broken linux port reset.
    23  * Resetting will break PalmOne. */
    24 #define NO_PORT_RESET
    25 /** Define NO_LOGICAL_RECONNECT to skip the broken logical reconnect handling. */
    26 #define NO_LOGICAL_RECONNECT
    2722
    2823
     
    9590#include <iprt/string.h>
    9691#include <iprt/list.h>
    97 #if defined(NO_PORT_RESET) && !defined(NO_LOGICAL_RECONNECT)
    98 # include <iprt/thread.h>
    99 #endif
    10092#include <iprt/time.h>
    10193#include "../USBProxyDevice.h"
     
    163155     * Used to figure out the configuration after a reset. */
    164156    char                *pszPath;
     157    /** Mask of claimed interfaces. */
     158    uint32_t            fClaimedIfsMask;
    165159} USBPROXYDEVLNX, *PUSBPROXYDEVLNX;
    166160
     
    169163*   Internal Functions                                                                                                           *
    170164*********************************************************************************************************************************/
    171 static int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries);
    172165static void usbProxLinuxUrbUnplugged(PUSBPROXYDEV pProxyDev);
    173 static void usbProxyLinuxSetConnected(PUSBPROXYDEV pProyxDev, int iIf, bool fConnect, bool fQuiet);
    174 static PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pSplitHead);
    175 static void usbProxyLinuxUrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx);
    176 static void usbProxyLinuxUrbFreeSplitList(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx);
    177 static int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg);
    178 
     166static DECLCALLBACK(int) usbProxyLinuxClaimInterface(PUSBPROXYDEV pProxyDev, int iIf);
     167static DECLCALLBACK(int) usbProxyLinuxReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf);
    179168
    180169
     
    676665                pDevLnx->fUsingSysfs = fUsingSysfs;
    677666                pDevLnx->hFile = hFile;
     667                pDevLnx->fClaimedIfsMask = 0;
    678668                rc = RTCritSectInit(&pDevLnx->CritSect);
    679669                if (RT_SUCCESS(rc))
     
    775765        else if (errno != ENODEV)
    776766            LogRel(("USB: Reset failed, errno=%d, pProxyDev=%s.\n", errno, usbProxyGetName(pProxyDev)));
    777         else
     767        else    /* This will happen if device was detached. */
    778768            Log(("USB: Reset failed, errno=%d (ENODEV), pProxyDev=%s.\n", errno, usbProxyGetName(pProxyDev)));
    779769    }
     
    833823
    834824
    835 #if defined(NO_PORT_RESET) && !defined(NO_LOGICAL_RECONNECT)
    836 /**
    837  * Look for the logically reconnected device.
    838  * After 5 seconds we'll give up.
    839  *
    840  * @returns VBox status code.
    841  * @thread  Reset thread or EMT.
    842  */
    843 static int usb_reset_logical_reconnect(PUSBPROXYDEV pDev)
    844 {
    845     FILE *          pFile;
    846     uint64_t        u64StartTS = RTTimeMilliTS();
    847 
    848     Log2(("usb_reset_logical_reconnect: pDev=%p:{.bBus=%#x, .bDevNum=%#x, .idVendor=%#x, .idProduct=%#x, .bcdDevice=%#x, .u64SerialHash=%#llx .bDevNumParent=%#x .bPort=%#x .bLevel=%#x}\n",
    849           pDev, pDev->Info.bBus, pDev->Info.bDevNum, pDev->Info.idVendor, pDev->Info.idProduct, pDev->Info.bcdDevice,
    850           pDev->Info.u64SerialHash, pDev->Info.bDevNumParent, pDev->Info.bPort, pDev->Info.bLevel));
    851 
    852     /* First, let hubd get a chance to logically reconnect the device. */
    853     if (!RTThreadYield())
    854         RTThreadSleep(1);
    855 
    856     /*
    857      * Search for the new device address.
    858      */
    859     pFile = get_devices_file();
    860     if (!pFile)
    861         return VERR_FILE_NOT_FOUND;
    862 
    863     /*
    864      * Loop until found or 5seconds have elapsed.
    865      */
    866     for (;;) {
    867         struct pollfd   pfd;
    868         uint8_t     tmp;
    869         int         rc;
    870         char        buf[512];
    871         uint64_t    u64Elapsed;
    872         int         got = 0;
    873         struct usb_dev_entry id = {0};
    874 
    875         /*
    876          * Since this is kernel ABI we don't need to be too fussy about
    877          * the parsing.
    878          */
    879         while (fgets(buf, sizeof(buf), pFile)) {
    880             char *psz = strchr(buf, '\n');
    881             if ( psz == NULL ) {
    882                 AssertMsgFailed(("usb_reset_logical_reconnect: Line to long!!\n"));
    883                 break;
    884             }
    885             *psz = '\0';
    886 
    887             switch ( buf[0] ) {
    888             case 'T': /* topology */
    889                 /* Check if we've got enough for a device. */
    890                 if (got >= 2) {
    891                     Log2(("usb_reset_logical_reconnect: {.bBus=%#x, .bDevNum=%#x, .idVendor=%#x, .idProduct=%#x, .bcdDevice=%#x, .u64SerialHash=%#llx, .bDevNumParent=%#x, .bPort=%#x, .bLevel=%#x}\n",
    892                           id.bBus, id.bDevNum, id.idVendor, id.idProduct, id.bcdDevice, id.u64SerialHash, id.bDevNumParent, id.bPort, id.bLevel));
    893                     if (    id.bDevNumParent == pDev->Info.bDevNumParent
    894                         &&  id.idVendor == pDev->Info.idVendor
    895                         &&  id.idProduct == pDev->Info.idProduct
    896                         &&  id.bcdDevice == pDev->Info.bcdDevice
    897                         &&  id.u64SerialHash == pDev->Info.u64SerialHash
    898                         &&  id.bBus == pDev->Info.bBus
    899                         &&  id.bPort == pDev->Info.bPort
    900                         &&  id.bLevel == pDev->Info.bLevel) {
    901                         goto l_found;
    902                     }
    903                 }
    904 
    905                 /* restart */
    906                 got = 0;
    907                 memset(&id, 0, sizeof(id));
    908 
    909                 /*T:  Bus=04 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0*/
    910                 Log2(("usb_reset_logical_reconnect: %s\n", buf));
    911                 buf[10] = '\0';
    912                 if ( !get_u8(buf + 8, &id.bBus) )
    913                     break;
    914                 buf[49] = '\0';
    915                 psz = buf + 46;
    916                 while ( *psz == ' ' )
    917                     psz++;
    918                 if ( !get_u8(psz, &id.bDevNum) )
    919                     break;
    920 
    921                 buf[17] = '\0';
    922                 if ( !get_u8(buf + 15, &id.bLevel) )
    923                     break;
    924                 buf[25] = '\0';
    925                 if ( !get_u8(buf + 23, &id.bDevNumParent) )
    926                     break;
    927                 buf[33] = '\0';
    928                 if ( !get_u8(buf + 31, &id.bPort) )
    929                     break;
    930                 got++;
    931                 break;
    932 
    933             case 'P': /* product */
    934                 Log2(("usb_reset_logical_reconnect: %s\n", buf));
    935                 buf[15] = '\0';
    936                 if ( !get_x16(buf + 11, &id.idVendor) )
    937                     break;
    938                 buf[27] = '\0';
    939                 if ( !get_x16(buf + 23, &id.idProduct) )
    940                     break;
    941                 buf[34] = '\0';
    942                 if ( buf[32] == ' ' )
    943                     buf[32] = '0';
    944                 id.bcdDevice = 0;
    945                 if ( !get_x8(buf + 32, &tmp) )
    946                     break;
    947                 id.bcdDevice = tmp << 8;
    948                 if ( !get_x8(buf + 35, &tmp) )
    949                     break;
    950                 id.bcdDevice |= tmp;
    951                 got++;
    952                 break;
    953 
    954             case 'S': /* String descriptor */
    955                 /* Skip past "S:" and then the whitespace */
    956                 for(psz = buf + 2; *psz != '\0'; psz++)
    957                     if ( !RT_C_IS_SPACE(*psz) )
    958                         break;
    959 
    960                 /* If it is a serial number string, skip past
    961                  * "SerialNumber="
    962                  */
    963                 if (strncmp(psz, RT_STR_TUPLE("SerialNumber=")))
    964                     break;
    965 
    966                 Log2(("usb_reset_logical_reconnect: %s\n", buf));
    967                 psz += sizeof("SerialNumber=") - 1;
    968 
    969                 usb_serial_hash(psz, &id.u64SerialHash);
    970                 break;
    971             }
    972         }
    973 
    974         /*
    975          * Check last.
    976          */
    977         if (    got >= 2
    978             &&  id.bDevNumParent == pDev->Info.bDevNumParent
    979             &&  id.idVendor == pDev->Info.idVendor
    980             &&  id.idProduct == pDev->Info.idProduct
    981             &&  id.bcdDevice == pDev->Info.bcdDevice
    982             &&  id.u64SerialHash == pDev->Info.u64SerialHash
    983             &&  id.bBus == pDev->Info.bBus
    984             &&  id.bPort == pDev->Info.bPort
    985             &&  id.bLevel == pDev->Info.bLevel) {
    986         l_found:
    987             /* close the existing file descriptor. */
    988             RTFileClose(pDevLnx->File);
    989             pDevLnx->File = NIL_RTFILE;
    990 
    991             /* open stuff at the new address. */
    992             pDev->Info = id;
    993             if (usbProxyLinuxOpen(pDev, &id))
    994                 return VINF_SUCCESS;
    995             break;
    996         }
    997 
    998         /*
    999          * Wait for a while and then check the file again.
    1000          */
    1001         u64Elapsed = RTTimeMilliTS() - u64StartTS;
    1002         if (u64Elapsed >= 5000/*ms*/)
    1003             break; /* done */
    1004 
    1005         pfd.fd = fileno(pFile);
    1006         pfd.events = POLLIN;
    1007         rc = poll(&pfd, 1, 5000 - u64Elapsed);
    1008         if (rc < 0) {
    1009             AssertMsg(errno == EINTR, ("errno=%d\n", errno));
    1010             RTThreadSleep(32); /* paranoia: don't eat cpu on failure */
    1011         }
    1012 
    1013         rewind(pFile);
    1014     } /* for loop */
    1015 
    1016     return VERR_GENERAL_FAILURE;
    1017 }
    1018 #endif /* !NO_PORT_RESET && !NO_LOGICAL_RECONNECT */
    1019 
    1020 
    1021825/** @interface_method_impl{USBPROXYBACK,pfnReset} */
    1022 static DECLCALLBACK(int) usbProxyLinuxReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
    1023 {
    1024 #ifdef NO_PORT_RESET
     826static DECLCALLBACK(int) usbProxyLinuxReset(PUSBPROXYDEV pProxyDev, bool fRootHubReset)
     827{
    1025828    PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
    1026 
    1027     /*
    1028      * Specific device resets are NOPs.
    1029      * Root hub resets that affects all devices are executed.
    1030      *
    1031      * The reasoning is that when a root hub reset is done, the guest shouldn't
    1032      * will have to re enumerate the devices after doing this kind of reset.
    1033      * So, it doesn't really matter if a device is 'logically disconnected'.
    1034      */
    1035     if (    !fResetOnLinux
    1036         ||  pProxyDev->fMaskedIfs)
    1037         LogFlow(("usbProxyLinuxReset: pProxyDev=%s - NO_PORT_RESET\n", usbProxyGetName(pProxyDev)));
    1038     else
    1039     {
    1040         LogFlow(("usbProxyLinuxReset: pProxyDev=%s - Real Reset!\n", usbProxyGetName(pProxyDev)));
    1041         if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RESET, NULL, false, 10))
    1042         {
    1043             int rc = errno;
    1044             Log(("usb-linux: Reset failed, rc=%s errno=%d.\n",
    1045                  RTErrGetShort(RTErrConvertFromErrno(rc)), rc));
    1046             pProxyDev->iActiveCfg = -1;
    1047             return RTErrConvertFromErrno(rc);
    1048         }
    1049 
    1050         /* find the active config - damn annoying. */
    1051         pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pDevLnx->pszPath, NULL);
    1052         LogFlow(("usbProxyLinuxReset: returns successfully iActiveCfg=%d\n", pProxyDev->iActiveCfg));
    1053     }
    1054     pProxyDev->cIgnoreSetConfigs = 2;
    1055 
    1056 #else /* !NO_PORT_RESET */
    1057 
    1058     /*
    1059      * This is the alternative, we will always reset when asked to do so.
    1060      *
    1061      * The problem we're facing here is that on reset failure linux will do
    1062      * a 'logical reconnect' on the device. This will invalidate the current
    1063      * handle and we'll have to reopen the device. This is problematic to say
    1064      * the least, especially since it happens pretty often.
    1065      */
     829    RT_NOREF(fRootHubReset);
     830    Assert(!pProxyDev->fMaskedIfs);
    1066831    LogFlow(("usbProxyLinuxReset: pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
    1067 # ifndef NO_LOGICAL_RECONNECT
    1068     ASMAtomicIncU32(&g_cResetActive);
    1069 # endif
     832
     833    uint32_t fActiveIfsMask = pDevLnx->fClaimedIfsMask;
     834    unsigned i;
     835
     836    /*
     837     * Before reset, release claimed interfaces. This less than obvious move
     838     * prevents Linux from rebinding in-kernel drivers to the device after reset.
     839     */
     840    for (i = 0; i < (sizeof(fActiveIfsMask) * 8); ++i)
     841    {
     842        if (fActiveIfsMask & RT_BIT(i))
     843        {
     844            usbProxyLinuxReleaseInterface(pProxyDev, i);
     845        }
     846    }
    1070847
    1071848    if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RESET, NULL, false, 10))
    1072849    {
    1073850        int rc = errno;
    1074 # ifndef NO_LOGICAL_RECONNECT
    1075         if (rc == ENODEV)
    1076         {
    1077             /*
    1078              * This usually happens because of a 'logical disconnection'.
    1079              * So, we're in for a real treat from our excellent OS now...
    1080              */
    1081             rc2 = usb_reset_logical_reconnect(pProxyDev);
    1082             if (RT_FAILURE(rc2))
    1083                 usbProxLinuxUrbUnplugged(pProxyDev);
    1084             if (RT_SUCCESS(rc2))
    1085             {
    1086                 ASMAtomicDecU32(&g_cResetActive);
    1087                 LogFlow(("usbProxyLinuxReset: returns success (after recovering disconnected device!)\n"));
    1088                 return VINF_SUCCESS;
    1089             }
    1090         }
    1091         ASMAtomicDecU32(&g_cResetActive);
    1092 # endif /* NO_LOGICAL_RECONNECT */
    1093 
    1094         Log(("usb-linux: Reset failed, rc=%s errno=%d.\n",
    1095              RTErrGetShort(RTErrConvertFromErrno(rc)), rc));
     851        LogRel(("usb-linux: Reset failed, rc=%s errno=%d.\n",
     852               RTErrGetShort(RTErrConvertFromErrno(rc)), rc));
    1096853        pProxyDev->iActiveCfg = -1;
    1097854        return RTErrConvertFromErrno(rc);
    1098855    }
    1099856
    1100 # ifndef NO_LOGICAL_RECONNECT
    1101     ASMAtomicDecU32(&g_cResetActive);
    1102 # endif
     857    /*
     858     * Now reclaim previously claimed interfaces. If that doesn't work, let's hope
     859     * the guest/VUSB can recover from that. Can happen if reset changes configuration.
     860     */
     861    for (i = 0; i < (sizeof(fActiveIfsMask) * 8); ++i)
     862    {
     863        if (fActiveIfsMask & RT_BIT(i))
     864        {
     865            usbProxyLinuxClaimInterface(pProxyDev, i);
     866        }
     867    }
     868
     869    /* find the active config - damn annoying. */
     870    pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pDevLnx->pszPath, NULL);
     871    LogFlow(("usbProxyLinuxReset: returns successfully iActiveCfg=%d\n", pProxyDev->iActiveCfg));
    1103872
    1104873    pProxyDev->cIgnoreSetConfigs = 2;
    1105     LogFlow(("usbProxyLinuxReset: returns success\n"));
    1106 #endif /* !NO_PORT_RESET */
    1107874    return VINF_SUCCESS;
    1108875}
     
    1139906static DECLCALLBACK(int) usbProxyLinuxClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
    1140907{
     908    PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
     909
    1141910    LogFlow(("usbProxyLinuxClaimInterface: pProxyDev=%s ifnum=%#x\n", usbProxyGetName(pProxyDev), iIf));
    1142911    usbProxyLinuxSetConnected(pProxyDev, iIf, false, false);
     
    1144913    if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_CLAIMINTERFACE, &iIf, true, UINT32_MAX))
    1145914    {
    1146         Log(("usb-linux: Claim interface. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
     915        pDevLnx->fClaimedIfsMask &= ~RT_BIT(iIf);
     916        LogRel(("usb-linux: Claim interface. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1147917        return RTErrConvertFromErrno(errno);
    1148918    }
     919    pDevLnx->fClaimedIfsMask |= RT_BIT(iIf);
    1149920    return VINF_SUCCESS;
    1150921}
     
    1157928static DECLCALLBACK(int) usbProxyLinuxReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
    1158929{
     930    PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
     931
    1159932    LogFlow(("usbProxyLinuxReleaseInterface: pProxyDev=%s ifnum=%#x\n", usbProxyGetName(pProxyDev), iIf));
    1160933
    1161934    if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RELEASEINTERFACE, &iIf, true, UINT32_MAX))
    1162935    {
    1163         Log(("usb-linux: Release interface, errno=%d. pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
     936        LogRel(("usb-linux: Release interface, errno=%d. pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1164937        return RTErrConvertFromErrno(errno);
    1165938    }
     939    pDevLnx->fClaimedIfsMask &= ~RT_BIT(iIf);
    1166940    return VINF_SUCCESS;
    1167941}
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