⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ichwave.cpp

📁 AC97 Sample Driver and Related Code Samples. This directory contains a sample AC97 adapter driver a
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/********************************************************************************
**    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
**
**       Portions Copyright (c) 1998-1999 Intel Corporation
**
********************************************************************************/

// Every debug output has "Modulname text"
static char STR_MODULENAME[] = "ICH Stream: ";

#include "minwave.h"
#include "ichwave.h"

/*****************************************************************************
 * General Info
 *****************************************************************************
 * To protect the stBDList structure that is used to store mappings, we use a
 * spin lock called MapLock. This spin lock is also acquired when we change
 * the DMA registers. Normally, changes in stBDList and the DMA registers go
 * hand in hand. In case we only want to change the DMA registers, we need
 * to acquire the spin lock!
 */

#pragma code_seg("PAGE")
/*****************************************************************************
 * CreateMiniportWaveICHStream
 *****************************************************************************
 * Creates a wave miniport stream object for the ICH audio adapter. This is
 * (nearly) like the macro STD_CREATE_BODY_ from STDUNK.H.
 */
NTSTATUS CreateMiniportWaveICHStream
(
    OUT CMiniportWaveICHStream  **WaveIchStream,
    IN  PUNKNOWN                pUnknownOuter,
    IN  POOL_TYPE               PoolType
)
{
    PAGED_CODE ();

    DOUT (DBG_PRINT, ("[CreateMiniportWaveICHStream]"));

    //
    // This is basically like the macro at stdunk with the change that we
    // don't cast to interface unknown but to interface WaveIchStream.
    //
    *WaveIchStream = new (PoolType, 'rCcP')
                        CMiniportWaveICHStream (pUnknownOuter);
    if (*WaveIchStream)
    {
        (*WaveIchStream)->AddRef ();
        return STATUS_SUCCESS;
    }

    return STATUS_INSUFFICIENT_RESOURCES;
}
   

/*****************************************************************************
 * CMiniportWaveICHStream::~CMiniportWaveICHStream
 *****************************************************************************
 * Destructor
 */
CMiniportWaveICHStream::~CMiniportWaveICHStream ()
{
    PAGED_CODE ();


    DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::~CMiniportWaveICHStream]"));

    //
    // Print information about the scatter gather list.
    //
    DOUT (DBG_DMA, ("Head %d, Tail %d, Tag counter %d, Entries %d.",
                   stBDList.nHead, stBDList.nTail, stBDList.ulTagCounter, 
                   stBDList.nBDEntries));

    if (Wave)
    {
        //
        // Disable interrupts and stop DMA just in case.
        //
        if (Wave->AdapterCommon)
        {
            Wave->AdapterCommon->WriteBMControlRegister (m_ulBDAddr + X_CR, (UCHAR)0);
            
            //
            // Update also the topology miniport if this was the render stream.
            //
            if (Wave->AdapterCommon->GetMiniportTopology () &&
                (Channel == PIN_WAVEOUT_OFFSET))
            {
                Wave->AdapterCommon->GetMiniportTopology ()->SetCopyProtectFlag (FALSE);
            }
        }
        
        //
        // Remove stream from miniport Streams array.
        //
        if (Wave->Streams[Channel] == this)
        {
            Wave->Streams[Channel] = NULL;
        }
        
        //
        // Release the scatter/gather table.
        //
        if (stBDList.pBDEntry)
        {
            HalFreeCommonBuffer (Wave->AdapterObject,
                                 PAGE_SIZE,
                                 stBDList.PhysAddr,
                                 (PVOID)stBDList.pBDEntry,
                                 FALSE);
            stBDList.pBDEntry = NULL;
        }

        //
        // Release the miniport.
        //
        Wave->Release ();
        Wave = NULL;
    }

    //
    // Release the service group.
    //
    if (ServiceGroup)
    {
        ServiceGroup->Release ();
        ServiceGroup = NULL;
    }

    //
    // Release the mapping table.
    //
    if (stBDList.pMapData)
    {
        ExFreePool (stBDList.pMapData);
        stBDList.pMapData = NULL;
    }

    //
    // Release the port stream.
    //
    if (PortStream)
    {
        PortStream->Release ();
        PortStream = NULL;
    }

}


/*****************************************************************************
 * CMiniportWaveICHStream::Init
 *****************************************************************************
 * This routine initializes the stream object, sets up the BDL, and programs
 * the buffer descriptor list base address register for the pin being
 * initialized.
 */
NTSTATUS CMiniportWaveICHStream::Init
(
    IN  CMiniportWaveICH        *Miniport_,
    IN  PPORTWAVEPCISTREAM      PortStream_,
    IN  ULONG                   Channel_,
    IN  BOOLEAN                 Capture_,
    IN  PKSDATAFORMAT           DataFormat_,
    OUT PSERVICEGROUP           *ServiceGroup_
)
{
    PAGED_CODE ();

    DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::Init]"));

    ASSERT (Miniport_);
    ASSERT (PortStream_);
    ASSERT (DataFormat_);
    ASSERT (ServiceGroup_);

    //
    // The rule here is that we return when we fail without a cleanup.
    // The destructor will relase the allocated memory.
    //
    NTSTATUS ntStatus = STATUS_SUCCESS;

    //
    // Initialize BDL info.
    //
    stBDList.pBDEntry = NULL;
    stBDList.pMapData = NULL;
    stBDList.nHead = 0;
    stBDList.nTail = 0;
    stBDList.ulTagCounter = 0;
    stBDList.nBDEntries = 0;

    //
    // Save miniport pointer and addref it.
    //
    Wave = Miniport_;
    Wave->AddRef ();

    //
    // Save portstream interface pointer and addref it.
    //
    PortStream = PortStream_;
    PortStream->AddRef ();

    //
    // Save channel ID and capture flag.
    //
    Channel = Channel_;
    Capture = Capture_;

    //
    // Save data format and current sample rate.
    //
    DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)DataFormat_;
    CurrentRate = DataFormat->WaveFormatEx.nSamplesPerSec;
    NumberOfChannels = DataFormat->WaveFormatEx.nChannels;

    //
    // Initialize the BDL spinlock.
    //
    KeInitializeSpinLock (&MapLock);

    //
    // Create a service group (a DPC abstraction/helper) to help with 
    // interrupts.
    //
    ntStatus = PcNewServiceGroup (&ServiceGroup, NULL);
    if (!NT_SUCCESS (ntStatus))
    {
        DOUT (DBG_ERROR, ("Failed to create a service group!"));
        return ntStatus;
    }

    //
    // Pass the ServiceGroup pointer to portcls.
    //
    *ServiceGroup_ = ServiceGroup;
    ServiceGroup->AddRef ();

    // 
    // Setup the Buffer Descriptor List (BDL)
    // Allocate 32 entries of 8 bytes (one BDL entry). We allocate two tables
    // because we need one table as a backup.
    // The pointer is aligned on a 8 byte boundary (that's what we need).
    //
    stBDList.pBDEntry = (tBDEntry *)HalAllocateCommonBuffer (Wave->AdapterObject,
                               MAX_BDL_ENTRIES * sizeof (tBDEntry) * 2,
                               &stBDList.PhysAddr,
                               FALSE);

    if (!stBDList.pBDEntry)
    {
        DOUT (DBG_ERROR, ("Failed HalAllocateCommonBuffer!"));
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    // calculate the (backup) pointer.
    stBDList.pBDEntryBackup = (tBDEntry *)stBDList.pBDEntry + MAX_BDL_ENTRIES;

    //
    // Allocate a buffer for the 32 possible mappings. We allocate two tables
    // because we need one table as a backup
    //
    stBDList.pMapData = 
        (tMapData *)ExAllocatePool (NonPagedPool, sizeof(tMapData) * 
                                    MAX_BDL_ENTRIES * 2);
    if (!stBDList.pMapData)
    {
        DOUT (DBG_ERROR, ("Failed to allocate the back up buffer!"));
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    // calculate the (backup) pointer.
    stBDList.pMapDataBackup = stBDList.pMapData + MAX_BDL_ENTRIES;
        
    //
    // Store the base address of this DMA engine.
    //
    if (Capture)
    {
        //
        // could be PCM or MIC capture
        //
        if (Channel == PIN_WAVEIN_OFFSET)
        {
            // Base address for DMA registers.
            m_ulBDAddr = PI_BDBAR;
        }
        else
        {
            // Base address for DMA registers.
            m_ulBDAddr = MC_BDBAR;
        }
    }
    else    // render
    {
        // Base address for DMA registers.
        m_ulBDAddr = PO_BDBAR;
    }

    //
    // Reset the DMA and set the BD list pointer.
    //
    ResetDMA ();

    //
    // Reset the position pointers.
    //
    TotalBytesMapped   = 0;
    TotalBytesReleased = 0;

    //
    // Now set the requested sample rate. In case of a failure, the object
    // gets destroyed and releases all memory etc.
    //
    ntStatus = SetFormat (DataFormat_);
    if (!NT_SUCCESS (ntStatus))
    {
        DOUT (DBG_ERROR, ("Stream init SetFormat call failed!"));
        return ntStatus;
    }

    //
    // Initialize the device state.
    //
    m_PowerState = PowerDeviceD0;


    PPREFETCHOFFSET PreFetchOffset;
    //
    // Query for the new interface "PreFetchOffset" and use
    // function offered there in case the interface is offered.
    //
    if (NT_SUCCESS(PortStream->QueryInterface(IID_IPreFetchOffset, (PVOID *)&PreFetchOffset)))
    {
        // why don't we pad by 32 sample frames
        PreFetchOffset->SetPreFetchOffset(32 * (DataFormat->WaveFormatEx.nChannels * 2)); 
        PreFetchOffset->Release();
    }

    //
    // Store the stream pointer, it is used by the ISR.
    //
    Wave->Streams[Channel] = this;

    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CMiniportWaveICHStream::NonDelegatingQueryInterface
 *****************************************************************************
 * Obtains an interface.  This function works just like a COM QueryInterface
 * call and is used if the object is not being aggregated.
 */
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::NonDelegatingQueryInterface
(
    IN  REFIID  Interface,
    OUT PVOID * Object
)
{
    PAGED_CODE ();

    ASSERT (Object);

    DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::NonDelegatingQueryInterface]"));

    //
    // Convert for IID_IMiniportWavePciStream
    //
    if (IsEqualGUIDAligned (Interface, IID_IMiniportWavePciStream))
    {
        *Object = (PVOID)(PMINIPORTWAVEPCISTREAM)this;
    }
    //
    // Convert for IID_IServiceSink
    //
    else if (IsEqualGUIDAligned (Interface, IID_IServiceSink))
    {
        *Object = (PVOID)(PSERVICESINK)this;
    }
    //
    // Convert for IID_IDrmAudioStream
    //
    else if (IsEqualGUIDAligned (Interface, IID_IDrmAudioStream))
    {
        *Object = (PVOID)(PDRMAUDIOSTREAM)this;
    }
    //
    // Convert for IID_IUnknown
    //
    else if (IsEqualGUIDAligned (Interface, IID_IUnknown))
    {
        *Object = (PVOID)(PUNKNOWN)(PMINIPORTWAVEPCISTREAM)this;
    }
    else
    {
        *Object = NULL;
        return STATUS_INVALID_PARAMETER;
    }

    ((PUNKNOWN)*Object)->AddRef ();
    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CMiniportWaveICHStream::GetAllocatorFraming
 *****************************************************************************
 * Returns the framing requirements for this device.
 * That is sample size (for one sample) and preferred frame (buffer) size.
 */
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::GetAllocatorFraming
(
    OUT PKSALLOCATOR_FRAMING AllocatorFraming
)
{
    PAGED_CODE ();

    ULONG SampleSize;

    DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::GetAllocatorFraming]"));
    
    //
    // Determine sample size in bytes.  Always number of 
    // channels * 2 (because 16-bit).
    //
    SampleSize = DataFormat->WaveFormatEx.nChannels * 2;

    //
    // Report the suggested requirements.
    //
    AllocatorFraming->RequirementsFlags =
        KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | 
        KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY;
    AllocatorFraming->Frames = 8;

    //
    // Currently, arbitrarily selecting 10ms as the frame target size.
    //
    //  This value needs to be sample block aligned for ICH to work correctly.
    //  Assumes 100Hz minimum sample rate (otherwise FrameSize is 0 bytes)
    //
    AllocatorFraming->FrameSize = SampleSize * (DataFormat->WaveFormatEx.nSamplesPerSec / 100);
    AllocatorFraming->FileAlignment = FILE_LONG_ALIGNMENT;
    AllocatorFraming->PoolType = NonPagedPool;

    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CMiniportWaveICHStream::SetFormat
 *****************************************************************************    
 * This routine tests for proper data format (calls wave miniport) and sets
 * or changes the stream data format.
 * To figure out if the codec supports the sample rate, we just program the
 * sample rate and read it back. If it matches we return happy, if not then
 * we restore the sample rate and return unhappy.
 * We fail this routine if we are currently running (playing or recording).
 */
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::SetFormat
(
    IN  PKSDATAFORMAT   Format
)
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -