⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 es1371.cpp

📁 此代码为WCE5.0下声卡的源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// 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 + -