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

📄 hwctxt.cpp

📁 老外的一个开源项目
💻 CPP
📖 第 1 页 / 共 4 页
字号:

        RegCloseKey(hDevKey);
    }

    return (TRUE);   
}

DWORD HardwareContext::GetInterruptThreadPriority()
{

//    HKEY hDevKey;
//    DWORD dwValType;
//    DWORD dwValLen;
    DWORD dwPrio = 249; // Default priority
/*    hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
    if (hDevKey)
    {
        dwValLen = sizeof(DWORD);
        RegQueryValueEx(
            hDevKey,
            TEXT("Priority256"),
            NULL,
            &dwValType,
            (PUCHAR)&dwPrio,
            &dwValLen);
        RegCloseKey(hDevKey);
    }
*/
    return dwPrio;
}


BOOL HardwareContext::InitInterruptThread()
{
    DEBUGMSG(ZONE_INIT, (TEXT("+InitInterruptThread\r\n")));

    m_hAudioInputInterruptThread  = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
                                            0,
                                            (LPTHREAD_START_ROUTINE)CallInputInterruptThread,
                                            this,
                                            0,
                                            NULL);
    m_hAudioOutputInterruptThread  = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
                                            0,
                                            (LPTHREAD_START_ROUTINE)CallOutputInterruptThread,
                                            this,
                                            0,
                                            NULL);

    if (!m_hAudioInputInterruptThread)
    {
        return FALSE;
    }

    if (!m_hAudioOutputInterruptThread)
    {
        return FALSE;
    }
   

    // Bump up the priority since the interrupt must be serviced immediately.
    CeSetThreadPriority(m_hAudioInputInterruptThread, GetInterruptThreadPriority());
    CeSetThreadPriority(m_hAudioOutputInterruptThread, GetInterruptThreadPriority());

    DEBUGMSG(ZONE_INIT, (TEXT("-InitInterruptThread\r\n")));
    return TRUE;
}

BOOL HardwareContext::Deinit()
{
    DEBUGMSG(ZONE_INIT, (TEXT("HardwareContext::Deinit\r\n")));

    m_audioDeinit = TRUE;
    
    StopOutputDMA();
    StopInputDMA();
    
    UnmapDMA();


    //Power down Codec and  shutdown the AClink
    PowerDown();
    DeInitAC97(FALSE);

    DeinitAudioDMA();
        
    UnMapDeviceRegisters();

    m_Initialized = FALSE;
    return TRUE;
}

ULONG HardwareContext::TransferInputBuffer(ULONG NumBuf)
{
    ULONG BytesTransferred;
    PBYTE pBufferStart = m_Input_pbDMA_PAGES[NumBuf];
    PBYTE pBufferEnd = pBufferStart + AUDIO_BUFFER_SIZE;
    PBYTE pBufferLast;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("TransferInputBuffer %d"), NumBuf));

    pBufferLast = m_InputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
    BytesTransferred = pBufferLast-pBufferStart;

    return BytesTransferred;
}

ULONG HardwareContext::TransferOutputBuffer(ULONG NumBuf)
{
    ULONG BytesTransferred;
    PBYTE pBufferStart = m_Output_pbDMA_PAGES[NumBuf];
    PBYTE pBufferEnd = pBufferStart + AUDIO_BUFFER_SIZE;
    PBYTE pBufferLast;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("TransferOutputBuffer %d\r\n"), NumBuf));

    pBufferLast = m_OutputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
    BytesTransferred = pBufferLast-pBufferStart;

    // AC'97 Controller will transmit data in multiple of 32 bytes only.
    // The trailing bytes will not be transmitted.
    // So we pad the buffer with zeroes to a multiple of 32 bytes.
    if(int pad = (BytesTransferred % 32))
    {
        // number of bytes to pad
        pad = 32 - pad;
        StreamContext::ClearBuffer(pBufferLast, pBufferLast+pad);
        BytesTransferred += pad;
    }

    // Set DMA transfer length based on actual data in buffer.
    // Also set STOP bit if it is the last buffer (ie. zero length buffer).
    if(NumBuf == 0)
    {
        m_vpAudioXmitA->DCMD = DMAC_AC97_XMITAB_CMD_MASK | BytesTransferred;

        if(BytesTransferred)
        {
            m_vpAudioXmitA->DDADR &= ~DESC_ADDRESS_STOP_MASK;
        }
        else
        {
            m_vpAudioXmitA->DDADR |= DESC_ADDRESS_STOP_MASK;
        }
    }
    else
    {
        m_vpAudioXmitB->DCMD = DMAC_AC97_XMITAB_CMD_MASK | BytesTransferred;

        if(BytesTransferred)
        {
            m_vpAudioXmitB->DDADR &= ~DESC_ADDRESS_STOP_MASK;
        }
        else
        {
            m_vpAudioXmitB->DDADR |= DESC_ADDRESS_STOP_MASK;
        }
    }

    DEBUGMSG(ZONE_VERBOSE, (TEXT("Fill buffer[%d]: 0x%x\r\n"), NumBuf, BytesTransferred));

    return BytesTransferred;
}

VOID HardwareContext::GetInterruptType()
{
    DWORD dwDCSR;
    DWORD dwDINT;

    dwDINT = m_pDMARegisters->DINT;
    DEBUGMSG(ZONE_VERBOSE, (TEXT( "HardwareContext::GetInterruptType: DINT=0x%x\r\n" ), dwDINT));

    if(dwDINT & DMAC_AC97AUDIORCV)
    {
        //
        // I N P U T
        //
        dwDCSR  = m_pDMARegisters->DCSR[m_RecordingChannel];
        DEBUGMSG(ZONE_VERBOSE, (TEXT( "GetInterruptType: RCV DCSR: 0x%x\r\n" ),dwDCSR));

        // Provide waiting Object the current value of DCSR
        // SetEventData(hInputIntEvent, dwDCSR);

        //did we get an input error?
        if (dwDCSR & DCSR_BUSERRINTR)
        {
            DEBUGMSG(ZONE_ERROR, (TEXT( "DCSR_BUSERRINTR ERROR on input\r\n" )) );
            DEBUGCHK(0);  // an unplanned dma interrupt occured 
            DumpDmacRegs();
        }
    
        //did we get an input start interrupt?
        if (dwDCSR & DCSR_STARTINTR)  
        {
            DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_STARTINTR on input\r\n" )) );
            DEBUGCHK(0); // an unplanned dma interrupt occured 
        }
    
        //did we get an input end interrupt?
        if (dwDCSR & DCSR_ENDINTR)  //if the input channel stopped at the end of a buffer xfer
        {
            DEBUGMSG(ZONE_ERROR, (TEXT( "DCSR_ENDINTR on intput\r\n" )) );
        }

        //did we get an input stop interrupt?
        if (dwDCSR & DCSR_STOPINTR)  
        {
            DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_STOPINTR on input\r\n" )) );
            dwDCSR &= ~DCSR_STOPIRQEN;
            DEBUGCHK(0); // an unplanned dma interrupt occured 
        }

        // Clear the status
        m_pDMARegisters->DCSR[m_RecordingChannel] = dwDCSR;

        SetEvent(hInputIntEvent);
    }

    if(dwDINT & DMAC_AC97AUDIOXMIT)
    {
        //
        // O U T P U T
        //
        dwDCSR  = m_pDMARegisters->DCSR[m_PlaybackChannel];
        DEBUGMSG(ZONE_VERBOSE, (TEXT( "GetInterruptType: OUT DCSR: 0x%x\r\n" ),dwDCSR));

        // Provide waiting Object the current value of DCSR
        // SetEventData(hOutputIntEvent, dwDCSR);

        //did we get an output error?
        if (dwDCSR & DCSR_BUSERRINTR)
        {
            DEBUGMSG(ZONE_ERROR, (TEXT( "DCSR_BUSERRINTR ERROR on output\r\n" )) );
            DumpDmacRegs();

            //note if we get here, we have a lot more to do than clear the interrupt.
            DEBUGCHK(0); // an unplanned dma interrupt occured 
        }

        //did we get an output start interrupt?
        if (dwDCSR & DCSR_STARTINTR)   
        {
            DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_STARTINTR on output\r\n" )) );
        }

        //did we get an output end interrupt?
        if (dwDCSR & DCSR_ENDINTR)      //if the out channel stopped at the end of a buffer xfer
        {       
            DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_ENDINTR on output\r\n" )) );
        }

        //did we get an output stop interrupt?
        if (dwDCSR & DCSR_STOPINTR)  
        {
            DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_STOPINTR on output\r\n" )) );
            dwDCSR &= ~DCSR_STOPIRQEN;

            m_OutputDMARunning = FALSE;
        }

        // Clear the status
        m_pDMARegisters->DCSR[m_PlaybackChannel] = dwDCSR;

        SetEvent(hOutputIntEvent);
    }

    return;
}


void HardwareContext::InterruptThread()
{
    while (TRUE)
    {
        WaitForSingleObject(m_hAudioInterrupt,  INFINITE);
        if (TRUE == m_audioDeinit)
        {
            return;
        }

        // Grab the lock
        Lock();

        GetInterruptType();

        Unlock();
        
        InterruptDone(m_SysIntrAudioDMA);

    }  // while(TRUE)

}

void CallInterruptThread(HardwareContext *pHWContext)
{
    DEBUGMSG(ZONE_INIT, (TEXT("CallInterruptThread")));
    pHWContext->InterruptThread();
}

void CallInputInterruptThread(HardwareContext *pHWContext)
{
    DEBUGMSG(ZONE_INIT, (TEXT("CallInputInterruptThread")));
    pHWContext->InputInterruptThread();
}

void CallOutputInterruptThread(HardwareContext *pHWContext)
{
    DEBUGMSG(ZONE_INIT, (TEXT("CallOutputInterruptThread")));
    pHWContext->OutputInterruptThread();
}

void HardwareContext::InputInterruptThread( )
{
    ULONG InputTransferred;

    DEBUGMSG(ZONE_INIT, (TEXT("InputInterruptThread")));

    while (TRUE)
    {
        WaitForSingleObject(hInputIntEvent,  INFINITE);
        if (TRUE == m_audioDeinit)
        {
            return;
        }

        DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_ENDINTR on intput\r\n" )) );
        Lock();

        int buffer = GetLastInputBuffer();
        InputTransferred = TransferInputBuffer(buffer);

        if( InputTransferred==0 )
        {
            StopInputDMA();
        }
        Unlock();
    }
}

void HardwareContext::OutputInterruptThread( )
{
    DEBUGMSG(ZONE_INIT, (TEXT("OutputInterruptThread")));

    while (TRUE)
    {
        WaitForSingleObject(hOutputIntEvent,  INFINITE);
        if (TRUE == m_audioDeinit)
        {
            return;
        }
                 
        DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_ENDINTER on output\r\n" )) );
        Lock();

        int buffer = GetNextOutputBuffer();
        ULONG Bytes = TransferOutputBuffer(buffer);

        if(!m_OutputDMARunning)
	{
            if(Bytes)
            {
                // More data to play. Restart DMA engine by loading the descriptor
	        // address reg to initialize DMA, pointing to the buffer just loaded.
                m_pDMARegisters->DDG[m_PlaybackChannel].DDADR =
                    (buffer == 0) ? (UINT32)m_vpAudioXmitA_Physical : (UINT32)m_vpAudioXmitB_Physical;;
                
                // Set the RUN bit and also enable STOPINTR so that we know DMA is done
                // on last buffer. A zero length buffer is considered the last buffer.
                m_pDMARegisters->DCSR[m_PlaybackChannel] |=  DCSR_RUN | DCSR_STOPIRQEN;
                m_OutputDMARunning=TRUE;
            }
            else
            {
                // No more data to play. Will stop when the previous buffer
	        //StopOutputDMA();
            }
 	}

        Unlock();
    }
}

BOOL HardwareContext::TestAcLink()
{
    BOOL RetVal=TRUE;

    int i;

    unsigned short int Value;

    for (i=0;i<0x80;i+=2)
    {
        SafeReadAC97(i, &Value);
        RETAILMSG(1, (TEXT( "register::value %x %x" ),i,Value ));
    }

    return (RetVal);
}

//------------------------------------------------------------------------------------------------------------
// Function: FillDescriptors
// 
// Purpose: Fill the descriptors with appropriate data
//
// Note: This code could be cleaner, but I want to be explicit on the programming of descriptors
//
//-------------------------------------------------------------------------------------------------------------
BOOL HardwareContext::FillOutputDescriptors( void )
{
    union DmaCmdReg     CmdBuff;
    memset (&CmdBuff,0, sizeof (CmdBuff));

        // set individual bit fields to for debug.  

#define USE_BITFIELD
#ifdef USE_BITFIELD  
        
        // set values with bit fields
        CmdBuff.DcmdReg.len = AUDIO_BUFFER_SIZE;  //length of memory buffer
        CmdBuff.DcmdReg.width = 0x3;    // binary 11 (see quick Quick Reference sheet to DMA programming in the cotulla EAS)
        CmdBuff.DcmdReg.size = 0x3;     // binary 11 
        CmdBuff.DcmdReg.endian = 0;     // little endian
        CmdBuff.DcmdReg.flybyt = 0;     // Flowthrough
        CmdBuff.DcmdReg.flybys = 0;     // Flowthrough
        CmdBuff.DcmdReg.endirqen = 1;   // 1 means Interrupt when decrement length = 0;
        CmdBuff.DcmdReg.startirqen = 0; // 1 means Interrupt when the desc is loaded
        CmdBuff.DcmdReg.flowtrg = 1;    // 1 means the target is an external peripheral
        CmdBuff.DcmdReg.flowsrc = 0;    // 1 means the source is an external peripheral (and needs flow con
        CmdBuff.DcmdReg.inctrgadd = 0;  // 1 means increment the target address (since it's memory) 
        CmdBuff.DcmdReg.incsrcadd = 1;  // 1 means increment the source address (since it's a peripheral)
#else  
        // set value based on masks
        CmdBuff.DcmdDword = DMAC_AC97_XMITAB_CMD_MASK | AUDIO_BUFFER_SIZE; 
#endif

        //
        // fill XmitA Descriptor
        //

        m_vpAudioXmitA->DDADR= (UINT32)m_vpAudioXmitB_Physical ;             // address of the next (XmitB) descriptor
        m_vpAudioXmitA->DTADR=  DMAC_AC97_AUDIO_XMIT_FIFO;                   // source address of the AC97 XmitA buffer

⌨️ 快捷键说明

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