diff options
Diffstat (limited to 'src/VBox/Devices/USB')
-rw-r--r-- | src/VBox/Devices/USB/DevEHCI.cpp | 50 | ||||
-rw-r--r-- | src/VBox/Devices/USB/DevOHCI.cpp | 93 | ||||
-rw-r--r-- | src/VBox/Devices/USB/DevXHCI.cpp | 103 | ||||
-rw-r--r-- | src/VBox/Devices/USB/DrvVUSBRootHub.cpp | 59 |
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; |