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

📄 common.cpp

📁 AC97 Sample Driver and Related Code Samples. This directory contains a sample AC97 adapter driver a
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    // No mask?  Could happen when you try to prg. left channel of a
    // mono volume.
    //
    if (!wMask)
        return STATUS_SUCCESS;

    //
    // Check to see if we are only writing specific bits.  If so, we want
    // to leave some bits in the register alone.
    //
    if (wMask != 0xffff)
    {
        //
        // Read the current register contents.
        //
        ntStatus = ReadCodecRegister (reg, &TempData);
        if (!NT_SUCCESS (ntStatus))
        {
            DOUT (DBG_ERROR, ("WriteCodecRegiser read for mask failed"));
            return ntStatus;
        }

        //
        // Do the masking.
        //
        TempData &= ~wMask;
        TempData |= (wMask & wData);
    }
    else
    {
        TempData = wData;
    }
    

    //
    // Grab the codec access semiphore.
    //
    ntStatus = AcquireCodecSemiphore ();
    if (!NT_SUCCESS (ntStatus))
    {
        DOUT (DBG_ERROR, ("WriteCodecRegister failed for register %s",
            reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
            reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
            reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" : "REG_INVALID"));
        return ntStatus;
    }
            
    //
    // Write the data.
    //
    WRITE_PORT_USHORT (m_pCodecBase + reg, TempData);

    //
    // Update cache.
    //
    m_stAC97Registers[reg].wCache = TempData;
    
    DOUT (DBG_REGS, ("AC97WRITE: %s -> 0x%04x", 
                   reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
                   reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
                   reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" : 
                   "REG_INVALID", TempData));
    
    
    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CAdapterCommon::PrimaryCodecReady
 *****************************************************************************
 * Checks whether the primary codec is present and ready.  This may take
 * awhile if we are bringing it up from a cold reset so give it a second
 * before giving up.
 */
NTSTATUS CAdapterCommon::PrimaryCodecReady (void)
{
    PAGED_CODE ();

    DOUT (DBG_PRINT, ("[CAdapterCommon::PrimaryCodecReady]"));

    
    //
    // Enable the AC link and raise the reset line.
    //
    DWORD dwRegValue = ReadBMControlRegister32 (GLOB_CNT);
    
    // If someone enabled GPI Interrupt Enable, then he hopefully handles that
    // too.
    dwRegValue = (dwRegValue | GLOB_CNT_COLD) & ~(GLOB_CNT_ACLOFF | GLOB_CNT_PRIE);
    WriteBMControlRegister (GLOB_CNT, dwRegValue);

    //
    // Wait for the Codec to be ready.
    //
    ULONG           WaitCycles = 200;
    LARGE_INTEGER   WaitTime = RtlConvertLongToLargeInteger (-50000);   // wait 5000us (5ms) relative

    do
    {
        if (READ_PORT_ULONG ((PULONG)(m_pBusMasterBase + GLOB_STA)) & 
            GLOB_STA_PCR)
        {
            return STATUS_SUCCESS;
        }

        KeDelayExecutionThread (KernelMode, FALSE, &WaitTime);
    } while (WaitCycles--);

    DOUT (DBG_ERROR, ("PrimaryCodecReady timed out!"));
    return STATUS_IO_TIMEOUT;
}


/*****************************************************************************
 * CAdapterCommon::PowerUpCodec
 *****************************************************************************
 * Sets the Codec to the highest power state and waits until the Codec reports
 * that the power state is reached.
 */
NTSTATUS CAdapterCommon::PowerUpCodec (void)
{
    PAGED_CODE ();

    WORD        wCodecReg;
    NTSTATUS    ntStatus;

    DOUT (DBG_PRINT, ("[CAdapterCommon::PowerUpCodec]"));

    //
    // Power up the Codec.
    //
    WriteCodecRegister (AC97REG_POWERDOWN, 0x00, -1);

    //
    // Wait for the Codec to be powered up.
    //
    ULONG           WaitCycles = 200;
    LARGE_INTEGER   WaitTime = RtlConvertLongToLargeInteger (-50000);   // wait 5000us (5ms) relative

    do
    {
        //
        // Read the power management register.
        //
        ntStatus = ReadCodecRegister (AC97REG_POWERDOWN, &wCodecReg);
        if (!NT_SUCCESS (ntStatus))
        {
            wCodecReg = 0;      // Will cause an error.
            break;
        }

        //
        // Check the power state. Should be ready.
        //
        if ((wCodecReg & 0x0f) == 0x0f)
            break;

        //
        // Let's wait a little, 5ms and then try again.
        //
        KeDelayExecutionThread (KernelMode, FALSE, &WaitTime);
    } while (WaitCycles--);

    // Check if we timed out.
    if ((wCodecReg & 0x0f) != 0x0f)
    {
        DOUT (DBG_ERROR, ("PowerUpCodec timed out. CoDec not powered up."));
        ntStatus = STATUS_DEVICE_NOT_READY;
    }

    return ntStatus;
}


/*****************************************************************************
 * CAdapterCommon::ProgramSampleRate
 *****************************************************************************
 * Programs the sample rate. If the rate cannot be programmed, the routine
 * restores the register and returns STATUS_UNSUCCESSFUL.
 * We don't handle double rate sample rates here, because the Intel ICH con-
 * troller cannot serve CoDecs with double rate or surround sound. If you want
 * to modify this driver for another AC97 controller, then you might want to
 * change this function too.
 */
STDMETHODIMP_(NTSTATUS) CAdapterCommon::ProgramSampleRate
(
    IN  AC97Register    Register,
    IN  DWORD           dwSampleRate
)
{
    PAGED_CODE ();

    WORD     wOldRateReg, wCodecReg;
    NTSTATUS ntStatus;

    DOUT (DBG_PRINT, ("[CAdapterCommon::ProgramSampleRate]"));

    //
    // Check if we support variable sample rate.
    //
    switch(Register)
    {
        case AC97REG_MIC_SAMPLERATE:
            //
            // Variable sample rate supported?
            //
            if (GetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED))
            {
                // Range supported?
                if (dwSampleRate > 48000ul)
                {
                    // Not possible.
                    DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
                    return STATUS_NOT_SUPPORTED;
                }
            }
            else
            {
                // Only 48000KHz possible.
                if (dwSampleRate != 48000ul)
                {
                    DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
                    return STATUS_NOT_SUPPORTED;
                }

                return STATUS_SUCCESS;
            }
            break;

        case AC97REG_FRONT_SAMPLERATE:
        case AC97REG_SURROUND_SAMPLERATE:
        case AC97REG_LFE_SAMPLERATE:
        case AC97REG_RECORD_SAMPLERATE:
            //
            // Variable sample rate supported?
            //
            if (GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED))
            {
                //
                // Check range supported
                //
                if (dwSampleRate > 48000ul)
                {
                    DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
                    return STATUS_NOT_SUPPORTED;
                }
            }
            else
            {
                // Only 48KHz possible.
                if (dwSampleRate != 48000ul)
                {
                    DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
                    return STATUS_NOT_SUPPORTED;
                }

                return STATUS_SUCCESS;
            }
            break;

        default:
            DOUT (DBG_ERROR, ("Invalid sample rate register!"));
            return STATUS_UNSUCCESSFUL;
    }

    
    //
    // Save the old sample rate register.
    //
    ntStatus = ReadCodecRegister (Register, &wOldRateReg);
    if (!NT_SUCCESS (ntStatus))
        return ntStatus;
    
    //
    // program the rate.
    //
    ntStatus = WriteCodecRegister (Register, (WORD)dwSampleRate, -1);
    if (!NT_SUCCESS (ntStatus))
    {
        DOUT (DBG_ERROR, ("Cannot program sample rate."));
        return ntStatus;
    }

    //
    // Read it back.
    //
    ntStatus = ReadCodecRegister (Register, &wCodecReg);
    if (!NT_SUCCESS (ntStatus))
    {
        DOUT (DBG_ERROR, ("Cannot read sample rate."));
        return ntStatus;
    }

    //
    // Validate.
    //
    if (wCodecReg != dwSampleRate)
    {
        //
        // restore sample rate and ctrl register.
        //
        WriteCodecRegister (Register, wOldRateReg, -1);
        
        DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
        return STATUS_NOT_SUPPORTED;
    }
    
    DOUT (DBG_VSR, ("Samplerate changed to %d.", dwSampleRate));
    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CAdapterCommon::PowerChangeState
 *****************************************************************************
 * Change power state for the device.  We handle the codec, PowerChangeNotify 
 * in the wave miniport handles the DMA registers.
 */
STDMETHODIMP_(void) CAdapterCommon::PowerChangeState
(
    IN  POWER_STATE NewState
)
{
    PAGED_CODE ();

    NTSTATUS ntStatus = STATUS_SUCCESS;

    DOUT (DBG_PRINT, ("[CAdapterCommon::PowerChangeNotify]"));

    //
    // Check to see if this is the current power state.
    //
    if (NewState.DeviceState == m_PowerState)
    {
        DOUT (DBG_POWER, ("New device state equals old state."));
        return;
    }

    //
    // Check the new device state.
    //
    if ((NewState.DeviceState < PowerDeviceD0) ||
        (NewState.DeviceState > PowerDeviceD3))
    {
        DOUT (DBG_ERROR, ("Unknown device state: D%d.", 
             (ULONG)NewState.DeviceState - (ULONG)PowerDeviceD0));
        return;
    }

    DOUT (DBG_POWER, ("Changing state to D%d.", (ULONG)NewState.DeviceState -
                    (ULONG)PowerDeviceD0));

    //
    // Switch on new state.
    //
    switch (NewState.DeviceState)
    {
        case PowerDeviceD0:
            //
            // If we are coming from D2 or D3 we have to restore the registers cause
            // there might have been a power loss.
            //
            if ((m_PowerState == PowerDeviceD3) || (m_PowerState == PowerDeviceD2))
            {
                //
                // Reset AD3 to indicate that we are now awake.
                // Because the system has only one power irp at a time, we are sure
                // that the modem driver doesn't get called while we are restoring
                // power.
                //
                WriteBMControlRegister (GLOB_STA,
                    ReadBMControlRegister32 (GLOB_STA) & ~GLOB_STA_AD3);

                //
                // Restore codec registers.
                //
                ntStatus = RestoreCodecRegisters ();
            }
            else        // We are coming from power state D1
            {
                ntStatus = PowerUpCodec ();
            }

            // Print error code.
            if (!NT_SUCCESS (ntStatus))
            {
                DOUT (DBG_ERROR, ("PowerChangeState failed to restore the codec."));
            }
            break;
    
        case PowerDeviceD1:
            //
            // This sleep state is the lowest latency sleep state with respect
            // to the latency time required to return to D0. If the 
            // driver is not being used an inactivity timer in portcls will 
            // place the driver in this state after a timeout period 
            // controllable via the registry.
            //
    
            // Let's power down the DAC/ADC's and analog mixer.

⌨️ 快捷键说明

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