virtual ~CIrpQueue(){}
protected:
- ULONG m_CurrentOffset;
+ volatile ULONG m_CurrentOffset;
LONG m_NumMappings;
ULONG m_NumDataAvailable;
BOOL m_StartStream;
- KSPIN_CONNECT * m_ConnectDetails;
+ PKSPIN_CONNECT m_ConnectDetails;
PKSDATAFORMAT_WAVEFORMATEX m_DataFormat;
KSPIN_LOCK m_IrpListLock;
};
+#define OFFSET_HEADERINDEX (0)
+#define OFFSET_STREAMHEADER (2)
+#define OFFSET_HEADERCOUNT (3)
+
+
+#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])
+
+
NTSTATUS
NTAPI
CIrpQueue::QueryInterface(
NTSTATUS
NTAPI
CIrpQueue::AddMapping(
- IN PUCHAR Buffer,
- IN ULONG BufferSize,
- IN PIRP Irp)
+ IN PIRP Irp,
+ OUT PULONG Data)
{
PKSSTREAM_HEADER Header;
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IoStack;
+ ULONG NumHeaders, NumData, Index;
+ PMDL Mdl;
+
+ PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
// get current irp stack location
IoStack = IoGetCurrentIrpStackLocation(Irp);
- if (!Buffer)
+ if (!Irp->MdlAddress)
{
+ // ioctl from KsStudio
+ // Wdmaud already probes buffers, therefore no need to probe it again
// probe the stream irp
- Status = KsProbeStreamIrp(Irp, KSSTREAM_WRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK | KSPROBE_ALLOWFORMATCHANGE | KSPROBE_SYSTEMADDRESS, 0);
+ 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);
// check for success
if (!NT_SUCCESS(Status))
{
- DPRINT1("KsProbeStreamIrp failed with %x\n", Status);
+ DPRINT("KsProbeStreamIrp failed with %x\n", Status);
return Status;
}
+ }
+
+ // get first stream header
+
+ if (Irp->RequestorMode == UserMode)
+ Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
+ else
+ Header = (PKSSTREAM_HEADER)Irp->UserBuffer;
+
+ // sanity check
+ PC_ASSERT(Header);
+
+ // calculate num headers
+ NumHeaders = IoStack->Parameters.DeviceIoControl.OutputBufferLength / Header->Size;
+
+ // 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);
- // get the stream header
- Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
+ NumData = 0;
+ // prepare all headers
+ for(Index = 0; Index < NumHeaders; Index++)
+ {
+ // sanity checks
PC_ASSERT(Header);
- PC_ASSERT(Irp->MdlAddress);
+ PC_ASSERT(Mdl);
- if (Irp->RequestorMode != KernelMode)
+ if (Irp->RequestorMode == UserMode)
{
- // use allocated mdl
- Header->Data = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ Header->Data = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
}
- }
- else
- {
- // HACK
- Header = (PKSSTREAM_HEADER)Buffer;
- }
- // HACK
- Irp->Tail.Overlay.DriverContext[2] = (PVOID)Header;
+ 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;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
- // sanity check
- PC_ASSERT(Header);
+ // increment num mappings
+ InterlockedIncrement(&m_NumMappings);
- // dont exceed max frame size
- //PC_ASSERT(m_MaxFrameSize >= Header->DataUsed);
+ // increment available data
+ InterlockedExchangeAdd((PLONG)&m_NumDataAvailable,
+ (max(Header->DataUsed, Header->FrameExtent)));
- // increment num mappings
- InterlockedIncrement(&m_NumMappings);
+ NumData += max(Header->DataUsed, Header->FrameExtent);
- // increment num data available
- m_NumDataAvailable += Header->DataUsed;
+ // move to next header
+ Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size);
+
+ // move to next mdl
+ Mdl = Mdl->Next;
+ }
+
+ DPRINT("StreamHeaders %u NumData %u FrameSize %u NumDataAvailable %u\n", NumHeaders, NumData, m_MaxFrameSize, m_NumDataAvailable);
+ *Data = NumData;
// mark irp as pending
IoMarkIrpPending(Irp);
if (!Irp)
{
+ DPRINT("NoIrp\n");
// no irp available, use silence buffer
*Buffer = (PUCHAR)m_SilenceBuffer;
*BufferSize = m_MaxFrameSize;
return STATUS_SUCCESS;
}
-#if 0
- // get current irp stack location
- IoStack = IoGetCurrentIrpStackLocation(Irp);
-
// get stream header
- StreamHeader = (PKSSTREAM_HEADER)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
-#else
- // HACK get stream header
StreamHeader = (PKSSTREAM_HEADER)Irp->Tail.Overlay.DriverContext[2];
-#endif
// sanity check
PC_ASSERT(StreamHeader);
// store buffersize
- *BufferSize = StreamHeader->DataUsed - Offset;
+ if (StreamHeader->DataUsed)
+ *BufferSize = StreamHeader->DataUsed - Offset;
+ else
+ *BufferSize = StreamHeader->FrameExtent - Offset;
+
+ PC_ASSERT(*BufferSize);
// store buffer
*Buffer = &((PUCHAR)StreamHeader->Data)[Offset];
CIrpQueue::UpdateMapping(
IN ULONG BytesWritten)
{
- //PIO_STACK_LOCATION IoStack;
PKSSTREAM_HEADER StreamHeader;
+ ULONG Size, NumData, Index;
if (!m_Irp)
{
return;
}
-#if 0
- // get current irp stack location
- IoStack = IoGetCurrentIrpStackLocation(m_Irp);
-
// get stream header
- StreamHeader = (PKSSTREAM_HEADER)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
-#else
- // HACK get stream header
- StreamHeader = (PKSSTREAM_HEADER)m_Irp->Tail.Overlay.DriverContext[2];
-#endif
+ StreamHeader = (PKSSTREAM_HEADER)STREAMHEADER_CURRENT(m_Irp);
// sanity check
// ASSERT(StreamHeader);
// add to current offset
- m_CurrentOffset += BytesWritten;
+ InterlockedExchangeAdd((volatile PLONG)&m_CurrentOffset, (LONG)BytesWritten);
// decrement available data counter
m_NumDataAvailable -= BytesWritten;
- if (m_CurrentOffset >= StreamHeader->DataUsed)
+ if (StreamHeader->DataUsed)
+ Size = StreamHeader->DataUsed;
+ else
+ Size = StreamHeader->FrameExtent;
+
+ PC_ASSERT(Size);
+
+ if (m_CurrentOffset >= Size)
{
- // irp has been processed completly
- m_Irp->IoStatus.Status = STATUS_SUCCESS;
+ if (STREAMHEADER_INDEX(m_Irp) + 1 < STREAMHEADER_COUNT(m_Irp))
+ {
+ // the irp has at least one more stream header
+ m_Irp->Tail.Overlay.DriverContext[OFFSET_HEADERINDEX] = UlongToPtr(STREAMHEADER_INDEX(m_Irp) + 1);
- // frame extend contains the original request size, DataUsed contains the real buffer size
- //is different when kmixer performs channel conversion, upsampling etc
-
- m_Irp->IoStatus.Information = StreamHeader->FrameExtent;
+ // get next stream header
+ StreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamHeader + StreamHeader->Size);
+
+ // store next stream header
+ STREAMHEADER_CURRENT(m_Irp) = (PVOID)StreamHeader;
+ // reset current 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++)
{
- // HACK - WDMAUD should pass PKSSTREAM_HEADERs
- ExFreePool(StreamHeader->Data);
- ExFreePool(StreamHeader);
+ 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);
}
+ 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);
+ // 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;
+ }
+
+ m_Irp->IoStatus.Status = STATUS_SUCCESS;
+ m_Irp->IoStatus.Information = NumData;
+
// complete the request
IoCompleteRequest(m_Irp, IO_SOUND_INCREMENT);
// remove irp as it is complete
NTAPI
CIrpQueue::CancelBuffers()
{
+ // is there an active irp
+ if (m_Irp)
+ {
+ // re-insert it to cancelable queue
+ KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, m_Irp, KsListEntryTail, NULL);
+ //set it to zero
+ m_Irp = NULL;
+ }
+ // cancel all irps
+ KsCancelIo(&m_IrpList, &m_IrpListLock);
+ // reset stream start flag
m_StartStream = FALSE;
+ // done
return TRUE;
}
return STATUS_UNSUCCESSFUL;
}
+ //FIXME support more than one stream header
+ PC_ASSERT(STREAMHEADER_COUNT(Irp) == 1);
+
// HACK get stream header
StreamHeader = (PKSSTREAM_HEADER)Irp->Tail.Overlay.DriverContext[2];
Irp->IoStatus.Information = StreamHeader->FrameExtent;
- // free stream data, no tag as wdmaud.drv does it atm
- ExFreePool(StreamHeader->Data);
-
// free stream header, no tag as wdmaud.drv allocates it atm
ExFreePool(StreamHeader);
return m_OutOfMapping;
}
-VOID
+ULONG
NTAPI
-CIrpQueue::PrintQueueStatus()
+CIrpQueue::GetCurrentIrpOffset()
{
+ return m_CurrentOffset;
}
VOID