diff options
Diffstat (limited to 'src/VBox/Devices/USB/DevOHCI.cpp')
-rw-r--r-- | src/VBox/Devices/USB/DevOHCI.cpp | 93 |
1 files changed, 81 insertions, 12 deletions
diff --git a/src/VBox/Devices/USB/DevOHCI.cpp b/src/VBox/Devices/USB/DevOHCI.cpp index 75c28aaf..cd139e98 100644 --- a/src/VBox/Devices/USB/DevOHCI.cpp +++ b/src/VBox/Devices/USB/DevOHCI.cpp @@ -668,7 +668,7 @@ typedef struct OHCIOPREG #define OHCI_INTR_START_OF_FRAME RT_BIT(2) /** RD - Resume detect. */ #define OHCI_INTR_RESUME_DETECT RT_BIT(3) -/** UE - Unrecoverable error. */ +/** UE - ",erable error. */ #define OHCI_INTR_UNRECOVERABLE_ERROR RT_BIT(4) /** FNO - Frame number overflow. */ #define OHCI_INTR_FRAMENUMBER_OVERFLOW RT_BIT(5) @@ -886,6 +886,7 @@ static void ohciR3PhysReadCacheInvalidate(POHCIPAGECACHE pPageCa static DECLCALLBACK(void) ohciR3RhXferCompletion(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb); static DECLCALLBACK(bool) ohciR3RhXferError(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb); +static bool ohciR3IsTdInFlight(POHCICC pThisCC, uint32_t GCPhysTD); static int ohciR3InFlightFind(POHCICC pThisCC, uint32_t GCPhysTD); # if defined(VBOX_STRICT) || defined(LOG_ENABLED) static int ohciR3InDoneQueueFind(POHCICC pThisCC, uint32_t GCPhysTD); @@ -1917,6 +1918,13 @@ DECLINLINE(int) ohciR3InFlightFindFree(POHCICC pThisCC, const int iStart) */ static void ohciR3InFlightAdd(POHCI pThis, POHCICC pThisCC, uint32_t GCPhysTD, PVUSBURB pUrb) { + if (ohciR3IsTdInFlight(pThisCC, GCPhysTD)) + { + PPDMDEVINS pDevIns = pThisCC->pDevInsR3; + ohciR3RaiseUnrecoverableError(pDevIns, pThis, 10); + return; + } + int i = ohciR3InFlightFindFree(pThisCC, (GCPhysTD >> 4) % RT_ELEMENTS(pThisCC->aInFlight)); if (i >= 0) { @@ -1995,6 +2003,7 @@ static bool ohciR3IsTdInFlight(POHCICC pThisCC, uint32_t GCPhysTD) return ohciR3InFlightFind(pThisCC, GCPhysTD) >= 0; } +#if 0 /** * Returns a URB associated with an in-flight TD, if any. * @@ -2012,6 +2021,7 @@ static PVUSBURB ohciR3TdInFlightUrb(POHCICC pThisCC, uint32_t GCPhysTD) return pThisCC->aInFlight[i].pUrb; return NULL; } +#endif /** * Removes a in-flight TD. @@ -3049,6 +3059,53 @@ static DECLCALLBACK(bool) ohciR3RhXferError(PVUSBIROOTHUBPORT pInterface, PVUSBU /** + * Determine transfer direction from an endpoint descriptor. + * NB: This may fail if the direction is not valid. If it does fail, + * we do not raise an unrecoverable error but the caller may wish to. + */ +static VUSBDIRECTION ohciR3GetDirection(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, PCOHCIED pEd) +{ + RT_NOREF(pThisCC); + RT_NOREF(pThis); + VUSBDIRECTION enmDir = VUSBDIRECTION_INVALID; + + if (pEd->hwinfo & ED_HWINFO_ISO) + { + switch (pEd->hwinfo & ED_HWINFO_DIR) + { + case ED_HWINFO_OUT: enmDir = VUSBDIRECTION_OUT; break; + case ED_HWINFO_IN: enmDir = VUSBDIRECTION_IN; break; + default: + Log(("ohciR3GetDirection: Invalid direction!!!! Ed.hwinfo=%#x\n", pEd->hwinfo)); + } + } + else + { + switch (pEd->hwinfo & ED_HWINFO_DIR) + { + case ED_HWINFO_OUT: enmDir = VUSBDIRECTION_OUT; break; + case ED_HWINFO_IN: enmDir = VUSBDIRECTION_IN; break; + default: + /* We must read the TD to determine direction. */ + uint32_t TdAddr = pEd->HeadP & ED_PTR_MASK; + OHCITD Td; + ohciR3ReadTd(pDevIns, TdAddr, &Td); + switch (Td.hwinfo & TD_HWINFO_DIR) + { + case TD_HWINFO_OUT: enmDir = VUSBDIRECTION_OUT; break; + case TD_HWINFO_IN: enmDir = VUSBDIRECTION_IN; break; + case 0: enmDir = VUSBDIRECTION_SETUP; break; + default: + Log(("ohciR3GetDirection: Invalid direction!!!! Td.hwinfo=%#x Ed.hwinfo=%#x\n", Td.hwinfo, pEd->hwinfo)); + } + } + } + + return enmDir; +} + + +/** * Service a general transport descriptor. */ static bool ohciR3ServiceTd(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, VUSBXFERTYPE enmType, @@ -3802,10 +3859,13 @@ static void ohciR3ServiceBulkList(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThis /* If the ED is in 'skip' state, no transactions on it are allowed and we must * cancel outstanding URBs, if any. */ - uint32_t TdAddr = Ed.HeadP & ED_PTR_MASK; - PVUSBURB pUrb = ohciR3TdInFlightUrb(pThisCC, TdAddr); - if (pUrb) - pThisCC->RootHub.pIRhConn->pfnCancelUrbsEp(pThisCC->RootHub.pIRhConn, pUrb); + uint8_t uAddr = Ed.hwinfo & ED_HWINFO_FUNCTION; + uint8_t uEndPt = (Ed.hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT; + VUSBDIRECTION enmDir = ohciR3GetDirection(pDevIns, pThis, pThisCC, &Ed); + if (enmDir != VUSBDIRECTION_INVALID) + { + pThisCC->RootHub.pIRhConn->pfnAbortEpByAddr(pThisCC->RootHub.pIRhConn, uAddr, uEndPt, enmDir); + } } } @@ -3858,9 +3918,14 @@ static void ohciR3UndoBulkList(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC) if (ohciR3IsTdInFlight(pThisCC, TdAddr)) { LogFlow(("ohciR3UndoBulkList: Ed=%#010RX32 Ed.TailP=%#010RX32 UNDO\n", EdAddr, Ed.TailP)); - PVUSBURB pUrb = ohciR3TdInFlightUrb(pThisCC, TdAddr); - if (pUrb) - pThisCC->RootHub.pIRhConn->pfnCancelUrbsEp(pThisCC->RootHub.pIRhConn, pUrb); + /* First we need to determine the transfer direction, which may fail(!). */ + uint8_t uAddr = Ed.hwinfo & ED_HWINFO_FUNCTION; + uint8_t uEndPt = (Ed.hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT; + VUSBDIRECTION enmDir = ohciR3GetDirection(pDevIns, pThis, pThisCC, &Ed); + if (enmDir != VUSBDIRECTION_INVALID) + { + pThisCC->RootHub.pIRhConn->pfnAbortEpByAddr(pThisCC->RootHub.pIRhConn, uAddr, uEndPt, enmDir); + } } } @@ -4022,11 +4087,15 @@ static void ohciR3ServicePeriodicList(PPDMDEVINS pDevIns, POHCI pThis, POHCICC p Log3(("ohciR3ServicePeriodicList: Ed=%#010RX32 Ed.TailP=%#010RX32 SKIP\n", EdAddr, Ed.TailP)); /* If the ED is in 'skip' state, no transactions on it are allowed and we must * cancel outstanding URBs, if any. + * First we need to determine the transfer direction, which may fail(!). */ - uint32_t TdAddr = Ed.HeadP & ED_PTR_MASK; - PVUSBURB pUrb = ohciR3TdInFlightUrb(pThisCC, TdAddr); - if (pUrb) - pThisCC->RootHub.pIRhConn->pfnCancelUrbsEp(pThisCC->RootHub.pIRhConn, pUrb); + uint8_t uAddr = Ed.hwinfo & ED_HWINFO_FUNCTION; + uint8_t uEndPt = (Ed.hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT; + VUSBDIRECTION enmDir = ohciR3GetDirection(pDevIns, pThis, pThisCC, &Ed); + if (enmDir != VUSBDIRECTION_INVALID) + { + pThisCC->RootHub.pIRhConn->pfnAbortEpByAddr(pThisCC->RootHub.pIRhConn, uAddr, uEndPt, enmDir); + } } } /* Trivial loop detection. */ |