Changeset 59700 in vbox for trunk/src/VBox/Devices/USB
- Timestamp:
- Feb 16, 2016 12:18:30 PM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 105557
- Location:
- trunk/src/VBox/Devices/USB
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/USB/DevOHCI.cpp
r59687 r59700 137 137 typedef struct OHCI const *PCOHCI; 138 138 139 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 140 /** 141 * Host controller transfer descriptor data. 142 */ 143 typedef struct VUSBURBHCITDINT 144 { 145 /** Type of TD. */ 146 uint32_t TdType; 147 /** The address of the */ 148 RTGCPHYS32 TdAddr; 149 /** A copy of the TD. */ 150 uint32_t TdCopy[16]; 151 } VUSBURBHCITDINT; 152 153 /** 154 * The host controller data associated with each URB. 155 */ 156 typedef struct VUSBURBHCIINT 157 { 158 /** The endpoint descriptor address. */ 159 RTGCPHYS32 EdAddr; 160 /** Number of Tds in the array. */ 161 uint32_t cTds; 162 /** When this URB was created. 163 * (Used for isochronous frames and for logging.) */ 164 uint32_t u32FrameNo; 165 /** Flag indicating that the TDs have been unlinked. */ 166 bool fUnlinked; 167 } VUSBURBHCIINT; 168 #endif 139 169 140 170 /** … … 1590 1620 { 1591 1621 #ifdef LOG_ENABLED 1592 pUrb-> Hci.u32FrameNo = pThis->HcFmNumber;1622 pUrb->pHci->u32FrameNo = pThis->HcFmNumber; 1593 1623 #endif 1594 1624 pThis->aInFlight[i].GCPhysTD = GCPhysTD; … … 1609 1639 static void ohci_in_flight_add_urb(POHCI pThis, PVUSBURB pUrb) 1610 1640 { 1611 for (unsigned iTd = 0; iTd < pUrb-> Hci.cTds; iTd++)1612 ohci_in_flight_add(pThis, pUrb-> Hci.paTds[iTd].TdAddr, pUrb);1641 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++) 1642 ohci_in_flight_add(pThis, pUrb->paTds[iTd].TdAddr, pUrb); 1613 1643 } 1614 1644 … … 1694 1724 { 1695 1725 #ifdef LOG_ENABLED 1696 const int cFramesInFlight = pThis->HcFmNumber - pThis->aInFlight[i].pUrb-> Hci.u32FrameNo;1726 const int cFramesInFlight = pThis->HcFmNumber - pThis->aInFlight[i].pUrb->pHci->u32FrameNo; 1697 1727 #else 1698 1728 const int cFramesInFlight = 0; 1699 1729 #endif 1700 1730 Log2(("ohci_in_flight_remove: reaping TD=%#010x %d frames (%#010x-%#010x)\n", 1701 GCPhysTD, cFramesInFlight, pThis->aInFlight[i].pUrb-> Hci.u32FrameNo, pThis->HcFmNumber));1731 GCPhysTD, cFramesInFlight, pThis->aInFlight[i].pUrb->pHci->u32FrameNo, pThis->HcFmNumber)); 1702 1732 pThis->aInFlight[i].GCPhysTD = 0; 1703 1733 pThis->aInFlight[i].pUrb = NULL; … … 1720 1750 static int ohci_in_flight_remove_urb(POHCI pThis, PVUSBURB pUrb) 1721 1751 { 1722 int cFramesInFlight = ohci_in_flight_remove(pThis, pUrb-> Hci.paTds[0].TdAddr);1723 if (pUrb-> Hci.cTds > 1)1724 { 1725 for (unsigned iTd = 1; iTd < pUrb-> Hci.cTds; iTd++)1726 if (ohci_in_flight_remove(pThis, pUrb-> Hci.paTds[iTd].TdAddr) < 0)1752 int cFramesInFlight = ohci_in_flight_remove(pThis, pUrb->paTds[0].TdAddr); 1753 if (pUrb->pHci->cTds > 1) 1754 { 1755 for (unsigned iTd = 1; iTd < pUrb->pHci->cTds; iTd++) 1756 if (ohci_in_flight_remove(pThis, pUrb->paTds[iTd].TdAddr) < 0) 1727 1757 cFramesInFlight = -1; 1728 1758 } … … 1955 1985 * Don't unlink more than once. 1956 1986 */ 1957 if (pUrb-> Hci.fUnlinked)1987 if (pUrb->pHci->fUnlinked) 1958 1988 return true; 1959 pUrb-> Hci.fUnlinked = true;1989 pUrb->pHci->fUnlinked = true; 1960 1990 1961 1991 if (pUrb->enmType == VUSBXFERTYPE_ISOC) 1962 1992 { 1963 for (unsigned iTd = 0; iTd < pUrb-> Hci.cTds; iTd++)1993 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++) 1964 1994 { 1965 POHCIITD pITd = (POHCIITD)&pUrb-> Hci.paTds[iTd].TdCopy[0];1966 const uint32_t ITdAddr = pUrb-> Hci.paTds[iTd].TdAddr;1995 POHCIITD pITd = (POHCIITD)&pUrb->paTds[iTd].TdCopy[0]; 1996 const uint32_t ITdAddr = pUrb->paTds[iTd].TdAddr; 1967 1997 1968 1998 /* … … 1989 2019 else 1990 2020 { 1991 for (unsigned iTd = 0; iTd < pUrb-> Hci.cTds; iTd++)2021 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++) 1992 2022 { 1993 POHCITD pTd = (POHCITD)&pUrb-> Hci.paTds[iTd].TdCopy[0];1994 const uint32_t TdAddr = pUrb-> Hci.paTds[iTd].TdAddr;2023 POHCITD pTd = (POHCITD)&pUrb->paTds[iTd].TdCopy[0]; 2024 const uint32_t TdAddr = pUrb->paTds[iTd].TdAddr; 1995 2025 1996 2026 /** @todo r=bird: Messing with the toggle flag in prepare is probably not correct … … 2078 2108 if (!pEd) 2079 2109 { 2080 ohciReadEd(pThis, pUrb-> Hci.EdAddr, &Ed);2110 ohciReadEd(pThis, pUrb->pHci->EdAddr, &Ed); 2081 2111 pEd = &Ed; 2082 2112 } … … 2084 2114 if (pUrb->enmType == VUSBXFERTYPE_ISOC) 2085 2115 { 2086 for (unsigned iTd = 0; iTd < pUrb-> Hci.cTds; iTd++)2116 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++) 2087 2117 { 2088 2118 union … … 2091 2121 uint32_t au32[8]; 2092 2122 } u; 2093 if ( (pUrb-> Hci.paTds[iTd].TdAddr & ED_PTR_MASK)2123 if ( (pUrb->paTds[iTd].TdAddr & ED_PTR_MASK) 2094 2124 == (pEd->TailP & ED_PTR_MASK)) 2095 2125 { 2096 2126 Log(("%s: ohciHasUrbBeenCanceled: iTd=%d cTds=%d TdAddr=%#010RX32 canceled (tail)! [iso]\n", 2097 pUrb->pszDesc, iTd, pUrb-> Hci.cTds, pUrb->Hci.paTds[iTd].TdAddr));2127 pUrb->pszDesc, iTd, pUrb->pHci->cTds, pUrb->paTds[iTd].TdAddr)); 2098 2128 STAM_COUNTER_INC(&pThis->StatCanceledIsocUrbs); 2099 2129 return true; 2100 2130 } 2101 ohciReadITd(pThis, pUrb-> Hci.paTds[iTd].TdAddr, &u.ITd);2102 if ( u.au32[0] != pUrb-> Hci.paTds[iTd].TdCopy[0] /* hwinfo */2103 || u.au32[1] != pUrb-> Hci.paTds[iTd].TdCopy[1] /* bp0 */2104 || u.au32[3] != pUrb-> Hci.paTds[iTd].TdCopy[3] /* be */2105 || ( u.au32[2] != pUrb-> Hci.paTds[iTd].TdCopy[2] /* NextTD */2106 && iTd + 1 < pUrb-> Hci.cTds /* ignore the last one */)2107 || u.au32[4] != pUrb-> Hci.paTds[iTd].TdCopy[4] /* psw0&1 */2108 || u.au32[5] != pUrb-> Hci.paTds[iTd].TdCopy[5] /* psw2&3 */2109 || u.au32[6] != pUrb-> Hci.paTds[iTd].TdCopy[6] /* psw4&5 */2110 || u.au32[7] != pUrb-> Hci.paTds[iTd].TdCopy[7] /* psw6&7 */2131 ohciReadITd(pThis, pUrb->paTds[iTd].TdAddr, &u.ITd); 2132 if ( u.au32[0] != pUrb->paTds[iTd].TdCopy[0] /* hwinfo */ 2133 || u.au32[1] != pUrb->paTds[iTd].TdCopy[1] /* bp0 */ 2134 || u.au32[3] != pUrb->paTds[iTd].TdCopy[3] /* be */ 2135 || ( u.au32[2] != pUrb->paTds[iTd].TdCopy[2] /* NextTD */ 2136 && iTd + 1 < pUrb->pHci->cTds /* ignore the last one */) 2137 || u.au32[4] != pUrb->paTds[iTd].TdCopy[4] /* psw0&1 */ 2138 || u.au32[5] != pUrb->paTds[iTd].TdCopy[5] /* psw2&3 */ 2139 || u.au32[6] != pUrb->paTds[iTd].TdCopy[6] /* psw4&5 */ 2140 || u.au32[7] != pUrb->paTds[iTd].TdCopy[7] /* psw6&7 */ 2111 2141 ) 2112 2142 { 2113 2143 Log(("%s: ohciHasUrbBeenCanceled: iTd=%d cTds=%d TdAddr=%#010RX32 canceled! [iso]\n", 2114 pUrb->pszDesc, iTd, pUrb-> Hci.cTds, pUrb->Hci.paTds[iTd].TdAddr));2144 pUrb->pszDesc, iTd, pUrb->pHci->cTds, pUrb->paTds[iTd].TdAddr)); 2115 2145 Log2((" %.*Rhxs (cur)\n" 2116 2146 "!= %.*Rhxs (copy)\n", 2117 sizeof(u.ITd), &u.ITd, sizeof(u.ITd), &pUrb-> Hci.paTds[iTd].TdCopy[0]));2147 sizeof(u.ITd), &u.ITd, sizeof(u.ITd), &pUrb->paTds[iTd].TdCopy[0])); 2118 2148 STAM_COUNTER_INC(&pThis->StatCanceledIsocUrbs); 2119 2149 return true; 2120 2150 } 2121 pUrb-> Hci.paTds[iTd].TdCopy[2] = u.au32[2];2151 pUrb->paTds[iTd].TdCopy[2] = u.au32[2]; 2122 2152 } 2123 2153 } 2124 2154 else 2125 2155 { 2126 for (unsigned iTd = 0; iTd < pUrb-> Hci.cTds; iTd++)2156 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++) 2127 2157 { 2128 2158 union … … 2131 2161 uint32_t au32[4]; 2132 2162 } u; 2133 if ( (pUrb-> Hci.paTds[iTd].TdAddr & ED_PTR_MASK)2163 if ( (pUrb->paTds[iTd].TdAddr & ED_PTR_MASK) 2134 2164 == (pEd->TailP & ED_PTR_MASK)) 2135 2165 { 2136 2166 Log(("%s: ohciHasUrbBeenCanceled: iTd=%d cTds=%d TdAddr=%#010RX32 canceled (tail)!\n", 2137 pUrb->pszDesc, iTd, pUrb-> Hci.cTds, pUrb->Hci.paTds[iTd].TdAddr));2167 pUrb->pszDesc, iTd, pUrb->pHci->cTds, pUrb->paTds[iTd].TdAddr)); 2138 2168 STAM_COUNTER_INC(&pThis->StatCanceledGenUrbs); 2139 2169 return true; 2140 2170 } 2141 ohciReadTd(pThis, pUrb-> Hci.paTds[iTd].TdAddr, &u.Td);2142 if ( u.au32[0] != pUrb-> Hci.paTds[iTd].TdCopy[0] /* hwinfo */2143 || u.au32[1] != pUrb-> Hci.paTds[iTd].TdCopy[1] /* cbp */2144 || u.au32[3] != pUrb-> Hci.paTds[iTd].TdCopy[3] /* be */2145 || ( u.au32[2] != pUrb-> Hci.paTds[iTd].TdCopy[2] /* NextTD */2146 && iTd + 1 < pUrb-> Hci.cTds /* ignore the last one */)2171 ohciReadTd(pThis, pUrb->paTds[iTd].TdAddr, &u.Td); 2172 if ( u.au32[0] != pUrb->paTds[iTd].TdCopy[0] /* hwinfo */ 2173 || u.au32[1] != pUrb->paTds[iTd].TdCopy[1] /* cbp */ 2174 || u.au32[3] != pUrb->paTds[iTd].TdCopy[3] /* be */ 2175 || ( u.au32[2] != pUrb->paTds[iTd].TdCopy[2] /* NextTD */ 2176 && iTd + 1 < pUrb->pHci->cTds /* ignore the last one */) 2147 2177 ) 2148 2178 { 2149 2179 Log(("%s: ohciHasUrbBeenCanceled: iTd=%d cTds=%d TdAddr=%#010RX32 canceled!\n", 2150 pUrb->pszDesc, iTd, pUrb-> Hci.cTds, pUrb->Hci.paTds[iTd].TdAddr));2180 pUrb->pszDesc, iTd, pUrb->pHci->cTds, pUrb->paTds[iTd].TdAddr)); 2151 2181 Log2((" %.*Rhxs (cur)\n" 2152 2182 "!= %.*Rhxs (copy)\n", 2153 sizeof(u.Td), &u.Td, sizeof(u.Td), &pUrb-> Hci.paTds[iTd].TdCopy[0]));2183 sizeof(u.Td), &u.Td, sizeof(u.Td), &pUrb->paTds[iTd].TdCopy[0])); 2154 2184 STAM_COUNTER_INC(&pThis->StatCanceledGenUrbs); 2155 2185 return true; 2156 2186 } 2157 pUrb-> Hci.paTds[iTd].TdCopy[2] = u.au32[2];2187 pUrb->paTds[iTd].TdCopy[2] = u.au32[2]; 2158 2188 } 2159 2189 } … … 2259 2289 * Copy the data back (if IN operation) and update the TDs. 2260 2290 */ 2261 for (unsigned iTd = 0; iTd < pUrb-> Hci.cTds; iTd++)2262 { 2263 POHCIITD pITd = (POHCIITD)&pUrb-> Hci.paTds[iTd].TdCopy[0];2264 const uint32_t ITdAddr = pUrb-> Hci.paTds[iTd].TdAddr;2291 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++) 2292 { 2293 POHCIITD pITd = (POHCIITD)&pUrb->paTds[iTd].TdCopy[0]; 2294 const uint32_t ITdAddr = pUrb->paTds[iTd].TdAddr; 2265 2295 const unsigned cFrames = ((pITd->HwInfo & ITD_HWINFO_FC) >> ITD_HWINFO_FC_SHIFT) + 1; 2266 unsigned R = (pUrb-> Hci.u32FrameNo & ITD_HWINFO_SF) - (pITd->HwInfo & ITD_HWINFO_SF);2296 unsigned R = (pUrb->pHci->u32FrameNo & ITD_HWINFO_SF) - (pITd->HwInfo & ITD_HWINFO_SF); 2267 2297 if (R >= 8) 2268 2298 R = 0; /* submitted ahead of time. */ … … 2385 2415 "psw0=%x:%x psw1=%x:%x psw2=%x:%x psw3=%x:%x psw4=%x:%x psw5=%x:%x psw6=%x:%x psw7=%x:%x R=%d\n", 2386 2416 pUrb->pszDesc, ITdAddr, 2387 pUrb-> Hci.EdAddr,2417 pUrb->pHci->EdAddr, 2388 2418 pITd->HwInfo & ITD_HWINFO_SF, pThis->HcFmNumber, 2389 2419 (pITd->HwInfo & ITD_HWINFO_CC) >> ITD_HWINFO_CC_SHIFT, … … 2414 2444 unsigned cbLeft = pUrb->cbData; 2415 2445 uint8_t *pb = &pUrb->abData[0]; 2416 for (unsigned iTd = 0; iTd < pUrb-> Hci.cTds; iTd++)2417 { 2418 POHCITD pTd = (POHCITD)&pUrb-> Hci.paTds[iTd].TdCopy[0];2419 const uint32_t TdAddr = pUrb-> Hci.paTds[iTd].TdAddr;2446 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++) 2447 { 2448 POHCITD pTd = (POHCITD)&pUrb->paTds[iTd].TdCopy[0]; 2449 const uint32_t TdAddr = pUrb->paTds[iTd].TdAddr; 2420 2450 2421 2451 /* … … 2473 2503 pThis->dqic = DoneInt; 2474 2504 Log(("%s: ohciRhXferCompleteGeneralURB: ED=%#010x TD=%#010x Age=%d enmStatus=%d cbTotal=%#x NewCbp=%#010RX32 dqic=%d\n", 2475 pUrb->pszDesc, pUrb-> Hci.EdAddr, TdAddr, cFmAge, pUrb->enmStatus, Buf.cbTotal, NewCbp, pThis->dqic));2505 pUrb->pszDesc, pUrb->pHci->EdAddr, TdAddr, cFmAge, pUrb->enmStatus, Buf.cbTotal, NewCbp, pThis->dqic)); 2476 2506 } 2477 2507 else 2478 2508 { 2479 2509 Log(("%s: ohciRhXferCompleteGeneralURB: HALTED ED=%#010x TD=%#010x (age %d) pUrb->enmStatus=%d\n", 2480 pUrb->pszDesc, pUrb-> Hci.EdAddr, TdAddr, cFmAge, pUrb->enmStatus));2510 pUrb->pszDesc, pUrb->pHci->EdAddr, TdAddr, cFmAge, pUrb->enmStatus)); 2481 2511 pEd->HeadP |= ED_HEAD_HALTED; 2482 2512 pThis->dqic = 0; /* "If the Transfer Descriptor is being retired with an error, … … 2549 2579 POHCI pThis = VUSBIROOTHUBPORT_2_OHCI(pInterface); 2550 2580 LogFlow(("%s: ohciRhXferCompletion: EdAddr=%#010RX32 cTds=%d TdAddr0=%#010RX32\n", 2551 pUrb->pszDesc, pUrb-> Hci.EdAddr, pUrb->Hci.cTds, pUrb->Hci.paTds[0].TdAddr));2581 pUrb->pszDesc, pUrb->pHci->EdAddr, pUrb->pHci->cTds, pUrb->paTds[0].TdAddr)); 2552 2582 2553 2583 RTCritSectEnter(&pThis->CritSect); … … 2556 2586 /* get the current end point descriptor. */ 2557 2587 OHCIED Ed; 2558 ohciReadEd(pThis, pUrb-> Hci.EdAddr, &Ed);2588 ohciReadEd(pThis, pUrb->pHci->EdAddr, &Ed); 2559 2589 2560 2590 /* … … 2573 2603 /* Leave the TD alone - the HCD doesn't want us talking to the device. */ 2574 2604 Log(("%s: ohciRhXferCompletion: CANCELED {ED=%#010x cTds=%d TD0=%#010x age %d}\n", 2575 pUrb->pszDesc, pUrb-> Hci.EdAddr, pUrb->Hci.cTds, pUrb->Hci.paTds[0].TdAddr, cFmAge));2605 pUrb->pszDesc, pUrb->pHci->EdAddr, pUrb->pHci->cTds, pUrb->paTds[0].TdAddr, cFmAge)); 2576 2606 STAM_COUNTER_INC(&pThis->StatDroppedUrbs); 2577 2607 RTCritSectLeave(&pThis->CritSect); … … 2587 2617 { 2588 2618 Log(("%s: ohciRhXferCompletion: DROPPED {ED=%#010x cTds=%d TD0=%#010x age %d} because:%s%s%s%s%s!!!\n", 2589 pUrb->pszDesc, pUrb-> Hci.EdAddr, pUrb->Hci.cTds, pUrb->Hci.paTds[0].TdAddr, cFmAge,2619 pUrb->pszDesc, pUrb->pHci->EdAddr, pUrb->pHci->cTds, pUrb->paTds[0].TdAddr, cFmAge, 2590 2620 (Ed.HeadP & ED_HEAD_HALTED) ? " ep halted" : "", 2591 2621 (Ed.hwinfo & ED_HWINFO_SKIP) ? " ep skip" : "", 2592 (Ed.HeadP & ED_PTR_MASK) != pUrb-> Hci.paTds[0].TdAddr? " ep head-changed" : "",2622 (Ed.HeadP & ED_PTR_MASK) != pUrb->paTds[0].TdAddr ? " ep head-changed" : "", 2593 2623 cFmAge < 0 ? " td not-in-flight" : "", 2594 2624 fHasBeenCanceled ? " td canceled" : "")); … … 2609 2639 2610 2640 /* finally write back the endpoint descriptor. */ 2611 ohciWriteEd(pThis, pUrb-> Hci.EdAddr, &Ed);2641 ohciWriteEd(pThis, pUrb->pHci->EdAddr, &Ed); 2612 2642 2613 2643 /* Calculate new frame rate and wakeup the framer thread if the rate was chnaged. */ … … 2656 2686 * This will make sure the TdCopy is up to date. 2657 2687 */ 2658 const uint32_t TdAddr = pUrb-> Hci.paTds[0].TdAddr;2688 const uint32_t TdAddr = pUrb->paTds[0].TdAddr; 2659 2689 /** @todo IMPORTANT! we must check if the ED is still valid at this point!!! */ 2660 2690 if (ohciHasUrbBeenCanceled(pThis, pUrb, NULL)) … … 2668 2698 * Get and update the error counter. 2669 2699 */ 2670 POHCITD pTd = (POHCITD)&pUrb-> Hci.paTds[0].TdCopy[0];2700 POHCITD pTd = (POHCITD)&pUrb->paTds[0].TdCopy[0]; 2671 2701 unsigned cErrs = (pTd->hwinfo & TD_HWINFO_ERRORS) >> TD_ERRORS_SHIFT; 2672 2702 pTd->hwinfo &= ~TD_HWINFO_ERRORS; … … 2735 2765 if (!pUrb) 2736 2766 return false; /* retry later... */ 2737 Assert(pUrb->Hci.cTds == 1);2738 2767 2739 2768 pUrb->EndPt = (pEd->hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT; 2740 2769 pUrb->fShortNotOk = !(Td.hwinfo & TD_HWINFO_ROUNDING); 2741 2770 pUrb->enmStatus = VUSBSTATUS_OK; 2742 pUrb->Hci.EdAddr = EdAddr; 2743 pUrb->Hci.fUnlinked = false; 2744 pUrb->Hci.paTds[0].TdAddr = TdAddr; 2745 pUrb->Hci.u32FrameNo = pThis->HcFmNumber; 2746 AssertCompile(sizeof(pUrb->Hci.paTds[0].TdCopy) >= sizeof(Td)); 2747 memcpy(pUrb->Hci.paTds[0].TdCopy, &Td, sizeof(Td)); 2771 pUrb->pHci->EdAddr = EdAddr; 2772 pUrb->pHci->fUnlinked = false; 2773 pUrb->pHci->cTds = 1; 2774 pUrb->paTds[0].TdAddr = TdAddr; 2775 pUrb->pHci->u32FrameNo = pThis->HcFmNumber; 2776 AssertCompile(sizeof(pUrb->paTds[0].TdCopy) >= sizeof(Td)); 2777 memcpy(pUrb->paTds[0].TdCopy, &Td, sizeof(Td)); 2748 2778 2749 2779 /* copy data if out bound transfer. */ … … 2888 2918 /* retry later... */ 2889 2919 return false; 2890 Assert(pUrb->Hci.cTds == cTds);2891 2920 Assert(pUrb->cbData == cbTotal); 2892 2921 … … 2896 2925 pUrb->fShortNotOk = !(pTail->Td.hwinfo & TD_HWINFO_ROUNDING); 2897 2926 pUrb->enmStatus = VUSBSTATUS_OK; 2898 pUrb->Hci.EdAddr = EdAddr; 2899 pUrb->Hci.fUnlinked = false; 2900 pUrb->Hci.u32FrameNo = pThis->HcFmNumber; 2927 pUrb->pHci->cTds = cTds; 2928 pUrb->pHci->EdAddr = EdAddr; 2929 pUrb->pHci->fUnlinked = false; 2930 pUrb->pHci->u32FrameNo = pThis->HcFmNumber; 2901 2931 2902 2932 /* Copy data and TD information. */ … … 2917 2947 2918 2948 /* TD info */ 2919 pUrb-> Hci.paTds[iTd].TdAddr = pCur->TdAddr;2920 AssertCompile(sizeof(pUrb-> Hci.paTds[iTd].TdCopy) >= sizeof(pCur->Td));2921 memcpy(pUrb-> Hci.paTds[iTd].TdCopy, &pCur->Td, sizeof(pCur->Td));2949 pUrb->paTds[iTd].TdAddr = pCur->TdAddr; 2950 AssertCompile(sizeof(pUrb->paTds[iTd].TdCopy) >= sizeof(pCur->Td)); 2951 memcpy(pUrb->paTds[iTd].TdCopy, &pCur->Td, sizeof(pCur->Td)); 2922 2952 } 2923 2953 … … 2985 3015 2986 3016 /* Update the copy and write it back. */ 2987 POHCIITD pITdPrev = ((POHCIITD)pUrbPrev-> Hci.paTds[0].TdCopy);3017 POHCIITD pITdPrev = ((POHCIITD)pUrbPrev->paTds[0].TdCopy); 2988 3018 pITdPrev->NextTD = (pITdPrev->NextTD & ~ED_PTR_MASK) | ITdAddrNext; 2989 3019 ohciWriteITd(pThis, ITdAddrPrev, pITdPrev, "ohciServiceIsochronousEndpoint"); … … 3002 3032 if (pUrb) 3003 3033 { 3004 pUrb-> Hci.fUnlinked = true;3034 pUrb->pHci->fUnlinked = true; 3005 3035 if (ohciHasUrbBeenCanceled(pThis, pUrb, pEd)) /* ensures the copy is correct (paranoia). */ 3006 3036 return false; 3007 3037 3008 POHCIITD pITdCopy = ((POHCIITD)pUrb-> Hci.paTds[0].TdCopy);3038 POHCIITD pITdCopy = ((POHCIITD)pUrb->paTds[0].TdCopy); 3009 3039 pITd->NextTD = pITdCopy->NextTD &= ~ED_PTR_MASK; 3010 3040 } … … 3097 3127 return false; 3098 3128 3099 pUrb->EndPt = (pEd->hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT; 3100 pUrb->fShortNotOk = false; 3101 pUrb->enmStatus = VUSBSTATUS_OK; 3102 pUrb->Hci.EdAddr = EdAddr; 3103 pUrb->Hci.fUnlinked = false; 3104 pUrb->Hci.u32FrameNo = pThis->HcFmNumber; 3105 pUrb->Hci.paTds[0].TdAddr = ITdAddr; 3106 AssertCompile(sizeof(pUrb->Hci.paTds[0].TdCopy) >= sizeof(*pITd)); 3107 memcpy(pUrb->Hci.paTds[0].TdCopy, pITd, sizeof(*pITd)); 3129 pUrb->EndPt = (pEd->hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT; 3130 pUrb->fShortNotOk = false; 3131 pUrb->enmStatus = VUSBSTATUS_OK; 3132 pUrb->pHci->EdAddr = EdAddr; 3133 pUrb->pHci->cTds = 1; 3134 pUrb->pHci->fUnlinked = false; 3135 pUrb->pHci->u32FrameNo = pThis->HcFmNumber; 3136 pUrb->paTds[0].TdAddr = ITdAddr; 3137 AssertCompile(sizeof(pUrb->paTds[0].TdCopy) >= sizeof(*pITd)); 3138 memcpy(pUrb->paTds[0].TdCopy, pITd, sizeof(*pITd)); 3108 3139 #if 0 /* color the data */ 3109 3140 memset(pUrb->abData, 0xfe, cbTotal); … … 5900 5931 } 5901 5932 5933 /* Set URB parameters. */ 5934 rc = VUSBIRhSetUrbParams(pThis->RootHub.pIRhConn, sizeof(VUSBURBHCIINT), sizeof(VUSBURBHCITDINT)); 5935 if (RT_FAILURE(rc)) 5936 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 5937 N_("OHCI: Failed to set URB parameters")); 5938 5902 5939 /* 5903 5940 * Calculate the timer intervals. … … 5914 5951 if (RT_FAILURE(rc)) 5915 5952 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 5916 N_(" EHCI: Failed to create critical section"));5953 N_("OHCI: Failed to create critical section")); 5917 5954 5918 5955 rc = RTSemEventMultiCreate(&pThis->hSemEventFrame); -
trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
r59688 r59700 373 373 * Reuse or allocate a new URB. 374 374 */ 375 /* Get the required amount of additional memory to allocate the whole state. */ 376 size_t cbMem = RT_ALIGN_32(cbData, 16) + pRh->cbHci + cTds * pRh->cbHciTd; 377 375 378 /** @todo try find a best fit, MSD which submits rather big URBs intermixed with small control 376 379 * messages ends up with a 2+ of these big URBs when a single one is sufficient. */ … … 383 386 while (pUrb) 384 387 { 385 if ( pUrb->VUsb.cbDataAllocated >= cbData 386 && pUrb->VUsb.cTdsAllocated >= cTds) 388 if (pUrb->VUsb.cbDataAllocated >= cbData) 389 { 390 /* Unlink and verify part of the state. */ 391 if (pUrbPrev) 392 pUrbPrev->VUsb.pNext = pUrb->VUsb.pNext; 393 else 394 pRh->pFreeUrbs = pUrb->VUsb.pNext; 395 Assert(pUrb->u32Magic == VUSBURB_MAGIC); 396 Assert(pUrb->VUsb.pvFreeCtx == pRh); 397 Assert(pUrb->VUsb.pfnFree == vusbRhFreeUrb); 398 Assert(pUrb->enmState == VUSBURBSTATE_FREE); 399 Assert(!pUrb->VUsb.pNext || pUrb->VUsb.pNext->enmState == VUSBURBSTATE_FREE); 387 400 break; 401 } 388 402 pUrbPrev = pUrb; 389 403 pUrb = pUrb->VUsb.pNext; 390 404 } 391 if (pUrb) 392 { 393 if (pUrbPrev) 394 pUrbPrev->VUsb.pNext = pUrb->VUsb.pNext; 395 else 396 pRh->pFreeUrbs = pUrb->VUsb.pNext; 397 Assert(pUrb->u32Magic == VUSBURB_MAGIC); 398 Assert(pUrb->VUsb.pvFreeCtx == pRh); 399 Assert(pUrb->VUsb.pfnFree == vusbRhFreeUrb); 400 Assert(pUrb->enmState == VUSBURBSTATE_FREE); 401 Assert(!pUrb->VUsb.pNext || pUrb->VUsb.pNext->enmState == VUSBURBSTATE_FREE); 402 } 403 else 405 406 if (!pUrb) 404 407 { 405 408 /* allocate a new one. */ 406 uint32_t cbDataAllocated = cbData <= _4K ? RT_ALIGN_32(cbData, _1K) 407 : cbData <= _32K ? RT_ALIGN_32(cbData, _4K) 408 : RT_ALIGN_32(cbData, 16*_1K); 409 uint32_t cTdsAllocated = RT_ALIGN_32(cTds, 16); 410 411 pUrb = (PVUSBURB)RTMemAlloc( RT_OFFSETOF(VUSBURB, abData[cbDataAllocated + 16]) 412 + sizeof(pUrb->Hci.paTds[0]) * cTdsAllocated); 409 uint32_t cbDataAllocated = cbMem <= _4K ? RT_ALIGN_32(cbMem, _1K) 410 : cbMem <= _32K ? RT_ALIGN_32(cbMem, _4K) 411 : RT_ALIGN_32(cbMem, 16*_1K); 412 413 pUrb = (PVUSBURB)RTMemAlloc(RT_OFFSETOF(VUSBURB, abData[cbDataAllocated])); 413 414 if (RT_UNLIKELY(!pUrb)) 414 415 { … … 422 423 pUrb->VUsb.pfnFree = vusbRhFreeUrb; 423 424 pUrb->VUsb.cbDataAllocated = cbDataAllocated; 424 pUrb->VUsb.cTdsAllocated = cTdsAllocated;425 pUrb->Hci.paTds = (VUSBURB::VUSBURBHCI::VUSBURBHCITD *)(&pUrb->abData[cbDataAllocated + 16]);426 425 } 427 426 RTCritSectLeave(&pRh->CritSectFreeUrbs); … … 430 429 * (Re)init the URB 431 430 */ 432 pUrb->enmState = VUSBURBSTATE_ALLOCATED;433 pUrb->fCompleting = false;434 pUrb->pszDesc = NULL;435 pUrb->VUsb.pNext = NULL;436 pUrb->VUsb.ppPrev = NULL;437 pUrb->VUsb.pCtrlUrb = NULL;431 pUrb->enmState = VUSBURBSTATE_ALLOCATED; 432 pUrb->fCompleting = false; 433 pUrb->pszDesc = NULL; 434 pUrb->VUsb.pNext = NULL; 435 pUrb->VUsb.ppPrev = NULL; 436 pUrb->VUsb.pCtrlUrb = NULL; 438 437 pUrb->VUsb.u64SubmitTS = 0; 439 pUrb->VUsb.pDev = vusbRhFindDevByAddress(pRh, DstAddress); 440 pUrb->Hci.EdAddr = ~0; 441 pUrb->Hci.cTds = cTds; 442 pUrb->Hci.pNext = NULL; 443 pUrb->Hci.u32FrameNo = 0; 444 pUrb->Hci.fUnlinked = false; 445 pUrb->Dev.pvPrivate = NULL; 446 pUrb->Dev.pNext = NULL; 447 pUrb->pUsbIns = pUrb->VUsb.pDev ? pUrb->VUsb.pDev->pUsbIns : NULL; 448 pUrb->DstAddress = DstAddress; 449 pUrb->EndPt = ~0; 450 pUrb->enmType = enmType; 451 pUrb->enmDir = enmDir; 452 pUrb->fShortNotOk = false; 453 pUrb->enmStatus = VUSBSTATUS_INVALID; 454 pUrb->cbData = cbData; 438 pUrb->VUsb.pvReadAhead = NULL; 439 pUrb->VUsb.pDev = vusbRhFindDevByAddress(pRh, DstAddress); 440 pUrb->Dev.pvPrivate = NULL; 441 pUrb->Dev.pNext = NULL; 442 pUrb->DstAddress = DstAddress; 443 pUrb->EndPt = ~0; 444 pUrb->enmType = enmType; 445 pUrb->enmDir = enmDir; 446 pUrb->fShortNotOk = false; 447 pUrb->enmStatus = VUSBSTATUS_INVALID; 448 pUrb->cbData = cbData; 449 pUrb->pHci = pRh->cbHci ? (PVUSBURBHCI)&pUrb->abData[cbData] : NULL; 450 pUrb->paTds = (pRh->cbHciTd && cTds) ? (PVUSBURBHCITD)&pUrb->abData[cbData + pRh->cbHci] : NULL; 455 451 456 452 #ifdef LOG_ENABLED … … 486 482 487 483 484 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetUrbParams */ 485 static DECLCALLBACK(int) vusbRhSetUrbParams(PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd) 486 { 487 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface); 488 489 pRh->cbHci = cbHci; 490 pRh->cbHciTd = cbHciTd; 491 492 return VINF_SUCCESS; 493 } 494 495 488 496 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnNewUrb */ 489 497 static DECLCALLBACK(PVUSBURB) vusbRhConnNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, VUSBXFERTYPE enmType, … … 545 553 */ 546 554 int rc; 547 if ( 548 && pUrb->pUsbIns)555 if ( pUrb->VUsb.pDev 556 && pUrb->VUsb.pDev->pUsbIns) 549 557 { 550 558 switch (pUrb->enmDir) … … 1052 1060 pThis->pDrvIns = pDrvIns; 1053 1061 /* the connector */ 1062 pThis->IRhConnector.pfnSetUrbParams = vusbRhSetUrbParams; 1054 1063 pThis->IRhConnector.pfnNewUrb = vusbRhConnNewUrb; 1055 1064 pThis->IRhConnector.pfnSubmitUrb = vusbRhSubmitUrb; … … 1061 1070 pThis->IRhConnector.pfnDetachDevice = vusbRhDetachDevice; 1062 1071 pThis->hSniffer = VUSBSNIFFER_NIL; 1072 pThis->cbHci = 0; 1073 pThis->cbHciTd = 0; 1063 1074 #ifdef LOG_ENABLED 1064 1075 pThis->iSerial = 0; -
trunk/src/VBox/Devices/USB/USBProxyDevice.cpp
r59117 r59700 67 67 VUSBURB Urb; 68 68 AssertCompile(RT_SIZEOFMEMB(VUSBURB, abData) >= _4K); 69 Urb.u32Magic = VUSBURB_MAGIC;70 Urb.enmState = VUSBURBSTATE_IN_FLIGHT;71 Urb.pszDesc = (char*)"URB sync";72 memset(&Urb.VUsb, 0, sizeof(Urb.VUsb));73 memset(&Urb.Hci, 0, sizeof(Urb.Hci));69 Urb.u32Magic = VUSBURB_MAGIC; 70 Urb.enmState = VUSBURBSTATE_IN_FLIGHT; 71 Urb.pszDesc = (char*)"URB sync"; 72 Urb.pHci = NULL; 73 Urb.paTds = NULL; 74 74 Urb.Dev.pvPrivate = NULL; 75 Urb.Dev.pNext = NULL;76 Urb. pUsbIns = pProxyDev->pUsbIns;77 Urb. DstAddress= 0;78 Urb. EndPt = 0;79 Urb.enm Type = VUSBXFERTYPE_MSG;80 Urb. enmDir = VUSBDIRECTION_IN;81 Urb. fShortNotOk = false;82 Urb.enmStatus = VUSBSTATUS_INVALID;75 Urb.Dev.pNext = NULL; 76 Urb.DstAddress = 0; 77 Urb.EndPt = 0; 78 Urb.enmType = VUSBXFERTYPE_MSG; 79 Urb.enmDir = VUSBDIRECTION_IN; 80 Urb.fShortNotOk = false; 81 Urb.VUsb.pCtrlUrb = NULL; 82 Urb.enmStatus = VUSBSTATUS_INVALID; 83 83 cbHint = RT_MIN(cbHint, sizeof(Urb.abData) - sizeof(VUSBSETUP)); 84 84 Urb.cbData = cbHint + sizeof(VUSBSETUP); -
trunk/src/VBox/Devices/USB/VUSBInternal.h
r59687 r59700 364 364 /** Version of the attached Host Controller. */ 365 365 uint32_t fHcVersions; 366 /** Size of the HCI specific data for each URB. */ 367 size_t cbHci; 368 /** Size of the HCI specific TD. */ 369 size_t cbHciTd; 366 370 #ifdef LOG_ENABLED 367 371 /** A serial number for URBs submitted on the roothub instance. -
trunk/src/VBox/Devices/USB/VUSBReadAhead.cpp
r59687 r59700 110 110 return NULL; 111 111 112 pUrb = vusbRhNewUrb(pRh, pDev->u8Address, VUSBXFERTYPE_ISOC, VUSBDIRECTION_IN, cbTotal, 1, NULL);112 pUrb = vusbRhNewUrb(pRh, pDev->u8Address, VUSBXFERTYPE_ISOC, VUSBDIRECTION_IN, cbTotal, 1, "prab"); 113 113 if (!pUrb) 114 114 /* not much we can do here... */ … … 118 118 pUrb->fShortNotOk = false; 119 119 pUrb->enmStatus = VUSBSTATUS_OK; 120 pUrb->Hci.EdAddr = 0;121 pUrb->Hci.fUnlinked = false;122 // @todo: fill in the rest? The Hci member is not relevant123 #ifdef LOG_ENABLED124 static unsigned s_iSerial = 0;125 s_iSerial = (s_iSerial + 1) % 10000;126 RTStrAPrintf(&pUrb->pszDesc, "URB %p prab<%04d", pUrb, s_iSerial); // prab = Periodic Read-Ahead Buffer127 #endif128 120 129 121 /* Set up the individual packets, again with bInterval in mind */ … … 224 216 Assert(pUrb->enmState == VUSBURBSTATE_ALLOCATED); 225 217 226 // @todo: at the moment we abuse the Hci.pNext member (which is otherwise entirely unused!) 227 pUrb->Hci.pNext = (PVUSBURB)pvUser; 228 218 pUrb->VUsb.pvReadAhead = pvUser; 229 219 pUrb->enmState = VUSBURBSTATE_IN_FLIGHT; 230 220 rc = vusbUrbQueueAsyncRh(pUrb); … … 260 250 PVUSBURB pBufferedUrb = pThis->pBuffUrbHead; 261 251 262 pThis->pBuffUrbHead = pBufferedUrb->Hci.pNext;252 pThis->pBuffUrbHead = (PVUSBURB)pBufferedUrb->VUsb.pvReadAhead; 263 253 pBufferedUrb->VUsb.pfnFree(pBufferedUrb); 264 254 } … … 279 269 { 280 270 Assert(pUrb); 281 Assert(pUrb-> Hci.pNext);282 PVUSBREADAHEADINT pThis = (PVUSBREADAHEADINT)pUrb-> Hci.pNext;271 Assert(pUrb->VUsb.pvReadAhead); 272 PVUSBREADAHEADINT pThis = (PVUSBREADAHEADINT)pUrb->VUsb.pvReadAhead; 283 273 PVUSBPIPE pPipe = pThis->pPipe; 284 274 Assert(pPipe); 285 275 286 276 RTCritSectEnter(&pThis->CritSectBuffUrbList); 287 pUrb-> Hci.pNext = NULL; // @todo: use a more suitable field277 pUrb->VUsb.pvReadAhead = NULL; 288 278 if (pThis->pBuffUrbHead == NULL) 289 279 { … … 296 286 // Some URBs are queued already 297 287 Assert(pThis->pBuffUrbTail); 298 Assert(!pThis->pBuffUrbTail->Hci.pNext); 299 pThis->pBuffUrbTail = pThis->pBuffUrbTail->Hci.pNext = pUrb; 288 Assert(!pThis->pBuffUrbTail->VUsb.pvReadAhead); 289 pThis->pBuffUrbTail->VUsb.pvReadAhead = pUrb; 290 pThis->pBuffUrbTail = pUrb; 300 291 } 301 292 ASMAtomicDecU32(&pThis->cSubmitted); … … 327 318 328 319 // There's a URB available in the read-ahead buffer; use it 329 pThis->pBuffUrbHead = pBufferedUrb->Hci.pNext;320 pThis->pBuffUrbHead = (PVUSBURB)pBufferedUrb->VUsb.pvReadAhead; 330 321 if (pThis->pBuffUrbHead == NULL) 331 322 pThis->pBuffUrbTail = NULL; -
trunk/src/VBox/Devices/USB/VUSBSnifferUsbMon.cpp
r59686 r59700 175 175 176 176 cch += RTStrPrintf(&aszLineBuf[cch], sizeof(aszLineBuf) - cch, ":%u:%u:%u ", 177 1 /* Interval */, pUrb->Hci.u32FrameNo, u32ErrorCount);177 1 /* Interval */, 0 /* Frame number */, u32ErrorCount); 178 178 } 179 179 else 180 180 cch += RTStrPrintf(&aszLineBuf[cch], sizeof(aszLineBuf) - cch, ":%u:%u ", 181 1 /* Interval */, pUrb->Hci.u32FrameNo);181 1 /* Interval */, 0 /* Frame number */); 182 182 } 183 183 else if (pUrb->enmType == VUSBXFERTYPE_INTR) -
trunk/src/VBox/Devices/USB/VUSBUrb.cpp
r57358 r59700 162 162 * Logs an URB. 163 163 * 164 * Note that pUrb-> pUsbIns, pUrb->VUsb.pDev and pUrb->VUsb.pDev->pUsbIns can all be NULL.164 * Note that pUrb->VUsb.pDev and pUrb->VUsb.pDev->pUsbIns can all be NULL. 165 165 */ 166 166 void vusbUrbTrace(PVUSBURB pUrb, const char *pszMsg, bool fComplete) … … 177 177 s_cchMaxMsg = cchMsg; 178 178 179 Log(("%s: %*s: pDev=%p[%s] rc=%s a=%i e=%u d=%s t=%s cb=%#x(%d) Ed=%08x cTds=%d Td0=%08xts=%RU64 (%RU64 ns ago) %s\n",179 Log(("%s: %*s: pDev=%p[%s] rc=%s a=%i e=%u d=%s t=%s cb=%#x(%d) ts=%RU64 (%RU64 ns ago) %s\n", 180 180 pUrb->pszDesc, s_cchMaxMsg, pszMsg, 181 181 pDev, 182 pUrb-> pUsbIns ? pUrb->pUsbIns->pszName : "",182 pUrb->VUsb.pDev ? pUrb->VUsb.pDev->pUsbIns->pszName : "", 183 183 vusbUrbStatusName(pUrb->enmStatus), 184 184 pDev ? pDev->u8Address : -1, … … 188 188 pUrb->cbData, 189 189 pUrb->cbData, 190 pUrb->Hci.EdAddr,191 pUrb->Hci.cTds,192 pUrb->Hci.cTds ? pUrb->Hci.paTds[0].TdAddr : ~(uint32_t)0,193 190 pUrb->VUsb.u64SubmitTS, 194 191 RTTimeNanoTS() - pUrb->VUsb.u64SubmitTS, … … 1171 1168 return pUrb->EndPt != 0 /* not default control pipe */ 1172 1169 || pSetup->wValue != 0 /* not ENDPOINT_HALT */ 1173 || !pUrb-> pUsbIns->pReg->pfnUsbClearHaltedEndpoint; /* not special need for backend */1170 || !pUrb->VUsb.pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint; /* not special need for backend */ 1174 1171 case VUSB_REQ_SET_ADDRESS: 1175 1172 case VUSB_REQ_SET_CONFIGURATION: … … 1229 1226 1230 1227 RTCritSectEnter(&pDev->CritSectAsyncUrbs); 1231 int rc = p Urb->pUsbIns->pReg->pfnUrbQueue(pUrb->pUsbIns, pUrb);1228 int rc = pDev->pUsbIns->pReg->pfnUrbQueue(pDev->pUsbIns, pUrb); 1232 1229 if (RT_FAILURE(rc)) 1233 1230 { … … 1416 1413 //pExtra->Urb.Hci = {0}; 1417 1414 //pExtra->Urb.Dev.pvProxyUrb = NULL; 1418 pExtra->Urb.pUsbIns = pUrb->pUsbIns;1419 1415 pExtra->Urb.DstAddress = pUrb->DstAddress; 1420 1416 pExtra->Urb.EndPt = pUrb->EndPt; … … 2086 2082 #ifdef VBOX_WITH_USB 2087 2083 // Read-ahead URBs are handled differently 2088 if (pUrb-> Hci.pNext != NULL)2084 if (pUrb->VUsb.pvReadAhead) 2089 2085 vusbUrbCompletionReadAhead(pUrb); 2090 2086 else … … 2117 2113 2118 2114 pUrb->enmState = VUSBURBSTATE_CANCELLED; 2119 PPDMUSBINS pUsbIns = pUrb-> pUsbIns;2115 PPDMUSBINS pUsbIns = pUrb->VUsb.pDev->pUsbIns; 2120 2116 pUsbIns->pReg->pfnUrbCancel(pUsbIns, pUrb); 2121 2117 Assert(pUrb->enmState == VUSBURBSTATE_CANCELLED || pUrb->enmState == VUSBURBSTATE_REAPED);
Note:
See TracChangeset
for help on using the changeset viewer.