From 5876e615b50b941fac1af2075589a75df6fe8b0e Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Wed, 3 Nov 2010 11:16:33 +0000 Subject: [PATCH] [KS] - Fix several bugs in KsProbeStreamIrp - If requestor is KernelMode - just save a pointer in Irp->AssociatedIrp.SystemBuffer (currently not used) - If requestor is UserMode mark irp as buffered. Also set Flag IRP_INPUT_OPERATION when the ioctl is IOCTL_KS_READ_STREAM. This is important to propagate modifications to KSSTREAM_HEADERS (in particular DataUsed member) - ReactOS KS can now be used in WinXP in combination with KSStudio. In order to make it fully work, ks needs to implement software bus functions [PORTCLS] - Rewrite internal irp queue handling - It now supports multiple KSSTREAM_HEADERs per Irp, variable sized KSSTREAM_HEADERs per irp. - Store the mapped virtual address not in the KSSTREAM_HEADER, as user programs will receive then invalid addresses - Add checks whether this irp is for an sink pin or source pin - Fix multiple bugs when the pin is looped buffer mode (How did this work before?) - ReactOS portcls + WinXP now properly works with audio recording [WDMAUD_KERNEL] - Don't free associated stream header anymore - Tested with VBox 3.2.10 + VmWare Player 3.1.2 + WinXP svn path=/trunk/; revision=49457 --- reactos/drivers/ksfilter/ks/irp.c | 11 + reactos/drivers/ksfilter/ks/topology.c | 2 +- .../wdm/audio/backpln/portcls/interfaces.hpp | 12 +- .../wdm/audio/backpln/portcls/irpstream.cpp | 619 ++++++++++++------ .../wdm/audio/backpln/portcls/pin_dmus.cpp | 2 +- .../audio/backpln/portcls/pin_wavecyclic.cpp | 6 +- .../wdm/audio/backpln/portcls/pin_wavepci.cpp | 2 +- .../wdm/audio/backpln/portcls/pin_wavert.cpp | 6 +- .../drivers/wdm/audio/legacy/wdmaud/control.c | 8 +- 9 files changed, 435 insertions(+), 233 deletions(-) diff --git a/reactos/drivers/ksfilter/ks/irp.c b/reactos/drivers/ksfilter/ks/irp.c index faeb0a2a38e..fb36d6df78a 100644 --- a/reactos/drivers/ksfilter/ks/irp.c +++ b/reactos/drivers/ksfilter/ks/irp.c @@ -661,6 +661,11 @@ KsProbeStreamIrp( if (Irp->RequestorMode == KernelMode || Irp->AssociatedIrp.SystemBuffer) { + if (Irp->RequestorMode == KernelMode) + { + /* no need to allocate stream header */ + Irp->AssociatedIrp.SystemBuffer = Irp->UserBuffer; + } AllocMdl: /* check if alloc mdl flag is passed */ if (!(ProbeFlags & KSPROBE_ALLOCATEMDL)) @@ -910,6 +915,9 @@ ProbeMdl: return STATUS_INSUFFICIENT_RESOURCES; } + /* mark irp as buffered so that changes the stream headers are propagated back */ + Irp->Flags = IRP_DEALLOCATE_BUFFER | IRP_BUFFERED_IO; + _SEH2_TRY { if (ProbeFlags & KSPROBE_STREAMWRITE) @@ -923,6 +931,9 @@ ProbeMdl: { /* stream reads means writing */ ProbeForWrite(Irp->UserBuffer, Length, sizeof(UCHAR)); + + /* set input operation flags */ + Irp->Flags |= IRP_INPUT_OPERATION; } /* copy stream buffer */ diff --git a/reactos/drivers/ksfilter/ks/topology.c b/reactos/drivers/ksfilter/ks/topology.c index 63ccaf277c6..49ae6599a7a 100644 --- a/reactos/drivers/ksfilter/ks/topology.c +++ b/reactos/drivers/ksfilter/ks/topology.c @@ -38,7 +38,7 @@ KspCreateObjectType( return STATUS_INSUFFICIENT_RESOURCES; } - /* build a request which looks like \{ObjectClass}\CreateParameters + /* build a request which looks like {ObjectClass}\CreateParameters * For pins the parent is the reference string used in registration * For clocks it is full path for pin\{ClockGuid}\ClockCreateParams */ diff --git a/reactos/drivers/wdm/audio/backpln/portcls/interfaces.hpp b/reactos/drivers/wdm/audio/backpln/portcls/interfaces.hpp index 248bcbe9012..9163a6a78d6 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/interfaces.hpp +++ b/reactos/drivers/wdm/audio/backpln/portcls/interfaces.hpp @@ -319,9 +319,11 @@ DECLARE_INTERFACE_(IIrpQueue, IUnknown) DEFINE_ABSTRACT_UNKNOWN() STDMETHOD_(NTSTATUS, Init)(THIS_ - IN KSPIN_CONNECT *ConnectDetails, + IN PKSPIN_CONNECT ConnectDetails, + IN PKSPIN_DESCRIPTOR Descriptor, IN ULONG FrameSize, - IN ULONG Alignment) PURE; + IN ULONG Alignment, + IN ULONG TagSupportEnabled) PURE; STDMETHOD_(NTSTATUS, AddMapping)(THIS_ IN PIRP Irp, @@ -360,9 +362,11 @@ DECLARE_INTERFACE_(IIrpQueue, IUnknown) #define IMP_IIrpQueue \ STDMETHODIMP_(NTSTATUS) Init(THIS_ \ - IN KSPIN_CONNECT *ConnectDetails, \ + IN PKSPIN_CONNECT ConnectDetails, \ + IN PKSPIN_DESCRIPTOR Descriptor, \ IN ULONG FrameSize, \ - IN ULONG Alignment); \ + IN ULONG Alignment, \ + IN ULONG TagSupportEnabled); \ \ STDMETHODIMP_(NTSTATUS) AddMapping(THIS_ \ IN PIRP Irp, \ diff --git a/reactos/drivers/wdm/audio/backpln/portcls/irpstream.cpp b/reactos/drivers/wdm/audio/backpln/portcls/irpstream.cpp index 628ea73edb9..2c6b88ccf28 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/irpstream.cpp +++ b/reactos/drivers/wdm/audio/backpln/portcls/irpstream.cpp @@ -35,31 +35,40 @@ public: virtual ~CIrpQueue(){} protected: - volatile ULONG m_CurrentOffset; - LONG m_NumMappings; - ULONG m_NumDataAvailable; + PKSPIN_CONNECT m_ConnectDetails; + PKSPIN_DESCRIPTOR m_Descriptor; + KSPIN_LOCK m_IrpListLock; LIST_ENTRY m_IrpList; LIST_ENTRY m_FreeIrpList; - PIRP m_Irp; ULONG m_OutOfMapping; ULONG m_MaxFrameSize; ULONG m_Alignment; + ULONG m_TagSupportEnabled; + ULONG m_NumDataAvailable; + volatile ULONG m_CurrentOffset; + + PIRP m_Irp; + LONG m_Ref; }; -#define OFFSET_HEADERINDEX (0) -#define OFFSET_STREAMHEADER (2) -#define OFFSET_HEADERCOUNT (3) +typedef struct +{ + ULONG StreamHeaderCount; + ULONG StreamHeaderIndex; + ULONG TotalStreamData; + PKSSTREAM_HEADER CurStreamHeader; + PVOID * Data; + PVOID * Tags; +}KSSTREAM_DATA, *PKSSTREAM_DATA; -#define STREAMHEADER_INDEX(Irp) (PtrToUlong(Irp->Tail.Overlay.DriverContext[OFFSET_HEADERINDEX])) -#define STREAMHEADER_COUNT(Irp) (PtrToUlong(Irp->Tail.Overlay.DriverContext[OFFSET_HEADERCOUNT])) -#define STREAMHEADER_CURRENT(Irp) (Irp->Tail.Overlay.DriverContext[OFFSET_STREAMHEADER]) +#define STREAM_DATA_OFFSET (0) NTSTATUS @@ -81,13 +90,17 @@ CIrpQueue::QueryInterface( NTSTATUS NTAPI CIrpQueue::Init( - IN KSPIN_CONNECT *ConnectDetails, + IN PKSPIN_CONNECT ConnectDetails, + IN PKSPIN_DESCRIPTOR Descriptor, IN ULONG FrameSize, - IN ULONG Alignment) + IN ULONG Alignment, + IN ULONG TagSupportEnabled) { m_ConnectDetails = ConnectDetails; + m_Descriptor = Descriptor; m_MaxFrameSize = FrameSize; m_Alignment = Alignment; + m_TagSupportEnabled = TagSupportEnabled; InitializeListHead(&m_IrpList); InitializeListHead(&m_FreeIrpList); @@ -103,110 +116,158 @@ CIrpQueue::AddMapping( OUT PULONG Data) { PKSSTREAM_HEADER Header; - NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS Status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION IoStack; - ULONG NumHeaders, NumData, Index; + ULONG Index, Length; PMDL Mdl; + PKSSTREAM_DATA StreamData; PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + // allocate stream data + StreamData = (PKSSTREAM_DATA)AllocateItem(NonPagedPool, sizeof(KSSTREAM_DATA), TAG_PORTCLASS); + if (!StreamData) + { + // not enough memory + return STATUS_INSUFFICIENT_RESOURCES; + } + // get current irp stack location IoStack = IoGetCurrentIrpStackLocation(Irp); - if (!Irp->MdlAddress) + // lets probe the irp + if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM) { - // ioctl from KsStudio - // Wdmaud already probes buffers, therefore no need to probe it again - // probe the stream irp - if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM) - Status = KsProbeStreamIrp(Irp, KSSTREAM_WRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK | KSPROBE_SYSTEMADDRESS, 0); - else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM) - Status = KsProbeStreamIrp(Irp, KSSTREAM_READ | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK | KSPROBE_SYSTEMADDRESS, 0); - else - PC_ASSERT(0); + // probe IOCTL_KS_WRITE_STREAM + Status = KsProbeStreamIrp(Irp, KSSTREAM_WRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK | KSPROBE_SYSTEMADDRESS, 0); + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM) + { + // probe IOCTL_KS_READ_STREAM + Status = KsProbeStreamIrp(Irp, KSSTREAM_READ | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK | KSPROBE_SYSTEMADDRESS, 0); + } - // check for success - if (!NT_SUCCESS(Status)) - { - DPRINT("KsProbeStreamIrp failed with %x\n", Status); - return Status; - } + // check for success + if (!NT_SUCCESS(Status)) + { + // irp probing failed + FreeItem(StreamData, TAG_PORTCLASS); + return Status; } // get first stream header + Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer; - if (Irp->RequestorMode == UserMode) - Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer; - else - Header = (PKSSTREAM_HEADER)Irp->UserBuffer; + // store header + StreamData->CurStreamHeader = Header; // sanity check PC_ASSERT(Header); - // calculate num headers - NumHeaders = IoStack->Parameters.DeviceIoControl.OutputBufferLength / Header->Size; + // first calculate the numbers of stream headers + Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength; - // assume headers of same length - PC_ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength % Header->Size == 0); - - - // get first audio buffer - Mdl = Irp->MdlAddress; - // sanity check - PC_ASSERT(Mdl); - - // store the current stream header - Irp->Tail.Overlay.DriverContext[OFFSET_STREAMHEADER] = (PVOID)Header; - // store header count - Irp->Tail.Overlay.DriverContext[OFFSET_HEADERCOUNT] = UlongToPtr(NumHeaders); - - // store current header index - Irp->Tail.Overlay.DriverContext[OFFSET_HEADERINDEX] = UlongToPtr(0); - - NumData = 0; - // prepare all headers - for(Index = 0; Index < NumHeaders; Index++) + do { - // sanity checks - PC_ASSERT(Header); - PC_ASSERT(Mdl); + /* subtract size */ + Length -= Header->Size; - if (Irp->RequestorMode == UserMode) + /* increment header count */ + StreamData->StreamHeaderCount++; + + if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN) { - Header->Data = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority); + // irp sink + StreamData->TotalStreamData += Header->DataUsed; + } + else + { + // irp source + StreamData->TotalStreamData += Header->FrameExtent; } - if (!Header->Data) - { - // insufficient resources - ExFreePool(Irp->AssociatedIrp.SystemBuffer); - Irp->AssociatedIrp.SystemBuffer = NULL; - // complete and forget request - Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; - Irp->IoStatus.Information = 0; + /* move to next header */ + Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size); - IoCompleteRequest(Irp, IO_NO_INCREMENT); + }while(Length); + + // sanity check + ASSERT(StreamData->StreamHeaderCount); + + // allocate array for storing the pointers of the data */ + StreamData->Data = (PVOID*)AllocateItem(NonPagedPool, sizeof(PVOID) * StreamData->StreamHeaderCount, TAG_PORTCLASS); + if (!StreamData->Data) + { + // out of memory + FreeItem(StreamData, TAG_PORTCLASS); + + // done + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (m_TagSupportEnabled) + { + // allocate array for storing the pointers of the data */ + StreamData->Tags = (PVOID*)AllocateItem(NonPagedPool, sizeof(PVOID) * StreamData->StreamHeaderCount, TAG_PORTCLASS); + if (!StreamData->Data) + { + // out of memory + FreeItem(StreamData->Data, TAG_PORTCLASS); + FreeItem(StreamData, TAG_PORTCLASS); + + // done + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + + // now get a system address for the user buffers + Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer; + Mdl = Irp->MdlAddress; + + for(Index = 0; Index < StreamData->StreamHeaderCount; Index++) + { + /* get system address */ + StreamData->Data[Index] = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority); + + /* check for success */ + if (!StreamData->Data[Index]) + { + // out of resources + FreeItem(StreamData->Data, TAG_PORTCLASS); + + if (m_TagSupportEnabled) + { + // free tag array + FreeItem(StreamData->Tags, TAG_PORTCLASS); + } + + FreeItem(StreamData, TAG_PORTCLASS); + // done return STATUS_INSUFFICIENT_RESOURCES; } - // increment num mappings - InterlockedIncrement(&m_NumMappings); + 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); + } - // increment available data - InterlockedExchangeAdd((PLONG)&m_NumDataAvailable, - (max(Header->DataUsed, Header->FrameExtent))); - - NumData += max(Header->DataUsed, Header->FrameExtent); - - // move to next header - Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size); - - // move to next mdl + // move to next header / mdl Mdl = Mdl->Next; + Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size); + } - DPRINT("StreamHeaders %u NumData %u FrameSize %u NumDataAvailable %u\n", NumHeaders, NumData, m_MaxFrameSize, m_NumDataAvailable); - *Data = NumData; + // store stream data + Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET] = (PVOID)StreamData; + + *Data = StreamData->TotalStreamData; // mark irp as pending IoMarkIrpPending(Irp); @@ -218,7 +279,7 @@ CIrpQueue::AddMapping( m_OutOfMapping = FALSE; // done - return Status; + return STATUS_SUCCESS; } NTSTATUS @@ -229,8 +290,7 @@ CIrpQueue::GetMapping( { PIRP Irp; ULONG Offset; - //PIO_STACK_LOCATION IoStack; - PKSSTREAM_HEADER StreamHeader; + PKSSTREAM_DATA StreamData; // check if there is an irp in the partially processed if (m_Irp) @@ -247,6 +307,7 @@ CIrpQueue::GetMapping( m_Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(m_Irp, IO_NO_INCREMENT); m_Irp = Irp = NULL; + m_CurrentOffset = 0; } } else @@ -259,26 +320,32 @@ CIrpQueue::GetMapping( if (!Irp) { // no irp buffer available - DPRINT("NoIrp\n"); return STATUS_UNSUCCESSFUL; } - // get stream header - StreamHeader = (PKSSTREAM_HEADER)Irp->Tail.Overlay.DriverContext[2]; + // get stream data + StreamData = (PKSSTREAM_DATA)Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; // sanity check - PC_ASSERT(StreamHeader); + PC_ASSERT(StreamData); - // store buffersize - if (StreamHeader->DataUsed) - *BufferSize = StreamHeader->DataUsed - Offset; + // get buffer size + if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN) + { + // sink pin + *BufferSize = StreamData->CurStreamHeader->DataUsed - Offset; + } else - *BufferSize = StreamHeader->FrameExtent - Offset; + { + // source pin + *BufferSize = StreamData->CurStreamHeader->FrameExtent - Offset; + } + // sanity check PC_ASSERT(*BufferSize); // store buffer - *Buffer = &((PUCHAR)StreamHeader->Data)[Offset]; + *Buffer = &((PUCHAR)StreamData->Data[StreamData->StreamHeaderIndex])[Offset]; // unset flag that no irps are available m_OutOfMapping = FALSE; @@ -291,102 +358,111 @@ NTAPI CIrpQueue::UpdateMapping( IN ULONG BytesWritten) { - PKSSTREAM_HEADER StreamHeader; - ULONG Size, NumData, Index; - - if (!m_Irp) - { - // silence buffer was used - return; - } - - // get stream header - StreamHeader = (PKSSTREAM_HEADER)STREAMHEADER_CURRENT(m_Irp); + PKSSTREAM_DATA StreamData; + ULONG Size; + PIO_STACK_LOCATION IoStack; // sanity check - // ASSERT(StreamHeader); + ASSERT(m_Irp); + + // get stream data + StreamData = (PKSSTREAM_DATA)m_Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; + + // sanity check + ASSERT(StreamData); // add to current offset InterlockedExchangeAdd((volatile PLONG)&m_CurrentOffset, (LONG)BytesWritten); + if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT) + { + // store written bytes (source pin) + StreamData->CurStreamHeader->DataUsed += BytesWritten; + } + // decrement available data counter m_NumDataAvailable -= BytesWritten; - if (StreamHeader->DataUsed) - Size = StreamHeader->DataUsed; + // get audio buffer size + if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT) + Size = StreamData->CurStreamHeader->FrameExtent; else - Size = StreamHeader->FrameExtent; + Size = StreamData->CurStreamHeader->DataUsed; + // sanity check PC_ASSERT(Size); if (m_CurrentOffset >= Size) { - if (STREAMHEADER_INDEX(m_Irp) + 1 < STREAMHEADER_COUNT(m_Irp)) + // sanity check + PC_ASSERT(Size == m_CurrentOffset); + + if (StreamData->StreamHeaderIndex + 1 < StreamData->StreamHeaderCount) { - // the irp has at least one more stream header - m_Irp->Tail.Overlay.DriverContext[OFFSET_HEADERINDEX] = UlongToPtr(STREAMHEADER_INDEX(m_Irp) + 1); + // move to next stream header + StreamData->CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamData->CurStreamHeader + StreamData->CurStreamHeader->Size); - // get next stream header - StreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamHeader + StreamHeader->Size); + // increment stream header index + StreamData->StreamHeaderIndex++; - // store next stream header - STREAMHEADER_CURRENT(m_Irp) = (PVOID)StreamHeader; - - // reset current offset + // reset offset m_CurrentOffset = 0; // done return; } - // irp has been processed completly - NumData = 0; - if (m_Irp->RequestorMode == KernelMode) - StreamHeader = (PKSSTREAM_HEADER)m_Irp->UserBuffer; - else - StreamHeader = (PKSSTREAM_HEADER)m_Irp->AssociatedIrp.SystemBuffer; - - // loop all stream headers - for(Index = 0; Index < STREAMHEADER_COUNT(m_Irp); Index++) - { - PC_ASSERT(StreamHeader); - - // add size of buffer - // depends on if the buffer is input / output - if (StreamHeader->DataUsed) - Size = StreamHeader->DataUsed; - else - Size = StreamHeader->FrameExtent; - - // increment size - NumData += Size; - - // get next stream header - StreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamHeader + StreamHeader->Size); - } - + // + // all stream buffers have been played + // check if this is a looped buffer + // if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING) { // looped streaming repeat the buffers untill // the caller decides to stop the streams // reset stream header index - m_Irp->Tail.Overlay.DriverContext[OFFSET_HEADERINDEX] = UlongToPtr(0); + 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); + // clear current irp m_Irp = NULL; + // reset offset m_CurrentOffset = 0; - // increment available data - InterlockedExchangeAdd((PLONG)&m_NumDataAvailable, NumData); + // done return; } + // free stream data array + FreeItem(StreamData->Data, TAG_PORTCLASS); + + if (m_TagSupportEnabled) + { + // free tag array + FreeItem(StreamData->Tags, TAG_PORTCLASS); + } + + // free stream data + FreeItem(StreamData, TAG_PORTCLASS); + + // get io stack + IoStack = IoGetCurrentIrpStackLocation(m_Irp); + // store operation status m_Irp->IoStatus.Status = STATUS_SUCCESS; - m_Irp->IoStatus.Information = 0; + + // store operation length + m_Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength; // complete the request IoCompleteRequest(m_Irp, IO_SOUND_INCREMENT); @@ -411,6 +487,8 @@ BOOL NTAPI CIrpQueue::CancelBuffers() { + //TODO: own cancel routine + // is there an active irp if (m_Irp) { @@ -422,8 +500,7 @@ CIrpQueue::CancelBuffers() // cancel all irps KsCancelIo(&m_IrpList, &m_IrpListLock); - // reset number of mappings - m_NumMappings = 0; + // reset number of data available m_NumDataAvailable = 0; @@ -440,44 +517,83 @@ CIrpQueue::GetMappingWithTag( OUT PULONG ByteCount, OUT PULONG Flags) { - PKSSTREAM_HEADER StreamHeader; - PIRP Irp; + PKSSTREAM_DATA StreamData; - *Flags = 0; + /* sanity checks */ PC_ASSERT(Tag != NULL); + PC_ASSERT(PhysicalAddress); + PC_ASSERT(VirtualAddress); + PC_ASSERT(ByteCount); + PC_ASSERT(Flags); - // get an irp from the queue - Irp = KsRemoveIrpFromCancelableQueue(&m_IrpList, &m_IrpListLock, KsListEntryHead, KsAcquireAndRemoveOnlySingleItem); + if (!m_Irp) + { + // get an irp from the queue + m_Irp = KsRemoveIrpFromCancelableQueue(&m_IrpList, &m_IrpListLock, KsListEntryHead, KsAcquireAndRemoveOnlySingleItem); + } // check if there is an irp - if (!Irp) + if (!m_Irp) { // no irp available m_OutOfMapping = TRUE; return STATUS_NOT_FOUND; } - //FIXME support more than one stream header - PC_ASSERT(STREAMHEADER_COUNT(Irp) == 1); + // get stream data + StreamData = (PKSSTREAM_DATA)m_Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; - // HACK get stream header - StreamHeader = (PKSSTREAM_HEADER)Irp->Tail.Overlay.DriverContext[2]; + // sanity check + PC_ASSERT(StreamData->StreamHeaderIndex < StreamData->StreamHeaderCount); - // store mapping in the free list - ExInterlockedInsertTailList(&m_FreeIrpList, &Irp->Tail.Overlay.ListEntry, &m_IrpListLock); - - // return mapping - *PhysicalAddress = MmGetPhysicalAddress(StreamHeader->Data); - *VirtualAddress = StreamHeader->Data; - *ByteCount = StreamHeader->DataUsed; - - // decrement mapping count - InterlockedDecrement(&m_NumMappings); - // decrement num data available - m_NumDataAvailable -= StreamHeader->DataUsed; + // setup mapping + *PhysicalAddress = MmGetPhysicalAddress(StreamData->Data[StreamData->StreamHeaderIndex]); + *VirtualAddress = StreamData->Data[StreamData->StreamHeaderIndex]; // store tag in irp - Irp->Tail.Overlay.DriverContext[3] = Tag; + StreamData->Tags[StreamData->StreamHeaderIndex] = Tag; + + // mapping size + if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN) + { + // sink pin + *ByteCount = StreamData->CurStreamHeader->DataUsed; + + // decrement num data available + m_NumDataAvailable -= StreamData->CurStreamHeader->DataUsed; + } + else + { + // source pin + *ByteCount = StreamData->CurStreamHeader->FrameExtent; + + // decrement num data available + m_NumDataAvailable -= StreamData->CurStreamHeader->FrameExtent; + } + + if (StreamData->StreamHeaderIndex + 1 == StreamData->StreamHeaderCount) + { + // last mapping + *Flags = 1; + + // insert mapping into free list + ExInterlockedInsertTailList(&m_FreeIrpList, &m_Irp->Tail.Overlay.ListEntry, &m_IrpListLock); + + // clear irp + m_Irp = NULL; + + } + else + { + // one more mapping in the irp + *Flags = 0; + + // increment header index + StreamData->StreamHeaderIndex++; + + // move to next header + StreamData->CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamData->CurStreamHeader + StreamData->CurStreamHeader->Size); + } // done return STATUS_SUCCESS; @@ -490,34 +606,123 @@ CIrpQueue::ReleaseMappingWithTag( { PIRP Irp; PLIST_ENTRY CurEntry; - PKSSTREAM_HEADER StreamHeader; + PKSSTREAM_DATA StreamData; + PIO_STACK_LOCATION IoStack; + ULONG Index; - DPRINT("CIrpQueue::ReleaseMappingWithTag Tag %p\n", Tag); + // 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]; + + if (StreamData->StreamHeaderIndex) + { + // 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) + { + // mark mapping as released + StreamData->Tags[Index] = NULL; + + // done + return STATUS_SUCCESS; + } + + } + } + } // remove irp from used list CurEntry = ExInterlockedRemoveHeadList(&m_FreeIrpList, &m_IrpListLock); + // sanity check PC_ASSERT(CurEntry); // get irp from list entry Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry); - // HACK get stream header - StreamHeader = (PKSSTREAM_HEADER)Irp->Tail.Overlay.DriverContext[2]; + // get stream data + StreamData = (PKSSTREAM_DATA)Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; - // driver must release items in the same order - PC_ASSERT(Irp->Tail.Overlay.DriverContext[3] == Tag); + // sanity check + PC_ASSERT(StreamData->StreamHeaderIndex + 1 == StreamData->StreamHeaderCount); - // irp has been processed completly - Irp->IoStatus.Status = STATUS_SUCCESS; + // check if the released mapping is one of these + for(Index = 0; Index < StreamData->StreamHeaderCount; Index++) + { + if (StreamData->Tags[Index] == Tag) + { + // mark mapping as released + StreamData->Tags[Index] = NULL; - // frame extend contains the original request size, DataUsed contains the real buffer size - // is different when kmixer performs channel conversion, upsampling etc - - Irp->IoStatus.Information = StreamHeader->FrameExtent; + // done + 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 + // + PC_ASSERT(StreamData->Tags[Index] == NULL); + } + } - // complete the request - IoCompleteRequest(Irp, IO_SOUND_INCREMENT); + // check if this is the last one released mapping + if (Index + 1 == StreamData->StreamHeaderCount) + { + // last mapping released + // now check if this is a looped buffer + if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING) + { + // 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); + + // re-insert irp + KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, Irp, KsListEntryTail, NULL); + + // done + return STATUS_SUCCESS; + } + + // + // time to complete non looped buffer + // + + // free stream data array + FreeItem(StreamData->Data, TAG_PORTCLASS); + + // free stream tags array + FreeItem(StreamData->Tags, TAG_PORTCLASS); + + // free stream data + FreeItem(StreamData, TAG_PORTCLASS); + + // get io stack + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // store operation status + Irp->IoStatus.Status = STATUS_SUCCESS; + + // store operation length + Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + + // complete the request + IoCompleteRequest(Irp, IO_SOUND_INCREMENT); + } return STATUS_SUCCESS; } @@ -545,38 +750,18 @@ CIrpQueue::GetAcquiredTagRange( { KIRQL OldLevel; BOOLEAN Ret = FALSE; - PIRP Irp; - PLIST_ENTRY CurEntry; + //PIRP Irp; + //PLIST_ENTRY CurEntry; + //PKSSTREAM_DATA StreamData; + // lock list KeAcquireSpinLock(&m_IrpListLock, &OldLevel); - if (!IsListEmpty(&m_FreeIrpList)) - { - // get first entry - CurEntry = RemoveHeadList(&m_FreeIrpList); - // get irp from list entry - Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry); + // initialize to zero + *FirstTag = NULL; + *LastTag = NULL; - // get tag of first acquired buffer - *FirstTag = Irp->Tail.Overlay.DriverContext[3]; - - // put back irp - InsertHeadList(&m_FreeIrpList, &Irp->Tail.Overlay.ListEntry); - - // get last entry - CurEntry = RemoveTailList(&m_FreeIrpList); - // get irp from list entry - Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry); - - // get tag of first acquired buffer - *LastTag = Irp->Tail.Overlay.DriverContext[3]; - - // put back irp - InsertTailList(&m_FreeIrpList, &Irp->Tail.Overlay.ListEntry); - - // indicate success - Ret = TRUE; - } + UNIMPLEMENTED; // release lock KeReleaseSpinLock(&m_IrpListLock, OldLevel); diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.cpp b/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.cpp index 5a616f302ec..848e4e98795 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.cpp +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.cpp @@ -604,7 +604,7 @@ CPortPinDMus::Init( } } - Status = m_IrpQueue->Init(ConnectDetails, 0, 0); + Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, 0, 0, FALSE); if (!NT_SUCCESS(Status)) { DPRINT("IrpQueue_Init failed with %x\n", Status); diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp index a3f65ba978e..7733606c6a5 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp @@ -702,7 +702,7 @@ CPortPinWaveCyclic::UpdateCommonBuffer( if (Gap > BufferLength) { // insert silence samples - DPRINT1("Inserting Silence Buffer Offset %lu GapLength %lu\n", m_CommonBufferOffset, BufferLength); + DPRINT("Inserting Silence Buffer Offset %lu GapLength %lu\n", m_CommonBufferOffset, BufferLength); m_Stream->Silence((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BufferLength); m_CommonBufferOffset += BufferLength; @@ -761,7 +761,7 @@ CPortPinWaveCyclic::UpdateCommonBufferOverlap( if (Gap > BufferLength) { // insert silence samples - DPRINT1("Overlap Inserting Silence Buffer Size %lu Offset %lu Gap %lu Position %lu\n", m_CommonBufferSize, m_CommonBufferOffset, Gap, Position); + DPRINT("Overlap Inserting Silence Buffer Size %lu Offset %lu Gap %lu Position %lu\n", m_CommonBufferSize, m_CommonBufferOffset, Gap, Position); m_Stream->Silence((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BufferLength); m_CommonBufferOffset += BufferLength; @@ -1303,7 +1303,7 @@ CPortPinWaveCyclic::Init( m_Stream->Silence(m_CommonBuffer, m_CommonBufferSize); - Status = m_IrpQueue->Init(ConnectDetails, m_FrameSize, 0); + Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, m_FrameSize, 0, FALSE); if (!NT_SUCCESS(Status)) { m_IrpQueue->Release(); diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp index 9a1cc75613b..021648a9dd1 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp @@ -919,7 +919,7 @@ CPortPinWavePci::Init( } // initialize irp queue - Status = m_IrpQueue->Init(ConnectDetails, m_AllocatorFraming.FrameSize, m_AllocatorFraming.FileAlignment); + Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, m_AllocatorFraming.FrameSize, m_AllocatorFraming.FileAlignment, TRUE); if (!NT_SUCCESS(Status)) { // this should never happen diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.cpp b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.cpp index fd6be3cc28f..f9a2644bb62 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.cpp +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.cpp @@ -283,7 +283,7 @@ NTAPI CPortPinWaveRT::HandleKsStream( IN PIRP Irp) { - DPRINT("IPortPinWaveRT_HandleKsStream entered State %u Stream %p\n", m_State, m_Stream); + DPRINT("IPortPinWaveRT_HandleKsStream entered State %u Stream %p is UNIMPLEMENTED\n", m_State, m_Stream); return STATUS_PENDING; } @@ -587,7 +587,7 @@ CPortPinWaveRT::Init( goto cleanup; } - Status = m_IrpQueue->Init(ConnectDetails, 0, 0); + Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, 0, 0, FALSE); if (!NT_SUCCESS(Status)) { goto cleanup; @@ -624,7 +624,7 @@ CPortPinWaveRT::Init( // delay of 10 milisec m_Delay = Int32x32To64(10, -10000); - Status = m_Stream->AllocateAudioBuffer(16384 * 11, &m_Mdl, &m_CommonBufferSize, &m_CommonBufferOffset, &m_CacheType); + Status = m_Stream->AllocateAudioBuffer(16384 * 11, &m_Mdl, &m_CommonBufferSize, &m_CommonBufferOffset, &m_CacheType); if (!NT_SUCCESS(Status)) { DPRINT("AllocateAudioBuffer failed with %x\n", Status); diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/control.c b/reactos/drivers/wdm/audio/legacy/wdmaud/control.c index ee5d03f32ea..afc692c15ac 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/control.c +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/control.c @@ -452,9 +452,6 @@ IoCompletion ( /* now free the mdl */ IoFreeMdl(Context->Mdl); - /* now free the stream header */ - ExFreePool(Irp->AssociatedIrp.SystemBuffer); - DPRINT("IoCompletion Irp %p IoStatus %lx Information %lx Length %lu\n", Irp, Irp->IoStatus.Status, Irp->IoStatus.Information, Length); if (Irp->IoStatus.Status == STATUS_SUCCESS) @@ -462,6 +459,11 @@ IoCompletion ( /* store the length */ Irp->IoStatus.Information = Length; } + else + { + /* failed */ + Irp->IoStatus.Information = 0; + } /* free context */ FreeItem(Context);