From 57f9b71712f15c3e31987a0df35a62417fdbd4a2 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Tue, 5 May 2009 16:01:39 +0000 Subject: [PATCH] - Implement IPortWaveRT, IPortFilterWaveRT, IPortPinWaveRT interface for audio drivers >= Vista svn path=/trunk/; revision=40797 --- .../wdm/audio/backpln/portcls/filter_wavert.c | 462 ++++++++ .../drivers/wdm/audio/backpln/portcls/guids.c | 11 + .../wdm/audio/backpln/portcls/interfaces.h | 44 + .../audio/backpln/portcls/pin_wavecyclic.c | 3 - .../wdm/audio/backpln/portcls/pin_wavert.c | 1044 +++++++++++++++++ .../wdm/audio/backpln/portcls/port_wavert.c | 676 +++++++++++ .../audio/backpln/portcls/port_wavertstream.c | 247 ++++ .../wdm/audio/backpln/portcls/private.h | 19 + 8 files changed, 2503 insertions(+), 3 deletions(-) create mode 100644 reactos/drivers/wdm/audio/backpln/portcls/filter_wavert.c create mode 100644 reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c create mode 100644 reactos/drivers/wdm/audio/backpln/portcls/port_wavert.c create mode 100644 reactos/drivers/wdm/audio/backpln/portcls/port_wavertstream.c diff --git a/reactos/drivers/wdm/audio/backpln/portcls/filter_wavert.c b/reactos/drivers/wdm/audio/backpln/portcls/filter_wavert.c new file mode 100644 index 00000000000..1797f74c365 --- /dev/null +++ b/reactos/drivers/wdm/audio/backpln/portcls/filter_wavert.c @@ -0,0 +1,462 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: drivers/wdm/audio/backpln/portcls/filter_wavert.c + * PURPOSE: portcls wave RT filter + * PROGRAMMER: Johannes Anderwald + */ + +#include "private.h" + +typedef struct +{ + IPortFilterWaveRTVtbl *lpVtbl; + + LONG ref; + + IPortWaveRT* Port; + IPortPinWaveRT ** Pins; + SUBDEVICE_DESCRIPTOR * Descriptor; + +}IPortFilterWaveRTImpl; + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnQueryInterface( + IPortFilterWaveRT* iface, + IN REFIID refiid, + OUT PVOID* Output) +{ + IPortFilterWaveRTImpl * This = (IPortFilterWaveRTImpl*)iface; + + if (IsEqualGUIDAligned(refiid, &IID_IIrpTarget) || + IsEqualGUIDAligned(refiid, &IID_IUnknown)) + { + *Output = &This->lpVtbl; + InterlockedIncrement(&This->ref); + return STATUS_SUCCESS; + } + else if (IsEqualGUIDAligned(refiid, &IID_IPort)) + { + *Output = This->Port; + This->Port->lpVtbl->AddRef(This->Port); + return STATUS_SUCCESS; + } + + + return STATUS_UNSUCCESSFUL; +} + +/* + * @implemented + */ +ULONG +NTAPI +IPortFilterWaveRT_fnAddRef( + IPortFilterWaveRT* iface) +{ + IPortFilterWaveRTImpl * This = (IPortFilterWaveRTImpl*)iface; + + return InterlockedIncrement(&This->ref); +} + +/* + * @implemented + */ +ULONG +NTAPI +IPortFilterWaveRT_fnRelease( + IPortFilterWaveRT* iface) +{ + IPortFilterWaveRTImpl * This = (IPortFilterWaveRTImpl*)iface; + + InterlockedDecrement(&This->ref); + + if (This->ref == 0) + { + FreeItem(This, TAG_PORTCLASS); + return 0; + } + return This->ref; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnNewIrpTarget( + IN IPortFilterWaveRT* iface, + OUT struct IIrpTarget **OutTarget, + IN WCHAR * Name, + IN PUNKNOWN Unknown, + IN POOL_TYPE PoolType, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN KSOBJECT_CREATE *CreateObject) +{ + NTSTATUS Status; + IPortPinWaveRT * Pin; + PKSPIN_CONNECT ConnectDetails; + IPortFilterWaveRTImpl * This = (IPortFilterWaveRTImpl *)iface; + + ASSERT(This->Port); + ASSERT(This->Descriptor); + ASSERT(This->Pins); + + DPRINT("IPortFilterWaveRT_fnNewIrpTarget entered\n"); + + /* let's verify the connection request */ + Status = PcValidateConnectRequest(Irp, &This->Descriptor->Factory, &ConnectDetails); + if (!NT_SUCCESS(Status)) + { + return STATUS_UNSUCCESSFUL; + } + + if (This->Pins[ConnectDetails->PinId] && This->Descriptor->Factory.Instances[ConnectDetails->PinId].CurrentPinInstanceCount) + { + /* release existing instance */ + ASSERT(0); + This->Pins[ConnectDetails->PinId]->lpVtbl->Close(This->Pins[ConnectDetails->PinId], DeviceObject, NULL); + } + + /* now create the pin */ + Status = NewPortPinWaveRT(&Pin); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* initialize the pin */ + Status = Pin->lpVtbl->Init(Pin, This->Port, iface, ConnectDetails, &This->Descriptor->Factory.KsPinDescriptor[ConnectDetails->PinId], GetDeviceObjectFromPortWaveRT(This->Port)); + if (!NT_SUCCESS(Status)) + { + Pin->lpVtbl->Release(Pin); + return Status; + } + + /* release existing pin */ + if (This->Pins[ConnectDetails->PinId]) + { + This->Pins[ConnectDetails->PinId]->lpVtbl->Release(This->Pins[ConnectDetails->PinId]); + } + /* store pin */ + This->Pins[ConnectDetails->PinId] = Pin; + + /* store result */ + *OutTarget = (IIrpTarget*)Pin; + + /* increment current instance count */ + This->Descriptor->Factory.Instances[ConnectDetails->PinId].CurrentPinInstanceCount++; + + return Status; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnDeviceIoControl( + IN IPortFilterWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + ISubdevice *SubDevice = NULL; + SUBDEVICE_DESCRIPTOR * Descriptor; + NTSTATUS Status; + IPortFilterWaveRTImpl * This = (IPortFilterWaveRTImpl *)iface; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY); + Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&SubDevice); + ASSERT(Status == STATUS_SUCCESS); + ASSERT(SubDevice != NULL); + + Status = SubDevice->lpVtbl->GetDescriptor(SubDevice, &Descriptor); + ASSERT(Status == STATUS_SUCCESS); + ASSERT(Descriptor != NULL); + + SubDevice->lpVtbl->Release(SubDevice); + + return PcPropertyHandler(Irp, Descriptor); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnRead( + IN IPortFilterWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnWrite( + IN IPortFilterWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnFlush( + IN IPortFilterWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnClose( + IN IPortFilterWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + ULONG Index; + IPortFilterWaveRTImpl * This = (IPortFilterWaveRTImpl *)iface; + + for(Index = 0; Index < This->Descriptor->Factory.PinDescriptorCount; Index++) + { + if (This->Pins[Index]) + { + This->Pins[Index]->lpVtbl->Close(This->Pins[Index], DeviceObject, NULL); + } + } + + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_UNSUCCESSFUL; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnQuerySecurity( + IN IPortFilterWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortFilterWaveRT_fnSetSecurity( + IN IPortFilterWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +IPortFilterWaveRT_fnFastDeviceIoControl( + IN IPortFilterWaveRT* iface, + IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + IN PVOID InputBuffer, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength, + IN ULONG IoControlCode, + OUT PIO_STATUS_BLOCK StatusBlock, + IN PDEVICE_OBJECT DeviceObject) +{ + ULONG Index; + PKSPROPERTY Property; + NTSTATUS Status; + ISubdevice * SubDevice = NULL; + PSUBDEVICE_DESCRIPTOR Descriptor = NULL; + IPortFilterWaveRTImpl * This = (IPortFilterWaveRTImpl *)iface; + + Property = (PKSPROPERTY)InputBuffer; + + if (InputBufferLength < sizeof(KSPROPERTY)) + return FALSE; + + + /* get private interface */ + Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&SubDevice); + if (!NT_SUCCESS(Status)) + return FALSE; + + /* get descriptor */ + Status = SubDevice->lpVtbl->GetDescriptor(SubDevice, &Descriptor); + if (!NT_SUCCESS(Status)) + { + SubDevice->lpVtbl->Release(SubDevice); + return FALSE; + } + + for(Index = 0; Index < Descriptor->FilterPropertySet.FreeKsPropertySetOffset; Index++) + { + if (IsEqualGUIDAligned(&Property->Set, Descriptor->FilterPropertySet.Properties[Index].Set)) + { + FastPropertyHandler(FileObject, (PKSPROPERTY)InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, StatusBlock, + 1, + &Descriptor->FilterPropertySet.Properties[Index], + Descriptor, SubDevice); + } + } + return TRUE; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +IPortFilterWaveRT_fnFastRead( + IN IPortFilterWaveRT* iface, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PIO_STATUS_BLOCK StatusBlock, + IN PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED + return FALSE; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +IPortFilterWaveRT_fnFastWrite( + IN IPortFilterWaveRT* iface, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PIO_STATUS_BLOCK StatusBlock, + IN PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED + return FALSE; +} + +/* + * @implemented + */ +static +NTSTATUS +NTAPI +IPortFilterWaveRT_fnInit( + IN IPortFilterWaveRT* iface, + IN IPortWaveRT* Port) +{ + ISubdevice * ISubDevice; + SUBDEVICE_DESCRIPTOR * Descriptor; + NTSTATUS Status; + IPortFilterWaveRTImpl * This = (IPortFilterWaveRTImpl*)iface; + + This->Port = Port; + + /* get our private interface */ + Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&ISubDevice); + if (!NT_SUCCESS(Status)) + return STATUS_UNSUCCESSFUL; + + /* get the subdevice descriptor */ + Status = ISubDevice->lpVtbl->GetDescriptor(ISubDevice, &Descriptor); + + /* release subdevice interface */ + ISubDevice->lpVtbl->Release(ISubDevice); + + if (!NT_SUCCESS(Status)) + return STATUS_UNSUCCESSFUL; + + /* save descriptor */ + This->Descriptor = Descriptor; + + /* allocate pin array */ + This->Pins = AllocateItem(NonPagedPool, Descriptor->Factory.PinDescriptorCount * sizeof(IPortPinWaveRT*), TAG_PORTCLASS); + + if (!This->Pins) + return STATUS_UNSUCCESSFUL; + + /* increment reference count */ + Port->lpVtbl->AddRef(Port); + + return STATUS_SUCCESS; +} + +static IPortFilterWaveRTVtbl vt_IPortFilterWaveRT = +{ + IPortFilterWaveRT_fnQueryInterface, + IPortFilterWaveRT_fnAddRef, + IPortFilterWaveRT_fnRelease, + IPortFilterWaveRT_fnNewIrpTarget, + IPortFilterWaveRT_fnDeviceIoControl, + IPortFilterWaveRT_fnRead, + IPortFilterWaveRT_fnWrite, + IPortFilterWaveRT_fnFlush, + IPortFilterWaveRT_fnClose, + IPortFilterWaveRT_fnQuerySecurity, + IPortFilterWaveRT_fnSetSecurity, + IPortFilterWaveRT_fnFastDeviceIoControl, + IPortFilterWaveRT_fnFastRead, + IPortFilterWaveRT_fnFastWrite, + IPortFilterWaveRT_fnInit +}; + +NTSTATUS +NewPortFilterWaveRT( + OUT IPortFilterWaveRT ** OutFilter) +{ + IPortFilterWaveRTImpl * This; + + This = AllocateItem(NonPagedPool, sizeof(IPortFilterWaveRTImpl), TAG_PORTCLASS); + if (!This) + return STATUS_INSUFFICIENT_RESOURCES; + + /* initialize IPortFilterWaveRT */ + This->ref = 1; + This->lpVtbl = &vt_IPortFilterWaveRT; + + /* return result */ + *OutFilter = (IPortFilterWaveRT*)&This->lpVtbl; + + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/wdm/audio/backpln/portcls/guids.c b/reactos/drivers/wdm/audio/backpln/portcls/guids.c index ab605606782..f7ecd961e81 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/guids.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/guids.c @@ -76,3 +76,14 @@ const GUID IID_ISubdevice = {0xB4C90A61, 0x5791, 0x11D0, {0x86, 0xF9, 0x00, 0xA0 const GUID IID_IIrpTarget = {0xB4C90A60, 0x5791, 0x11D0, {0xF9, 0x86, 0x00, 0xA0, 0xC9, 0x11, 0xB5, 0x44}}; const GUID IID_IIrpTargetFactory = {0xB4C90A62, 0x5791, 0x11D0, {0xF9, 0x86, 0x00, 0xA0, 0xC9, 0x11, 0xB5, 0x44}}; + +/// +/// >= Vista GUIDs +/// +const GUID IID_IPortWaveRT = {0x339ff909, 0x68a9, 0x4310, {0xb0, 0x9b, 0x27, 0x4e, 0x96, 0xee, 0x4c, 0xbd}}; +const GUID IID_IPortWaveRTStream = {0x1809ce5a, 0x64bc, 0x4e62, {0xbd, 0x7d, 0x95, 0xbc, 0xe4, 0x3d, 0xe3, 0x93}}; +const GUID IID_IMiniportWaveRT = {0x0f9fc4d6, 0x6061, 0x4f3c, {0xb1, 0xfc, 0x7, 0x5e, 0x35, 0xf7, 0x96, 0xa}}; +const GUID IID_IMiniportWaveRTStream = {0x000ac9ab, 0xfaab, 0x4f3d, {0x94, 0x55, 0x6f, 0xf8, 0x30, 0x6a, 0x74, 0xa0}}; +const GUID IID_IMiniportWaveRTStreamNotification = {0x23759128, 0x96f1, 0x423b, {0xab, 0x4d, 0x81, 0x63, 0x5b, 0xcf, 0x8c, 0xa1}}; + + diff --git a/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h b/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h index ee7c389df52..66f5c4e7cea 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h +++ b/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h @@ -474,6 +474,50 @@ DECLARE_INTERFACE_(IPortPinWavePci, IIrpTarget) typedef IPortPinWavePci *PPORTPINWAVEPCI; +/***************************************************************************** + * IPortFilterWaveRT + ***************************************************************************** + */ + +#undef INTERFACE +#define INTERFACE IPortFilterWaveRT + +DECLARE_INTERFACE_(IPortFilterWaveRT, IIrpTarget) +{ + DEFINE_ABSTRACT_UNKNOWN() + + DEFINE_ABSTRACT_IRPTARGET() + + STDMETHOD_(NTSTATUS, Init)(THIS_ + IN PPORTWAVERT Port)PURE; +}; + +typedef IPortFilterWaveRT *PPORTFILTERWAVERT; + +/***************************************************************************** + * IPortPinWavePci + ***************************************************************************** + */ + +#undef INTERFACE +#define INTERFACE IPortPinWaveRT + +DECLARE_INTERFACE_(IPortPinWaveRT, IIrpTarget) +{ + DEFINE_ABSTRACT_UNKNOWN() + + DEFINE_ABSTRACT_IRPTARGET() + + STDMETHOD_(NTSTATUS, Init)(THIS_ + IN PPORTWAVERT Port, + IN PPORTFILTERWAVERT Filter, + IN KSPIN_CONNECT * ConnectDetails, + IN KSPIN_DESCRIPTOR * PinDescriptor, + IN PDEVICE_OBJECT DeviceObject) PURE; +}; + +typedef IPortPinWavePci *PPORTPINWAVERT; + /***************************************************************************** * IPortFilterWaveCyclic ***************************************************************************** diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c index db62a991ea7..85433e78858 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c @@ -31,9 +31,6 @@ typedef struct IIrpQueue * IrpQueue; - PUCHAR ActiveIrpBuffer; - ULONG ActiveIrpBufferSize; - ULONG ActiveIrpOffset; ULONG FrameSize; BOOL Capture; diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c new file mode 100644 index 00000000000..e9263766609 --- /dev/null +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavert.c @@ -0,0 +1,1044 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: drivers/wdm/audio/backpln/portcls/pin_wavert.c + * PURPOSE: WaveRT IRP Audio Pin + * PROGRAMMER: Johannes Anderwald + */ + +#include "private.h" + +typedef struct +{ + IPortPinWaveRTVtbl *lpVtbl; + IServiceSinkVtbl *lpVtblServiceSink; + LONG ref; + + IPortWaveRT * Port; + IPortFilterWaveRT * Filter; + KSPIN_DESCRIPTOR * KsPinDescriptor; + PMINIPORTWAVERT Miniport; + PMINIPORTWAVERTSTREAM Stream; + PPORTWAVERTSTREAM PortStream; + PSERVICEGROUP ServiceGroup; + KSSTATE State; + PKSDATAFORMAT Format; + KSPIN_CONNECT * ConnectDetails; + + PVOID CommonBuffer; + ULONG CommonBufferSize; + ULONG CommonBufferOffset; + + IIrpQueue * IrpQueue; + + BOOL Capture; + + ULONG TotalPackets; + ULONG PreCompleted; + ULONG PostCompleted; + + ULONGLONG Delay; + + MEMORY_CACHING_TYPE CacheType; + PMDL Mdl; + +}IPortPinWaveRTImpl; + + +typedef struct +{ + IPortPinWaveRTImpl *Pin; + PIO_WORKITEM WorkItem; + KSSTATE State; +}SETSTREAM_CONTEXT, *PSETSTREAM_CONTEXT; + +static +VOID +NTAPI +SetStreamState( + IN IPortPinWaveRTImpl * This, + IN KSSTATE State); + +//================================================================================================================================== +static +NTSTATUS +NTAPI +IServiceSink_fnQueryInterface( + IServiceSink* iface, + IN REFIID refiid, + OUT PVOID* Output) +{ + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)CONTAINING_RECORD(iface, IPortPinWaveRTImpl, lpVtblServiceSink); + + DPRINT("IServiceSink_fnQueryInterface entered\n"); + + if (IsEqualGUIDAligned(refiid, &IID_IServiceSink) || + IsEqualGUIDAligned(refiid, &IID_IUnknown)) + { + *Output = &This->lpVtblServiceSink; + InterlockedIncrement(&This->ref); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + +static +ULONG +NTAPI +IServiceSink_fnAddRef( + IServiceSink* iface) +{ + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)CONTAINING_RECORD(iface, IPortPinWaveRTImpl, lpVtblServiceSink); + DPRINT("IServiceSink_fnAddRef entered\n"); + + return InterlockedIncrement(&This->ref); +} + +static +ULONG +NTAPI +IServiceSink_fnRelease( + IServiceSink* iface) +{ + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)CONTAINING_RECORD(iface, IPortPinWaveRTImpl, lpVtblServiceSink); + + InterlockedDecrement(&This->ref); + + DPRINT("IServiceSink_fnRelease entered %u\n", This->ref); + + if (This->ref == 0) + { + FreeItem(This, TAG_PORTCLASS); + return 0; + } + /* Return new reference count */ + return This->ref; +} + +static +VOID +NTAPI +IServiceSink_fnRequestService( + IServiceSink* iface) +{ + KSAUDIO_POSITION Position; + NTSTATUS Status; + PUCHAR Buffer; + ULONG BufferSize; + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)CONTAINING_RECORD(iface, IPortPinWaveRTImpl, lpVtblServiceSink); + + ASSERT_IRQL(DISPATCH_LEVEL); + + Status = This->IrpQueue->lpVtbl->GetMapping(This->IrpQueue, &Buffer, &BufferSize); + if (!NT_SUCCESS(Status)) + { + SetStreamState(This, KSSTATE_STOP); + return; + } + + Status = This->Stream->lpVtbl->GetPosition(This->Stream, &Position); + DPRINT("PlayOffset %llu WriteOffset %llu %u Buffer %p BufferSize %u\n", Position.PlayOffset, Position.WriteOffset, Buffer, This->CommonBufferSize, BufferSize); + + //FIXME + // implement writing into cyclic buffer + // + + /* reschedule the timer */ + This->ServiceGroup->lpVtbl->RequestDelayedService(This->ServiceGroup, This->Delay); +} + +static IServiceSinkVtbl vt_IServiceSink = +{ + IServiceSink_fnQueryInterface, + IServiceSink_fnAddRef, + IServiceSink_fnRelease, + IServiceSink_fnRequestService +}; + + +static +VOID +NTAPI +SetStreamWorkerRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context) +{ + IPortPinWaveRTImpl * This; + PSETSTREAM_CONTEXT Ctx = (PSETSTREAM_CONTEXT)Context; + KSSTATE State; + + This = Ctx->Pin; + State = Ctx->State; + + IoFreeWorkItem(Ctx->WorkItem); + FreeItem(Ctx, TAG_PORTCLASS); + + /* Has the audio stream resumed? */ + if (This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue) && State == KSSTATE_STOP) + return; + + /* Set the state */ + if (NT_SUCCESS(This->Stream->lpVtbl->SetState(This->Stream, State))) + { + /* Set internal state to stop */ + This->State = State; + + if (This->State == KSSTATE_STOP) + { + /* reset start stream */ + This->IrpQueue->lpVtbl->CancelBuffers(This->IrpQueue); //FIX function name + This->ServiceGroup->lpVtbl->CancelDelayedService(This->ServiceGroup); + DPRINT1("Stopping PreCompleted %u PostCompleted %u\n", This->PreCompleted, This->PostCompleted); + } + + if (This->State == KSSTATE_RUN) + { + /* start the notification timer */ + This->ServiceGroup->lpVtbl->RequestDelayedService(This->ServiceGroup, This->Delay); + } + } +} + +static +VOID +NTAPI +SetStreamState( + IN IPortPinWaveRTImpl * This, + IN KSSTATE State) +{ + PDEVICE_OBJECT DeviceObject; + PIO_WORKITEM WorkItem; + PSETSTREAM_CONTEXT Context; + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + /* Has the audio stream resumed? */ + if (This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue) && State == KSSTATE_STOP) + return; + + /* Has the audio state already been set? */ + if (This->State == State) + return; + + /* Get device object */ + DeviceObject = GetDeviceObjectFromPortWaveRT(This->Port); + + /* allocate set state context */ + Context = AllocateItem(NonPagedPool, sizeof(SETSTREAM_CONTEXT), TAG_PORTCLASS); + + if (!Context) + return; + + /* allocate work item */ + WorkItem = IoAllocateWorkItem(DeviceObject); + + if (!WorkItem) + { + ExFreePool(Context); + return; + } + + Context->Pin = (PVOID)This; + Context->WorkItem = WorkItem; + Context->State = State; + + /* queue the work item */ + IoQueueWorkItem(WorkItem, SetStreamWorkerRoutine, DelayedWorkQueue, (PVOID)Context); +} + +//================================================================================================================================== +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnQueryInterface( + IPortPinWaveRT* iface, + IN REFIID refiid, + OUT PVOID* Output) +{ + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + if (IsEqualGUIDAligned(refiid, &IID_IIrpTarget) || + IsEqualGUIDAligned(refiid, &IID_IUnknown)) + { + *Output = &This->lpVtbl; + InterlockedIncrement(&This->ref); + return STATUS_SUCCESS; + } + + return STATUS_UNSUCCESSFUL; +} + +/* + * @implemented + */ +ULONG +NTAPI +IPortPinWaveRT_fnAddRef( + IPortPinWaveRT* iface) +{ + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + return InterlockedIncrement(&This->ref); +} + +/* + * @implemented + */ +ULONG +NTAPI +IPortPinWaveRT_fnRelease( + IPortPinWaveRT* iface) +{ + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + InterlockedDecrement(&This->ref); + + if (This->ref == 0) + { + FreeItem(This, TAG_PORTCLASS); + return 0; + } + return This->ref; +} + +/* + * @unimplemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnNewIrpTarget( + IN IPortPinWaveRT* iface, + OUT struct IIrpTarget **OutTarget, + IN WCHAR * Name, + IN PUNKNOWN Unknown, + IN POOL_TYPE PoolType, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN KSOBJECT_CREATE *CreateObject) +{ + UNIMPLEMENTED + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +NTAPI +IPortPinWaveRT_HandleKsProperty( + IN IPortPinWaveRT * iface, + IN PIRP Irp) +{ + PKSPROPERTY Property; + NTSTATUS Status; + UNICODE_STRING GuidString; + PIO_STACK_LOCATION IoStack; + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + + DPRINT("IPortPinWave_HandleKsProperty entered\n"); + + if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY)) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INVALID_PARAMETER; + } + + Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer; + + if (IsEqualGUIDAligned(&Property->Set, &KSPROPSETID_Connection)) + { + if (Property->Id == KSPROPERTY_CONNECTION_STATE) + { + PKSSTATE State = (PKSSTATE)Irp->UserBuffer; + + if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSSTATE)) + { + Irp->IoStatus.Information = sizeof(KSSTATE); + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + if (Property->Flags & KSPROPERTY_TYPE_SET) + { + Status = STATUS_UNSUCCESSFUL; + Irp->IoStatus.Information = 0; + + if (This->Stream) + { + Status = This->Stream->lpVtbl->SetState(This->Stream, *State); + + DPRINT1("Setting state %u %x\n", *State, Status); + if (NT_SUCCESS(Status)) + { + This->State = *State; + } + } + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + else if (Property->Flags & KSPROPERTY_TYPE_GET) + { + *State = This->State; + Irp->IoStatus.Information = sizeof(KSSTATE); + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + } + else if (Property->Id == KSPROPERTY_CONNECTION_DATAFORMAT) + { + PKSDATAFORMAT DataFormat = (PKSDATAFORMAT)Irp->UserBuffer; + if (Property->Flags & KSPROPERTY_TYPE_SET) + { + PKSDATAFORMAT NewDataFormat; + if (!RtlCompareMemory(DataFormat, This->Format, DataFormat->FormatSize)) + { + Irp->IoStatus.Information = DataFormat->FormatSize; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + + NewDataFormat = AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS); + if (!NewDataFormat) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_NO_MEMORY; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NO_MEMORY; + } + RtlMoveMemory(NewDataFormat, DataFormat, DataFormat->FormatSize); + + if (This->Stream) + { + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + ASSERT(NewDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX)); + ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO)); + ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)); + ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)); + + ASSERT(This->State == KSSTATE_STOP); + DPRINT1("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nChannels, + ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.wBitsPerSample, + ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nSamplesPerSec); + + Status = This->Stream->lpVtbl->SetFormat(This->Stream, NewDataFormat); + if (NT_SUCCESS(Status)) + { + if (This->Format) + ExFreePoolWithTag(This->Format, TAG_PORTCLASS); + + This->IrpQueue->lpVtbl->UpdateFormat(This->IrpQueue, (PKSDATAFORMAT)NewDataFormat); + This->Format = NewDataFormat; + Irp->IoStatus.Information = DataFormat->FormatSize; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + } + DPRINT1("Failed to set format\n"); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_UNSUCCESSFUL; + } + else if (Property->Flags & KSPROPERTY_TYPE_GET) + { + if (!This->Format) + { + DPRINT1("No format\n"); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_UNSUCCESSFUL; + } + if (This->Format->FormatSize > IoStack->Parameters.DeviceIoControl.OutputBufferLength) + { + Irp->IoStatus.Information = This->Format->FormatSize; + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + RtlMoveMemory(DataFormat, This->Format, This->Format->FormatSize); + Irp->IoStatus.Information = DataFormat->FormatSize; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + } + + } + RtlStringFromGUID(&Property->Set, &GuidString); + DPRINT1("Unhandeled property Set |%S| Id %u Flags %x\n", GuidString.Buffer, Property->Id, Property->Flags); + DbgBreakPoint(); + RtlFreeUnicodeString(&GuidString); + + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +IPortPinWaveRT_HandleKsStream( + IN IPortPinWaveRT * iface, + IN PIRP Irp) +{ + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + DPRINT("IPortPinWaveRT_HandleKsStream entered State %u Stream %p\n", This->State, This->Stream); + + return STATUS_PENDING; +} + +/* + * @unimplemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnDeviceIoControl( + IN IPortPinWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + + + if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY) + { + return IPortPinWaveRT_HandleKsProperty(iface, Irp); + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_ENABLE_EVENT) + { + /// FIXME + /// handle enable event + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_DISABLE_EVENT) + { + /// FIXME + /// handle disable event + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_RESET_STATE) + { + /// FIXME + /// handle reset state + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM) + { + return IPortPinWaveRT_HandleKsStream(iface, Irp); + } + else + { + return KsDefaultDeviceIoCompletion(DeviceObject, Irp); + } + + UNIMPLEMENTED + DbgBreakPoint(); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_UNSUCCESSFUL; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnRead( + IN IPortPinWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnWrite( + IN IPortPinWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnFlush( + IN IPortPinWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +static +VOID +NTAPI +CloseStreamRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context) +{ + PMINIPORTWAVERTSTREAM Stream; + NTSTATUS Status; + ISubdevice *ISubDevice; + PSUBDEVICE_DESCRIPTOR Descriptor; + IPortPinWaveRTImpl * This; + PCLOSESTREAM_CONTEXT Ctx = (PCLOSESTREAM_CONTEXT)Context; + + This = (IPortPinWaveRTImpl*)Ctx->Pin; + + if (This->Stream) + { + if (This->State != KSSTATE_STOP) + { + This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP); + KeStallExecutionProcessor(10); + } + } + + Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&ISubDevice); + if (NT_SUCCESS(Status)) + { + Status = ISubDevice->lpVtbl->GetDescriptor(ISubDevice, &Descriptor); + if (NT_SUCCESS(Status)) + { + ISubDevice->lpVtbl->Release(ISubDevice); + Descriptor->Factory.Instances[This->ConnectDetails->PinId].CurrentPinInstanceCount--; + } + } + + if (This->Format) + { + ExFreePool(This->Format); + This->Format = NULL; + } + + if (This->IrpQueue) + { + This->IrpQueue->lpVtbl->Release(This->IrpQueue); + } + + /* complete the irp */ + Ctx->Irp->IoStatus.Information = 0; + Ctx->Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Ctx->Irp, IO_NO_INCREMENT); + + /* free the work item */ + IoFreeWorkItem(Ctx->WorkItem); + + /* free work item ctx */ + FreeItem(Ctx, TAG_PORTCLASS); + + if (This->Stream) + { + Stream = This->Stream; + This->Stream = NULL; + DPRINT1("Closing stream at Irql %u\n", KeGetCurrentIrql()); + Stream->lpVtbl->Release(Stream); + /* this line is never reached */ + } +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnClose( + IN IPortPinWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PCLOSESTREAM_CONTEXT Ctx; + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + if (This->Stream) + { + Ctx = AllocateItem(NonPagedPool, sizeof(CLOSESTREAM_CONTEXT), TAG_PORTCLASS); + if (!Ctx) + { + DPRINT1("Failed to allocate stream context\n"); + goto cleanup; + } + + Ctx->WorkItem = IoAllocateWorkItem(DeviceObject); + if (!Ctx->WorkItem) + { + DPRINT1("Failed to allocate work item\n"); + goto cleanup; + } + + Ctx->Irp = Irp; + Ctx->Pin = (PVOID)This; + + IoMarkIrpPending(Irp); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_PENDING; + + /* defer work item */ + IoQueueWorkItem(Ctx->WorkItem, CloseStreamRoutine, DelayedWorkQueue, (PVOID)Ctx); + /* Return result */ + return STATUS_PENDING; + } + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; + +cleanup: + + if (Ctx) + FreeItem(Ctx, TAG_PORTCLASS); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_UNSUCCESSFUL; + +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnQuerySecurity( + IN IPortPinWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnSetSecurity( + IN IPortPinWaveRT* iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +IPortPinWaveRT_fnFastDeviceIoControl( + IN IPortPinWaveRT* iface, + IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + IN PVOID InputBuffer, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength, + IN ULONG IoControlCode, + OUT PIO_STATUS_BLOCK StatusBlock, + IN PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED + return FALSE; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +IPortPinWaveRT_fnFastRead( + IN IPortPinWaveRT* iface, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PIO_STATUS_BLOCK StatusBlock, + IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + PCONTEXT_WRITE Packet; + PIRP Irp; + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + DPRINT("IPortPinWaveRT_fnFastRead entered\n"); + + Packet = (PCONTEXT_WRITE)Buffer; + + Irp = Packet->Irp; + StatusBlock->Status = STATUS_PENDING; + + Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Irp); + + if (!NT_SUCCESS(Status)) + return FALSE; + + if (This->IrpQueue->lpVtbl->MinimumDataAvailable(This->IrpQueue) == TRUE && This->State != KSSTATE_RUN) + { + /* some should initiate a state request but didnt do it */ + DPRINT1("Starting stream with %lu mappings\n", This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue)); + + This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_RUN); + This->State = KSSTATE_RUN; + } + return TRUE; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +IPortPinWaveRT_fnFastWrite( + IN IPortPinWaveRT* iface, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PIO_STATUS_BLOCK StatusBlock, + IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + PCONTEXT_WRITE Packet; + PIRP Irp; + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + InterlockedIncrement((PLONG)&This->TotalPackets); + + DPRINT("IPortPinWaveRT_fnFastWrite entered Total %u Pre %u Post %u\n", This->TotalPackets, This->PreCompleted, This->PostCompleted); + + 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); + } + + Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Irp); + + if (!NT_SUCCESS(Status)) + return FALSE; + + if (This->IrpQueue->lpVtbl->MinimumDataAvailable(This->IrpQueue) == TRUE && 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); + } + + return TRUE; +} + +/* + * @unimplemented + */ +NTSTATUS +NTAPI +IPortPinWaveRT_fnInit( + IN IPortPinWaveRT* iface, + IN PPORTWAVERT Port, + IN PPORTFILTERWAVERT Filter, + IN KSPIN_CONNECT * ConnectDetails, + IN KSPIN_DESCRIPTOR * KsPinDescriptor, + IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + PKSDATAFORMAT DataFormat; + BOOL Capture; + KSRTAUDIO_HWLATENCY Latency; + IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface; + + Port->lpVtbl->AddRef(Port); + Filter->lpVtbl->AddRef(Filter); + + This->Port = Port; + This->Filter = Filter; + This->KsPinDescriptor = KsPinDescriptor; + This->ConnectDetails = ConnectDetails; + This->Miniport = GetWaveRTMiniport(Port); + + DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1); + + DPRINT("IPortPinWaveRT_fnInit entered\n"); + + This->Format = AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS); + if (!This->Format) + return STATUS_INSUFFICIENT_RESOURCES; + + RtlMoveMemory(This->Format, DataFormat, DataFormat->FormatSize); + + Status = NewIrpQueue(&This->IrpQueue); + if (!NT_SUCCESS(Status)) + { + goto cleanup; + } + + Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DataFormat, DeviceObject, 0); + if (!NT_SUCCESS(Status)) + { + goto cleanup; + } + + Status = NewPortWaveRTStream(&This->PortStream); + if (!NT_SUCCESS(Status)) + { + goto cleanup; + } + + Status = PcNewServiceGroup(&This->ServiceGroup, NULL); + if (!NT_SUCCESS(Status)) + { + goto cleanup; + } + + This->ServiceGroup->lpVtbl->AddMember(This->ServiceGroup, (PSERVICESINK)&This->lpVtblServiceSink); + This->ServiceGroup->lpVtbl->SupportDelayedService(This->ServiceGroup); + + if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN) + { + Capture = FALSE; + } + else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT) + { + Capture = TRUE; + } + else + { + DPRINT1("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow); + KeBugCheck(0); + } + + Status = This->Miniport->lpVtbl->NewStream(This->Miniport, + &This->Stream, + This->PortStream, + ConnectDetails->PinId, + Capture, + This->Format); + DPRINT("IPortPinWaveRT_fnInit Status %x\n", Status); + + if (!NT_SUCCESS(Status)) + goto cleanup; + + This->Stream->lpVtbl->GetHWLatency(This->Stream, &Latency); + /* minimum delay of 10 milisec */ + This->Delay = Int32x32To64(min(max(Latency.ChipsetDelay + Latency.CodecDelay + Latency.FifoSize, 10), 10), -10000); + + Status = This->Stream->lpVtbl->AllocateAudioBuffer(This->Stream, 16384, &This->Mdl, &This->CommonBufferSize, &This->CommonBufferOffset, &This->CacheType); + if (!NT_SUCCESS(Status)) + { + DPRINT1("AllocateAudioBuffer failed with %x\n", Status); + goto cleanup; + } + + This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP); + This->State = KSSTATE_STOP; + This->Capture = Capture; + + This->Stream->lpVtbl->SetFormat(This->Stream, (PKSDATAFORMAT)This->Format); + return STATUS_SUCCESS; + +cleanup: + if (This->IrpQueue) + { + This->IrpQueue->lpVtbl->Release(This->IrpQueue); + This->IrpQueue = NULL; + } + + if (This->Format) + { + FreeItem(This->Format, TAG_PORTCLASS); + This->Format = NULL; + } + + if (This->ServiceGroup) + { + This->ServiceGroup->lpVtbl->Release(This->ServiceGroup); + This->ServiceGroup = NULL; + } + + if (This->PortStream) + { + This->PortStream->lpVtbl->Release(This->PortStream); + This->PortStream = NULL; + } + + return Status; +} + +static IPortPinWaveRTVtbl vt_IPortPinWaveRT = +{ + IPortPinWaveRT_fnQueryInterface, + IPortPinWaveRT_fnAddRef, + IPortPinWaveRT_fnRelease, + IPortPinWaveRT_fnNewIrpTarget, + IPortPinWaveRT_fnDeviceIoControl, + IPortPinWaveRT_fnRead, + IPortPinWaveRT_fnWrite, + IPortPinWaveRT_fnFlush, + IPortPinWaveRT_fnClose, + IPortPinWaveRT_fnQuerySecurity, + IPortPinWaveRT_fnSetSecurity, + IPortPinWaveRT_fnFastDeviceIoControl, + IPortPinWaveRT_fnFastRead, + IPortPinWaveRT_fnFastWrite, + IPortPinWaveRT_fnInit +}; + +NTSTATUS NewPortPinWaveRT( + OUT IPortPinWaveRT ** OutPin) +{ + IPortPinWaveRTImpl * This; + + This = AllocateItem(NonPagedPool, sizeof(IPortPinWaveRTImpl), TAG_PORTCLASS); + if (!This) + return STATUS_INSUFFICIENT_RESOURCES; + + /* initialize IPortPinWaveRT */ + This->ref = 1; + This->lpVtbl = &vt_IPortPinWaveRT; + This->lpVtblServiceSink = &vt_IServiceSink; + + /* store result */ + *OutPin = (IPortPinWaveRT*)&This->lpVtbl; + + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/wdm/audio/backpln/portcls/port_wavert.c b/reactos/drivers/wdm/audio/backpln/portcls/port_wavert.c new file mode 100644 index 00000000000..ff7216c482d --- /dev/null +++ b/reactos/drivers/wdm/audio/backpln/portcls/port_wavert.c @@ -0,0 +1,676 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: drivers/wdm/audio/backpln/portcls/port_wavert.c + * PURPOSE: WaveRT Port Driver + * PROGRAMMER: Johannes Anderwald + */ + +#include "private.h" + +typedef struct +{ + IPortWaveRTVtbl *lpVtbl; + IPortEventsVtbl *lpVbtlPortEvents; + IUnregisterSubdeviceVtbl *lpVtblUnregisterSubdevice; + IUnregisterPhysicalConnectionVtbl *lpVtblPhysicalConnection; + IPortEventsVtbl *lpVtblPortEvents; + ISubdeviceVtbl *lpVtblSubDevice; + + LONG ref; + + BOOL bInitialized; + PDEVICE_OBJECT pDeviceObject; + PMINIPORTWAVERT pMiniport; + PRESOURCELIST pResourceList; + PPINCOUNT pPinCount; + PPOWERNOTIFY pPowerNotify; + PPCFILTER_DESCRIPTOR pDescriptor; + PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor; + IPortFilterWaveRT * Filter; +}IPortWaveRTImpl; + +static GUID InterfaceGuids[3] = +{ + { + /// KSCATEGORY_RENDER + 0x65E8773EL, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} + }, + { + /// KSCATEGORY_CAPTURE + 0x65E8773DL, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} + }, + { + /// KS_CATEGORY_AUDIO + 0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} + } +}; + +DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterWaveRTTopologySet, TopologyPropertyHandler); +DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterWaveRTPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler); + +KSPROPERTY_SET WaveRTPropertySet[] = +{ + { + &KSPROPSETID_Topology, + sizeof(PortFilterWaveRTTopologySet) / sizeof(KSPROPERTY_ITEM), + (const KSPROPERTY_ITEM*)&PortFilterWaveRTTopologySet, + 0, + NULL + }, + { + &KSPROPSETID_Pin, + sizeof(PortFilterWaveRTPinSet) / sizeof(KSPROPERTY_ITEM), + (const KSPROPERTY_ITEM*)&PortFilterWaveRTPinSet, + 0, + NULL + } +}; + +//KSEVENTSETID_LoopedStreaming, Type = KSEVENT_LOOPEDSTREAMING_POSITION +//KSEVENTSETID_Connection, Type = KSEVENT_CONNECTION_ENDOFSTREAM, + + + +#if 0 +static const KSIDENTIFIER Identifiers[] = +{ + { + &KSINTERFACESETID_Standard, + 0, + 0 + }, + { + &KSINTERFACESETID_Standard, + 1, + 0 + } +}; +#endif + +//--------------------------------------------------------------- +// IPortEvents +// + +static +NTSTATUS +NTAPI +IPortEvents_fnQueryInterface( + IPortEvents* iface, + IN REFIID refiid, + OUT PVOID* Output) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblPortEvents); + + DPRINT("IPortEvents_fnQueryInterface entered\n"); + + if (IsEqualGUIDAligned(refiid, &IID_IPortEvents) || + IsEqualGUIDAligned(refiid, &IID_IUnknown)) + { + *Output = &This->lpVbtlPortEvents; + InterlockedIncrement(&This->ref); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + +static +ULONG +NTAPI +IPortEvents_fnAddRef( + IPortEvents* iface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblPortEvents); + DPRINT("IPortEvents_fnQueryInterface entered\n"); + return InterlockedIncrement(&This->ref); +} + +static +ULONG +NTAPI +IPortEvents_fnRelease( + IPortEvents* iface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblPortEvents); + + DPRINT("IPortEvents_fnRelease entered\n"); + InterlockedDecrement(&This->ref); + + if (This->ref == 0) + { + FreeItem(This, TAG_PORTCLASS); + return 0; + } + /* Return new reference count */ + return This->ref; +} + +static +void +NTAPI +IPortEvents_fnAddEventToEventList( + IPortEvents* iface, + IN PKSEVENT_ENTRY EventEntry) +{ + UNIMPLEMENTED +} + + +static +void +NTAPI +IPortEvents_fnGenerateEventList( + IPortEvents* iface, + IN GUID* Set OPTIONAL, + IN ULONG EventId, + IN BOOL PinEvent, + IN ULONG PinId, + IN BOOL NodeEvent, + IN ULONG NodeId) +{ + UNIMPLEMENTED +} + +static IPortEventsVtbl vt_IPortEvents = +{ + IPortEvents_fnQueryInterface, + IPortEvents_fnAddRef, + IPortEvents_fnRelease, + IPortEvents_fnAddEventToEventList, + IPortEvents_fnGenerateEventList +}; + +//--------------------------------------------------------------- +// IUnknown interface functions +// + +NTSTATUS +NTAPI +IPortWaveRT_fnQueryInterface( + IPortWaveRT* iface, + IN REFIID refiid, + OUT PVOID* Output) +{ + UNICODE_STRING GuidString; + IPortWaveRTImpl * This = (IPortWaveRTImpl*)iface; + + if (IsEqualGUIDAligned(refiid, &IID_IPortWaveRT) || + IsEqualGUIDAligned(refiid, &IID_IUnknown)) + { + *Output = &This->lpVtbl; + InterlockedIncrement(&This->ref); + return STATUS_SUCCESS; + } + else if (IsEqualGUIDAligned(refiid, &IID_IPortEvents)) + { + *Output = &This->lpVtblPortEvents; + InterlockedIncrement(&This->ref); + return STATUS_SUCCESS; + } + else if (IsEqualGUIDAligned(refiid, &IID_ISubdevice)) + { + *Output = &This->lpVtblSubDevice; + InterlockedIncrement(&This->ref); + return STATUS_SUCCESS; + } + else if (IsEqualGUIDAligned(refiid, &IID_IPortClsVersion)) + { + return NewPortClsVersion((PPORTCLSVERSION*)Output); + } + else if (IsEqualGUIDAligned(refiid, &IID_IDrmPort) || + IsEqualGUIDAligned(refiid, &IID_IDrmPort2)) + { + return NewIDrmPort((PDRMPORT2*)Output); + } + + if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS) + { + DPRINT1("IPortWaveRT_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer); + RtlFreeUnicodeString(&GuidString); + } + + return STATUS_UNSUCCESSFUL; +} + +ULONG +NTAPI +IPortWaveRT_fnAddRef( + IPortWaveRT* iface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)iface; + + return InterlockedIncrement(&This->ref); +} + +ULONG +NTAPI +IPortWaveRT_fnRelease( + IPortWaveRT* iface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)iface; + + InterlockedDecrement(&This->ref); + + if (This->ref == 0) + { + if (This->bInitialized) + { + This->pMiniport->lpVtbl->Release(This->pMiniport); + } + if (This->pPinCount) + This->pPinCount->lpVtbl->Release(This->pPinCount); + + if (This->pPowerNotify) + This->pPowerNotify->lpVtbl->Release(This->pPowerNotify); + + FreeItem(This, TAG_PORTCLASS); + return 0; + } + /* Return new reference count */ + return This->ref; +} + + +//--------------------------------------------------------------- +// IPort interface functions +// + +NTSTATUS +NTAPI +IPortWaveRT_fnGetDeviceProperty( + IN IPortWaveRT * iface, + IN DEVICE_REGISTRY_PROPERTY DeviceRegistryProperty, + IN ULONG BufferLength, + OUT PVOID PropertyBuffer, + OUT PULONG ReturnLength) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)iface; + ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); + + if (!This->bInitialized) + { + DPRINT("IPortWaveRT_fnNewRegistryKey called w/o initiazed\n"); + return STATUS_UNSUCCESSFUL; + } + + return IoGetDeviceProperty(This->pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength); +} + +NTSTATUS +NTAPI +IPortWaveRT_fnInit( + IN IPortWaveRT * iface, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PUNKNOWN UnknownMiniport, + IN PUNKNOWN UnknownAdapter OPTIONAL, + IN PRESOURCELIST ResourceList) +{ + IMiniportWaveRT * Miniport; + NTSTATUS Status; + PPINCOUNT PinCount; + PPOWERNOTIFY PowerNotify; + IPortWaveRTImpl * This = (IPortWaveRTImpl*)iface; + + DPRINT("IPortWaveRT_Init entered %p\n", This); + ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); + + if (This->bInitialized) + { + DPRINT("IPortWaveRT_Init called again\n"); + return STATUS_SUCCESS; + } + + Status = UnknownMiniport->lpVtbl->QueryInterface(UnknownMiniport, &IID_IMiniportWaveRT, (PVOID*)&Miniport); + if (!NT_SUCCESS(Status)) + { + DPRINT("IPortWaveRT_Init called with invalid IMiniport adapter\n"); + return STATUS_INVALID_PARAMETER; + } + + /* Initialize port object */ + This->pMiniport = Miniport; + This->pDeviceObject = DeviceObject; + This->bInitialized = TRUE; + This->pResourceList = ResourceList; + + /* increment reference on miniport adapter */ + Miniport->lpVtbl->AddRef(Miniport); + + Status = Miniport->lpVtbl->Init(Miniport, UnknownAdapter, ResourceList, iface); + if (!NT_SUCCESS(Status)) + { + DPRINT("IMiniportWaveRT_Init failed with %x\n", Status); + Miniport->lpVtbl->Release(Miniport); + This->bInitialized = FALSE; + return Status; + } + + + /* get the miniport device descriptor */ + Status = Miniport->lpVtbl->GetDescription(Miniport, &This->pDescriptor); + if (!NT_SUCCESS(Status)) + { + DPRINT1("failed to get description\n"); + Miniport->lpVtbl->Release(Miniport); + This->bInitialized = FALSE; + return Status; + } + + /* create the subdevice descriptor */ + Status = PcCreateSubdeviceDescriptor(&This->SubDeviceDescriptor, + 3, + InterfaceGuids, + 0, + NULL, + 2, + WaveRTPropertySet, + 0, + 0, + 0, + NULL, + 0, + NULL, + This->pDescriptor); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("PcCreateSubdeviceDescriptor failed with %x\n", Status); + Miniport->lpVtbl->Release(Miniport); + This->bInitialized = FALSE; + return Status; + } + + /* check if it supports IPinCount interface */ + Status = UnknownMiniport->lpVtbl->QueryInterface(UnknownMiniport, &IID_IPinCount, (PVOID*)&PinCount); + if (NT_SUCCESS(Status)) + { + /* store IPinCount interface */ + This->pPinCount = PinCount; + } + + /* does the Miniport adapter support IPowerNotify interface*/ + Status = UnknownMiniport->lpVtbl->QueryInterface(UnknownMiniport, &IID_IPowerNotify, (PVOID*)&PowerNotify); + if (NT_SUCCESS(Status)) + { + /* store reference */ + This->pPowerNotify = PowerNotify; + } + + /* increment reference on resource list */ + ResourceList->lpVtbl->AddRef(ResourceList); + + + DPRINT("IPortWaveRT successfully initialized\n"); + return STATUS_SUCCESS; +} + + +NTSTATUS +NTAPI +IPortWaveRT_fnNewRegistryKey( + IN IPortWaveRT * iface, + OUT PREGISTRYKEY *OutRegistryKey, + IN PUNKNOWN OuterUnknown OPTIONAL, + IN ULONG RegistryKeyType, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN ULONG CreateOptions OPTIONAL, + OUT PULONG Disposition OPTIONAL) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)iface; + + ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); + + if (!This->bInitialized) + { + DPRINT("IPortWaveRT_fnNewRegistryKey called w/o initialized\n"); + return STATUS_UNSUCCESSFUL; + } + return PcNewRegistryKey(OutRegistryKey, OuterUnknown, RegistryKeyType, DesiredAccess, This->pDeviceObject, NULL /*FIXME*/, ObjectAttributes, CreateOptions, Disposition); +} + +static IPortWaveRTVtbl vt_IPortWaveRTVtbl = +{ + IPortWaveRT_fnQueryInterface, + IPortWaveRT_fnAddRef, + IPortWaveRT_fnRelease, + IPortWaveRT_fnInit, + IPortWaveRT_fnGetDeviceProperty, + IPortWaveRT_fnNewRegistryKey +}; + +//--------------------------------------------------------------- +// ISubdevice interface +// + +static +NTSTATUS +NTAPI +ISubDevice_fnQueryInterface( + IN ISubdevice *iface, + IN REFIID InterfaceId, + IN PVOID* Interface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + return IPortWaveRT_fnQueryInterface((IPortWaveRT*)This, InterfaceId, Interface); +} + +static +ULONG +NTAPI +ISubDevice_fnAddRef( + IN ISubdevice *iface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + return IPortWaveRT_fnAddRef((IPortWaveRT*)This); +} + +static +ULONG +NTAPI +ISubDevice_fnRelease( + IN ISubdevice *iface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + return IPortWaveRT_fnRelease((IPortWaveRT*)This); +} + +static +NTSTATUS +NTAPI +ISubDevice_fnNewIrpTarget( + IN ISubdevice *iface, + OUT struct IIrpTarget **OutTarget, + IN WCHAR * Name, + IN PUNKNOWN Unknown, + IN POOL_TYPE PoolType, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN KSOBJECT_CREATE *CreateObject) +{ + NTSTATUS Status; + IPortFilterWaveRT * Filter; + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + DPRINT("ISubDevice_NewIrpTarget this %p\n", This); + + if (This->Filter) + { + *OutTarget = (IIrpTarget*)This->Filter; + return STATUS_SUCCESS; + } + + + Status = NewPortFilterWaveRT(&Filter); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = Filter->lpVtbl->Init(Filter, (IPortWaveRT*)This); + if (!NT_SUCCESS(Status)) + { + Filter->lpVtbl->Release(Filter); + return Status; + } + + *OutTarget = (IIrpTarget*)Filter; + return Status; +} + +static +NTSTATUS +NTAPI +ISubDevice_fnReleaseChildren( + IN ISubdevice *iface) +{ + //IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + UNIMPLEMENTED + return STATUS_UNSUCCESSFUL; +} + +static +NTSTATUS +NTAPI +ISubDevice_fnGetDescriptor( + IN ISubdevice *iface, + IN SUBDEVICE_DESCRIPTOR ** Descriptor) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + ASSERT(This->SubDeviceDescriptor != NULL); + + *Descriptor = This->SubDeviceDescriptor; + + DPRINT("ISubDevice_GetDescriptor this %p desc %p\n", This, This->SubDeviceDescriptor); + return STATUS_SUCCESS; +} + +static +NTSTATUS +NTAPI +ISubDevice_fnDataRangeIntersection( + IN ISubdevice *iface, + IN ULONG PinId, + IN PKSDATARANGE DataRange, + IN PKSDATARANGE MatchingDataRange, + IN ULONG OutputBufferLength, + OUT PVOID ResultantFormat OPTIONAL, + OUT PULONG ResultantFormatLength) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + DPRINT("ISubDevice_DataRangeIntersection this %p\n", This); + + if (This->pMiniport) + { + return This->pMiniport->lpVtbl->DataRangeIntersection (This->pMiniport, PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength); + } + + return STATUS_UNSUCCESSFUL; +} + +static +NTSTATUS +NTAPI +ISubDevice_fnPowerChangeNotify( + IN ISubdevice *iface, + IN POWER_STATE PowerState) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + if (This->pPowerNotify) + { + This->pPowerNotify->lpVtbl->PowerChangeNotify(This->pPowerNotify, PowerState); + } + + return STATUS_SUCCESS; +} + +static +NTSTATUS +NTAPI +ISubDevice_fnPinCount( + IN ISubdevice *iface, + IN ULONG PinId, + IN OUT PULONG FilterNecessary, + IN OUT PULONG FilterCurrent, + IN OUT PULONG FilterPossible, + IN OUT PULONG GlobalCurrent, + IN OUT PULONG GlobalPossible) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl*)CONTAINING_RECORD(iface, IPortWaveRTImpl, lpVtblSubDevice); + + if (This->pPinCount) + { + This->pPinCount->lpVtbl->PinCount(This->pPinCount, PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible); + return STATUS_SUCCESS; + } + + /* FIXME + * scan filter descriptor + */ + return STATUS_UNSUCCESSFUL; +} + +static ISubdeviceVtbl vt_ISubdeviceVtbl = +{ + ISubDevice_fnQueryInterface, + ISubDevice_fnAddRef, + ISubDevice_fnRelease, + ISubDevice_fnNewIrpTarget, + ISubDevice_fnReleaseChildren, + ISubDevice_fnGetDescriptor, + ISubDevice_fnDataRangeIntersection, + ISubDevice_fnPowerChangeNotify, + ISubDevice_fnPinCount +}; + + +///-------------------------------------------------------------- +PMINIPORTWAVERT +GetWaveRTMiniport( + IN IPortWaveRT* iface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl *)iface; + return This->pMiniport; +} + +PDEVICE_OBJECT +GetDeviceObjectFromPortWaveRT( + PPORTWAVERT iface) +{ + IPortWaveRTImpl * This = (IPortWaveRTImpl *)iface; + return This->pDeviceObject; +} + +//--------------------------------------------------------------- +// IPortWaveRT constructor +// + +NTSTATUS +NewPortWaveRT( + OUT PPORT* OutPort) +{ + IPortWaveRTImpl * This; + + This = AllocateItem(NonPagedPool, sizeof(IPortWaveRTImpl), TAG_PORTCLASS); + if (!This) + return STATUS_INSUFFICIENT_RESOURCES; + + This->lpVtbl = &vt_IPortWaveRTVtbl; + This->lpVtblSubDevice = &vt_ISubdeviceVtbl; + This->lpVtblPortEvents = &vt_IPortEvents; + This->ref = 1; + *OutPort = (PPORT)(&This->lpVtbl); + + DPRINT("NewPortWaveRT %p\n", *OutPort); + + return STATUS_SUCCESS; +} + diff --git a/reactos/drivers/wdm/audio/backpln/portcls/port_wavertstream.c b/reactos/drivers/wdm/audio/backpln/portcls/port_wavertstream.c new file mode 100644 index 00000000000..f9ebafba17d --- /dev/null +++ b/reactos/drivers/wdm/audio/backpln/portcls/port_wavertstream.c @@ -0,0 +1,247 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: drivers/wdm/audio/backpln/portcls/port_wavertstream.c + * PURPOSE: WaveRTStream helper object + * PROGRAMMER: Johannes Anderwald + */ + +#include "private.h" + +typedef struct +{ + IPortWaveRTStreamVtbl *lpVtbl; + LONG ref; + +}IPortWaveRTStreamImpl; + +/* + * @implemented + */ +static +NTSTATUS +NTAPI +IPortWaveRTStream_fnQueryInterface( + IPortWaveRTStream* iface, + IN REFIID refiid, + OUT PVOID* Output) +{ + IPortWaveRTStreamImpl * This = (IPortWaveRTStreamImpl*)iface; + + DPRINT("IPortWaveRTStream_fnQueryInterface entered\n"); + + if (IsEqualGUIDAligned(refiid, &IID_IPortWaveRTStream) || + IsEqualGUIDAligned(refiid, &IID_IUnknown)) + { + *Output = &This->lpVtbl; + InterlockedIncrement(&This->ref); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + +/* + * @implemented + */ +static +ULONG +NTAPI +IPortWaveRTStream_fnAddRef( + IPortWaveRTStream* iface) +{ + IPortWaveRTStreamImpl * This = (IPortWaveRTStreamImpl*)iface; + DPRINT("IPortWaveRTStream_fnAddRef entered\n"); + + return InterlockedIncrement(&This->ref); +} + +/* + * @implemented + */ +static +ULONG +NTAPI +IPortWaveRTStream_fnRelease( + IPortWaveRTStream* iface) +{ + IPortWaveRTStreamImpl * This = (IPortWaveRTStreamImpl*)iface; + + InterlockedDecrement(&This->ref); + + DPRINT("IPortWaveRTStream_fnRelease entered %u\n", This->ref); + + if (This->ref == 0) + { + FreeItem(This, TAG_PORTCLASS); + return 0; + } + /* Return new reference count */ + return This->ref; +} + +/* + * @implemented + */ +static +PMDL +NTAPI +IPortWaveRTStream_fnAllocatePagesForMdl( + IN IPortWaveRTStream* iface, + IN PHYSICAL_ADDRESS HighAddress, + IN SIZE_T TotalBytes) +{ + return MmAllocatePagesForMdl(RtlConvertUlongToLargeInteger(0), HighAddress, RtlConvertUlongToLargeInteger(0), TotalBytes); +} + +/* + * @implemented + */ +static +PMDL +NTAPI +IPortWaveRTStream_fnAllocateContiguousPagesForMdl( + IN IPortWaveRTStream* iface, + IN PHYSICAL_ADDRESS LowAddress, + IN PHYSICAL_ADDRESS HighAddress, + IN SIZE_T TotalBytes) +{ + PMDL Mdl; + PVOID Buffer; + PHYSICAL_ADDRESS Address; + + Buffer = MmAllocateContiguousMemorySpecifyCache(TotalBytes, LowAddress, HighAddress, RtlConvertUlongToLargeInteger(0), MmNonCached); + if (!Buffer) + { + DPRINT1("MmAllocateContiguousMemorySpecifyCache failed\n"); + return NULL; + } + + Address = MmGetPhysicalAddress(Buffer); + + MmFreeContiguousMemorySpecifyCache(Buffer, TotalBytes, MmNonCached); + + Mdl = MmAllocatePagesForMdl(Address, HighAddress, RtlConvertUlongToLargeInteger(0), TotalBytes); + if (!Mdl) + { + DPRINT1("MmAllocatePagesForMdl failed\n"); + return NULL; + } + + if (MmGetMdlByteCount(Mdl) < TotalBytes) + { + MmFreePagesFromMdl(Mdl); + ExFreePool(Mdl); + return NULL; + } + + return NULL; +} + +/* + * @implemented + */ +static +PVOID +NTAPI +IPortWaveRTStream_fnMapAllocatedPages( + IN IPortWaveRTStream* iface, + IN PMDL MemoryDescriptorList, + IN MEMORY_CACHING_TYPE CacheType) +{ + return MmMapLockedPagesSpecifyCache(MemoryDescriptorList, KernelMode, CacheType, NULL, 0, NormalPagePriority); +} + +/* + * @implemented + */ +static +VOID +NTAPI +IPortWaveRTStream_fnUnmapAllocatedPages( + IN IPortWaveRTStream* iface, + IN PVOID BaseAddress, + IN PMDL MemoryDescriptorList) +{ + MmUnmapLockedPages(BaseAddress, MemoryDescriptorList); +} + +/* + * @implemented + */ +static +VOID +NTAPI +IPortWaveRTStream_fnFreePagesFromMdl( + IN IPortWaveRTStream* iface, + IN PMDL MemoryDescriptorList) +{ + MmFreePagesFromMdl(MemoryDescriptorList); + ExFreePool(MemoryDescriptorList); +} + +/* + * @implemented + */ +static +ULONG +NTAPI +IPortWaveRTStream_fnGetPhysicalPagesCount( + IN IPortWaveRTStream* iface, + IN PMDL MemoryDescriptorList) +{ + return ADDRESS_AND_SIZE_TO_SPAN_PAGES(0, MmGetMdlByteCount(MemoryDescriptorList)); +} + +/* + * @implemented + */ +static +PHYSICAL_ADDRESS +NTAPI +IPortWaveRTStream_fnGetPhysicalPageAddress( + IN IPortWaveRTStream* iface, + IN PMDL MemoryDescriptorList, + IN ULONG Index) +{ + PVOID Buffer; + ULONG Pages; + + Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(0, MmGetMdlByteCount(MemoryDescriptorList)); + if (Pages <= Index) + { + DPRINT1("OutOfBounds: Pages %u Index %u\n", Pages, Index); + return RtlConvertUlongToLargeInteger(0); + } + + Buffer = UlongToPtr(PtrToUlong(MmGetSystemAddressForMdl(MemoryDescriptorList)) + Index * PAGE_SIZE); + return MmGetPhysicalAddress(Buffer); +} + +static IPortWaveRTStreamVtbl vt_PortWaveRTStream = +{ + IPortWaveRTStream_fnQueryInterface, + IPortWaveRTStream_fnAddRef, + IPortWaveRTStream_fnRelease, + IPortWaveRTStream_fnAllocatePagesForMdl, + IPortWaveRTStream_fnAllocateContiguousPagesForMdl, + IPortWaveRTStream_fnMapAllocatedPages, + IPortWaveRTStream_fnUnmapAllocatedPages, + IPortWaveRTStream_fnFreePagesFromMdl, + IPortWaveRTStream_fnGetPhysicalPagesCount, + IPortWaveRTStream_fnGetPhysicalPageAddress +}; + +NTSTATUS +NewPortWaveRTStream( + PPORTWAVERTSTREAM *OutStream) +{ + IPortWaveRTStreamImpl* This = AllocateItem(NonPagedPool, sizeof(IPortWaveRTStreamImpl), TAG_PORTCLASS); + if (!This) + return STATUS_INSUFFICIENT_RESOURCES; + + This->ref = 1; + This->lpVtbl = &vt_PortWaveRTStream; + + *OutStream = (PPORTWAVERTSTREAM)&This->lpVtbl; + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/wdm/audio/backpln/portcls/private.h b/reactos/drivers/wdm/audio/backpln/portcls/private.h index 6399d28ecc2..c974c740446 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/private.h +++ b/reactos/drivers/wdm/audio/backpln/portcls/private.h @@ -109,6 +109,25 @@ PMINIPORTWAVEPCI GetWavePciMiniport( PPORTWAVEPCI Port); +NTSTATUS +NewPortFilterWaveRT( + OUT IPortFilterWaveRT ** OutFilter); + +NTSTATUS NewPortPinWaveRT( + OUT IPortPinWaveRT ** OutPin); + +PMINIPORTWAVERT +GetWaveRTMiniport( + IN IPortWaveRT* iface); + +PDEVICE_OBJECT +GetDeviceObjectFromPortWaveRT( + IPortWaveRT* iface); + +NTSTATUS +NewPortWaveRTStream( + PPORTWAVERTSTREAM *OutStream); + NTSTATUS NTAPI NewDispatchObject(