VirtualBox

Ignore:
Timestamp:
Feb 24, 2022 12:20:43 PM (3 years ago)
Author:
vboxsync
Message:

Devices/USB: Convert the HCI emulations to call into the roothub using the devices port instead of using the VUSBIDEVICE interface directly. This will avoid races when devices will get detached unexpectedly while being in use. Also move the device re-attach logic after a saved state operation down to the roothub in order to avoid code duplication, bugref:10196

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp

    r93115 r93914  
    220220
    221221
     222#define VUSB_ROOTHUB_SAVED_STATE_VERSION 1
     223
     224
     225/**
     226 * Data used for reattaching devices on a state load.
     227 */
     228typedef struct VUSBROOTHUBLOAD
     229{
     230    /** Timer used once after state load to inform the guest about new devices.
     231     * We do this to be sure the guest get any disconnect / reconnect on the
     232     * same port. */
     233    TMTIMERHANDLE       hTimer;
     234    /** Number of detached devices. */
     235    unsigned            cDevs;
     236    /** Array of devices which were detached. */
     237    PVUSBDEV            apDevs[VUSB_DEVICES_MAX];
     238} VUSBROOTHUBLOAD;
     239
     240
     241/**
     242 * Returns the attached VUSB device for the given port or NULL if none is attached.
     243 *
     244 * @returns Pointer to the VUSB device or NULL if not found.
     245 * @param   pThis               The VUSB roothub device instance.
     246 * @param   uPort               The port to get the device for.
     247 *
     248 * @note The reference count of the VUSB device structure is retained to prevent it from going away.
     249 */
     250static PVUSBDEV vusbR3RhGetVUsbDevByPortRetain(PVUSBROOTHUB pThis, uint32_t uPort)
     251{
     252    PVUSBDEV pDev = NULL;
     253
     254    AssertReturn(uPort < RT_ELEMENTS(pThis->apDevByPort), NULL);
     255
     256    RTCritSectEnter(&pThis->CritSectDevices);
     257
     258    pDev = pThis->apDevByPort[uPort];
     259    if (RT_LIKELY(pDev))
     260        ASMAtomicIncU32(&pDev->cRefs);
     261
     262    RTCritSectLeave(&pThis->CritSectDevices);
     263
     264    return pDev;
     265}
     266
    222267
    223268/**
     
    375420 * Worker routine for vusbRhConnNewUrb().
    376421 */
    377 static PVUSBURB vusbRhNewUrb(PVUSBROOTHUB pRh, uint8_t DstAddress, PVUSBDEV pDev, VUSBXFERTYPE enmType,
     422static PVUSBURB vusbRhNewUrb(PVUSBROOTHUB pRh, uint8_t DstAddress, uint32_t uPort, VUSBXFERTYPE enmType,
    378423                             VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag)
    379424{
     
    387432    }
    388433
    389     if (!pDev)
     434    PVUSBDEV pDev;
     435    if (uPort == VUSB_DEVICE_PORT_INVALID)
    390436        pDev = vusbRhFindDevByAddress(pRh, DstAddress);
    391437    else
    392         vusbDevRetain(pDev);
     438        pDev = vusbR3RhGetVUsbDevByPortRetain(pRh, uPort);
    393439
    394440    if (pDev)
     
    631677
    632678
     679/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnReset} */
     680static DECLCALLBACK(int) vusbR3RhReset(PVUSBIROOTHUBCONNECTOR pInterface, bool fResetOnLinux)
     681{
     682    PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     683    return pRh->pIRhPort->pfnReset(pRh->pIRhPort, fResetOnLinux);
     684}
     685
     686
     687/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnPowerOn} */
     688static DECLCALLBACK(int) vusbR3RhPowerOn(PVUSBIROOTHUBCONNECTOR pInterface)
     689{
     690    PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     691    LogFlow(("vusR3bRhPowerOn: pRh=%p\n", pRh));
     692
     693    Assert(     pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_DETACHED
     694           &&   pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_RESET);
     695
     696    if (pRh->Hub.Dev.enmState == VUSB_DEVICE_STATE_ATTACHED)
     697        pRh->Hub.Dev.enmState = VUSB_DEVICE_STATE_POWERED;
     698
     699    return VINF_SUCCESS;
     700}
     701
     702
     703/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnPowerOff} */
     704static DECLCALLBACK(int) vusbR3RhPowerOff(PVUSBIROOTHUBCONNECTOR pInterface)
     705{
     706    PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     707    LogFlow(("vusbR3RhDevPowerOff: pThis=%p\n", pThis));
     708
     709    Assert(     pThis->Hub.Dev.enmState != VUSB_DEVICE_STATE_DETACHED
     710           &&   pThis->Hub.Dev.enmState != VUSB_DEVICE_STATE_RESET);
     711
     712    /*
     713     * Cancel all URBs and reap them.
     714     */
     715    VUSBIRhCancelAllUrbs(&pThis->IRhConnector);
     716    for (uint32_t uPort = 0; uPort < RT_ELEMENTS(pThis->apDevByPort); uPort++)
     717        VUSBIRhReapAsyncUrbs(&pThis->IRhConnector, uPort, 0);
     718
     719    pThis->Hub.Dev.enmState = VUSB_DEVICE_STATE_ATTACHED;
     720    return VINF_SUCCESS;
     721}
     722
     723
    633724/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnNewUrb} */
    634 static DECLCALLBACK(PVUSBURB) vusbRhConnNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, PVUSBIDEVICE pDev, VUSBXFERTYPE enmType,
     725static DECLCALLBACK(PVUSBURB) vusbRhConnNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t uPort, VUSBXFERTYPE enmType,
    635726                                               VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag)
    636727{
    637728    PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
    638     return vusbRhNewUrb(pRh, DstAddress, (PVUSBDEV)pDev, enmType, enmDir, cbData, cTds, pszTag);
     729    return vusbRhNewUrb(pRh, DstAddress, uPort, enmType, enmDir, cbData, cTds, pszTag);
    639730}
    640731
     
    760851
    761852/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnReapAsyncUrbs} */
    762 static DECLCALLBACK(void) vusbRhReapAsyncUrbs(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice, RTMSINTERVAL cMillies)
     853static DECLCALLBACK(void) vusbRhReapAsyncUrbs(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, RTMSINTERVAL cMillies)
    763854{
    764855    PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface); NOREF(pRh);
    765     PVUSBDEV pDev = (PVUSBDEV)pDevice;
    766 
    767     if (RTListIsEmpty(&pDev->LstAsyncUrbs))
     856    PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pRh, uPort);
     857
     858    if (  !pDev
     859        || RTListIsEmpty(&pDev->LstAsyncUrbs))
    768860        return;
    769861
     
    772864    AssertRC(rc);
    773865    STAM_PROFILE_STOP(&pRh->StatReapAsyncUrbs, a);
     866
     867    vusbDevRelease(pDev);
    774868}
    775869
     
    871965
    872966/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnAbortEp} */
    873 static DECLCALLBACK(int) vusbRhAbortEp(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice, int EndPt, VUSBDIRECTION enmDir)
     967static DECLCALLBACK(int) vusbRhAbortEp(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, int EndPt, VUSBDIRECTION enmDir)
    874968{
    875969    PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
    876     if (&pRh->Hub != ((PVUSBDEV)pDevice)->pHub)
     970    PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pRh, uPort);
     971
     972    if (&pRh->Hub != pDev->pHub)
    877973        AssertFailedReturn(VERR_INVALID_PARAMETER);
    878974
    879     RTCritSectEnter(&pRh->CritSectDevices);
    880     PVUSBDEV pDev = (PVUSBDEV)pDevice;
    881975    vusbDevIoThreadExecSync(pDev, (PFNRT)vusbRhAbortEpWorker, 3, pDev, EndPt, enmDir);
    882     RTCritSectLeave(&pRh->CritSectDevices);
     976    vusbDevRelease(pDev);
    883977
    884978    /* The reaper thread will take care of completing the URB. */
    885979
    886980    return VINF_SUCCESS;
    887 }
    888 
    889 
    890 /** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnAttachDevice} */
    891 static DECLCALLBACK(int) vusbRhAttachDevice(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)
    892 {
    893     PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
    894     return vusbHubAttach(&pRh->Hub, (PVUSBDEV)pDevice);
    895 }
    896 
    897 
    898 /** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnDetachDevice} */
    899 static DECLCALLBACK(int) vusbRhDetachDevice(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)
    900 {
    901     PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
    902     if (&pRh->Hub != ((PVUSBDEV)pDevice)->pHub)
    903         AssertFailedReturn(VERR_INVALID_PARAMETER);
    904     return vusbDevDetach((PVUSBDEV)pDevice);
    905981}
    906982
     
    9801056
    9811057/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnUpdateIsocFrameDelta} */
    982 static DECLCALLBACK(uint32_t) vusbRhUpdateIsocFrameDelta(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice,
     1058static DECLCALLBACK(uint32_t) vusbRhUpdateIsocFrameDelta(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort,
    9831059                                                         int EndPt, VUSBDIRECTION enmDir, uint16_t uNewFrameID, uint8_t uBits)
    9841060{
    9851061    PVUSBROOTHUB    pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
    9861062    AssertReturn(pRh, 0);
    987     PVUSBDEV        pDev = (PVUSBDEV)pDevice;
     1063    PVUSBDEV        pDev = vusbR3RhGetVUsbDevByPortRetain(pRh, uPort); AssertPtr(pDev);
    9881064    PVUSBPIPE       pPipe = &pDev->aPipes[EndPt];
    9891065    uint32_t        *puLastFrame;
     
    9981074        uFrameDelta += uMaxVal;
    9991075
     1076    vusbDevRelease(pDev);
    10001077    return (uint16_t)uFrameDelta;
    10011078}
    10021079
    1003 /* -=-=-=-=-=- VUSB Device methods (for the root hub) -=-=-=-=-=- */
    1004 
    1005 
    1006 /**
    1007  * @interface_method_impl{VUSBIDEVICE,pfnReset}
    1008  */
    1009 static DECLCALLBACK(int) vusbRhDevReset(PVUSBIDEVICE pInterface, bool fResetOnLinux,
    1010                                         PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
    1011 {
    1012     RT_NOREF(pfnDone, pvUser, pVM);
    1013     PVUSBROOTHUB pRh = RT_FROM_MEMBER(pInterface, VUSBROOTHUB, Hub.Dev.IDevice);
    1014     Assert(!pfnDone);
    1015     return pRh->pIRhPort->pfnReset(pRh->pIRhPort, fResetOnLinux); /** @todo change rc from bool to vbox status everywhere! */
    1016 }
    1017 
    1018 
    1019 /**
    1020  * @interface_method_impl{VUSBIDEVICE,pfnPowerOn}
    1021  */
    1022 static DECLCALLBACK(int) vusbRhDevPowerOn(PVUSBIDEVICE pInterface)
    1023 {
    1024     PVUSBROOTHUB pRh = RT_FROM_MEMBER(pInterface, VUSBROOTHUB, Hub.Dev.IDevice);
    1025     LogFlow(("vusbRhDevPowerOn: pRh=%p\n", pRh));
    1026 
    1027     Assert(     pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_DETACHED
    1028            &&   pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_RESET);
    1029 
    1030     if (pRh->Hub.Dev.enmState == VUSB_DEVICE_STATE_ATTACHED)
    1031         pRh->Hub.Dev.enmState = VUSB_DEVICE_STATE_POWERED;
    1032 
    1033     return VINF_SUCCESS;
    1034 }
    1035 
    1036 
    1037 /**
    1038  * @interface_method_impl{VUSBIDEVICE,pfnPowerOff}
    1039  */
    1040 static DECLCALLBACK(int) vusbRhDevPowerOff(PVUSBIDEVICE pInterface)
    1041 {
    1042     PVUSBROOTHUB pRh = RT_FROM_MEMBER(pInterface, VUSBROOTHUB, Hub.Dev.IDevice);
    1043     LogFlow(("vusbRhDevPowerOff: pRh=%p\n", pRh));
    1044 
    1045     Assert(     pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_DETACHED
    1046            &&   pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_RESET);
    1047 
    1048     /*
    1049      * Cancel all URBs and reap them.
    1050      */
    1051     VUSBIRhCancelAllUrbs(&pRh->IRhConnector);
    1052     RTCritSectEnter(&pRh->CritSectDevices);
    1053     PVUSBDEV pDev = pRh->pDevices;
    1054     while (pDev)
    1055     {
    1056         VUSBIRhReapAsyncUrbs(&pRh->IRhConnector, (PVUSBIDEVICE)pDev, 0);
    1057         pDev = pDev->pNext;
    1058     }
    1059     RTCritSectLeave(&pRh->CritSectDevices);
    1060 
    1061     pRh->Hub.Dev.enmState = VUSB_DEVICE_STATE_ATTACHED;
    1062     return VINF_SUCCESS;
    1063 }
    1064 
    1065 /**
    1066  * @interface_method_impl{VUSBIDEVICE,pfnGetState}
    1067  */
    1068 static DECLCALLBACK(VUSBDEVICESTATE) vusbRhDevGetState(PVUSBIDEVICE pInterface)
    1069 {
    1070     PVUSBROOTHUB pRh = RT_FROM_MEMBER(pInterface, VUSBROOTHUB, Hub.Dev.IDevice);
    1071     return pRh->Hub.Dev.enmState;
     1080
     1081/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnDevReset} */
     1082static DECLCALLBACK(int) vusbR3RhDevReset(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, bool fResetOnLinux,
     1083                                          PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
     1084{
     1085    PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     1086    PVUSBDEV     pDev  = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort);
     1087    AssertPtr(pDev);
     1088
     1089    int rc = VUSBIDevReset(&pDev->IDevice, fResetOnLinux, pfnDone, pvUser, pVM);
     1090    vusbDevRelease(pDev);
     1091    return rc;
     1092}
     1093
     1094
     1095/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnDevPowerOn} */
     1096static DECLCALLBACK(int) vusbR3RhDevPowerOn(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1097{
     1098    PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     1099    PVUSBDEV     pDev  = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort);
     1100    AssertPtr(pDev);
     1101
     1102    int rc = VUSBIDevPowerOn(&pDev->IDevice);
     1103    vusbDevRelease(pDev);
     1104    return rc;
     1105}
     1106
     1107
     1108/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnDevPowerOff} */
     1109static DECLCALLBACK(int) vusbR3RhDevPowerOff(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1110{
     1111    PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     1112    PVUSBDEV     pDev  = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort);
     1113    AssertPtr(pDev);
     1114
     1115    int rc = VUSBIDevPowerOff(&pDev->IDevice);
     1116    vusbDevRelease(pDev);
     1117    return rc;
     1118}
     1119
     1120
     1121/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnDevGetState} */
     1122static DECLCALLBACK(VUSBDEVICESTATE) vusbR3RhDevGetState(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1123{
     1124    PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     1125    PVUSBDEV     pDev  = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort);
     1126    AssertPtr(pDev);
     1127
     1128    VUSBDEVICESTATE enmState = VUSBIDevGetState(&pDev->IDevice);
     1129    vusbDevRelease(pDev);
     1130    return enmState;
     1131}
     1132
     1133
     1134/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnIsSavedStateSupported} */
     1135static DECLCALLBACK(bool) vusbR3RhDevIsSavedStateSupported(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1136{
     1137    PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     1138    PVUSBDEV     pDev  = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort);
     1139    AssertPtr(pDev);
     1140
     1141    bool fSavedStateSupported = VUSBIDevIsSavedStateSupported(&pDev->IDevice);
     1142    vusbDevRelease(pDev);
     1143    return fSavedStateSupported;
     1144}
     1145
     1146
     1147/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnDevGetSpeed} */
     1148static DECLCALLBACK(VUSBSPEED) vusbR3RhDevGetSpeed(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1149{
     1150    PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
     1151    PVUSBDEV     pDev  = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort);
     1152    AssertPtr(pDev);
     1153
     1154    VUSBSPEED enmSpeed = pDev->IDevice.pfnGetSpeed(&pDev->IDevice);
     1155    vusbDevRelease(pDev);
     1156    return enmSpeed;
    10721157}
    10731158
     
    11041189}
    11051190
     1191
     1192/**
     1193 * @callback_method_impl{FNSSMDEVSAVEPREP, All URBs needs to be canceled.}
     1194 */
     1195static DECLCALLBACK(int) vusbR3RhSavePrep(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
     1196{
     1197    PVUSBROOTHUB pThis = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
     1198    LogFlow(("vusbR3RhSavePrep:\n"));
     1199    RT_NOREF(pSSM);
     1200
     1201    /*
     1202     * Detach all proxied devices.
     1203     */
     1204    RTCritSectEnter(&pThis->CritSectDevices);
     1205
     1206    /** @todo we a) can't tell which are proxied, and b) this won't work well when continuing after saving! */
     1207    for (unsigned i = 0; i < RT_ELEMENTS(pThis->apDevByPort); i++)
     1208    {
     1209        PVUSBDEV pDev = pThis->apDevByPort[i];
     1210        if (pDev)
     1211        {
     1212            if (!VUSBIDevIsSavedStateSupported(&pDev->IDevice))
     1213            {
     1214                int rc = vusbDevDetach(pDev);
     1215                AssertRC(rc);
     1216
     1217                /*
     1218                 * Save the device pointers here so we can reattach them afterwards.
     1219                 * This will work fine even if the save fails since the Done handler is
     1220                 * called unconditionally if the Prep handler was called.
     1221                 */
     1222                pThis->apDevByPort[i] = pDev;
     1223            }
     1224        }
     1225    }
     1226
     1227    RTCritSectLeave(&pThis->CritSectDevices);
     1228
     1229    /*
     1230     * Kill old load data which might be hanging around.
     1231     */
     1232    if (pThis->pLoad)
     1233    {
     1234        PDMDrvHlpTimerDestroy(pDrvIns, pThis->pLoad->hTimer);
     1235        pThis->pLoad->hTimer = NIL_TMTIMERHANDLE;
     1236        PDMDrvHlpMMHeapFree(pDrvIns, pThis->pLoad);
     1237        pThis->pLoad = NULL;
     1238    }
     1239
     1240    return VINF_SUCCESS;
     1241}
     1242
     1243
     1244/**
     1245 * @callback_method_impl{FNSSMDEVSAVEDONE}
     1246 */
     1247static DECLCALLBACK(int) vusbR3RhSaveDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
     1248{
     1249    PVUSBROOTHUB pThis = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
     1250    PVUSBDEV     aPortsOld[VUSB_DEVICES_MAX];
     1251    unsigned     i;
     1252    LogFlow(("vusbR3RhSaveDone:\n"));
     1253    RT_NOREF(pSSM);
     1254
     1255    /* Save the current data. */
     1256    memcpy(aPortsOld, pThis->apDevByPort, sizeof(aPortsOld));
     1257    AssertCompile(sizeof(aPortsOld) == sizeof(pThis->apDevByPort));
     1258
     1259    /*
     1260     * NULL the dev pointers.
     1261     */
     1262    for (i = 0; i < RT_ELEMENTS(pThis->apDevByPort); i++)
     1263        if (pThis->apDevByPort[i] && !VUSBIDevIsSavedStateSupported(&pThis->apDevByPort[i]->IDevice))
     1264            pThis->apDevByPort[i] = NULL;
     1265
     1266    /*
     1267     * Attach the devices.
     1268     */
     1269    for (i = 0; i < RT_ELEMENTS(pThis->apDevByPort); i++)
     1270    {
     1271        PVUSBDEV pDev = aPortsOld[i];
     1272        if (pDev && !VUSBIDevIsSavedStateSupported(&pDev->IDevice))
     1273            vusbHubAttach(&pThis->Hub, pDev);
     1274    }
     1275
     1276    return VINF_SUCCESS;
     1277}
     1278
     1279
     1280/**
     1281 * @callback_method_impl{FNSSMDEVLOADPREP, This must detach the devices
     1282 * currently attached and save them for reconnect after the state load has been
     1283 * completed.}
     1284 */
     1285static DECLCALLBACK(int) vusbR3RhLoadPrep(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
     1286{
     1287    PVUSBROOTHUB pThis = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
     1288    int     rc = VINF_SUCCESS;
     1289    LogFlow(("vusbR3RhLoadPrep:\n"));
     1290    RT_NOREF(pSSM);
     1291
     1292    if (!pThis->pLoad)
     1293    {
     1294        VUSBROOTHUBLOAD Load;
     1295        unsigned        i;
     1296
     1297        /// @todo This is all bogus.
     1298        /*
     1299         * Detach all devices which are present in this session. Save them in the load
     1300         * structure so we can reattach them after restoring the guest.
     1301         */
     1302        Load.hTimer = NIL_TMTIMERHANDLE;
     1303        Load.cDevs  = 0;
     1304        for (i = 0; i < RT_ELEMENTS(pThis->apDevByPort); i++)
     1305        {
     1306            PVUSBDEV pDev = pThis->apDevByPort[i];
     1307            if (pDev && !VUSBIDevIsSavedStateSupported(&pDev->IDevice))
     1308            {
     1309                Load.apDevs[Load.cDevs++] = pDev;
     1310                vusbDevDetach(pDev);
     1311                Assert(!pThis->apDevByPort[i]);
     1312            }
     1313        }
     1314
     1315        /*
     1316         * Any devices to reattach? If so, duplicate the Load struct.
     1317         */
     1318        if (Load.cDevs)
     1319        {
     1320            pThis->pLoad = (PVUSBROOTHUBLOAD)RTMemAllocZ(sizeof(Load));
     1321            if (!pThis->pLoad)
     1322                return VERR_NO_MEMORY;
     1323            *pThis->pLoad = Load;
     1324        }
     1325    }
     1326    /* else: we ASSUME no device can be attached or detached in the time
     1327     *       between a state load and the pLoad stuff processing. */
     1328    return rc;
     1329}
     1330
     1331
     1332/**
     1333 * Reattaches devices after a saved state load.
     1334 */
     1335static DECLCALLBACK(void) vusbR3RhLoadReattachDevices(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, void *pvUser)
     1336{
     1337    PVUSBROOTHUB        pThis = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
     1338    PVUSBROOTHUBLOAD    pLoad = pThis->pLoad;
     1339    LogFlow(("vusbR3RhLoadReattachDevices:\n"));
     1340    Assert(hTimer == pLoad->hTimer); RT_NOREF(pvUser);
     1341
     1342    /*
     1343     * Reattach devices.
     1344     */
     1345    for (unsigned i = 0; i < pLoad->cDevs; i++)
     1346        vusbHubAttach(&pThis->Hub, pLoad->apDevs[i]);
     1347
     1348    /*
     1349     * Cleanup.
     1350     */
     1351    PDMDrvHlpTimerDestroy(pDrvIns, hTimer);
     1352    pLoad->hTimer = NIL_TMTIMERHANDLE;
     1353    RTMemFree(pLoad);
     1354    pThis->pLoad = NULL;
     1355}
     1356
     1357
     1358/**
     1359 * @callback_method_impl{FNSSMDEVLOADDONE}
     1360 */
     1361static DECLCALLBACK(int) vusbR3RhLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
     1362{
     1363    PVUSBROOTHUB pThis = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
     1364    LogFlow(("vusbR3RhLoadDone:\n"));
     1365    RT_NOREF(pSSM);
     1366
     1367    /*
     1368     * Start a timer if we've got devices to reattach
     1369     */
     1370    if (pThis->pLoad)
     1371    {
     1372        int rc = PDMDrvHlpTMTimerCreate(pDrvIns, TMCLOCK_VIRTUAL, vusbR3RhLoadReattachDevices, NULL,
     1373                                        TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0,
     1374                                        "VUSB reattach on load", &pThis->pLoad->hTimer);
     1375        if (RT_SUCCESS(rc))
     1376            rc = PDMDrvHlpTimerSetMillies(pDrvIns, pThis->pLoad->hTimer, 250);
     1377        return rc;
     1378    }
     1379
     1380    return VINF_SUCCESS;
     1381}
     1382
     1383
    11061384/* -=-=-=-=-=- VUSB Hub methods -=-=-=-=-=- */
    11071385
     
    11361414     * linked into the device list of this hub.
    11371415     */
    1138     int rc = pRh->pIRhPort->pfnAttach(pRh->pIRhPort, &pDev->IDevice, iPort);
     1416    VUSBSPEED enmSpeed = pDev->IDevice.pfnGetSpeed(&pDev->IDevice);
     1417    int rc = pRh->pIRhPort->pfnAttach(pRh->pIRhPort, iPort, enmSpeed);
    11391418    if (RT_SUCCESS(rc))
    11401419    {
     
    11421421        pDev->pNext = pRh->pDevices;
    11431422        pRh->pDevices = pDev;
     1423
     1424        Assert(!pRh->apDevByPort[iPort]);
     1425        pRh->apDevByPort[iPort] = pDev;
     1426
    11441427        RTCritSectLeave(&pRh->CritSectDevices);
    11451428        LogRel(("VUSB: Attached '%s' to port %d on %s (%sSpeed)\n", pDev->pUsbIns->pszName,
     
    11841467        pRh->pDevices = pDev->pNext;
    11851468    pDev->pNext = NULL;
     1469
     1470    pRh->apDevByPort[pDev->i16Port] = NULL;
    11861471    RTCritSectLeave(&pRh->CritSectDevices);
    11871472
     
    11901475     */
    11911476    unsigned uPort = pDev->i16Port;
    1192     pRh->pIRhPort->pfnDetach(pRh->pIRhPort, &pDev->IDevice, uPort);
     1477    pRh->pIRhPort->pfnDetach(pRh->pIRhPort, uPort);
    11931478    LogRel(("VUSB: Detached '%s' from port %u on %s\n", pDev->pUsbIns->pszName, uPort, pHub->pszName));
    11941479    ASMBitSet(&pRh->Bitmap, uPort);
     
    13071592    /* the usb device */
    13081593    pThis->Hub.Dev.enmState             = VUSB_DEVICE_STATE_ATTACHED;
    1309     pThis->Hub.Dev.u8Address            = VUSB_INVALID_ADDRESS;
    1310     pThis->Hub.Dev.u8NewAddress         = VUSB_INVALID_ADDRESS;
    1311     pThis->Hub.Dev.i16Port              = -1;
    13121594    pThis->Hub.Dev.cRefs                = 1;
    1313     pThis->Hub.Dev.IDevice.pfnReset     = vusbRhDevReset;
    1314     pThis->Hub.Dev.IDevice.pfnPowerOn   = vusbRhDevPowerOn;
    1315     pThis->Hub.Dev.IDevice.pfnPowerOff  = vusbRhDevPowerOff;
    1316     pThis->Hub.Dev.IDevice.pfnGetState  = vusbRhDevGetState;
    13171595    /* the hub */
    13181596    pThis->Hub.pOps                     = &s_VUsbRhHubOps;
     
    13261604    /* the connector */
    13271605    pThis->IRhConnector.pfnSetUrbParams               = vusbRhSetUrbParams;
     1606    pThis->IRhConnector.pfnReset                      = vusbR3RhReset;
     1607    pThis->IRhConnector.pfnPowerOn                    = vusbR3RhPowerOn;
     1608    pThis->IRhConnector.pfnPowerOff                   = vusbR3RhPowerOff;
    13281609    pThis->IRhConnector.pfnNewUrb                     = vusbRhConnNewUrb;
    13291610    pThis->IRhConnector.pfnFreeUrb                    = vusbRhConnFreeUrb;
     
    13331614    pThis->IRhConnector.pfnCancelAllUrbs              = vusbRhCancelAllUrbs;
    13341615    pThis->IRhConnector.pfnAbortEp                    = vusbRhAbortEp;
    1335     pThis->IRhConnector.pfnAttachDevice               = vusbRhAttachDevice;
    1336     pThis->IRhConnector.pfnDetachDevice               = vusbRhDetachDevice;
    13371616    pThis->IRhConnector.pfnSetPeriodicFrameProcessing = vusbRhSetFrameProcessing;
    13381617    pThis->IRhConnector.pfnGetPeriodicFrameRate       = vusbRhGetPeriodicFrameRate;
    13391618    pThis->IRhConnector.pfnUpdateIsocFrameDelta       = vusbRhUpdateIsocFrameDelta;
     1619    pThis->IRhConnector.pfnDevReset                   = vusbR3RhDevReset;
     1620    pThis->IRhConnector.pfnDevPowerOn                 = vusbR3RhDevPowerOn;
     1621    pThis->IRhConnector.pfnDevPowerOff                = vusbR3RhDevPowerOff;
     1622    pThis->IRhConnector.pfnDevGetState                = vusbR3RhDevGetState;
     1623    pThis->IRhConnector.pfnDevIsSavedStateSupported   = vusbR3RhDevIsSavedStateSupported;
     1624    pThis->IRhConnector.pfnDevGetSpeed                = vusbR3RhDevGetSpeed;
    13401625    pThis->hSniffer                                   = VUSBSNIFFER_NIL;
    13411626    pThis->cbHci                                      = 0;
     
    13881673    if (RT_FAILURE(rc))
    13891674        return rc;
     1675
     1676    /*
     1677     * Register the saved state data unit for attaching devices.
     1678     */
     1679    rc = PDMDrvHlpSSMRegisterEx(pDrvIns, VUSB_ROOTHUB_SAVED_STATE_VERSION, 0,
     1680                                NULL, NULL, NULL,
     1681                                vusbR3RhSavePrep, NULL, vusbR3RhSaveDone,
     1682                                vusbR3RhLoadPrep, NULL, vusbR3RhLoadDone);
     1683    AssertRCReturn(rc, rc);
    13901684
    13911685    /*
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