VirtualBox

Changeset 93914 in vbox for trunk


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

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vusb.h

    r93115 r93914  
    564564
    565565
    566 
    567 /**
    568  * VBox USB port bitmap.
    569  *
    570  * Bit 0 == Port 0, ... , Bit 127 == Port 127.
    571  */
    572 typedef struct VUSBPORTBITMAP
    573 {
    574     /** 128 bits */
    575     char ach[16];
    576 } VUSBPORTBITMAP;
    577 /** Pointer to a VBox USB port bitmap. */
    578 typedef VUSBPORTBITMAP *PVUSBPORTBITMAP;
    579 
    580 #ifndef RDESKTOP
    581 
    582 /**
    583  * The VUSB RootHub port interface provided by the HCI (down).
    584  * Pair with VUSBIROOTCONNECTOR
    585  */
    586 typedef struct VUSBIROOTHUBPORT
    587 {
    588     /**
    589      * Get the number of available ports in the hub.
    590      *
    591      * @returns The number of ports available.
    592      * @param   pInterface      Pointer to this structure.
    593      * @param   pAvailable      Bitmap indicating the available ports. Set bit == available port.
    594      */
    595     DECLR3CALLBACKMEMBER(unsigned, pfnGetAvailablePorts,(PVUSBIROOTHUBPORT pInterface, PVUSBPORTBITMAP pAvailable));
    596 
    597     /**
    598      * Gets the supported USB versions.
    599      *
    600      * @returns The mask of supported USB versions.
    601      * @param   pInterface      Pointer to this structure.
    602      */
    603     DECLR3CALLBACKMEMBER(uint32_t, pfnGetUSBVersions,(PVUSBIROOTHUBPORT pInterface));
    604 
    605     /**
    606      * A device is being attached to a port in the roothub.
    607      *
    608      * @param   pInterface      Pointer to this structure.
    609      * @param   pDev            Pointer to the device being attached.
    610      * @param   uPort           The port number assigned to the device.
    611      */
    612     DECLR3CALLBACKMEMBER(int, pfnAttach,(PVUSBIROOTHUBPORT pInterface, PVUSBIDEVICE pDev, unsigned uPort));
    613 
    614     /**
    615      * A device is being detached from a port in the roothub.
    616      *
    617      * @param   pInterface      Pointer to this structure.
    618      * @param   pDev            Pointer to the device being detached.
    619      * @param   uPort           The port number assigned to the device.
    620      */
    621     DECLR3CALLBACKMEMBER(void, pfnDetach,(PVUSBIROOTHUBPORT pInterface, PVUSBIDEVICE pDev, unsigned uPort));
    622 
    623     /**
    624      * Reset the root hub.
    625      *
    626      * @returns VBox status code.
    627      * @param   pInterface      Pointer to this structure.
    628      * @param   pResetOnLinux   Whether or not to do real reset on linux.
    629      */
    630     DECLR3CALLBACKMEMBER(int, pfnReset,(PVUSBIROOTHUBPORT pInterface, bool fResetOnLinux));
    631 
    632     /**
    633      * Transfer completion callback routine.
    634      *
    635      * VUSB will call this when a transfer have been completed
    636      * in a one or another way.
    637      *
    638      * @param   pInterface      Pointer to this structure.
    639      * @param   pUrb            Pointer to the URB in question.
    640      */
    641     DECLR3CALLBACKMEMBER(void, pfnXferCompletion,(PVUSBIROOTHUBPORT pInterface, PVUSBURB urb));
    642 
    643     /**
    644      * Handle transfer errors.
    645      *
    646      * VUSB calls this when a transfer attempt failed. This function will respond
    647      * indicating whether to retry or complete the URB with failure.
    648      *
    649      * @returns Retry indicator.
    650      * @param   pInterface      Pointer to this structure.
    651      * @param   pUrb            Pointer to the URB in question.
    652      */
    653     DECLR3CALLBACKMEMBER(bool, pfnXferError,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb));
    654 
    655     /**
    656      * Processes a new frame if periodic frame processing is enabled.
    657      *
    658      * @returns Flag whether there was activity which influences the frame rate.
    659      * @param   pInterface      Pointer to this structure.
    660      * @param   u32FrameNo      The frame number.
    661      */
    662     DECLR3CALLBACKMEMBER(bool, pfnStartFrame, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameNo));
    663 
    664     /**
    665      * Informs the callee about a change in the frame rate due to too many idle cycles or
    666      * when seeing activity after some idle time.
    667      *
    668      * @returns nothing.
    669      * @param   pInterface      Pointer to this structure.
    670      * @param   u32FrameRate    The new frame rate.
    671      */
    672     DECLR3CALLBACKMEMBER(void, pfnFrameRateChanged, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameRate));
    673 
    674     /** Alignment dummy. */
    675     RTR3PTR Alignment;
    676 
    677 } VUSBIROOTHUBPORT;
    678 /** VUSBIROOTHUBPORT interface ID. */
    679 # define VUSBIROOTHUBPORT_IID                   "6571aece-6c33-4714-a8ac-9508a3b8b429"
    680 
    681 /** Pointer to a VUSB RootHub connector interface. */
    682 typedef struct VUSBIROOTHUBCONNECTOR *PVUSBIROOTHUBCONNECTOR;
    683 /**
    684  * The VUSB RootHub connector interface provided by the VBox USB RootHub driver
    685  * (up).
    686  * Pair with VUSBIROOTHUBPORT.
    687  */
    688 typedef struct VUSBIROOTHUBCONNECTOR
    689 {
    690     /**
    691      * Sets the URB parameters for the caller.
    692      *
    693      * @returns VBox status code.
    694      * @param   pInterface  Pointer to this struct.
    695      * @param   cbHci       Size of the data private to the HCI for each URB when allocated.
    696      * @param   cbHciTd     Size of one transfer descriptor. The number of transfer descriptors
    697      *                      is given VUSBIROOTHUBCONNECTOR::pfnNewUrb for each URB to calculate the
    698      *                      final amount of memory required for the TDs.
    699      *
    700      * @note This must be called before starting to allocate any URB or otherwise there will be no
    701      *       data available for the HCI.
    702      */
    703     DECLR3CALLBACKMEMBER(int, pfnSetUrbParams, (PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd));
    704 
    705     /**
    706      * Allocates a new URB for a transfer.
    707      *
    708      * Either submit using pfnSubmitUrb or free using VUSBUrbFree().
    709      *
    710      * @returns Pointer to a new URB.
    711      * @returns NULL on failure - try again later.
    712      *          This will not fail if the device wasn't found. We'll fail it
    713      *          at submit time, since that makes the usage of this api simpler.
    714      * @param   pInterface  Pointer to this struct.
    715      * @param   DstAddress  The destination address of the URB.
    716      * @param   pDev        Optional device pointer the URB is for.
    717      * @param   enmType     Type of the URB.
    718      * @param   enmDir      Data transfer direction.
    719      * @param   cbData      The amount of data space required.
    720      * @param   cTds        The amount of TD space.
    721      * @param   pszTag      Custom URB tag assigned by the caller, only for
    722      *                      logged builds and optional.
    723      *
    724      * @note pDev should be NULL in most cases. The only useful case is for USB3 where
    725      *       it is required for the SET_ADDRESS request because USB3 uses unicast traffic.
    726      */
    727     DECLR3CALLBACKMEMBER(PVUSBURB, pfnNewUrb,(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, PVUSBIDEVICE pDev,
    728                                               VUSBXFERTYPE enmType, VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag));
    729 
    730     /**
    731      * Free an URB not submitted yet.
    732      *
    733      * @returns VBox status code.
    734      * @param   pInterface  Pointer to this struct.
    735      * @param   pUrb        Pointer to the URB to free returned by VUSBIROOTHUBCONNECTOR::pfnNewUrb.
    736      */
    737     DECLR3CALLBACKMEMBER(int, pfnFreeUrb, (PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb));
    738 
    739     /**
    740      * Submits a URB for transfer.
    741      * The transfer will do asynchronously if possible.
    742      *
    743      * @returns VBox status code.
    744      * @param   pInterface  Pointer to this struct.
    745      * @param   pUrb        Pointer to the URB returned by pfnNewUrb.
    746      *                      The URB will be freed in case of failure.
    747      * @param   pLed        Pointer to USB Status LED
    748      */
    749     DECLR3CALLBACKMEMBER(int, pfnSubmitUrb,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed));
    750 
    751     /**
    752      * Call to service asynchronous URB completions in a polling fashion.
    753      *
    754      * Reaped URBs will be finished by calling the completion callback,
    755      * thus there is no return code or input or anything from this function
    756      * except for potential state changes elsewhere.
    757      *
    758      * @returns VINF_SUCCESS if no URBs are pending upon return.
    759      * @returns VERR_TIMEOUT if one or more URBs are still in flight upon returning.
    760      * @returns Other VBox status code.
    761      *
    762      * @param   pInterface  Pointer to this struct.
    763      * @param   pDevice     Pointer to a USB device.
    764      * @param   cMillies    Number of milliseconds to poll for completion.
    765      */
    766     DECLR3CALLBACKMEMBER(void, pfnReapAsyncUrbs,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice, RTMSINTERVAL cMillies));
    767 
    768     /**
    769      * Cancels and completes - with CRC failure - all URBs queued on an endpoint.
    770      * This is done in response to guest URB cancellation.
    771      *
    772      * @returns VBox status code.
    773      * @param   pInterface  Pointer to this struct.
    774      * @param   pUrb        Pointer to a previously submitted URB.
    775      */
    776     DECLR3CALLBACKMEMBER(int, pfnCancelUrbsEp,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb));
    777 
    778     /**
    779      * Cancels and completes - with CRC failure - all in-flight async URBs.
    780      * This is typically done before saving a state.
    781      *
    782      * @param   pInterface  Pointer to this struct.
    783      */
    784     DECLR3CALLBACKMEMBER(void, pfnCancelAllUrbs,(PVUSBIROOTHUBCONNECTOR pInterface));
    785 
    786     /**
    787      * Cancels and completes - with CRC failure - all URBs queued on an endpoint.
    788      * This is done in response to a guest endpoint/pipe abort.
    789      *
    790      * @returns VBox status code.
    791      * @param   pInterface  Pointer to this struct.
    792      * @param   pDevice     Pointer to a USB device.
    793      * @param   EndPt       Endpoint number.
    794      * @param   enmDir      Endpoint direction.
    795      */
    796     DECLR3CALLBACKMEMBER(int, pfnAbortEp,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice, int EndPt, VUSBDIRECTION enmDir));
    797 
    798     /**
    799      * Attach the device to the root hub.
    800      * The device must not be attached to any hub for this call to succeed.
    801      *
    802      * @returns VBox status code.
    803      * @param   pInterface  Pointer to this struct.
    804      * @param   pDevice     Pointer to the device (interface) to attach.
    805      */
    806     DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice));
    807 
    808     /**
    809      * Detach the device from the root hub.
    810      * The device must already be attached for this call to succeed.
    811      *
    812      * @returns VBox status code.
    813      * @param   pInterface  Pointer to this struct.
    814      * @param   pDevice     Pointer to the device (interface) to detach.
    815      */
    816     DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice));
    817 
    818     /**
    819      * Sets periodic frame processing.
    820      *
    821      * @returns VBox status code.
    822      * @param   pInterface  Pointer to this struct.
    823      * @param   uFrameRate  The target frame rate in Hertz, 0 disables periodic frame processing.
    824      *                      The real frame rate might be lower if there is no activity for a certain period or
    825      *                      higher if there is a need for catching up with where the guest expects the device to be.
    826      */
    827     DECLR3CALLBACKMEMBER(int, pfnSetPeriodicFrameProcessing, (PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate));
    828 
    829     /**
    830      * Returns the current frame rate for the periodic frame processing.
    831      *
    832      * @returns Frame rate for periodic frame processing.
    833      * @retval  0 if disabled.
    834      * @param   pInterface  Pointer to this struct.
    835      */
    836     DECLR3CALLBACKMEMBER(uint32_t, pfnGetPeriodicFrameRate, (PVUSBIROOTHUBCONNECTOR pInterface));
    837 
    838     /**
    839      * Updates the internally stored isochronous scheduling frame for a given
    840      * endpoint and returns the delta between the current and previous frame.
    841      *
    842      * @returns Delta between currently and previously scheduled frame.
    843      * @retval  0 if no previous frame was set.
    844      * @param   pInterface  Pointer to this struct.
    845      * @param   pDevice     Pointer to a USB device.
    846      * @param   EndPt       Endpoint number.
    847      * @param   enmDir      Endpoint direction.
    848      * @param   uNewFrameID The frame ID of a new transfer.
    849      * @param   uBits       The number of significant bits in frame ID.
    850      */
    851     DECLR3CALLBACKMEMBER(uint32_t, pfnUpdateIsocFrameDelta, (PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice,
    852                                                              int EndPt, VUSBDIRECTION enmDir, uint16_t uNewFrameID, uint8_t uBits));
    853 
    854     /** Alignment dummy. */
    855     RTR3PTR Alignment;
    856 
    857 } VUSBIROOTHUBCONNECTOR;
    858 AssertCompileSizeAlignment(VUSBIROOTHUBCONNECTOR, 8);
    859 /** VUSBIROOTHUBCONNECTOR interface ID. */
    860 # define VUSBIROOTHUBCONNECTOR_IID              "662d7822-b9c6-43b5-88b6-5d59f0106e46"
    861 
    862 
    863 # ifdef IN_RING3
    864 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetUrbParams */
    865 DECLINLINE(int) VUSBIRhSetUrbParams(PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd)
    866 {
    867     return pInterface->pfnSetUrbParams(pInterface, cbHci, cbHciTd);
    868 }
    869 
    870 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnNewUrb */
    871 DECLINLINE(PVUSBURB) VUSBIRhNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, PVUSBIDEVICE pDev,
    872                                    VUSBXFERTYPE enmType, VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag)
    873 {
    874     return pInterface->pfnNewUrb(pInterface, DstAddress, pDev, enmType, enmDir, cbData, cTds, pszTag);
    875 }
    876 
    877 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnFreeUrb */
    878 DECLINLINE(int) VUSBIRhFreeUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb)
    879 {
    880     return pInterface->pfnFreeUrb(pInterface, pUrb);
    881 }
    882 
    883 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnSubmitUrb */
    884 DECLINLINE(int) VUSBIRhSubmitUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed)
    885 {
    886     return pInterface->pfnSubmitUrb(pInterface, pUrb, pLed);
    887 }
    888 
    889 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnReapAsyncUrbs */
    890 DECLINLINE(void) VUSBIRhReapAsyncUrbs(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice, RTMSINTERVAL cMillies)
    891 {
    892     pInterface->pfnReapAsyncUrbs(pInterface, pDevice, cMillies);
    893 }
    894 
    895 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnCancelAllUrbs */
    896 DECLINLINE(void) VUSBIRhCancelAllUrbs(PVUSBIROOTHUBCONNECTOR pInterface)
    897 {
    898     pInterface->pfnCancelAllUrbs(pInterface);
    899 }
    900 
    901 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnAttachDevice */
    902 DECLINLINE(int) VUSBIRhAttachDevice(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)
    903 {
    904     return pInterface->pfnAttachDevice(pInterface, pDevice);
    905 }
    906 
    907 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnDetachDevice */
    908 DECLINLINE(int) VUSBIRhDetachDevice(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)
    909 {
    910     return pInterface->pfnDetachDevice(pInterface, pDevice);
    911 }
    912 
    913 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetPeriodicFrameProcessing */
    914 DECLINLINE(int) VUSBIRhSetPeriodicFrameProcessing(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate)
    915 {
    916     return pInterface->pfnSetPeriodicFrameProcessing(pInterface, uFrameRate);
    917 }
    918 
    919 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnGetPeriodicFrameRate */
    920 DECLINLINE(uint32_t) VUSBIRhGetPeriodicFrameRate(PVUSBIROOTHUBCONNECTOR pInterface)
    921 {
    922     return pInterface->pfnGetPeriodicFrameRate(pInterface);
    923 }
    924 # endif /* IN_RING3 */
    925 
    926 #endif /* ! RDESKTOP */
    927 
    928 
    929566/**
    930567 * VUSB device reset completion callback function.
     
    932569 *
    933570 * @param   pDevice Pointer to the virtual USB device core.
     571 * @param   uPort   The port of the device which completed the reset.
    934572 * @param   rc      The VBox status code of the reset operation.
    935573 * @param   pvUser  User specific argument.
     
    937575 * @thread  The reset thread or EMT.
    938576 */
    939 typedef DECLCALLBACKTYPE(void, FNVUSBRESETDONE,(PVUSBIDEVICE pDevice, int rc, void *pvUser));
     577typedef DECLCALLBACKTYPE(void, FNVUSBRESETDONE,(PVUSBIDEVICE pDevice, uint32_t uPort, int rc, void *pvUser));
    940578/** Pointer to a device reset completion callback function (FNUSBRESETDONE). */
    941579typedef FNVUSBRESETDONE *PFNVUSBRESETDONE;
     580
    942581
    943582/**
     
    965604    VUSB_DEVICE_STATE_32BIT_HACK = 0x7fffffff
    966605} VUSBDEVICESTATE;
     606
     607
     608/** Maximum number of USB devices supported. */
     609#define VUSB_DEVICES_MAX            128
     610/** An invalid device port. */
     611#define VUSB_DEVICE_PORT_INVALID    UINT32_MAX
     612
     613/**
     614 * VBox USB port bitmap.
     615 *
     616 * Bit 0 == Port 0, ... , Bit 127 == Port 127.
     617 */
     618typedef struct VUSBPORTBITMAP
     619{
     620    /** 128 bits */
     621    char ach[VUSB_DEVICES_MAX / 8];
     622} VUSBPORTBITMAP;
     623/** Pointer to a VBox USB port bitmap. */
     624typedef VUSBPORTBITMAP *PVUSBPORTBITMAP;
     625AssertCompile(sizeof(VUSBPORTBITMAP) * 8 >= VUSB_DEVICES_MAX);
     626
     627#ifndef RDESKTOP
     628
     629/**
     630 * The VUSB RootHub port interface provided by the HCI (down).
     631 * Pair with VUSBIROOTCONNECTOR
     632 */
     633typedef struct VUSBIROOTHUBPORT
     634{
     635    /**
     636     * Get the number of available ports in the hub.
     637     *
     638     * @returns The number of ports available.
     639     * @param   pInterface      Pointer to this structure.
     640     * @param   pAvailable      Bitmap indicating the available ports. Set bit == available port.
     641     */
     642    DECLR3CALLBACKMEMBER(unsigned, pfnGetAvailablePorts,(PVUSBIROOTHUBPORT pInterface, PVUSBPORTBITMAP pAvailable));
     643
     644    /**
     645     * Gets the supported USB versions.
     646     *
     647     * @returns The mask of supported USB versions.
     648     * @param   pInterface      Pointer to this structure.
     649     */
     650    DECLR3CALLBACKMEMBER(uint32_t, pfnGetUSBVersions,(PVUSBIROOTHUBPORT pInterface));
     651
     652    /**
     653     * A device is being attached to a port in the roothub.
     654     *
     655     * @param   pInterface      Pointer to this structure.
     656     * @param   uPort           The port number assigned to the device.
     657     * @param   enmSpeed        The speed of the device being attached.
     658     */
     659    DECLR3CALLBACKMEMBER(int, pfnAttach,(PVUSBIROOTHUBPORT pInterface, uint32_t uPort, VUSBSPEED enmSpeed));
     660
     661    /**
     662     * A device is being detached from a port in the roothub.
     663     *
     664     * @param   pInterface      Pointer to this structure.
     665     * @param   uPort           The port number assigned to the device.
     666     */
     667    DECLR3CALLBACKMEMBER(void, pfnDetach,(PVUSBIROOTHUBPORT pInterface, uint32_t uPort));
     668
     669    /**
     670     * Reset the root hub.
     671     *
     672     * @returns VBox status code.
     673     * @param   pInterface      Pointer to this structure.
     674     * @param   fResetOnLinux   Whether or not to do real reset on linux.
     675     */
     676    DECLR3CALLBACKMEMBER(int, pfnReset,(PVUSBIROOTHUBPORT pInterface, bool fResetOnLinux));
     677
     678    /**
     679     * Transfer completion callback routine.
     680     *
     681     * VUSB will call this when a transfer have been completed
     682     * in a one or another way.
     683     *
     684     * @param   pInterface      Pointer to this structure.
     685     * @param   pUrb            Pointer to the URB in question.
     686     */
     687    DECLR3CALLBACKMEMBER(void, pfnXferCompletion,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb));
     688
     689    /**
     690     * Handle transfer errors.
     691     *
     692     * VUSB calls this when a transfer attempt failed. This function will respond
     693     * indicating whether to retry or complete the URB with failure.
     694     *
     695     * @returns Retry indicator.
     696     * @param   pInterface      Pointer to this structure.
     697     * @param   pUrb            Pointer to the URB in question.
     698     */
     699    DECLR3CALLBACKMEMBER(bool, pfnXferError,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb));
     700
     701    /**
     702     * Processes a new frame if periodic frame processing is enabled.
     703     *
     704     * @returns Flag whether there was activity which influences the frame rate.
     705     * @param   pInterface      Pointer to this structure.
     706     * @param   u32FrameNo      The frame number.
     707     */
     708    DECLR3CALLBACKMEMBER(bool, pfnStartFrame, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameNo));
     709
     710    /**
     711     * Informs the callee about a change in the frame rate due to too many idle cycles or
     712     * when seeing activity after some idle time.
     713     *
     714     * @returns nothing.
     715     * @param   pInterface      Pointer to this structure.
     716     * @param   u32FrameRate    The new frame rate.
     717     */
     718    DECLR3CALLBACKMEMBER(void, pfnFrameRateChanged, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameRate));
     719
     720    /** Alignment dummy. */
     721    RTR3PTR Alignment;
     722
     723} VUSBIROOTHUBPORT;
     724/** VUSBIROOTHUBPORT interface ID. */
     725# define VUSBIROOTHUBPORT_IID                   "2ece01c2-4dbf-4bd5-96ca-09fc14164cd4"
     726
     727/** Pointer to a VUSB RootHub connector interface. */
     728typedef struct VUSBIROOTHUBCONNECTOR *PVUSBIROOTHUBCONNECTOR;
     729/**
     730 * The VUSB RootHub connector interface provided by the VBox USB RootHub driver
     731 * (up).
     732 * Pair with VUSBIROOTHUBPORT.
     733 */
     734typedef struct VUSBIROOTHUBCONNECTOR
     735{
     736    /**
     737     * Sets the URB parameters for the caller.
     738     *
     739     * @returns VBox status code.
     740     * @param   pInterface  Pointer to this struct.
     741     * @param   cbHci       Size of the data private to the HCI for each URB when allocated.
     742     * @param   cbHciTd     Size of one transfer descriptor. The number of transfer descriptors
     743     *                      is given VUSBIROOTHUBCONNECTOR::pfnNewUrb for each URB to calculate the
     744     *                      final amount of memory required for the TDs.
     745     *
     746     * @note This must be called before starting to allocate any URB or otherwise there will be no
     747     *       data available for the HCI.
     748     */
     749    DECLR3CALLBACKMEMBER(int, pfnSetUrbParams, (PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd));
     750
     751    /**
     752     * Resets the roothub.
     753     *
     754     * @returns VBox status code.
     755     * @param   pInterface      Pointer to this struct.
     756     * @param   fResetOnLinux   Whether or not to do real reset on linux.
     757     */
     758    DECLR3CALLBACKMEMBER(int, pfnReset, (PVUSBIROOTHUBCONNECTOR pInterface, bool fResetOnLinux));
     759
     760    /**
     761     * Powers on the roothub.
     762     *
     763     * @returns VBox status code.
     764     * @param   pInterface  Pointer to this struct.
     765     */
     766    DECLR3CALLBACKMEMBER(int, pfnPowerOn, (PVUSBIROOTHUBCONNECTOR pInterface));
     767
     768    /**
     769     * Power off the roothub.
     770     *
     771     * @returns VBox status code.
     772     * @param   pInterface  Pointer to this struct.
     773     */
     774    DECLR3CALLBACKMEMBER(int, pfnPowerOff, (PVUSBIROOTHUBCONNECTOR pInterface));
     775
     776    /**
     777     * Allocates a new URB for a transfer.
     778     *
     779     * Either submit using pfnSubmitUrb or free using VUSBUrbFree().
     780     *
     781     * @returns Pointer to a new URB.
     782     * @returns NULL on failure - try again later.
     783     *          This will not fail if the device wasn't found. We'll fail it
     784     *          at submit time, since that makes the usage of this api simpler.
     785     * @param   pInterface  Pointer to this struct.
     786     * @param   DstAddress  The destination address of the URB.
     787     * @param   uPort       Optional port of the device the URB is for, use VUSB_DEVICE_PORT_INVALID to indicate to use the destination address.
     788     * @param   enmType     Type of the URB.
     789     * @param   enmDir      Data transfer direction.
     790     * @param   cbData      The amount of data space required.
     791     * @param   cTds        The amount of TD space.
     792     * @param   pszTag      Custom URB tag assigned by the caller, only for
     793     *                      logged builds and optional.
     794     *
     795     * @note pDev should be NULL in most cases. The only useful case is for USB3 where
     796     *       it is required for the SET_ADDRESS request because USB3 uses unicast traffic.
     797     */
     798    DECLR3CALLBACKMEMBER(PVUSBURB, pfnNewUrb,(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t uPort,
     799                                              VUSBXFERTYPE enmType, VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag));
     800
     801    /**
     802     * Free an URB not submitted yet.
     803     *
     804     * @returns VBox status code.
     805     * @param   pInterface  Pointer to this struct.
     806     * @param   pUrb        Pointer to the URB to free returned by VUSBIROOTHUBCONNECTOR::pfnNewUrb.
     807     */
     808    DECLR3CALLBACKMEMBER(int, pfnFreeUrb, (PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb));
     809
     810    /**
     811     * Submits a URB for transfer.
     812     * The transfer will do asynchronously if possible.
     813     *
     814     * @returns VBox status code.
     815     * @param   pInterface  Pointer to this struct.
     816     * @param   pUrb        Pointer to the URB returned by pfnNewUrb.
     817     *                      The URB will be freed in case of failure.
     818     * @param   pLed        Pointer to USB Status LED
     819     */
     820    DECLR3CALLBACKMEMBER(int, pfnSubmitUrb,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed));
     821
     822    /**
     823     * Call to service asynchronous URB completions in a polling fashion.
     824     *
     825     * Reaped URBs will be finished by calling the completion callback,
     826     * thus there is no return code or input or anything from this function
     827     * except for potential state changes elsewhere.
     828     *
     829     * @returns VINF_SUCCESS if no URBs are pending upon return.
     830     * @returns VERR_TIMEOUT if one or more URBs are still in flight upon returning.
     831     * @returns Other VBox status code.
     832     *
     833     * @param   pInterface  Pointer to this struct.
     834     * @param   uPort       Port of the device to reap URBs on.
     835     * @param   cMillies    Number of milliseconds to poll for completion.
     836     */
     837    DECLR3CALLBACKMEMBER(void, pfnReapAsyncUrbs,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, RTMSINTERVAL cMillies));
     838
     839    /**
     840     * Cancels and completes - with CRC failure - all URBs queued on an endpoint.
     841     * This is done in response to guest URB cancellation.
     842     *
     843     * @returns VBox status code.
     844     * @param   pInterface  Pointer to this struct.
     845     * @param   pUrb        Pointer to a previously submitted URB.
     846     */
     847    DECLR3CALLBACKMEMBER(int, pfnCancelUrbsEp,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb));
     848
     849    /**
     850     * Cancels and completes - with CRC failure - all in-flight async URBs.
     851     * This is typically done before saving a state.
     852     *
     853     * @param   pInterface  Pointer to this struct.
     854     */
     855    DECLR3CALLBACKMEMBER(void, pfnCancelAllUrbs,(PVUSBIROOTHUBCONNECTOR pInterface));
     856
     857    /**
     858     * Cancels and completes - with CRC failure - all URBs queued on an endpoint.
     859     * This is done in response to a guest endpoint/pipe abort.
     860     *
     861     * @returns VBox status code.
     862     * @param   pInterface  Pointer to this struct.
     863     * @param   uPort       Port of the device.
     864     * @param   EndPt       Endpoint number.
     865     * @param   enmDir      Endpoint direction.
     866     */
     867    DECLR3CALLBACKMEMBER(int, pfnAbortEp,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, int EndPt, VUSBDIRECTION enmDir));
     868
     869    /**
     870     * Attach the device to the root hub.
     871     * The device must not be attached to any hub for this call to succeed.
     872     *
     873     * @returns VBox status code.
     874     * @param   pInterface  Pointer to this struct.
     875     * @param   uPort       Port of the device to attach.
     876     */
     877    DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort));
     878
     879    /**
     880     * Detach the device from the root hub.
     881     * The device must already be attached for this call to succeed.
     882     *
     883     * @returns VBox status code.
     884     * @param   pInterface  Pointer to this struct.
     885     * @param   uPort       Port of the device to detach.
     886     */
     887    DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort));
     888
     889    /**
     890     * Sets periodic frame processing.
     891     *
     892     * @returns VBox status code.
     893     * @param   pInterface  Pointer to this struct.
     894     * @param   uFrameRate  The target frame rate in Hertz, 0 disables periodic frame processing.
     895     *                      The real frame rate might be lower if there is no activity for a certain period or
     896     *                      higher if there is a need for catching up with where the guest expects the device to be.
     897     */
     898    DECLR3CALLBACKMEMBER(int, pfnSetPeriodicFrameProcessing, (PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate));
     899
     900    /**
     901     * Returns the current frame rate for the periodic frame processing.
     902     *
     903     * @returns Frame rate for periodic frame processing.
     904     * @retval  0 if disabled.
     905     * @param   pInterface  Pointer to this struct.
     906     */
     907    DECLR3CALLBACKMEMBER(uint32_t, pfnGetPeriodicFrameRate, (PVUSBIROOTHUBCONNECTOR pInterface));
     908
     909    /**
     910     * Updates the internally stored isochronous scheduling frame for a given
     911     * endpoint and returns the delta between the current and previous frame.
     912     *
     913     * @returns Delta between currently and previously scheduled frame.
     914     * @retval  0 if no previous frame was set.
     915     * @param   pInterface  Pointer to this struct.
     916     * @param   uPort       Port of the device.
     917     * @param   EndPt       Endpoint number.
     918     * @param   enmDir      Endpoint direction.
     919     * @param   uNewFrameID The frame ID of a new transfer.
     920     * @param   uBits       The number of significant bits in frame ID.
     921     */
     922    DECLR3CALLBACKMEMBER(uint32_t, pfnUpdateIsocFrameDelta, (PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort,
     923                                                             int EndPt, VUSBDIRECTION enmDir, uint16_t uNewFrameID, uint8_t uBits));
     924
     925    /**
     926     * Resets the device.
     927     *
     928     * Since a device reset shall take at least 10ms from the guest point of view,
     929     * it must be performed asynchronously. We create a thread which performs this
     930     * operation and ensures it will take at least 10ms.
     931     *
     932     * At times - like init - a synchronous reset is required, this can be done
     933     * by passing NULL for pfnDone.
     934     *
     935     * -- internal stuff, move it --
     936     * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state.
     937     * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful,
     938     * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed.
     939     * -- internal stuff, move it --
     940     *
     941     * @returns VBox status code.
     942     * @param   pInterface      Pointer to this struct.
     943     * @param   uPort           Port of the device to reset.
     944     * @param   fResetOnLinux   Set if we can permit a real reset and a potential logical
     945     *                          device reconnect on linux hosts.
     946     * @param   pfnDone         Pointer to the completion routine. If NULL a synchronous
     947     *                          reset  is performed not respecting the 10ms.
     948     * @param   pvUser          User argument to the completion routine.
     949     * @param   pVM             The cross context VM structure.  Required if pfnDone
     950     *                          is not NULL.
     951     */
     952    DECLR3CALLBACKMEMBER(int, pfnDevReset,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, bool fResetOnLinux,
     953                                           PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM));
     954
     955    /**
     956     * Powers on the device.
     957     *
     958     * @returns VBox status code.
     959     * @param   pInterface      Pointer to this struct.
     960     * @param   uPort           Port of the device to power on.
     961     */
     962    DECLR3CALLBACKMEMBER(int, pfnDevPowerOn,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort));
     963
     964    /**
     965     * Powers off the device.
     966     *
     967     * @returns VBox status code.
     968     * @param   pInterface      Pointer to this struct.
     969     * @param   uPort           Port of the device to power off.
     970     */
     971    DECLR3CALLBACKMEMBER(int, pfnDevPowerOff,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort));
     972
     973    /**
     974     * Get the state of the device.
     975     *
     976     * @returns Device state.
     977     * @param   pInterface      Pointer to this struct.
     978     * @param   uPort           Port of the device to get the state for.
     979     */
     980    DECLR3CALLBACKMEMBER(VUSBDEVICESTATE, pfnDevGetState,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort));
     981
     982    /**
     983     * Returns whether the device implements the saved state handlers
     984     * and doesn't need to get detached.
     985     *
     986     * @returns true if the device supports saving the state, false otherwise.
     987     * @param   pInterface      Pointer to this struct.
     988     * @param   uPort           Port of the device to query saved state support for.
     989     */
     990    DECLR3CALLBACKMEMBER(bool, pfnDevIsSavedStateSupported,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort));
     991
     992    /**
     993     * Get the speed the device is operating at.
     994     *
     995     * @returns Device state.
     996     * @param   pInterface      Pointer to this struct.
     997     * @param   uPort           Port of the device to query the speed for.
     998     */
     999    DECLR3CALLBACKMEMBER(VUSBSPEED, pfnDevGetSpeed,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort));
     1000
     1001} VUSBIROOTHUBCONNECTOR;
     1002AssertCompileSizeAlignment(VUSBIROOTHUBCONNECTOR, 8);
     1003/** VUSBIROOTHUBCONNECTOR interface ID. */
     1004# define VUSBIROOTHUBCONNECTOR_IID              "662d7822-b9c6-43b5-88b6-5d59f0106e46"
     1005
     1006
     1007# ifdef IN_RING3
     1008/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetUrbParams */
     1009DECLINLINE(int) VUSBIRhSetUrbParams(PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd)
     1010{
     1011    return pInterface->pfnSetUrbParams(pInterface, cbHci, cbHciTd);
     1012}
     1013
     1014/** @copydoc VUSBIROOTHUBCONNECTOR::pfnNewUrb */
     1015DECLINLINE(PVUSBURB) VUSBIRhNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t uPort,
     1016                                   VUSBXFERTYPE enmType, VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag)
     1017{
     1018    return pInterface->pfnNewUrb(pInterface, DstAddress, uPort, enmType, enmDir, cbData, cTds, pszTag);
     1019}
     1020
     1021/** @copydoc VUSBIROOTHUBCONNECTOR::pfnFreeUrb */
     1022DECLINLINE(int) VUSBIRhFreeUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb)
     1023{
     1024    return pInterface->pfnFreeUrb(pInterface, pUrb);
     1025}
     1026
     1027/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSubmitUrb */
     1028DECLINLINE(int) VUSBIRhSubmitUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed)
     1029{
     1030    return pInterface->pfnSubmitUrb(pInterface, pUrb, pLed);
     1031}
     1032
     1033/** @copydoc VUSBIROOTHUBCONNECTOR::pfnReapAsyncUrbs */
     1034DECLINLINE(void) VUSBIRhReapAsyncUrbs(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, RTMSINTERVAL cMillies)
     1035{
     1036    pInterface->pfnReapAsyncUrbs(pInterface, uPort, cMillies);
     1037}
     1038
     1039/** @copydoc VUSBIROOTHUBCONNECTOR::pfnCancelAllUrbs */
     1040DECLINLINE(void) VUSBIRhCancelAllUrbs(PVUSBIROOTHUBCONNECTOR pInterface)
     1041{
     1042    pInterface->pfnCancelAllUrbs(pInterface);
     1043}
     1044
     1045/** @copydoc VUSBIROOTHUBCONNECTOR::pfnAttachDevice */
     1046DECLINLINE(int) VUSBIRhAttachDevice(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1047{
     1048    return pInterface->pfnAttachDevice(pInterface, uPort);
     1049}
     1050
     1051/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDetachDevice */
     1052DECLINLINE(int) VUSBIRhDetachDevice(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1053{
     1054    return pInterface->pfnDetachDevice(pInterface, uPort);
     1055}
     1056
     1057/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetPeriodicFrameProcessing */
     1058DECLINLINE(int) VUSBIRhSetPeriodicFrameProcessing(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate)
     1059{
     1060    return pInterface->pfnSetPeriodicFrameProcessing(pInterface, uFrameRate);
     1061}
     1062
     1063/** @copydoc VUSBIROOTHUBCONNECTOR::pfnGetPeriodicFrameRate */
     1064DECLINLINE(uint32_t) VUSBIRhGetPeriodicFrameRate(PVUSBIROOTHUBCONNECTOR pInterface)
     1065{
     1066    return pInterface->pfnGetPeriodicFrameRate(pInterface);
     1067}
     1068
     1069/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevReset */
     1070DECLINLINE(int) VUSBIRhDevReset(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, bool fResetOnLinux,
     1071                                PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
     1072{
     1073    return pInterface->pfnDevReset(pInterface, uPort, fResetOnLinux, pfnDone, pvUser, pVM);
     1074}
     1075
     1076/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevPowerOn */
     1077DECLINLINE(int) VUSBIRhDevPowerOn(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1078{
     1079    return pInterface->pfnDevPowerOn(pInterface, uPort);
     1080}
     1081
     1082/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevPowerOff */
     1083DECLINLINE(int) VUSBIRhDevPowerOff(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1084{
     1085    return pInterface->pfnDevPowerOff(pInterface, uPort);
     1086}
     1087
     1088/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetState */
     1089DECLINLINE(VUSBDEVICESTATE) VUSBIRhDevGetState(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1090{
     1091    return pInterface->pfnDevGetState(pInterface, uPort);
     1092}
     1093
     1094/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetState */
     1095DECLINLINE(bool) VUSBIRhDevIsSavedStateSupported(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1096{
     1097    return pInterface->pfnDevIsSavedStateSupported(pInterface, uPort);
     1098}
     1099
     1100/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetSpeed */
     1101DECLINLINE(VUSBSPEED) VUSBIRhDevGetSpeed(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)
     1102{
     1103    return pInterface->pfnDevGetSpeed(pInterface, uPort);
     1104}
     1105# endif /* IN_RING3 */
     1106
     1107#endif /* ! RDESKTOP */
     1108
    9671109
    9681110#ifndef RDESKTOP
  • trunk/src/VBox/Devices/USB/DevOHCI.cpp

    r93115 r93914  
    136136/* Macro to query the number of currently configured ports. */
    137137#define OHCI_NDP_CFG(pohci) ((pohci)->RootHub.desc_a & OHCI_RHA_NDP)
     138/** Macro to convert a EHCI port index (zero based) to a VUSB roothub port ID (one based). */
     139#define OHCI_PORT_2_VUSB_PORT(a_uPort) ((a_uPort) + 1)
    138140
    139141/** Pointer to OHCI device data. */
     
    180182    /** The port register. */
    181183    uint32_t                fReg;
    182 #if HC_ARCH_BITS == 64
    183     uint32_t                Alignment0; /**< Align the pointer correctly. */
    184 #endif
    185     /** The device attached to the port. */
    186     R3PTRTYPE(PVUSBIDEVICE) pDev;
     184    /** Flag whether there is a device attached to the port. */
     185    bool                    fAttached;
     186    bool                    afPadding[3];
    187187} OHCIHUBPORT;
    188 #if HC_ARCH_BITS == 64
    189 AssertCompile(sizeof(OHCIHUBPORT) == 16); /* saved state */
    190 #endif
    191188/** Pointer to an OHCI hub port. */
    192189typedef OHCIHUBPORT *POHCIHUBPORT;
     
    222219    /** Pointer to the connector interface of the VUSB RootHub. */
    223220    R3PTRTYPE(PVUSBIROOTHUBCONNECTOR)   pIRhConn;
    224     /** Pointer to the device interface of the VUSB RootHub. */
    225     R3PTRTYPE(PVUSBIDEVICE)             pIDev;
    226221    /** The base interface exposed to the roothub driver. */
    227222    PDMIBASE                            IBase;
     
    241236/** Pointer to the OHCI ring-3 root hub data. */
    242237typedef OHCIROOTHUBR3 *POHCIROOTHUBR3;
    243 
    244 
    245 /**
    246  * Data used for reattaching devices on a state load.
    247  */
    248 typedef struct OHCILOAD
    249 {
    250     /** Timer used once after state load to inform the guest about new devices.
    251      * We do this to be sure the guest get any disconnect / reconnect on the
    252      * same port. */
    253     TMTIMERHANDLE       hTimer;
    254     /** Number of detached devices. */
    255     unsigned            cDevs;
    256     /** Array of devices which were detached. */
    257     PVUSBIDEVICE apDevs[OHCI_NDP_MAX];
    258 } OHCILOAD;
    259 /** Pointer to an OHCILOAD structure. */
    260 typedef OHCILOAD *POHCILOAD;
    261238
    262239#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     
    283260    uint32_t            fno : 1;
    284261
     262    /** Align roothub structure on a 8-byte boundary. */
     263    uint32_t            u32Alignment0;
    285264    /** Root hub device, shared data. */
    286265    OHCIROOTHUB         RootHub;
     
    423402    RTCRITSECT          CritSect;
    424403
    425     /** Pointer to state load data. */
    426     R3PTRTYPE(POHCILOAD) pLoad;
    427404    /** The restored periodic frame rate. */
    428405    uint32_t             uRestoredPeriodicFrameRate;
     
    890867#ifdef IN_RING3
    891868/* Update host controller state to reflect a device attach */
    892 static void                 ohciR3RhPortPower(POHCIROOTHUB pRh, unsigned iPort, bool fPowerUp);
     869static void                 ohciR3RhPortPower(POHCIROOTHUBR3 pRh, unsigned iPort, bool fPowerUp);
    893870static void                 ohciR3BusResume(PPDMDEVINS pDevIns, POHCI pOhci, POHCICC pThisCC, bool fHardware);
    894871static void                 ohciR3BusStop(POHCICC pThisCC);
     
    10401017
    10411018    for (unsigned iPort = 0; iPort < OHCI_NDP_CFG(pThis); iPort++)
    1042         if (!pThis->RootHub.aPorts[iPort].pDev)
     1019        if (!pThis->RootHub.aPorts[iPort].fAttached)
    10431020        {
    10441021            cPorts++;
     
    10641041
    10651042
    1066 /**
    1067  * A device is being attached to a port in the roothub.
    1068  *
    1069  * @param   pInterface      Pointer to this structure.
    1070  * @param   pDev            Pointer to the device being attached.
    1071  * @param   uPort           The port number assigned to the device.
    1072  */
    1073 static DECLCALLBACK(int) ohciR3RhAttach(PVUSBIROOTHUBPORT pInterface, PVUSBIDEVICE pDev, unsigned uPort)
     1043/** @interface_method_impl{VUSBIROOTHUBPORT,pfnAttach} */
     1044static DECLCALLBACK(int) ohciR3RhAttach(PVUSBIROOTHUBPORT pInterface, uint32_t uPort, VUSBSPEED enmSpeed)
    10741045{
    10751046    POHCICC    pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
    10761047    PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
    10771048    POHCI      pThis   = PDMDEVINS_2_DATA(pDevIns, POHCI);
    1078     VUSBSPEED  enmSpeed;
    1079     LogFlow(("ohciR3RhAttach: pDev=%p uPort=%u\n", pDev, uPort));
     1049    LogFlow(("ohciR3RhAttach: uPort=%u\n", uPort));
    10801050    int const  rcLock  = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
    10811051    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
     
    10861056    Assert(uPort >= 1 && uPort <= OHCI_NDP_CFG(pThis));
    10871057    uPort--;
    1088     Assert(!pThis->RootHub.aPorts[uPort].pDev);
    1089     enmSpeed = pDev->pfnGetSpeed(pDev);
     1058    Assert(!pThis->RootHub.aPorts[uPort].fAttached);
    10901059    /* Only LS/FS devices should end up here. */
    10911060    Assert(enmSpeed == VUSB_SPEED_LOW || enmSpeed == VUSB_SPEED_FULL);
     
    10971066    if (enmSpeed == VUSB_SPEED_LOW)
    10981067        pThis->RootHub.aPorts[uPort].fReg |= OHCI_PORT_LSDA;
    1099     pThis->RootHub.aPorts[uPort].pDev = pDev;
    1100     ohciR3RhPortPower(&pThis->RootHub, uPort, 1 /* power on */);
     1068    pThis->RootHub.aPorts[uPort].fAttached = true;
     1069    ohciR3RhPortPower(&pThisCC->RootHub, uPort, 1 /* power on */);
    11011070
    11021071    ohciR3RemoteWakeup(pDevIns, pThis, pThisCC);
     
    11121081 *
    11131082 * @param   pInterface      Pointer to this structure.
    1114  * @param   pDev            Pointer to the device being detached.
    11151083 * @param   uPort           The port number assigned to the device.
    11161084 */
    1117 static DECLCALLBACK(void) ohciR3RhDetach(PVUSBIROOTHUBPORT pInterface, PVUSBIDEVICE pDev, unsigned uPort)
     1085static DECLCALLBACK(void) ohciR3RhDetach(PVUSBIROOTHUBPORT pInterface, uint32_t uPort)
    11181086{
    11191087    POHCICC    pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
    11201088    PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
    11211089    POHCI      pThis   = PDMDEVINS_2_DATA(pDevIns, POHCI);
    1122     RT_NOREF(pDev);
    1123     LogFlow(("ohciR3RhDetach: pDev=%p uPort=%u\n", pDev, uPort));
     1090    LogFlow(("ohciR3RhDetach: uPort=%u\n", uPort));
    11241091    int const  rcLock  = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
    11251092    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
     
    11301097    Assert(uPort >= 1 && uPort <= OHCI_NDP_CFG(pThis));
    11311098    uPort--;
    1132     Assert(pThis->RootHub.aPorts[uPort].pDev == pDev);
     1099    Assert(pThis->RootHub.aPorts[uPort].fAttached);
    11331100
    11341101    /*
    11351102     * Detach it.
    11361103     */
    1137     pThis->RootHub.aPorts[uPort].pDev = NULL;
     1104    pThis->RootHub.aPorts[uPort].fAttached = false;
    11381105    if (pThis->RootHub.aPorts[uPort].fReg & OHCI_PORT_PES)
    11391106        pThis->RootHub.aPorts[uPort].fReg = OHCI_PORT_CSC | OHCI_PORT_PESC;
     
    11561123 *
    11571124 * @param pDev      The root hub device.
     1125 * @param uPort     The port of the device completing the reset.
    11581126 * @param rc        The result of the operation.
    11591127 * @param pvUser    Pointer to the controller.
    11601128 */
    1161 static DECLCALLBACK(void) ohciR3RhResetDoneOneDev(PVUSBIDEVICE pDev, int rc, void *pvUser)
     1129static DECLCALLBACK(void) ohciR3RhResetDoneOneDev(PVUSBIDEVICE pDev, uint32_t uPort, int rc, void *pvUser)
    11621130{
    11631131    LogRel(("OHCI: root hub reset completed with %Rrc\n", rc));
    1164     NOREF(pDev); NOREF(rc); NOREF(pvUser);
     1132    RT_NOREF(pDev, uPort, rc, pvUser);
    11651133}
    11661134
     
    12051173    for (unsigned iPort = 0; iPort < OHCI_NDP_CFG(pThis); iPort++)
    12061174    {
    1207         if (pThis->RootHub.aPorts[iPort].pDev)
     1175        if (pThis->RootHub.aPorts[iPort].fAttached)
    12081176        {
    12091177            pThis->RootHub.aPorts[iPort].fReg = OHCI_PORT_CCS | OHCI_PORT_CSC | OHCI_PORT_PPS;
     
    12111179            {
    12121180                PVM pVM = PDMDevHlpGetVM(pDevIns);
    1213                 VUSBIDevReset(pThis->RootHub.aPorts[iPort].pDev, fResetOnLinux, ohciR3RhResetDoneOneDev, pThis, pVM);
     1181                VUSBIRhDevReset(pThisCC->RootHub.pIRhConn, OHCI_PORT_2_VUSB_PORT(iPort), fResetOnLinux,
     1182                                ohciR3RhResetDoneOneDev, pThis, pVM);
    12141183            }
    12151184        }
     
    13101279     */
    13111280    if (fNewMode == OHCI_USB_RESET)
    1312         VUSBIDevReset(pThisCC->RootHub.pIDev, fResetOnLinux, NULL, NULL, NULL);
     1281        pThisCC->RootHub.pIRhConn->pfnReset(pThisCC->RootHub.pIRhConn, fResetOnLinux);
    13131282}
    13141283
     
    30953064     * Allocate and initialize a new URB.
    30963065     */
    3097     PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, NULL,
     3066    PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, VUSB_DEVICE_PORT_INVALID,
    30983067                                  enmType, enmDir, Buf.cbTotal, 1, NULL);
    30993068    if (!pUrb)
     
    32653234     * Allocate and initialize a new URB.
    32663235     */
    3267     PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, NULL,
     3236    PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, VUSB_DEVICE_PORT_INVALID,
    32683237                                  enmType, enmDir, cbTotal, cTds, "ohciR3ServiceTdMultiple");
    32693238    if (!pUrb)
     
    34993468     * Allocate and initialize a new URB.
    35003469     */
    3501     PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, NULL,
     3470    PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, VUSB_DEVICE_PORT_INVALID,
    35023471                                  VUSBXFERTYPE_ISOC, enmDir, cbTotal, 1, NULL);
    35033472    if (!pUrb)
     
    44054374static void ohciR3BusStart(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
    44064375{
    4407     VUSBIDevPowerOn(pThisCC->RootHub.pIDev);
     4376    pThisCC->RootHub.pIRhConn->pfnPowerOn(pThisCC->RootHub.pIRhConn);
    44084377    pThis->dqic = 0x7;
    44094378
     
    44234392    int rc = pThisCC->RootHub.pIRhConn->pfnSetPeriodicFrameProcessing(pThisCC->RootHub.pIRhConn, 0);
    44244393    AssertRC(rc);
    4425     VUSBIDevPowerOff(pThisCC->RootHub.pIDev);
     4394    pThisCC->RootHub.pIRhConn->pfnPowerOff(pThisCC->RootHub.pIRhConn);
    44264395}
    44274396
     
    44464415
    44474416/* Power a port up or down */
    4448 static void ohciR3RhPortPower(POHCIROOTHUB pRh, unsigned iPort, bool fPowerUp)
     4417static void ohciR3RhPortPower(POHCIROOTHUBR3 pRh, unsigned iPort, bool fPowerUp)
    44494418{
    44504419    POHCIHUBPORT pPort = &pRh->aPorts[iPort];
     
    44564425    {
    44574426        /* power up */
    4458         if (pPort->pDev)
     4427        if (pPort->fAttached)
    44594428            pPort->fReg |= OHCI_PORT_CCS;
    44604429        if (pPort->fReg & OHCI_PORT_CCS)
    44614430            pPort->fReg |= OHCI_PORT_PPS;
    4462         if (pPort->pDev && !fOldPPS)
    4463             VUSBIDevPowerOn(pPort->pDev);
     4431        if (pPort->fAttached && !fOldPPS)
     4432            VUSBIRhDevPowerOn(pRh->pIRhConn, OHCI_PORT_2_VUSB_PORT(iPort));
    44644433    }
    44654434    else
     
    44674436        /* power down */
    44684437        pPort->fReg &= ~(OHCI_PORT_PPS | OHCI_PORT_CCS | OHCI_PORT_PSS | OHCI_PORT_PRS);
    4469         if (pPort->pDev && fOldPPS)
    4470             VUSBIDevPowerOff(pPort->pDev);
     4438        if (pPort->fAttached && fOldPPS)
     4439            VUSBIRhDevPowerOff(pRh->pIRhConn, OHCI_PORT_2_VUSB_PORT(iPort));
    44714440    }
    44724441}
     
    45634532                 * that correctly in the roothub reset callback yet. check it's
    45644533                 * comments and argument for more details. */
    4565                 VUSBIDevReset(pThisCC->RootHub.pIDev, false /* don't do a real reset */, NULL, NULL, NULL);
     4534                pThisCC->RootHub.pIRhConn->pfnReset(pThisCC->RootHub.pIRhConn, false /* don't do a real reset */);
    45664535                break;
    45674536            }
     
    52105179{
    52115180#ifdef IN_RING3
     5181    POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
     5182
    52125183    /* log */
    52135184    uint32_t old = pThis->RootHub.status;
     
    52315202        Log2(("ohci: global power up\n"));
    52325203        for (i = 0; i < OHCI_NDP_CFG(pThis); i++)
    5233             ohciR3RhPortPower(&pThis->RootHub, i, true /* power up */);
     5204            ohciR3RhPortPower(&pThisCC->RootHub, i, true /* power up */);
    52345205    }
    52355206
     
    52405211        Log2(("ohci: global power down\n"));
    52415212        for (i = 0; i < OHCI_NDP_CFG(pThis); i++)
    5242             ohciR3RhPortPower(&pThis->RootHub, i, false /* power down */);
     5213            ohciR3RhPortPower(&pThisCC->RootHub, i, false /* power down */);
    52435214    }
    52445215
     
    52965267 * @thread EMT.
    52975268 */
    5298 static DECLCALLBACK(void) ohciR3PortResetDone(PVUSBIDEVICE pDev, int rc, void *pvUser)
    5299 {
    5300     PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
    5301     POHCI      pThis   = PDMDEVINS_2_DATA(pDevIns, POHCI);
    5302 
    5303     /*
    5304      * Find the port in question
    5305      */
    5306     POHCIHUBPORT pPort = NULL;
    5307     unsigned iPort;
    5308     for (iPort = 0; iPort < OHCI_NDP_CFG(pThis); iPort++) /* lazy bird */
    5309         if (pThis->RootHub.aPorts[iPort].pDev == pDev)
    5310         {
    5311             pPort = &pThis->RootHub.aPorts[iPort];
    5312             break;
    5313         }
    5314     if (!pPort)
    5315     {
    5316         Assert(pPort); /* sometimes happens because of @bugref{1510} */
    5317         return;
    5318     }
     5269static DECLCALLBACK(void) ohciR3PortResetDone(PVUSBIDEVICE pDev, uint32_t uPort, int rc, void *pvUser)
     5270{
     5271    RT_NOREF(pDev);
     5272
     5273    Assert(uPort >= 1);
     5274    PPDMDEVINS      pDevIns = (PPDMDEVINS)pvUser;
     5275    POHCI           pThis   = PDMDEVINS_2_DATA(pDevIns, POHCI);
     5276    POHCICC         pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
     5277    POHCIHUBPORT    pPort   = &pThis->RootHub.aPorts[uPort - 1];
    53195278
    53205279    if (RT_SUCCESS(rc))
     
    53305289    {
    53315290        /* desperate measures. */
    5332         if (    pPort->pDev
    5333             &&  VUSBIDevGetState(pPort->pDev) == VUSB_DEVICE_STATE_ATTACHED)
     5291        if (    pPort->fAttached
     5292            &&  VUSBIRhDevGetState(pThisCC->RootHub.pIRhConn, uPort) == VUSB_DEVICE_STATE_ATTACHED)
    53345293        {
    53355294            /*
     
    53965355#ifdef IN_RING3
    53975356    const unsigned  i = iReg - 21;
     5357    POHCICC         pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
    53985358    POHCIHUBPORT    p = &pThis->RootHub.aPorts[i];
    53995359    uint32_t        old_state = p->fReg;
     
    54435403            PVM pVM = PDMDevHlpGetVM(pDevIns);
    54445404            p->fReg &= ~OHCI_PORT_PRSC;
    5445             VUSBIDevReset(p->pDev, false /* don't reset on linux */, ohciR3PortResetDone, pDevIns, pVM);
     5405            VUSBIRhDevReset(pThisCC->RootHub.pIRhConn, OHCI_PORT_2_VUSB_PORT(i), false /* don't reset on linux */,
     5406                            ohciR3PortResetDone, pDevIns, pVM);
    54465407        }
    54475408        else if (p->fReg & OHCI_PORT_PRS)
     
    54605421         */
    54615422        if (val & OHCI_PORT_CLRPP)
    5462             ohciR3RhPortPower(&pThis->RootHub, i, false /* power down */);
     5423            ohciR3RhPortPower(&pThisCC->RootHub, i, false /* power down */);
    54635424        if (val & OHCI_PORT_PPS)
    5464             ohciR3RhPortPower(&pThis->RootHub, i, true /* power up */);
     5425            ohciR3RhPortPower(&pThisCC->RootHub, i, true /* power up */);
    54655426    }
    54665427
     
    54685429    if (val & OHCI_PORT_CLRSS)
    54695430    {
    5470         ohciR3RhPortPower(&pThis->RootHub, i, true /* power up */);
     5431        ohciR3RhPortPower(&pThisCC->RootHub, i, true /* power up */);
    54715432        pThis->RootHub.aPorts[i].fReg &= ~OHCI_PORT_PSS;
    54725433        pThis->RootHub.aPorts[i].fReg |= OHCI_PORT_PSSC;
     
    56145575
    56155576/**
    5616  * Prepares for state saving.
    5617  * All URBs needs to be canceled.
     5577 * Saves the state of the OHCI device.
    56185578 *
    56195579 * @returns VBox status code.
     
    56215581 * @param   pSSM        The handle to save the state to.
    56225582 */
    5623 static DECLCALLBACK(int) ohciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    5624 {
    5625     RT_NOREF(pSSM);
    5626     POHCICC      pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
    5627     POHCI        pThis   = PDMDEVINS_2_DATA(pDevIns, POHCI);
    5628     LogFlow(("ohciR3SavePrep: \n"));
    5629 
    5630     /*
    5631      * Detach all proxied devices.
    5632      */
    5633     int rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
    5634     AssertRCReturn(rc, rc);
    5635 
    5636     /** @todo this won't work well when continuing after saving! */
    5637     for (unsigned i = 0; i < RT_ELEMENTS(pThis->RootHub.aPorts); i++)
    5638     {
    5639         PVUSBIDEVICE pDev = pThis->RootHub.aPorts[i].pDev;
    5640         if (pDev)
    5641         {
    5642             if (!VUSBIDevIsSavedStateSupported(pDev))
    5643             {
    5644                 VUSBIRhDetachDevice(pThisCC->RootHub.pIRhConn, pDev);
    5645                 /*
    5646                  * Save the device pointers here so we can reattach them afterwards.
    5647                  * This will work fine even if the save fails since the Done handler is
    5648                  * called unconditionally if the Prep handler was called.
    5649                  */
    5650                 pThis->RootHub.aPorts[i].pDev = pDev;
    5651             }
    5652         }
    5653     }
    5654 
    5655     PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
    5656 
    5657     /*
    5658      * Kill old load data which might be hanging around.
    5659      */
    5660     if (pThisCC->pLoad)
    5661     {
    5662         PDMDevHlpTimerDestroy(pDevIns, pThisCC->pLoad->hTimer);
    5663         PDMDevHlpMMHeapFree(pDevIns, pThisCC->pLoad);
    5664         pThisCC->pLoad = NULL;
    5665     }
    5666     return VINF_SUCCESS;
    5667 }
    5668 
    5669 
    5670 /**
    5671  * Saves the state of the OHCI device.
    5672  *
    5673  * @returns VBox status code.
    5674  * @param   pDevIns     The device instance.
    5675  * @param   pSSM        The handle to save the state to.
    5676  */
    56775583static DECLCALLBACK(int) ohciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    56785584{
     
    56865592    /* Save the periodic frame rate so we can we can tell if the bus was started or not when restoring. */
    56875593    return pDevIns->pHlpR3->pfnSSMPutU32(pSSM, VUSBIRhGetPeriodicFrameRate(pThisCC->RootHub.pIRhConn));
    5688 }
    5689 
    5690 
    5691 /**
    5692  * Done state save operation.
    5693  *
    5694  * @returns VBox load code.
    5695  * @param   pDevIns         Device instance of the device which registered the data unit.
    5696  * @param   pSSM            SSM operation handle.
    5697  */
    5698 static DECLCALLBACK(int) ohciR3SaveDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    5699 {
    5700     POHCI   pThis   = PDMDEVINS_2_DATA(pDevIns, POHCI);
    5701     POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
    5702     LogFlow(("ohciR3SaveDone:\n"));
    5703     RT_NOREF(pSSM);
    5704 
    5705     /*
    5706      * NULL the dev pointers.
    5707      */
    5708     POHCIROOTHUB pRh = &pThis->RootHub;
    5709     OHCIROOTHUB  Rh  = *pRh;
    5710     for (unsigned i = 0; i < RT_ELEMENTS(pRh->aPorts); i++)
    5711     {
    5712         if (   pRh->aPorts[i].pDev
    5713             && !VUSBIDevIsSavedStateSupported(pRh->aPorts[i].pDev))
    5714             pRh->aPorts[i].pDev = NULL;
    5715     }
    5716 
    5717     /*
    5718      * Attach the devices.
    5719      */
    5720     for (unsigned i = 0; i < RT_ELEMENTS(pRh->aPorts); i++)
    5721     {
    5722         PVUSBIDEVICE pDev = Rh.aPorts[i].pDev;
    5723         if (   pDev
    5724             && !VUSBIDevIsSavedStateSupported(pDev))
    5725             VUSBIRhAttachDevice(pThisCC->RootHub.pIRhConn, pDev);
    5726     }
    5727 
    5728     return VINF_SUCCESS;
    5729 }
    5730 
    5731 
    5732 /**
    5733  * Prepare loading the state of the OHCI device.
    5734  * This must detach the devices currently attached and save
    5735  * the up for reconnect after the state load have been completed
    5736  *
    5737  * @returns VBox status code.
    5738  * @param   pDevIns     The device instance.
    5739  * @param   pSSM        The handle to the saved state.
    5740  */
    5741 static DECLCALLBACK(int) ohciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    5742 {
    5743     POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
    5744     POHCI   pThis   = PDMDEVINS_2_DATA(pDevIns, POHCI);
    5745     LogFlow(("ohciR3LoadPrep:\n"));
    5746     RT_NOREF(pSSM);
    5747 
    5748     if (!pThisCC->pLoad)
    5749     {
    5750         /*
    5751          * Detach all devices which are present in this session. Save them in the load
    5752          * structure so we can reattach them after restoring the guest.
    5753          */
    5754         POHCIROOTHUB pRh = &pThis->RootHub;
    5755         OHCILOAD Load;
    5756         Load.hTimer = NIL_TMTIMERHANDLE;
    5757         Load.cDevs  = 0;
    5758         for (unsigned i = 0; i < RT_ELEMENTS(pRh->aPorts); i++)
    5759         {
    5760             PVUSBIDEVICE pDev = pRh->aPorts[i].pDev;
    5761             if (   pDev
    5762                 && !VUSBIDevIsSavedStateSupported(pDev))
    5763             {
    5764                 Load.apDevs[Load.cDevs++] = pDev;
    5765                 VUSBIRhDetachDevice(pThisCC->RootHub.pIRhConn, pDev);
    5766                 Assert(!pRh->aPorts[i].pDev);
    5767             }
    5768         }
    5769 
    5770         /*
    5771          * Any devices to reattach, if so duplicate the Load struct.
    5772          */
    5773         if (Load.cDevs)
    5774         {
    5775             pThisCC->pLoad = (POHCILOAD)PDMDevHlpMMHeapAlloc(pDevIns, sizeof(Load));
    5776             if (!pThisCC->pLoad)
    5777                 return VERR_NO_MEMORY;
    5778             *pThisCC->pLoad = Load;
    5779         }
    5780     }
    5781     /* else: we ASSUME no device can be attached or detach in the period
    5782      *       between a state load and the pLoad stuff is processed. */
    5783     return VINF_SUCCESS;
    57845594}
    57855595
     
    58475657
    58485658/**
    5849  * @callback_method_impl{FNTMTIMERDEV,
    5850  *      Reattaches devices after a saved state load.}
    5851  */
    5852 static DECLCALLBACK(void) ohciR3LoadReattachDevices(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
    5853 {
    5854     POHCICC      pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
    5855     POHCILOAD    pLoad   = pThisCC->pLoad;
    5856     LogFlow(("ohciR3LoadReattachDevices:\n"));
    5857     Assert(hTimer == pLoad->hTimer); RT_NOREF(pvUser);
    5858 
    5859     /*
    5860      * Reattach devices.
    5861      */
    5862     for (unsigned i = 0; i < pLoad->cDevs; i++)
    5863         VUSBIRhAttachDevice(pThisCC->RootHub.pIRhConn, pLoad->apDevs[i]);
    5864 
    5865     /*
    5866      * Cleanup.
    5867      */
    5868     PDMDevHlpTimerDestroy(pDevIns, hTimer);
    5869     pLoad->hTimer = NIL_TMTIMERHANDLE;
    5870     PDMDevHlpMMHeapFree(pDevIns, pLoad);
    5871     pThisCC->pLoad = NULL;
    5872 }
    5873 
    5874 
    5875 /**
    5876  * Done state load operation.
    5877  *
    5878  * @returns VBox load code.
    5879  * @param   pDevIns         Device instance of the device which registered the data unit.
    5880  * @param   pSSM            SSM operation handle.
    5881  */
    5882 static DECLCALLBACK(int) ohciR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    5883 {
    5884     POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
    5885     LogFlow(("ohciR3LoadDone:\n"));
    5886     RT_NOREF(pSSM);
    5887 
    5888     /*
    5889      * Start a timer if we've got devices to reattach
    5890      */
    5891     if (pThisCC->pLoad)
    5892     {
    5893         int rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ohciR3LoadReattachDevices, NULL /*pvUser*/,
    5894                                       TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0, "OHCI reattach on load",
    5895                                       &pThisCC->pLoad->hTimer);
    5896         if (RT_SUCCESS(rc))
    5897             rc = PDMDevHlpTimerSetMillies(pDevIns, pThisCC->pLoad->hTimer, 250);
    5898         return rc;
    5899     }
    5900 
    5901     return VINF_SUCCESS;
    5902 }
    5903 
    5904 
    5905 /**
    59065659 * Reset notification.
    59075660 *
     
    61535906    rc = PDMDevHlpSSMRegisterEx(pDevIns, OHCI_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
    61545907                                NULL, NULL, NULL,
    6155                                 ohciR3SavePrep, ohciR3SaveExec, ohciR3SaveDone,
    6156                                 ohciR3LoadPrep, ohciR3LoadExec, ohciR3LoadDone);
     5908                                NULL, ohciR3SaveExec, NULL,
     5909                                NULL, ohciR3LoadExec, NULL);
    61575910    AssertRCReturn(rc, rc);
    61585911
     
    61695922    AssertMsgReturn(pThisCC->RootHub.pIRhConn,
    61705923                    ("Configuration error: The driver doesn't provide the VUSBIROOTHUBCONNECTOR interface!\n"),
    6171                     VERR_PDM_MISSING_INTERFACE);
    6172     pThisCC->RootHub.pIDev = PDMIBASE_QUERY_INTERFACE(pThisCC->RootHub.pIBase, VUSBIDEVICE);
    6173     AssertMsgReturn(pThisCC->RootHub.pIDev,
    6174                     ("Configuration error: The driver doesn't provide the VUSBIDEVICE interface!\n"),
    61755924                    VERR_PDM_MISSING_INTERFACE);
    61765925
  • 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    /*
  • trunk/src/VBox/Devices/USB/VUSBDevice.cpp

    r93115 r93914  
    14331433        vusbDevSetAddress(pDev, VUSB_DEFAULT_ADDRESS);
    14341434    if (pfnDone)
    1435         pfnDone(&pDev->IDevice, rc, pvUser);
     1435        pfnDone(&pDev->IDevice, pDev->i16Port, rc, pvUser);
    14361436}
    14371437
     
    16471647        PVUSBROOTHUB pRh = (PVUSBROOTHUB)pDev;
    16481648        VUSBIRhCancelAllUrbs(&pRh->IRhConnector);
    1649         VUSBIRhReapAsyncUrbs(&pRh->IRhConnector, pInterface, 0);
     1649        VUSBIRhReapAsyncUrbs(&pRh->IRhConnector, pDev->i16Port, 0);
    16501650    }
    16511651
  • trunk/src/VBox/Devices/USB/VUSBInternal.h

    r93115 r93914  
    377377
    378378
     379/** Pointer to a VUSBROOTHUBLOAD struct. */
     380typedef struct VUSBROOTHUBLOAD *PVUSBROOTHUBLOAD;
     381
    379382/** The address hash table size. */
    380383#define VUSB_ADDR_HASHSZ    5
     
    391394    /** The HUB.
    392395     * @todo remove this? */
    393     VUSBHUB                    Hub;
     396    VUSBHUB                     Hub;
    394397    /** Address hash table. */
    395     PVUSBDEV                   apAddrHash[VUSB_ADDR_HASHSZ];
     398    PVUSBDEV                    apAddrHash[VUSB_ADDR_HASHSZ];
    396399    /** The default address. */
    397     PVUSBDEV                   pDefaultAddress;
     400    PVUSBDEV                    pDefaultAddress;
    398401
    399402    /** Pointer to the driver instance. */
    400     PPDMDRVINS                 pDrvIns;
     403    PPDMDRVINS                  pDrvIns;
    401404    /** Pointer to the root hub port interface we're attached to. */
    402     PVUSBIROOTHUBPORT          pIRhPort;
     405    PVUSBIROOTHUBPORT           pIRhPort;
    403406    /** Connector interface exposed upwards. */
    404     VUSBIROOTHUBCONNECTOR      IRhConnector;
     407    VUSBIROOTHUBCONNECTOR       IRhConnector;
    405408
    406409    /** Critical section protecting the device list. */
    407     RTCRITSECT                 CritSectDevices;
     410    RTCRITSECT                  CritSectDevices;
    408411    /** Chain of devices attached to this hub. */
    409     PVUSBDEV                   pDevices;
     412    PVUSBDEV                    pDevices;
     413
     414    /** Array of pointers to USB devices indexed by the port the device is on. */
     415    PVUSBDEV                    apDevByPort[VUSB_DEVICES_MAX];
     416    /** Structure after a saved state load to re-attach devices. */
     417    PVUSBROOTHUBLOAD            pLoad;
    410418
    411419#if HC_ARCH_BITS == 32
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