?? hwctxt.cpp
字號:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*++
Module Name:
hwctxt.cpp
Abstract:
ChangesLog:
06-28-2005
1. Added installable ISR for audio DMA interrupt handling.
2. Improved DMA buffer handling.
3. AC97 shared resource management is now in ACLink.lib which is shared by touch driver.
4. Added power management support.
--*/
/*
** Copyright 2000-2003 Intel Corporation All Rights Reserved
**
** Portions of the source code contained or described herein and all documents
** related to such source code (Material) are owned by Intel Corporation
** or its suppliers or licensors and is licensed by Microsoft Corporation for distribution.
** Title to the Material remains with Intel Corporation or its suppliers and licensors.
** Use of the Materials is subject to the terms of the Microsoft license agreement which accompanied the Materials.
** No other license under any patent, copyright, trade secret or other intellectual
** property right is granted to or conferred upon you by disclosure or
** delivery of the Materials, either expressly, by implication, inducement,
** estoppel or otherwise
** Some portion of the Materials may be copyrighted by Microsoft Corporation..
*/
#include <windows.h>
#include <aclink.h>
#include "ac97.h"
#include "wavemain.h"
#include "dmac.h"
#define DMA_INTERRUPT_REGISTER 0x400000f0
#define INTERRUPT_THREAD_PRIORITY_DEFAULT 150
const LPCWSTR g_wszDmaIsrDll = L"giisr.dll";
const LPCWSTR g_wszDmaIsrHandler = L"ISRHandler";
HardwareContext *g_pHWContext=NULL;
static const POWER_CAPABILITIES g_PowerCaps =
{
// DeviceDx: Supported power states
DX_MASK(D0) | DX_MASK(D1) | DX_MASK(D2) | DX_MASK(D3) | DX_MASK(D4),
0, // WakeFromDx:
0, // InrushDx: No inrush of power
{ // Power: Maximum milliwatts in each state
0x00000001, // D0 = 0
0x00000001, // D1 = 0
0x00000001, // D2 = 0
0x00000001, // D3 = 0
0x00000001 // D4 = 0 (off)
},
{ // Latency
0x00000000, // D0 = 0
0x00000000, // D1 = 0
0x00000000, // D2 = 0
0x00000000, // D3 = 0
0x00000000 // D4 = 0
},
0, // Flags: None
};
BOOL HardwareContext::CreateHWContext(DWORD Index)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("+HardwareContext::CreateHWContext")));
//if the hardware context exists then don't init again
if (g_pHWContext)
{
return TRUE;
}
g_pHWContext = new HardwareContext;
if (!g_pHWContext)
{
return FALSE; //oops we should have not be null
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("-HardwareContext::CreateHWContext")));
return g_pHWContext->Init(Index);
}
HardwareContext::HardwareContext(): m_InputDeviceContext(), m_OutputDeviceContext()
{
InitializeCriticalSection(&m_Lock); //some code is not reentrant
m_Initialized=FALSE; //we are just getting started, we are not initialized yet
m_fOutputRenderMonoOnly = 0;
}
HardwareContext::~HardwareContext()
{
DeleteCriticalSection(&m_Lock); //we're going down, clean up semiphore
}
BOOL HardwareContext::Init(DWORD Index)
{
DEBUGMSG(ZONE_INIT, (TEXT("+HardwareContext::Init")));
//initialize the hardware, bring it up to a state ready for quick rendering of
//audio streams and UI sounds
m_DriverIndex = Index;
m_InPowerHandler = FALSE;
m_InputDMARunning = FALSE;
m_OutputDMARunning = FALSE;
m_NumForcedSpeaker = 0;
m_Sleeping = FALSE;
m_audioDeinit = FALSE;
m_SysIntrAudioDMA = SYSINTR_UNDEFINED;
m_hAudioInterrupt = NULL;
m_hDMAIsrHandler = NULL;
m_PlaybackChannel = (XLLP_DMAC_CHANNEL_T)DMA_CH_OUT; // DMA Ch. 1
m_RecordingChannel = (XLLP_DMAC_CHANNEL_T)DMA_CH_RCV; // DMA Ch. 4
// Initial power state
m_dwPowerState = D0;
GetRegKeys();
m_OutputDeviceContext.SetMono(m_fOutputRenderMonoOnly);
if (!MapDeviceRegisters())
{
goto Exit;
}
if (!InitAudioDMA())
{
goto Exit;
}
if (!MapDMADescriptors())
{
goto Exit;
}
// Map the DMA buffers (and fill the descriptors) into driver's virtual address space
if (!MapDMABuffers())
{
goto Exit;
}
// Bring up AC-LINK and initialize the Codec
if(InitializeACLink(FALSE, DEV_AUDIO))
{
PowerUp();
InitCodec();
}
else
{
goto Exit;
}
// Configure the DMA controller
InitInputDMA();
InitOutputDMA();
m_Initialized = TRUE;
Exit:
if (FALSE == m_Initialized)
{//fail to initialize
Deinit();
}
DEBUGMSG(ZONE_INIT, (TEXT("-HardwareContext::Init")));
return m_Initialized;
}
BOOL HardwareContext::MapDMABuffers()
{
PBYTE pbDMATemp;
DMA_ADAPTER_OBJECT Adapter;
PHYSICAL_ADDRESS PA;
DEBUGMSG(ZONE_INIT, (TEXT("+MapDMABuffers")));
Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
Adapter.InterfaceType = Internal;
Adapter.BusNumber = 0;
pbDMATemp = (BYTE *) HalAllocateCommonBuffer(&Adapter, (AUDIO_BUFFER_SIZE * NUM_DMA_AUDIO_BUFFERS), &PA, FALSE);
if (!pbDMATemp)
{
DEBUGMSG(ZONE_ERROR, (TEXT("ERROR: AudioInitialize: failed to allocate DMA buffer(s).\r\n")));
return(FALSE);
}
m_Output_pbDMA_PAGES[0] = pbDMATemp;
m_Output_pbDMA_PAGES[1] = pbDMATemp + AUDIO_BUFFER_SIZE;
m_Input_pbDMA_PAGES[0] = pbDMATemp + 2*AUDIO_BUFFER_SIZE;
m_Input_pbDMA_PAGES[1] = pbDMATemp + 3*AUDIO_BUFFER_SIZE;
m_Output_pbDMA_PAGES_Physical[0] = (BYTE *)PA.LowPart;
m_Output_pbDMA_PAGES_Physical[1] = (BYTE *)PA.LowPart + AUDIO_BUFFER_SIZE;
m_Input_pbDMA_PAGES_Physical[0] = (BYTE *)PA.LowPart + 2*AUDIO_BUFFER_SIZE;
m_Input_pbDMA_PAGES_Physical[1] = (BYTE *)PA.LowPart + 3*AUDIO_BUFFER_SIZE;
return TRUE;
}
void HardwareContext::InitInputDMA()
{
FillInputDescriptors();
}
void HardwareContext::InitOutputDMA()
{
FillOutputDescriptors();
}
int HardwareContext::GetNextOutputBuffer(void)
{
return ((UINT32)m_pDMARegisters->ddg[m_PlaybackChannel].dsadr >= (UINT32)m_Output_pbDMA_PAGES_Physical[1]) ? 0 : 1 ;
}
void HardwareContext::StartOutputDMA()
{
DEBUGMSG(ZONE_VERBOSE, (TEXT("+StartOutputDMA\r\n")));
if (!m_OutputDMARunning)
{
ULONG OutputTransferred;
// Fill in the first DMA buffer before kicking start DMA, which will
// generate an interrupt (e.g. STARTINTR) right away. The IST thread will then
// fill in the second DMA buffer.
OutputTransferred = TransferOutputBuffer(0);
if (OutputTransferred)
{
m_OutputDMARunning=TRUE;
// Initialize the DMA channel format
//set the sample rate on every buffer due to ac97 work around. (???)
SetSampleRate(SAMPLERATE, WAPI_OUT);
m_pAc97regs->POSR = 0x10; //clear the output Fifo error
if(OutputTransferred < AUDIO_BUFFER_SIZE)
{
// Set second buffer descriptor STOP bit and the minimum length
// in case we overrun into the second buffer.
m_vpAudioXmitB->ddadr |= DESC_ADDRESS_STOP_MASK;
m_vpAudioXmitB->dcmd = DMAC_AC97_XMITAB_CMD_MASK | 32;
}
DEBUGMSG(ZONE_VERBOSE, (TEXT( "Starting DMA XMIT channel %d \r\n" ),m_PlaybackChannel) );
// Load descriptor address reg to initialize DMA, pointing
// to the buffer just loaded.
m_pDMARegisters->ddg[m_PlaybackChannel].ddadr =(UINT32)m_vpAudioXmitA_Physical;
m_pDMARegisters->drcmr[DMA_CHMAP_AC97_OUT] = DMA_MAP_VALID_MASK | m_PlaybackChannel ;
// Enable STOPINTR so that we know DMA is done on final buffer. A zero length buffer
// is considered the final buffer.
// And finally set RUN bit to start DMA.
m_pDMARegisters->dcsr[m_PlaybackChannel] |= DCSR_RUN | DCSR_STOPIRQEN;
DEBUGMSG(ZONE_VERBOSE, (TEXT("Started Output DMA\r\n")));
}
else
{
m_OutputDMARunning=FALSE;
DEBUGMSG(ZONE_VERBOSE, (TEXT("no Output started with DMA\r\n")));
}
}
}
void HardwareContext::StopOutputDMA()
{
DEBUGMSG(ZONE_VERBOSE, (TEXT("StopOutputDMA\r\n")));
if (m_OutputDMARunning)
{
//stop the dma channel and mute
StopDmac(m_PlaybackChannel);
m_OutputDMARunning=FALSE;
}
}
int HardwareContext::GetLastInputBuffer(void)
{
return ((UINT32)m_pDMARegisters->ddg[m_RecordingChannel].dtadr >= (UINT32)m_Input_pbDMA_PAGES_Physical[1]) ? 0 : 1 ;
}
void HardwareContext::StartInputDMA()
{
if (!m_InputDMARunning)
{
//set it on every buffer due to ac97 work around. (???)
SetSampleRate(SAMPLERATE, WAPI_IN);
// For now, pretend input dma is running in case we accidentally get reentered
m_InputDMARunning=TRUE;
//DMA_CH_RCV:
DEBUGMSG(ZONE_VERBOSE, (TEXT( "Starting DMA Recieve channel \r\n" )) );
m_pDMARegisters->ddg[m_RecordingChannel].ddadr = (UINT32)m_vpAudioRcvA_Physical;
m_pDMARegisters->drcmr[DMA_CHMAP_AC97_RCV] = DMA_MAP_VALID_MASK | m_RecordingChannel ;
m_pAc97regs->PISR = 0x10; // clear Pcm Input Fifo status
m_pAc97regs->PISR = 0x8; // dedicated write to clear EOC bit
m_pDMARegisters->dcsr[m_RecordingChannel] |= DCSR_RUN; // set the RUN bit
}
}
void HardwareContext::StopInputDMA()
{
if (m_InputDMARunning)
{
m_InputDMARunning=FALSE;
StopDmac(m_RecordingChannel);
}
}
/* ;resample stereo output to mono output?
;set this if your platform has only mono speaker. if your platform supports
; both mono speaker and a stereo headset you'll have to dynamically change
; the flag in wavedev2 driver for proper output rendering (mono vs. stereo)
;MainstoneIII has both a mono speaker and a stereo headphone jack. But unfortunately
; headphone presence detection is not supported by the onboard philips codec.
; For this reason we only render mono output.
"HKLM\Drivers\BuiltIn\WaveDev\OutputRenderMonoOnly"=dword:1 <-- Reg Key
m_fOutputRenderMonoOnly <-- flag in wavedev2 driver
*/
#define WAV_OUTPUT_RENDER_MONO_ONLY TEXT("OutputRenderMonoOnly")
BOOL HardwareContext::GetRegKeys()
{
HKEY hDevKey;
hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
if (hDevKey)
{
DWORD dwValLen = sizeof(DWORD);
DWORD dwOutputRenderMonoOnly = 0;
LONG regError = RegQueryValueEx(hDevKey, WAV_OUTPUT_RENDER_MONO_ONLY, NULL, NULL,
(PUCHAR)&dwOutputRenderMonoOnly, &dwValLen);
if (regError != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT,(TEXT("WAVEDEV_GetRegKeys: INFO: Failed opening \\Drivers\\BuiltIn\\WaveDev\\OutputRenderMonoOnly\r\n")));
}
m_fOutputRenderMonoOnly = (dwOutputRenderMonoOnly == 1);
RegCloseKey(hDevKey);
}
return (TRUE);
}
DWORD HardwareContext::GetInterruptThreadPriority()
{
HKEY hDevKey;
DWORD dwValType;
DWORD dwValLen;
LONG regError;
DWORD dwPrio = INTERRUPT_THREAD_PRIORITY_DEFAULT; // Default priority
hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -