Sample Code

Windows Driver Samples/ Microsoft Virtual Audio Device Driver Sample/ C++/ basewave.cpp/

/*++

Copyright (c) 1997-2000  Microsoft Corporation All Rights Reserved

Module Name:

    basewave.cpp

Abstract:

    Implementation of wavecyclic miniport.

--*/

#pragma warning (disable : 4127)

#include <msvad.h>
#include "common.h"
#include "basewave.h"

//=============================================================================
// CMiniportWaveCyclicMSVAD
//=============================================================================

//=============================================================================
#pragma code_seg("PAGE")
CMiniportWaveCyclicMSVAD::CMiniportWaveCyclicMSVAD
(
    void
)
/*++

Routine Description:

  Constructor for wavecyclic miniport.

Arguments:

Return Value:

--*/
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveCyclicMSVAD::CMiniportWaveCyclicMSVAD]"));

    // Initialize members.
    //
    m_AdapterCommon = NULL;
    m_Port = NULL;
    m_FilterDescriptor = NULL;

    m_NotificationInterval = 0;
    m_SamplingFrequency = 0;

    m_ServiceGroup = NULL;
    m_MaxDmaBufferSize = DMA_BUFFER_SIZE;

    m_MaxOutputStreams = 0;
    m_MaxInputStreams = 0;
    m_MaxTotalStreams = 0;

    m_MinChannels = 0;
    m_MaxChannelsPcm = 0;
    m_MinBitsPerSamplePcm = 0;
    m_MaxBitsPerSamplePcm = 0;
    m_MinSampleRatePcm = 0;
    m_MaxSampleRatePcm = 0;
} // CMiniportWaveCyclicMSVAD

//=============================================================================
CMiniportWaveCyclicMSVAD::~CMiniportWaveCyclicMSVAD
(
    void
)
/*++

Routine Description:

  Destructor for wavecyclic miniport

Arguments:

Return Value:

--*/
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveCyclicMSVAD::~CMiniportWaveCyclicMSVAD]"));

    if (m_Port)
    {
        m_Port->Release();
    }

    if (m_ServiceGroup)
    {
        m_ServiceGroup->Release();
    }

    if (m_AdapterCommon)
    {
        m_AdapterCommon->Release();
    }
} // ~CMiniportWaveCyclicMSVAD

//=============================================================================
STDMETHODIMP
CMiniportWaveCyclicMSVAD::GetDescription
(
    _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
)
/*++

Routine Description:

    The GetDescription function gets a pointer to a filter description.
    The descriptor is defined in wavtable.h for each MSVAD sample.

Arguments:

  OutFilterDescriptor - Pointer to the filter description

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(OutFilterDescriptor);

    DPF_ENTER(("[CMiniportWaveCyclicMSVAD::GetDescription]"));

    *OutFilterDescriptor = m_FilterDescriptor;

    return (STATUS_SUCCESS);
} // GetDescription

//=============================================================================
STDMETHODIMP
CMiniportWaveCyclicMSVAD::Init
(
    _In_    PUNKNOWN                UnknownAdapter_,
    _In_    PRESOURCELIST           ResourceList_,
    _In_    PPORTWAVECYCLIC         Port_
)
/*++

Routine Description:

Arguments:

  UnknownAdapter_ - pointer to adapter common.

  ResourceList_ - resource list. MSVAD does not use resources.

  Port_ - pointer to the port

Return Value:

  NT status code.

--*/
{
    UNREFERENCED_PARAMETER(ResourceList_);

    PAGED_CODE();

    ASSERT(UnknownAdapter_);
    ASSERT(Port_);

    DPF_ENTER(("[CMiniportWaveCyclicMSVAD::Init]"));

    // AddRef() is required because we are keeping this pointer.
    //
    m_Port = Port_;
    m_Port->AddRef();

    // We want the IAdapterCommon interface on the adapter common object,
    // which is given to us as a IUnknown.  The QueryInterface call gives us
    // an AddRefed pointer to the interface we want.
    //
    NTSTATUS ntStatus =
        UnknownAdapter_->QueryInterface
        (
            IID_IAdapterCommon,
            (PVOID *) &m_AdapterCommon
        );

    if (NT_SUCCESS(ntStatus))
    {
        KeInitializeMutex(&m_SampleRateSync, 1);
        ntStatus = PcNewServiceGroup(&m_ServiceGroup, NULL);

        if (NT_SUCCESS(ntStatus))
        {
            m_AdapterCommon->SetWaveServiceGroup(m_ServiceGroup);
        }
    }

    if (!NT_SUCCESS(ntStatus))
    {
        // clean up AdapterCommon
        //
        if (m_AdapterCommon)
        {
            // clean up the service group
            //
            if (m_ServiceGroup)
            {
                m_AdapterCommon->SetWaveServiceGroup(NULL);
                m_ServiceGroup->Release();
                m_ServiceGroup = NULL;
            }

            m_AdapterCommon->Release();
            m_AdapterCommon = NULL;
        }

        // release the port
        //
        m_Port->Release();
        m_Port = NULL;
    }

    return ntStatus;
} // Init

//=============================================================================
NTSTATUS
CMiniportWaveCyclicMSVAD::PropertyHandlerCpuResources
(
    IN  PPCPROPERTY_REQUEST     PropertyRequest
)
/*++

Routine Description:

  Processes KSPROPERTY_AUDIO_CPURESOURCES

Arguments:

  PropertyRequest - property request structure

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(PropertyRequest);

    DPF_ENTER(("[CMiniportWaveCyclicMSVAD::PropertyHandlerCpuResources]"));

    NTSTATUS                    ntStatus = STATUS_INVALID_DEVICE_REQUEST;

    if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
    {
        ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(LONG), 0);
        if (NT_SUCCESS(ntStatus))
        {
            *(PLONG(PropertyRequest->Value)) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU;
            PropertyRequest->ValueSize = sizeof(LONG);
            ntStatus = STATUS_SUCCESS;
        }
    }
    else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
    {
        ntStatus =
            PropertyHandler_BasicSupport
            (
                PropertyRequest,
                KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
                VT_I4
            );
    }

    return ntStatus;
} // PropertyHandlerCpuResources

//=============================================================================
NTSTATUS
CMiniportWaveCyclicMSVAD::PropertyHandlerGeneric
(
    IN  PPCPROPERTY_REQUEST     PropertyRequest
)
/*++

Routine Description:

  Handles all properties for this miniport.

Arguments:

  PropertyRequest - property request structure

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(PropertyRequest);
    ASSERT(PropertyRequest->PropertyItem);

    NTSTATUS                    ntStatus = STATUS_INVALID_DEVICE_REQUEST;

    switch (PropertyRequest->PropertyItem->Id)
    {
        case KSPROPERTY_AUDIO_CPU_RESOURCES:
            ntStatus = PropertyHandlerCpuResources(PropertyRequest);
            break;

        default:
            DPF(D_TERSE, ("[PropertyHandlerGeneric: Invalid Device Request]"));
            ntStatus = STATUS_INVALID_DEVICE_REQUEST;
    }

    return ntStatus;
} // PropertyHandlerGeneric

//=============================================================================
NTSTATUS
CMiniportWaveCyclicMSVAD::ValidateFormat
(
    IN  PKSDATAFORMAT           pDataFormat
)
/*++

Routine Description:

  Validates that the given dataformat is valid.
  This version of the driver only supports PCM.

Arguments:

  pDataFormat - The dataformat for validation.

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(pDataFormat);

    DPF_ENTER(("[CMiniportWaveCyclicMSVAD::ValidateFormat]"));

    NTSTATUS                    ntStatus = STATUS_INVALID_PARAMETER;
    PWAVEFORMATEX               pwfx;

    pwfx = GetWaveFormatEx(pDataFormat);
    if (pwfx)
    {
        if (IS_VALID_WAVEFORMATEX_GUID(&pDataFormat->SubFormat))
        {
            USHORT wfxID = EXTRACT_WAVEFORMATEX_ID(&pDataFormat->SubFormat);

            switch (wfxID)
            {
                case WAVE_FORMAT_PCM:
                {
                    switch (pwfx->wFormatTag)
                    {
                        case WAVE_FORMAT_PCM:
                        {
                            ntStatus = ValidatePcm(pwfx);
                            break;
                        }
                    }
                    break;
                }

                default:
                    DPF(D_TERSE, ("Invalid format EXTRACT_WAVEFORMATEX_ID!"));
                    break;
            }
        }
        else
        {
            DPF(D_TERSE, ("Invalid pDataFormat->SubFormat!") );
        }
    }

    return ntStatus;
} // ValidateFormat

//-----------------------------------------------------------------------------
NTSTATUS
CMiniportWaveCyclicMSVAD::ValidatePcm
(
    IN  PWAVEFORMATEX           pWfx
)
/*++

Routine Description:

  Given a waveformatex and format size validates that the format is in device
  datarange.

Arguments:

  pWfx - wave format structure.

Return Value:

    NT status code.

--*/
{
    PAGED_CODE();

    DPF_ENTER(("CMiniportWaveCyclicMSVAD::ValidatePcm"));

    if
    (
        pWfx                                                &&
        (pWfx->cbSize == 0)                                 &&
        (pWfx->nChannels >= m_MinChannels)                  &&
        (pWfx->nChannels <= m_MaxChannelsPcm)               &&
        (pWfx->nSamplesPerSec >= m_MinSampleRatePcm)        &&
        (pWfx->nSamplesPerSec <= m_MaxSampleRatePcm)        &&
        (pWfx->wBitsPerSample >= m_MinBitsPerSamplePcm)     &&
        (pWfx->wBitsPerSample <= m_MaxBitsPerSamplePcm)
    )
    {
        return STATUS_SUCCESS;
    }

    DPF(D_TERSE, ("Invalid PCM format"));

    return STATUS_INVALID_PARAMETER;
} // ValidatePcm

//=============================================================================
// CMiniportWaveCyclicStreamMSVAD
//=============================================================================

CMiniportWaveCyclicStreamMSVAD::CMiniportWaveCyclicStreamMSVAD
(
    void
)
{
    PAGED_CODE();

    m_pMiniport = NULL;
    m_fCapture = FALSE;
    m_fFormat16Bit = FALSE;
    m_usBlockAlign = 0;
    m_ksState = KSSTATE_STOP;
    m_ulPin = (ULONG)-1;

    m_pDpc = NULL;
    m_pTimer = NULL;

    m_fDmaActive = FALSE;
    m_ulDmaPosition = 0;
    m_ullElapsedTimeCarryForward = 0;
    m_ulByteDisplacementCarryForward = 0;
    m_pvDmaBuffer = NULL;
    m_ulDmaBufferSize = 0;
    m_ulDmaMovementRate = 0;
    m_ullDmaTimeStamp = 0;
}

//=============================================================================
CMiniportWaveCyclicStreamMSVAD::~CMiniportWaveCyclicStreamMSVAD
(
    void
)
/*++

Routine Description:

  Destructor for wavecyclic stream

Arguments:

  void

Return Value:

--*/
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveCyclicStreamMS::~CMiniportWaveCyclicStreamMS]"));

    if (m_pTimer)
    {
        KeCancelTimer(m_pTimer);
        ExFreePoolWithTag(m_pTimer, MSVAD_POOLTAG);
    }

    // Since we just cancelled the timer, wait for all queued DPCs to complete
    // before we free the DPC.
    //
    KeFlushQueuedDpcs();

    if (m_pDpc)
    {
        ExFreePoolWithTag( m_pDpc, MSVAD_POOLTAG );
    }

    // Free the DMA buffer
    //
    FreeBuffer();
} // ~CMiniportWaveCyclicStreamMSVAD

//=============================================================================
#pragma warning (push)
#pragma warning (disable : 26165)
NTSTATUS
CMiniportWaveCyclicStreamMSVAD::Init
(
    IN  PCMiniportWaveCyclicMSVAD 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_ - miniport object

  Pin_ - pin id

  Capture_ - TRUE if this is a capture stream

  DataFormat_ - new dataformat

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveCyclicStreamMSVAD::Init]"));

    ASSERT(Miniport_);
    ASSERT(DataFormat_);

    NTSTATUS                    ntStatus = STATUS_SUCCESS;
    PWAVEFORMATEX               pWfx;

    pWfx = GetWaveFormatEx(DataFormat_);
    if (!pWfx)
    {
        DPF(D_TERSE, ("Invalid DataFormat param in NewStream"));
        ntStatus = STATUS_INVALID_PARAMETER;
    }

    if (NT_SUCCESS(ntStatus))
    {
        m_pMiniport = Miniport_;

        m_ulPin                           = Pin_;
        m_fCapture                        = Capture_;
        m_usBlockAlign                    = pWfx->nBlockAlign;
        m_fFormat16Bit                    = (pWfx->wBitsPerSample == 16);
        m_ksState                         = KSSTATE_STOP;
        m_ulDmaPosition                   = 0;
        m_ullElapsedTimeCarryForward      = 0;
        m_ulByteDisplacementCarryForward  = 0;
        m_fDmaActive                      = FALSE;
        m_pDpc                            = NULL;
        m_pTimer                          = NULL;
        m_pvDmaBuffer                     = NULL;

        // If this is not the capture stream, create the output file.
        //
        if (!m_fCapture)
        {
            DPF(D_TERSE, ("SaveData %p", &m_SaveData));
            ntStatus = m_SaveData.SetDataFormat(DataFormat_);
            if (NT_SUCCESS(ntStatus))
            {
                ntStatus = m_SaveData.Initialize();
            }

        }
    }

    // Allocate DMA buffer for this stream.
    //
    if (NT_SUCCESS(ntStatus))
    {
        ntStatus = AllocateBuffer(m_pMiniport->m_MaxDmaBufferSize, NULL);
    }

    // Set sample frequency. Note that m_SampleRateSync access should
    // be syncronized.
    //
    if (NT_SUCCESS(ntStatus))
    {
        ntStatus =
            KeWaitForSingleObject
            (
                &m_pMiniport->m_SampleRateSync,
                Executive,
                KernelMode,
                FALSE,
                NULL
            );
        if (STATUS_SUCCESS == ntStatus)
        {
            m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec;
            KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE);
        }
        else
        {
            DPF(D_TERSE, ("[SamplingFrequency Sync failed: %08X]", ntStatus));
        }
    }

    if (NT_SUCCESS(ntStatus))
    {
        ntStatus = SetFormat(DataFormat_);
    }

    if (NT_SUCCESS(ntStatus))
    {
        m_pDpc = (PRKDPC)
            ExAllocatePoolWithTag
            (
                NonPagedPool,
                sizeof(KDPC),
                MSVAD_POOLTAG
            );
        if (!m_pDpc)
        {
            DPF(D_TERSE, ("[Could not allocate memory for DPC]"));
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        }
    }

    if (NT_SUCCESS(ntStatus))
    {
        m_pTimer = (PKTIMER)
            ExAllocatePoolWithTag
            (
                NonPagedPool,
                sizeof(KTIMER),
                MSVAD_POOLTAG
            );
        if (!m_pTimer)
        {
            DPF(D_TERSE, ("[Could not allocate memory for Timer]"));
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        }
    }

    if (NT_SUCCESS(ntStatus))
    {
        KeInitializeDpc(m_pDpc, TimerNotify, m_pMiniport);
        KeInitializeTimerEx(m_pTimer, NotificationTimer);
    }

    return ntStatus;
} // Init
#pragma warning (pop)

#pragma code_seg()

//=============================================================================
// CMiniportWaveCyclicStreamMSVAD IMiniportWaveCyclicStream
//=============================================================================

//=============================================================================
STDMETHODIMP
CMiniportWaveCyclicStreamMSVAD::GetPosition
(
    _Out_ PULONG                  Position
)
/*++

Routine Description:

  The GetPosition function gets the current position of the DMA read or write
  pointer for the stream. Callers of GetPosition should run at
  IRQL <= DISPATCH_LEVEL.

Arguments:

  Position - Position of the DMA pointer

Return Value:

  NT status code.

--*/
{
    if (m_fDmaActive)
    {
        // Get the current time
        //
        ULONGLONG CurrentTime = KeQueryInterruptTime();

        // Calculate the time elapsed since the last call to GetPosition() or since the
        // DMA engine started.  Note that the division by 10000 to convert to milliseconds
        // may cause us to lose some of the time, so we will carry the remainder forward 
        // to the next GetPosition() call.
        //
        ULONG TimeElapsedInMS =
            ( (ULONG) (CurrentTime - m_ullDmaTimeStamp + m_ullElapsedTimeCarryForward) ) / 10000;

        // Carry forward the remainder of this division so we don't fall behind with our position.
        //
        m_ullElapsedTimeCarryForward = 
            (CurrentTime - m_ullDmaTimeStamp + m_ullElapsedTimeCarryForward) % 10000;

        // Calculate how many bytes in the DMA buffer would have been processed in the elapsed
        // time.  Note that the division by 1000 to convert to milliseconds may cause us to 
        // lose some bytes, so we will carry the remainder forward to the next GetPosition() call.
        //
        ULONG ByteDisplacement =
            ((m_ulDmaMovementRate * TimeElapsedInMS) + m_ulByteDisplacementCarryForward) / 1000;

        // Carry forward the remainder of this division so we don't fall behind with our position.
        //
        m_ulByteDisplacementCarryForward = (
            (m_ulDmaMovementRate * TimeElapsedInMS) + m_ulByteDisplacementCarryForward) % 1000;

        // Increment the DMA position by the number of bytes displaced since the last
        // call to GetPosition() and ensure we properly wrap at buffer length.
        //
        m_ulDmaPosition =
            (m_ulDmaPosition + ByteDisplacement) % m_ulDmaBufferSize;

        // Return the new DMA position
        //
        *Position = m_ulDmaPosition;

        // Update the DMA time stamp for the next call to GetPosition()
        //
        m_ullDmaTimeStamp = CurrentTime;
    }
    else
    {
        // DMA is inactive so just return the current DMA position.
        //
        *Position = m_ulDmaPosition;
    }

    return STATUS_SUCCESS;
} // GetPosition

//=============================================================================
STDMETHODIMP
CMiniportWaveCyclicStreamMSVAD::NormalizePhysicalPosition
(
    _Inout_ PLONGLONG            PhysicalPosition
)
/*++

Routine Description:

  Given a physical position based on the actual number of bytes transferred,
  NormalizePhysicalPosition converts the position to a time-based value of
  100 nanosecond units. Callers of NormalizePhysicalPosition can run at any IRQL.

Arguments:

  PhysicalPosition - On entry this variable contains the value to convert.
                     On return it contains the converted value

Return Value:

  NT status code.

--*/
{
    ASSERT(PhysicalPosition);

    *PhysicalPosition =
        ( _100NS_UNITS_PER_SECOND / m_usBlockAlign * *PhysicalPosition ) /
        m_pMiniport->m_SamplingFrequency;

    return STATUS_SUCCESS;
} // NormalizePhysicalPosition

#pragma code_seg("PAGE")
//=============================================================================
STDMETHODIMP_(NTSTATUS)
CMiniportWaveCyclicStreamMSVAD::SetFormat
(
    _In_  PKSDATAFORMAT           Format
)
/*++

Routine Description:

  The SetFormat function changes the format associated with a stream.
  Callers of SetFormat should run at IRQL PASSIVE_LEVEL

Arguments:

  Format - Pointer to a KSDATAFORMAT structure which indicates the new format
           of the stream.

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(Format);

    DPF_ENTER(("[CMiniportWaveCyclicStreamMSVAD::SetFormat]"));

    NTSTATUS                    ntStatus = STATUS_INVALID_DEVICE_REQUEST;
    PWAVEFORMATEX               pWfx;

    if (m_ksState != KSSTATE_RUN)
    {
        // MSVAD does not validate the format.
        //
        pWfx = GetWaveFormatEx(Format);
        if (pWfx)
        {
            ntStatus =
                KeWaitForSingleObject
                (
                    &m_pMiniport->m_SampleRateSync,
                    Executive,
                    KernelMode,
                    FALSE,
                    NULL
                );
            if (STATUS_SUCCESS == ntStatus)
            {
                if (!m_fCapture)
                {
                    ntStatus = m_SaveData.SetDataFormat(Format);
                }

                m_usBlockAlign = pWfx->nBlockAlign;
                m_fFormat16Bit = (pWfx->wBitsPerSample == 16);
                m_pMiniport->m_SamplingFrequency =
                    pWfx->nSamplesPerSec;
                m_ulDmaMovementRate = pWfx->nAvgBytesPerSec;

                DPF(D_TERSE, ("New Format: %d", pWfx->nSamplesPerSec));
            }

            KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE);
        }
    }

    return ntStatus;
} // SetFormat

//=============================================================================
STDMETHODIMP_(ULONG)
CMiniportWaveCyclicStreamMSVAD::SetNotificationFreq
(
    _In_  ULONG                   Interval,
    _Out_ PULONG                  FramingSize
)
/*++

Routine Description:

  The SetNotificationFrequency function sets the frequency at which
  notification interrupts are generated. Callers of SetNotificationFrequency
  should run at IRQL PASSIVE_LEVEL.

Arguments:

  Interval - Value indicating the interval between interrupts,
             expressed in milliseconds

  FramingSize - Pointer to a ULONG value where the number of bytes equivalent
                to Interval milliseconds is returned

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(FramingSize);

    DPF_ENTER(("[CMiniportWaveCyclicStreamMSVAD::SetNotificationFreq]"));

    m_pMiniport->m_NotificationInterval = Interval;

    *FramingSize =
        m_usBlockAlign *
        m_pMiniport->m_SamplingFrequency *
        Interval / 1000;

    return m_pMiniport->m_NotificationInterval;
} // SetNotificationFreq

//=============================================================================
STDMETHODIMP
CMiniportWaveCyclicStreamMSVAD::SetState
(
    _In_  KSSTATE                 NewState
)
/*++

Routine Description:

  The SetState function sets the new state of playback or recording for the
  stream. SetState should run at IRQL PASSIVE_LEVEL

Arguments:

  NewState - KSSTATE indicating the new state for the stream.

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveCyclicStreamMSVAD::SetState]"));

    NTSTATUS                    ntStatus = STATUS_SUCCESS;

    // The acquire state is not distinguishable from the stop state for our
    // purposes.
    //
    if (NewState == KSSTATE_ACQUIRE)
    {
        NewState = KSSTATE_STOP;
    }

    if (m_ksState != NewState)
    {
        switch(NewState)
        {
            case KSSTATE_PAUSE:
            {
                DPF(D_TERSE, ("KSSTATE_PAUSE"));

                m_fDmaActive = FALSE;
            }
            break;

            case KSSTATE_RUN:
            {
                DPF(D_TERSE, ("KSSTATE_RUN"));

                 LARGE_INTEGER   delay;

                // Set the timer for DPC.
                //
                m_ullDmaTimeStamp             = KeQueryInterruptTime();
                m_ullElapsedTimeCarryForward  = 0;
                m_fDmaActive                  = TRUE;
                delay.HighPart                = 0;
                delay.LowPart                 = m_pMiniport->m_NotificationInterval;

                KeSetTimerEx
                (
                    m_pTimer,
                    delay,
                    m_pMiniport->m_NotificationInterval,
                    m_pDpc
                );
            }
            break;

        case KSSTATE_STOP:

            DPF(D_TERSE, ("KSSTATE_STOP"));

            m_fDmaActive                      = FALSE;
            m_ulDmaPosition                   = 0;
            m_ullElapsedTimeCarryForward      = 0;
            m_ulByteDisplacementCarryForward  = 0;

            KeCancelTimer( m_pTimer );

            // Wait until all work items are completed.
            //
            if (!m_fCapture)
            {
                m_SaveData.WaitAllWorkItems();
            }

            break;
        }

        m_ksState = NewState;
    }

    return ntStatus;
} // SetState

#pragma code_seg()

//=============================================================================
_Use_decl_annotations_
STDMETHODIMP_(void)
CMiniportWaveCyclicStreamMSVAD::Silence
(
    PVOID Buffer,
    ULONG                    ByteCount
)
/*++

Routine Description:

  The Silence function is used to copy silence samplings to a certain location.
  Callers of Silence can run at any IRQL

Arguments:

  Buffer - Pointer to the buffer where the silence samplings should
           be deposited.

  ByteCount - Size of buffer indicating number of bytes to be deposited.

Return Value:

  NT status code.

--*/
{
    RtlFillMemory(Buffer, ByteCount, m_fFormat16Bit ? 0 : 0x80);
} // Silence

//=============================================================================
void
TimerNotify
(
    IN  PKDPC                   Dpc,
    IN  PVOID                   DeferredContext,
    IN  PVOID                   SA1,
    IN  PVOID                   SA2
)
/*++

Routine Description:

  Dpc routine. This simulates an interrupt service routine. The Dpc will be
  called whenever CMiniportWaveCyclicStreamMSVAD::m_pTimer triggers.

Arguments:

  Dpc - the Dpc object

  DeferredContext - Pointer to a caller-supplied context to be passed to
                    the DeferredRoutine when it is called

  SA1 - System argument 1

  SA2 - System argument 2

Return Value:

  NT status code.

--*/
{
    UNREFERENCED_PARAMETER(Dpc);
    UNREFERENCED_PARAMETER(SA1);
    UNREFERENCED_PARAMETER(SA2);

    PCMiniportWaveCyclicMSVAD pMiniport =
        (PCMiniportWaveCyclicMSVAD) DeferredContext;

    if (pMiniport && pMiniport->m_Port)
    {
        pMiniport->m_Port->Notify(pMiniport->m_ServiceGroup);
    }
} // TimerNotify


Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS