class STAC9766
{
public:
	STAC9766::STAC9766();
    ~STAC9766();

    // Power Management
    ULONG SetPowerState( ULONG ulState );

    // DMA control
    MMRESULT AllocDMAChannel (ULONG ulDirection, 
                              ULONG ulSize, 
                              PULONG pulChannelIndex);
    BOOL FreeDMAChannel (ULONG ulChannelIndex);
	ULONG	GetNumFreeDMAChannels(ULONG ulDirection);
    void GetDMABuffer(      ULONG ulChannelIndex, 
                              PULONG pulBufferSize,
                              PVOID* ppvVirtAddr);
    
    void InitDMAChannel(      ULONG ulChannelIndex, 
                              DMAINTHANDLER pfHandler,
                              PVOID pvContext);

    void SetDMAChannelFormat( ULONG ulChannelIndex,
                              ULONG ulChannels,
                              ULONG ul16Bit,
                              ULONG ulSampleRate );
    void SetDMAChannelBuffer( ULONG ulChannelIndex,
                              ULONG ulBufferLength,
                              ULONG ulSamplesPerInt );
    void StartDMAChannel( ULONG ulChannelIndex );
    void StopDMAChannel( ULONG ulChannelIndex );
    void PauseDMAChannel( ULONG ulChannelIndex );
    void SetDMAInterruptPeriod( ULONG ulChannelIndex, ULONG ulSamplesPerInt);
    void SetDMALooping (ULONG ulChannelIndex, BOOL fIsLooping);
    void SetDMAVolume (ULONG ulChannelIndex, USHORT usVolLeft, USHORT usVolRight);
    ULONG GetDMAPosition( ULONG ulChannelIndex );
    void SetDMAPosition( ULONG ulChannelIndex, ULONG ulPosition );


    // Codec control
    void WriteCodecRegister( UCHAR Reg, USHORT Val);
    USHORT ReadCodecRegister( UCHAR Reg );
    void RMWCodecRegister (UCHAR Reg, USHORT Mask, USHORT Value); // Reg = (Reg & Mask) | Value
    USHORT GetCodecRegisterValue( UCHAR Reg );
    ULONG Codec_SetPowerState( ULONG ulNewState );

	// PCI routines
	BOOL AudioInitialize(CRegKey * pKey);
    BOOL MapDevice (CRegKey * pKey);


    // Sample Rate Converter
    void InitSRC( BOOLEAN fEnable );
    USHORT SRCRegRead( USHORT reg );
    void SRCRegWrite( USHORT reg, USHORT val );
    void SRCSetRate ( ULONG ulChannelIndex, USHORT wSampleRate );
    ULONG SRCPollIOReg ();
    void SRCWaitForFrame1 ();
    void SRCSaveRegisterState( void );
    void SRCRestoreRegisterState( void );

    // global variables pointing to pre-allocated memory
private:
    // Interrupts
    UCHAR GetInterruptSource( void );
    void AckDMAInterrupt( UCHAR ucIntSrc );

    // Register Access
    VOID HwPagedIOWrite( UCHAR Page, ULONG pAddr, ULONG ulData );
    ULONG HwPagedIORead( UCHAR Page, ULONG pAddr );
    ULONG HwRegRMW ( UCHAR Reg, ULONG dwBitMask, ULONG dwSetBits );
    USHORT HwRegRMW ( UCHAR Reg, USHORT wBitMask, USHORT wSetBits );
    UCHAR HwRegRMW ( UCHAR Reg, UCHAR bBitMask, UCHAR bSetBits );

    // Member Variable
    PUCHAR m_pPciAddr;
    DWORD   m_dwPciLength;
    DWORD m_dwDeviceID;             // the PCI Device ID
    DWORD m_dwRevisionID;        // the PCI chip revision
    HANDLE m_hIsrHandler;       // installable ISR handler
    DWORD m_dwBusNumber;
    DWORD m_dwInterfaceType;

    ULONG m_ulDRegs[12];  // STAC9766 direct registers
    ULONG m_ulIRegs[16];  // STAC9766 indirect registers

    // power management
    ULONG m_ulPowerState; // STAC9766 power state
    UCHAR m_ucSerialControl;
    UCHAR m_ucDeviceControl;
    ULONG m_ulDRegsPMContext[12];  
    ULONG m_ulIRegsPMContext[64];
    USHORT m_usCRegsPMContext[40];
    USHORT m_usSRCRegsPMContext[20];

    // codec
    USHORT m_usCRegs[40]; // AC97 CoDec registers
    ULONG m_ulCodecVendorID;
    ULONG m_ulCodecRevision;
    ULONG m_ulCodecPowerState; // current power state of the AC97 Codec

    // DMA
#define NUM_DMACHANNELS 3

    DMACHANNEL m_dmachannel[NUM_DMACHANNELS]; // info about dma channel states


	// PCI related variables
	DWORD	m_IntrAudio;	// Interrupt ID
	BOOL	m_fIsMapped;	// must call MmUnmapIoSpace when destroyed

    // Initialization
    void InitHardware();

    // Power Management
    void SaveSTAC9766Context( void );
    void RetoreSTAC9766Context( void );

    // AC97 Codec
    void InitCodec();
    void Codec_WaitForPowerState( USHORT usState );
    void Codec_SaveRegisterState( USHORT *pusRegisters );
    void Codec_RestoreRegisterState( USHORT *pusRegisters );


    // UART
    void InitUART();
    UCHAR UARTWaitForTxRdy();

	// IST
	static DWORD WINAPI IST_Startup(LPVOID lpParameter);
	void IST();
	HANDLE m_hISTInterruptEvent;
	BOOL   m_bExitIST;
	HANDLE m_hISThread;

	CRITICAL_SECTION m_csPageLock;
};