//audio.c
#include <windows.h>
#include "ls220.h"

#ifdef LS240
	#include "ac3_240.h"
	#include "pcm_240.h"
	#include "mpg_240.h"
	#include "ac3i2s_240.h"
	#include "pcmi2s_240.h"
	#include "mpgi2s_240.h"
#else
	#include "ac3.h"
	#include "ac3i2s.h"
	#include "pcm.h"
	#include "pcmi2s.h"
	#include "mpg.h"
	#include "mpgi2s.h"
#endif

#include "dvhw32.h"
#include "audio.h"
#include "video.h"
	
#define OK

//#define LINE21

//globals
BYTE	a_m_vol;
BOOL	ac3_flag;
BOOL	a_m_fg;
BOOL	a_m_mpeg1;
int		a_m_speed;
DWORD	a_m_adj;
DWORD	a_m_total;
DWORD	a_PTS;
BOOL	a_m_mute;	// for ProComm to Support Audio on/off
int		a_m_ptscnt;
DWORD	aud_fifo_off;
DWORD	aud_fifo_len;
BOOL	m_spdif_first_play = FALSE;

DWORD	dwptsoff = 0x1c00;

int	stop_read = 0;

// volume table
DWORD	vol_table[16] = { 
		0x7fffff,
		0x6046c5,
		0x4c79a0,
		0x3cbf0f,
		0x3040a5,
		0x26540e,
		0x1e71fe,
		0x182efd,
		0x1335ad,
		0xf4240,
		0xc1ed8,
		0x9a0ad,
		0x7a5c3,
		0x6131b,
		0x4d343,
		0x0
};


extern BOOL	m_spdif;
extern BYTE eprom[16];

#ifdef DBG
	extern ULONG DbgPrint(PCH pchFormat, ...);
#endif

// #define LS240_PM	// power saving for LS240

void waitup_dsp();
void Wait();

extern DWORD luxbase;
extern DWORD BASE;
extern VOID KeStallExecutionProcessor(IN ULONG MicroSeconds);

extern int	m_noVideo;

/////////////////////////////////////////////////////////////////////////
void waitup_dsp()
{
DWORD dwcnt = 0;

	dwcnt = DVReadReg(0x10);
	dwcnt &= 0xfffffff7;
	dwcnt |= 0x30;
	DVWriteREG(0x10,dwcnt);
}

void Wait()
{
DWORD dwcnt = 0;

#ifdef LS240_PM
	waitup_dsp();
#endif

	DVReadReg(0x250);	

	while(DVReadDRAM(DSPMEM_CMD) != 0x100)
	{
#ifdef LS240_PM
		waitup_dsp();
#endif

		KeStallExecutionProcessor(50);

		if(dwcnt++ >= 0xfff)
		{
			#ifdef DBG
				DbgPrint("luxdvd ERROR : wait timed out !!!!\n");
			#endif
			break;
		}
	}
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioVarInit()
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioVarInit\n");
	#endif

	a_m_mute = FALSE;	// ProComm
	a_m_total = 0;
	a_PTS = 0;
	a_m_mpeg1 = FALSE;	// init to AC/3
	a_m_fg = TRUE;
	a_m_vol = 15;		
	a_m_adj = 0x600;

	ac3_flag = 1;
	
	a_m_ptscnt = 0;

	a_m_speed = 0;

	stop_read = 0;
}

/////////////////////////////////////////////////////////////////////////

BOOL LUXAudioDsp_Init(BOOL ac3)
{
	DVWriteDRAM(DSPMEM_AC3_CONF,0x3400L);	// Prologic DownMixing , org is 0x240f , to increase 
											// volumn , we use 0x340f

	ac3_flag = ac3;
			
	if( (int)ac3 == 1 )
	{
		#ifdef DBG
			DbgPrint("luxdvd : LUXAudioDsp_Init for AC3\n");
		#endif

		a_m_adj = 0x600;
		DVWriteDRAM(DSPMEM_CMD,DSP_CMD_AC3);
	}
	else if( (int) ac3 == 0 )	// PCM
	{
		#ifdef DBG
			DbgPrint("luxdvd : LUXAudioDsp_Init for PCM\n");
		#endif

		a_m_adj = 0x600;
		DVWriteDRAM(DSPMEM_CMD,DSP_CMD_PCM);
	}
	else if( (int) ac3 == 2 )	//MPG 1 Audio
	{
		a_m_adj = 0x0;
		DVWriteDRAM(DSPMEM_CMD,DSP_CMD_MPEG1);
	}

	Wait();

	LUXAudioSetVolume(a_m_vol);
	
	aud_fifo_off = DVReadDRAM(DSPMEM_FIFO_START);
	aud_fifo_len = DVReadDRAM(DSPMEM_FIFO_END) - DVReadDRAM(DSPMEM_FIFO_START);
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////

BOOL LUXAudioInit(BOOL type)
{
	#ifdef DBG
		DbgPrint("luxdvd : LUXAudioInit with type=%d\n",type);
	#endif

	a_m_mpeg1 = 0;	//not ready for mpg1

	#ifdef	OK		// for LS220
		DVWriteREG(0x24,0x0);

		#ifdef OLD
			DVWriteREG(0x104,0x0);		// dsp run
			DVWriteREG(0x100,0x7c600L);
			DVWriteREG(0x104,0x1);		// dsp run
			KeStallExecutionProcessor(200);//Sleep(20);			// wait for DSP
			DVWriteDRAM(DSPMEM_FIFO_WR,AUD_FIFO_OFF);
			DVWriteDRAM(DSPMEM_FIFO_RD,AUD_FIFO_OFF);
			DVWriteDRAM(DSPMEM_PTS_WR,AUD_PTS_OFF);
			DVWriteDRAM(DSPMEM_PTS_RD,AUD_PTS_OFF);
		#endif

		LUXAudioDsp_Init(type);
	#endif

	a_m_total = 0;
	a_PTS = 0;
	a_m_ptscnt = 0;

	if ( ac3_flag == 2 )	// for MPEG only
		a_m_ptscnt = 1;

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////

DWORD LUXAudioSendData(BYTE *pdata, BYTE *p, DWORD len, DWORD pts, BOOL b_scr, WORD aoff)
{
DWORD	dstoff;
DWORD	srcoff;
DWORD	hwspace,size;
DWORD	arptr,awptr;
DWORD	dwcnt=0;
DWORD	dwloop=0;
DWORD   datalen=len;
DWORD	off;
BYTE	*ptr=NULL;

	if(a_m_speed != 1000)
		return len;
	    	
	awptr = DVReadDRAM(DSPMEM_FIFO_WR);
	arptr = DVReadDRAM(DSPMEM_FIFO_RD);
	hwspace = (awptr >= arptr)?(aud_fifo_len+arptr-awptr):(arptr-awptr);
	
	if(hwspace < (datalen+32))	//not enough room in aud fifo
	{
		return 0;
	}

  	if( pts )	//program PTS
	{
		if(ac3_flag != 2)
			a_m_ptscnt++;

	#ifndef LS240
		if( (a_m_ptscnt % 10) ==  1 )
		{
	#endif
			if( !LUXAudioWritePTS(pts + a_m_adj, aoff) )
			{
				#ifdef DBG
					DbgPrint("luxdvd ERROR : LUXAudioMoveData - Write PTS failed !!!!\n");
				#endif
				return 0;
			}
	#ifndef LS240
		}
	#endif
	}

	if ( m_noVideo >= 0 )
	{
		if ( m_noVideo++ >= 10 )
		{
			m_noVideo = -1;
			LUXVideoFlush();
			LUXVideoSeq_end();
		}
	}

	srcoff  = (DWORD)p;
	dstoff	= DRAM_BASE + awptr;
	hwspace	= aud_fifo_len+aud_fifo_off - awptr;
	
	if( b_scr )		//check for scramble
	{
		ptr = (BYTE *)p;
		off = awptr + pdata + 80 - ptr;

		if (off >= (aud_fifo_off+aud_fifo_len))
			off -= aud_fifo_len;

		#ifdef LS240
			DVWriteREG(0x28,off|0x400000);
			dstoff = awptr-0x100000L;
		#else
			DVWriteREG(0x24,off|0x400000);
		#endif

	}
	
    if ( hwspace >= datalen) 
	{		// check circle
		DVMoveStr(dstoff,srcoff,datalen);
	} 
	else 
	{
		DVMoveStr(dstoff,srcoff,hwspace);

		dstoff = DRAM_BASE + aud_fifo_off;

		#ifdef LS240
			if (b_scr)
				dstoff = aud_fifo_off-0x100000L;
		#endif
		size = len - hwspace;
		
		DVMoveStr(dstoff,(DWORD)(srcoff+hwspace),size);
	}

	awptr += datalen;
	if (awptr >= (aud_fifo_off+aud_fifo_len))
		awptr -= (aud_fifo_len);

	#ifdef LS240
		DVWriteREG(0x28,0x0L);
	#else
		DVWriteREG(0x24,0x0L);
	#endif

	
	DVWriteDRAM(DSPMEM_FIFO_WR,awptr);
	a_m_total += datalen;		// update the real length first

	return len;
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioPlay(int speed)
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioPlay\n");
	#endif
	
	a_m_speed = speed;

	if (speed == 1000) 
	{
		#ifdef	LS240
			DVWriteREG(0x280,0x8L);	//
			DVWriteREG(0x280,0x9L);	//
			DVWriteREG(0x29c,0x30008235L);	//
			DVWriteREG(0x200,0x419);	
			DVWriteREG(0x200,0x3b);	
		#else
			DWORD tmp = DVReadDRAM(SYNC_AUD_CONTROL);
	//		DVWriteREG(SYNC_AUD_CONTROL,tmp|0x22);
			DVWriteREG(SYNC_AUD_CONTROL,tmp|0x20);
		#endif

		DVWriteDRAM(DSPMEM_CMD,DSP_CMD_PLAY);
		
		Wait();

		if ( eprom[EPROM_BOARDTYPE] == 3 && !m_spdif )	// PCM Output
		{
			DVWriteREG(0x350,DVReadReg(0x350)|0x010100);
		}
		
		if ( !(eprom[EPROM_SPDIF_CH]&0x2) && m_spdif && m_spdif_first_play)	// do spdif
		{
			m_spdif_first_play = FALSE;	// do only once

			DVWriteDRAM(DSPMEM_CMD,DSP_CMD_INITDONE);
			
			Wait();
		}
		
	} 
#ifndef CHANGE_REG274
	else 
	{
		if ( (int)ac3_flag == 1 )
			DVWriteDRAM(DSPMEM_CMD,DSP_CMD_AC3);
		else if ( (int)ac3_flag == 0 )
			DVWriteDRAM(DSPMEM_CMD,DSP_CMD_PCM);
		else if ( (int)ac3_flag == 2 )
			DVWriteDRAM(DSPMEM_CMD,DSP_CMD_MPEG1);

		
		Wait();

		a_m_total = 0;
		a_PTS = 0;
		a_m_ptscnt = 0;
	}
#endif
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioSetSpeed(int speed)
{
	a_m_speed = speed;
}

/////////////////////////////////////////////////////////////////////////

DWORD LUXAudioGetSpeed()
{
	return a_m_speed;
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioSetConfig(BOOL sixch)
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioSetConfig\n");
	#endif

	if ( ac3_flag )
	{
		if ( (sixch==1) && !(eprom[EPROM_SPDIF_CH]&0x1) )
			DVWriteDRAM(DSPMEM_AC3_CONF,0x340fL);	// six channels
		else
		{
			switch (sixch)
			{
				case 0:	// No Six Channels , use default Prologic 
				case 1: // Want to use 6 channels , but this board doesn't support
				case 3:	// use default Prologic
					DVWriteDRAM(DSPMEM_AC3_CONF,0x3400L); // Prologic Downmixing
					break;
				case 2:	// No Six Channels , but use Two channels downmixing 
					DVWriteDRAM(DSPMEM_AC3_CONF,0x3402L);
					break;
			}
		}
	}
	else
	{
		if ( (DWORD) sixch > 1 ) 
			DVWriteDRAM(DSPMEM_AC3_CONF,(DWORD)sixch); // PCM
	}
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioSetDSPType(int type)
{
	ac3_flag = type;
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioSetSPDIF(BOOL onoff)
{
DWORD tmp;
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioSetSPDIF\n");
	#endif

	#ifdef OLD
		DVWriteDRAM(DSPMEM_SPDIF,(DWORD)onoff);		// 0 is off, 1 is on
	#else
		tmp = DVReadDRAM(DSPMEM_AUDIO_CONF);

		if ( onoff )
		{
			DVWriteDRAM(DSPMEM_AUDIO_CONF,tmp|0x80);	// turn on spdif
		}
		else
		{
			DVWriteDRAM(DSPMEM_AUDIO_CONF,tmp&0x7f);	// turn off spdif
		}
	#endif
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioStop()
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioStop\n");
	#endif

	stop_read = 0;

	DVWriteDRAM(DSPMEM_CMD,DSP_CMD_MUTE);
	
	Wait();

	//new for avthread
	DVWriteDRAM(DSPMEM_PTS_WR,AUD_PTS_OFF);
	DVWriteDRAM(DSPMEM_PTS_RD,AUD_PTS_OFF);

	if ( (int)ac3_flag == 1 )
		DVWriteDRAM(DSPMEM_CMD,DSP_CMD_AC3);
	else if ( (int)ac3_flag == 0 )
		DVWriteDRAM(DSPMEM_CMD,DSP_CMD_PCM);
	else if ( (int)ac3_flag == 2 )
		DVWriteDRAM(DSPMEM_CMD,DSP_CMD_MPEG1);

	
	Wait();

	LUXAudioSetVolume(a_m_vol);

	a_m_total = 0;
	a_PTS = 0;
	a_m_ptscnt = 0;

	if ( ac3_flag == 2 )	// for MPEG only
		a_m_ptscnt = 1;

}

/////////////////////////////////////////////////////////////////////////

void LUXAudioMute()
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioMute\n");
	#endif

//	DVWriteDRAM(DSPMEM_CMD,DSP_CMD_PAUSE);
//	while(DVReadDRAM(DSPMEM_CMD))
//		PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);

	DVWriteDRAM(DSPMEM_CMD,DSP_CMD_STOPF);
	
	Wait();
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioPause()
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioPause\n");
	#endif

	DVWriteDRAM(DSPMEM_CMD,DSP_CMD_PAUSE);
	
	Wait();
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioContinue()
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioContinue\n");
	#endif

	DVWriteDRAM(DSPMEM_CMD,DSP_CMD_PLAY);
	
	Wait();
}

/////////////////////////////////////////////////////////////////////////

DWORD LUXAudioReportFrame()
{
DWORD dwval = 0;

	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioReportFrame\n");
	#endif

	DVWriteDRAM(DSPMEM_CMD,DSP_CMD_FRAME);
	
	Wait();
	dwval = DVReadDRAM(DSPMEM_STATUS);

	return dwval;
}

/////////////////////////////////////////////////////////////////////////

DWORD LUXAudioReportStatus()
{
DWORD dwval = 0;

	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioReportStatus\n");
	#endif

	DVWriteDRAM(DSPMEM_CMD,DSP_CMD_STATUS);
	
	Wait();
	dwval = DVReadDRAM(DSPMEM_STATUS);

	return dwval;
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioAudOnOff(BOOL onoff)
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioAudOnOff\n");
	#endif

	a_m_mute = onoff;

	if ( !a_m_mute )	// no mute , restore current setting
	{
		LUXAudioSetVolume(a_m_vol);
	}
	else	// mute , can't call setvolume , because don't want to change m_vol
	{
		DVWriteDRAM(DSPMEM_VOLUME_LEVEL,vol_table[15]);
		DVWriteDRAM(DSPMEM_CMD,DSP_CMD_VOLUME);
		
		Wait();
	}
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioAfterSeek()
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioAfterSeek\n");
	#endif

#ifdef OLD
	DVWriteDRAM(DSPMEM_FIFO_WR,AUD_FIFO_OFF);
	DVWriteDRAM(DSPMEM_FIFO_RD,AUD_FIFO_OFF);
#endif
	DVWriteDRAM(DSPMEM_FIFO_WR,aud_fifo_off);
	DVWriteDRAM(DSPMEM_FIFO_RD,aud_fifo_off);
	DVWriteDRAM(DSPMEM_PTS_WR,AUD_PTS_OFF);
	DVWriteDRAM(DSPMEM_PTS_RD,AUD_PTS_OFF);
}

/////////////////////////////////////////////////////////////////////////

BOOL LUXAudioWritePTS(DWORD pts,WORD aoff)
{
DWORD	pRd,pWr,space;
DWORD	dwVal;

	pRd = DVReadDRAM(DSPMEM_PTS_RD);
	pWr = DVReadDRAM(DSPMEM_PTS_WR);
	space = (pWr >= pRd)? (AUD_PTS_LEN+pRd-pWr):(pRd-pWr);

	if (space < 0x8)	 //space need to be at least 0x10
		return FALSE;

	#ifndef LS240	// DSP will do this
		if (!a_PTS) 
		{
			dwVal = DVReadDRAM(0x200);
			DVWriteREG(0x200,(dwVal&0xfbf));       //audio master
		}
	#endif
	
	DVWriteDRAM(DRAM_BASE+pWr,pts);	
	pWr += 4;
	DVWriteDRAM(DRAM_BASE+pWr,a_m_total+aoff);
	pWr += 4;
	
	if (pWr >= (AUD_PTS_OFF+AUD_PTS_LEN))
		pWr -= AUD_PTS_LEN;

	DVWriteREG(DSPMEM_PTS_WR,pWr);

	a_PTS = pts;
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioStopDSP()
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioStopDSP\n");
	#endif

	DVWriteREG(0x104,0x0);		// dsp stop

	#ifdef CHANGE_REG274
		#ifdef LINE21
			DVWriteREG(SYNC_INT_CTRL,0x8000 | 0x100);	// 0x274
		#else
			DVWriteREG(SYNC_INT_CTRL,0x8000);	// 0x274
		#endif
	#else
		#ifdef LINE21
			DVWriteREG(SYNC_INT_CTRL,0x0 | 0x100);	// 0x274
		#else
			DVWriteREG(SYNC_INT_CTRL,0x0);	// 0x274
		#endif
	#endif
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioEnableDSP()
{
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioEnableDSP\n");
	#endif

	DVWriteREG(0x100,0x7c600);
	DVWriteREG(0x104,0x1);		// dsp run
	KeStallExecutionProcessor(100);
	#ifdef LS240
		#ifdef LINE21
			DVWriteREG(SYNC_INT_CTRL,0x38000001L | 0x100);
		#else
			DVWriteREG(SYNC_INT_CTRL,0x38000001L);
		#endif
	#else
		#ifdef CHANGE_REG274
			#ifdef LINE21
				DVWriteREG(SYNC_INT_CTRL,0xe8001L | 0x100);
			#else
				DVWriteREG(SYNC_INT_CTRL,0xe8001L);
			#endif
		#else
			#ifdef LINE21
				DVWriteREG(SYNC_INT_CTRL,0xe0001L | 0x100);
			#else
				DVWriteREG(SYNC_INT_CTRL,0xe0001L);
			#endif
		#endif
	#endif
}

/////////////////////////////////////////////////////////////////////////

// value should not greater than 15
void LUXAudioSetVolume(BYTE val)
{
DWORD	vol;
	
	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioSetVolume\n");
	#endif
		
	if (a_m_mute)
		return;

	if(val == 0xff)
	{
		#ifdef DBG
			//DbgPrint("luxdvd : LUXAudioSetVolume - performing MUTE\n");
		#endif
		DVWriteREG(DSPMEM_CMD,DSP_CMD_MUTE);
		
		Wait();
		val = 0;
	}
	else
		a_m_vol = val;	

	DVWriteDRAM(DSPMEM_VOLUME_LEVEL,vol_table[15-val]);

	DVWriteDRAM(DSPMEM_CMD,DSP_CMD_VOLUME);
	
	Wait();
}

/////////////////////////////////////////////////////////////////////////

void LoadUcode(BYTE ucode)
{
DWORD dstoff=0;
int loop=0;
DWORD	size;
BOOL b_i2s = FALSE;

	#ifdef DBG
		DbgPrint("luxdvd : LoadUcode for ");
		if( ucode == 1 ) 
			DbgPrint("AC3\n");
		else if ( ucode == 2 )
			DbgPrint("MPG\n");
		else
			DbgPrint("PCM\n");
	#endif

	if ( eprom[EPROM_I2S]==0x03 )
	{
		#ifdef DBG
			DbgPrint("luxdvd LoadUcode - loading I2S version !!!!!\n");
		#endif
		b_i2s = TRUE;		
	}
	else
	{
		b_i2s = FALSE;
	}

	// --------- First Array -----------------

	dstoff = DRAM_BASE + 0x1f1800;

	if(ucode==1)	//AC3
	{
		#ifdef LS240
			if ( !b_i2s )
				size = sizeof( AC3240Ucode1f1800)/4;
			else
				size = sizeof( AC3I2S240Ucode1f1800)/4;
		#else
			if(!b_i2s)
				size = sizeof( AC3Ucode1f1800)/4;
			else
				size = sizeof( AC3I2SUcode1f1800)/4;
		#endif
	}
	else if ( ucode == 2)	// MPG
	{
		#ifdef LS240
			if ( !b_i2s )
				size = sizeof( MPG240Ucode1f1800)/4;
			else
				size = sizeof( MPGI2S240Ucode1f1800)/4;
		#else
			if ( !b_i2s )
				size = sizeof( MPGUcode1f1800)/4;
			else
				size = sizeof( MPGI2SUcode1f1800)/4;
		#endif
	}
	else			//PCM
	{
		#ifdef LS240
			if(!b_i2s)
				size = sizeof( PCM240Ucode1f1800)/4;
			else
				size = sizeof( PCMI2S240Ucode1f1800)/4;
		#else
			if(!b_i2s)
				size = sizeof( PCMUcode1f1800)/4;
			else
				size = sizeof( PCMI2SUcode1f1800)/4;
		#endif
	}

	#ifdef DBG
		DbgPrint("luxdvd : LoadUcode - loading 1st section to 0x%lx\n",dstoff);
	#endif

	for(loop=0; loop < (int)size; loop++)
	{
		if(ucode==1)	// AC3
		{
			#ifdef LS240
				if(!b_i2s)
					DVWriteDRAM(dstoff,AC3240Ucode1f1800[loop]);
				else
					DVWriteDRAM(dstoff,AC3I2S240Ucode1f1800[loop]);
			#else
				if(!b_i2s)
					DVWriteDRAM(dstoff,AC3Ucode1f1800[loop]);
				else
					DVWriteDRAM(dstoff,AC3I2SUcode1f1800[loop]);
			#endif
		}
		else if ( ucode == 2 )	// MPG
		{
			#ifdef LS240
				if(!b_i2s)
					DVWriteDRAM(dstoff,MPG240Ucode1f1800[loop]);
				else
					DVWriteDRAM(dstoff,MPGI2S240Ucode1f1800[loop]);
			#else
				if(!b_i2s)
					DVWriteDRAM(dstoff,MPGUcode1f1800[loop]);
				else
					DVWriteDRAM(dstoff,MPGI2SUcode1f1800[loop]);
			#endif
		}
		else			// PCM
		{
			#ifdef LS240
				if(!b_i2s)
					DVWriteDRAM(dstoff,PCM240Ucode1f1800[loop]);
				else
					DVWriteDRAM(dstoff,PCMI2S240Ucode1f1800[loop]);
			#else
				if(!b_i2s)
					DVWriteDRAM(dstoff,PCMUcode1f1800[loop]);
				else
					DVWriteDRAM(dstoff,PCMI2SUcode1f1800[loop]);
			#endif
		}

		dstoff += 4;
	}

	// --------- 2nd Array -----------------

	if(ucode==1)	// AC3
	{
		dstoff = DRAM_BASE + 0x1f8000;

		#ifdef LS240
			if(!b_i2s)
				size = sizeof( AC3240Ucode1f8000)/4;
			else
				size = sizeof( AC3I2S240Ucode1f8000)/4;
		#else
			if(!b_i2s)
				size = sizeof( AC3Ucode1f8000)/4;
			else
				size = sizeof( AC3I2SUcode1f8000)/4;
		#endif
	}
	else if ( ucode == 2 )	// MPG
	{
		dstoff = DRAM_BASE + 0x1f5c00;

		#ifdef LS240
			if(!b_i2s)
				size = sizeof( MPG240Ucode1f5c00)/4;
			else
				size = sizeof( MPGI2S240Ucode1f5c00)/4;
		#else
			if(!b_i2s)
				size = sizeof( MPGUcode1f5c00)/4;
			else
				size = sizeof( MPGI2SUcode1f5c00)/4;
		#endif
	}
	else			//PCM
	{
		dstoff = DRAM_BASE + 0x1f4b00;

		#ifdef LS240
			if(!b_i2s)
				size = sizeof( PCM240Ucode1f4b00)/4;
			else
				size = sizeof( PCMI2S240Ucode1f4b00)/4;
		#else
			if(!b_i2s)
				size = sizeof( PCMUcode1f4b00)/4;
			else
				size = sizeof( PCMI2SUcode1f4b00)/4;
		#endif
	}

	#ifdef DBG
		DbgPrint("luxdvd : LoadUcode - loading 2nd section to 0x%lx\n",dstoff);
	#endif

	for(loop=0; loop < (int)size; loop++)
	{
		if(ucode==1)	// AC3
		{
			#ifdef LS240
				if(!b_i2s)
					DVWriteDRAM(dstoff,AC3240Ucode1f8000[loop]);
				else
					DVWriteDRAM(dstoff,AC3I2S240Ucode1f8000[loop]);
			#else
				if(!b_i2s)
					DVWriteDRAM(dstoff,AC3Ucode1f8000[loop]);
				else
					DVWriteDRAM(dstoff,AC3I2SUcode1f8000[loop]);
			#endif				
		}
		else if ( ucode == 2 )
		{
			#ifdef LS240
				if(!b_i2s)
					DVWriteDRAM(dstoff,MPG240Ucode1f5c00[loop]);
				else
					DVWriteDRAM(dstoff,MPGI2S240Ucode1f5c00[loop]);
			#else
				if(!b_i2s)
					DVWriteDRAM(dstoff,MPGUcode1f5c00[loop]);
				else
					DVWriteDRAM(dstoff,MPGI2SUcode1f5c00[loop]);
			#endif				
		}
		else			// PCM
		{
			#ifdef LS240
				if(!b_i2s)
					DVWriteDRAM(dstoff,PCM240Ucode1f4b00[loop]);
				else
					DVWriteDRAM(dstoff,PCMI2S240Ucode1f4b00[loop]);
			#else
				if(!b_i2s)
					DVWriteDRAM(dstoff,PCMUcode1f4b00[loop]);
				else
					DVWriteDRAM(dstoff,PCMI2SUcode1f4b00[loop]);
			#endif
		}
		dstoff += 4;
	}

	if( ucode != 1 )	
	{
		return;		// PCM , MPG is done
	}

	// --------- 3rd Array -----------------

	if(ucode==1)	// AC3
	{
		dstoff = DRAM_BASE + 0x1fe000;

		#ifdef LS240
			if ( !b_i2s )
				size = sizeof( AC3240Ucode1fe000)/4;
			else
				size = sizeof( AC3I2S240Ucode1fe000)/4;
		#else
			if(!b_i2s)
				size = sizeof( AC3Ucode1fe000)/4;
			else
				size = sizeof( AC3I2SUcode1fe000)/4;
		#endif
	}

	#ifdef DBG
		DbgPrint("luxdvd : LoadUcode - loading 3rd section to 0x%lx\n",dstoff);
	#endif

	for(loop=0; loop < (int)size; loop++)
	{
		if(ucode==1)	// AC3
		{
			#ifdef LS240
				if(!b_i2s)
					DVWriteDRAM(dstoff,AC3240Ucode1fe000[loop]);
				else
					DVWriteDRAM(dstoff,AC3I2S240Ucode1fe000[loop]);
			#else
				if(!b_i2s)
					DVWriteDRAM(dstoff,AC3Ucode1fe000[loop]);
				else
					DVWriteDRAM(dstoff,AC3I2SUcode1fe000[loop]);
			#endif
		}
		dstoff += 4;
	}

	// --------- 4rd Array -----------------

	if(ucode==1)		// AC3
	{
		dstoff = DRAM_BASE + 0x1fff80;

		#ifdef LS240
			if(!b_i2s)
				size = sizeof( AC3240Ucode1fff80)/4;
			else
				size = sizeof( AC3I2S240Ucode1fff80)/4;
		#else
			if(!b_i2s)
				size = sizeof( AC3Ucode1fff80)/4;
		else
			size = sizeof( AC3I2SUcode1fff80)/4;
		#endif
	}

	#ifdef DBG
		DbgPrint("luxdvd : LoadUcode - loading 4th section to 0x%lx\n",dstoff);
	#endif

	for(loop=0; loop < (int)size; loop++)
	{
		if(ucode==1)	// AC3
		{
			#ifdef LS240
				if(!b_i2s)
					DVWriteDRAM(dstoff,AC3240Ucode1fff80[loop]);
				else
					DVWriteDRAM(dstoff,AC3I2S240Ucode1fff80[loop]);
			#else
				if(!b_i2s)
					DVWriteDRAM(dstoff,AC3Ucode1fff80[loop]);
				else
					DVWriteDRAM(dstoff,AC3I2SUcode1fff80[loop]);
			#endif
		}
		dstoff += 4;
	}
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioSetUClock(BYTE type)
{
	#ifdef OLD
		if ( type && (eprom[EPROM_CLOCKTYPE]==1) )
			DVWriteDRAM(DSPMEM_UCLOCK,1);
		else
			DVWriteDRAM(DSPMEM_UCLOCK,0);
	#endif
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioSetAudioInfo()
{
WORD clock_chip;	// clock chip defition
WORD left_ch;		// left channel polarity
WORD pcm_size;		// PCM ( output ) size 
WORD i2s_pin;		// I2S exist or not

	#ifdef DBG
		//DbgPrint("luxdvd : LUXAudioSetAudioInfo\n");
	#endif

	clock_chip	= (WORD)eprom[EPROM_CLOCKTYPE];
	left_ch		= (WORD)eprom[EPROM_LEFT_CH_POL]<<3;
	pcm_size	= 0;

	if ( eprom[EPROM_I2S] == 0x3 )
		i2s_pin	= 0x40;
	else
		i2s_pin = 0;

	DVWriteDRAM(DSPMEM_AUDIO_CONF,i2s_pin|pcm_size|left_ch|clock_chip);
}

/////////////////////////////////////////////////////////////////////////

void LUXAudioSetKaraoke(BYTE pKa)
{
	if ( !ac3_flag ) // PCM
		return;

	switch(pKa)
	{
	case 0:
		DVWriteDRAM(DSPMEM_KARAOKE,0);	// no vocal ( AC3 )
		break;
	case 1:
		DVWriteDRAM(DSPMEM_KARAOKE,0x1);	// vocal 1 enable ( AC3 )
		break;
	case 2:
		DVWriteDRAM(DSPMEM_KARAOKE,0x2);	// vocal 2 enable ( AC3 )
		break;
	case 3:
		DVWriteDRAM(DSPMEM_KARAOKE,0x3);	// v1 v2 enable ( AC3 )
		break;
	}
}

/////////////////////////////////////////////////////////////////////////

#ifdef LS240

void LUXAudioPCMEnableTriState()
{
	DVWriteREG(0x284,DVReadReg(0x284)|0x200000);
}

#endif

BYTE LUXAudioGetVolume()
{
	return a_m_vol;
}

WORD dlen;		// real data length
BYTE* m_p;		// moving pointer
BYTE* m_cp;		// starting point for copying data

BYTE mtmp[2048];

DWORD LUXAudioMpegPacket(BYTE *mbuf,BYTE *pp,ULONG used)	// mbuf point to starting of 2K , p point to PES_packet_length
{
BYTE aid;

WORD	pes_len;	// PES_packet_length
DWORD	CurPTS;		// PTS
BOOL	b_scramble;	// scramble flag

BOOL m_ext = FALSE;

WORD ext_pes_len;

BOOL m_exthead = FALSE;

BYTE* p;

	RtlCopyMemory((void *)mtmp,(void *)mbuf,(ULONG)2048);

	p = mtmp + ( pp - mbuf );

	ext_pes_len = 0;

	CurPTS = 0;

	aid = *(p-1)&0x7;

	if ( stop_read )
	{
		p += 2;

		b_scramble = (BOOL)((*p) & 0x30);

		pes_len = (WORD)(*(p+2));

		p += 3;

		if (((*p & 0xf0) == 0x20)&&(pes_len>0)) // Get PTS here
		{	
			CurPTS = GetWORD(p+1) >> 1;
			CurPTS = CurPTS << 14 | GetWORD(p+3)>>2;
			CurPTS |= ((DWORD)(*p & 0xe)) << 28;
		}

		p += pes_len;

		goto tryit;
	}

	if ( ( *(p-1) & 0xf0 ) == 0xd0 )
	{
		m_exthead = TRUE;
		m_ext = TRUE;
	}

	dlen = GetWORD(p);

	p += 2;

	m_cp = p + dlen;	// end of A_PKT

	if ( m_cp < (BYTE*) (mtmp+0x800) )
	{
		if ( ( GetDWORD(m_cp) & 0xfffffff0 ) != 0x1c0 )
			m_ext = TRUE;
	}

	b_scramble = (BOOL)((*p) & 0x30);

	pes_len = (WORD)(*(p+2));

	p += 3;

	dlen = dlen - 3 - pes_len;
	
	if (((*p & 0xf0) == 0x20)&&(pes_len>0))	// get PTS here
	{
		CurPTS = GetWORD(p+1) >> 1;
		CurPTS = CurPTS << 14 | GetWORD(p+3)>>2;
		CurPTS |= ((DWORD)(*p & 0xe)) << 28;
	}

	p += pes_len;

	if ( m_exthead )	// starting is 0x1d0
	{
		m_cp = p;
		dlen = 0;
		CurPTS = 0;
	}

	if ( m_ext )
	{
		m_p = m_cp;

		while ( m_p < (BYTE*) (mtmp+0x800) )	// need to go through the rest od A_PCK
		{
			while ( (GetDWORD(m_p)&0xffffff00) != 0x100  )
			{
				if ( m_p++ >= (BYTE*)(mtmp+0x800) )
					goto tryit;				
			}

			if (( *(m_p+3) & 0xf0 ) != 0xc0 )
			{
				m_p += 4;	// point to PES_packet_length

				ext_pes_len = GetWORD(m_p);

				m_p += ext_pes_len + 2;
				continue;
			}

			if ( ( GetDWORD(m_p) & 0xfffffff0 ) == 0x1c0 ) // Next A_PKT
			{
				m_p += 4;	// skip 0x1c0

				ext_pes_len = GetWORD(m_p);	// pes_packet_length
				m_p += 2;
				pes_len = (int)(*(m_p+2));
				m_p += 3;
				ext_pes_len = ext_pes_len - 3 - pes_len;

				if ( m_exthead )
				{
					if (((*m_p & 0xf0) == 0x20)&&(pes_len>0))	// get PTS here
					{
						CurPTS = GetWORD(m_p+1) >> 1;
						CurPTS = CurPTS << 14 | GetWORD(m_p+3)>>2;
						CurPTS |= ((DWORD)(*m_p & 0xe)) << 28;
					}
					m_exthead = FALSE;
				}

				m_p += pes_len;	// point to real data

				RtlCopyMemory((void *)(m_cp),(void *)m_p,(ULONG)ext_pes_len);

				dlen += ext_pes_len;

				m_cp += ext_pes_len;

				m_p += ext_pes_len;
			}
		} // end of while

	}

tryit:

	if ( dlen == 0 )
	{
		stop_read = 0;
		return used;
	}

	if( LUXAudioSendData((BYTE *)mtmp,(BYTE *)p,dlen,CurPTS,b_scramble,0) )
	{
		stop_read = 0;
		return used;
	}
	else
	{
		RtlCopyMemory((void *)mbuf,(void *)mtmp,(ULONG)2048);
		stop_read = 1;
		return 0;
	}
}
