📄 hwctxt.cpp
字号:
// WM9713 Need This !!!!
WriteCodecRegister(WM9713_POWER_CONTROL, 0x1000);
AC97_enable_codec_ready_interrupt();
AC97_enable_ACLink_data_transfer();
AC97_wait_for_codec_ready();
AC97_disable_all_interrupt();
AC97_clear_all_interrupt();
AC97_set_pcmout_transfer_mode(AC97_CH_OFF);
AC97_set_pcmin_transfer_mode(AC97_CH_OFF);
WAV_MSG((_T("[WAV] --InitAC97() \n\r")));
return TRUE;
}
BOOL
HardwareContext::InitCodec()
{
USHORT CodecVendorID0, CodecVendorID1;
BOOL bRet = TRUE;
WAV_MSG((_T("[WAV] ++InitCodec()\n\r")));
WriteCodecRegister(WM9713_POWER_CONTROL, 0x0000);
WriteCodecRegister(WM9713_POWERDOWN1, 0x0000);
WriteCodecRegister(WM9713_POWERDOWN2, 0x0000);
WriteCodecRegister(WM9713_MCLK_PLL_CTRL0, 0x0b80);
WriteCodecRegister(WM9713_HEADPHONE_VOL, 0x0808); // Unmute HPL, HPR
WriteCodecRegister(WM9713_DAC_VOL_ROUTING, 0x6404); // Unmute DAC to HPMix, SPKMix, MONOMix, 0 dB
WriteCodecRegister(WM9713_OUTPUT_MUX, 0x00a0); // Output HPL, HPR is HPMix, All others is Vmid
WriteCodecRegister(WM9713_RECORD_ROUTING_MUX, 0xd652); // Record Mux Source is LineIn, +20dB
WriteCodecRegister(WM9713_RECORD_VOL, 0x0000); // Unmute ADC input
WriteCodecRegister(WM9713_ADDITIONAL_FUNC2, 0x0080); // AC97_ADDITIONAL_FUNC2 // Set DAC Auto-Mute, bit[1:0]=00, ADC Slot(L/R=3/4)
WriteCodecRegister(WM9713_EXTED_AUDIOCTRL, 0x0031); // bit[5:4]=11, SPDIF Output Slot(L/R=10/11), VRA Enabled
//------------------------------------------------------------------------------
// If using sampling rate other than 48KHz you must enable VRA before set sampling rate !!!!!
//------------------------------------------------------------------------------
WriteCodecRegister(WM9713_AUDIO_DAC_RATE, SAMPLERATE); // 2Ch DAC Sample rate
WriteCodecRegister(WM9713_AUDIO_ADC_RATE, SAMPLERATE); // 32h ADC Sample rate
WriteCodecRegister(WM9713_AUX_DAC_RATE, SAMPLERATE); // AC97_AUXDAC_RATE // 2Eh AUXDAC Sample rate
CodecMuteControl(DMA_CH_OUT | DMA_CH_IN, FALSE); // output, Input Mute
CodecPowerControl(); // ADC, DAC Power Off
CodecVendorID0 = ReadCodecRegister(WM9713_VENDOR_ID1);
CodecVendorID1 = ReadCodecRegister(WM9713_VENDOR_ID2);
if (CodecVendorID0 != 0x574d || CodecVendorID1 != 0x4c13)
{
// 0x574D4C13 is VenderID of WM9713 Codec
WAV_ERR((_T("[WAV:ERR] InitCodec() : VenderID Mismatch\n\r")));
bRet = FALSE;
}
WAV_INF((_T("[WAV:INF] InitCodec() : VenderID = 0x%08x\n\r"), ((CodecVendorID0<<16) | CodecVendorID1)));
WAV_MSG((_T("[WAV] --InitCodec()\n\r")));
return bRet;
}
BOOL
HardwareContext::InitOutputDMA()
{
BOOL bRet = TRUE;
WAV_MSG((_T("[WAV] ++InitOutputDMA()\n\r")));
if (!g_PhyDMABufferAddr.LowPart)
{
WAV_ERR((_T("[WAV:ERR] InitOutputDMA() : DMA Buffer is Not Allocated Yet\n\r")));
bRet = FALSE;
goto CleanUp;
}
bRet = DMA_request_channel(&g_OutputDMA, DMA_AC97_PCMOUT);
if (bRet)
{
DMA_initialize_channel(&g_OutputDMA, TRUE);
DMA_set_channel_source(&g_OutputDMA, m_OutputDMABufferPhyPage[0], WORD_UNIT, BURST_1, INCREASE);
DMA_set_channel_destination(&g_OutputDMA, AC97_get_pcmout_physical_buffer_address(), WORD_UNIT, BURST_1, FIXED);
DMA_set_channel_transfer_size(&g_OutputDMA, AUDIO_DMA_PAGE_SIZE);
DMA_initialize_LLI(&g_OutputDMA, 2);
DMA_set_LLI_entry(&g_OutputDMA, 0, LLI_NEXT_ENTRY, m_OutputDMABufferPhyPage[0],
AC97_get_pcmout_physical_buffer_address(), AUDIO_DMA_PAGE_SIZE);
DMA_set_LLI_entry(&g_OutputDMA, 1, LLI_FIRST_ENTRY, m_OutputDMABufferPhyPage[1],
AC97_get_pcmout_physical_buffer_address(), AUDIO_DMA_PAGE_SIZE);
DMA_set_initial_LLI(&g_OutputDMA, 1);
}
CleanUp:
WAV_MSG((_T("[WAV] --InitOutputDMA()\n\r")));
return bRet;
}
BOOL HardwareContext::InitInputDMA()
{
BOOL bRet = TRUE;
WAV_MSG((_T("[WAV] ++InitInputDMA()\n\r")));
if (!g_PhyDMABufferAddr.LowPart)
{
WAV_ERR((_T("[WAV:ERR] InitInputDMA() : DMA Buffer is Not Allocated Yet\n\r")));
bRet = FALSE;
goto CleanUp;
}
bRet = DMA_request_channel(&g_InputDMA, DMA_AC97_PCMIN);
if (bRet)
{
DMA_initialize_channel(&g_InputDMA, TRUE);
DMA_set_channel_source(&g_InputDMA, AC97_get_pcmin_physical_buffer_address(), WORD_UNIT, BURST_1, FIXED);
DMA_set_channel_destination(&g_InputDMA, m_InputDMABufferPhyPage[0], WORD_UNIT, BURST_1, INCREASE);
DMA_set_channel_transfer_size(&g_InputDMA, AUDIO_DMA_PAGE_SIZE);
DMA_initialize_LLI(&g_InputDMA, 2);
DMA_set_initial_LLI(&g_InputDMA, 1);
DMA_set_LLI_entry(&g_InputDMA, 0, LLI_NEXT_ENTRY, AC97_get_pcmin_physical_buffer_address(),
m_InputDMABufferPhyPage[0], AUDIO_DMA_PAGE_SIZE);
DMA_set_LLI_entry(&g_InputDMA, 1, LLI_FIRST_ENTRY, AC97_get_pcmin_physical_buffer_address(),
m_InputDMABufferPhyPage[1], AUDIO_DMA_PAGE_SIZE);
}
CleanUp:
WAV_MSG((_T("[WAV] --InitInputDMA()\n\r")));
return bRet;
}
BOOL
HardwareContext::InitInterruptThread()
{
DWORD Irq;
DWORD dwPriority;
Irq = g_OutputDMA.dwIRQ;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(DWORD), &m_dwSysintrOutput, sizeof(DWORD), NULL))
{
WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : Output DMA IOCTL_HAL_REQUEST_SYSINTR Failed \n\r")));
return FALSE;
}
Irq = g_InputDMA.dwIRQ;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(DWORD), &m_dwSysintrInput, sizeof(DWORD), NULL))
{
WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : Input DMA IOCTL_HAL_REQUEST_SYSINTR Failed \n\r")));
return FALSE;
}
m_hOutputDMAInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hOutputDMAInterrupt == NULL)
{
WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : Output DMA CreateEvent() Failed \n\r")));
return(FALSE);
}
m_hInputDMAInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hInputDMAInterrupt == NULL)
{
WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : Input DMA CreateEvent() Failed \n\r")));
return(FALSE);
}
if (!InterruptInitialize(m_dwSysintrOutput, m_hOutputDMAInterrupt, NULL, 0))
{
WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : Output DMA InterruptInitialize() Failed \n\r")));
return FALSE;
}
if (! InterruptInitialize(m_dwSysintrInput, m_hInputDMAInterrupt, NULL, 0))
{
WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : Input DMA InterruptInitialize() Failed \n\r")));
return FALSE;
}
m_hOutputDMAInterruptThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0,
(LPTHREAD_START_ROUTINE)CallInterruptThreadOutputDMA, this, 0, NULL);
if (m_hOutputDMAInterruptThread == NULL)
{
WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : Output DMA CreateThread() Failed \n\r")));
return FALSE;
}
m_hInputDMAInterruptThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0,
(LPTHREAD_START_ROUTINE)CallInterruptThreadInputDMA, this, 0, NULL);
if (m_hInputDMAInterruptThread == NULL)
{
WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : Input DMA CreateThread() Failed \n\r")));
return FALSE;
}
dwPriority = GetInterruptThreadPriority();
// Bump up the priority since the interrupt must be serviced immediately.
CeSetThreadPriority(m_hOutputDMAInterruptThread, dwPriority);
CeSetThreadPriority(m_hInputDMAInterruptThread, dwPriority);
WAV_INF((_T("[WAV:INF] InitInterruptThread() : IST Priority = %d\n\r"), dwPriority));
return(TRUE);
}
BOOL
HardwareContext::DeinitInterruptThread()
{
return TRUE;
}
DWORD
HardwareContext::GetInterruptThreadPriority()
{
HKEY hDevKey;
DWORD dwValType;
DWORD dwValLen;
DWORD dwPrio = INTERRUPT_THREAD_PRIORITY_DEFAULT;
LONG lResult;
hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
if (hDevKey)
{
dwValLen = sizeof(DWORD);
lResult = RegQueryValueEx(hDevKey, TEXT("Priority256"), NULL, &dwValType, (PUCHAR)&dwPrio, &dwValLen);
RegCloseKey(hDevKey);
}
else
{
WAV_ERR((_T("[WAV:ERR] GetInterruptThreadPriority() : OpenDeviceKey() Failed\n\r")));
}
return dwPrio;
}
ULONG
HardwareContext::TransferOutputBuffer(DWORD dwStatus)
{
ULONG BytesTransferred = 0;
ULONG BytesTotal = 0;
dwStatus &= (DMA_DONEA|DMA_DONEB|DMA_BIU);
//WAV_MSG((_T("[WAV] TransferOutputBuffer(0x%08x)\n\r"), dwStatus));
switch (dwStatus)
{
case 0:
case DMA_BIU:
// No done bits set- must not be my interrupt
return 0;
case DMA_DONEA|DMA_DONEB|DMA_BIU:
// Load B, then A
BytesTransferred = FillOutputBuffer(OUTPUT_DMA_BUFFER1);
// fall through
case DMA_DONEA: // This should never happen!
case DMA_DONEA|DMA_BIU:
BytesTransferred += FillOutputBuffer(OUTPUT_DMA_BUFFER0); // charlie, A => B
break;
case DMA_DONEA|DMA_DONEB:
// Load A, then B
BytesTransferred = FillOutputBuffer(OUTPUT_DMA_BUFFER0);
// charlie
BytesTransferred += FillOutputBuffer(OUTPUT_DMA_BUFFER1);
break; // charlie
case DMA_DONEB|DMA_BIU: // This should never happen!
case DMA_DONEB:
// Load B
BytesTransferred += FillOutputBuffer(OUTPUT_DMA_BUFFER1); // charlie, B => A
break;
}
// If it was our interrupt, but we weren't able to transfer any bytes
// (e.g. no full buffers ready to be emptied)
// and all the output DMA buffers are now empty, then stop the output DMA
BytesTotal = m_nOutByte[OUTPUT_DMA_BUFFER0]+m_nOutByte[OUTPUT_DMA_BUFFER1];
if (BytesTotal == 0)
{
StopOutputDMA();
}
else
{
StartOutputDMA(); // for DMA resume when wake up
}
return BytesTransferred;
}
ULONG
HardwareContext::FillOutputBuffer(int nBufferNumber)
{
ULONG BytesTransferred = 0;
PBYTE pBufferStart = m_OutputDMABufferVirPage[nBufferNumber];
PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
PBYTE pBufferLast;
//WAV_MSG((_T("[WAV] FillOutputBuffer(%d)\n\r"), nBufferNumber));
__try
{
pBufferLast = m_OutputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd, NULL);
BytesTransferred = pBufferLast-pBufferStart;
m_nOutByte[nBufferNumber] = BytesTransferred;
// Enable if you need to clear the rest of the DMA buffer
StreamContext::ClearBuffer(pBufferLast, pBufferEnd);
if(nBufferNumber == OUTPUT_DMA_BUFFER0) // Output Buffer A
{
m_OutputDMAStatus &= ~DMA_DONEA;
m_OutputDMAStatus |= DMA_STRTA;
}
else // Output Buffer B
{
m_OutputDMAStatus &= ~DMA_DONEB;
m_OutputDMAStatus |= DMA_STRTB;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WAV_ERR((_T("[WAV:ERR] FillOutputBuffer() : Exception ccurs [%d]\n\r"), GetExceptionCode()));
DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferOutputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
}
return BytesTransferred;
}
ULONG
HardwareContext::TransferInputBuffers(DWORD dwStatus)
{
ULONG BytesTransferred=0;
dwStatus &= (DMA_DONEA|DMA_DONEB|DMA_BIU);
//WAV_MSG((_T("[WAV] TransferInputBuffers(0x%08x)\n\r"), dwStatus));
switch (dwStatus)
{
case 0:
case DMA_BIU:
// No done bits set- must not be my interrupt
return 0;
case DMA_DONEA|DMA_DONEB|DMA_BIU:
// Load B, then A
BytesTransferred = FillInputBuffer(INPUT_DMA_BUFFER1);
// fall through
case DMA_DONEA: // This should never happen!
case DMA_DONEA|DMA_BIU:
// Load A
BytesTransferred += FillInputBuffer(INPUT_DMA_BUFFER0);
break;
case DMA_DONEA|DMA_DONEB:
// Load A, then B
BytesTransferred = FillInputBuffer(INPUT_DMA_BUFFER0);
BytesTransferred += FillInputBuffer(INPUT_DMA_BUFFER1);
break;
case DMA_DONEB|DMA_BIU: // This should never happen!
case DMA_DONEB:
// Load B
BytesTransferred += FillInputBuffer(INPUT_DMA_BUFFER1);
break;
}
// If it was our interrupt, but we weren't able to transfer any bytes
// (e.g. no empty buffers ready to be filled)
// Then stop the input DMA
if (BytesTransferred==0)
{
StopInputDMA();
}
else
{
StartInputDMA(); // for DMA resume when wake up
}
return BytesTransferred;
}
ULONG
HardwareContext::FillInputBuffer(int nBufferNumber)
{
ULONG BytesTransferred = 0;
PBYTE pBufferStart = m_InputDMABufferVirPage[nBufferNumber];
PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
PBYTE pBufferLast;
//WAV_MSG((_T("[WAV] FillInputBuffer(%d)\n\r"), nBufferNumber));
__try
{
pBufferLast = m_InputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd, NULL);
BytesTransferred = m_nInByte[nBufferNumber] = pBufferLast-pBufferStart;
if(nBufferNumber == INPUT_DMA_BUFFER0) // Input Buffer A
{
m_InputDMAStatus &= ~DMA_DONEA;
m_InputDMAStatus |= DMA_STRTA;
}
else // Input Buffer B
{
m_InputDMAStatus &= ~DMA_DONEB;
m_InputDMAStatus |= DMA_STRTB;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WAV_ERR((_T("[WAV:ERR] FillInputBuffer() : Exception ccurs [%d]\n\r"), GetExceptionCode()));
}
return BytesTransferred;
}
void
HardwareContext::WriteCodecRegister(UCHAR Reg, USHORT Val)
{
AC97_write_codec(Reg, Val);
}
USHORT
HardwareContext::ReadCodecRegister(UCHAR Reg)
{
return AC97_read_codec(Reg);
}
BOOL
HardwareContext::CodecPowerControl()
{
if( m_bInputDMARunning & m_bOutputDMARunning )
{
//WAV_MSG((_T("[WAV] CodecPowerControl() : CodecPowerControl() ADC & DAC On\n\r")));
WriteCodecRegister(WM9713_POWER_CONTROL, AC97_PWR_D0); // ADC, DAC power up
}
else if( m_bInputDMARunning )
{
//WAV_MSG((_T("[WAV] CodecPowerControl() : CodecPowerControl() ADC On\n\r")));
WriteCodecRegister(WM9713_POWER_CONTROL, AC97_PWR_PR1); // DAC power down
}
else if( m_bOutputDMARunning )
{
//WAV_MSG((_T("[WAV] CodecPowerControl() : CodecPowerControl() DAC On\n\r")));
WriteCodecRegister(WM9713_POWER_CONTROL, AC97_PWR_PR0); // ADC power down
}
else
{
//WAV_MSG((_T("[WAV] CodecPowerControl() : CodecPowerControl() ADC & DAC Off\n\r")));
WriteCodecRegister(WM9713_POWER_CONTROL, AC97_PWR_PR1|AC97_PWR_PR0); // ADC, DAC power down
}
return(TRUE);
}
BOOL
HardwareContext::CodecMuteControl(DWORD channel, BOOL bMute)
{
USHORT volume;
if((channel & DMA_CH_OUT ))// && !m_bOutputDMARunning )
{
if(bMute)
{
volume = ReadCodecRegister(WM9713_HEADPHONE_VOL);
WriteCodecRegister(WM9713_HEADPHONE_VOL, volume|0x8080);
}
else
{
volume = ReadCodecRegister(WM9713_HEADPHONE_VOL);
WriteCodecRegister(WM9713_HEADPHONE_VOL, volume&~0x8080);
}
}
if( (channel & DMA_CH_IN))// && !m_bInputDMARunning )
{
if(bMute)
{
volume = ReadCodecRegister(WM9713_RECORD_VOL);
WriteCodecRegister(WM9713_RECORD_VOL, volume|0x8000);
}
else
{
volume = ReadCodecRegister(WM9713_RECORD_VOL);
WriteCodecRegister(WM9713_RECORD_VOL, volume&~0x8000);
}
}
return(TRUE);
}
void HardwareContext::SetSpeakerEnable(BOOL bEnable)
{
// Code to turn speaker on/off here
return;
}
void CallInterruptThreadOutputDMA(HardwareContext *pHWContext)
{
pHWContext->InterruptThreadOutputDMA();
}
void CallInterruptThreadInputDMA(HardwareContext *pHWContext)
{
pHWContext->InterruptThreadInputDMA();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -