715 lines
15 KiB
C++
715 lines
15 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1997-2000 Microsoft Corporation All Rights Reserved
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
minwave.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Implementation of wavecyclic miniport.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <msvad.h>
|
||
|
#include <common.h>
|
||
|
#include "simple.h"
|
||
|
#include "minwave.h"
|
||
|
#include "wavtable.h"
|
||
|
|
||
|
#pragma code_seg("PAGE")
|
||
|
|
||
|
//=============================================================================
|
||
|
// CMiniportWaveCyclic
|
||
|
//=============================================================================
|
||
|
|
||
|
//=============================================================================
|
||
|
NTSTATUS
|
||
|
CreateMiniportWaveCyclicMSVAD
|
||
|
(
|
||
|
OUT PUNKNOWN * Unknown,
|
||
|
IN REFCLSID,
|
||
|
IN PUNKNOWN UnknownOuter OPTIONAL,
|
||
|
IN POOL_TYPE PoolType
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Create the wavecyclic miniport.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Unknown -
|
||
|
|
||
|
RefClsId -
|
||
|
|
||
|
UnknownOuter -
|
||
|
|
||
|
PoolType -
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(Unknown);
|
||
|
|
||
|
STD_CREATE_BODY(CMiniportWaveCyclic, Unknown, UnknownOuter, PoolType);
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
CMiniportWaveCyclic::~CMiniportWaveCyclic
|
||
|
(
|
||
|
void
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Destructor for wavecyclic miniport
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
DPF_ENTER(("[CMiniportWaveCyclic::~CMiniportWaveCyclic]"));
|
||
|
} // ~CMiniportWaveCyclic
|
||
|
|
||
|
|
||
|
//=============================================================================
|
||
|
STDMETHODIMP_(NTSTATUS)
|
||
|
CMiniportWaveCyclic::DataRangeIntersection
|
||
|
(
|
||
|
IN ULONG PinId,
|
||
|
IN PKSDATARANGE ClientDataRange,
|
||
|
IN PKSDATARANGE MyDataRange,
|
||
|
IN ULONG OutputBufferLength,
|
||
|
OUT PVOID ResultantFormat,
|
||
|
OUT PULONG ResultantFormatLength
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The DataRangeIntersection function determines the highest quality
|
||
|
intersection of two data ranges.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PinId - Pin for which data intersection is being determined.
|
||
|
|
||
|
ClientDataRange - Pointer to KSDATARANGE structure which contains the data
|
||
|
range submitted by client in the data range intersection
|
||
|
property request.
|
||
|
|
||
|
MyDataRange - Pin's data range to be compared with client's data
|
||
|
range. In this case we actually ignore our own data
|
||
|
range, because we know that we only support one range.
|
||
|
|
||
|
OutputBufferLength - Size of the buffer pointed to by the resultant format
|
||
|
parameter.
|
||
|
|
||
|
ResultantFormat - Pointer to value where the resultant format should be
|
||
|
returned.
|
||
|
|
||
|
ResultantFormatLength - Actual length of the resultant format placed in
|
||
|
ResultantFormat. This should be less than or equal
|
||
|
to OutputBufferLength.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
// This driver only supports PCM formats.
|
||
|
// Portcls will handle the request for us.
|
||
|
//
|
||
|
|
||
|
return STATUS_NOT_IMPLEMENTED;
|
||
|
} // DataRangeIntersection
|
||
|
|
||
|
//=============================================================================
|
||
|
STDMETHODIMP_(NTSTATUS)
|
||
|
CMiniportWaveCyclic::GetDescription
|
||
|
(
|
||
|
OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The GetDescription function gets a pointer to a filter description.
|
||
|
It provides a location to deposit a pointer in miniport's description
|
||
|
structure. This is the placeholder for the FromNode or ToNode fields in
|
||
|
connections which describe connections to the filter's pins.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
OutFilterDescriptor - Pointer to the filter description.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(OutFilterDescriptor);
|
||
|
|
||
|
return
|
||
|
CMiniportWaveCyclicMSVAD::GetDescription(OutFilterDescriptor);
|
||
|
} // GetDescription
|
||
|
|
||
|
//=============================================================================
|
||
|
STDMETHODIMP_(NTSTATUS)
|
||
|
CMiniportWaveCyclic::Init
|
||
|
(
|
||
|
IN PUNKNOWN UnknownAdapter_,
|
||
|
IN PRESOURCELIST ResourceList_,
|
||
|
IN PPORTWAVECYCLIC Port_
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The Init function initializes the miniport. Callers of this function
|
||
|
should run at IRQL PASSIVE_LEVEL
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
|
||
|
|
||
|
ResourceList - Pointer to the resource list to be supplied to the miniport
|
||
|
during initialization. The port driver is free to examine the
|
||
|
contents of the ResourceList. The port driver will not be
|
||
|
modify the ResourceList contents.
|
||
|
|
||
|
Port - Pointer to the topology port object that is linked with this miniport.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(UnknownAdapter_);
|
||
|
ASSERT(Port_);
|
||
|
|
||
|
NTSTATUS ntStatus;
|
||
|
|
||
|
DPF_ENTER(("[CMiniportWaveCyclic::Init]"));
|
||
|
|
||
|
m_MaxOutputStreams = MAX_OUTPUT_STREAMS;
|
||
|
m_MaxInputStreams = MAX_INPUT_STREAMS;
|
||
|
m_MaxTotalStreams = MAX_TOTAL_STREAMS;
|
||
|
|
||
|
m_MinChannels = MIN_CHANNELS;
|
||
|
m_MaxChannelsPcm = MAX_CHANNELS_PCM;
|
||
|
|
||
|
m_MinBitsPerSamplePcm = MIN_BITS_PER_SAMPLE_PCM;
|
||
|
m_MaxBitsPerSamplePcm = MAX_BITS_PER_SAMPLE_PCM;
|
||
|
m_MinSampleRatePcm = MIN_SAMPLE_RATE;
|
||
|
m_MaxSampleRatePcm = MAX_SAMPLE_RATE;
|
||
|
|
||
|
ntStatus =
|
||
|
CMiniportWaveCyclicMSVAD::Init
|
||
|
(
|
||
|
UnknownAdapter_,
|
||
|
ResourceList_,
|
||
|
Port_
|
||
|
);
|
||
|
if (NT_SUCCESS(ntStatus))
|
||
|
{
|
||
|
// Set filter descriptor.
|
||
|
m_FilterDescriptor = &MiniportFilterDescriptor;
|
||
|
|
||
|
m_fCaptureAllocated = FALSE;
|
||
|
m_fRenderAllocated = FALSE;
|
||
|
}
|
||
|
|
||
|
return ntStatus;
|
||
|
} // Init
|
||
|
|
||
|
//=============================================================================
|
||
|
STDMETHODIMP_(NTSTATUS)
|
||
|
CMiniportWaveCyclic::NewStream
|
||
|
(
|
||
|
OUT PMINIPORTWAVECYCLICSTREAM * OutStream,
|
||
|
IN PUNKNOWN OuterUnknown,
|
||
|
IN POOL_TYPE PoolType,
|
||
|
IN ULONG Pin,
|
||
|
IN BOOLEAN Capture,
|
||
|
IN PKSDATAFORMAT DataFormat,
|
||
|
OUT PDMACHANNEL * OutDmaChannel,
|
||
|
OUT PSERVICEGROUP * OutServiceGroup
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The NewStream function creates a new instance of a logical stream
|
||
|
associated with a specified physical channel. Callers of NewStream should
|
||
|
run at IRQL PASSIVE_LEVEL.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
OutStream -
|
||
|
|
||
|
OuterUnknown -
|
||
|
|
||
|
PoolType -
|
||
|
|
||
|
Pin -
|
||
|
|
||
|
Capture -
|
||
|
|
||
|
DataFormat -
|
||
|
|
||
|
OutDmaChannel -
|
||
|
|
||
|
OutServiceGroup -
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(OutStream);
|
||
|
ASSERT(DataFormat);
|
||
|
ASSERT(OutDmaChannel);
|
||
|
ASSERT(OutServiceGroup);
|
||
|
|
||
|
DPF_ENTER(("[CMiniportWaveCyclic::NewStream]"));
|
||
|
|
||
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||
|
PCMiniportWaveCyclicStream stream = NULL;
|
||
|
|
||
|
// Check if we have enough streams.
|
||
|
if (Capture)
|
||
|
{
|
||
|
if (m_fCaptureAllocated)
|
||
|
{
|
||
|
DPF(D_TERSE, ("[Only one capture stream supported]"));
|
||
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (m_fRenderAllocated)
|
||
|
{
|
||
|
DPF(D_TERSE, ("[Only one render stream supported]"));
|
||
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Determine if the format is valid.
|
||
|
//
|
||
|
if (NT_SUCCESS(ntStatus))
|
||
|
{
|
||
|
ntStatus = ValidateFormat(DataFormat);
|
||
|
}
|
||
|
|
||
|
// Instantiate a stream. Stream must be in
|
||
|
// NonPagedPool because of file saving.
|
||
|
//
|
||
|
if (NT_SUCCESS(ntStatus))
|
||
|
{
|
||
|
stream = new (NonPagedPool, MSVAD_POOLTAG)
|
||
|
CMiniportWaveCyclicStream(OuterUnknown);
|
||
|
|
||
|
if (stream)
|
||
|
{
|
||
|
stream->AddRef();
|
||
|
|
||
|
ntStatus =
|
||
|
stream->Init
|
||
|
(
|
||
|
this,
|
||
|
Pin,
|
||
|
Capture,
|
||
|
DataFormat
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NT_SUCCESS(ntStatus))
|
||
|
{
|
||
|
if (Capture)
|
||
|
{
|
||
|
m_fCaptureAllocated = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_fRenderAllocated = TRUE;
|
||
|
}
|
||
|
|
||
|
*OutStream = PMINIPORTWAVECYCLICSTREAM(stream);
|
||
|
(*OutStream)->AddRef();
|
||
|
|
||
|
*OutDmaChannel = PDMACHANNEL(stream);
|
||
|
(*OutDmaChannel)->AddRef();
|
||
|
|
||
|
*OutServiceGroup = m_ServiceGroup;
|
||
|
(*OutServiceGroup)->AddRef();
|
||
|
|
||
|
// The stream, the DMA channel, and the service group have
|
||
|
// references now for the caller. The caller expects these
|
||
|
// references to be there.
|
||
|
}
|
||
|
|
||
|
// This is our private reference to the stream. The caller has
|
||
|
// its own, so we can release in any case.
|
||
|
//
|
||
|
if (stream)
|
||
|
{
|
||
|
stream->Release();
|
||
|
}
|
||
|
|
||
|
return ntStatus;
|
||
|
} // NewStream
|
||
|
|
||
|
//=============================================================================
|
||
|
STDMETHODIMP_(NTSTATUS)
|
||
|
CMiniportWaveCyclic::NonDelegatingQueryInterface
|
||
|
(
|
||
|
IN REFIID Interface,
|
||
|
OUT PVOID * Object
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
QueryInterface
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Interface - GUID
|
||
|
|
||
|
Object - interface pointer to be returned.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(Object);
|
||
|
|
||
|
if (IsEqualGUIDAligned(Interface, IID_IUnknown))
|
||
|
{
|
||
|
*Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLIC(this)));
|
||
|
}
|
||
|
else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
|
||
|
{
|
||
|
*Object = PVOID(PMINIPORT(this));
|
||
|
}
|
||
|
else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclic))
|
||
|
{
|
||
|
*Object = PVOID(PMINIPORTWAVECYCLIC(this));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*Object = NULL;
|
||
|
}
|
||
|
|
||
|
if (*Object)
|
||
|
{
|
||
|
// We reference the interface for the caller.
|
||
|
|
||
|
PUNKNOWN(*Object)->AddRef();
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
} // NonDelegatingQueryInterface
|
||
|
|
||
|
//=============================================================================
|
||
|
NTSTATUS
|
||
|
CMiniportWaveCyclic::PropertyHandlerComponentId
|
||
|
(
|
||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Handles KSPROPERTY_GENERAL_COMPONENTID
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PropertyRequest -
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
DPF_ENTER(("[PropertyHandlerComponentId]"));
|
||
|
|
||
|
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
|
||
|
if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
|
||
|
{
|
||
|
ntStatus =
|
||
|
PropertyHandler_BasicSupport
|
||
|
(
|
||
|
PropertyRequest,
|
||
|
KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
|
||
|
VT_ILLEGAL
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ntStatus =
|
||
|
ValidatePropertyParams
|
||
|
(
|
||
|
PropertyRequest,
|
||
|
sizeof(KSCOMPONENTID),
|
||
|
0
|
||
|
);
|
||
|
if (NT_SUCCESS(ntStatus))
|
||
|
{
|
||
|
if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
|
||
|
{
|
||
|
PKSCOMPONENTID pComponentId = (PKSCOMPONENTID)
|
||
|
PropertyRequest->Value;
|
||
|
|
||
|
INIT_MMREG_MID(&pComponentId->Manufacturer, MM_MICROSOFT);
|
||
|
pComponentId->Product = PID_MSVAD;
|
||
|
pComponentId->Name = NAME_MSVAD_SIMPLE;
|
||
|
pComponentId->Component = GUID_NULL; // Not used for extended caps.
|
||
|
pComponentId->Version = MSVAD_VERSION;
|
||
|
pComponentId->Revision = MSVAD_REVISION;
|
||
|
|
||
|
PropertyRequest->ValueSize = sizeof(KSCOMPONENTID);
|
||
|
ntStatus = STATUS_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF(D_TERSE, ("[PropertyHandlerComponentId - Invalid parameter]"));
|
||
|
ntStatus = STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ntStatus;
|
||
|
} // PropertyHandlerComponentId
|
||
|
|
||
|
//=============================================================================
|
||
|
NTSTATUS
|
||
|
PropertyHandler_WaveFilter
|
||
|
(
|
||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Redirects general property request to miniport object
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PropertyRequest -
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
PCMiniportWaveCyclic pWave =
|
||
|
(PCMiniportWaveCyclic) PropertyRequest->MajorTarget;
|
||
|
|
||
|
switch (PropertyRequest->PropertyItem->Id)
|
||
|
{
|
||
|
case KSPROPERTY_GENERAL_COMPONENTID:
|
||
|
ntStatus =
|
||
|
pWave->PropertyHandlerComponentId
|
||
|
(
|
||
|
PropertyRequest
|
||
|
);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DPF(D_TERSE, ("[PropertyHandler_WaveFilter: Invalid Device Request]"));
|
||
|
}
|
||
|
|
||
|
return ntStatus;
|
||
|
} // PropertyHandler_WaveFilter
|
||
|
|
||
|
//=============================================================================
|
||
|
// CMiniportWaveStreamCyclicSimple
|
||
|
//=============================================================================
|
||
|
|
||
|
//=============================================================================
|
||
|
CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream
|
||
|
(
|
||
|
void
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Destructor for wavecyclicstream
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
DPF_ENTER(("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]"));
|
||
|
|
||
|
if (NULL != m_pMiniportLocal)
|
||
|
{
|
||
|
if (m_fCapture)
|
||
|
{
|
||
|
m_pMiniportLocal->m_fCaptureAllocated = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_pMiniportLocal->m_fRenderAllocated = FALSE;
|
||
|
}
|
||
|
}
|
||
|
} // ~CMiniportWaveCyclicStream
|
||
|
|
||
|
//=============================================================================
|
||
|
NTSTATUS
|
||
|
CMiniportWaveCyclicStream::Init
|
||
|
(
|
||
|
IN PCMiniportWaveCyclic Miniport_,
|
||
|
IN ULONG Pin_,
|
||
|
IN BOOLEAN Capture_,
|
||
|
IN PKSDATAFORMAT DataFormat_
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Initializes the stream object. Allocate a DMA buffer, timer and DPC
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Miniport_ -
|
||
|
|
||
|
Pin_ -
|
||
|
|
||
|
Capture_ -
|
||
|
|
||
|
DataFormat -
|
||
|
|
||
|
DmaChannel_ -
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
m_pMiniportLocal = Miniport_;
|
||
|
|
||
|
return
|
||
|
CMiniportWaveCyclicStreamMSVAD::Init
|
||
|
(
|
||
|
Miniport_,
|
||
|
Pin_,
|
||
|
Capture_,
|
||
|
DataFormat_
|
||
|
);
|
||
|
} // Init
|
||
|
|
||
|
//=============================================================================
|
||
|
STDMETHODIMP_(NTSTATUS)
|
||
|
CMiniportWaveCyclicStream::NonDelegatingQueryInterface
|
||
|
(
|
||
|
IN REFIID Interface,
|
||
|
OUT PVOID * Object
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
QueryInterface
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Interface - GUID
|
||
|
|
||
|
Object - interface pointer to be returned
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(Object);
|
||
|
|
||
|
if (IsEqualGUIDAligned(Interface, IID_IUnknown))
|
||
|
{
|
||
|
*Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this)));
|
||
|
}
|
||
|
else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclicStream))
|
||
|
{
|
||
|
*Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this));
|
||
|
}
|
||
|
else if (IsEqualGUIDAligned(Interface, IID_IDmaChannel))
|
||
|
{
|
||
|
*Object = PVOID(PDMACHANNEL(this));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*Object = NULL;
|
||
|
}
|
||
|
|
||
|
if (*Object)
|
||
|
{
|
||
|
PUNKNOWN(*Object)->AddRef();
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
} // NonDelegatingQueryInterface
|
||
|
#pragma code_seg()
|
||
|
|