📄 es1371.cpp
字号:
CES1371::HwRegRMW ( UCHAR Reg, USHORT wBitMask, USHORT wSetBits )
{
USHORT wNewValue;
USHORT *pus_DRegs = (USHORT *)m_ulDRegs;
// are we setting the whole data space?
if ( 0x0000 == wBitMask )
{
return ( *(pus_DRegs + Reg/2) );
}
else if ( 0xffff == wBitMask )
{
wNewValue = wSetBits;
}
else
{
// read original value,
// zero out bits of interest,
// set proper bits to one
if ( (0xffff != *(pus_DRegs + (Reg/2))) || ( m_ulPowerState > 0 ) )
wNewValue = *(pus_DRegs + (Reg/2));
else
wNewValue = READ_PORT_USHORT ( (PUSHORT)(m_pPciAddr + Reg) );
wNewValue &= ~wBitMask;
wNewValue |= (wSetBits & wBitMask);
}
/* write new value to hardware */
if ( 0 == m_ulPowerState )
WRITE_PORT_USHORT ( (PUSHORT)(m_pPciAddr + Reg), wNewValue );
// save the value for the future
*(pus_DRegs + (Reg/2)) = wNewValue;
return wNewValue;
} /* end of function: hw_reg_rmw_short */
// }}}
// {{{ HwRegRMW
ULONG
CES1371::HwRegRMW ( UCHAR Reg, ULONG dwBitMask, ULONG dwSetBits )
{
ULONG dwNewValue;
// are we setting the whole data space?
if ( 0x00000000 == dwBitMask )
{
return ( m_ulDRegs[Reg/4] );
}
else if ( 0xffffffff == dwBitMask )
{
dwNewValue = dwSetBits;
}
else
{
// read original value,
// zero out bits of interest,
// set proper bits to one
if ( (0xffffffff != m_ulDRegs[Reg/4]) || ( m_ulPowerState > 0 ) )
dwNewValue = m_ulDRegs[Reg/4];
else
dwNewValue = READ_PORT_ULONG ( (PULONG)(m_pPciAddr + Reg) );
dwNewValue &= ~dwBitMask;
dwNewValue |= (dwSetBits & dwBitMask);
}
/* write new value to hardware */
if ( 0 == m_ulPowerState )
WRITE_PORT_ULONG ( (PULONG)(m_pPciAddr + Reg), dwNewValue );
// save the value for the future
m_ulDRegs[Reg/4] = dwNewValue;
return dwNewValue;
} /* end of function: hw_reg_rmw_long */
// }}}
// {{{ SRCRegRead
USHORT
CES1371::SRCRegRead( USHORT reg )
{
/* LOCAL DATA */
ULONG dtemp;
/* END LOCAL DATA */
// Is the device powered down?
if ( m_ulPowerState > 0 )
return m_usSRCRegsPMContext[ reg ];
/* wait for ready */
dtemp = SRCPollIOReg ();
/* assert a read request */
WRITE_PORT_ULONG((PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF),
(dtemp & SRC_CTLMASK) | (ULONG(reg) << 25) );
/* wait for the data */
dtemp = SRCPollIOReg ();
return (USHORT) dtemp;
}
// }}}
void
CES1371::SRCRegWrite(USHORT reg, USHORT val)
{
ULONG i, dtemp;
// Is the device powered down?
if ( m_ulPowerState > 0 )
{
m_usSRCRegsPMContext[ reg ] = val;
return;
}
/* wait for ready */
dtemp = SRCPollIOReg ();
/* assert the write request */
i = (dtemp & SRC_CTLMASK) | SRC_WENABLE |
( (ULONG)reg << 25 ) | val;
/* write the value */
WRITE_PORT_ULONG((PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF), i);
#ifdef DBG
{
USHORT us;
us = SRCRegRead ( reg );
if ( us != val )
_DbgPrintF( DEBUGLVL_TERSE, ("[SRCRegWrite] FAILED reg %02x wrote %04x read %04x", reg, val, us));
}
#endif
return;
}
// }}}
void
CES1371::SRCSetRate( UCHAR ucDMAChannel, USHORT wSampleRate )
{
ULONG i, freq, dtemp;
USHORT N, truncM, truncStart, wtemp;
// Is the device powered down?
if ( m_ulPowerState > 0 )
return;
switch ( ucDMAChannel )
{
case ES1371_DAC0:
// freeze the channel
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
if( !(READ_PORT_ULONG ( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF) ) & SRC_BUSY) )
break;
dtemp = READ_PORT_ULONG((PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF));
WRITE_PORT_ULONG( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF),
(dtemp & SRC_CTLMASK) | SRC_DAC0FREEZE);
// calculate new frequency and write it
// preserve accum
freq = ((ULONG) wSampleRate << 16) / 3000U;
SRCRegWrite( SRC_DAC0_BASE + SRC_INT_REGS_OFF,
(SRCRegRead( SRC_DAC0_BASE + SRC_INT_REGS_OFF ) & 0x00ffU) |
((USHORT) (freq >> 6) & 0xfc00));
SRCRegWrite( SRC_DAC0_BASE + SRC_VFREQ_FRAC_OFF, (USHORT) freq >> 1);
// un-freeze the channel
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
if( !(READ_PORT_ULONG ( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF) ) & SRC_BUSY) )
break;
dtemp = READ_PORT_ULONG((PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF));
WRITE_PORT_ULONG( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF),
(dtemp & SRC_CTLMASK) & (~SRC_DAC0FREEZE) );
break;
case ES1371_DAC1:
// freeze the channel
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
if( !(READ_PORT_ULONG ( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF) ) & SRC_BUSY) )
break;
dtemp = READ_PORT_ULONG((PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF));
WRITE_PORT_ULONG( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF),
(dtemp & SRC_CTLMASK) | SRC_DAC1FREEZE);
// calculate new frequency and write it
// preserve accum
freq = ((ULONG) wSampleRate << 16) / 3000U;
SRCRegWrite( SRC_DAC1_BASE + SRC_INT_REGS_OFF,
(SRCRegRead( SRC_DAC1_BASE + SRC_INT_REGS_OFF ) & 0x00ffU) |
((USHORT) (freq >> 6) & 0xfc00));
SRCRegWrite( SRC_DAC1_BASE + SRC_VFREQ_FRAC_OFF, (USHORT) freq >> 1);
// un-freeze the channel
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
if( !(READ_PORT_ULONG ( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF) ) & SRC_BUSY) )
break;
dtemp = READ_PORT_ULONG((PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF));
WRITE_PORT_ULONG( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF),
(dtemp & SRC_CTLMASK) & (~SRC_DAC1FREEZE) );
break;
case ES1371_ADC:
// derive oversample ratio
N = wSampleRate/3000U;
if( N == 15 || N == 13 || N == 11 || N == 9 )
--N;
// truncate the filter and write n/trunc_start
truncM = (21*N - 1) | 1;
if( wSampleRate >= 24000U )
{
if( truncM > 239 )
truncM = 239;
truncStart = (239 - truncM) >> 1;
SRCRegWrite( SRC_ADC_BASE + SRC_TRUNC_N_OFF,
(truncStart << 9) | (N << 4));
}
else
{
if( truncM > 119 )
truncM = 119;
truncStart = (119 - truncM) >> 1;
SRCRegWrite( SRC_ADC_BASE + SRC_TRUNC_N_OFF,
0x8000U | (truncStart << 9) | (N << 4));
}
/* calculate new frequency and write it - preserve accum */
freq = ((48000UL << 16) / wSampleRate) * N;
wtemp = SRCRegRead( SRC_ADC_BASE + SRC_INT_REGS_OFF );
SRCRegWrite( SRC_ADC_BASE + SRC_INT_REGS_OFF,
(wtemp & 0x00ff) | ((USHORT) (freq >> 6) & 0xfc00));
SRCRegWrite( SRC_ADC_BASE + SRC_VFREQ_FRAC_OFF, (USHORT) freq >> 1);
SRCRegWrite( SRC_ADC_VOL_L, N << 8);
SRCRegWrite( SRC_ADC_VOL_R, N << 8);
break;
}
return;
}
//--------------------------------------------------------------------------
//
// Name: SRCWaitForFrame1
//
// Description: code that polls a value in the SRC converter so that we know
// when it is safe to write.
//
// Parameters: PFRAME_CONTEXT
//
// Returns: always succeeds
//
// Note: Apparently, we can't do CODEC writes when the sync pulse is high.
// Luckily, there are some debug things in the SRC that let us know
// when sync pulse is low. This needs to be synched with the ISR so
// we don't get interrupted and lose track of where we are.
//
//--------------------------------------------------------------------------
void
CES1371::SRCWaitForFrame1 ( )
{
while( !((READ_PORT_ULONG( (PULONG)(m_pPciAddr + ES1371_dSRCIO_OFF) ) & 0x00070000UL) ==
0x00010000UL) )
//<mod:ce> KeStallExecutionProcessor(1);
return;
}
// }}}
// {{{ SRCPollIOReg
//--------------------------------------------------------------------------
//
// Name: SRCPollIOReg
//
// Description:
//
// Parameters:
//
// Returns:
//
// Note: This function must be called prior to any
// writes to the Disable/Pause bits
//
//--------------------------------------------------------------------------
ULONG
CES1371::SRCPollIOReg ()
{
int i;
ULONG dw=0;
for (i=0; i<SRC_IOPOLL_COUNT; ++i)
{
if (!((dw = READ_PORT_ULONG ((PULONG)(m_pPciAddr+ES1371_dSRCIO_OFF))) & SRC_BUSY) )
break;
//<mod:ce> KeStallExecutionProcessor (1);
}
#ifdef DBG
if (i == SRC_IOPOLL_COUNT)
_DbgPrintF( DEBUGLVL_TERSE, ("[SRCPollIOReg] timeout %x", dw));
#endif
return dw;
}
// }}}
//--------------------------------------------------------------------------
//
// Name: InitDMAChannel
//
// Description: Intialize all the things about a DMA channel
//
// Parameters: UCHAR ucDMAChannel : Index of the DMA channel to init
// ULONG ulPhysDMAAddr : Physical address of the DMA buffer
// in memory
// USHORT usBufferSize : Number of bytes in a DMA buffer
//
// Returns: none
//
// Note:
//
//--------------------------------------------------------------------------
void
CES1371::InitDMAChannel( UCHAR ucDMAChannel,
ULONG ulPhysDMAAddr,
ULONG ulBufferSize )
{
ULONG ulFrameCount = 0;
m_dmachannel[ucDMAChannel].ulPhysDMAAddr = ulPhysDMAAddr;
m_dmachannel[ucDMAChannel].ulDMABufSize = ulBufferSize;
switch ( ucDMAChannel )
{
case ES1371_DAC0 :
// Set up the physical DMA buffer address
HwPagedIOWrite( ES1371_DAC0CTL_PAGE, ES1371_dDAC0PADDR_OFF, ulPhysDMAAddr);
// Clear out the Frame count register
HwPagedIOWrite( ES1371_DAC0CTL_PAGE, ES1371_wDAC0FC_OFF, ulFrameCount);
break;
case ES1371_DAC1 :
// Set up the physical DMA buffer address
HwPagedIOWrite( ES1371_DAC1CTL_PAGE, ES1371_dDAC1PADDR_OFF, ulPhysDMAAddr);
// Clear out the Frame count register
HwPagedIOWrite( ES1371_DAC1CTL_PAGE, ES1371_wDAC1FC_OFF, ulFrameCount);
break;
case ES1371_ADC :
// Set up the physical DMA buffer address
HwPagedIOWrite( ES1371_ADCCTL_PAGE, ES1371_dADCPADDR_OFF, ulPhysDMAAddr);
// Clear out the Frame count register
HwPagedIOWrite( ES1371_ADCCTL_PAGE, ES1371_wADCFC_OFF, ulFrameCount);
break;
}
return ;
}
//--------------------------------------------------------------------------
//
// Name: SetDMAChannelFormat
//
// Description: Set the Format of a particular DMA channel.
//
// Parameters: UCHAR ucDMAChannel : Index of the DMA channel to init
// ULONG ulChannels : Number of audio channels 1=mono 2=stereo
// ULONG ul16Bit : flag for sample size 0=8bit 1=16bit
// ULONG ulSampleRate : actual number of samples/second.
//
// Returns: none
//
// Note:
//
//--------------------------------------------------------------------------
void
CES1371::SetDMAChannelFormat( UCHAR ucDMAChannel,
ULONG ulChannels,
ULONG ul16Bit,
ULONG ulSampleRate )
{
UCHAR ucFormatBits;
UCHAR ucSkipCount;
// save off the info for power managment
m_dmachannel[ucDMAChannel].ulChannels = ulChannels;
m_dmachannel[ucDMAChannel].ul16Bit = ul16Bit;
m_dmachannel[ucDMAChannel].ulSampleRate = ulSampleRate;
// first set the new sample rate
SRCSetRate ( ucDMAChannel, (USHORT) ulSampleRate );
switch ( ucDMAChannel )
{
case ES1371_DAC0 :
// set format bits for DAC0 ...
ucFormatBits = 0x00;
if( 2 == ulChannels )
ucFormatBits |= ES1371_PCM_DAC0_STEREO ;
if( 1 == ul16Bit )
ucFormatBits |= ES1371_PCM_DAC0_16BIT ;
HwRegRMW( ES1371_bSERFMT_OFF,
ES1371_PCM_DAC0_STEREO|ES1371_PCM_DAC0_16BIT,
ucFormatBits );
break;
case ES1371_DAC1 :
// set format bits for DAC1 ...
ucFormatBits = 0x00;
if( 2 == ulChannels )
ucFormatBits |= ES1371_PCM_DAC1_STEREO ;
if( 1 == ul16Bit )
{
ucFormatBits |= ES1371_PCM_DAC1_16BIT ;
// set the SKIP register for proper playback
ucSkipCount = 0x10;
HwRegRMW( ES1371_bSKIPC_OFF, 0x18, ucSkipCount );
}
else
{ // set the SKIP register for proper playback
ucSkipCount = 0x08;
HwRegRMW( ES1371_bSKIPC_OFF, 0x18, ucSkipCount );
}
HwRegRMW( ES1371_bSERFMT_OFF,
ES1371_PCM_DAC1_STEREO|ES1371_PCM_DAC1_16BIT,
ucFormatBits );
break;
case ES1371_ADC :
// set format bits for ADC ...
ucFormatBits = 0x00;
if( 2 == ulChannels )
ucFormatBits |= ES1371_PCM_ADC_STEREO ;
if( 1 == ul16Bit )
ucFormatBits |= ES1371_PCM_ADC_16BIT ;
HwRegRMW( ES1371_bSERFMT_OFF,
ES1371_PCM_ADC_STEREO|ES1371_PCM_ADC_16BIT,
ucFormatBits );
break;
}
return ;
}
//--------------------------------------------------------------------------
//
// Name: SetDMAChannelBuffer
//
// Description: Set the buffer sizes of a particular DMA channel.
//
// Parameters: UCHAR ucDMAChannel : Index of the DMA channel to init
// ULONG ulBufferLength : Size in bytes of the whole DMA buffer
// ULONG ulSamplesPerInt : Count of samples before interrupting
//
// Returns: none
//
// Note:
//
//--------------------------------------------------------------------------
void
CES1371::SetDMAChannelBuffer( UCHAR ucDMAChannel,
ULONG ulBufferLength,
ULONG ulSamplesPerInt )
{
ULONG ulDesiredBufferSize = m_dmachannel[ucDMAChannel].ulDMABufSize;
USHORT usInterruptCount = (USHORT) (ulSamplesPerInt - 1);
m_dmachannel[ucDMAChannel].ulBufferLength = ulBufferLength;
m_dmachannel[ucDMAChannel].ulSamplesPerInt = ulSamplesPerInt;
// buffer can't be bigger than half the physical buffer
ulDesiredBufferSize = MIN( ulDesiredBufferSize, ulBufferLength ) ;
switch ( ucDMAChannel )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -