📄 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.
//
// $Workfile: es1371.cpp $
//
#include <windows.h>
#include <waveddsi.h>
#include <ceddk.h>
#include "es1371.h"
DWORD gIntrAudio;
#define STR_MODULENAME "CES1371: "
typedef struct
{
CES1371 * pHardware;
BOOLEAN fRead;
ULONG ulPage;
ULONG ulIOAddress;
PULONG pulData;
}
SYNCIOCONTEXT, *PSYNCIOCONTEXT;
static
NTSTATUS
SynchronizedPagedIO
(
IN PINTERRUPTSYNC InterruptSync,
IN PVOID syncIOContext
);
// {{{ constructor/destructor
CES1371::CES1371 (void)
{
m_pInterruptSync = (IInterruptSync_WinCeStub*)new IInterruptSync_WinCeStub;
m_fIsMapped = FALSE;
m_refcount = 0;
m_ulPowerState = 0;
}
CES1371::~CES1371 ()
{
//invalidate our member variables
if (m_fIsMapped) {
MmUnmapIoSpace(m_pPciAddr, ES1371_IO_SPACE_SIZE);
m_fIsMapped = FALSE;
}
m_pPciAddr = 0;
}
LONG CES1371::AddRef (void)
{
return InterlockedIncrement (&m_refcount);
}
LONG CES1371::Release (void)
{ LONG newcount;
newcount = InterlockedDecrement (&m_refcount);
if (newcount == 0) {
delete this;
}
return newcount;
}
// }}}
// {{{ Init
//--------------------------------------------------------------------------
//
// Name: CES1371::MapHardware
//
// Description: Maps port address, assigns SysIntr
//
// Parameters: none
//
// Returns: BOOL
// TRUE if device was mapped properly
// FALSE if device could not be mapped
//
// Note:
//
//--------------------------------------------------------------------------
BOOL CES1371::MapHardware (ULONG ulSysIntr, ULONG ulPciAddr, ULONG ulPciLength, ULONG ulDeviceID, ULONG ulRevisionID)
{
PHYSICAL_ADDRESS PortAddress;
PHYSICAL_ADDRESS MappedAddress;
//initialize our member variables
m_pPciAddr = (PUCHAR)ulPciAddr;
//
// Configure IO address
//
{
//
// Translate address
//
DWORD inIoSpace = 1; // io space
PortAddress.LowPart = (DWORD)m_pPciAddr;
PortAddress.HighPart = 0;
if (!HalTranslateBusAddress(PCIBus, 0, PortAddress, &inIoSpace, &MappedAddress)) {
DEBUGMSG(1, (L"CES1371::MapHardware - failed HalTranslateBusAddress\r\n"));
return FALSE;
}
if (!inIoSpace) {
// Get virtual address
if ((m_pPciAddr = (PUCHAR)MmMapIoSpace(MappedAddress, ulPciLength, FALSE)) == NULL) {
DEBUGMSG(1, (TEXT("CES1371::MapHardware - Error mapping I/O Ports.\r\n")));
return FALSE;
}
DEBUGMSG(1, (L"CES1371::MapHardware - MappedAddress = 0x%X, m_pPciAddr = 0x%X\r\n", MappedAddress.LowPart, m_pPciAddr));
} else {
m_pPciAddr = (PUCHAR)MappedAddress.LowPart;
}
}
DEBUGMSG(1, (L"CES1371::MapHardware2 - MappedAddress = 0x%X, m_pPciAddr = 0x%X\r\n", MappedAddress.LowPart, m_pPciAddr));
//
// Configure Interrupt
//
gIntrAudio = ulSysIntr;
// record the Device ID and Revision ID for posterity.
m_usDid = (USHORT)ulDeviceID;
m_ucRevision = (UCHAR)ulRevisionID;
//call our initialization functions
InitHardware();
return TRUE;
}
//--------------------------------------------------------------------------
//
// 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_usDid == ES5880_PCI_DEVID) ||
((m_usDid == ES1371_PCI_DEVID) && (m_ucRevision == 7)) ||
((m_usDid == ES1371_PCI_DEVID) && (m_ucRevision >= 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;
/*
*put the HW into a happy state
*/
InitSRC( TRUE );
/* 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();
// initialize UART
m_ulUARTState = 0;
//
// Cycle the power state to get registers image, etc.
//
//SetPowerState(1); // Turn off to set register arrays
//SetPowerState(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( 1, (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( 1, (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
//
//--------------------------------------------------------------------------
NTSTATUS
CES1371::HwPagedIOWrite( UCHAR Page, ULONG pAddr, ULONG ulData )
{
SYNCIOCONTEXT context;
ULONG ulWriteData;
NTSTATUS ntStatus = STATUS_SUCCESS;
if ( 0 == m_ulPowerState )
{
// normal power state - go read the hardware
ulWriteData = ulData;
context.pHardware = this;
context.fRead = FALSE;
context.ulPage = ULONG( Page );
context.ulIOAddress = pAddr;
context.pulData = &ulWriteData;
ntStatus = m_pInterruptSync->
CallSynchronizedRoutine(SynchronizedPagedIO,PVOID(&context));
}
else
{
// power down state - can't write hardware write the saved setting
m_ulIRegsPMContext[ (ULONG(Page) * 4) + ( (pAddr - 0x30) / 4 ) ] = ulData;
}
return ntStatus;
}
//--------------------------------------------------------------------------
//
// 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 )
{
SYNCIOCONTEXT context;
ULONG ulReadData;
NTSTATUS ntStatus = STATUS_SUCCESS;
if ( 0 == m_ulPowerState )
{
// normal power state - go read the hardware
context.pHardware = this;
context.fRead = TRUE;
context.ulPage = ULONG( Page );
context.ulIOAddress = pAddr;
context.pulData = &ulReadData;
ntStatus = m_pInterruptSync->
CallSynchronizedRoutine(SynchronizedPagedIO,PVOID(&context));
}
else
{
// power down state - can't read hardware get the saved setting
ulReadData = m_ulIRegsPMContext[ (ULONG(Page) * 4) + ( (pAddr - 0x30) / 4 ) ];
}
return ulReadData;
}
// {{{ HwRegRMW
/* ----------------------------------------------------------------------- /
Routine: HwRegRMW
Purpose: The routine is used to access a Concert chip register via
its shadowed value. This routine is required to provide
exclusion (synchronization) to the register.
This routine should be run from the KeSynchronizeExecution
call, forceing this routine to execute at our devices
DIRQL. It also acquires the spin lock, providing exclusion.
The current value in the shadow ram is read, ANDed with
the mask and ORed with the bits.
Inputs:
Output: None
Errors: None
/ ----------------------------------------------------------------------- */
UCHAR
CES1371::HwRegRMW ( UCHAR Reg, UCHAR bBitMask, UCHAR bSetBits )
{
UCHAR bNewValue;
UCHAR *puc_DRegs = (UCHAR *)m_ulDRegs;
// are we setting the whole data space?
if ( 0x00 == bBitMask )
{
return ( *(puc_DRegs + Reg) );
}
else if ( 0xff == bBitMask )
{
bNewValue = bSetBits;
}
else
{
// read original value,
// zero out bits of interest,
// set proper bits to one
if ( (0xff != *(puc_DRegs + Reg)) || ( m_ulPowerState > 0 ) )
bNewValue = *(puc_DRegs + Reg);
else
bNewValue = READ_PORT_UCHAR (m_pPciAddr + Reg);
bNewValue &= ~bBitMask;
bNewValue |= (bSetBits & bBitMask);
}
// write new value to hardware
if ( 0 == m_ulPowerState )
WRITE_PORT_UCHAR ( m_pPciAddr + Reg, bNewValue);
// save the value for the future
*(puc_DRegs + Reg) = bNewValue;
return bNewValue;
} // end of function: hw_reg_rmw_char
// }}}
// {{{ HwRegRMW
USHORT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -