From 9061b8ee40045bdbf4baf6415551246c4bb0c3da Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sun, 2 Aug 2009 11:40:38 +0000 Subject: [PATCH] [KS] - Implement KsQueryInformationFile - Properly implement KsStreamIo - Fix a desastreous bug in KsRemoveIrpFromCancelableQueue - Implement KsMoveIrpsOnCancelableQueue [PORTCLS] - Switch portcls to use the provided ks irp queue function instead of the homegrown IRP_MAPPING routines. Irp queueing is now faster and consumes less memory - Return an allocated silence buffer when there are no mappings available - HACK-Remove: Don't pre-complete any audio buffers now anymore. If you experience audio stuttering, let me know [SYSAUDIO, PORTCLS, KMIXER] - FastRead / FastWrite routines must store their return values in the status block as KsStreamIo now checks these svn path=/trunk/; revision=42334 --- reactos/drivers/ksfilter/ks/irp.c | 268 +++++++++++--- .../wdm/audio/backpln/portcls/interfaces.h | 3 +- .../wdm/audio/backpln/portcls/irpstream.c | 349 ++++++++---------- .../wdm/audio/backpln/portcls/pin_dmus.c | 2 +- .../audio/backpln/portcls/pin_wavecyclic.c | 33 +- .../wdm/audio/backpln/portcls/pin_wavepci.c | 2 +- .../wdm/audio/backpln/portcls/pin_wavert.c | 2 +- .../drivers/wdm/audio/filters/kmixer/pin.c | 2 + .../drivers/wdm/audio/legacy/wdmaud/control.c | 69 +++- .../drivers/wdm/audio/legacy/wdmaud/wdmaud.h | 9 - reactos/drivers/wdm/audio/sysaudio/pin.c | 9 +- 11 files changed, 468 insertions(+), 280 deletions(-) diff --git a/reactos/drivers/ksfilter/ks/irp.c b/reactos/drivers/ksfilter/ks/irp.c index 2ec01c9b1e9..7f1c1c8c520 100644 --- a/reactos/drivers/ksfilter/ks/irp.c +++ b/reactos/drivers/ksfilter/ks/irp.c @@ -344,7 +344,7 @@ KsWriteFile( } /* - @unimplemented + @implemented */ KSDDKAPI NTSTATUS @@ -357,7 +357,13 @@ KsQueryInformationFile( { PDEVICE_OBJECT DeviceObject; PFAST_IO_DISPATCH FastIoDispatch; + PIRP Irp; + PIO_STACK_LOCATION IoStack; IO_STATUS_BLOCK IoStatus; + KEVENT Event; + LARGE_INTEGER Offset; + IO_STATUS_BLOCK StatusBlock; + NTSTATUS Status; /* get related file object */ DeviceObject = IoGetRelatedDeviceObject(FileObject); @@ -386,10 +392,47 @@ KsQueryInformationFile( } } } + /* clear event */ + KeClearEvent(&FileObject->Event); - /* Implement Me */ + /* initialize event */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); - return STATUS_UNSUCCESSFUL; + /* set offset to zero */ + Offset.QuadPart = 0L; + + /* build the request */ + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_QUERY_INFORMATION, IoGetRelatedDeviceObject(FileObject), NULL, 0, &Offset, &Event, &StatusBlock); + + if (!Irp) + return STATUS_INSUFFICIENT_RESOURCES; + + /* get next stack location */ + IoStack = IoGetNextIrpStackLocation(Irp); + + /* setup parameters */ + IoStack->Parameters.QueryFile.FileInformationClass = FileInformationClass; + IoStack->Parameters.QueryFile.Length = Length; + Irp->AssociatedIrp.SystemBuffer = FileInformation; + + + /* call the driver */ + Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp); + + if (Status == STATUS_PENDING) + { + /* wait for the operation to complete */ + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + + /* is object sync */ + if (FileObject->Flags & FO_SYNCHRONOUS_IO) + Status = FileObject->FinalStatus; + else + Status = StatusBlock.Status; + } + + /* done */ + return Status; } /* @@ -506,78 +549,105 @@ KsStreamIo( PIRP Irp; PIO_STACK_LOCATION IoStack; PDEVICE_OBJECT DeviceObject; - ULONG Code; NTSTATUS Status; LARGE_INTEGER Offset; PKSIOBJECT_HEADER ObjectHeader; + BOOLEAN Ret; - - if (Flags == KSSTREAM_READ) - Code = IRP_MJ_READ; - else if (Flags == KSSTREAM_WRITE) - Code = IRP_MJ_WRITE; - else - return STATUS_INVALID_PARAMETER; - + /* get related device object */ DeviceObject = IoGetRelatedDeviceObject(FileObject); - if (!DeviceObject) - return STATUS_INVALID_PARAMETER; + /* sanity check */ + ASSERT(DeviceObject != NULL); + /* is there a event provided */ if (Event) { - KeResetEvent(Event); + /* reset event */ + KeClearEvent(Event); } - //ASSERT(DeviceObject->DeviceType == FILE_DEVICE_KS); - ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext; - ASSERT(ObjectHeader); - if (Code == IRP_MJ_READ) + if (RequestorMode || ExGetPreviousMode() == KernelMode) { - if (ObjectHeader->DispatchTable.FastRead) + /* requestor is from kernel land */ + ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext; + + if (ObjectHeader) { - if (ObjectHeader->DispatchTable.FastRead(FileObject, NULL, Length, FALSE, 0, StreamHeaders, IoStatusBlock, DeviceObject)) + /* there is a object header */ + if (Flags == KSSTREAM_READ) { - return STATUS_SUCCESS; + /* is fast read supported */ + if (ObjectHeader->DispatchTable.FastRead) + { + /* call fast read dispatch routine */ + Ret = ObjectHeader->DispatchTable.FastRead(FileObject, NULL, Length, FALSE, 0, StreamHeaders, IoStatusBlock, DeviceObject); + + if (Ret) + { + /* the request was handeled */ + return IoStatusBlock->Status; + } + } } - } - } - else - { - if (ObjectHeader->DispatchTable.FastWrite) - { - if (ObjectHeader->DispatchTable.FastWrite(FileObject, NULL, Length, FALSE, 0, StreamHeaders, IoStatusBlock, DeviceObject)) + else if (Flags == KSSTREAM_WRITE) { - return STATUS_SUCCESS; + /* is fast write supported */ + if (ObjectHeader->DispatchTable.FastWrite) + { + /* call fast write dispatch routine */ + Ret = ObjectHeader->DispatchTable.FastWrite(FileObject, NULL, Length, FALSE, 0, StreamHeaders, IoStatusBlock, DeviceObject); + + if (Ret) + { + /* the request was handeled */ + return IoStatusBlock->Status; + } + } } } } + /* clear file object event */ + KeClearEvent(&FileObject->Event); + + /* set the offset to zero */ Offset.QuadPart = 0LL; - Irp = IoBuildSynchronousFsdRequest(Code, DeviceObject, (PVOID)StreamHeaders, Length, &Offset, Event, IoStatusBlock); + + /* now build the irp */ + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_DEVICE_CONTROL, + DeviceObject, (PVOID)StreamHeaders, Length, &Offset, Event, IoStatusBlock); if (!Irp) { - return STATUS_UNSUCCESSFUL; + /* not enough memory */ + return STATUS_INSUFFICIENT_RESOURCES; } + /* setup irp parameters */ + Irp->RequestorMode = RequestorMode; + Irp->Overlay.AsynchronousParameters.UserApcContext = PortContext; + Irp->Tail.Overlay.OriginalFileObject = FileObject; + Irp->UserBuffer = StreamHeaders; + + /* get next irp stack location */ + IoStack = IoGetNextIrpStackLocation(Irp); + /* setup stack parameters */ + IoStack->FileObject = FileObject; + IoStack->Parameters.DeviceIoControl.InputBufferLength = Length; + IoStack->Parameters.DeviceIoControl.Type3InputBuffer = StreamHeaders; + IoStack->Parameters.DeviceIoControl.IoControlCode = (Flags == KSSTREAM_READ ? IOCTL_KS_READ_STREAM : IOCTL_KS_WRITE_STREAM); if (CompletionRoutine) { - IoSetCompletionRoutine(Irp, - CompletionRoutine, - CompletionContext, - (CompletionInvocationFlags & KsInvokeOnSuccess), - (CompletionInvocationFlags & KsInvokeOnError), - (CompletionInvocationFlags & KsInvokeOnCancel)); + /* setup completion routine for async processing */ + IoSetCompletionRoutine(Irp, CompletionRoutine, CompletionContext, (CompletionInvocationFlags & KsInvokeOnSuccess), (CompletionInvocationFlags & KsInvokeOnError), (CompletionInvocationFlags & KsInvokeOnCancel)); } - IoStack = IoGetNextIrpStackLocation(Irp); - IoStack->FileObject = FileObject; - + /* now call the driver */ Status = IoCallDriver(DeviceObject, Irp); + /* done */ return Status; } - /* @unimplemented */ @@ -933,7 +1003,7 @@ KsRemoveIrpFromCancelableQueue( } /* get irp offset */ - Irp = (PIRP)CONTAINING_RECORD(Irp, IRP, Tail.Overlay.ListEntry); + Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry); if (Irp->Cancel) { @@ -988,7 +1058,7 @@ KsRemoveIrpFromCancelableQueue( } /* - @unimplemented + @implemented */ KSDDKAPI NTSTATUS @@ -1002,8 +1072,114 @@ KsMoveIrpsOnCancelableQueue( IN PFNKSIRPLISTCALLBACK ListCallback, IN PVOID Context) { - UNIMPLEMENTED; - return STATUS_UNSUCCESSFUL; + KIRQL OldLevel; + PLIST_ENTRY SrcEntry; + PIRP Irp; + NTSTATUS Status; + + if (!DestinationLock) + { + /* no destination lock just acquire the source lock */ + KeAcquireSpinLock(SourceLock, &OldLevel); + } + else + { + /* acquire cancel spinlock */ + IoAcquireCancelSpinLock(&OldLevel); + + /* now acquire source lock */ + KeAcquireSpinLockAtDpcLevel(SourceLock); + + /* now acquire destination lock */ + KeAcquireSpinLockAtDpcLevel(DestinationLock); + } + + /* point to list head */ + SrcEntry = SourceList; + + /* now move all irps */ + while(TRUE) + { + if (ListLocation == KsListEntryTail) + { + /* move queue downwards */ + SrcEntry = SrcEntry->Flink; + } + else + { + /* move queue upwards */ + SrcEntry = SrcEntry->Blink; + } + + if (SrcEntry == DestinationList) + { + /* eof list reached */ + break; + } + + /* get irp offset */ + Irp = (PIRP)CONTAINING_RECORD(SrcEntry, IRP, Tail.Overlay.ListEntry); + + /* now check if irp can be moved */ + Status = ListCallback(Irp, Context); + + /* check if irp can be moved */ + if (Status == STATUS_SUCCESS) + { + /* remove irp from src list */ + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + + if (ListLocation == KsListEntryTail) + { + /* insert irp end of list */ + InsertTailList(DestinationList, &Irp->Tail.Overlay.ListEntry); + } + else + { + /* insert irp head of list */ + InsertHeadList(DestinationList, &Irp->Tail.Overlay.ListEntry); + } + + /* do we need to update the irp lock */ + if (DestinationLock) + { + /* update irp lock */ + KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) = DestinationLock; + } + } + else + { + if (Status != STATUS_NO_MATCH) + { + /* callback decided to stop enumeration */ + break; + } + + /* reset return value */ + Status = STATUS_SUCCESS; + } + } + + if (!DestinationLock) + { + /* release source lock */ + KeReleaseSpinLock(SourceLock, OldLevel); + } + else + { + /* now release destination lock */ + KeReleaseSpinLockFromDpcLevel(DestinationLock); + + /* now release source lock */ + KeReleaseSpinLockFromDpcLevel(SourceLock); + + + /* now release cancel spinlock */ + IoReleaseCancelSpinLock(OldLevel); + } + + /* done */ + return Status; } /* diff --git a/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h b/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h index 440680a2d28..7ee232afc70 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h +++ b/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h @@ -197,7 +197,8 @@ DECLARE_INTERFACE_(IIrpQueue, IUnknown) IN PKSDATAFORMAT DataFormat, IN PDEVICE_OBJECT DeviceObject, IN ULONG FrameSize, - IN ULONG Alignment); + IN ULONG Alignment, + IN PVOID SilenceBuffer); STDMETHOD_(NTSTATUS, AddMapping)(THIS_ IN PUCHAR Buffer, diff --git a/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c b/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c index f3e9a6d0038..c8ac7f02373 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c @@ -8,17 +8,6 @@ #include "private.h" -typedef struct _IRP_MAPPING_ -{ - LIST_ENTRY Entry; - PVOID Buffer; - ULONG BufferSize; - ULONG OriginalBufferSize; - PVOID OriginalBuffer; - PIRP Irp; - - PVOID Tag; -}IRP_MAPPING, *PIRP_MAPPING; typedef struct { @@ -33,9 +22,11 @@ typedef struct KSPIN_CONNECT *ConnectDetails; PKSDATAFORMAT_WAVEFORMATEX DataFormat; - KSPIN_LOCK Lock; - LIST_ENTRY ListHead; - LIST_ENTRY FreeHead; + KSPIN_LOCK IrpListLock; + LIST_ENTRY IrpList; + LIST_ENTRY FreeIrpList; + PIRP Irp; + PVOID SilenceBuffer; ULONG OutOfMapping; ULONG MaxFrameSize; @@ -44,28 +35,6 @@ typedef struct }IIrpQueueImpl; -VOID -NTAPI -FreeMappingRoutine( - PIRP_MAPPING CurMapping) -{ - ASSERT(CurMapping); - - if (CurMapping->Irp) - { - CurMapping->Irp->IoStatus.Information = CurMapping->OriginalBufferSize; - CurMapping->Irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest(CurMapping->Irp, IO_SOUND_INCREMENT); - } - - if (CurMapping->OriginalBuffer) - { - ExFreePool(CurMapping->OriginalBuffer); - } - - ExFreePool(CurMapping); -} - NTSTATUS NTAPI IIrpQueue_fnQueryInterface( @@ -121,19 +90,21 @@ IIrpQueue_fnInit( IN PKSDATAFORMAT DataFormat, IN PDEVICE_OBJECT DeviceObject, IN ULONG FrameSize, - IN ULONG Alignment) + IN ULONG Alignment, + IN PVOID SilenceBuffer) { IIrpQueueImpl * This = (IIrpQueueImpl*)iface; This->ConnectDetails = ConnectDetails; This->DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)DataFormat; This->MaxFrameSize = FrameSize; + This->SilenceBuffer = SilenceBuffer; This->Alignment = Alignment; This->MinimumDataThreshold = ((PKSDATAFORMAT_WAVEFORMATEX)DataFormat)->WaveFormatEx.nAvgBytesPerSec / 3; - InitializeListHead(&This->ListHead); - InitializeListHead(&This->FreeHead); - KeInitializeSpinLock(&This->Lock); + InitializeListHead(&This->IrpList); + InitializeListHead(&This->FreeIrpList); + KeInitializeSpinLock(&This->IrpListLock); return STATUS_SUCCESS; } @@ -146,84 +117,35 @@ IIrpQueue_fnAddMapping( IN ULONG BufferSize, IN PIRP Irp) { - PIRP_MAPPING Mapping = NULL; - KSSTREAM_HEADER * Header = (KSSTREAM_HEADER*)Buffer; - ULONG Index, NumMappings, Offset; + PKSSTREAM_HEADER Header; IIrpQueueImpl * This = (IIrpQueueImpl*)iface; + /* FIXME + * irp should contain the stream header... + */ - if (This->MaxFrameSize) - { - if (This->MaxFrameSize > Header->DataUsed) - { - /* small mapping */ - NumMappings = 1; - } - else - { - ULONG Rest = Header->DataUsed % This->MaxFrameSize; + /* get stream header */ + Header = (KSSTREAM_HEADER*)Buffer; - NumMappings = Header->DataUsed / This->MaxFrameSize; - if (Rest) - { - NumMappings++; - } - } - } - else - { - /* no framesize restriction */ - NumMappings = 1; - } + /* dont exceed max frame size */ + ASSERT(This->MaxFrameSize >= Header->DataUsed); - for(Index = 0; Index < NumMappings; Index++) - { - Mapping = AllocateItem(NonPagedPool, sizeof(IRP_MAPPING), TAG_PORTCLASS); - if (!Mapping) - { - DPRINT("OutOfMemory\n"); - return STATUS_UNSUCCESSFUL; - } + /* hack untill stream probing is ready */ + Irp->Tail.Overlay.DriverContext[2] = (PVOID)Header; - if (Index) - Offset = Index * This->MaxFrameSize; - else - Offset = 0; + /* increment num mappings */ + InterlockedIncrement(&This->NumMappings); - Mapping->Buffer = (PVOID)UlongToPtr((PtrToUlong(Header->Data) + Offset + 3) & ~(0x3)); + /* increment num data available */ + This->NumDataAvailable += Header->DataUsed; - if (This->MaxFrameSize) - Mapping->BufferSize = min(Header->DataUsed - Offset, This->MaxFrameSize); - else - Mapping->BufferSize = Header->DataUsed; + /* mark irp as pending */ + IoMarkIrpPending(Irp); - Mapping->OriginalBufferSize = Header->FrameExtent; - Mapping->OriginalBuffer = NULL; - Mapping->Irp = NULL; - Mapping->Tag = NULL; - - This->NumDataAvailable += Mapping->BufferSize; - - if (Index == NumMappings - 1) - { - /* last mapping should free the irp if provided */ - Mapping->OriginalBuffer = Header->Data; - Mapping->Irp = Irp; - } - - ExInterlockedInsertTailList(&This->ListHead, &Mapping->Entry, &This->Lock); - (void)InterlockedIncrement((volatile long*)&This->NumMappings); - - DPRINT("IIrpQueue_fnAddMapping NumMappings %u SizeOfMapping %lu NumDataAvailable %lu Mapping %p FrameSize %u\n", This->NumMappings, Mapping->BufferSize, This->NumDataAvailable, Mapping, This->MaxFrameSize); - } - - if (Irp) - { - Irp->IoStatus.Status = STATUS_PENDING; - Irp->IoStatus.Information = 0; - IoMarkIrpPending(Irp); - } + /* add irp to cancelable queue */ + KsAddIrpToCancelableQueue(&This->IrpList, &This->IrpListLock, Irp, KsListEntryTail, NULL); + /* done */ return STATUS_SUCCESS; } @@ -234,55 +156,102 @@ IIrpQueue_fnGetMapping( OUT PUCHAR * Buffer, OUT PULONG BufferSize) { - - PIRP_MAPPING CurMapping; + PIRP Irp; + ULONG Offset; + PKSSTREAM_HEADER StreamHeader; IIrpQueueImpl * This = (IIrpQueueImpl*)iface; - PLIST_ENTRY CurEntry; - CurEntry = ExInterlockedRemoveHeadList(&This->ListHead, &This->Lock); - if (!CurEntry) + /* check if there is an irp in the partially processed */ + if (This->Irp) { - This->StartStream = FALSE; - This->OutOfMapping = TRUE; - return STATUS_UNSUCCESSFUL; + /* use last irp */ + Irp = This->Irp; + Offset = This->CurrentOffset; + /* TODO cancel irp when required */ + ASSERT(Irp->Cancel == FALSE); + } + else + { + /* get a fresh new irp from the queue */ + This->Irp = Irp = KsRemoveIrpFromCancelableQueue(&This->IrpList, &This->IrpListLock, KsListEntryHead, KsAcquireAndRemoveOnlySingleItem); + This->CurrentOffset = Offset = 0; } - CurMapping = CONTAINING_RECORD(CurEntry, IRP_MAPPING, Entry); - *Buffer = (PUCHAR)CurMapping->Buffer + This->CurrentOffset; - *BufferSize = CurMapping->BufferSize - This->CurrentOffset; - ExInterlockedInsertHeadList(&This->ListHead, &CurMapping->Entry, &This->Lock); + if (!Irp) + { + /* no irp available, use silence buffer */ + *Buffer = This->SilenceBuffer; + *BufferSize = This->MaxFrameSize; + /* flag for port wave pci driver */ + This->OutOfMapping = TRUE; + /* indicate flag to restart fast buffering */ + This->StartStream = FALSE; + return STATUS_SUCCESS; + } + + /* HACK get stream header */ + StreamHeader = (PKSSTREAM_HEADER)Irp->Tail.Overlay.DriverContext[2]; + + /* sanity check */ + ASSERT(StreamHeader); + + /* store buffersize */ + *BufferSize = StreamHeader->DataUsed - Offset; + + /* store buffer */ + *Buffer = &((PUCHAR)StreamHeader->Data)[Offset]; + + /* unset flag that no irps are available */ This->OutOfMapping = FALSE; return STATUS_SUCCESS; } - - VOID NTAPI IIrpQueue_fnUpdateMapping( IN IIrpQueue *iface, IN ULONG BytesWritten) { - PLIST_ENTRY CurEntry; - PIRP_MAPPING CurMapping; + PKSSTREAM_HEADER StreamHeader; IIrpQueueImpl * This = (IIrpQueueImpl*)iface; - CurEntry = ExInterlockedRemoveHeadList(&This->ListHead, &This->Lock); - CurMapping = CONTAINING_RECORD(CurEntry, IRP_MAPPING, Entry); + if (!This->Irp) + { + /* silence buffer was used */ + return; + } + /* HACK get stream header */ + StreamHeader = (PKSSTREAM_HEADER)This->Irp->Tail.Overlay.DriverContext[2]; + + /* add to current offset */ This->CurrentOffset += BytesWritten; + + /* decrement available data counter */ This->NumDataAvailable -= BytesWritten; - if (CurMapping->BufferSize <= This->CurrentOffset) + if (This->CurrentOffset >= StreamHeader->DataUsed) { + /* irp has been processed completly */ + This->Irp->IoStatus.Status = STATUS_SUCCESS; + + /* frame extend contains the original request size, DataUsed contains the real buffer size + * is different when kmixer performs channel conversion, upsampling etc + */ + This->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); + + /* complete the request */ + IoCompleteRequest(This->Irp, IO_SOUND_INCREMENT); + /* remove irp as it is complete */ + This->Irp = NULL; This->CurrentOffset = 0; - InterlockedDecrement(&This->NumMappings); - FreeMappingRoutine(CurMapping); - } - else - { - ExInterlockedInsertHeadList(&This->ListHead, &CurMapping->Entry, &This->Lock); } } @@ -293,6 +262,7 @@ IIrpQueue_fnNumMappings( { IIrpQueueImpl * This = (IIrpQueueImpl*)iface; + /* returns the amount of mappings available */ return This->NumMappings; } @@ -302,6 +272,7 @@ IIrpQueue_fnNumData( IN IIrpQueue *iface) { IIrpQueueImpl * This = (IIrpQueueImpl*)iface; + /* returns the amount of audio stream data available */ return This->NumDataAvailable; } @@ -363,50 +334,45 @@ IIrpQueue_fnGetMappingWithTag( OUT PULONG ByteCount, OUT PULONG Flags) { - PIRP_MAPPING CurMapping; - PLIST_ENTRY CurEntry; + PKSSTREAM_HEADER StreamHeader; + PIRP Irp; IIrpQueueImpl * This = (IIrpQueueImpl*)iface; *Flags = 0; ASSERT(Tag != NULL); + /* get an irp from the queue */ + Irp = KsRemoveIrpFromCancelableQueue(&This->IrpList, &This->IrpListLock, KsListEntryHead, KsAcquireAndRemoveOnlySingleItem); - CurEntry = ExInterlockedRemoveHeadList(&This->ListHead, &This->Lock); - if (!CurEntry) + /* check if there is an irp */ + if (!Irp) { + /* no irp available */ This->OutOfMapping = TRUE; This->StartStream = FALSE; return STATUS_UNSUCCESSFUL; } - CurMapping = CONTAINING_RECORD(CurEntry, IRP_MAPPING, Entry); + /* HACK get stream header */ + StreamHeader = (PKSSTREAM_HEADER)Irp->Tail.Overlay.DriverContext[2]; - *PhysicalAddress = MmGetPhysicalAddress(CurMapping->Buffer); - *VirtualAddress = CurMapping->Buffer; - *ByteCount = CurMapping->BufferSize; + /* store mapping in the free list */ + ExInterlockedInsertTailList(&This->FreeIrpList, &Irp->Tail.Overlay.ListEntry, &This->IrpListLock); + /* return mapping */ + *PhysicalAddress = MmGetPhysicalAddress(StreamHeader->Data); + *VirtualAddress = StreamHeader->Data; + *ByteCount = StreamHeader->DataUsed; + + /* decrement mapping count */ InterlockedDecrement(&This->NumMappings); - This->NumDataAvailable -= CurMapping->BufferSize; + /* decrement num data available */ + This->NumDataAvailable -= StreamHeader->DataUsed; - if (CurMapping->OriginalBuffer) - { - /* last partial buffer */ - *Flags = 1; - - /* store tag */ - CurMapping->Tag = Tag; - - /* insert into list to free later */ - ExInterlockedInsertTailList(&This->FreeHead, &CurMapping->Entry, &This->Lock); - DPRINT("IIrpQueue_fnGetMappingWithTag Tag %p Mapping %p\n", Tag, CurMapping); - } - else - { - /* we can free this entry now */ - FreeItem(CurMapping, TAG_PORTCLASS); - DPRINT("IIrpQueue_fnGetMappingWithTag Tag %p Mapping %p FREED\n", Tag, CurMapping); - } + /* store tag in irp */ + Irp->Tail.Overlay.DriverContext[3] = Tag; + /* done */ return STATUS_SUCCESS; } @@ -416,30 +382,44 @@ IIrpQueue_fnReleaseMappingWithTag( IN IIrpQueue *iface, IN PVOID Tag) { - PIRP_MAPPING CurMapping = NULL; + PIRP Irp; PLIST_ENTRY CurEntry; + PKSSTREAM_HEADER StreamHeader; IIrpQueueImpl * This = (IIrpQueueImpl*)iface; DPRINT("IIrpQueue_fnReleaseMappingWithTag Tag %p\n", Tag); - CurEntry = ExInterlockedRemoveHeadList(&This->FreeHead, &This->Lock); - if (!CurMapping) - { - return STATUS_SUCCESS; - } + /* remove irp from used list */ + CurEntry = ExInterlockedRemoveHeadList(&This->FreeIrpList, &This->IrpListLock); + /* sanity check */ + ASSERT(CurEntry); - CurMapping = CONTAINING_RECORD(CurEntry, IRP_MAPPING, Entry); - if (CurMapping->Tag != Tag) - { - /* the released mapping is not the last one */ - ExInterlockedInsertHeadList(&This->FreeHead, &CurMapping->Entry, &This->Lock); - return STATUS_SUCCESS; - } + /* get irp from list entry */ + Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry); - /* last mapping of the irp, free irp */ - DPRINT("IIrpQueue_fnReleaseMappingWithTag Tag %p Mapping %p FREED\n", Tag, CurMapping); + /* HACK get stream header */ + StreamHeader = (PKSSTREAM_HEADER)Irp->Tail.Overlay.DriverContext[2]; + + /* driver must release items in the same order */ + ASSERT(Irp->Tail.Overlay.DriverContext[3] == Tag); + + /* irp has been processed completly */ + Irp->IoStatus.Status = STATUS_SUCCESS; + + /* 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; + + /* 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); + + /* complete the request */ + IoCompleteRequest(Irp, IO_SOUND_INCREMENT); - FreeMappingRoutine(CurMapping); return STATUS_SUCCESS; } @@ -457,24 +437,7 @@ NTAPI IIrpQueue_fnPrintQueueStatus( IN IIrpQueue *iface) { - PIRP_MAPPING CurMapping = NULL; - PLIST_ENTRY CurEntry; - IIrpQueueImpl * This = (IIrpQueueImpl*)iface; - KeAcquireSpinLockAtDpcLevel(&This->Lock); - - CurEntry = This->ListHead.Flink; - DPRINT("IIrpQueue_fnPrintQueueStatus % u ===============\n", This->NumMappings); - - while (CurEntry != &This->ListHead) - { - CurMapping = CONTAINING_RECORD(CurEntry, IRP_MAPPING, Entry); - DPRINT("Mapping %p Size %u Original %p\n", CurMapping, CurMapping->BufferSize, CurMapping->OriginalBuffer); - CurEntry = CurEntry->Flink; - } - - KeReleaseSpinLockFromDpcLevel(&This->Lock); - DPRINT("IIrpQueue_fnPrintQueueStatus ===============\n"); } VOID diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.c b/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.c index 66f8bf7bca3..7e82894dd60 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.c @@ -1135,7 +1135,7 @@ IPortPinDMus_fnInit( This->ServiceGroup->lpVtbl->SupportDelayedService(This->ServiceGroup); } - Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, This->Format, DeviceObject, 0, 0); + Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, This->Format, DeviceObject, 0, 0, NULL /*FIXME*/); if (!NT_SUCCESS(Status)) { DPRINT1("IrpQueue_Init failed with %x\n", Status); diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c index 885f32b0905..f5b58b41e89 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c @@ -970,38 +970,25 @@ IPortPinWaveCyclic_fnFastWrite( PrePostRatio = (This->PreCompleted * 100) / This->TotalPackets; MinData = This->IrpQueue->lpVtbl->NumData(This->IrpQueue); - DPRINT("IPortPinWaveCyclic_fnFastWrite entered Total %u Pre %u Post %u State %x MinData %u Ratio %u\n", This->TotalPackets, This->PreCompleted, This->PostCompleted, This->State, This->IrpQueue->lpVtbl->NumData(This->IrpQueue), PrePostRatio); + DPRINT1("IPortPinWaveCyclic_fnFastWrite entered Total %u Pre %u Post %u State %x MinData %u Ratio %u\n", This->TotalPackets, This->PreCompleted, This->PostCompleted, This->State, This->IrpQueue->lpVtbl->NumData(This->IrpQueue), PrePostRatio); Packet = (PCONTEXT_WRITE)Buffer; - - if (This->IrpQueue->lpVtbl->MinimumDataAvailable(This->IrpQueue)) - { - Irp = Packet->Irp; - StatusBlock->Status = STATUS_PENDING; - InterlockedIncrement((PLONG)&This->PostCompleted); - } - else - { - Irp = NULL; - Packet->Irp->IoStatus.Status = STATUS_SUCCESS; - Packet->Irp->IoStatus.Information = Packet->Header.FrameExtent; - IoCompleteRequest(Packet->Irp, IO_SOUND_INCREMENT); - StatusBlock->Status = STATUS_SUCCESS; - InterlockedIncrement((PLONG)&This->PreCompleted); - } + Irp = Packet->Irp; Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Irp); if (!NT_SUCCESS(Status)) return FALSE; - if (This->State != KSSTATE_RUN && This->IrpQueue->lpVtbl->MinimumDataAvailable(This->IrpQueue) == TRUE) + if (This->State != KSSTATE_RUN) { SetStreamState(This, KSSTATE_RUN); /* some should initiate a state request but didnt do it */ DPRINT1("Starting stream with %lu mappings Status %x\n", This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue), Status); } + StatusBlock->Status = STATUS_PENDING; + return TRUE; } @@ -1021,6 +1008,7 @@ IPortPinWaveCyclic_fnInit( PKSDATAFORMAT DataFormat; PDEVICE_OBJECT DeviceObject; BOOL Capture; + PVOID SilenceBuffer; //IDrmAudioStream * DrmAudio = NULL; IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface; @@ -1114,14 +1102,19 @@ IPortPinWaveCyclic_fnInit( Status = This->Stream->lpVtbl->SetNotificationFreq(This->Stream, 10, &This->FrameSize); - Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DataFormat, DeviceObject, This->FrameSize, 0); + SilenceBuffer = AllocateItem(NonPagedPool, This->FrameSize, TAG_PORTCLASS); + if (!SilenceBuffer) + return STATUS_INSUFFICIENT_RESOURCES; + + This->Stream->lpVtbl->Silence(This->Stream, SilenceBuffer, This->FrameSize); + + Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DataFormat, DeviceObject, This->FrameSize, 0, SilenceBuffer); if (!NT_SUCCESS(Status)) { This->IrpQueue->lpVtbl->Release(This->IrpQueue); return Status; } - //This->Stream->lpVtbl->SetFormat(This->Stream, (PKSDATAFORMAT)This->Format); DPRINT1("Setting state to acquire %x\n", This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_ACQUIRE)); DPRINT1("Setting state to pause %x\n", This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_PAUSE)); diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.c b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.c index a332c9248ac..463a6e172c0 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.c @@ -1069,7 +1069,7 @@ IPortPinWavePci_fnInit( if (!NT_SUCCESS(Status)) return Status; - Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, This->Format, DeviceObject, This->AllocatorFraming.FrameSize, This->AllocatorFraming.FileAlignment); + Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, This->Format, DeviceObject, This->AllocatorFraming.FrameSize, This->AllocatorFraming.FileAlignment, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("IrpQueue_Init failed with %x\n", Status); diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c index aaff97fcc69..7b0c3a5dd9f 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c @@ -992,7 +992,7 @@ IPortPinWaveRT_fnInit( goto cleanup; } - Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DataFormat, DeviceObject, 0, 0); + Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DataFormat, DeviceObject, 0, 0, NULL); if (!NT_SUCCESS(Status)) { goto cleanup; diff --git a/reactos/drivers/wdm/audio/filters/kmixer/pin.c b/reactos/drivers/wdm/audio/filters/kmixer/pin.c index 71f817ce684..402f58776e9 100644 --- a/reactos/drivers/wdm/audio/filters/kmixer/pin.c +++ b/reactos/drivers/wdm/audio/filters/kmixer/pin.c @@ -668,6 +668,8 @@ Pin_fnFastWrite( } } + IoStatus->Status = Status; + if (NT_SUCCESS(Status)) return TRUE; else diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/control.c b/reactos/drivers/wdm/audio/legacy/wdmaud/control.c index 2f13fb7c9ec..1a4fc915677 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/control.c +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/control.c @@ -704,6 +704,28 @@ WdmAudDeviceControl( return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0); } +NTSTATUS +NTAPI +WdmAudWriteCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP LowerIrp, + IN PVOID Context) +{ + PIRP Irp; + ASSERT(LowerIrp->PendingReturned == FALSE); + /* get original irp */ + Irp = (PIRP)Context; + + /* save status */ + Irp->IoStatus.Status = LowerIrp->IoStatus.Status; + Irp->IoStatus.Information = LowerIrp->IoStatus.Information; + /* complete request */ + IoCompleteRequest(Irp, IO_SOUND_INCREMENT); + /* return success to free irp */ + return STATUS_SUCCESS; +} + + NTSTATUS NTAPI WdmAudWrite( @@ -715,11 +737,13 @@ WdmAudWrite( PWDMAUD_CLIENT ClientInfo; NTSTATUS Status = STATUS_SUCCESS; PUCHAR Buffer; - PCONTEXT_WRITE Packet; PFILE_OBJECT FileObject; - IO_STATUS_BLOCK IoStatusBlock; PMDL Mdl; + //PIRP LowerIrp; + PCONTEXT_WRITE Packet; PVOID SystemBuffer; + //LARGE_INTEGER Offset; + IO_STATUS_BLOCK IoStatusBlock; IoStack = IoGetCurrentIrpStackLocation(Irp); @@ -826,14 +850,51 @@ WdmAudWrite( ExFreePool(Packet); IoFreeMdl(Mdl); ObDereferenceObject(FileObject); - return SetIrpIoStatus(Irp, Status, 0); + return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0); } RtlMoveMemory(Buffer, SystemBuffer, DeviceInfo->BufferSize); MmUnlockPages(Mdl); IoFreeMdl(Mdl); - KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, KernelMode); +#if 1 + KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, UserMode); + /* dereference file object */ ObDereferenceObject(FileObject); return IoStatusBlock.Status; +#else + Offset.QuadPart = 0L; + + /* now build the irp */ + LowerIrp = IoBuildAsynchronousFsdRequest (IRP_MJ_WRITE, + IoGetRelatedDeviceObject(FileObject), + Packet, + sizeof(KSSTREAM_HEADER), + &Offset, + NULL); + + if (!LowerIrp) + { + /* failed to create an associated irp */ + ExFreePool(Buffer); + ExFreePool(Packet); + ObDereferenceObject(FileObject); + + return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0); + } + + /* set a completion routine */ + IoSetCompletionRoutine(LowerIrp, WdmAudWriteCompletion, (PVOID)Irp, TRUE, TRUE, TRUE); + + /* mark irp as pending */ + IoMarkIrpPending(Irp); + + /* call the driver */ + Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), LowerIrp); + + /* dereference file object */ + ObDereferenceObject(FileObject); + + return STATUS_PENDING; +#endif } diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h b/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h index ce37f2b79a5..4fb5c6cc8e5 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h @@ -56,15 +56,6 @@ typedef struct PIRP Irp; }CONTEXT_WRITE, *PCONTEXT_WRITE; - -typedef struct -{ - PIRP Irp; - IO_STATUS_BLOCK StatusBlock; - ULONG Length; -}WRITE_CONTEXT, *PWRITE_CONTEXT; - - NTSTATUS WdmAudRegisterDeviceInterface( IN PDEVICE_OBJECT PhysicalDeviceObject, diff --git a/reactos/drivers/wdm/audio/sysaudio/pin.c b/reactos/drivers/wdm/audio/sysaudio/pin.c index 21456926621..2ed463b96f6 100644 --- a/reactos/drivers/wdm/audio/sysaudio/pin.c +++ b/reactos/drivers/wdm/audio/sysaudio/pin.c @@ -161,7 +161,7 @@ Pin_fnWrite( /* call the portcls audio pin */ Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_WRITE_STREAM, - MmGetMdlVirtualAddress(Irp->MdlAddress), + Irp->UserBuffer, IoStack->Parameters.Write.Length, NULL, 0, @@ -379,13 +379,14 @@ Pin_fnFastWrite( Status = ObReferenceObjectByHandle(Context->hMixerPin, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&RealFileObject, NULL); if (NT_SUCCESS(Status)) { - Status = KsStreamIo(RealFileObject, NULL, NULL, NULL, NULL, 0, IoStatus, Buffer, Length, KSSTREAM_WRITE, KernelMode); + Status = KsStreamIo(RealFileObject, NULL, NULL, NULL, NULL, 0, IoStatus, Buffer, Length, KSSTREAM_WRITE, UserMode); ObDereferenceObject(RealFileObject); } if (!NT_SUCCESS(Status)) { DPRINT1("Mixing stream failed with %lx\n", Status); + DbgBreakPoint(); return FALSE; } } @@ -394,11 +395,11 @@ Pin_fnFastWrite( if (!NT_SUCCESS(Status)) return FALSE; - Status = KsStreamIo(RealFileObject, NULL, NULL, NULL, NULL, 0, IoStatus, Buffer, Length, KSSTREAM_WRITE, KernelMode); + Status = KsStreamIo(RealFileObject, NULL, NULL, NULL, NULL, 0, IoStatus, Buffer, Length, KSSTREAM_WRITE, UserMode); ObDereferenceObject(RealFileObject); - if (Status == STATUS_SUCCESS) + if (NT_SUCCESS(Status)) return TRUE; else return FALSE;