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

📄 ac97.cpp

📁 ICEExt for Driver Studio3.2的sourcecode
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			call    si_DelayMilliSec                ; delays cuz codecs are slow

			pop     edx
			pop     eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// Set PCM Master Volume
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_SetMasterVolume( USHORT dwVolume )
{
    __asm
	{
			push    eax
			push    edx

			mov     ax, dwVolume
			mov     dx, ds:[NAMBAR]
			add     dx, CODEC_MASTER_VOL_REG         
			out     dx, ax

			mov     eax, 4
			call    si_DelayMilliSec                ; delays cuz codecs are slow

			pop     edx
			pop     eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// Set PCM Out Volume
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_SetPcmOutVolume( USHORT dwVolume )
{
    __asm
	{
			push    eax
			push    edx

			mov     ax, dwVolume
			mov     dx, ds:[NAMBAR]
			add     dx, CODEC_PCM_OUT_REG        
			out     dx, ax
  
			mov     eax, 4
			call    si_DelayMilliSec                ; delays cuz codecs are slow
  
			pop     edx
			pop     eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// register reset the DMA engine.  This may cause a pop noise on the output
// lines when the device is reset.  Prolly a better idea to mute output, then
// reset.
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_ResetDMA( VOID )
{
	__asm
	{
			push    eax
			push    edx

			mov     dx, ds:[NABMBAR]
			add     dx, PO_CR_REG                  ; set pointer to Cntl reg
			mov     al, RR                         ; set reset
			out     dx, al                         ; self clearing bit

 			pop	    edx
			pop     eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// The Last Valid Index register tells the DMA engine when to stop playing.
// input AL = index # to stop on
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_SetLastValidIndex( UCHAR dwLastIndex )
{
	__asm
	{
	    push    eax
	    push    edx

	    mov     al, dwLastIndex
	    mov	    dx, ds:[NABMBAR]
	    add	    dx, PO_LVI_REG
            out     dx, al
    	
	    pop	    edx
	    pop     eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// Returns current index value
//
///////////////////////////////////////////////////////////////////////////////////
ULONG ac97_GetCurrentIndex( VOID )
{
	ULONG val;

    __asm
	{
	    push    edx

	    xor     eax, eax
	    mov	    dx, ds:[NABMBAR]      		
	    add     dx, PO_CIV_REG
	    in	    al, dx
    	
	    pop	    edx

		mov     val, eax
	}

	return val;
}

///////////////////////////////////////////////////////////////////////////////////
//
// set the last valid index to something other than what we're currently
// playing so that we never end.
//
// this routine just sets the last valid index to 1 less than the index
// that we're currently playing, thus keeping it in and endless loop
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_SetNewIndex( VOID )
{
	__asm
	{
	    push    eax

            call    ac97_GetCurrentIndex            ; get CIV
            dec     al                              ; make new index <> current
            and     al, INDEX_MASK                  ; make sure new value is 0-31
            push    eax
            call    ac97_SetLastValidIndex          ; write new value

            pop	    eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// examines the CIV and the LVI.  When they're the same, we set LVI <> CIV
// that way, we never run out of buffers to play.
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_UpdateLVI( VOID )
{
	__asm
	{
	    push    eax
	    push    edx
     	    
            mov	    dx, ds:[NABMBAR]
            add     dx, PO_CIV_REG          ; read Current Index Value
            in      ax, dx                  ; and Last Valid Index value together.

            cmp     al, ah                  ; are we playing the last index?
            jnz     not_last                ; no, never mind

            call    ac97_SetNewIndex        ; set it to something else.

not_last:
     	    pop	    edx
	    pop	    eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// create Buffer Descriptor List
//
// A buffer descriptor list is a list of pointers and control bits that the
// DMA engine uses to know where to get the .wav data and how to play it.
//
// I set it up to use only 2 buffers of .wav data, and whenever 1 buffer is
// playing, I refresh the other one with good data.
//
//
// For the control bits, you can specify that the DMA engine fire an interrupt
// after a buffer has been processed, but I poll the current index register
// to know when it's safe to update the other buffer.
//
// I set the BUP bit, which tells the DMA engine to just play 0's (silence)
// if it ever runs out of data to play.  Good for safety.
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_CreateBDL( VOID )
{
	ULONG dwWavBuf1PhysAddr = (ULONG)MmGetPhysicalAddress(WAV_BUFFER1).QuadPart;
	ULONG dwWavBuf2PhysAddr = (ULONG)MmGetPhysicalAddress(WAV_BUFFER2).QuadPart;
	
	// setup 32 entries in BDL 
	for (int i = 0; i < 16; i++)
	{
		BDL_BUFFER[i*4+0] = dwWavBuf1PhysAddr; 
		BDL_BUFFER[i*4+1] = (WAV_BUFFER_SIZE / sizeof(USHORT)) | BUP | IOC; // set length to 32k samples.  1 sample is 16bits or 2bytes. 
		BDL_BUFFER[i*4+2] = dwWavBuf2PhysAddr; 
		BDL_BUFFER[i*4+3] = (WAV_BUFFER_SIZE / sizeof(USHORT)) | BUP | IOC; // set length to 32k samples.  1 sample is 16bits or 2bytes.
        }
}

///////////////////////////////////////////////////////////////////////////////////
//
// tell the DMA engine where to find our list of Buffer Descriptors.
// this 32bit value is a flat mode memory offset (ie no segment:offset)
//
// write NABMBAR+10h with offset of buffer descriptor list
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_SetBDLAddress( VOID )
{
        ULONG dwPhysAddr = (ULONG)MmGetPhysicalAddress(BDL_BUFFER).QuadPart;

	__asm
	{
	    push    eax
	    push    edx

            mov     eax, dwPhysAddr
            mov     dx, ds:[NABMBAR]
            add     dx, PO_BDBAR_REG                ; set pointer to BDL
            out     dx, eax                         ; write to AC97 controller

       	    pop	    edx
	    pop     eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// Let's play some music.
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_Play( VOID )
{
        __asm
	{
	    push    eax
	    push    edx

            mov     dx, ds:[NABMBAR]
            add     dx, PO_CR_REG                   ; DCM out control register
            mov     al, RPBM | LVBIE  
            out     dx, al                          ; set start!

	    pop	    edx
	    pop     eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// Stop player
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_Stop( VOID )
{
        __asm
	{
	    push    eax
	    push    edx

            mov     dx, ds:[NABMBAR]        ; finshed with song, stop everything
            add     dx, PO_CR_REG           ; DCM out control register
            mov     al, 0
            out     dx, al                  ; stop player

      	    pop	    edx
	    pop     eax
	}
}

///////////////////////////////////////////////////////////////////////////////////
//
// while DMA engine is running, examine current index and wait until it hits 1
// as soon as it's 1, we need to refresh the data in wavbuffer1 with another
// 64k.  Likewise when it's playing buffer 2, refresh buffer 1 and repeat.
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_Loop( VOID )
{
    while (1)
    {
        // wait while buffer1 is played than load it with new PCM data
        KeStallExecutionProcessor(10);
        while( (ac97_GetCurrentIndex() & BIT0) == 1 ) 
        {
//            ac97_UpdateLVI(); // set LVI != CIV
            if (si_ReadFromKbdBuffer_char() == KBD_ESC) return;
        }
        if (mp3_GetData(WAV_BUFFER1, WAV_BUFFER_SIZE) == -1) mp3_RestartStream();

        // wait while buffer2 is played than load it with new PCM data
        KeStallExecutionProcessor(10);
        while( (ac97_GetCurrentIndex() & BIT0) == 0 )
        {
//            ac97_UpdateLVI(); // set LVI != CIV
            if (si_ReadFromKbdBuffer_char() == KBD_ESC) return;
        }
        if (mp3_GetData(WAV_BUFFER2, WAV_BUFFER_SIZE) == -1) mp3_RestartStream();
    }
}

⌨️ 快捷键说明

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