2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/irpstream.cpp
5 * PURPOSE: IRP Stream handling
6 * PROGRAMMER: Johannes Anderwald
12 class CIrpQueue
: public IIrpQueue
15 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
17 STDMETHODIMP_(ULONG
) AddRef()
19 InterlockedIncrement(&m_Ref
);
22 STDMETHODIMP_(ULONG
) Release()
24 InterlockedDecrement(&m_Ref
);
34 CIrpQueue(IUnknown
*OuterUnknown
){}
35 virtual ~CIrpQueue(){}
38 ULONG m_CurrentOffset
;
40 ULONG m_NumDataAvailable
;
42 KSPIN_CONNECT
* m_ConnectDetails
;
43 PKSDATAFORMAT_WAVEFORMATEX m_DataFormat
;
45 KSPIN_LOCK m_IrpListLock
;
47 LIST_ENTRY m_FreeIrpList
;
49 PVOID m_SilenceBuffer
;
54 ULONG m_MinimumDataThreshold
;
62 CIrpQueue::QueryInterface(
66 if (IsEqualGUIDAligned(refiid
, IID_IUnknown
))
68 *Output
= PVOID(PUNKNOWN(this));
69 PUNKNOWN(*Output
)->AddRef();
70 return STATUS_SUCCESS
;
73 return STATUS_UNSUCCESSFUL
;
79 IN KSPIN_CONNECT
*ConnectDetails
,
80 IN PKSDATAFORMAT DataFormat
,
81 IN PDEVICE_OBJECT DeviceObject
,
84 IN PVOID SilenceBuffer
)
86 m_ConnectDetails
= ConnectDetails
;
87 m_DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)DataFormat
;
88 m_MaxFrameSize
= FrameSize
;
89 m_SilenceBuffer
= SilenceBuffer
;
90 m_Alignment
= Alignment
;
91 m_MinimumDataThreshold
= ((PKSDATAFORMAT_WAVEFORMATEX
)DataFormat
)->WaveFormatEx
.nAvgBytesPerSec
/ 3;
93 InitializeListHead(&m_IrpList
);
94 InitializeListHead(&m_FreeIrpList
);
95 KeInitializeSpinLock(&m_IrpListLock
);
97 return STATUS_SUCCESS
;
102 CIrpQueue::AddMapping(
107 PKSSTREAM_HEADER Header
;
108 NTSTATUS Status
= STATUS_SUCCESS
;
109 PIO_STACK_LOCATION IoStack
;
111 // get current irp stack location
112 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
116 // probe the stream irp
117 Status
= KsProbeStreamIrp(Irp
, KSSTREAM_WRITE
| KSPROBE_ALLOCATEMDL
| KSPROBE_PROBEANDLOCK
| KSPROBE_ALLOWFORMATCHANGE
| KSPROBE_SYSTEMADDRESS
, 0);
120 if (!NT_SUCCESS(Status
))
122 DPRINT1("KsProbeStreamIrp failed with %x\n", Status
);
126 // get the stream header
127 Header
= (PKSSTREAM_HEADER
)Irp
->AssociatedIrp
.SystemBuffer
;
129 PC_ASSERT(Irp
->MdlAddress
);
131 if (Irp
->RequestorMode
!= KernelMode
)
134 Header
->Data
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
140 Header
= (PKSSTREAM_HEADER
)Buffer
;
144 Irp
->Tail
.Overlay
.DriverContext
[2] = (PVOID
)Header
;
149 // dont exceed max frame size
150 //PC_ASSERT(m_MaxFrameSize >= Header->DataUsed);
152 // increment num mappings
153 InterlockedIncrement(&m_NumMappings
);
155 // increment num data available
156 m_NumDataAvailable
+= Header
->DataUsed
;
158 // mark irp as pending
159 IoMarkIrpPending(Irp
);
161 // add irp to cancelable queue
162 KsAddIrpToCancelableQueue(&m_IrpList
, &m_IrpListLock
, Irp
, KsListEntryTail
, NULL
);
170 CIrpQueue::GetMapping(
172 OUT PULONG BufferSize
)
176 //PIO_STACK_LOCATION IoStack;
177 PKSSTREAM_HEADER StreamHeader
;
179 // check if there is an irp in the partially processed
183 if (m_Irp
->Cancel
== FALSE
)
186 Offset
= m_CurrentOffset
;
190 // irp has been cancelled
191 m_Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
192 IoCompleteRequest(m_Irp
, IO_NO_INCREMENT
);
198 // get a fresh new irp from the queue
199 m_Irp
= Irp
= KsRemoveIrpFromCancelableQueue(&m_IrpList
, &m_IrpListLock
, KsListEntryHead
, KsAcquireAndRemoveOnlySingleItem
);
200 m_CurrentOffset
= Offset
= 0;
205 // no irp available, use silence buffer
206 *Buffer
= (PUCHAR
)m_SilenceBuffer
;
207 *BufferSize
= m_MaxFrameSize
;
208 // flag for port wave pci driver
209 m_OutOfMapping
= TRUE
;
210 // indicate flag to restart fast buffering
211 m_StartStream
= FALSE
;
212 return STATUS_SUCCESS
;
216 // get current irp stack location
217 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
220 StreamHeader
= (PKSSTREAM_HEADER
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
222 // HACK get stream header
223 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
227 PC_ASSERT(StreamHeader
);
230 *BufferSize
= StreamHeader
->DataUsed
- Offset
;
233 *Buffer
= &((PUCHAR
)StreamHeader
->Data
)[Offset
];
235 // unset flag that no irps are available
236 m_OutOfMapping
= FALSE
;
238 return STATUS_SUCCESS
;
243 CIrpQueue::UpdateMapping(
244 IN ULONG BytesWritten
)
246 //PIO_STACK_LOCATION IoStack;
247 PKSSTREAM_HEADER StreamHeader
;
251 // silence buffer was used
256 // get current irp stack location
257 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
260 StreamHeader
= (PKSSTREAM_HEADER
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
262 // HACK get stream header
263 StreamHeader
= (PKSSTREAM_HEADER
)m_Irp
->Tail
.Overlay
.DriverContext
[2];
267 // ASSERT(StreamHeader);
269 // add to current offset
270 m_CurrentOffset
+= BytesWritten
;
272 // decrement available data counter
273 m_NumDataAvailable
-= BytesWritten
;
275 if (m_CurrentOffset
>= StreamHeader
->DataUsed
)
277 // irp has been processed completly
278 m_Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
280 // frame extend contains the original request size, DataUsed contains the real buffer size
281 //is different when kmixer performs channel conversion, upsampling etc
283 m_Irp
->IoStatus
.Information
= StreamHeader
->FrameExtent
;
285 if (m_Irp
->RequestorMode
== KernelMode
)
287 // HACK - WDMAUD should pass PKSSTREAM_HEADERs
288 ExFreePool(StreamHeader
->Data
);
289 ExFreePool(StreamHeader
);
292 // complete the request
293 IoCompleteRequest(m_Irp
, IO_SOUND_INCREMENT
);
294 // remove irp as it is complete
302 CIrpQueue::NumMappings()
305 // returns the amount of mappings available
306 return m_NumMappings
;
313 // returns the amount of audio stream data available
314 return m_NumDataAvailable
;
320 CIrpQueue::MinimumDataAvailable()
327 if (m_MinimumDataThreshold
< m_NumDataAvailable
)
329 m_StartStream
= TRUE
;
341 CIrpQueue::CancelBuffers()
344 m_StartStream
= FALSE
;
350 CIrpQueue::UpdateFormat(
351 PKSDATAFORMAT DataFormat
)
353 m_DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)DataFormat
;
354 m_MinimumDataThreshold
= m_DataFormat
->WaveFormatEx
.nAvgBytesPerSec
/ 3;
355 m_StartStream
= FALSE
;
356 m_NumDataAvailable
= 0;
361 CIrpQueue::GetMappingWithTag(
363 OUT PPHYSICAL_ADDRESS PhysicalAddress
,
364 OUT PVOID
*VirtualAddress
,
365 OUT PULONG ByteCount
,
368 PKSSTREAM_HEADER StreamHeader
;
372 PC_ASSERT(Tag
!= NULL
);
374 // get an irp from the queue
375 Irp
= KsRemoveIrpFromCancelableQueue(&m_IrpList
, &m_IrpListLock
, KsListEntryHead
, KsAcquireAndRemoveOnlySingleItem
);
377 // check if there is an irp
381 m_OutOfMapping
= TRUE
;
382 m_StartStream
= FALSE
;
383 return STATUS_UNSUCCESSFUL
;
386 // HACK get stream header
387 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
389 // store mapping in the free list
390 ExInterlockedInsertTailList(&m_FreeIrpList
, &Irp
->Tail
.Overlay
.ListEntry
, &m_IrpListLock
);
393 *PhysicalAddress
= MmGetPhysicalAddress(StreamHeader
->Data
);
394 *VirtualAddress
= StreamHeader
->Data
;
395 *ByteCount
= StreamHeader
->DataUsed
;
397 // decrement mapping count
398 InterlockedDecrement(&m_NumMappings
);
399 // decrement num data available
400 m_NumDataAvailable
-= StreamHeader
->DataUsed
;
403 Irp
->Tail
.Overlay
.DriverContext
[3] = Tag
;
406 return STATUS_SUCCESS
;
411 CIrpQueue::ReleaseMappingWithTag(
415 PLIST_ENTRY CurEntry
;
416 PKSSTREAM_HEADER StreamHeader
;
418 DPRINT("CIrpQueue::ReleaseMappingWithTag Tag %p\n", Tag
);
420 // remove irp from used list
421 CurEntry
= ExInterlockedRemoveHeadList(&m_FreeIrpList
, &m_IrpListLock
);
425 // get irp from list entry
426 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
428 // HACK get stream header
429 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
431 // driver must release items in the same order
432 PC_ASSERT(Irp
->Tail
.Overlay
.DriverContext
[3] == Tag
);
434 // irp has been processed completly
435 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
437 // frame extend contains the original request size, DataUsed contains the real buffer size
438 // is different when kmixer performs channel conversion, upsampling etc
440 Irp
->IoStatus
.Information
= StreamHeader
->FrameExtent
;
442 // free stream data, no tag as wdmaud.drv does it atm
443 ExFreePool(StreamHeader
->Data
);
445 // free stream header, no tag as wdmaud.drv allocates it atm
446 ExFreePool(StreamHeader
);
448 // complete the request
449 IoCompleteRequest(Irp
, IO_SOUND_INCREMENT
);
451 return STATUS_SUCCESS
;
456 CIrpQueue::HasLastMappingFailed()
458 return m_OutOfMapping
;
463 CIrpQueue::PrintQueueStatus()
470 CIrpQueue::SetMinimumDataThreshold(
471 ULONG MinimumDataThreshold
)
474 m_MinimumDataThreshold
= MinimumDataThreshold
;
479 CIrpQueue::GetMinimumDataThreshold()
481 return m_MinimumDataThreshold
;
488 IN IIrpQueue
**Queue
)
490 CIrpQueue
*This
= new(NonPagedPool
, TAG_PORTCLASS
)CIrpQueue(NULL
);
492 return STATUS_INSUFFICIENT_RESOURCES
;
496 *Queue
= (IIrpQueue
*)This
;
497 return STATUS_SUCCESS
;