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

📄 ichwave.cpp

📁 AC97 Sample Driver and Related Code Samples. This directory contains a sample AC97 adapter driver a
💻 CPP
📖 第 1 页 / 共 4 页
字号:


/*****************************************************************************
 * CMiniportWaveICHStream::Service
 *****************************************************************************
 * This routine is called by the port driver in response to the interrupt
 * service routine requesting service on the stream's service group.
 * Requesting service on the service group results in a DPC being scheduled
 * that calls this routine when it runs.
 */
STDMETHODIMP_(void) CMiniportWaveICHStream::Service (void)
{

    DOUT (DBG_PRINT, ("Service"));

    // release all mappings
    ReleaseUsedMappings ();

    // get new mappings
    GetNewMappings ();
}


/*****************************************************************************
 * CMiniportWaveICHStream::NormalizePhysicalPosition
 *****************************************************************************
 * Given a physical position based on the actual number of bytes transferred,
 * this function converts the position to a time-based value of 100ns units.
 */
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::NormalizePhysicalPosition
(
    IN OUT PLONGLONG PhysicalPosition
)
{
    ULONG SampleSize;

    DOUT (DBG_PRINT, ("NormalizePhysicalPosition"));

    //
    // Determine the sample size in bytes
    //
    SampleSize = DataFormat->WaveFormatEx.nChannels * 2;

    //
    // Calculate the time in 100ns steps.
    //
    *PhysicalPosition = (_100NS_UNITS_PER_SECOND / SampleSize * 
                         *PhysicalPosition) / CurrentRate;

    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CMiniportWaveICHStream::GetPosition
 *****************************************************************************
 * Gets the stream position. This is a byte count of the current position of
 * a stream running on a particular DMA engine.  We must return a sample
 * accurate count or the WaveDrv32 wave drift tests (35.2 & 36.2) will fail.
 *
 * The position is the sum of three parts:
 *     1) The total number of bytes in released buffers
 *     2) The position in the current buffer.
 *     3) The total number of bytes in played but not yet released buffers
 */
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::GetPosition
(
    OUT PULONGLONG   Position
)
{
    KIRQL   OldIrql;
    UCHAR   nCurrentIndex = 0;
    DWORD   RegisterX_PICB;

    ASSERT (Position);
               
    //
    // Acquire the mapping spin lock.
    //
    KeAcquireSpinLock (&MapLock, &OldIrql);

    //
    // Start with TotalBytesReleased (mappings released).
    //
    *Position = TotalBytesReleased;
    
    //
    // If we have entries in the list, we may have buffers that have not been
    // released but have been at least partially played.
    //
    if (stBDList.nBDEntries)
    {
        //
        // Repeat this until we get the same reading twice.  This will prevent
        // jumps when we are near the end of the buffer.
        //
        do
        {
            nCurrentIndex = Wave->AdapterCommon->
                ReadBMControlRegister8 (m_ulBDAddr + X_CIV);
            
            RegisterX_PICB = (DWORD)Wave->AdapterCommon->ReadBMControlRegister16 (m_ulBDAddr + X_PICB);
        } while (nCurrentIndex != (int)Wave->AdapterCommon->
                ReadBMControlRegister8 (m_ulBDAddr + X_CIV));
        
        //
        // If we never released a buffer and register X_PICB is zero then the DMA was not
        // initialized yet and the position should be zero.
        //
        if (RegisterX_PICB || nCurrentIndex || TotalBytesReleased)
        {
            //
            // Add in our position in the current buffer.  The read returns the 
            // amount left in the buffer.
            //
            *Position += (stBDList.pMapData[nCurrentIndex].ulBufferLength - (RegisterX_PICB << 1));
            
            //
            // Total any buffers that have been played and not released.
            //
            if (nCurrentIndex != ((stBDList.nHead -1) & BDL_MASK))
            {
                int i = stBDList.nHead;
                while (i != nCurrentIndex)
                {
                    *Position += (ULONGLONG)stBDList.pMapData[i].ulBufferLength;
                    i = (i + 1) & BDL_MASK;
                }
            }
        }
    }

    DOUT (DBG_POSITION, ("[GetPosition] POS: %08x'%08x\n", (DWORD)(*Position >> 32), (DWORD)*Position));

    //
    // Release the mapping spin lock.
    //
    KeReleaseSpinLock (&MapLock, OldIrql);


    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CMiniportWaveICHStream::RevokeMappings
 *****************************************************************************
 * This routine is used by the port to revoke mappings previously delivered 
 * to the miniport stream that have not yet been unmapped.  This would 
 * typically be called in response to an I/O cancellation request.
 */
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::RevokeMappings
(
    IN  PVOID     FirstTag,
    IN  PVOID     LastTag,
    OUT PULONG    MappingsRevoked
)
{
    ASSERT (MappingsRevoked);

    KIRQL   OldIrql;
    ULONG   ulOldDMAEngineState;
    int     nCurrentIndex, nSearchIndex, nFirst, nLast, nNumMappings;

    DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::RevokeMappings]"));
    
    //
    // 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));

    //
    // Start accessing the mappings.
    //
    KeAcquireSpinLock (&MapLock, &OldIrql);

    //
    // Save old DMA engine state.
    //
    ulOldDMAEngineState = DMAEngineState;
    
    //
    // First stop the DMA engine so it won't process the next buffer in the
    // scatter gather list which might be one of the revoked buffers.
    //
    PauseDMA ();

    // Get current index 
    nCurrentIndex = Wave->AdapterCommon->
        ReadBMControlRegister8 (m_ulBDAddr + X_CIV);

    //
    // We always rearrange the scatter gather list. That means we reset the DMA
    // engine and move the BD list so that the entry where the current index
    // pointed to is located at position 0.
    //
    ResetDMA ();

    //
    // Return immediately if we just have 1 entry in our BD list.
    //
    if (!stBDList.nBDEntries || (stBDList.nBDEntries == 1))
    {
        *MappingsRevoked = stBDList.nBDEntries;
        stBDList.nHead = stBDList.nTail = stBDList.nBDEntries = 0;
        
        //
        // CIV and LVI of DMA registers are set to 0 already.
        //
        KeReleaseSpinLock (&MapLock, OldIrql);
        return STATUS_SUCCESS;
    }

    //
    // First move the BD list to the beginning.  In case the DMA engine was 
    // stopped, current index may point to an empty BD entry.
    //
    if ((nCurrentIndex == ((stBDList.nHead - 1) & BDL_MASK)) &&
       (stBDList.nBDEntries != MAX_BDL_ENTRIES - 1))
    {
        nCurrentIndex = stBDList.nHead;     // point to head
    }

    //
    // Move BD list to (0-((current - head) & mask)) & mask
    // where ((current - head) & mask) is the difference between head and
    // current index, no matter where they are :)
    //
    MoveBDList (stBDList.nHead, (stBDList.nTail - 1) & BDL_MASK,
            (0 - ((nCurrentIndex - stBDList.nHead) & BDL_MASK)) & BDL_MASK);
    
    //
    // Update structure.
    //
    stBDList.nHead = (0 - ((nCurrentIndex - stBDList.nHead) & BDL_MASK)) & 
        BDL_MASK;
    stBDList.nTail = (stBDList.nHead + stBDList.nBDEntries) & BDL_MASK;

    //
    // Then we have to search for the tags. If we wouldn't have to rearrange the
    // scatter gather list all the time, then we could use the tag as an index
    // to the array, but the only way to clear DMA caches is a reset which has
    // the side-effect that we have to rearrange the BD list (see above).
    //
    // search for first...
    //
    nSearchIndex = stBDList.nHead;
    do
    {
        if ((void *)ULongToPtr(stBDList.pMapData[nSearchIndex].ulTag) == FirstTag)
            break;
        nSearchIndex = (nSearchIndex + 1) & BDL_MASK;
    } while (nSearchIndex != stBDList.nTail);
    nFirst = nSearchIndex;
    
    //
    // Search for last...
    //
    nSearchIndex = stBDList.nHead;
    do
    {
        if ((void *)ULongToPtr(stBDList.pMapData[nSearchIndex].ulTag) == LastTag)
            break;
        nSearchIndex = (nSearchIndex + 1) & BDL_MASK;
    } while (nSearchIndex != stBDList.nTail);
    nLast = nSearchIndex;


    //
    // Check search result.
    //
    if ((nFirst == stBDList.nTail) || (nLast == stBDList.nTail))
    {
        DOUT (DBG_ERROR, ("!!! Entry not found !!!"));
        
        //
        // restart DMA in case it was running
        //
        if ((ulOldDMAEngineState & DMA_ENGINE_ON) && stBDList.nBDEntries)
            ResumeDMA ();
        *MappingsRevoked = 0;
        KeReleaseSpinLock (&MapLock, OldIrql);
        return STATUS_UNSUCCESSFUL;         // one of the tags not found
    }

    // Print the index numbers found.
    DOUT (DBG_DMA, ("Removing entries %d (%d) to %d (%d).", nFirst, FirstTag,
                  nLast, LastTag));

    //
    // Calculate the entries between the indizes.
    //
    if (nLast < nFirst)
    {
        nNumMappings = ((nLast + MAX_BDL_ENTRIES) - nFirst) + 1;
    }
    else
    {
        nNumMappings = (nLast - nFirst) + 1;
    }

    //
    // Print debug inormation.
    //
    DOUT (DBG_DMA, ("Found entries: %d-%d, %d entries.", nFirst, nLast, 
                   nNumMappings));
    
    //
    // Now remove the revoked buffers.  Move the BD list and modify the 
    // status information.
    //
    if (nFirst < stBDList.nTail)
    {
        //
        // In this case, both first and last are >= the current index (0)
        //
        if (nLast != ((stBDList.nTail - 1) & BDL_MASK))
        {
            //
            // Not the last entry, so move the BD list + mappings.
            //
            MoveBDList ((nLast + 1) & BDL_MASK, (stBDList.nTail - 1) & BDL_MASK,
                        nFirst);
        }
        stBDList.nTail = (stBDList.nTail - nNumMappings) & BDL_MASK;
    }

    //
    // In this case, at least first is "<" than current index (0)
    //
    else    
    {
        //
        // Check for last.
        //
        if (nLast < stBDList.nTail)
        {                 
            //
            // Last is ">=" current index and first is "<" current index (0).
            // Remove MAX_DBL_ENTRIES - first entries in front of current index.
            //
            if (nFirst != stBDList.nHead)
            {
                //
                // Move from head towards current index.
                //
                MoveBDList (stBDList.nHead, nFirst - 1, 
                           (stBDList.nHead + (MAX_BDL_ENTRIES - nFirst)) & 
                           BDL_MASK);
            }

            //
            // Adjust head.
            //
            stBDList.nHead = (stBDList.nHead + (MAX_BDL_ENTRIES - nFirst)) & 
                BDL_MASK;

            //
            // Remove nLast entries from CIV to tail.
            //
            if (nLast != ((stBDList.nTail - 1) & BDL_MASK))
            {
                //
                // Not the last entry, so move the BD list + mappings.
                //
                MoveBDList (nLast + 1, (stBDList.nTail - 1) & BDL_MASK, 0);
            }

            //
            // Adjust tail.
            //
            stBDList.nTail = (stBDList.nTail - (nLast + 1)) & BDL_MASK;
        }

        //
        // Last is "<" current index and first is "<" current index (0).
        //
        else
        {
            //
            // Remove nNumMappings entries in front of current index.
            //
            if (nFirst != stBDList.nHead)
            {
                //
                // Move from head towards current index.
                //
                MoveBDList (stBDList.nHead, nFirst - 1, 
                           (nLast - nNumMappings) + 1);
            }
            
            //
            // Adjust head.
            //
            stBDList.nHead = (stBDList.nHead + nNumMappings) & BDL_MASK;
        }
    }

    //
    // In all cases, reduce the number of mappings.
    //
    stBDList.nBDEntries -= nNumMappings;

    //
    // Print debug information.
    //
    DOUT (DBG_DMA, ("Number of mappings is now %d, Head is %d, Tail is %d",
            stBDList.nBDEntries, stBDList.nHead, stBDList.nTail));
    
    //
    // Reprogram the last valid index only when tail != 0
    //
    if (stBDList.nTail)
    {
        Wave->AdapterCommon->WriteBMControlRegister (m_ulBDAddr + X_LVI,
                    (UCHAR)(stBDList.nTail - 1 & BDL_MASK));
    }

    //
    // Just un-pause the DMA engine if it was running before and there are 
    // still entries left and tail != 0.
    //
    if ((ulOldDMAEngineState & DMA_ENGINE_ON) && stBDList.nBDEntries 
       && stBDList.nTail)
    {
        ResumeDMA ();
    }

    //
    // Release the mapping spin lock and return the number of mappings we 
    // revoked.
    //
    KeReleaseSpinLock (&MapLock, OldIrql);
    *MappingsRevoked = nNumMappings;
    
    
    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CMiniportWaveICHStream::MappingAvailable
 *****************************************************************************
 * This routine is called by the port driver to notify the stream that there
 * are new mappings available.  Note that this is ONLY called after the stream
 * has previously had a GetMapping() call fail due to lack of available
 * mappings.
 */
STDMETHODIMP_(void) CMiniportWaveICHStream::MappingAvailable (void)
{
    DOUT (DBG_PRINT, ("MappingAvailable"));

    //
    // Release processed mappings.
    //
    ReleaseUsedMappings ();

    //
    // Process the new mappings.
    //
    GetNewMappings ();
}


/*****************************************************************************
 * CMiniportWaveICHStream::GetNewMappings
 *****************************************************************************

⌨️ 快捷键说明

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