Writes the TD of a stage and hands it to the controller. On failure the ring is put back as it was and the caller fails the stage.
1739{
1742 XhciDmaBuffer* PadBuffer = Ring->m_Controller->m_SplitPadBuffer;
1746 ULONG Packets = Ring->PacketCount(Stage->Size);
1751 ULONG ElementLeft = 0;
1754 volatile UCHAR* CycleByte;
1761
1762 Stage->TrbsWritten = 0;
1763
1764 if (Ring->m_Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment) && !
InsertLink(Ring, Stage,
TRUE))
1765 {
1768 }
1769
1770 while (Step != XhciBulkStep::Done)
1771 {
1772 IsFirst = (&Ring->m_Trbs[Ring->m_EnqueueIndex] ==
First);
1773
1774
1775 if (
Pending + Ring->m_EnqueueIndex > Ring->m_LastIndex ||
1776 (NoOps && Step == XhciBulkStep::EventData &&
1778 {
1779
1781 {
1784 }
1785 continue;
1786 }
1787
1789
1790 if (Step == XhciBulkStep::Normal)
1791 {
1793
1795 {
1796 case XhciBulkMechanism::Immediate:
1799 Chunk = Stage->Size;
1800 Step = XhciBulkStep::EventData;
1801 break;
1802
1803 case XhciBulkMechanism::DoubleBuffer:
1805 RtlCopyMemory(Stage->DoubleBuffer->VirtualAddress, Stage->Buffer, Stage->Size);
1806 Trb.
Dword[0] = Stage->DoubleBuffer->LogicalAddress.LowPart;
1807 Trb.
Dword[1] = (
ULONG)Stage->DoubleBuffer->LogicalAddress.HighPart;
1808 Chunk = Stage->Size;
1809 Step = XhciBulkStep::EventData;
1810 break;
1811
1812 case XhciBulkMechanism::Dma:
1813 if (ElementLeft == 0)
1814 {
1815 ElementAddress = (
ULONG64)
SgList->Elements[Element].Address.QuadPart;
1816 ElementLeft =
SgList->Elements[Element].Length;
1817 Element++;
1818 }
1819
1820
1823 Trb.
Dword[1] = (
ULONG)(ElementAddress >> 32);
1824 ElementAddress += Chunk;
1825 ElementLeft -= Chunk;
1826
1827 if (ElementLeft == 0 && Element >=
SgList->NumberOfElements)
1828 Step = XhciBulkStep::EventData;
1829 break;
1830
1831 default:
1832 Chunk = 0;
1833 Step = XhciBulkStep::EventData;
1834 break;
1835 }
1836
1837 Mapped += Chunk;
1838 Trb.
Dword[2] = Chunk |
1842 }
1843 else if (Step == XhciBulkStep::Pad)
1844 {
1847 Trb.
Dword[2] = PadBytes;
1850 PadBytes = 0;
1851 Step = XhciBulkStep::EventData;
1852 }
1853 else
1854 {
1859 Step = XhciBulkStep::Done;
1860 }
1861
1862 Stage->TrbsWritten++;
1863
1864 if (Step == XhciBulkStep::EventData)
1865 {
1866 if (PadBytes != 0 && PadBuffer !=
NULL)
1867 {
1869 Step = XhciBulkStep::Pad;
1870
1871
1874 }
1875 else
1876 {
1877
1880 }
1881 }
1882 else if (Step == XhciBulkStep::Normal &&
Pending == 0)
1883 {
1884 Pending = (Stage->TrbsReserved > Stage->TrbsWritten) ?
1885 min(Stage->BurstTrbBudget, Stage->TrbsReserved - Stage->TrbsWritten) :
1886 Stage->BurstTrbBudget;
1887 }
1888
1889
1892
1893 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1894 Ring->m_EnqueueIndex++;
1895
1896 if (Step == XhciBulkStep::Done && NoOps)
1897 {
1899 {
1902 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1903 Ring->m_EnqueueIndex++;
1904 }
1905 }
1906 }
1907
1908 NT_ASSERT(Stage->TrbsWritten <= Stage->TrbsReserved);
1909
1910
1911 Stage->LastSegment = Ring->m_Segment;
1912 Stage->EndIndex = Ring->m_EnqueueIndex;
1914
1919 Bulk->m_PendingStages++;
1920 Stage->OnHardware =
TRUE;
1921 Ring->m_DoorbellRung =
TRUE;
1923
1924
1926 CycleByte =
reinterpret_cast<volatile UCHAR*
>(&
First->Dword[3]);
1929
1930 Ring->RingDoorbell();
1932}
static BOOLEAN NTAPI XhciBulkNeedsNoOps(_In_ const XhciTransferRing *Ring)
static ULONG64 NTAPI XhciBulkEventData(_In_ const XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage)
static ULONG NTAPI XhciBulkPadSize(_In_ const XhciTransferRing *Ring, _In_ ULONG Size)
static const ULONG XhciBulkNoOpCount
static BOOLEAN NTAPI XhciBulkTransferIn(_In_ const XhciBulkTransfer *Transfer)
static const ULONG XhciBulkTrbBytesMax
static VOID UndoTd(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
static BOOLEAN InsertLink(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage, _In_ BOOLEAN FirstOfTd)
FORCEINLINE VOID KeMemoryBarrier(VOID)
XhciBulkMechanism Mechanism
PHYSICAL_ADDRESS LogicalAddress
#define RtlCopyMemory(Destination, Source, Length)
#define RtlZeroMemory(Destination, Length)
_In_ WDFCOLLECTION _In_ ULONG Index
WDF_EXTERN_C_START typedef _In_ WDFDEVICE _In_ WDFCONTEXT _In_ WDF_DMA_DIRECTION _In_ PSCATTER_GATHER_LIST SgList
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
struct _SCATTER_GATHER_LIST * PSCATTER_GATHER_LIST
#define XHCI_TRB_TYPE_SHIFT
#define XHCI_TRB_TD_SIZE_SHIFT
#define XHCI_TRB_INTERRUPTER_SHIFT