[KS]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Sun, 2 Aug 2009 11:40:38 +0000 (11:40 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Sun, 2 Aug 2009 11:40:38 +0000 (11:40 +0000)
- 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
reactos/drivers/wdm/audio/backpln/portcls/interfaces.h
reactos/drivers/wdm/audio/backpln/portcls/irpstream.c
reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.c
reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c
reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.c
reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c
reactos/drivers/wdm/audio/filters/kmixer/pin.c
reactos/drivers/wdm/audio/legacy/wdmaud/control.c
reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h
reactos/drivers/wdm/audio/sysaudio/pin.c

index 2ec01c9..7f1c1c8 100644 (file)
@@ -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;
 }
 
 /*
index 440680a..7ee232a 100644 (file)
@@ -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,
index f3e9a6d..c8ac7f0 100644 (file)
@@ -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;
-
-            NumMappings = Header->DataUsed / This->MaxFrameSize;
-            if (Rest)
-            {
-                NumMappings++;
-            }
-        }
-    }
-    else
-    {
-        /* no framesize restriction */
-        NumMappings = 1;
-    }
+    /* get stream header */
+    Header = (KSSTREAM_HEADER*)Buffer;
 
-    for(Index = 0; Index < NumMappings; Index++)
-    {
-        Mapping = AllocateItem(NonPagedPool, sizeof(IRP_MAPPING), TAG_PORTCLASS);
-        if (!Mapping)
-        {
-            DPRINT("OutOfMemory\n");
-            return STATUS_UNSUCCESSFUL;
-        }
-
-        if (Index)
-            Offset = Index * This->MaxFrameSize;
-        else
-            Offset = 0;
-
-        Mapping->Buffer = (PVOID)UlongToPtr((PtrToUlong(Header->Data) + Offset + 3) & ~(0x3));
-
-        if (This->MaxFrameSize)
-            Mapping->BufferSize = min(Header->DataUsed - Offset, This->MaxFrameSize);
-        else
-            Mapping->BufferSize = Header->DataUsed;
-
-        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);
-    }
+    /* dont exceed max frame size */
+    ASSERT(This->MaxFrameSize >= Header->DataUsed);
 
-    if (Irp)
-    {
-        Irp->IoStatus.Status = STATUS_PENDING;
-        Irp->IoStatus.Information = 0;
-        IoMarkIrpPending(Irp);
-    }
+    /* hack untill stream probing is ready */
+    Irp->Tail.Overlay.DriverContext[2] = (PVOID)Header;
+
+    /* increment num mappings */
+    InterlockedIncrement(&This->NumMappings);
+
+    /* increment num data available */
+    This->NumDataAvailable += Header->DataUsed;
+
+    /* mark irp as pending */
+    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;
+        /* 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;
+    }
+
+    if (!Irp)
+    {
+        /* no irp available, use silence buffer */
+        *Buffer = This->SilenceBuffer;
+        *BufferSize = This->MaxFrameSize;
+        /* flag for port wave pci driver */
         This->OutOfMapping = TRUE;
-        return STATUS_UNSUCCESSFUL;
+        /* indicate flag to restart fast buffering */
+        This->StartStream = FALSE;
+        return STATUS_SUCCESS;
     }
 
-    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);
+    /* 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);
 
-    InterlockedDecrement(&This->NumMappings);
-    This->NumDataAvailable -= CurMapping->BufferSize;
+    /* return mapping */
+    *PhysicalAddress = MmGetPhysicalAddress(StreamHeader->Data);
+    *VirtualAddress = StreamHeader->Data;
+    *ByteCount = StreamHeader->DataUsed;
 
-    if (CurMapping->OriginalBuffer)
-    {
-        /* last partial buffer */
-        *Flags = 1;
+    /* decrement mapping count */
+    InterlockedDecrement(&This->NumMappings);
+    /* decrement num data available */
+    This->NumDataAvailable -= StreamHeader->DataUsed;
 
-        /* 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);
+
+    /* 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);
 
-    /* last mapping of the irp, free irp */
-    DPRINT("IIrpQueue_fnReleaseMappingWithTag Tag %p Mapping %p FREED\n", Tag, CurMapping);
+    /* 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
index 66f8bf7..7e82894 100644 (file)
@@ -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);
index 885f32b..f5b58b4 100644 (file)
@@ -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));
index a332c92..463a6e1 100644 (file)
@@ -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);
index aaff97f..7b0c3a5 100644 (file)
@@ -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;
index 71f817c..402f587 100644 (file)
@@ -668,6 +668,8 @@ Pin_fnFastWrite(
         }
     }
 
+    IoStatus->Status = Status;
+
     if (NT_SUCCESS(Status))
         return TRUE;
     else
index 2f13fb7..1a4fc91 100644 (file)
@@ -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
 }
index ce37f2b..4fb5c6c 100644 (file)
@@ -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,
index 2145692..2ed463b 100644 (file)
@@ -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;