2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/irpstream.c
5 * PURPOSE: IRP Stream handling
6 * PROGRAMMER: Johannes Anderwald
14 IIrpQueueVtbl
*lpVtbl
;
20 ULONG NumDataAvailable
;
22 KSPIN_CONNECT
*ConnectDetails
;
23 PKSDATAFORMAT_WAVEFORMATEX DataFormat
;
25 KSPIN_LOCK IrpListLock
;
27 LIST_ENTRY FreeIrpList
;
34 ULONG MinimumDataThreshold
;
40 IIrpQueue_fnQueryInterface(
45 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
47 if (IsEqualGUIDAligned(refiid
, &IID_IUnknown
))
49 *Output
= &This
->lpVtbl
;
50 _InterlockedIncrement(&This
->ref
);
51 return STATUS_SUCCESS
;
53 return STATUS_UNSUCCESSFUL
;
61 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
63 return _InterlockedIncrement(&This
->ref
);
71 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
73 _InterlockedDecrement(&This
->ref
);
77 FreeItem(This
, TAG_PORTCLASS
);
80 /* Return new reference count */
89 IN KSPIN_CONNECT
*ConnectDetails
,
90 IN PKSDATAFORMAT DataFormat
,
91 IN PDEVICE_OBJECT DeviceObject
,
94 IN PVOID SilenceBuffer
)
96 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
98 This
->ConnectDetails
= ConnectDetails
;
99 This
->DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)DataFormat
;
100 This
->MaxFrameSize
= FrameSize
;
101 This
->SilenceBuffer
= SilenceBuffer
;
102 This
->Alignment
= Alignment
;
103 This
->MinimumDataThreshold
= ((PKSDATAFORMAT_WAVEFORMATEX
)DataFormat
)->WaveFormatEx
.nAvgBytesPerSec
/ 3;
105 InitializeListHead(&This
->IrpList
);
106 InitializeListHead(&This
->FreeIrpList
);
107 KeInitializeSpinLock(&This
->IrpListLock
);
109 return STATUS_SUCCESS
;
114 IIrpQueue_fnAddMapping(
120 PKSSTREAM_HEADER Header
;
121 NTSTATUS Status
= STATUS_SUCCESS
;
122 PIO_STACK_LOCATION IoStack
;
123 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
125 /* get current irp stack location */
126 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
130 /* probe the stream irp */
131 Status
= KsProbeStreamIrp(Irp
, KSSTREAM_WRITE
| KSPROBE_ALLOCATEMDL
| KSPROBE_PROBEANDLOCK
| KSPROBE_ALLOWFORMATCHANGE
| KSPROBE_SYSTEMADDRESS
, 0);
133 /* check for success */
134 if (!NT_SUCCESS(Status
))
136 DPRINT1("KsProbeStreamIrp failed with %x\n", Status
);
140 /* get the stream header */
141 Header
= (PKSSTREAM_HEADER
)Irp
->AssociatedIrp
.SystemBuffer
;
143 ASSERT(Irp
->MdlAddress
);
145 if (Irp
->RequestorMode
!= KernelMode
)
147 /* use allocated mdl */
148 Header
->Data
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
154 Header
= (PKSSTREAM_HEADER
)Buffer
;
158 Irp
->Tail
.Overlay
.DriverContext
[2] = (PVOID
)Header
;
163 /* dont exceed max frame size */
164 //ASSERT(This->MaxFrameSize >= Header->DataUsed);
166 /* increment num mappings */
167 InterlockedIncrement(&This
->NumMappings
);
169 /* increment num data available */
170 This
->NumDataAvailable
+= Header
->DataUsed
;
172 /* mark irp as pending */
173 IoMarkIrpPending(Irp
);
175 /* add irp to cancelable queue */
176 KsAddIrpToCancelableQueue(&This
->IrpList
, &This
->IrpListLock
, Irp
, KsListEntryTail
, NULL
);
184 IIrpQueue_fnGetMapping(
187 OUT PULONG BufferSize
)
191 //PIO_STACK_LOCATION IoStack;
192 PKSSTREAM_HEADER StreamHeader
;
193 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
195 /* check if there is an irp in the partially processed */
199 if (This
->Irp
->Cancel
== FALSE
)
202 Offset
= This
->CurrentOffset
;
206 /* irp has been cancelled */
207 This
->Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
208 IoCompleteRequest(This
->Irp
, IO_NO_INCREMENT
);
209 This
->Irp
= Irp
= NULL
;
214 /* get a fresh new irp from the queue */
215 This
->Irp
= Irp
= KsRemoveIrpFromCancelableQueue(&This
->IrpList
, &This
->IrpListLock
, KsListEntryHead
, KsAcquireAndRemoveOnlySingleItem
);
216 This
->CurrentOffset
= Offset
= 0;
221 /* no irp available, use silence buffer */
222 *Buffer
= This
->SilenceBuffer
;
223 *BufferSize
= This
->MaxFrameSize
;
224 /* flag for port wave pci driver */
225 This
->OutOfMapping
= TRUE
;
226 /* indicate flag to restart fast buffering */
227 This
->StartStream
= FALSE
;
228 return STATUS_SUCCESS
;
232 /* get current irp stack location */
233 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
235 /* get stream header */
236 StreamHeader
= (PKSSTREAM_HEADER
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
238 /* HACK get stream header */
239 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
243 ASSERT(StreamHeader
);
245 /* store buffersize */
246 *BufferSize
= StreamHeader
->DataUsed
- Offset
;
249 *Buffer
= &((PUCHAR
)StreamHeader
->Data
)[Offset
];
251 /* unset flag that no irps are available */
252 This
->OutOfMapping
= FALSE
;
254 return STATUS_SUCCESS
;
259 IIrpQueue_fnUpdateMapping(
261 IN ULONG BytesWritten
)
263 //PIO_STACK_LOCATION IoStack;
264 PKSSTREAM_HEADER StreamHeader
;
265 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
269 /* silence buffer was used */
274 /* get current irp stack location */
275 IoStack
= IoGetCurrentIrpStackLocation(This
->Irp
);
277 /* get stream header */
278 StreamHeader
= (PKSSTREAM_HEADER
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
280 /* HACK get stream header */
281 StreamHeader
= (PKSSTREAM_HEADER
)This
->Irp
->Tail
.Overlay
.DriverContext
[2];
285 ASSERT(StreamHeader
);
287 /* add to current offset */
288 This
->CurrentOffset
+= BytesWritten
;
290 /* decrement available data counter */
291 This
->NumDataAvailable
-= BytesWritten
;
293 if (This
->CurrentOffset
>= StreamHeader
->DataUsed
)
295 /* irp has been processed completly */
296 This
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
298 /* frame extend contains the original request size, DataUsed contains the real buffer size
299 * is different when kmixer performs channel conversion, upsampling etc
301 This
->Irp
->IoStatus
.Information
= StreamHeader
->FrameExtent
;
303 /* free stream data, no tag as wdmaud.drv does it atm */
304 //ExFreePool(StreamHeader->Data);
306 /* free stream header, no tag as wdmaud.drv allocates it atm */
307 //ExFreePool(StreamHeader);
309 /* complete the request */
310 IoCompleteRequest(This
->Irp
, IO_SOUND_INCREMENT
);
311 /* remove irp as it is complete */
313 This
->CurrentOffset
= 0;
319 IIrpQueue_fnNumMappings(
322 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
324 /* returns the amount of mappings available */
325 return This
->NumMappings
;
333 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
334 /* returns the amount of audio stream data available */
335 return This
->NumDataAvailable
;
341 IIrpQueue_fnMinimumDataAvailable(
345 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
347 if (This
->StartStream
)
350 if (This
->MinimumDataThreshold
< This
->NumDataAvailable
)
352 This
->StartStream
= TRUE
;
364 IIrpQueue_fnCancelBuffers(
367 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
369 This
->StartStream
= FALSE
;
375 IIrpQueue_fnUpdateFormat(
377 PKSDATAFORMAT DataFormat
)
379 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
380 This
->DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)DataFormat
;
381 This
->MinimumDataThreshold
= This
->DataFormat
->WaveFormatEx
.nAvgBytesPerSec
/ 3;
382 This
->StartStream
= FALSE
;
383 This
->NumDataAvailable
= 0;
388 IIrpQueue_fnGetMappingWithTag(
391 OUT PPHYSICAL_ADDRESS PhysicalAddress
,
392 OUT PVOID
*VirtualAddress
,
393 OUT PULONG ByteCount
,
396 PKSSTREAM_HEADER StreamHeader
;
398 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
403 /* get an irp from the queue */
404 Irp
= KsRemoveIrpFromCancelableQueue(&This
->IrpList
, &This
->IrpListLock
, KsListEntryHead
, KsAcquireAndRemoveOnlySingleItem
);
406 /* check if there is an irp */
409 /* no irp available */
410 This
->OutOfMapping
= TRUE
;
411 This
->StartStream
= FALSE
;
412 return STATUS_UNSUCCESSFUL
;
415 /* HACK get stream header */
416 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
418 /* store mapping in the free list */
419 ExInterlockedInsertTailList(&This
->FreeIrpList
, &Irp
->Tail
.Overlay
.ListEntry
, &This
->IrpListLock
);
422 *PhysicalAddress
= MmGetPhysicalAddress(StreamHeader
->Data
);
423 *VirtualAddress
= StreamHeader
->Data
;
424 *ByteCount
= StreamHeader
->DataUsed
;
426 /* decrement mapping count */
427 InterlockedDecrement(&This
->NumMappings
);
428 /* decrement num data available */
429 This
->NumDataAvailable
-= StreamHeader
->DataUsed
;
431 /* store tag in irp */
432 Irp
->Tail
.Overlay
.DriverContext
[3] = Tag
;
435 return STATUS_SUCCESS
;
440 IIrpQueue_fnReleaseMappingWithTag(
445 PLIST_ENTRY CurEntry
;
446 PKSSTREAM_HEADER StreamHeader
;
447 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
449 DPRINT("IIrpQueue_fnReleaseMappingWithTag Tag %p\n", Tag
);
451 /* remove irp from used list */
452 CurEntry
= ExInterlockedRemoveHeadList(&This
->FreeIrpList
, &This
->IrpListLock
);
456 /* get irp from list entry */
457 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
459 /* HACK get stream header */
460 StreamHeader
= (PKSSTREAM_HEADER
)Irp
->Tail
.Overlay
.DriverContext
[2];
462 /* driver must release items in the same order */
463 ASSERT(Irp
->Tail
.Overlay
.DriverContext
[3] == Tag
);
465 /* irp has been processed completly */
466 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
468 /* frame extend contains the original request size, DataUsed contains the real buffer size
469 * is different when kmixer performs channel conversion, upsampling etc
471 Irp
->IoStatus
.Information
= StreamHeader
->FrameExtent
;
473 /* free stream data, no tag as wdmaud.drv does it atm */
474 ExFreePool(StreamHeader
->Data
);
476 /* free stream header, no tag as wdmaud.drv allocates it atm */
477 ExFreePool(StreamHeader
);
479 /* complete the request */
480 IoCompleteRequest(Irp
, IO_SOUND_INCREMENT
);
482 return STATUS_SUCCESS
;
487 IIrpQueue_fnHasLastMappingFailed(
490 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
491 return This
->OutOfMapping
;
496 IIrpQueue_fnPrintQueueStatus(
504 IIrpQueue_fnSetMinimumDataThreshold(
506 ULONG MinimumDataThreshold
)
508 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
510 This
->MinimumDataThreshold
= MinimumDataThreshold
;
515 IIrpQueue_fnGetMinimumDataThreshold(
518 IIrpQueueImpl
* This
= (IIrpQueueImpl
*)iface
;
520 return This
->MinimumDataThreshold
;
524 static IIrpQueueVtbl vt_IIrpQueue
=
526 IIrpQueue_fnQueryInterface
,
530 IIrpQueue_fnAddMapping
,
531 IIrpQueue_fnGetMapping
,
532 IIrpQueue_fnUpdateMapping
,
533 IIrpQueue_fnNumMappings
,
535 IIrpQueue_fnMinimumDataAvailable
,
536 IIrpQueue_fnCancelBuffers
,
537 IIrpQueue_fnUpdateFormat
,
538 IIrpQueue_fnGetMappingWithTag
,
539 IIrpQueue_fnReleaseMappingWithTag
,
540 IIrpQueue_fnHasLastMappingFailed
,
541 IIrpQueue_fnPrintQueueStatus
,
542 IIrpQueue_fnSetMinimumDataThreshold
,
543 IIrpQueue_fnGetMinimumDataThreshold
549 IN IIrpQueue
**Queue
)
551 IIrpQueueImpl
*This
= AllocateItem(NonPagedPool
, sizeof(IIrpQueueImpl
), TAG_PORTCLASS
);
553 return STATUS_INSUFFICIENT_RESOURCES
;
556 This
->lpVtbl
= &vt_IIrpQueue
;
558 *Queue
= (IIrpQueue
*)This
;
559 return STATUS_SUCCESS
;