https://git.reactos.org/?p=reactos.git;a=commitdiff;h=378294a7dfd1b939aac5b45fa230678927744d29

commit 378294a7dfd1b939aac5b45fa230678927744d29
Author:     Michael Stamper <[email protected]>
AuthorDate: Wed Jan 5 00:20:44 2022 +0000
Commit:     GitHub <[email protected]>
CommitDate: Wed Jan 5 03:20:44 2022 +0300

    [PORTCLS] Fix races, fix WavePci Port Drivers
    
    - Split buffers on page to prevent non-contiguous memory being passed to 
driver.
    - Protect CIrpQueue::GetMappingWithTag, ReleaseMappingWithTag with spinlock 
to prevent race conditions
      (GetMapping, ReleaseMapping do not need spinlock, they are only called 
from a service routine).
    - Remove ASSERT in CIrpQueue::ReleaseMappingWithTag, when mappings are 
released out of order. Just ignore
      the tag argument and release the next one in the list. This is what 
windows does, confirmed by calling
      PortWavePciStream::ReleaseMapping() with tag argument set to 0, absolutly 
no difference observed.
      Allowing out of order release is essential given that a driver is not 
permitted to hold a spinlock when calling
      ReleaseMapping().
    - Remove IIrpQueue::HasLastMappingFailed(), it never worked and there is no 
way it could work.
      CPortPinWavePci::HandleKsStream() call MappingAvailable() 
non-conditionally, this is what Windows does,
      verified by debug prints in ac97 driver.
    - Implement CIrpQueue::NumData().
    - Remove incorrect interlocked operations/volatile variables and several 
(now unused) class fields.
---
 drivers/wdm/audio/backpln/portcls/interfaces.hpp  |   1 -
 drivers/wdm/audio/backpln/portcls/irpstream.cpp   | 433 +++++++++++++---------
 drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp |   5 +-
 3 files changed, 256 insertions(+), 183 deletions(-)

diff --git a/drivers/wdm/audio/backpln/portcls/interfaces.hpp 
b/drivers/wdm/audio/backpln/portcls/interfaces.hpp
index ce924174852..d525b85ccfa 100644
--- a/drivers/wdm/audio/backpln/portcls/interfaces.hpp
+++ b/drivers/wdm/audio/backpln/portcls/interfaces.hpp
@@ -350,7 +350,6 @@ DECLARE_INTERFACE_(IIrpQueue, IUnknown)
     STDMETHOD_(NTSTATUS, ReleaseMappingWithTag)(THIS_
         IN PVOID Tag) PURE;
 
-    STDMETHOD_(BOOLEAN, HasLastMappingFailed)(THIS) PURE;
     STDMETHOD_(ULONG, GetCurrentIrpOffset)(THIS) PURE;
 
     STDMETHOD_(BOOLEAN, GetAcquiredTagRange)(THIS_
diff --git a/drivers/wdm/audio/backpln/portcls/irpstream.cpp 
b/drivers/wdm/audio/backpln/portcls/irpstream.cpp
index 572117e27d3..75f0717ec88 100644
--- a/drivers/wdm/audio/backpln/portcls/irpstream.cpp
+++ b/drivers/wdm/audio/backpln/portcls/irpstream.cpp
@@ -14,6 +14,31 @@
 
 #include <debug.h>
 
+static
+PIRP
+RemoveHeadList_IRP(
+    IN OUT PLIST_ENTRY QueueHead)
+{
+    PIRP Irp;
+    PLIST_ENTRY CurEntry;
+
+    for (CurEntry = QueueHead->Flink; CurEntry != QueueHead; CurEntry = 
CurEntry->Flink)
+    {
+        /* Get the IRP offset */
+        Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
+
+        /* Remove the cancel routine */
+        if (IoSetCancelRoutine(Irp, NULL))
+        {
+            /* Remove the IRP from the list and return it */
+            RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+            return Irp;
+        }
+    }
+
+    /* no non canceled irp has been found */
+    return NULL;
+}
 class CIrpQueue : public IIrpQueue
 {
 public:
@@ -48,13 +73,16 @@ protected:
     LIST_ENTRY m_IrpList;
     LIST_ENTRY m_FreeIrpList;
 
-    BOOLEAN m_OutOfMapping;
     ULONG m_MaxFrameSize;
     ULONG m_Alignment;
     ULONG m_TagSupportEnabled;
-    volatile ULONG m_NumDataAvailable;
-    volatile ULONG m_CurrentOffset;
-    volatile PIRP m_Irp;
+
+    ULONG m_StreamHeaderIndex;
+    ULONG m_TagIndex;
+    PKSSTREAM_HEADER m_CurStreamHeader;
+
+    ULONG m_CurrentOffset;
+    PIRP m_Irp;
     volatile LONG m_Ref;
 };
 
@@ -67,10 +95,8 @@ typedef struct
 typedef struct
 {
     ULONG StreamHeaderCount;
-    ULONG StreamHeaderIndex;
-    ULONG TotalStreamData;
+    ULONG nTags;
 
-    PKSSTREAM_HEADER CurStreamHeader;
     PVOID * Data;
     PKSSTREAM_TAG Tags;
 }KSSTREAM_DATA, *PKSSTREAM_DATA;
@@ -128,6 +154,9 @@ CIrpQueue::AddMapping(
     ULONG Index, Length;
     PMDL Mdl;
     PKSSTREAM_DATA StreamData;
+    LONG TotalStreamData;
+    LONG StreamPageCount;
+    LONG HeaderLength;
 
     PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
 
@@ -165,14 +194,15 @@ CIrpQueue::AddMapping(
     // get first stream header
     Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
 
-    // store header
-    StreamData->CurStreamHeader = Header;
-
     // sanity check
     PC_ASSERT(Header);
 
     // first calculate the numbers of stream headers
     Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+    Mdl = Irp->MdlAddress;
+
+    TotalStreamData = 0;
+    StreamPageCount = 0;
 
     do
     {
@@ -185,15 +215,23 @@ CIrpQueue::AddMapping(
         if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN)
         {
             // irp sink
-            StreamData->TotalStreamData += Header->DataUsed;
+            HeaderLength = Header->DataUsed;
         }
         else
         {
             // irp source
-            StreamData->TotalStreamData += Header->FrameExtent;
+            HeaderLength = Header->FrameExtent;
         }
 
-        /* move to next header */
+        // increment available data
+        TotalStreamData += HeaderLength;
+
+        // append page count
+        StreamPageCount += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+                               MmGetMdlByteOffset(Mdl), HeaderLength);
+
+        // move to next header / mdl
+        Mdl = Mdl->Next;
         Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size);
 
     }while(Length);
@@ -215,7 +253,7 @@ CIrpQueue::AddMapping(
     if (m_TagSupportEnabled)
     {
         // allocate array for storing the pointers of the data */
-        StreamData->Tags = (PKSSTREAM_TAG)AllocateItem(NonPagedPool, 
sizeof(KSSTREAM_TAG) * StreamData->StreamHeaderCount, TAG_PORTCLASS);
+        StreamData->Tags = (PKSSTREAM_TAG)AllocateItem(NonPagedPool, 
sizeof(KSSTREAM_TAG) * StreamPageCount, TAG_PORTCLASS);
         if (!StreamData->Data)
         {
             // out of memory
@@ -254,17 +292,6 @@ CIrpQueue::AddMapping(
             return STATUS_INSUFFICIENT_RESOURCES;
         }
 
-        if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN)
-        {
-            // increment available data
-            InterlockedExchangeAdd((PLONG)&m_NumDataAvailable, 
Header->DataUsed);
-        }
-        else if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT)
-        {
-            // increment available data
-            InterlockedExchangeAdd((PLONG)&m_NumDataAvailable, 
Header->FrameExtent);
-        }
-
         // move to next header / mdl
         Mdl = Mdl->Next;
         Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size);
@@ -274,7 +301,7 @@ CIrpQueue::AddMapping(
     // store stream data
     Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET] = (PVOID)StreamData;
 
-    *Data = StreamData->TotalStreamData;
+    *Data = TotalStreamData;
 
     // mark irp as pending
     IoMarkIrpPending(Irp);
@@ -282,9 +309,6 @@ CIrpQueue::AddMapping(
     // add irp to cancelable queue
     KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, Irp, 
KsListEntryTail, NULL);
 
-    // disable mapping failed status
-    m_OutOfMapping = FALSE;
-
     // done
     return STATUS_SUCCESS;
 }
@@ -322,6 +346,15 @@ CIrpQueue::GetMapping(
         // get a fresh new irp from the queue
         m_Irp = Irp = KsRemoveIrpFromCancelableQueue(&m_IrpList, 
&m_IrpListLock, KsListEntryHead, KsAcquireAndRemoveOnlySingleItem);
         m_CurrentOffset = Offset = 0;
+
+        if (m_Irp)
+        {
+            // reset stream header index
+            m_StreamHeaderIndex = 0;
+
+            // reset stream header
+            m_CurStreamHeader = 
(PKSSTREAM_HEADER)m_Irp->AssociatedIrp.SystemBuffer;
+        }
     }
 
     if (!Irp)
@@ -340,22 +373,19 @@ CIrpQueue::GetMapping(
     if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN)
     {
         // sink pin
-        *BufferSize = StreamData->CurStreamHeader->DataUsed - Offset;
+        *BufferSize = m_CurStreamHeader->DataUsed - Offset;
     }
     else
     {
         // source pin
-        *BufferSize = StreamData->CurStreamHeader->FrameExtent - Offset;
+        *BufferSize = m_CurStreamHeader->FrameExtent - Offset;
     }
 
     // sanity check
     PC_ASSERT(*BufferSize);
 
     // store buffer
-    *Buffer = 
&((PUCHAR)StreamData->Data[StreamData->StreamHeaderIndex])[Offset];
-
-    // unset flag that no irps are available
-    m_OutOfMapping = FALSE;
+    *Buffer = &((PUCHAR)StreamData->Data[m_StreamHeaderIndex])[Offset];
 
     return STATUS_SUCCESS;
 }
@@ -381,22 +411,19 @@ CIrpQueue::UpdateMapping(
     ASSERT(StreamData);
 
     // add to current offset
-    InterlockedExchangeAdd((PLONG)&m_CurrentOffset, (LONG)BytesWritten);
+    m_CurrentOffset += BytesWritten;
 
     if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT)
     {
         // store written bytes (source pin)
-        StreamData->CurStreamHeader->DataUsed += BytesWritten;
+        m_CurStreamHeader->DataUsed += BytesWritten;
     }
 
-    // decrement available data counter
-    m_NumDataAvailable -= BytesWritten;
-
     // get audio buffer size
     if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT)
-        Size = StreamData->CurStreamHeader->FrameExtent;
+        Size = m_CurStreamHeader->FrameExtent;
     else
-        Size = StreamData->CurStreamHeader->DataUsed;
+        Size = m_CurStreamHeader->DataUsed;
 
     // sanity check
     PC_ASSERT(Size);
@@ -406,13 +433,13 @@ CIrpQueue::UpdateMapping(
         // sanity check
         PC_ASSERT(Size == m_CurrentOffset);
 
-        if (StreamData->StreamHeaderIndex + 1 < StreamData->StreamHeaderCount)
+        if (m_StreamHeaderIndex + 1 < StreamData->StreamHeaderCount)
         {
             // move to next stream header
-            StreamData->CurStreamHeader = 
(PKSSTREAM_HEADER)((ULONG_PTR)StreamData->CurStreamHeader + 
StreamData->CurStreamHeader->Size);
+            m_CurStreamHeader = 
(PKSSTREAM_HEADER)((ULONG_PTR)m_CurStreamHeader + m_CurStreamHeader->Size);
 
             // increment stream header index
-            StreamData->StreamHeaderIndex++;
+            m_StreamHeaderIndex++;
 
             // reset offset
             m_CurrentOffset = 0;
@@ -430,15 +457,6 @@ CIrpQueue::UpdateMapping(
             // looped streaming repeat the buffers untill
             // the caller decides to stop the streams
 
-            // reset stream header index
-            StreamData->StreamHeaderIndex = 0;
-
-            // reset stream header
-            StreamData->CurStreamHeader = 
(PKSSTREAM_HEADER)m_Irp->AssociatedIrp.SystemBuffer;
-
-            // increment available data
-            InterlockedExchangeAdd((PLONG)&m_NumDataAvailable, 
StreamData->TotalStreamData);
-
             // re-insert irp
             KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, m_Irp, 
KsListEntryTail, NULL);
 
@@ -495,8 +513,70 @@ ULONG
 NTAPI
 CIrpQueue::NumData()
 {
-    // returns the amount of audio stream data available
-    return m_NumDataAvailable;
+    KIRQL OldLevel;
+    ULONG NumDataAvailable;
+    PLIST_ENTRY CurEntry;
+    PIRP Irp;
+    ULONG CurrentOffset;
+    ULONG StreamHeaderIndex;
+    PKSSTREAM_HEADER CurStreamHeader;
+    PKSSTREAM_DATA StreamData;
+    ULONG Size;
+
+    KeAcquireSpinLock(&m_IrpListLock, &OldLevel);
+
+    NumDataAvailable = 0;
+    CurEntry = &m_IrpList;
+
+    // current IRP state
+    Irp = m_Irp;
+    CurrentOffset = m_CurrentOffset;
+    StreamHeaderIndex = m_StreamHeaderIndex;
+    CurStreamHeader = m_CurStreamHeader;
+
+    while (TRUE)
+    {
+        if (Irp != NULL)
+        {
+            // get stream data
+            StreamData = 
(PKSSTREAM_DATA)Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET];
+
+            // loop over stream headers
+            for (; StreamHeaderIndex < StreamData->StreamHeaderCount; 
StreamHeaderIndex++)
+            {
+                // get audio buffer size
+                if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT)
+                    Size = CurStreamHeader->FrameExtent;
+                else
+                    Size = CurStreamHeader->DataUsed;
+
+                // increment available data
+                NumDataAvailable += Size - CurrentOffset;
+                CurrentOffset = 0;
+
+                // move to next stream header
+                CurStreamHeader = 
(PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size);
+            }
+        }
+
+        /* iterate to next entry */
+        CurEntry = CurEntry->Flink;
+
+        /* is the end of list reached */
+        if (CurEntry == &m_IrpList)
+            break;
+
+        /* get irp offset */
+        Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
+
+        // next IRP state
+        CurrentOffset = 0;
+        StreamHeaderIndex = 0;
+        CurStreamHeader = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
+    }
+
+    KeReleaseSpinLock(&m_IrpListLock, OldLevel);
+    return NumDataAvailable;
 }
 
 BOOL
@@ -517,9 +597,6 @@ CIrpQueue::CancelBuffers()
     // cancel all irps
     KsCancelIo(&m_IrpList, &m_IrpListLock);
 
-    // reset number of data available
-    m_NumDataAvailable = 0;
-
     // done
     return TRUE;
 }
@@ -534,6 +611,9 @@ CIrpQueue::GetMappingWithTag(
     OUT PULONG  Flags)
 {
     PKSSTREAM_DATA StreamData;
+    KIRQL OldLevel;
+    ULONG Size;
+    LPBYTE Data;
 
     /* sanity checks */
     PC_ASSERT(PhysicalAddress);
@@ -541,77 +621,104 @@ CIrpQueue::GetMappingWithTag(
     PC_ASSERT(ByteCount);
     PC_ASSERT(Flags);
 
+    KeAcquireSpinLock(&m_IrpListLock, &OldLevel);
+
     if (!m_Irp)
     {
         // get an irp from the queue
-        m_Irp = KsRemoveIrpFromCancelableQueue(&m_IrpList, &m_IrpListLock, 
KsListEntryHead, KsAcquireAndRemoveOnlySingleItem);
-    }
+        m_Irp = RemoveHeadList_IRP(&m_IrpList);
 
-    // check if there is an irp
-    if (!m_Irp)
-    {
-        // no irp available
-        m_OutOfMapping = TRUE;
-        DPRINT("GetMappingWithTag no mapping available\n");
-        return STATUS_NOT_FOUND;
+        // check if there is an irp
+        if (!m_Irp)
+        {
+            // no irp available
+            KeReleaseSpinLock(&m_IrpListLock, OldLevel);
+
+            DPRINT("GetMappingWithTag no mapping available\n");
+            return STATUS_NOT_FOUND;
+        }
+
+        // reset offset
+        m_CurrentOffset = 0;
+
+        // reset tag index
+        m_TagIndex = 0;
+
+        // reset stream header index
+        m_StreamHeaderIndex = 0;
+
+        // reset stream header
+        m_CurStreamHeader = 
(PKSSTREAM_HEADER)m_Irp->AssociatedIrp.SystemBuffer;
     }
 
     // get stream data
     StreamData = 
(PKSSTREAM_DATA)m_Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET];
 
     // sanity check
-    PC_ASSERT(StreamData->StreamHeaderIndex < StreamData->StreamHeaderCount);
-
-    // setup mapping
-    *PhysicalAddress = 
MmGetPhysicalAddress(StreamData->Data[StreamData->StreamHeaderIndex]);
-    *VirtualAddress = StreamData->Data[StreamData->StreamHeaderIndex];
+    PC_ASSERT(m_StreamHeaderIndex < StreamData->StreamHeaderCount);
 
     // store tag in irp
-    StreamData->Tags[StreamData->StreamHeaderIndex].Tag = Tag;
-    StreamData->Tags[StreamData->StreamHeaderIndex].Used = TRUE;
+    StreamData->Tags[m_TagIndex].Tag = Tag;
+    StreamData->Tags[m_TagIndex].Used = TRUE;
+    m_TagIndex++;
 
-    // increment header index
-    StreamData->StreamHeaderIndex++;
+    // get audio buffer size
+    if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT)
+        Size = m_CurStreamHeader->FrameExtent;
+    else
+        Size = m_CurStreamHeader->DataUsed;
 
-    // mapping size
-    if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN)
-    {
-        // sink pin
-        *ByteCount = StreamData->CurStreamHeader->DataUsed;
+    // sanity check
+    PC_ASSERT(Size);
 
-        // decrement num data available
-        m_NumDataAvailable -= StreamData->CurStreamHeader->DataUsed;
-    }
-    else
-    {
-        // source pin
-        *ByteCount = StreamData->CurStreamHeader->FrameExtent;
+    // setup mapping
+    Data = (LPBYTE)StreamData->Data[m_StreamHeaderIndex] + m_CurrentOffset;
+    *VirtualAddress = Data;
 
-        // decrement num data available
-        m_NumDataAvailable -= StreamData->CurStreamHeader->FrameExtent;
-    }
+    // get byte count
+    *ByteCount = (LPBYTE)ROUND_TO_PAGES(Data+1)-Data;
+    if (*ByteCount > (Size - m_CurrentOffset))
+        *ByteCount = (Size - m_CurrentOffset);
+    m_CurrentOffset += *ByteCount;
 
-    if (StreamData->StreamHeaderIndex == StreamData->StreamHeaderCount)
+    if (m_CurrentOffset >= Size)
     {
-        // last mapping
-        *Flags = 1;
+        // sanity check
+        PC_ASSERT(Size == m_CurrentOffset);
 
-        // insert mapping into free list
-        ExInterlockedInsertTailList(&m_FreeIrpList, 
&m_Irp->Tail.Overlay.ListEntry, &m_IrpListLock);
+        // increment header index
+        m_StreamHeaderIndex++;
 
-        // clear irp
-        m_Irp = NULL;
+        if (m_StreamHeaderIndex == StreamData->StreamHeaderCount)
+        {
+            // last mapping
+            *Flags = 1;
 
-    }
-    else
-    {
-        // one more mapping in the irp
-        *Flags = 0;
+            //
+            StreamData->nTags = m_TagIndex;
+
+            // insert mapping into free list
+            InsertTailList(&m_FreeIrpList, &m_Irp->Tail.Overlay.ListEntry);
+
+            // clear irp
+            m_Irp = NULL;
 
-        // move to next header
-        StreamData->CurStreamHeader = 
(PKSSTREAM_HEADER)((ULONG_PTR)StreamData->CurStreamHeader + 
StreamData->CurStreamHeader->Size);
+        }
+        else
+        {
+            // one more mapping in the irp
+            *Flags = 0;
+
+            // move to next header
+            m_CurStreamHeader = 
(PKSSTREAM_HEADER)((ULONG_PTR)m_CurStreamHeader + m_CurStreamHeader->Size);
+        }
     }
 
+    // get physical address
+    *PhysicalAddress = MmGetPhysicalAddress(*VirtualAddress);
+
+    KeReleaseSpinLock(&m_IrpListLock, OldLevel);
+
     DPRINT("GetMappingWithTag Tag %p Buffer %p Flags %lu ByteCount %lx\n", 
Tag, VirtualAddress, *Flags, *ByteCount);
     // done
     return STATUS_SUCCESS;
@@ -627,82 +734,63 @@ CIrpQueue::ReleaseMappingWithTag(
     PKSSTREAM_DATA StreamData;
     PIO_STACK_LOCATION IoStack;
     ULONG Index;
+    KIRQL OldLevel;
 
-    // first check if there is an active irp
-    if (m_Irp)
-    {
-        // now check if there are already used mappings
-        StreamData = 
(PKSSTREAM_DATA)m_Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET];
+    KeAcquireSpinLock(&m_IrpListLock, &OldLevel);
 
-        if (StreamData->StreamHeaderIndex)
+    // check if used list empty
+    if (IsListEmpty(&m_FreeIrpList))
+    {
+        // get current irp
+        if (!m_Irp)
         {
-            // check if the released mapping is one current processed irps
-            for(Index = 0; Index < StreamData->StreamHeaderIndex; Index++)
-            {
-                // check if it is the same tag
-                if ((StreamData->Tags[Index].Tag == Tag) &&
-                    (StreamData->Tags[Index].Used != FALSE))
-                {
-                    // mark mapping as released
-                    StreamData->Tags[Index].Tag = NULL;
-                    StreamData->Tags[Index].Used = FALSE;
-
-                    // done
-                    return STATUS_SUCCESS;
-                }
+            KeReleaseSpinLock(&m_IrpListLock, OldLevel);
 
-            }
+            // this should not happen
+            DPRINT("ReleaseMappingWithTag Tag %p not found\n", Tag);
+            return STATUS_NOT_FOUND;
         }
-    }
 
-    // remove irp from used list
-    CurEntry = ExInterlockedRemoveHeadList(&m_FreeIrpList, &m_IrpListLock);
-    if (CurEntry == NULL)
-    {
-        // this should not happen
-        DPRINT("ReleaseMappingWithTag Tag %p not found\n", Tag);
-        return STATUS_NOT_FOUND;
+        Irp = m_Irp;
     }
+    else
+    {
+        // remove irp from used list
+        CurEntry = RemoveHeadList(&m_FreeIrpList);
 
-    // sanity check
-    PC_ASSERT(CurEntry);
-
-    // get irp from list entry
-    Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
+        // get irp from list entry
+        Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
+    }
 
     // get stream data
     StreamData = 
(PKSSTREAM_DATA)Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET];
 
-    // sanity check
-    PC_ASSERT(StreamData->StreamHeaderIndex == StreamData->StreamHeaderCount);
-
-    // check if the released mapping is one of these
-    for(Index = 0; Index < StreamData->StreamHeaderCount; Index++)
+    // release oldest in use mapping
+    for (Index = 0; Index < StreamData->nTags; Index++)
     {
-        if ((StreamData->Tags[Index].Tag == Tag) &&
-            (StreamData->Tags[Index].Used != FALSE))
+        if (StreamData->Tags[Index].Used != FALSE)
         {
-            // mark mapping as released
-            StreamData->Tags[Index].Tag = NULL;
             StreamData->Tags[Index].Used = FALSE;
 
-            // done
+            // Warn if wrong mapping released
+            if (StreamData->Tags[Index].Tag != Tag)
+            {
+                DPRINT1("Mapping released out of order\n");
+            }
+
             break;
         }
-        else
-        {
-            //
-            // we assume that mappings are released in the same order as they 
have been acquired
-            // therefore if the current mapping is not the searched one, it 
must have been already
-            // released
-            //
-            ASSERT(StreamData->Tags[Index].Tag == NULL);
-            ASSERT(StreamData->Tags[Index].Used == FALSE);
-        }
+    }
+
+    // If this is the current IRP, do not complete
+    if (Irp == m_Irp)
+    {
+        KeReleaseSpinLock(&m_IrpListLock, OldLevel);
+        return STATUS_SUCCESS;
     }
 
     // check if this is the last one released mapping
-    if (Index + 1 == StreamData->StreamHeaderCount)
+    if (Index + 1 == StreamData->nTags)
     {
         // last mapping released
         // now check if this is a looped buffer
@@ -711,14 +799,7 @@ CIrpQueue::ReleaseMappingWithTag(
             // looped buffers are not completed when they have been played
             // they are completed when the stream is set to stop
 
-            // reset stream header index
-            StreamData->StreamHeaderIndex = 0;
-
-            // reset stream header
-            StreamData->CurStreamHeader = 
(PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
-
-            // increment available data
-            InterlockedExchangeAdd((PLONG)&m_NumDataAvailable, 
StreamData->TotalStreamData);
+            KeReleaseSpinLock(&m_IrpListLock, OldLevel);
 
             // re-insert irp
             KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, Irp, 
KsListEntryTail, NULL);
@@ -731,6 +812,8 @@ CIrpQueue::ReleaseMappingWithTag(
         // time to complete non looped buffer
         //
 
+        KeReleaseSpinLock(&m_IrpListLock, OldLevel);
+
         // free stream data array
         FreeItem(StreamData->Data, TAG_PORTCLASS);
 
@@ -755,19 +838,14 @@ CIrpQueue::ReleaseMappingWithTag(
     else
     {
         // there are still some headers not consumed
-        ExInterlockedInsertHeadList(&m_FreeIrpList, 
&Irp->Tail.Overlay.ListEntry, &m_IrpListLock);
+        InsertHeadList(&m_FreeIrpList, &Irp->Tail.Overlay.ListEntry);
+
+        KeReleaseSpinLock(&m_IrpListLock, OldLevel);
     }
 
     return STATUS_SUCCESS;
 }
 
-BOOLEAN
-NTAPI
-CIrpQueue::HasLastMappingFailed()
-{
-    return m_OutOfMapping;
-}
-
 ULONG
 NTAPI
 CIrpQueue::GetCurrentIrpOffset()
@@ -817,4 +895,3 @@ NewIrpQueue(
     *Queue = (IIrpQueue*)This;
     return STATUS_SUCCESS;
 }
-
diff --git a/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp 
b/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp
index 3ad941270f7..9f681a000c2 100644
--- a/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp
+++ b/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp
@@ -549,13 +549,10 @@ CPortPinWavePci::HandleKsStream(
 {
     NTSTATUS Status;
     ULONG Data = 0;
-    BOOLEAN bFailed;
     InterlockedIncrement((PLONG)&m_TotalPackets);
 
     DPRINT("IPortPinWaveCyclic_HandleKsStream entered Total %u State %x 
MinData %u\n", m_TotalPackets, m_State, m_IrpQueue->NumData());
 
-    bFailed = m_IrpQueue->HasLastMappingFailed();
-
     Status = m_IrpQueue->AddMapping(Irp, &Data);
 
     if (NT_SUCCESS(Status))
@@ -565,7 +562,7 @@ CPortPinWavePci::HandleKsStream(
         else
             m_Position.PlayOffset += Data;
 
-        if (bFailed)
+        if (m_State == KSSTATE_RUN)
         {
             // notify stream of new mapping
             m_Stream->MappingAvailable();

Reply via email to