- 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
This commit is contained in:
Johannes Anderwald 2010-11-03 11:16:33 +00:00
parent db762f8fa5
commit 5876e615b5
9 changed files with 435 additions and 233 deletions

View file

@ -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 */

View file

@ -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
*/

View file

@ -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, \

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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

View file

@ -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);

View file

@ -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);