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 if (!Irp
->MdlAddress
)
118 // ioctl from KsStudio
119 // Wdmaud already probes buffers, therefore no need to probe it again
120 // probe the stream irp
121 Status
= KsProbeStreamIrp(Irp
, KSSTREAM_WRITE
| KSPROBE_ALLOCATEMDL
| KSPROBE_PROBEANDLOCK
| KSPROBE_ALLOWFORMATCHANGE
| KSPROBE_SYSTEMADDRESS
, 0);
124 if (!NT_SUCCESS(Status
))
126 DPRINT1("KsProbeStreamIrp failed with %x\n", Status
);
130 // get the stream header
131 Header
= (PKSSTREAM_HEADER
)Irp
->AssociatedIrp
.SystemBuffer
;
133 PC_ASSERT(Irp
->MdlAddress
);
135 DPRINT("Size %u DataUsed %u FrameExtent %u SizeHeader %u\n", Header
->Size
, Header
->DataUsed
, Header
->FrameExtent
, sizeof(KSSTREAM_HEADER
));
137 if (Irp
->RequestorMode
!= KernelMode
)
140 Header
->Data
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
141 PC_ASSERT(Header
->Data
);
147 Header
= (PKSSTREAM_HEADER
)Buffer
;
151 Irp
->Tail
.Overlay
.DriverContext
[2] = (PVOID
)Header
;
156 // dont exceed max frame size
157 //PC_ASSERT(m_MaxFrameSize >= Header->DataUsed);
159 // increment num mappings
160 InterlockedIncrement(&m_NumMappings
);
162 // increment num data available
163 m_NumDataAvailable
+= Header
->DataUsed
;
165 // mark irp as pending
166 IoMarkIrpPending(Irp
);
168 // add irp to cancelable queue
169 KsAddIrpToCancelableQueue(&m_IrpList
, &m_IrpListLock
, Irp
, KsListEntryTail
, NULL
);
177 CIrpQueue::GetMapping(
179 OUT PULONG BufferSize
)
183 //PIO_STACK_LOCATION IoStack;
184 PKSSTREAM_HEADER StreamHeader
;
186 // check if there is an irp in the partially processed
190 if (m_Irp
->Cancel
== FALSE
)
193 Offset
= m_CurrentOffset
;
197 // irp has been cancelled
198 m_Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
199 IoCompleteRequest(m_Irp
, IO_NO_INCREMENT
);
205 // get a fresh new irp from the queue
206 m_Irp
= Irp
= KsRemoveIrpFromCancelableQueue(&m_IrpList
, &m_IrpListLock
, KsListEntryHead
, KsAcquireAndRemoveOnlySingleItem
);
207 m_CurrentOffset
= Offset
= 0;
212 // no irp available, use silence buffer
213 *Buffer
= (PUCHAR
)m_SilenceBuffer
;
214 *BufferSize
= m_MaxFrameSize
;
215 // flag for port wave pci driver
216 m_OutOfMapping
= TRUE
;
217 // indicate flag to restart fast buffering
218 m_StartStream
= FALSE
;
219 return STATUS_SUCCESS
;
223 // get current irp stack location
224 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
227 StreamHeader
= (PKSSTREAM_HEADER
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
229 // HACK get stream header
230 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
234 PC_ASSERT(StreamHeader
);
237 if (StreamHeader
->DataUsed
)
238 *BufferSize
= StreamHeader
->DataUsed
- Offset
;
240 *BufferSize
= StreamHeader
->FrameExtent
- Offset
;
242 PC_ASSERT(*BufferSize
);
245 *Buffer
= &((PUCHAR
)StreamHeader
->Data
)[Offset
];
247 // unset flag that no irps are available
248 m_OutOfMapping
= FALSE
;
250 return STATUS_SUCCESS
;
255 CIrpQueue::UpdateMapping(
256 IN ULONG BytesWritten
)
258 PKSSTREAM_HEADER StreamHeader
;
263 // silence buffer was used
268 StreamHeader
= (PKSSTREAM_HEADER
)m_Irp
->Tail
.Overlay
.DriverContext
[2];
271 // ASSERT(StreamHeader);
273 // add to current offset
274 m_CurrentOffset
+= BytesWritten
;
276 // decrement available data counter
277 m_NumDataAvailable
-= BytesWritten
;
279 if (StreamHeader
->DataUsed
)
280 Size
= StreamHeader
->DataUsed
;
282 Size
= StreamHeader
->FrameExtent
;
286 if (m_CurrentOffset
>= Size
)
288 // irp has been processed completly
289 m_Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
291 // frame extend contains the original request size, DataUsed contains the real buffer size
292 //is different when kmixer performs channel conversion, upsampling etc
294 m_Irp
->IoStatus
.Information
= Size
;
296 PC_ASSERT_IRQL(DISPATCH_LEVEL
);
297 MmUnlockPages(m_Irp
->MdlAddress
);
298 IoFreeMdl(m_Irp
->MdlAddress
);
299 m_Irp
->MdlAddress
= NULL
;
300 ExFreePool(m_Irp
->AssociatedIrp
.SystemBuffer
);
301 m_Irp
->AssociatedIrp
.SystemBuffer
= NULL
;
303 // complete the request
304 IoCompleteRequest(m_Irp
, IO_SOUND_INCREMENT
);
305 // remove irp as it is complete
313 CIrpQueue::NumMappings()
316 // returns the amount of mappings available
317 return m_NumMappings
;
324 // returns the amount of audio stream data available
325 return m_NumDataAvailable
;
331 CIrpQueue::MinimumDataAvailable()
338 if (m_MinimumDataThreshold
< m_NumDataAvailable
)
340 m_StartStream
= TRUE
;
352 CIrpQueue::CancelBuffers()
355 m_StartStream
= FALSE
;
361 CIrpQueue::UpdateFormat(
362 PKSDATAFORMAT DataFormat
)
364 m_DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)DataFormat
;
365 m_MinimumDataThreshold
= m_DataFormat
->WaveFormatEx
.nAvgBytesPerSec
/ 3;
366 m_StartStream
= FALSE
;
367 m_NumDataAvailable
= 0;
372 CIrpQueue::GetMappingWithTag(
374 OUT PPHYSICAL_ADDRESS PhysicalAddress
,
375 OUT PVOID
*VirtualAddress
,
376 OUT PULONG ByteCount
,
379 PKSSTREAM_HEADER StreamHeader
;
383 PC_ASSERT(Tag
!= NULL
);
385 // get an irp from the queue
386 Irp
= KsRemoveIrpFromCancelableQueue(&m_IrpList
, &m_IrpListLock
, KsListEntryHead
, KsAcquireAndRemoveOnlySingleItem
);
388 // check if there is an irp
392 m_OutOfMapping
= TRUE
;
393 m_StartStream
= FALSE
;
394 return STATUS_UNSUCCESSFUL
;
397 // HACK get stream header
398 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
400 // store mapping in the free list
401 ExInterlockedInsertTailList(&m_FreeIrpList
, &Irp
->Tail
.Overlay
.ListEntry
, &m_IrpListLock
);
404 *PhysicalAddress
= MmGetPhysicalAddress(StreamHeader
->Data
);
405 *VirtualAddress
= StreamHeader
->Data
;
406 *ByteCount
= StreamHeader
->DataUsed
;
408 // decrement mapping count
409 InterlockedDecrement(&m_NumMappings
);
410 // decrement num data available
411 m_NumDataAvailable
-= StreamHeader
->DataUsed
;
414 Irp
->Tail
.Overlay
.DriverContext
[3] = Tag
;
417 return STATUS_SUCCESS
;
422 CIrpQueue::ReleaseMappingWithTag(
426 PLIST_ENTRY CurEntry
;
427 PKSSTREAM_HEADER StreamHeader
;
429 DPRINT("CIrpQueue::ReleaseMappingWithTag Tag %p\n", Tag
);
431 // remove irp from used list
432 CurEntry
= ExInterlockedRemoveHeadList(&m_FreeIrpList
, &m_IrpListLock
);
436 // get irp from list entry
437 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
439 // HACK get stream header
440 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
442 // driver must release items in the same order
443 PC_ASSERT(Irp
->Tail
.Overlay
.DriverContext
[3] == Tag
);
445 // irp has been processed completly
446 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
448 // frame extend contains the original request size, DataUsed contains the real buffer size
449 // is different when kmixer performs channel conversion, upsampling etc
451 Irp
->IoStatus
.Information
= StreamHeader
->FrameExtent
;
453 // free stream header, no tag as wdmaud.drv allocates it atm
454 ExFreePool(StreamHeader
);
456 // complete the request
457 IoCompleteRequest(Irp
, IO_SOUND_INCREMENT
);
459 return STATUS_SUCCESS
;
464 CIrpQueue::HasLastMappingFailed()
466 return m_OutOfMapping
;
471 CIrpQueue::PrintQueueStatus()
478 CIrpQueue::SetMinimumDataThreshold(
479 ULONG MinimumDataThreshold
)
482 m_MinimumDataThreshold
= MinimumDataThreshold
;
487 CIrpQueue::GetMinimumDataThreshold()
489 return m_MinimumDataThreshold
;
496 IN IIrpQueue
**Queue
)
498 CIrpQueue
*This
= new(NonPagedPool
, TAG_PORTCLASS
)CIrpQueue(NULL
);
500 return STATUS_INSUFFICIENT_RESOURCES
;
504 *Queue
= (IIrpQueue
*)This
;
505 return STATUS_SUCCESS
;