#pragma once
//
// 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.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

   
Module Name:	HWCTXT.H

Abstract:		Platform dependent code for the mixing audio driver.
  
Environment:	Samsung SC2440 CPU and Windows 3.0 (or later)
    
-*/

#include <oalintr.h>
#include <pm.h>
#include <s2440.h>
#include "ac97.h"
//#include "hw_ac97.h"

#include "pmplatform.h"

#define OUTCHANNELS (2)
#define INCHANNELS (2)
#define BITSPERSAMPLE (16)
#define SAMPLERATE  (44100)

// Inverse sample rate, in .32 fixed format, with 1 added at bottom to ensure round up.
#define INVSAMPLERATE ((UINT32)(((1i64<<32)/SAMPLERATE)+1))

typedef INT16 HWSAMPLE;
typedef HWSAMPLE *PHWSAMPLE;

// Set USE_MIX_SATURATE to 1 if you want the mixing code to guard against saturation
// This costs a couple of instructions in the inner loop
#define USE_MIX_SATURATE (1)
// The code will use the follwing values as saturation points
#define AUDIO_SAMPLE_MAX    (32767)
#define AUDIO_SAMPLE_MIN    (-32768)

#define AUDIO_DMA_PAGE_SIZE		2048					// Size in bytes			

//----- Used to track DMA controllers status -----
#define DMA_CLEAR			0x00000000
#define DMA_STRTA			0x00000001
#define DMA_DONEA			0x00000002
#define DMA_STRTB			0x00000010
#define DMA_DONEB			0x00000020
#define DMA_BIU				0x00000080					// DMA BUFFER PAGE Select (0 = A, 1 = B)

//----- Used for scheduling DMA transfers -----
#define  OUT_BUFFER_A		0							
#define  OUT_BUFFER_B		1
#define	 IN_BUFFER_A		0
#define  IN_BUFFER_B		1


class HardwareContext
{
public:
    static BOOL CreateHWContext(DWORD Index);
    HardwareContext();
    ~HardwareContext();

    void Lock()   {EnterCriticalSection(&m_Lock);}
    void Unlock() {LeaveCriticalSection(&m_Lock);}

    DWORD GetNumInputDevices()  {return 1;}
    DWORD GetNumOutputDevices() {return 1;}

    DeviceContext *GetInputDeviceContext(UINT DeviceId)
    {
        return &m_InputDeviceContext;
    }

    DeviceContext *GetOutputDeviceContext(UINT DeviceId)
    {
        return &m_OutputDeviceContext;
    }

    BOOL AC97_Init();

    BOOL Init(DWORD Index);										
    BOOL Deinit();

    void PowerUp();
    void PowerDown();

    BOOL StartInputDMA();
    BOOL StartOutputDMA();

    void StopInputDMA();
    void StopOutputDMA();

    void InterruptThread();

	DWORD ForceSpeaker (BOOL bSpeaker);
	
    // IOCTL pass-through
    BOOL IOControl( DWORD  dwOpenData,
                    DWORD  dwCode,
                    PBYTE  pBufIn,
                    DWORD  dwLenIn,
                    PBYTE  pBufOut,
                    DWORD  dwLenOut,
                    PDWORD pdwActualOut);

    DWORD Open();
    DWORD Close();
    
    CEDEVICE_POWER_STATE GetDx() { return m_Dx;}
    
protected:

    DWORD m_MicrophoneRouting;
    DWORD m_SpeakerRouting;
    DWORD m_InternalRouting;
    DWORD m_MasterOutputGain;

    BOOL InitInterruptThread();

    BOOL InitInputDMA();
    BOOL InitOutputDMA();
    BOOL Codec_channel();
    BOOL InitCodec();
    
    BOOL MapRegisters();
    BOOL UnmapRegisters();
    BOOL MapDMABuffers();
	BOOL UnmapDMABuffers();

    ULONG TransferInputBuffer(ULONG NumBuf);
    ULONG TransferOutputBuffer(ULONG NumBuf);
    ULONG TransferInputBuffers(DWORD dwDCSR);
    ULONG TransferOutputBuffers(DWORD dwDCSR);


    DWORD GetInterruptThreadPriority();

    DWORD m_DriverIndex;
    CRITICAL_SECTION m_Lock;

    BOOL m_Initialized;
    BOOL m_InPowerHandler;
    DWORD m_IntrAudio;

    InputDeviceContext m_InputDeviceContext;
    OutputDeviceContext m_OutputDeviceContext;

    PBYTE		m_Input_pbDMA_PAGES[2];
    PBYTE		m_Output_pbDMA_PAGES[2];

    BOOL m_InputDMARunning;
    BOOL m_OutputDMARunning;
    ULONG m_OutBytes[2];
    ULONG m_InBytes[2];

    WORD  m_nOutputVolume;					// Current HW Playback Volume 
    WORD  m_nInputVolume;					// Current HW Input (Microphone) Volume 

	HANDLE m_hAudioInterrupt;				// Handle to Audio Interrupt event.
    HANDLE m_hAudioInterruptThread;			// Handle to thread which waits on an audio interrupt event.

	//----------------------- Platform specific members ----------------------------------

	DWORD  m_OutputDMAStatus;					// Output DMA channel's status
	DWORD  m_InputDMAStatus;					// Input DMA channel's status

	BOOL AudioMute(DWORD channel, BOOL bMute);	
	//------------------------------------------------------------------------------------

	LONG m_NumForcedSpeaker;
    void SetSpeakerEnable(BOOL bEnable);
    void RecalcSpeakerEnable();
	
	CEDEVICE_POWER_STATE    m_Dx;
};

void CallInterruptThread(HardwareContext *pHWContext);


//----------------------------------- Helper Functions and Macros ----------------------------------------

//======== Playback =========
#define ioPlaybackPointerLow			(v_pDMAregs->rDISRC1)
#define ioPlaybackPointerHigh			(v_pDMAregs->rDISRC1)

#define PLAY_DMA_BUFFER_PHYS			( AUDIO_DMA_BUFFER_PHYS )
#define AUDIO_RESET_PLAYBACK_POINTER()	{ ioPlaybackPointerLow  = (PLAY_DMA_BUFFER_PHYS); }
						 				 //ioPlaybackPointerHigh = (AUDIO_DMA_BUFFER_PHYS + AUDIO_DMA_PAGE_SIZE); 

#define AUDIO_OUT_CLEAR_INTERRUPTS()	( v_pDMAregs->rDCON1 = v_pDMAregs->rDCON1 )

#define AUDIO_OUT_DMA_ENABLE()			{ v_pDMAregs->rDMASKTRIG1 |= ENABLE_DMA_CHANNEL; }
													
#define AUDIO_OUT_DMA_DISABLE()			{ v_pDMAregs->rDMASKTRIG1 &= ~ENABLE_DMA_CHANNEL; }
							

#define SELECT_AUDIO_DMA_OUTPUT_BUFFER_A()	(v_pDMAregs->rDISRC1 = (int)(PLAY_DMA_BUFFER_PHYS) )
#define SELECT_AUDIO_DMA_OUTPUT_BUFFER_B()	(v_pDMAregs->rDISRC1 = (int)(PLAY_DMA_BUFFER_PHYS+AUDIO_DMA_PAGE_SIZE) )


//======== Record =========
#define ioRecordPointerLow				(v_pDMAregs->rDIDST2)
#define ioRecordPointerHigh				(v_pDMAregs->rDIDST2)

#define RECORD_DMA_BUFFER_PHYS			( AUDIO_DMA_BUFFER_PHYS + 2 * AUDIO_DMA_PAGE_SIZE)

#define AUDIO_RESET_RECORD_POINTER()	{ ioRecordPointerLow  = (RECORD_DMA_BUFFER_PHYS); }
						 				  //ioRecordPointerHigh = (RECORD_DMA_BUFFER_PHYS+ AUDIO_DMA_PAGE_SIZE); 

#define AUDIO_IN_CLEAR_INTERRUPTS()		( v_pDMAregs->rDCON2 = v_pDMAregs->rDCON2 )

#define AUDIO_IN_DMA_ENABLE()			{ v_pDMAregs->rDMASKTRIG2 = ENABLE_DMA_CHANNEL; \
										  v_pDMAregs->rDMASKTRIG2 &= STOP_DMA_TRANSFER; }	
													
#define AUDIO_IN_DMA_DISABLE()			{ v_pDMAregs->rDMASKTRIG2 |= STOP_DMA_TRANSFER; }

#define SELECT_AUDIO_DMA_INPUT_BUFFER_A()	(v_pDMAregs->rDIDST2 = (int)(RECORD_DMA_BUFFER_PHYS) )
#define SELECT_AUDIO_DMA_INPUT_BUFFER_B()	(v_pDMAregs->rDIDST2 = (int)(RECORD_DMA_BUFFER_PHYS+AUDIO_DMA_PAGE_SIZE) )

//------------------------------------------ Externs ----------------------------------------------
extern HardwareContext *g_pHWContext;


