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

📄 aaci_audio.c

📁 此压缩包为杰得开发得z228的BSP的源代码,可以实现很多功能,尤其是视频解码有很好的效果.
💻 C
📖 第 1 页 / 共 5 页
字号:
//  This routine is called when the driver
//  is being unloaded. Free up memory, etc.
//---------------------------------------------------------
VOID AACI_Deinitialize(VOID)
{
    FUNC_WPDD("+AACI_Deinitialize");

    if( g_AudioRegBase )
    {
        // Disable AACI functionality
        AACI_RegWrite32( AACIReg_MainControl, 0 );

        // Unmap hardware register space
        MmUnmapIoSpace( g_AudioRegBase, AACI_HWREGS_SIZE );
    }
	OnDeinit();
    FUNC_WPDD("-AACI_Deinitialize");
}

//---------------------------------------------------------
//   ULONG AACI_GetVolume(VOID)
//
//   Returns the digital volume to the caller
//---------------------------------------------------------
ULONG AACI_GetVolume(VOID)
{
RETAILMSG( DBG_AACI, (TEXT("AACI_GetVolume()\r\n")));	
    MISC1("AACI_GetVolume: 0x%08x", g_nVolume);

    return g_nVolume;
}
FILE* fp = NULL; // for test
//---------------------------------------------------------
//   VOID AACI_SetVolume(ULONG)
//
//   Sets the digital volume based on the value sent by the caller
//---------------------------------------------------------
#define DEFAULT_MINI_VOLUME 4
VOID AACI_SetVolume(ULONG Vol)
{
	USHORT rVol, lVol, codecVol;
	UCHAR rIdx, lIdx;

	g_nVolume = Vol;
	RETAILMSG( 0, (TEXT("Vol (size=%d)\n"),Vol) ); 

	// Extract top 5 MSBs from Left and Right channel volumes
	rIdx = (UCHAR)((Vol & 0xF8000000) >> (32 - 5));//高5位
	lIdx = (UCHAR)((Vol & 0x0000F800) >> (16 - 5));//中间五位 

	RETAILMSG( DBG_AACI, (TEXT("AACI_SetVolume()\r\n")));	
    
	// Convert to CODEC volume range
	// NOTE: Swap L & R as output is reversed on Versatile
	lVol = VolumeLUT[rIdx];//总共有32档2的5次方 --总共32档
	rVol = VolumeLUT[lIdx];//总共有32档2的5次方 --总共32档

	RETAILMSG( 0, (TEXT("lIdx (size=%d)\n"),lIdx) ); 
	RETAILMSG( 0, (TEXT("rIdx (size=%d)\n"),rIdx) ); 
	RETAILMSG( 0, (TEXT("lVol (size=%d)\n"),lVol) );
	RETAILMSG( 0, (TEXT("rVol (size=%d)\n"),rVol) );

	// Create CODEC data packet
    codecVol = (rVol) | (lVol << 8);//写声卡寄存器

	// Check for mute volume setting on both channels, and convert to 
	//  complete mute
	if ( codecVol == LM4549A_MUTEVOL_RL )//这个成立则对应 LOUT2/ROUT2  VOL =100000--这种情况衰减倍数太多基本就没有输出,所以可以直接关掉
		codecVol = LM4549A_BIT_VOLUME_MUTE;

	MISC2("AACI_SetVolume: MSFT:0x%08x, CODEC:0x%04x", Vol, codecVol);
	Volume = codecVol;

	//add junxz 调整到最小音量不为最大的bug
	//当音量小于一定的值时就关掉功放
	if(lIdx  < DEFAULT_MINI_VOLUME || rIdx < DEFAULT_MINI_VOLUME)
	{
		AACI_CodecWrite16( 0x18, 0xe000 );
		//AACI_RegWrite32( AACIReg_Slot12Tx, 0x00000 );
		//AACI_RegWrite32( AACIReg_Slot12Tx, (AACI_CodecRead16(0x54)&(~0x07)) <<4);
		//SET_SLOT12_FALSE;
		set_pa_off();
	}
	else
	{
		if(lout&&playflags)
		{
			if(TRUE==leftout)
			{
				AACI_CodecWrite16( 0x18, 0xa000 );
			}
			else
			{
				AACI_CodecWrite16( 0x18, AACI_CodecRead16(0x18)|0x001d);
			}
			//AACI_RegWrite32( AACIReg_Slot12Tx, (AACI_CodecRead16(0x54)|0x07) <<4 );
			//SET_SLOT12_TRUE;
			set_pa_on();
		}
		else if(headphone&&playflags)
		{
			AACI_CodecWrite16( 0x18, 0x4000);
		}
	}

	if(lout&&playflags)//如果当前是用喇叭并且当前是在播放
		AACI_CodecWrite16( 0x02, Volume&0x7fff );//控制喇叭寄存器(通过0x02控制音量)
	else
		AACI_CodecWrite16( 0x02, Volume|0x8000 );//控制喇叭寄存器(通过0x02控制音量)

	if(headphone&&playflags)//如果当前是用耳机并且当前是在播放
		AACI_CodecWrite16( 0x04, Volume&0x7fff );//控制喇叭寄存器(通过0x02控制音量)
	else
		AACI_CodecWrite16( 0x04, Volume|0x8000 );//控制喇叭寄存器(通过0x02控制音量)
	
}

//---------------------------------------------------------
//   VOID AACI_LeftSound(WAPI_INOUT)
//
//   Sets WAPI_OUT or WAPI_IN to set left speaker on or off 
//---------------------------------------------------------
void AACI_LeftSound(WAPI_INOUT apidir)
{
	if((WAPI_OUT == apidir)&&(headphone!=TRUE)) // off left speaker
	{
		if(fp)fprintf(fp, "off left speaker\n");
		leftout = FALSE;
		AACI_CodecWrite16(0x02, AACI_CodecRead16(0x02)|0x001f);
		RETAILMSG( 0, (TEXT("AACI_LeftSound() -> OFF AACI_CodecRead16(0x18)=0x%x\r\n"), AACI_CodecRead16(0x18)) ); 
	}
	else if((WAPI_IN == apidir)&&(headphone!=TRUE)) // on left speaker
	{
		if(fp)fprintf(fp, "on left speaker\n");
		leftout = TRUE;
		//for test
		AACI_CodecWrite16(0x02, AACI_CodecRead16(0x02)&(~0x001f)); // modify by he
		//AACI_CodecWrite16(0x02, Volume);
		RETAILMSG( 0, (TEXT("AACI_LeftSound() -> ON  AACI_CodecRead16(0x18)=0x%x\r\n"), AACI_CodecRead16(0x18)) );		
	}
}

// -----------------------------------------------------------------------------
//
//   AUDIO_STATE AACI_GetInterruptType(VOID)
//
//   Called by the driver's ISR.
//   Returns the state of the stream being Played/Recorded.
// -----------------------------------------------------------------------------
AUDIO_STATE AACI_GetInterruptType(VOID)
{
    AUDIO_STATE asResult = AUDIO_STATE_IGNORE;
    ULONG ulStatus;
	
#ifdef TEST_API
    if( !g_fTesting )
    {
#endif
        ulStatus = AACI_RegRead32( AACIReg_Channel1IntStatus );

        // check WAPI_IN first
        if( g_dwRunMode[WAPI_IN] == RUNMODE_RUNNING )
        {
            if( gv_fMoreData[WAPI_IN] )
            {
                if( ulStatus & AACIBit_RxIE )
                {
                    asResult |= AUDIO_STATE_IN_RECORDING;
                }
                else if( AACI_RegRead32( AACIReg_Channel1Status ) & 
                         AACIBit_RXFIFOHalfFull )
                {
                    // No obvious interrupt, but channel status shows half 
                    //  full, so report recording
                    asResult |= AUDIO_STATE_IN_RECORDING;
                    
                    WRNMSG1("AACI_GetInterruptType: Receive status halffull but no interrupt!");
                }
            }
            else
            {
                // Signal end of recording
                asResult |= AUDIO_STATE_IN_STOPPED;
                g_dwRunMode[WAPI_IN] = RUNMODE_STOPPING;
#ifdef AACI_STATS
                MISC1( "AACI_GetInterruptType: Stopping receive - no more data (read %d bytes)", 
                        g_dwBytesRecorded[WAPI_IN] );
#endif
            }
        }
        else
        {
            if( ulStatus & (AACIBit_RxIE | AACIBit_RxOIE | 
                            AACIBit_RxTIE | AACIBit_RxTOIE) )
            {
                // Getting receive interrupts when not running - disable them
                VERBOSEMSG("AACI_GetInterruptType: Disabling Receive interrupts as not running");
                AACI_RegWrite32( AACIReg_Channel1IntEnable, 
                                AACI_RegRead32( AACIReg_Channel1IntEnable ) & 
                                ~(AACIBit_RxIE | AACIBit_RxOIE | 
                                  AACIBit_RxTIE | AACIBit_RxTOIE) );
            }
        }

        // check WAPI_OUT
        if( g_dwRunMode[WAPI_OUT] == RUNMODE_RUNNING )
        {
			//RETAILMSG( 1 , (TEXT("aaci : query interrupt \r\n")));
			//if( DmaCmd == DMA_CMD_START )
			asResult |= AUDIO_STATE_OUT_PLAYING;			
        }
        else
        {
            if( ulStatus & (AACIBit_TxCIE | AACIBit_TxIE | AACIBit_TxUIE) )
            {
                // Getting transmit interrupts when not running - disable them
                VERBOSEMSG("AACI_GetInterruptType: Disabling Transmit interrupts as not running");
                AACI_RegWrite32( AACIReg_Channel1IntEnable, 
                                 AACI_RegRead32( AACIReg_Channel1IntEnable ) & 
                                 ~(AACIBit_TxCIE | AACIBit_TxIE | AACIBit_TxUIE) );
            }
        }

#ifdef TEST_API
    }
    else
    {
        // Just TESTING... Save the interrupt status for the tests
        g_dwTestIntStatus = AACI_RegRead32( AACIReg_Channel1IntStatus );

        TESTMSG2("AACI_GetInterruptType: ints=0x%08x, status=0x%04x", 
                g_dwTestIntStatus, AACI_RegRead32(AACIReg_Channel1Status));

        // Disable any other interrupts (clears the interrupt status)
        if( g_fTestIntDisable ) AACI_RegWrite32( AACIReg_Channel1IntEnable, 0 );

        // Wake up any tests waiting for an interrupt
        SetEvent( g_hTestInterrupt );
    }
#endif

    return asResult;
}


// -----------------------------------------------------------------------------
// FIFO operations
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// Hardware (CODEC and AACI) operations
// -----------------------------------------------------------------------------

// Internal function to send raw data to the codec
static VOID CodecSend( ULONG raw_codec_reg, ULONG raw_codec_data )
{
    // First check that the AACISLxTX registers are empty
    TESTWAIT(!( AACI_RegRead32(AACIReg_SlotFlag) & 
               (AACIBit_Slot1TXEmpty | AACIBit_Slot2TXEmpty)), 
             "Slot1TXEmpty | Slot2TXEmpty")

    AACI_RegWrite32( AACIReg_Slot2Tx, raw_codec_data );
    AACI_RegWrite32( AACIReg_Slot1Tx, raw_codec_reg );
	
    // Pause so that slots can be transmitted
    Sleep(1);

    // Wait till slots 1&2 transmit complete
    TESTWAIT(AACI_RegRead32(AACIReg_SlotFlag) & 
             (AACIBit_Slot1TXBusy | AACIBit_Slot2TXBusy), 
             "Slot1TXBusy | Slot2TXBusy")

    // Pause here for the operation to complete on the CODEC, i.e. wait for 
    //  data to be returned or CODEC registers to be updated depending on 
    //  read or write
    Sleep(1);
}


#define WM9712_WRITE 1
#define WM9712_READ 0

//-----------------------------------------------------------------------
//
//  USHORT AACI_CodecRead16( USHORT codec_reg )
//
//  Reads data from the CODEC
//
//-----------------------------------------------------------------------
USHORT AACI_CodecRead16( USHORT codec_reg )
{
#ifdef WAV_DEBUG
	USHORT ret;
	USHORT data = codec_reg;
	ULONG size;
	if(hd_9712 != INVALID_HANDLE_VALUE)
		DeviceIoControl(hd_9712, WM9712_READ, (BYTE*)&data, sizeof(USHORT), &ret, NULL, &size, NULL);  
	return ret;
#else
	ENTERMUTEX;	
	
    // Tell the codec we are trying to read a register
    CodecSend( (((ULONG)codec_reg) << 12) | AACIBit_Slot1Tx_Read, (ULONG)0 );

    // Check if LM4549 has returned requested value
    TESTWAIT(!( AACI_RegRead32( AACIReg_SlotFlag ) & AACIBit_Slot2RXValid ), 
             "Slot2RXValid")
	RELEASEMUTEX;
	
    return( (USHORT)(AACI_RegRead32( AACIReg_Slot2Rx ) >> 4) );
#endif    
}


typedef struct 
{
	USHORT reg;
	USHORT data;
} PARA, *pPARA;
//-----------------------------------------------------------------------
//
//  void AACI_CodecWrite16( USHORT codec_reg, USHORT codec_data  )
//
//  Writes data to the CODEC
//
//-----------------------------------------------------------------------
VOID AACI_CodecWrite16( USHORT codec_reg, USHORT codec_data )
{
#ifdef WAV_DEBUG
	int ret;
	PARA para;
	para.reg = codec_reg;
	para.data = codec_data;
	if(hd_9712 != INVALID_HANDLE_VALUE)
		DeviceIoControl(hd_9712, WM9712_WRITE, (BYTE*)&para, sizeof(PARA), &ret, NULL, NULL, NULL);  
	
#else	
	ENTERMUTEX;	
	CodecSend( (((ULONG)codec_reg) << 12), (((ULONG)codec_data) << 4) );
	RELEASEMUTEX;
#endif
}

//-----------------------------------------------------------------------
//   VOID AACI_RegWrite32 (USHORT reg, ULONG val)
//
//   Writes 32 bits to the 5530/5540 I/O port
//-----------------------------------------------------------------------
VOID AACI_RegWrite32(USHORT reg, ULONG val)
{
    PULONG reg_loc;

    reg_loc  = (PULONG)(g_AudioRegBase + reg);
    *reg_loc = val;
}

//-----------------------------------------------------------------------
//   ULONG AACI_RegRead32(USHORT reg)
//
//   Reads 32 bits from the 5530/5540 I/O port
//-----------------------------------------------------------------------
ULONG AACI_RegRead32(USHORT reg)
{
    PULONG reg_loc;
    ULONG val;

    reg_loc  = (PULONG)(g_AudioRegBase + reg);
    val      = *reg_loc;
    return( val );
}


// -----------------------------------------------------------------------------
// Clear FIFO Functions
// -----------------------------------------------------------------------------

// Clear the FIFO by enabling transmit, waiting for it to empty then 
//  disabling transmit
static BOOL ClearTransmitFIFO()
{
    DWORD dwStatus, dwCount = 0;

    // Make sure FIFO is enabled
    AACI_RegWrite32( AACIReg_Channel1TxControl, 
                     AACI_RegRead32(AACIReg_Channel1TxControl) | 
                     AACIBit_EnableFIFO );
    Sleep(10);
    
    // Wait till not busy
    dwStatus = AACI_RegRead32(AACIReg_Channel1Status);
    while( (dwCount < 10) && (dwStatus & AACIBit_TXFIFOBusy) )
    {
        // Check for any flagged interrupts (and clear them if need be)
        if( (dwStatus & AACIBit_TXUnderrun) && !(dwStatus & AACIBit_TXFIFOEmpty) )
        {
            ERRMSG("Underrun occurred (FIFO not empty)");
            AACI_RegWrite32( AACIReg_IntClear, AACIBit_TxUEC1 );
        }
        Sleep(50);

⌨️ 快捷键说明

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