summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/USB
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/USB')
-rw-r--r--src/VBox/Devices/USB/DevEHCI.cpp50
-rw-r--r--src/VBox/Devices/USB/DevOHCI.cpp93
-rw-r--r--src/VBox/Devices/USB/DevXHCI.cpp103
-rw-r--r--src/VBox/Devices/USB/DrvVUSBRootHub.cpp59
4 files changed, 234 insertions, 71 deletions
diff --git a/src/VBox/Devices/USB/DevEHCI.cpp b/src/VBox/Devices/USB/DevEHCI.cpp
index ade53208..1ca85af3 100644
--- a/src/VBox/Devices/USB/DevEHCI.cpp
+++ b/src/VBox/Devices/USB/DevEHCI.cpp
@@ -1623,7 +1623,7 @@ DECLINLINE(void) ehciR3DumpQTD(PPDMDEVINS pDevIns, RTGCPHYS GCPhysHead, bool fLi
if (GCPhys == ((RTGCPHYS)qtd.Next.Pointer << EHCI_TD_PTR_SHIFT))
break; /* detect if list item is self-cycled. */
- GCPhys = qtd.Next.Pointer << EHCI_TD_PTR_SHIFT;
+ GCPhys = (RTGCPHYS)qtd.Next.Pointer << EHCI_TD_PTR_SHIFT;
if (GCPhys == GCPhysHead)
break;
@@ -1659,7 +1659,7 @@ DECLINLINE(void) ehciR3DumpQTD(PPDMDEVINS pDevIns, RTGCPHYS GCPhysHead, bool fLi
if (GCPhys == ((RTGCPHYS)qtd.AltNext.Pointer << EHCI_TD_PTR_SHIFT))
break; /* detect if list item is self-cycled. */
- GCPhys = qtd.AltNext.Pointer << EHCI_TD_PTR_SHIFT;
+ GCPhys = (RTGCPHYS)qtd.AltNext.Pointer << EHCI_TD_PTR_SHIFT;
if (GCPhys == GCPhysHead)
break;
@@ -1701,8 +1701,8 @@ DECLINLINE(void) ehciR3DumpQH(PPDMDEVINS pDevIns, RTGCPHYS GCPhysHead, bool fLis
((RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT),
((RTGCPHYS)qhd.Overlay.OrgQTD.Next.Pointer << EHCI_TD_PTR_SHIFT), qhd.Overlay.OrgQTD.Next.Terminate,
((RTGCPHYS)qhd.Overlay.OrgQTD.AltNext.Pointer << EHCI_TD_PTR_SHIFT), qhd.Overlay.OrgQTD.AltNext.Terminate));
- ehciR3DumpSingleQTD(qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT, &qhd.Overlay.OrgQTD, "");
- ehciR3DumpQTD(pDevIns, qhd.Overlay.OrgQTD.Next.Pointer << EHCI_TD_PTR_SHIFT, true);
+ ehciR3DumpSingleQTD((RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT, &qhd.Overlay.OrgQTD, "");
+ ehciR3DumpQTD(pDevIns, (RTGCPHYS)qhd.Overlay.OrgQTD.Next.Pointer << EHCI_TD_PTR_SHIFT, true);
Assert(qhd.Next.Pointer || qhd.Next.Terminate);
if ( !fList
@@ -1727,7 +1727,7 @@ DECLINLINE(void) ehciR3DumpQH(PPDMDEVINS pDevIns, RTGCPHYS GCPhysHead, bool fLis
if (GCPhys == ((RTGCPHYS)ptr.Pointer << EHCI_TD_PTR_SHIFT))
break; /* Looping on itself. Bad guest! */
- GCPhys = ptr.Pointer << EHCI_TD_PTR_SHIFT;
+ GCPhys = (RTGCPHYS)ptr.Pointer << EHCI_TD_PTR_SHIFT;
if (GCPhys == GCPhysHead)
break; /* break the loop */
@@ -1767,7 +1767,7 @@ DECLINLINE(void) ehciR3DumpITD(PPDMDEVINS pDevIns, RTGCPHYS GCPhysHead, bool fLi
if (pItd->Transaction[i].Active)
{
Log2(("T%d Len=%x Offset=%x PG=%d IOC=%d Buffer=%x\n", i, pItd->Transaction[i].Length, pItd->Transaction[i].Offset, pItd->Transaction[i].PG, pItd->Transaction[i].IOC,
- pItd->Buffer.Buffer[pItd->Transaction[i].PG].Pointer << EHCI_BUFFER_PTR_SHIFT));
+ (RTGCPHYS)pItd->Buffer.Buffer[pItd->Transaction[i].PG].Pointer << EHCI_BUFFER_PTR_SHIFT));
}
}
Assert(pItd->Next.Pointer || pItd->Next.Terminate);
@@ -1784,7 +1784,7 @@ DECLINLINE(void) ehciR3DumpITD(PPDMDEVINS pDevIns, RTGCPHYS GCPhysHead, bool fLi
}
/* next */
- GCPhys = pItd->Next.Pointer << EHCI_TD_PTR_SHIFT;
+ GCPhys = (RTGCPHYS)pItd->Next.Pointer << EHCI_TD_PTR_SHIFT;
}
}
@@ -2325,7 +2325,7 @@ static void ehciR3RhXferCompleteITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pTh
if ((pg + 1) >= EHCI_NUM_ITD_PAGES)
LogRelMax(10, ("EHCI: Crossing to undefined page %d in iTD at %RGp on completion.\n", pg + 1, pUrb->paTds[0].TdAddr));
- GCPhysBuf = pItd->Buffer.Buffer[pg + 1].Pointer << EHCI_BUFFER_PTR_SHIFT;
+ GCPhysBuf = (RTGCPHYS)pItd->Buffer.Buffer[pg + 1].Pointer << EHCI_BUFFER_PTR_SHIFT;
ehciPhysWrite(pDevIns, GCPhysBuf, pb + cb1, cb2);
}
else
@@ -2409,7 +2409,7 @@ static void ehciR3RhXferCompleteQH(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThi
AssertMsg(pUrb->paTds[0].TdAddr == ((RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT),
("Out of order completion %RGp != %RGp Endpoint=%#x\n", pUrb->paTds[0].TdAddr,
((RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT), pUrb->EndPt));
- ehciR3ReadQTD(pDevIns, qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT, &qtd);
+ ehciR3ReadQTD(pDevIns, (RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT, &qtd);
/*
* Check that the URB hasn't been canceled and then try unlink the TDs.
@@ -2460,7 +2460,7 @@ static void ehciR3RhXferCompleteQH(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThi
RTGCPHYS GCPhysBuf;
unsigned cbCurTransfer;
- GCPhysBuf = qtd.Buffer.Buffer[i].Pointer << EHCI_BUFFER_PTR_SHIFT;
+ GCPhysBuf = (RTGCPHYS)qtd.Buffer.Buffer[i].Pointer << EHCI_BUFFER_PTR_SHIFT;
if (i == 0)
GCPhysBuf += qtd.Buffer.Offset.Offset;
@@ -2600,7 +2600,7 @@ static bool ehciR3RhXferErrorQH(PPDMDEVINS pDevIns, PEHCICC pThisCC, PVUSBURB pU
/* Read the whole QHD & QTD */
ehciR3ReadQHD(pDevIns, pUrb->pHci->EdAddr, &qhd);
Assert(pUrb->paTds[0].TdAddr == ((RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT));
- ehciR3ReadQTD(pDevIns, qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT, &qtd);
+ ehciR3ReadQTD(pDevIns, (RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT, &qtd);
/*
* Check if the TDs still are valid.
@@ -2737,7 +2737,7 @@ static bool ehciR3SubmitQTD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC, RT
RTGCPHYS GCPhysBuf;
unsigned cbCurTransfer;
- GCPhysBuf = pQtd->Buffer.Buffer[i].Pointer << EHCI_BUFFER_PTR_SHIFT;
+ GCPhysBuf = (RTGCPHYS)pQtd->Buffer.Buffer[i].Pointer << EHCI_BUFFER_PTR_SHIFT;
if (i == 0)
GCPhysBuf += pQtd->Buffer.Offset.Offset;
@@ -2862,7 +2862,7 @@ static bool ehciR3SubmitITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
{
const unsigned pg = pItd->Transaction[i].PG;
- GCPhysBuf = pItd->Buffer.Buffer[pg].Pointer << EHCI_BUFFER_PTR_SHIFT;
+ GCPhysBuf = (RTGCPHYS)pItd->Buffer.Buffer[pg].Pointer << EHCI_BUFFER_PTR_SHIFT;
GCPhysBuf += pItd->Transaction[i].Offset;
/* If the transfer would cross page boundary, use the next sequential PG pointer
@@ -2877,7 +2877,7 @@ static bool ehciR3SubmitITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
if ((pg + 1) >= EHCI_NUM_ITD_PAGES)
LogRelMax(10, ("EHCI: Crossing to undefined page %d in iTD at %RGp on submit.\n", pg + 1, pUrb->paTds[0].TdAddr));
- GCPhysBuf = pItd->Buffer.Buffer[pg + 1].Pointer << EHCI_BUFFER_PTR_SHIFT;
+ GCPhysBuf = (RTGCPHYS)pItd->Buffer.Buffer[pg + 1].Pointer << EHCI_BUFFER_PTR_SHIFT;
ehciPhysRead(pDevIns, GCPhysBuf, &pUrb->abData[curOffset + cb1], cb2);
}
else
@@ -3024,7 +3024,7 @@ static void ehciR3QHUpdateOverlay(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThis
if (!pQhd->Overlay.OrgQTD.Next.Terminate)
{
EHCI_QTD qtdNext;
- RTGCPHYS GCPhysNextQTD = pQhd->Overlay.OrgQTD.Next.Pointer << EHCI_TD_PTR_SHIFT;
+ RTGCPHYS GCPhysNextQTD = (RTGCPHYS)pQhd->Overlay.OrgQTD.Next.Pointer << EHCI_TD_PTR_SHIFT;
if (ehciR3IsTdInFlight(pThisCC, GCPhysNextQTD))
{
@@ -3073,7 +3073,7 @@ static RTGCPHYS ehciR3ServiceQTD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisC
|| GCPhysQTD == (RTGCPHYS)pQhd->CurrQTD.Pointer << EHCI_TD_PTR_SHIFT)
ehciR3QHSetupOverlay(pDevIns, pQhd, GCPhysQHD, &qtd, GCPhysQTD);
else
- Log2Func(("transfer %RGp in progress -> don't update the overlay\n", (RTGCPHYS)(pQhd->CurrQTD.Pointer << EHCI_TD_PTR_SHIFT)));
+ Log2Func(("transfer %RGp in progress -> don't update the overlay\n", (RTGCPHYS)pQhd->CurrQTD.Pointer << EHCI_TD_PTR_SHIFT));
ehciR3SubmitQTD(pDevIns, pThis, pThisCC, GCPhysQHD, pQhd, GCPhysQTD, &qtd, iFrame);
@@ -3119,14 +3119,14 @@ static RTGCPHYS ehciR3ServiceQTD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisC
{
Assert(qtd.AltNext.Pointer);
Log2(("Taking alternate pointer %RGp\n", (RTGCPHYS)(qtd.AltNext.Pointer << EHCI_TD_PTR_SHIFT)));
- return qtd.AltNext.Pointer << EHCI_TD_PTR_SHIFT;
+ return (RTGCPHYS)qtd.AltNext.Pointer << EHCI_TD_PTR_SHIFT;
}
else
{
Assert(qtd.Next.Pointer || qtd.Next.Terminate);
if (qtd.Next.Terminate || !qtd.Next.Pointer)
return 0;
- return qtd.Next.Pointer << EHCI_TD_PTR_SHIFT;
+ return (RTGCPHYS)qtd.Next.Pointer << EHCI_TD_PTR_SHIFT;
}
}
@@ -3206,8 +3206,8 @@ static bool ehciR3ServiceQHD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
RTGCPHYS GCPhysQTD;
if (qhd.Overlay.OrgQTD.Token.Bits.Active)
{
- Assert(ehciR3IsTdInFlight(pThisCC, qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT));
- GCPhysQTD = qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT;
+ Assert(ehciR3IsTdInFlight(pThisCC, (RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT));
+ GCPhysQTD = (RTGCPHYS)qhd.CurrQTD.Pointer << EHCI_TD_PTR_SHIFT;
}
else
{
@@ -3216,8 +3216,8 @@ static bool ehciR3ServiceQHD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
&& qhd.Overlay.OrgQTD.Token.Bits.Length)
{
Assert(qhd.Overlay.OrgQTD.AltNext.Pointer);
- Log2(("Taking alternate pointer %RGp\n", (RTGCPHYS)(qhd.Overlay.OrgQTD.AltNext.Pointer << EHCI_TD_PTR_SHIFT)));
- GCPhysQTD = qhd.Overlay.OrgQTD.AltNext.Pointer << EHCI_TD_PTR_SHIFT;
+ Log2(("Taking alternate pointer %RGp\n", (RTGCPHYS)qhd.Overlay.OrgQTD.AltNext.Pointer << EHCI_TD_PTR_SHIFT));
+ GCPhysQTD = (RTGCPHYS)qhd.Overlay.OrgQTD.AltNext.Pointer << EHCI_TD_PTR_SHIFT;
}
else
{
@@ -3225,7 +3225,7 @@ static bool ehciR3ServiceQHD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
if (qhd.Overlay.OrgQTD.Next.Terminate || !qhd.Overlay.OrgQTD.Next.Pointer || qhd.Overlay.OrgQTD.Token.Bits.Halted)
GCPhysQTD = 0;
else
- GCPhysQTD = qhd.Overlay.OrgQTD.Next.Pointer << EHCI_TD_PTR_SHIFT;
+ GCPhysQTD = (RTGCPHYS)qhd.Overlay.OrgQTD.Next.Pointer << EHCI_TD_PTR_SHIFT;
}
}
@@ -3308,7 +3308,7 @@ static void ehciR3ServiceAsyncList(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThi
AssertMsgBreak(++cIterations < 128, ("Too many iterations, exiting\n"));
/* next */
- GCPhys = ptr.Pointer << EHCI_TD_PTR_SHIFT;
+ GCPhys = (RTGCPHYS)ptr.Pointer << EHCI_TD_PTR_SHIFT;
Assert(!(GCPhys & 0x1f));
if ( GCPhys == GCPhysHead
|| GCPhys == GCPhysLast)
@@ -3357,7 +3357,7 @@ static void ehciR3ServicePeriodicList(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC p
ehciR3ReadFrameListPtr(pDevIns, GCPhys, &FramePtr);
while (!FramePtr.Terminate && (pThis->cmd & EHCI_CMD_RUN))
{
- GCPhys = FramePtr.FrameAddr << EHCI_FRAME_LIST_NEXTPTR_SHIFT;
+ GCPhys = (RTGCPHYS)FramePtr.FrameAddr << EHCI_FRAME_LIST_NEXTPTR_SHIFT;
/* Process the descriptor based on its type. Note that on the periodic
* list, HCDs may (and do) mix iTDs and qHDs more or less freely.
*/
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. */
diff --git a/src/VBox/Devices/USB/DevXHCI.cpp b/src/VBox/Devices/USB/DevXHCI.cpp
index 5df1cc5a..c8212158 100644
--- a/src/VBox/Devices/USB/DevXHCI.cpp
+++ b/src/VBox/Devices/USB/DevXHCI.cpp
@@ -1603,8 +1603,8 @@ typedef struct XHCI
uint32_t Alignment00; /**< Force alignment. */
#endif
- /** Flag indicating a sleeping worker thread. */
- volatile bool fWrkThreadSleeping;
+ /** Flag indicating a pending worker thread notification. */
+ volatile bool fNotificationSent;
volatile bool afPadding[3];
/** The event semaphore the worker thread waits on. */
@@ -2165,7 +2165,7 @@ static void xhciKickWorker(PPDMDEVINS pDevIns, PXHCI pThis, XHCI_JOB enmJob, uin
RT_NOREF(enmJob, uWorkDesc);
/* Tell the worker thread there's something to do. */
- if (ASMAtomicReadBool(&pThis->fWrkThreadSleeping))
+ if (!ASMAtomicXchgBool(&pThis->fNotificationSent, true))
{
LogFlowFunc(("Signal event semaphore\n"));
int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
@@ -4352,18 +4352,21 @@ static unsigned xhciR3StopEndpoint(PPDMDEVINS pDevIns, PXHCI pThis, PXHCICC pThi
uint32_t uPort;
/* Abort the endpoint, i.e. cancel any outstanding URBs. This needs to be done after
- * writing back the EP state so that the completion callback can operate.
+ * writing back the EP state so that the completion callback can operate. Note that
+ * the completion callback will not modify the TR when it sees that the EP is not in
+ * the 'running' state.
+ * NB: If a URB is canceled before it completed, we have no way to tell if any data
+ * was already (partially) transferred.
*/
if (RT_SUCCESS(xhciR3FindRhDevBySlot(pDevIns, pThis, pThisCC, uSlotID, &pRh, &uPort)))
{
/* Temporarily give up the lock so that the completion callbacks can run. */
RTCritSectLeave(&pThisCC->CritSectThrd);
Log(("Aborting DCI %u -> ep=%u d=%u\n", uDCI, uDCI / 2, uDCI & 1 ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT));
- pRh->pIRhConn->pfnAbortEp(pRh->pIRhConn, uPort, uDCI / 2, uDCI & 1 ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT);
+ pRh->pIRhConn->pfnAbortEpByPort(pRh->pIRhConn, uPort, uDCI / 2, uDCI & 1 ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT);
RTCritSectEnter(&pThisCC->CritSectThrd);
}
- /// @todo The completion callbacks should do more work for canceled URBs.
/* Once the completion callbacks had a chance to run, we have to adjust
* the endpoint state.
* NB: The guest may just ring the doorbell to continue and not execute
@@ -4371,6 +4374,9 @@ static unsigned xhciR3StopEndpoint(PPDMDEVINS pDevIns, PXHCI pThis, PXHCICC pThi
*/
PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysEndp, &endp_ctx, sizeof(endp_ctx));
+ /* If the enqueue and dequeue pointers are different, a transfer was
+ * in progress.
+ */
bool fXferWasInProgress = endp_ctx.trep != endp_ctx.trdp;
/* Reset the TREP, but the EDTLA should be left alone. */
@@ -4557,6 +4563,8 @@ static unsigned xhciR3ConfigureDevice(PPDMDEVINS pDevIns, PXHCI pThis, uint64_t
XHCI_DEV_CTX dc_out;
unsigned uDCI;
+ RT_ZERO(dc_inp);
+
Assert(uSlotID);
LogFlowFunc(("Slot ID %u, input control context @ %RGp\n", uSlotID, GCPhysInpCtx));
@@ -4638,15 +4646,6 @@ static unsigned xhciR3ConfigureDevice(PPDMDEVINS pDevIns, PXHCI pThis, uint64_t
/// @todo Check input slot context according to 6.2.2.2
/// @todo Check input EP contexts according to 6.2.3.2
}
-/** @todo r=bird: Looks like MSC is right that dc_inp can be used uninitalized.
- *
- * However, this function is so hard to read I'm leaving the exorcism of it to
- * the author and just zeroing it in the mean time.
- *
- */
- else
- RT_ZERO(dc_inp);
-
/* Read the output Slot Context plus all Endpoint Contexts up to and
* including the one with the highest 'add' or 'drop' bit set.
*/
@@ -5252,20 +5251,17 @@ static DECLCALLBACK(int) xhciR3WorkerLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
- uint32_t u32Tasks = 0;
uint8_t uSlotID;
- ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, true);
- u32Tasks = ASMAtomicXchgU32(&pThis->u32TasksNew, 0);
- if (!u32Tasks)
+ bool fNotificationSent = ASMAtomicXchgBool(&pThis->fNotificationSent, false);
+ if (!fNotificationSent)
{
- Assert(ASMAtomicReadBool(&pThis->fWrkThreadSleeping));
rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtProcess, RT_INDEFINITE_WAIT);
AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
break;
LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
- u32Tasks = ASMAtomicXchgU32(&pThis->u32TasksNew, 0);
+ ASMAtomicWriteBool(&pThis->fNotificationSent, false);
}
RTCritSectEnter(&pThisCC->CritSectThrd);
@@ -5305,8 +5301,6 @@ static DECLCALLBACK(int) xhciR3WorkerLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread
}
RTCritSectLeave(&pThisCC->CritSectThrd);
-
- ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, false);
} /* While running */
LogFlow(("xHCI worker thread exiting.\n"));
@@ -7565,6 +7559,68 @@ static DECLCALLBACK(void) xhciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, con
pThis->fDropUrb = true;
return;
}
+
+ if (pszArgs && strstr(pszArgs, "genintrhw"))
+ {
+ pHlp->pfnPrintf(pHlp, "Generating hardware interrupt (external)...\n");
+ int iIntr = 0;
+ PXHCIINTRPTR pIntr = &pThis->aInterrupters[iIntr & XHCI_INTR_MASK];
+ xhciSetIntr(pDevIns, pThis, pIntr);
+ return;
+ }
+
+ if (pszArgs && strstr(pszArgs, "genintrint"))
+ {
+ pHlp->pfnPrintf(pHlp, "Generating hardware interrupt (internal)...\n");
+ int iIntr = 0;
+ PXHCIINTRPTR pIntr = &pThis->aInterrupters[iIntr & XHCI_INTR_MASK];
+ xhciR3SetIntrPending(pDevIns, pThis, pIntr);
+ return;
+ }
+
+ if (pszArgs && strstr(pszArgs, "genintrhw"))
+ {
+ pHlp->pfnPrintf(pHlp, "Generating hardware interrupt (external)...\n");
+ int iIntr = 0;
+ PXHCIINTRPTR pIntr = &pThis->aInterrupters[iIntr & XHCI_INTR_MASK];
+ xhciSetIntr(pDevIns, pThis, pIntr);
+ return;
+ }
+
+ if (pszArgs && strstr(pszArgs, "genintrint"))
+ {
+ pHlp->pfnPrintf(pHlp, "Generating hardware interrupt (internal)...\n");
+ int iIntr = 0;
+ PXHCIINTRPTR pIntr = &pThis->aInterrupters[iIntr & XHCI_INTR_MASK];
+ xhciR3SetIntrPending(pDevIns, pThis, pIntr);
+ return;
+ }
+
+ if (pszArgs && strstr(pszArgs, "genportchgevt"))
+ {
+ pHlp->pfnPrintf(pHlp, "Generating port change event...\n");
+ int iPort = 0;
+ xhciR3GenPortChgEvent(pDevIns, pThis, IDX_TO_ID(iPort));
+ return;
+ }
+
+ if (pszArgs && strstr(pszArgs, "genmfiwrapevt"))
+ {
+ pHlp->pfnPrintf(pHlp, "Generating MF Index wrap event...\n");
+ XHCI_EVENT_TRB ed;
+ RT_ZERO(ed);
+ ed.mwe.cc = XHCI_TCC_SUCCESS;
+ ed.mwe.type = XHCI_TRB_MFIDX_WRAP;
+ xhciR3WriteEvent(pDevIns, pThis, &ed, XHCI_PRIMARY_INTERRUPTER, false);
+ return;
+ }
+
+ if (pszArgs && strstr(pszArgs, "gendoorbell"))
+ {
+ pHlp->pfnPrintf(pHlp, "Generating doorbell ring..\n");
+ xhciKickWorker(pDevIns, pThis, XHCI_JOB_DOORBELL, 0);
+ return;
+ }
#endif
/* Show basic information. */
@@ -7731,6 +7787,7 @@ static DECLCALLBACK(void) xhciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, con
pcszDesc = ctxSlot.slot_state < RT_ELEMENTS(g_apszSltStates) ? g_apszSltStates[ctxSlot.slot_state] : "BAD!!!";
pHlp->pfnPrintf(pHlp, " Speed:%u Entries:%u RhPort:%u", ctxSlot.speed, ctxSlot.ctx_ent, ctxSlot.rh_port);
pHlp->pfnPrintf(pHlp, " Address:%u State:%s \n", ctxSlot.dev_addr, pcszDesc);
+ pHlp->pfnPrintf(pHlp, " Doorbells:%08X\n", pThis->aBellsRung[ID_TO_IDX(uSlotID)]);
/* Endpoint contexts. */
for (j = 1; j <= ctxSlot.ctx_ent; ++j)
diff --git a/src/VBox/Devices/USB/DrvVUSBRootHub.cpp b/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
index 7088390c..c1d5ab9d 100644
--- a/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
+++ b/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
@@ -1109,17 +1109,52 @@ static DECLCALLBACK(int) vusbRhAbortEpWorker(PVUSBDEV pDev, int EndPt, VUSBDIREC
}
-/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnAbortEp} */
-static DECLCALLBACK(int) vusbRhAbortEp(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, int EndPt, VUSBDIRECTION enmDir)
+/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnAbortEpByPort} */
+static DECLCALLBACK(int) vusbRhAbortEpByPort(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, int EndPt, VUSBDIRECTION enmDir)
{
PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
- PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pRh, uPort, "vusbRhAbortEp");
+ PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pRh, uPort, "vusbRhAbortEpByPort");
+
+ /* We expect to be called from a device like xHCI which keeps good track
+ * of device <--> port correspondence. Being called for a nonexistent
+ * device is an error.
+ */
+ AssertPtrReturn(pDev, VERR_INVALID_PARAMETER);
if (pDev->pHub != pRh)
AssertFailedReturn(VERR_INVALID_PARAMETER);
vusbDevIoThreadExecSync(pDev, (PFNRT)vusbRhAbortEpWorker, 3, pDev, EndPt, enmDir);
- vusbDevRelease(pDev, "vusbRhAbortEp");
+ vusbDevRelease(pDev, "vusbRhAbortEpByPort");
+
+ /* The reaper thread will take care of completing the URB. */
+
+ return VINF_SUCCESS;
+}
+
+
+/** @interface_method_impl{VUSBIROOTHUBCONNECTOR,pfnAbortEpByAddr} */
+static DECLCALLBACK(int) vusbRhAbortEpByAddr(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, int EndPt, VUSBDIRECTION enmDir)
+{
+ PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
+ PVUSBDEV pDev = vusbR3RhGetVUsbDevByAddrRetain(pRh, DstAddress, "vusbRhAbortEpByAddr");
+
+ /* We expect to be called from a device like OHCI which does not
+ * keep track of device <--> address correspondence and may try to
+ * cancel an address that does not correspond to a device. If there's
+ * no device, just do nothing.
+ */
+ if (!pDev)
+ return VINF_SUCCESS;
+
+ if (pDev->pHub != pRh)
+ AssertFailedReturn(VERR_INVALID_PARAMETER);
+
+ /* This method is the same as vusbRhAbortEp[ByPort], intended for old controllers
+ * which don't have a defined port <-> device relationship.
+ */
+ vusbDevIoThreadExecSync(pDev, (PFNRT)vusbRhAbortEpWorker, 3, pDev, EndPt, enmDir);
+ vusbDevRelease(pDev, "vusbRhAbortEpByAddr");
/* The reaper thread will take care of completing the URB. */
@@ -1206,7 +1241,8 @@ static DECLCALLBACK(uint32_t) vusbRhUpdateIsocFrameDelta(PVUSBIROOTHUBCONNECTOR
{
PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
AssertReturn(pRh, 0);
- PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pRh, uPort, "vusbRhUpdateIsocFrameDelta"); AssertPtr(pDev);
+ PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pRh, uPort, "vusbRhUpdateIsocFrameDelta");
+ AssertPtrReturn(pDev, 0);
PVUSBPIPE pPipe = &pDev->aPipes[EndPt];
uint32_t *puLastFrame;
int32_t uFrameDelta;
@@ -1243,7 +1279,7 @@ static DECLCALLBACK(int) vusbR3RhDevPowerOn(PVUSBIROOTHUBCONNECTOR pInterface, u
{
PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort, "vusbR3RhDevPowerOn");
- AssertPtr(pDev);
+ AssertPtrReturn(pDev, VERR_VUSB_DEVICE_NOT_ATTACHED);
int rc = VUSBIDevPowerOn(&pDev->IDevice);
vusbDevRelease(pDev, "vusbR3RhDevPowerOn");
@@ -1256,7 +1292,7 @@ static DECLCALLBACK(int) vusbR3RhDevPowerOff(PVUSBIROOTHUBCONNECTOR pInterface,
{
PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort, "vusbR3RhDevPowerOff");
- AssertPtr(pDev);
+ AssertPtrReturn(pDev, VERR_VUSB_DEVICE_NOT_ATTACHED);
int rc = VUSBIDevPowerOff(&pDev->IDevice);
vusbDevRelease(pDev, "vusbR3RhDevPowerOff");
@@ -1269,7 +1305,7 @@ static DECLCALLBACK(VUSBDEVICESTATE) vusbR3RhDevGetState(PVUSBIROOTHUBCONNECTOR
{
PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort, "vusbR3RhDevGetState");
- AssertPtr(pDev);
+ AssertPtrReturn(pDev, VUSB_DEVICE_STATE_DETACHED);
VUSBDEVICESTATE enmState = VUSBIDevGetState(&pDev->IDevice);
vusbDevRelease(pDev, "vusbR3RhDevGetState");
@@ -1282,7 +1318,7 @@ static DECLCALLBACK(bool) vusbR3RhDevIsSavedStateSupported(PVUSBIROOTHUBCONNECTO
{
PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort, "vusbR3RhDevIsSavedStateSupported");
- AssertPtr(pDev);
+ AssertPtrReturn(pDev, false);
bool fSavedStateSupported = VUSBIDevIsSavedStateSupported(&pDev->IDevice);
vusbDevRelease(pDev, "vusbR3RhDevIsSavedStateSupported");
@@ -1295,7 +1331,7 @@ static DECLCALLBACK(VUSBSPEED) vusbR3RhDevGetSpeed(PVUSBIROOTHUBCONNECTOR pInter
{
PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pThis, uPort, "vusbR3RhDevGetSpeed");
- AssertPtr(pDev);
+ AssertPtrReturn(pDev, VUSB_SPEED_UNKNOWN);
VUSBSPEED enmSpeed = pDev->IDevice.pfnGetSpeed(&pDev->IDevice);
vusbDevRelease(pDev, "vusbR3RhDevGetSpeed");
@@ -1609,7 +1645,8 @@ static DECLCALLBACK(int) vusbRhConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uin
pThis->IRhConnector.pfnReapAsyncUrbs = vusbRhReapAsyncUrbs;
pThis->IRhConnector.pfnCancelUrbsEp = vusbRhCancelUrbsEp;
pThis->IRhConnector.pfnCancelAllUrbs = vusbRhCancelAllUrbs;
- pThis->IRhConnector.pfnAbortEp = vusbRhAbortEp;
+ pThis->IRhConnector.pfnAbortEpByPort = vusbRhAbortEpByPort;
+ pThis->IRhConnector.pfnAbortEpByAddr = vusbRhAbortEpByAddr;
pThis->IRhConnector.pfnSetPeriodicFrameProcessing = vusbRhSetFrameProcessing;
pThis->IRhConnector.pfnGetPeriodicFrameRate = vusbRhGetPeriodicFrameRate;
pThis->IRhConnector.pfnUpdateIsocFrameDelta = vusbRhUpdateIsocFrameDelta;