📄 es1371.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// Copyright 1998-2000 (c) Creative Labs, Malvern. All rights reserved.
// Portions copyright 1999-2000 (c) Microsoft Corporation. All rights reserved.
//
#include "wavdrv.h"
#include <nkintr.h>
#include <ceddk.h>
#include <cardserv.h>
#include <devload.h>
#include <giisr.h>
#include <ddkreg.h>
#define DEVLOAD_DEVICEID_VALNAME TEXT("DeviceID")
#define DEVLOAD_REVISIONID_VALNAME TEXT("RevisionID")
// {{{ constructor/destructor
CES1371::CES1371 (void)
{ int i;
InitializeCriticalSection( &m_csPageLock );
//initialize our member variables
for (i = 0; i < NUM_DMACHANNELS; i++) {
m_dmachannel[i].ulDMAChannelState = DMA_STOPPED;
m_dmachannel[i].fAllocated = FALSE;
}
m_dmachannel[ES1371_ADC ].ulDirection = DMADIR_IN;
m_dmachannel[ES1371_DAC0].ulDirection = DMADIR_OUT;
m_dmachannel[ES1371_DAC1].ulDirection = DMADIR_OUT;
m_dmachannel[ES1371_ADC].ulInitialSize = PRE_ALLOC_BUFFER_SIZE_ADC;
m_dmachannel[ES1371_DAC0].ulInitialSize = PRE_ALLOC_BUFFER_SIZE_DAC0;
m_dmachannel[ES1371_DAC1].ulInitialSize = PRE_ALLOC_BUFFER_SIZE_DAC1;
m_dmachannel[ES1371_ADC].ucIntMask = ES1371_INT_ADC;
m_dmachannel[ES1371_DAC0].ucIntMask = ES1371_INT_DAC0;
m_dmachannel[ES1371_DAC1].ucIntMask = ES1371_INT_DAC1;
m_hISTInterruptEvent = NULL;
m_hISThread = NULL;
m_bExitIST = FALSE;
m_fIsMapped = FALSE;
m_ulPowerState = 0; // record the internal state of the device as "powered up"
}
CES1371::~CES1371 ()
{
//invalidate our member variables
// Close the IST
m_bExitIST = true;
SetEvent(m_hISTInterruptEvent);
if( WAIT_OBJECT_0 != WaitForSingleObject(m_hISThread, 10000) )
DEBUGMSG(ZONE_ERROR,(TEXT("~CES1371-- Error closing IST \r\n")));
CloseHandle(m_hISTInterruptEvent);
CloseHandle(m_hISThread);
DeleteCriticalSection( &m_csPageLock );
if (m_fIsMapped) {
MmUnmapIoSpace(m_pPciAddr, m_dwPciLength);
m_fIsMapped = FALSE;
}
if (m_hIsrHandler != NULL) {
FreeIntChainHandler(m_hIsrHandler);
}
}
void
CES1371::GetDMABuffer (ULONG ulChannelIndex, PULONG pulBufferSize, PVOID * pvVirtAddr)
{
if (ulChannelIndex < NUM_DMACHANNELS) {
*pulBufferSize = m_dmachannel[ulChannelIndex].ulBufferSize;
*pvVirtAddr = m_dmachannel[ulChannelIndex].pvBufferVirtAddr;
}
}
ULONG
CES1371::GetNumFreeDMAChannels(ULONG ulDirection)
{ ULONG count = 0;
int index;
for (index = 0; index < NUM_DMACHANNELS; index++) {
if ((m_dmachannel[index].ulDirection & ulDirection) && ! m_dmachannel[index].fAllocated) {
count ++;
}
}
return count;
}
MMRESULT
CES1371::AllocDMAChannel (ULONG ulDirection, ULONG ulSize, PULONG pulChannelIndex)
{ ULONG index;
if (ulSize > 64 * 1024) {
// ES1371 only handles up to 64Kbyte DMA buffers
return MMSYSERR_NOMEM;
}
// make two passes through the DMA channel table:
// in pass 1, we try to use pre-allocated memory first.
// only in pass 2 do we allocate new memory
for (index = 0; index < NUM_DMACHANNELS; index++) {
if ((m_dmachannel[index].ulDirection & ulDirection) && ! m_dmachannel[index].fAllocated) {
// we found an open slot. see if we can get enough memory
if (m_dmachannel[index].ulAllocatedSize >= ulSize) {
// currently allocated memory is sufficient. We're done.
m_dmachannel[index].fAllocated = TRUE;
m_dmachannel[index].ulBufferSize = ulSize; // record what we're actually using
*pulChannelIndex = index;
return MMSYSERR_NOERROR;
}
}
}
// pass 2: find a free slot and allocate memory
for (index = 0; index < NUM_DMACHANNELS; index++) {
if ((m_dmachannel[index].ulDirection & ulDirection) && ! m_dmachannel[index].fAllocated) {
// pass 2: try to allocate memory for the request
// make new allocation first, only if it succeeds do we release existing memory
ULONG ulPhysAddr;
PVOID pVirtAddr;
PHYSICAL_ADDRESS LogicalAddress;
DMA_ADAPTER_OBJECT AdapterObject;
AdapterObject.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
AdapterObject.InterfaceType = (INTERFACE_TYPE) m_dwInterfaceType;
AdapterObject.BusNumber = m_dwBusNumber;
if ((pVirtAddr = HalAllocateCommonBuffer(&AdapterObject, ulSize, &LogicalAddress, FALSE)) == NULL)
{
DEBUGMSG(ZONE_ERROR,(TEXT("AllocDMAChannel - unable to allocate %d bytes of physical memory\r\n"), ulSize));
// if this fails, there's not much point in trying it over and over
return MMSYSERR_NOMEM;
}
ulPhysAddr = LogicalAddress.LowPart;
if (m_dmachannel[index].ulBufferSize > 0) {
// free the previous allocation
LogicalAddress.QuadPart = 0;
HalFreeCommonBuffer(NULL, 0, LogicalAddress, m_dmachannel[index].pvBufferVirtAddr, FALSE);
}
m_dmachannel[index].ulAllocatedSize = ulSize;
m_dmachannel[index].ulBufferSize = ulSize;
m_dmachannel[index].ulBufferPhysAddr = ulPhysAddr;
m_dmachannel[index].pvBufferVirtAddr = pVirtAddr;
m_dmachannel[index].fAllocated = TRUE;
*pulChannelIndex = index;
return MMSYSERR_NOERROR;
}
}
DEBUGMSG(ZONE_INFO, (TEXT("AllocDMAChannel - no free channels\r\n")));
return MMSYSERR_ALLOCATED;
}
BOOL
CES1371::FreeDMAChannel (ULONG ulChannelIndex)
{
ASSERT(ulChannelIndex < NUM_DMACHANNELS);
ASSERT(m_dmachannel[ulChannelIndex].fAllocated);
m_dmachannel[ulChannelIndex].fAllocated = FALSE;
m_dmachannel[ulChannelIndex].pfIntHandler = NULL;
m_dmachannel[ulChannelIndex].pvIntContext = NULL;
// note that we DO NOT relinquish physical memory, since contigous physical memory is
// harder to come by as the system runs. We'd run the risk of not getting the memory
// back next time we need it.
return TRUE;
}
// }}}
// {{{ Init
//--------------------------------------------------------------------------
//
// Name: CES1371::InitHardware
//
// Description: intitializes the 1371 hardware
//
// Parameters: none
//
// Returns: void
//
// Note:
//
//--------------------------------------------------------------------------
void CES1371::InitHardware()
{
UCHAR bReg = 0x00;
USHORT wReg = 0x0000;
ULONG i;
// if we have a 5880 then take the AC97 codec out of reset
if ( (m_dwDeviceID == ES5880_PCI_DEVID) ||
((m_dwDeviceID == ES1371_PCI_DEVID) && (m_dwRevisionID == 7)) ||
((m_dwDeviceID == ES1371_PCI_DEVID) && (m_dwRevisionID >= 9))
)
{
// write the es137x AC97 reset bit
bReg = 0x20;
HwRegRMW( ES1371_bINTSUMM_OFF, 0x20, bReg );
// wait around a long time for the codec to come out of reset
// i.e. 20 msec or 200 * 100 nanosec
#ifdef UNDER_CE
Sleep(1);
#else
if ( KeGetCurrentIrql() == PASSIVE_LEVEL )
{
LARGE_INTEGER liTimeout =
RtlConvertLongToLargeInteger( -200 );
KeDelayExecutionThread( KernelMode, FALSE, &liTimeout );
}
else // wait around the old fashioned way by polling
{
ULONG ulPollCount;
UCHAR ucDummyRead;
for ( ulPollCount = 0; ulPollCount < 110000; ulPollCount++ )
{
ucDummyRead = READ_PORT_UCHAR( m_pPciAddr );
}
}
#endif
// The 5880 has a mux to configure the line in/rear spkr out
// jack to the appropriate function. In the basic driver,
// we'll assume it'll always be a line in function (set
// GPIO2 bit to zero).
HwRegRMW( ES1371_bGPIO_OFF, (UCHAR)0x04, (UCHAR) 0x00);
}
// write bogus values into the DRegs so the initial writes take
for ( i=0; i<12; i++)
m_ulDRegs[i] = 0xffffffff;
/* setup the MISCCTRL reg */
bReg =
ES1371_MISCCTL_PDLEV_D0
& ~ES1371_MISCCTL_CCBINTRM_EN;
HwRegRMW( ES1371_bMISCCTL_OFF, 0xff, bReg );
/* setup the DEVCTRL reg */
/* enable UART, XTAL clock and PCI clock */
bReg =
ES1371_DEVCTL_UART_EN
& ~ES1371_DEVCTL_XTALCLK_DS
& ~ES1371_DEVCTL_PCICLK_DS;
HwRegRMW( ES1371_bDEVCTL_OFF, 0xff, bReg );
/* setup the JOYCTRL reg */
bReg = 0;
HwRegRMW( ES1371_bJOYCTL_OFF, 0xff, bReg );
/* disable the NMI */
bReg = 0x00;
HwRegRMW( ES1371_bNMIENA_OFF, 0xff, bReg );
/* clear the NMI status register */
wReg = 0x0000;
HwRegRMW( ES1371_wNMISTAT_OFF, 0xffff, wReg );
/* clear the Serial Control register */
bReg = 0x00;
HwRegRMW( ES1371_bSERCTL_OFF, 0xff, bReg );
// initialize Codec
InitCodec();
/*
*put the HW into a happy state
*/
InitSRC( TRUE );
// initialize UART
m_ulUARTState = 0;
return;
}
// }}}
// {{{ SRCInit
void CES1371::InitSRC( BOOLEAN fEnable )
{
USHORT i;
ULONG ulHardwareWrite;
/* must poll before writes to DISABLE or PAUSE the SRCIO register */
SRCPollIOReg ();
/* disable SRC for init */
ulHardwareWrite = SRC_DISABLE;
HwRegRMW( ES1371_dSRCIO_OFF, 0xffffffff, ulHardwareWrite );
// WRITE_PORT_ULONG((PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF), SRC_DISABLE);
/* clear the SRC RAM */
for( i = 0; i < 0x80; ++i )
SRCRegWrite(i, 0 );
SRCRegWrite(SRC_DAC0_BASE + SRC_TRUNC_N_OFF, 16 << 4);
SRCRegWrite(SRC_DAC0_BASE + SRC_INT_REGS_OFF, 16 << 10);
SRCRegWrite(SRC_DAC1_BASE + SRC_TRUNC_N_OFF, 16 << 4);
SRCRegWrite(SRC_DAC1_BASE + SRC_INT_REGS_OFF, 16 << 10);
SRCRegWrite(SRC_ADC_BASE + SRC_TRUNC_N_OFF, 16 << 4);
SRCRegWrite(SRC_ADC_BASE + SRC_INT_REGS_OFF, 16 << 10);
SRCRegWrite(SRC_DAC0_VOL_L, 1 << 12);
SRCRegWrite(SRC_DAC0_VOL_R, 1 << 12);
SRCRegWrite(SRC_DAC1_VOL_L, 1 << 12);
SRCRegWrite(SRC_DAC1_VOL_R, 1 << 12);
SRCRegWrite(SRC_ADC_VOL_L, 1 << 12);
SRCRegWrite(SRC_ADC_VOL_R, 1 << 12);
/* default some rates */
SRCSetRate(ES1371_DAC0, 22050);
SRCSetRate(ES1371_DAC1, 22050);
SRCSetRate(ES1371_ADC, 22050);
#if (DBG)
USHORT usSRCdata[8];
USHORT j;
/* dump the SRC ram */
DEBUGMSG( ZONE_INFO, (TEXT("es1371 dump SRC ram\r")));
for ( i = 0; i < 16; i++ )
{
for ( j = 0; j < 8; j++)
{
usSRCdata[j] = SRCRegRead( i*8 + j );
}
DEBUGMSG( ZONE_INFO, (TEXT("%02x %04x %04x %04x %04x %04x %04x %04x %04x\r"), i*8,
usSRCdata[0],usSRCdata[1],
usSRCdata[2],usSRCdata[3],
usSRCdata[4],usSRCdata[5],
usSRCdata[6],usSRCdata[7]));
}
#endif
if ( fEnable )
{
/* now enable the whole deal */
SRCPollIOReg ();
ulHardwareWrite = 0L;
HwRegRMW( ES1371_dSRCIO_OFF, 0xffffffff, ulHardwareWrite );
}
return;
}
// }}}
//--------------------------------------------------------------------------
//
// Name: HwPagedIOWrite
//
// Description: Does a MP-safe write to the indirect registers
//
// Parameters: UCHAR Page : the memory page to set
// PULONG pAddr : the IO address to write
// ULONG ulData : the data to write
//
// Returns: NTSTATUS
//
//--------------------------------------------------------------------------
VOID
CES1371::HwPagedIOWrite( UCHAR Page, ULONG pAddr, ULONG ulData )
{
if ( 0 == m_ulPowerState )
{
CAutoLock csa(&m_csPageLock);
// write the page register if needed
if ( m_ulDRegs[ES1371_bMEMPAGE_OFF/4] != Page ) {
WRITE_PORT_UCHAR(m_pPciAddr + ES1371_bMEMPAGE_OFF, Page & 0x0f );
// save in the regs array
m_ulDRegs[ES1371_bMEMPAGE_OFF/4] = Page;
}
WRITE_PORT_ULONG((PULONG) (m_pPciAddr + pAddr), ulData);
}
else
{
// power down state - can't write hardware write the saved setting
m_ulIRegsPMContext[ (ULONG(Page) * 4) + ( (pAddr - 0x30) / 4 ) ] = ulData;
}
}
//--------------------------------------------------------------------------
//
// Name: HwPagedIORead
//
// Description: Sets the current page of indirect registers
//
// Parameters: UCHAR Page : the memory page to set
// PULONG pAddr : the IO address to read
//
// Returns: data read
//
//--------------------------------------------------------------------------
ULONG
CES1371::HwPagedIORead( UCHAR Page, ULONG pAddr )
{
ULONG ulReadData;
if ( 0 == m_ulPowerState )
{
CAutoLock csa(&m_csPageLock);
// write the page register if needed
if ( m_ulDRegs[ES1371_bMEMPAGE_OFF/4] != Page ) {
WRITE_PORT_UCHAR(m_pPciAddr + ES1371_bMEMPAGE_OFF, Page & 0x0f );
// save in the regs array
m_ulDRegs[ES1371_bMEMPAGE_OFF/4] = Page;
}
ulReadData = READ_PORT_ULONG((PULONG) (m_pPciAddr + pAddr));
}
else
{
// power down state - can't read hardware get the saved setting
ulReadData = m_ulIRegsPMContext[ (ULONG(Page) * 4) + ( (pAddr - 0x30) / 4 ) ];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -