summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/USB/DevOHCI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/USB/DevOHCI.cpp')
-rw-r--r--src/VBox/Devices/USB/DevOHCI.cpp93
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. */