
#include "strmini.h"
#include "stdefs.h"
#include "mpinit.h"
#include "mpvideo.h"
#include "copyprot.h"
#include "ls220.h"
#include "dvhw32.h"
#include "video.h"
#include "audio.h"
#include "lssubp.h"

#define 	LOCALBUF	128*1024	// Buffer for storing data from DVDemux

#define		WORK_AROUND
#define		HW_ASM

#define  FIFO_SIZE	8									// PTS FIFO entry count
#define	 HIGH_FIFO	32									// HighLight Fifo size
#define  SCRM_FIFO	0x800								// Scramble buffer size
#define  SPBLOCK	( 0xE000 - HIGH_FIFO - SCRM_FIFO ) 	// 56K - 32 bytes - 2k
#define  SubBLOCK	0xE00								// PTS + DCI = 3.5K
#define	 DCIBLOCK	( SubBLOCK - 8*FIFO_SIZE )
#define  PxdBLOCK	( SPBLOCK - SubBLOCK )
#define  FStart		0x20								// PTS FIFO Start Address
#define	SUBBASE ( DRAM_BASE + SUB_FIFO_OFF )

#define		MAX_THD		2

// global variable

HANDLE		m_currTd = NULL;
DWORD		BASE = DRAM_BASE + SUB_FIFO_OFF;
DWORD		reg_FIFO_Start=0x230, reg_FIFO_End=0x234, reg_FIFO_Write=0x238, reg_FIFO_Read=0x23c;
DWORD		PTS_Start = FStart;
DWORD		PTS_End;
DWORD		DCI_Start;
DWORD		DCI_End;
DWORD		PXD_Start;
DWORD		PXD_End;
DWORD		SRM_Start;	// for unscramble use
BYTE		ibuf[LOCALBUF];	// For Storing data from DVDemux module
BYTE		*iptr = NULL;		// Moving pointer 
int			sx, sy, ex, ey, sbsize, dcsq_sa, field[2];
BOOL		m_firstPK;			// first packet ?
DWORD		m_ptsDW;			// Sub PTS bit 31-0
DWORD		m_ptshead;
DWORD		m_dcihead;
DWORD		m_pxdhead;
DWORD		CurPXD;
DWORD		CurDCI;               
WORD		sp_dcsq_stm; 		// Start Time of SP_DCSQ
WORD		sp_cur_dcsq_sa;		// Start Address of current SP_DCSQ
WORD		sp_nxt_dcsq_sa;		// Start Address of next SP_DCSQ
WORD		m_set_color;		// For Cmd 3
WORD 		m_set_contr;		// For Cmd 4
WORD		ss;					// For command 7
BOOL		m_cmd7;				// Command 7 presented ?
BOOL		m_fsa;				// Force to start
BOOL		m_sta;				// Start
BOOL		m_stp;				// Stop
DWORD		csel;
DWORD		cact;
BOOL		f_HLIActive = FALSE;
int			t_tail = 0;
int			t_head = 0;
DWORD		hDCIaddress;	// DCI adress for highlight
BOOL		highflag;	// if highlight exists
DWORD		highPTS;	// highlight PTS
WORD		hsx;		// highlight Start X
WORD		hex;		// highlight End X
WORD		hsy;		// highlight Start Y
WORD		hey;		// highlight End Y
WORD		hcolor;		// highlight Color
WORD		hcontr;		// highlight Contrast
WORD		hacolor;		// highlight activate Color
WORD		hacontr;		// highlight activate Contrast

//function prototype

DWORD	GetDWORD(unsigned char *p);
WORD	GetWORD(BYTE *p);
DWORD	SwapByte(BYTE* p);
void	dcialloc(DWORD);	// buffer management
void	pxdalloc();			// buffer management
void	move_data();
void	show();
void	BtnActivation();
void	SetCurrentBtn(BYTE*,DWORD);
void	SetHighlight(BYTE*);
void	SetBtnColor(DWORD*);
void	do_cmd(void);
void	do_unscramble(BYTE*);
void	resetSub(void);
void	SPStub(PHW_STREAM_REQUEST_BLOCK pSrb);
void	SPPacketStub(PSP_STRM_EX pspstrmex);

static ULONG cSPBytes = 0;
//extern PVIDEO pVideo;
extern PSP_STRM_EX pSPstrmex;
extern BYTE eprom[16];
extern DWORD luxbase;

static ULONG ulRemain = 0;

extern BOOL  m_Pal;	// Video Src

//Rate chnage global function
extern void SetRateChange(PHW_DEVICE_EXTENSION pHwDevExt, LONG strm);


//////////////////////////////////////////////////////////////////////////////////

#define GetCurNibble(foo) (((foo) % 2) ? (*((PBYTE)pspstrmex->pdecctl.pData + ((foo) >> 1))\
		& 0x0f) : (((*((PBYTE)pspstrmex->pdecctl.pData + ((foo)  >> 1)))) >> 4))

//////////////////////////////////////////////////////////////////////////////////

void LS_SP_Init()
{
int i=0;

	#ifdef DBG
		DbgPrint("luxdvd : LS_SP_Init\n");
	#endif

	BASE = DRAM_BASE + SUB_FIFO_OFF;
	reg_FIFO_Start=0x230;
	reg_FIFO_End=0x234;
	reg_FIFO_Write=0x238;
	reg_FIFO_Read=0x23c;
	PTS_Start = FStart;
		
	PTS_End = FStart + ( 8 * FIFO_SIZE ) - 1;
	DCI_Start = PTS_End + 1;
	DCI_End = PTS_Start + SubBLOCK - 1;
	PXD_Start = DCI_End + 1;
	PXD_End = PTS_Start + SPBLOCK  - 1;
	SRM_Start = PXD_End + 1;	// for unscramble use

	for(i=0; i < LOCALBUF; i++)
		ibuf[i]=0;

	m_cmd7		= FALSE;
	iptr		= ibuf;
	m_ptshead	= PTS_Start;
	m_pxdhead	= PXD_Start;
	m_dcihead	= DCI_Start;
	CurDCI		= m_dcihead;
	CurPXD		= m_pxdhead;
	m_firstPK	= TRUE;

	hDCIaddress = 0;

	f_HLIActive = FALSE;
	
	resetSub();
			
}
/////////////////////////////////////////////////////////////////////////////////////////////////////

DWORD GetDWORD(unsigned char *p) 
{ 
	if(p == NULL)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : invalid arg to GetDWORD !!!\n");
		#endif
		return 0;
	}
	else
		return (DWORD)(*p)<<24|(DWORD)(*(p+1))<<16|(DWORD)(*(p+2))<<8| (DWORD)(*(p+3));
}

//////////////////////////////////////////////////////////////////////////////////

WORD GetWORD(BYTE *p) 
{ 
	if(p == NULL)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : invalid arg to GetWORD !!!\n");
		#endif
		return 0;
	}
	else
		return ((WORD)(*p)<<8) | ((WORD)(*(p+1))); 
}

//////////////////////////////////////////////////////////////////////////////////

DWORD SwapByte(BYTE* p) 
{
	if(p==NULL)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : invalid arg to SwapByte !!!\n");
		#endif
		return 0;
	}
	else
		return (DWORD)(*(p+3))<<24|(DWORD)(*(p+2))<<16|(DWORD)(*(p+1))<<8|(DWORD)(*p);
}

//////////////////////////////////////////////////////////////////////////////////

BOOL LS_Send_Sub(DWORD PTS, BYTE *ptr,	WORD len, BYTE scramble, PSP_STRM_EX pspstrmex)
{   
DWORD tid;

	field[0]	= 4;
	field[1]	= 4;

	m_cmd7		= FALSE;
	
	if ( m_firstPK ) 
	{
		DVWriteREG(reg_FIFO_Start,SUB_FIFO_OFF+PTS_Start);	// PTS FIFO at 0x2000
		DVWriteREG(reg_FIFO_End  ,SUB_FIFO_OFF+PTS_End);
		DVWriteREG(reg_FIFO_Write,SUB_FIFO_OFF+PTS_Start);

		DVWriteREG(0x3d8,0x4000400L);	// Scaling 
	}

	RtlCopyMemory((void *)iptr,(void *)ptr,(ULONG)len); 	    // copy buffer    
	
    if ( iptr == ibuf ) 
	{			// First Pkt
		m_ptsDW	= (PTS<<1);			// PTS is from bit 1 to bit32
    	sbsize	= GetWORD(iptr);	// SPU size
    	dcsq_sa	= GetWORD(iptr+2);	// command seq starting address

		#ifdef DBG
		
			if( /*pspstrmex->phwdevex->ShowSP ||*/ f_HLIActive )
				DbgPrint("luxdvd : m_ptsDW=0x%lx, STC=0x%lx\n",m_ptsDW,DVReadReg(0x218));
		
		#endif

    	if ( sbsize > len ) 
		{ // Still need more Pkts
    		iptr += len;
    		return TRUE;
    	}
	}
    else 
	{
    	if ( ibuf + sbsize > iptr + len ) 
		{	// Still need more Pkts
			iptr += len;
			return TRUE;		
    	}
    }

	iptr = ibuf;	// Reset the iptr pointer

	if ( m_firstPK ) 
	{
		m_firstPK = FALSE;
		
		if( pspstrmex->phwdevex->ShowSP || f_HLIActive )
		{
			//Even if SP is off, we still need to show HLI
			show();
		}
	}

	if( pspstrmex->phwdevex->ShowSP || f_HLIActive )
		do_cmd();	// Real Command Parsing and Buffer Management

	return TRUE;
}

//////////////////////////////////////////////////////////////////////////////////
	
void move_data()
{
int   tmp;
DWORD dstoff;
DWORD srcoff;
DWORD dwloop=0;

	dstoff = (DWORD) ( BASE + CurPXD );
	srcoff = (DWORD) ibuf;

	tmp	   = ( dcsq_sa % 4 ) ? ( dcsq_sa + 4 - ( dcsq_sa % 4 )) : dcsq_sa;

#ifdef LS240
	while ( DVReadReg(0x24) || DVReadReg(0x28) )
#else
	while ( DVReadReg(0x24) )
#endif
	{
		KeStallExecutionProcessor(2);
		dwloop++;
		if(dwloop >= 0xfffff0)
		{
			#ifdef DBG
				DbgPrint("luxdvd ERROR : SP move_data - timed out waiting for reg 0x24 !!!!!!!\n");
			#endif
			break;
		}
	}

	DVMoveStr(dstoff,srcoff,tmp);
}

//////////////////////////////////////////////////////////////////////////////////

void do_unscramble(BYTE* p)
{
DWORD off;

	off = SUB_FIFO_OFF + SRM_Start + 80;

#ifdef LS240
	DVWriteREG(0x2c,off|0x400000L);
	
	#ifdef HW_ASM
	DVMoveStr(SUB_FIFO_OFF+SRM_Start-0x80000,(DWORD)p,2048);	// send to HW
	DVReadStr((DWORD)p,SUB_FIFO_OFF+SRM_Start-0x80000,2048);	// Get data from HW
	#else
	RtlCopyMemory((void *)(luxbase+SUB_FIFO_OFF+SRM_Start-0x80000),(void *)p,(ULONG)2048);
	RtlCopyMemory((void *)p,(void *)(luxbase+SUB_FIFO_OFF+SRM_Start-0x80000),(ULONG)2048);
	#endif

	DVWriteREG(0x2c,0);
#else
	DVWriteREG(0x24,off|0x400000L);
	#ifdef HW_ASM
		DVMoveStr(BASE+SRM_Start,(DWORD)p,2048);	// send to HW
		DVReadStr((DWORD)p,BASE+SRM_Start,2048);	// Get data from HW
	#else
		RtlCopyMemory((void *)(luxbase+BASE+SRM_Start),(void *)p,(ULONG)2048);
		RtlCopyMemory((void *)p,(void *)(luxbase+BASE+SRM_Start),(ULONG)2048);
	#endif
	DVWriteREG(0x24,0);
#endif
}

//////////////////////////////////////////////////////////////////////////////////

void do_cmd(void)
{
BYTE*	p;					// p point to the starting position of DCSQT
BYTE*	ptr7;
BYTE*	SPU_END;			// end addr of DCSQ
WORD	m_sgdcsq;
WORD	ext_size;			// Use for cmd7
WORD    x_change;			// Use for cmd7
int		gp = 0;
int		i  = 0;
int		j  = 0;
DWORD	data2;
DWORD	ppts32=0;
DWORD	dwcnt=0;
BOOL	oldCM7=0;

	
	ppts32 = m_ptsDW;
	
	pxdalloc();					// Allocate PXD FIFO
	move_data();

	hDCIaddress = 0;

	p		= ibuf + dcsq_sa;
	SPU_END	= ibuf + sbsize;
	
	sp_cur_dcsq_sa	= dcsq_sa;	// Initial current DCSQ Starting addr
                   
	while ( p < SPU_END )
	{
		m_fsa = FALSE;
		m_sta = FALSE;
		m_stp = FALSE;

		ss				= 0;
		m_cmd7			= FALSE;
		sp_dcsq_stm		= GetWORD(p); 
		p += 2;
		sp_nxt_dcsq_sa	= GetWORD(p); 
		p += 2;
		
		m_ptsDW = ppts32 + ( sp_dcsq_stm << 10 );

		if ( sp_nxt_dcsq_sa != sp_cur_dcsq_sa ) // Still have next DCSQ
			m_sgdcsq	= sp_nxt_dcsq_sa - sp_cur_dcsq_sa - 4;
		else 									// It's the last DCSQ
			m_sgdcsq	= sbsize - sp_cur_dcsq_sa - 4;
		
		#ifdef DBG
			//DbgPrint("luxdvd : SP do_cmd - ");
		#endif

		while ( m_sgdcsq ) 
		{		// Handle single SP_DCSQ
			switch(*p) 
			{
				case 0:		// FSTA_DSP
					#ifdef DBG
						//DbgPrint("FSTA_DSP ");
					#endif
					m_fsa = TRUE;
					--m_sgdcsq;
					p++;
					break;

				case 1:		// STA_DSP
					#ifdef DBG
						//DbgPrint("STA_DSP ");
					#endif
					m_sta = TRUE;
					--m_sgdcsq;
					p++;
					break;

				case 2:		// STP_DSP
					#ifdef DBG
						//DbgPrint("STP_DSP ");
					#endif
					m_stp = TRUE;
					--m_sgdcsq;
					p++;
					break;

				case 3:		// SET_COLOR **
					#ifdef DBG
						//DbgPrint("SET_COLOR ");
					#endif
					m_set_color = GetWORD(p+1);
					m_sgdcsq -= 3;
					p += 3;
					break;

				case 4:		// SET_CONT        
					#ifdef DBG
						//DbgPrint("SET_CONT ");
					#endif
					m_set_contr = GetWORD(p+1);
					m_sgdcsq -= 3;
					p += 3;
					break;

				case 5:		// SET_DAREA
					#ifdef DBG
						//DbgPrint("SET_DAREA ");
					#endif
					sx = ((WORD)(*(p+1)&0x3f)<<4)|(*(p+2)>>4);
					ex = ((WORD)(*(p+2)&0x3)<<8)|*(p+3);
					sy = ((WORD)(*(p+4)&0x3f)<<4)|(*(p+5)>>4);
					ey = ((WORD)(*(p+5)&0x3)<<8)|*(p+6);
					m_sgdcsq -= 7;
					p += 7;
					break;

				case 6:		// SET_DSPXA
					#ifdef DBG
						//DbgPrint("SET_DSPXA ");
					#endif
					field[0] = ((WORD)(*(p+1))<<8)|*(p+2);
					field[1] = ((WORD)(*(p+3))<<8)|*(p+4);
					m_sgdcsq -= 5;
					p += 5;
					break;

				case 7:		// CHG_COLCON
					#ifdef DBG
						//DbgPrint("CHG_COLCON ");
					#endif
					ptr7     = p + 1;
					m_cmd7   = TRUE;
					ext_size = GetWORD(p+1) - 2;
					m_sgdcsq -= 3;
					p += 3; // point to the data 
				
					while ( ext_size ) 
					{
						if ( GetDWORD(p) == 0x0fffffff ) 
						{
							ext_size -= 4;
							m_sgdcsq -= 4;
							p += 4;
							break;
						}
					
						x_change = (*(p+2)) >> 4 ;
						if ( x_change != 0 ) 
							ss += 52;	// For each Y group will use 52 Bytes
						m_sgdcsq -= ( 4 + 6*x_change );
						p += ( 4 + 6*x_change );
						ext_size -= ( 4 + 6*x_change );
					} 
					break;

				case 0xff:		//CMD_END
					#ifdef DBG
						//DbgPrint("CMD_END ");
					#endif
					--m_sgdcsq;
					p++;
					break;

				default:
					#ifdef DBG
						DbgPrint("luxdvd ERROR : SP cannot match Display Ctrl Cmd - breaking out of do_cmd and call resetSub !!!!!\n");
					#endif
					resetSub();
					return;
			}
		}// end of inner while

		#ifdef DBG
			//DbgPrint("\n");
		#endif
		
		oldCM7 = m_cmd7;

#ifndef WORK_AROUND
		if (( highPTS == ppts32 ) && highflag && !m_cmd7 && !hDCIaddress)
#else
		if ( highflag && !m_cmd7 && !hDCIaddress && !(hsx==hex) && !(hsy==hey) )
#endif
		{
			m_cmd7 = TRUE;
			ss = 56;
		}

		if ( ! m_cmd7 ) 
			dcialloc(24);
		else
			dcialloc(24+ss+4);

		DVWriteDRAM(BASE+m_ptshead , m_ptsDW);
				
		if ( m_fsa | m_sta ) 
		{
			DVWriteDRAM(BASE+m_ptshead+4 ,((SUB_FIFO_OFF+CurDCI)&0xfffffcL)|(m_cmd7 ? 0x03 : 0x02));
		}
		else if ( m_stp ) 
		{
			DVWriteDRAM(BASE+m_ptshead+4 ,((SUB_FIFO_OFF+CurDCI)&0xfffffcL)|(m_cmd7 ? 0x01 : 0x00));
		}
		else 
		{
			DVWriteDRAM(BASE+m_ptshead+4 ,((SUB_FIFO_OFF+CurDCI)&0xfffffcL)|(m_cmd7 ? 0x03 : 0x02));
		}
		
#ifndef WORK_AROUND
		if (( highPTS == ppts32 ) && highflag && !oldCM7 )
#else
		if ( highflag && !oldCM7 )
#endif
		{
			m_cmd7 = FALSE;
			ss = 0;
		}

		DVWriteDRAM(BASE+CurDCI   ,((DWORD)sy)<<16|ey); 
		DVWriteDRAM(BASE+CurDCI+4 ,((DWORD)sx)<<16|ex); 
		DVWriteDRAM(BASE+CurDCI+8 ,(SUB_FIFO_OFF+CurPXD+field[0])&0xffffff);
		DVWriteDRAM(BASE+CurDCI+12,(SUB_FIFO_OFF+CurPXD+field[1])&0xffffff);
		DVWriteDRAM(BASE+CurDCI+16,((DWORD)m_set_color)<<16|m_set_contr);

		if ( ! m_cmd7 ) 
		{
#ifndef WORK_AROUND
			if (( highPTS == ppts32 ) && highflag && !hDCIaddress )
#else
			if ( highflag && !hDCIaddress )
#endif
			{
				hDCIaddress = BASE+CurDCI+20;	// keep DCI address
				DVWriteDRAM(hDCIaddress,(DWORD)hsy<<16|((WORD)0x3<<12)|hey);
				DVWriteDRAM(hDCIaddress+4,(DWORD)m_set_contr<<16|sx);
				if ( ( hsx - sx ) <= 1 )
					DVWriteDRAM(hDCIaddress+8,(DWORD)(hsx+2)<<16|m_set_color);
				else 
					DVWriteDRAM(hDCIaddress+8,(DWORD)hsx<<16|m_set_color);
				DVWriteDRAM(hDCIaddress+12,(DWORD)hcolor<<16|hcontr);
				DVWriteDRAM(hDCIaddress+16,(DWORD)m_set_contr<<16|hex);
				DVWriteDRAM(hDCIaddress+20,0xffff0000|m_set_color);
				DVWriteDRAM(hDCIaddress+24,0xffffffff);
				DVWriteDRAM(hDCIaddress+52,0xffffffff);
				DVWriteDRAM(hDCIaddress+56,0xffffffff);
			}
			else
				DVWriteDRAM(BASE+CurDCI+20,0xffffffff);
		}
		else 
		{
			ext_size = GetWORD(ptr7) - 2;
			ptr7 += 2;

			gp = 0;
			i  = 0;
			j  = 0;

			while ( ext_size ) 
			{
				if ( GetDWORD(ptr7) == 0x0fffffff ) 
					break;
				x_change = (*(ptr7+2)) >> 4 ;
				
				DVWriteDRAM(BASE+CurDCI+20+gp,GetDWORD(ptr7));	// Y information

				gp		+= 4;
				ptr7	+= 4;

				ext_size -= 4;

				i = 0;
				j = x_change;

				while ( x_change > 0 ) 
				{
					if ( ( i % 2 ) == 0 ) 
					{ // 0 , 2 , 4 , 6
						data2 = (DWORD)(GetWORD(ptr7+4))<<16|GetWORD(ptr7);
						DVWriteDRAM(BASE+CurDCI+20+gp,data2);
						gp += 4;
						if ( ( x_change - 1 ) > 0 ) 
						{
							data2 = (DWORD)(GetWORD(ptr7+6))<<16|GetWORD(ptr7+2);
						}
						else
						{
							data2 = 0xffff0000 | GetWORD(ptr7+2);
						}
						DVWriteDRAM(BASE+CurDCI+20+gp,data2);
					}
					else 
					{					// 1 , 3 , 5 , 7
						data2 = GetDWORD(ptr7+2);
						DVWriteDRAM(BASE+CurDCI+20+gp,data2);	
					}
					i++;
					x_change--;
					gp += 4;
					ptr7 += 6;
					ext_size -= 6;
				}// inner while

				if ( j != 8 )  
				{
					DVWriteDRAM(BASE+CurDCI+20+gp,0xffffffff);
					if ( ( j % 2 ) == 0 ) 
					{
						gp += ( 8 - j ) * 6;
					}
					else 
					{
						gp += 48 - (( j / 2 )*12 + 8);
					}
				}
			}// outter while
			DVWriteDRAM(BASE+CurDCI+20+ss,0xffffffff);
			DVWriteDRAM(BASE+CurDCI+20+ss+4,0xffffffff);
		}

		dwcnt=0;

		if ( ( m_ptshead + 8 ) > PTS_End )
		{
			while ( DVReadReg(reg_FIFO_Read) == (SUB_FIFO_OFF+PTS_Start) )
			{
			
				KeStallExecutionProcessor(5);
				if(dwcnt++ > 1000)
				{
					#ifdef DBG
						DbgPrint("luxdvd ERROR : SP do_cmd timed out on loop for reg_FIFO_Read, call resetSub !!!!\n");
					#endif
					highflag = FALSE;
					resetSub();
					return;
				}
			}
			m_ptshead = PTS_Start;
		}
		else 
		{
			while ( DVReadReg(reg_FIFO_Read) == (SUB_FIFO_OFF+m_ptshead+8) )
			{
				KeStallExecutionProcessor(5);
				if(dwcnt++ > 1000)
				{
					#ifdef DBG
						DbgPrint("luxdvd ERROR : SP do_cmd timed out on loop for reg_FIFO_Read, call resetSub !!!!\n");
					#endif
					highflag = FALSE;
					resetSub();
					return;
				}
			}
			m_ptshead += 8;
		}

		DVWriteREG(reg_FIFO_Write,SUB_FIFO_OFF+m_ptshead);
		
		sp_cur_dcsq_sa = sp_nxt_dcsq_sa;
	}

	highflag = FALSE;

}

//////////////////////////////////////////////////////////////////////////////////

void show()
{
	DVWriteREG(0x3d0,DVReadDRAM(0x3d0)|0x1);			// enable sub-pict
}

//////////////////////////////////////////////////////////////////////////////////

void pxdalloc()
{
int m_tmp;

	m_tmp = dcsq_sa % 4;
	if ( m_tmp != 0 ) 
	{
		m_tmp = dcsq_sa + ( 4 - m_tmp );
	}
	else 
		m_tmp = dcsq_sa;

	if (( PXD_End - m_pxdhead + 1 ) > (unsigned)m_tmp) 
	{
		CurPXD = m_pxdhead;
		m_pxdhead += m_tmp;
	}
	else if (( PXD_End - m_pxdhead + 1 ) == (unsigned)m_tmp)
	{
		CurPXD = m_pxdhead;
		m_pxdhead = PXD_Start;
	}
	else 
	{
		CurPXD = PXD_Start;
		m_pxdhead = PXD_Start + m_tmp;
	}
}

//////////////////////////////////////////////////////////////////////////////////

void dcialloc(DWORD dcisize)
{   
int m_tmp;

	m_tmp = dcisize % 4;

	if ( m_tmp != 0 ) 
	{
		m_tmp = dcisize + ( 4 - m_tmp );
	}
	else 
		m_tmp = dcisize;

	if (( DCI_End - m_dcihead + 1 ) > (unsigned)m_tmp) 
	{
		CurDCI = m_dcihead;
		m_dcihead += m_tmp;
	}
	else if (( DCI_End - m_dcihead + 1 ) == (unsigned)m_tmp)
	{
		CurDCI = m_dcihead;
		m_dcihead = DCI_Start;
	}
	else 
	{
		m_dcihead = DCI_Start + m_tmp;
		CurDCI = DCI_Start;
	}
}

//////////////////////////////////////////////////////////////////////////////////

void resetSub()
{
	DVWriteREG(0x3d0,0);	// Disable the Sub-Pict

	DVWriteREG(reg_FIFO_Write,SUB_FIFO_OFF+PTS_Start);

	m_cmd7		= FALSE;
	iptr		= ibuf;
	m_ptshead	= PTS_Start;
	m_pxdhead	= PXD_Start;
	m_dcihead	= DCI_Start;
	CurDCI		= m_dcihead;
	CurPXD		= m_pxdhead;
	m_firstPK	= TRUE;

	//f_HLIActive = FALSE;

	t_head = t_tail = 0;

	sy = 0;
}

//////////////////////////////////////////////////////////////////////////////////

void BtnActivation()
{
	DVWriteDRAM(BASE+20,cact);	// Group1 Selection color & contrast
	DVWriteDRAM(BASE+24,cact);	// Group1 Selection color & contrast

	if ( hDCIaddress != 0 )
	{
		DVWriteDRAM(hDCIaddress,(DWORD)hsy<<16|((WORD)0x3<<12)|hey);
		DVWriteDRAM(hDCIaddress+4,(DWORD)m_set_contr<<16|sx);
		if ( ( hsx - sx ) <= 1 )
			DVWriteDRAM(hDCIaddress+8,(DWORD)(hsx+2)<<16|m_set_color);
		else 
			DVWriteDRAM(hDCIaddress+8,(DWORD)hsx<<16|m_set_color);
		DVWriteDRAM(hDCIaddress+12,(DWORD)hacolor<<16|hacontr);
		DVWriteDRAM(hDCIaddress+16,(DWORD)m_set_contr<<16|hex);
		DVWriteDRAM(hDCIaddress+20,0xffff0000|m_set_color);
		DVWriteDRAM(hDCIaddress+24,0xffffffff);
		DVWriteDRAM(hDCIaddress+52,0xffffffff);
		DVWriteDRAM(hDCIaddress+56,0xffffffff);
	}

	KeStallExecutionProcessor(300);

	if ( hDCIaddress != 0 )
	{
		DVWriteDRAM(hDCIaddress,(DWORD)hsy<<16|((WORD)0x3<<12)|hey);
		DVWriteDRAM(hDCIaddress+4,(DWORD)m_set_contr<<16|sx);
		if ( ( hsx - sx ) <= 1 )
			DVWriteDRAM(hDCIaddress+8,(DWORD)(hsx+2)<<16|m_set_color);
		else 
			DVWriteDRAM(hDCIaddress+8,(DWORD)hsx<<16|m_set_color);
		DVWriteDRAM(hDCIaddress+12,(DWORD)hcolor<<16|hcontr);
		DVWriteDRAM(hDCIaddress+16,(DWORD)m_set_contr<<16|hex);
		DVWriteDRAM(hDCIaddress+20,0xffff0000|m_set_color);
		DVWriteDRAM(hDCIaddress+24,0xffffffff);
		DVWriteDRAM(hDCIaddress+52,0xffffffff);
		DVWriteDRAM(hDCIaddress+56,0xffffffff);
	}
}

//////////////////////////////////////////////////////////////////////////////////

void SetCurrentBtn(BYTE* p,DWORD base)
{
DWORD data , addr;

	if ( base == 0 ) 
		addr = 0x3e2000;
	else 
		addr = base;

	DVWriteDRAM(BASE+20,csel);	// Group1 Selection color & contrast
	DVWriteDRAM(BASE+24,csel);	// Group1 Selection color & contrast

	hsx = (GetWORD(p)&0x3ff0)>>4;		// highlight Start X
	hex = GetWORD(p+1)&0x03ff;		// highlight End X
	hsy = (GetWORD(p+3)&0x3fff)>>4;		// highlight Start Y
	hey = GetWORD(p+4)&0x03ff;		// highlight End Y

	if ( hDCIaddress != 0 )
	{
		DVWriteDRAM(hDCIaddress,(DWORD)hsy<<16|((WORD)0x3<<12)|hey);
		DVWriteDRAM(hDCIaddress+4,(DWORD)m_set_contr<<16|sx);
		if ( ( hsx - sx ) <= 1 )
			DVWriteDRAM(hDCIaddress+8,(DWORD)(hsx+2)<<16|m_set_color);
		else 
			DVWriteDRAM(hDCIaddress+8,(DWORD)hsx<<16|m_set_color);
		DVWriteDRAM(hDCIaddress+12,(DWORD)hcolor<<16|hcontr);
		DVWriteDRAM(hDCIaddress+16,(DWORD)m_set_contr<<16|hex);
		DVWriteDRAM(hDCIaddress+20,0xffff0000|m_set_color);
		DVWriteDRAM(hDCIaddress+24,0xffffffff);
		DVWriteDRAM(hDCIaddress+52,0xffffffff);
		DVWriteDRAM(hDCIaddress+56,0xffffffff);
	}

	data = ((DWORD)GetWORD(p+3))<<12 | ((GetWORD(p)&0xc000)|(GetWORD(p+4)&0x03ff));
	DVWriteDRAM(addr,data);
	data = ((DWORD)(GetWORD(p+3)&0xc000))<<16 | ((DWORD)(GetWORD(p)&0x3ff0))<<12 | (GetWORD(p+1)&0x03ff);
	DVWriteDRAM(addr+4,data);
}

//////////////////////////////////////////////////////////////////////////////////

void SetHighlight(BYTE* p)
{
BYTE* ptr;
BYTE  fosl_btnn , foac_btnn;
BYTE  btn_ns;

	ptr = p;	// point to Highlight information

	highflag = FALSE;	// if highlight exists

	if ( ( GetWORD(ptr) & 0x03 ) != 0 ) 
	{	// Highlight exists

		ptr += 2;
		btn_ns = *(ptr+15);

		highPTS = GetDWORD(ptr)&0xfffffffe;	// highlight PTS

		DVWriteREG(0x240,GetDWORD(ptr)&0xfffffffe);	// Start PTS
		DVWriteREG(0x244,GetDWORD(ptr+4));	// End   PTS
		DVWriteREG(0x248,GetDWORD(ptr+8));	// Button Select End PTS
		DVWriteREG(0x24c,SUB_FIFO_OFF);		// Highlight FIFO

		ptr += 18;

		fosl_btnn = *(ptr);
		foac_btnn = *(ptr+1);

		DVWriteDRAM(BASE+16,((DWORD)foac_btnn)<<16|fosl_btnn);	// FOAC & FOSL

		ptr += 2;

		csel = GetDWORD(ptr);
		cact = GetDWORD(ptr+4);

		//new
		hcolor = HIWORD(csel);		// highlight Color
		hcontr = LOWORD(csel);		// highlight Contrast

		hacolor = HIWORD(cact);		// highlight activate Color
		hacontr = LOWORD(cact);		// highlight activate Contrast
		//

		DVWriteDRAM(BASE+20,csel);	// Group1 Selection color & contrast

#ifdef OLD
		DVWriteDRAM(BASE+24,cact);	// Group1 Activation color & contrast
#else
		DVWriteDRAM(BASE+24,csel);	// SW work around
#endif

		ptr += 24;	// point to Button information table

#ifdef OLD
		// Tell HW Highlight exists
		DVWriteREG(0x3d0,DVReadDRAM(0x3d0)|0x04);
#endif

		// Forcedly activated
		if ( foac_btnn == 0 ) return;
		if ( foac_btnn != 63 ) {
			SetCurrentBtn(ptr+(foac_btnn-1)*18,BASE+8);
			return;
		}
	} 
	else {
		DVWriteREG(0x3d0,DVReadDRAM(0x3d0)&0x01);
	}
}

//////////////////////////////////////////////////////////////////////////////////

void SetBtnColor(DWORD* ptr)
{
BYTE* p = (BYTE*)ptr;

	DVWriteREG(0x380,GetDWORD(p));	// Color 
	DVWriteREG(0x384,GetDWORD(p+4));
	DVWriteREG(0x388,GetDWORD(p+8));
	DVWriteREG(0x38c,GetDWORD(p+12));
	DVWriteREG(0x390,GetDWORD(p+16));
	DVWriteREG(0x394,GetDWORD(p+20));
	DVWriteREG(0x398,GetDWORD(p+24));
	DVWriteREG(0x39c,GetDWORD(p+28));
	DVWriteREG(0x3a0,GetDWORD(p+32));
	DVWriteREG(0x3a4,GetDWORD(p+36));
	DVWriteREG(0x3a8,GetDWORD(p+40));
	DVWriteREG(0x3ac,GetDWORD(p+44));
	DVWriteREG(0x3b0,GetDWORD(p+48));
	DVWriteREG(0x3b4,GetDWORD(p+52));
	DVWriteREG(0x3b8,GetDWORD(p+56));
	DVWriteREG(0x3bc,GetDWORD(p+60));
}


////////////////////////////////////////////////////////////////////////////////////////////

void SPStub(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef DBG
		DbgPrint("luxdvd : SPStub - calling SPReceiveDataPacket\n");
	#endif
	SPReceiveDataPacket(pSrb);
}

////////////////////////////////////////////////////////////////////////////////////////////

VOID SPReceiveDataPacket(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PSP_STRM_EX pspstrmex =	&(((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->spstrmex);
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
PKSSTREAM_HEADER	pPacket;
ULONG				cPack=0;
BYTE				*p=NULL;
PHW_STREAM_OBJECT	phstrmo=NULL;
PHW_DEVICE_EXTENSION pdevext = pSrb->StreamObject->HwDeviceExtension;

	if(!pSrb)
    {
		#ifdef DBG
			DbgPrint("luxdvd ERROR : SPReceiveDataPacket  - invalid SRB !!!!\n");
		#endif
		return;
	}


	StreamClassStreamNotification(ReadyForNextStreamDataRequest,pSrb->StreamObject);

	switch (pSrb->Command)
	{
		case SRB_WRITE_DATA:

			// search the packet for discontinuity bits.  If it has any, we need
			// to dump all current subpicture data, and stop the display.
			
			pPacket = pSrb->CommandData.DataBufferArray;

			if(pPacket->TypeSpecificFlags & KS_AM_UseNewCSSKey)
			{
				#ifdef DBG
					DbgPrint("luxdvd : SPReceiveDataPacket - received KS_AM_UseNewCSSKey flag\n");
					//DEBUG_BREAKPOINT()
				#endif

				
				pSrb->Status = STATUS_SUCCESS;
				//StreamClassStreamNotification(ReadyForNextStreamDataRequest,pSrb->StreamObject);
				StreamClassStreamNotification(StreamRequestComplete,pSrb->StreamObject,pSrb);
				return;
				
			}

			
			for (cPack =0;cPack < pSrb->NumberOfBuffers;cPack++, pPacket++)
			{
				if (pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)
				{
					#ifdef DBG
						DbgPrint("luxdvd : SPReceiveDataPacket found KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY - call AbortSP()\n");
					#endif
					AbortSP(pspstrmex);
					
					//new
					if(!f_HLIActive)
					{
						#ifdef DBG
							DbgPrint("luxdvd : SPReceiveDataPacket found KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY - call resetSub()\n");
						#endif
						resetSub();
					}

					pSrb->Status = STATUS_SUCCESS;
					//StreamClassStreamNotification(ReadyForNextStreamDataRequest,pSrb->StreamObject);
					StreamClassStreamNotification(StreamRequestComplete,pSrb->StreamObject,pSrb);
					return;
					//break;
				}
				else if(pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY)
				{
					if( pdevext->TimeDisCount++ >= 2)
					{
						#ifdef DBG
							DbgPrint("luxdvd : received all 3 Stream TimeDisContinuties !!!\n");
						#endif
						pdevext->TimeDisCount = 0;
						//After A, V, SP have all received TimeDis, we are fairly certain that
						//a menu will appear. Here we turn off menu workaround
//						LUXVideoMenu(0);
					}
				}
				else if (pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY && 
					pSrb->NumberOfBuffers <= 1)
				{
					#ifdef DBG
						DbgPrint("luxdvd : SPReceiveDataPacket found KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY\n");
					#endif

					// call back this packet
					pSrb->Status = STATUS_SUCCESS;
					phstrmo = pSrb->StreamObject;
					if(phstrmo == NULL)
					{
						#ifdef DBG
							DbgPrint("luxdvd ERROR : SPReceiveDataPacket  - invalid phstrmo !!!!\n");
						#endif
						return;
					}
					StreamClassStreamNotification(StreamRequestComplete,phstrmo,pSrb);
					return;
				} // end if discontinuity bit is set

			} // end loop on packets

			break;

		default:

			CallBackError(pSrb);
			return;

	}

	SPEnqueue(pSrb, pspstrmex);

	if(!(pspstrmex->pdecctl.decFlags & SPDECFL_BUF_IN_USE))
	{
		//DumpPacket(pspstrmex);

		StreamClassCallAtNewPriority(pSrb->StreamObject,
							pspstrmex->phwdevex,                       
							Dispatch,
							(PHW_PRIORITY_ROUTINE)DumpPacket,
							pspstrmex);
	}

	//StreamClassStreamNotification(ReadyForNextStreamDataRequest,pSrb->StreamObject);
	
}

/////////////////////////////////////////////////////////////////////////////////////////////////////

void AbortSP(PSP_STRM_EX pspstrmex)
{
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);

	if(!pspstrmex)
	{
		#ifdef DBG
			DbgPrint("luxdvd  ERROR : AbortSP - invalid arg !!!!\n");
		#endif
	}

	pdecctl->curData = 0;

	pspstrmex->pdecctl.decFlags = 0;
	CleanSPQueue(pspstrmex);
	
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
void SPPacketStub(PSP_STRM_EX pspstrmex)
{		
	//Call At Dispatch IRQL
	if ( pspstrmex && pspstrmex->pSrbQ )
	{
		StreamClassCallAtNewPriority(pspstrmex->pSrbQ->StreamObject,
								pspstrmex->phwdevex,                       
								Dispatch,
								(PHW_PRIORITY_ROUTINE)DumpPacket,
								pspstrmex);	
	}
}


void DumpPacket(PSP_STRM_EX pspstrmex)
{
PHW_STREAM_REQUEST_BLOCK pSrb;
PSP_DECODE_CTL		pdecctl = &(pspstrmex->pdecctl);
PKSSTREAM_HEADER	pPacket;
ULONG				cPack;
PHW_STREAM_OBJECT	phstrmo;
ULONG				cSkipped = 0;
DWORD				CurPTS=0;
PVOID				Data = NULL;
PUCHAR				pdata = NULL;
int					len,pes_len;

	if(!pspstrmex)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : DumpPacket - invalid arg !!!\n");
		#endif
		return;
	}

	if ( m_Pal )
	{
		if ( pspstrmex->pSrbQ )
		{
			StreamClassScheduleTimer(pspstrmex->pSrbQ->StreamObject, 
								pspstrmex->pSrbQ->HwDeviceExtension,
								50, 
								(PHW_PRIORITY_ROUTINE)SPPacketStub, 
								pspstrmex);
		}
		return;
	}

	do
	{

RESTART_QUEUE:

		if (pSrb = SPDequeue(pspstrmex))
		{
			pPacket = pSrb->CommandData.DataBufferArray;	//get data descriptor

RESTART_COPY:

				while (((pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)
					 || (!pPacket->Data) || (pPacket->DataUsed < sizeof (SPPCKHDR) + PACK_HEADER_SIZE))) 
				{
					#ifdef DBG
						DbgPrint("luxdvd  : DumpPacket KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY\n");
					#endif
					pPacket++;
					cSkipped++;
					//skipped all the KSDATA_PACKET descriptors in psrb
					if (cSkipped >= pSrb->NumberOfBuffers)
					{
						#ifdef DBG
							DbgPrint("luxdvd  : DumpPacket encountered first KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY\n");
						#endif

						//Dont call resetSub here as it seems to erase the menu hightlights
						//We process DataDis in SPReceiveDataPacket and we call resetSub there
						//resetSub();

						// call back this packet
						pSrb->Status = STATUS_SUCCESS;
						phstrmo = pSrb->StreamObject;
						StreamClassStreamNotification(StreamRequestComplete,phstrmo,pSrb);
						goto RESTART_QUEUE;
					}
				}

				if (pSrb)
				{
					// go ahead and start moving the data
					for (cPack = cSkipped; cPack < pSrb->NumberOfBuffers; cPack++, pPacket++)
					{
						if (pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY ||
							pPacket->DataUsed < 4)
						{
							// yikes!  We have a discontinuity!  Dump all data
							// up to this point, and start again!
							pdecctl->curData = 0;
							pPacket++;
							cSkipped = cPack + 1;
							#ifdef DBG
								DbgPrint("luxdvd ERROR : DumpPacket - lower KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY - resetSub !!!\n");
							#endif
							resetSub();	//reset all sp stuff
							goto RESTART_COPY;
						}
					
						#ifdef DBG
							//Check for SP stream_id 0x000001
							Data = (PVOID) ((ULONG) pPacket->Data + PACK_HEADER_SIZE);
							if ((*((PDWORD) Data) & 0xFFFFFF) != 0x010000)
							{
								#ifdef DBG
									DbgPrint("luxdvd ERROR : Dumppacket 1st packet - invalid SP_PCK PES header !\n");
									//DEBUG_BREAKPOINT();
								#endif
								CallBackError(pSrb);
								return;             
							}
						#endif

						//skip the 14bytes PACK_HEADER and SP start code
						pdata = (PUCHAR)( (ULONG)pPacket->Data + PACK_HEADER_SIZE + 4); 
						len = (int)GetWORD(pdata);	//get the PES_packet_length
						if(pdata[2] & 0x30)//scrambled packet
						{
							#ifdef DBG
								//DbgPrint("luxdvd : DumpPacket 1st packet - scrambled SP\n");
							#endif
							do_unscramble((BYTE *)((ULONG)pPacket->Data));
						}
						pes_len = (int)pdata[4];
						len = (int)(len - 3 - pes_len);
						if( ((pdata[5] & 0xf0) == 0x20) && (pes_len > 0) )
						{
							CurPTS = GetWORD(&pdata[6]) >> 1;
							CurPTS = CurPTS << 14 | GetWORD(&pdata[8]) >> 2;
							CurPTS |= (DWORD) ( pdata[5] & 0xe )  << 28;
						}
						pdata += pes_len + 5;
						LS_Send_Sub(CurPTS,(BYTE *)(pdata + 1),(WORD)(len-1),0,pspstrmex);					
						// have we reached the end of the subpicture unit?
						pdecctl->curData += len-1;
						if (pdecctl->curData == pdecctl->cData)
						{
							cPack= 0xFFFFFFFE;
						}
					}
	
					// call back this packet, if we don't have leftover
					pSrb->Status = STATUS_SUCCESS;
					phstrmo = pSrb->StreamObject;

					StreamClassStreamNotification(StreamRequestComplete,
						    phstrmo,              
							pSrb);             
					
					if (pdecctl->curData == pdecctl->cData)
					{
						// y: indicate that we have a full buffer, and start
						// the initial decoding process
						pdecctl->decFlags |= SPDECFL_BUF_IN_USE | SPDECFL_NEW_PIC;
						//mark the packet as finsihed
						pdecctl->decFlags &= ~(SPDECFL_BUF_IN_USE | SPDECFL_SUBP_ON_DISPLAY);
						pdecctl->decFlags |= SPDECFL_LAST_FRAME;
						pdecctl->curData = 0;
						return;
					}
				}
			}
			else
				return;

		} while(TRUE);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////

void CallBackError(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	if(!pSrb)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : CallBackError - invalid arg !!!\n");
		#endif
		return;
	}
		
	pSrb->Status = STATUS_SUCCESS;

	if (pSPstrmex)
	{

		pSPstrmex->pdecctl.curData = 0;
		pSPstrmex->pdecctl.decFlags = 0;

	}

	StreamClassStreamNotification(StreamRequestComplete,
					pSrb->StreamObject,              
					pSrb);             
}

/////////////////////////////////////////////////////////////////////////////////////////////////////

void SPEnqueue(PHW_STREAM_REQUEST_BLOCK pSrb, PSP_STRM_EX pspstrmex)
{
PHW_STREAM_REQUEST_BLOCK pSrbTmp;
ULONG cSrb;

	if( !pSrb || !pspstrmex )
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : SPEnqueue -invalid arg !!!\n");
		#endif
	}

	// enqueue the given SRB on the device extension queue

	for (cSrb =0,
		pSrbTmp = CONTAINING_RECORD((&(pspstrmex->pSrbQ)),
			HW_STREAM_REQUEST_BLOCK, NextSRB);
			pSrbTmp->NextSRB;
			pSrbTmp = pSrbTmp->NextSRB, cSrb++);

	pSrbTmp->NextSRB = pSrb;
	pSrb->NextSRB = NULL;

}

/////////////////////////////////////////////////////////////////////////////////////////////////////

PHW_STREAM_REQUEST_BLOCK SPDequeue(PSP_STRM_EX pspstrmex)
{
PHW_STREAM_REQUEST_BLOCK pRet = NULL;

	if( !pspstrmex )
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : SPDequeue - invalid arg !!!\n");
		#endif
	}
	if (pspstrmex->pSrbQ)
	{
		pRet = pspstrmex->pSrbQ;
		pspstrmex->pSrbQ = pRet->NextSRB;
	}

	return(pRet);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////

void CleanSPQueue(PSP_STRM_EX pspstrmex)
{
PHW_STREAM_REQUEST_BLOCK pSrb;

	if( !pspstrmex )
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : CleanSPQueue - invalid arg !!!\n");
		#endif
	}

	pspstrmex->pdecctl.curData = 0;
	ulRemain = 0;


	while (pSrb = SPDequeue(pspstrmex))
	{
		CallBackError(pSrb);
	}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////


void SPSetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION phwdevext;
PSP_STRM_EX pspstrmex;

	if(!pSrb)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : SPSetState - received invalid SRB !!!!!\n");
		#endif
		return;
	}

	phwdevext =	((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

	pspstrmex =	&(((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->spstrmex);

	pspstrmex->pdecctl.spState = pSrb->CommandData.StreamState;

	switch (pSrb->CommandData.StreamState)  
	{
		case KSSTATE_STOP:
		
			#ifdef DBG
				DbgPrint("luxdvd : SPSetState - KSSTATE_STOP\n");
			#endif

			pspstrmex->pdecctl.decFlags = 0;

			pspstrmex->pdecctl.HLI.fValid = FALSE;
			pspstrmex->pdecctl.HLI.fProcessed = TRUE;
			CleanSPQueue(pspstrmex);
			LS_SP_Init();
			break;

		case KSSTATE_PAUSE:
		case KSSTATE_RUN:

			#ifdef DBG
				if(pSrb->CommandData.StreamState == KSSTATE_RUN)
					DbgPrint("luxdvd : SPSetState - KSSTATE_RUN\n");
				else
					DbgPrint("luxdvd : SPSetState - KSSTATE_PAUSE\n");
			#endif

			pspstrmex->pdecctl.decFlags |= SPDECFL_NEW_PIC;
			DumpPacket(pspstrmex);
			break;

		default:
		{
			TRAP
		}

	}

	pSrb->Status = STATUS_SUCCESS;

}

/////////////////////////////////////////////////////////////////////////////////////////////////////

void SPGetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION phwdevext;
PSP_STRM_EX pspstrmex;

	#ifdef DBG
		DbgPrint("luxdvd : SPGetState\n");
	#endif

	pspstrmex =	&(((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->spstrmex);

	pSrb->CommandData.StreamState = pspstrmex->pdecctl.spState;
	pSrb->Status = STATUS_SUCCESS;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////

void SPSetProp (PHW_STREAM_REQUEST_BLOCK pSrb)
{
PSP_STRM_EX pspstrmex;
PSP_DECODE_CTL pdecctl;
PKSPROPERTY_SPPAL ppal;
USHORT cPal;
WORD wlow=0;
WORD whi=0;
DWORD dwcolor[16];
DWORD dwdata;
PHW_DEVICE_EXTENSION phwdevext;
int i=0;

	if(!pSrb)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : SPSetProp - received invalid SRB !!!!!\n");
		#endif
		return;
	}

	pspstrmex =	&(((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->spstrmex);
	pdecctl = &(pspstrmex->pdecctl);
	phwdevext =	((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

	// make sure it is a valid property set

	switch(pSrb->CommandData.PropertyInfo->PropertySetID)
	{
		case 0:

			switch (pSrb->CommandData.PropertyInfo->Property->Id )
			{
				// look for the pallette property
				case KSPROPERTY_DVDSUBPIC_PALETTE:

					#ifdef DBG
						DbgPrint("luxdvd : SPSetProp - KSPROPERTY_DVDSUBPIC_PALETTE\n");
					#endif

					ppal = (PKSPROPERTY_SPPAL)pSrb->CommandData.PropertyInfo->PropertyInfo;
					for (cPal = 0;cPal < 16; cPal++)
					{
						#ifdef ORIGINAL_CODE
						pdecctl->spYUV.ucY[cPal] = ppal->sppal[cPal].Y >> 2;
						pdecctl->spYUV.ucU[cPal] = ppal->sppal[cPal].U >> 4;
						pdecctl->spYUV.ucV[cPal] = ppal->sppal[cPal].V >> 4;
						#endif
				
						wlow = MAKEWORD(ppal->sppal[cPal].V,ppal->sppal[cPal].U);
						whi = MAKEWORD(ppal->sppal[cPal].Y,0x0);
						dwcolor[cPal] = (DWORD)MAKELONG(wlow,whi);
						DVWriteREG( (DWORD)(0x380 + cPal*4), dwcolor[cPal]);
					}
					pSrb->Status = STATUS_SUCCESS;

					break;

				// look for HLI property

				case KSPROPERTY_DVDSUBPIC_HLI:
				{						
					#ifdef DBG
						//DbgPrint("luxdvd - KSPROPERTY_DVDSUBPIC_HLI\n");
					#endif

					// copy the HLI over
			
					pdecctl->HLI.hli = *((PKSPROPERTY_SPHLI)pSrb->CommandData.PropertyInfo->PropertyInfo);

					#ifdef DBG
					/*
					DbgPrint("\nSPSetProp : KSPROPERTY_DVDSUBPIC_HLI\n");
					DbgPrint("SPSetProp : StartPTM=0x%lx, EndPTM=0x%lx\n",(DWORD)(pdecctl->HLI.hli.StartPTM),(DWORD)(pdecctl->HLI.hli.EndPTM));
					DbgPrint("SPSetProp : StartX=0x%lx, StartY=0x%lx, StopX=0x%lx, StopY=0x%lx\n",
					(DWORD)(pdecctl->HLI.hli.StartX),(DWORD)(pdecctl->HLI.hli.StartY),(DWORD)(pdecctl->HLI.hli.StopX),(DWORD)(pdecctl->HLI.hli.StopY));
					DbgPrint("SPSetProp : emph2col=0x%lx, emph1col=0x%lx, backcol=0x%lx, patcol=0x%lx\n",
					(DWORD)(pdecctl->HLI.hli.ColCon.emph2col),(DWORD)(pdecctl->HLI.hli.ColCon.emph1col),
					(DWORD)(pdecctl->HLI.hli.ColCon.backcol),(DWORD)(pdecctl->HLI.hli.ColCon.patcol));
					DbgPrint("SPSetProp : emph2con=0x%lx, emph1con=0x%lx, backcon=0x%lx, patcon=0x%lx\n",
					(DWORD)(pdecctl->HLI.hli.ColCon.emph2con),(DWORD)(pdecctl->HLI.hli.ColCon.emph1con),
					(DWORD)(pdecctl->HLI.hli.ColCon.backcon),(DWORD)(pdecctl->HLI.hli.ColCon.patcon));
					*/
					#endif

					#ifdef ORIGINAL_CODE
						pdecctl->HLI.fProcessed = FALSE;
						if (pdecctl->HLI.hli.HLISS)
							pdecctl->HLI.fValid = TRUE;
						else
						{
							if (!pdecctl->HLI.fActive)
								pdecctl->HLI.fProcessed = TRUE;
			
							pdecctl->HLI.fValid = FALSE;
						}
						// indicate that this HLI has not been processed yet
						pdecctl->HLI.fActive = FALSE;
						pSrb->Status = STATUS_SUCCESS;
					#else

						f_HLIActive = TRUE;
			
						if (!pdecctl->HLI.hli.HLISS)
						{
							#ifdef DBG
								DbgPrint("luxdvd : SetSPProp - HLISS is invalid !!!!\n");
							#endif
							f_HLIActive = FALSE;
							highflag = FALSE;
							break;
						}
						
						highflag = TRUE;

						//pgm HLI_S_PTM
						#ifdef DBG
							//DbgPrint("luxdvd : SetSPProp - HLI_S_PTM=0x%lx, STC=0x%lx\n",(DWORD)(pdecctl->HLI.hli.StartPTM),DVReadDRAM(0x218));
						#endif
						DVWriteDRAM(0x240,(DWORD)(pdecctl->HLI.hli.StartPTM & 0xffffffff));


//						LUXVideoMenu(1);	//do menu workaround
												
						//pgm HLI_E_PTM
						DVWriteDRAM(0x244,(DWORD)(pdecctl->HLI.hli.EndPTM));
			
						//pgm BTN_SL_E_PTM
						DVWriteDRAM(0x248,(DWORD)(pdecctl->HLI.hli.EndPTM));

						//pgm Highlight FIFO
						DVWriteDRAM(0x24c,SUB_FIFO_OFF);

						dwdata = (DWORD)(	((pdecctl->HLI.hli.ColCon.emph2col & 0xf)<<28) |
									((pdecctl->HLI.hli.ColCon.emph1col & 0xf)<<24) |
									((pdecctl->HLI.hli.ColCon.patcol & 0xf)<<20) |
									((pdecctl->HLI.hli.ColCon.backcol & 0xf)<<16) |
									((pdecctl->HLI.hli.ColCon.emph2con & 0xf)<<12) |
									((pdecctl->HLI.hli.ColCon.emph1con & 0xf)<<8) |
									((pdecctl->HLI.hli.ColCon.patcon & 0xf)<<4) |
									(pdecctl->HLI.hli.ColCon.backcon & 0xf) );
						#ifdef DBG
							//DbgPrint("SPSetProp : Selection Color/Contrast = 0x%lx\n",dwdata);
						#endif

						//set Selection color contrast 
						DVWriteDRAM(BASE+20,dwdata);

						/*
						Due to hw bug in LS220, we also fill in the Action Color/Contrast with Selection values
						*/

						DVWriteDRAM(BASE+24,dwdata);	//Action Values

						//new
						hcolor = HIWORD(dwdata);		// highlight Color
						hcontr = LOWORD(dwdata);		// highlight Contrast

						hacolor = HIWORD(dwdata);		// highlight activate Color
						hacontr = LOWORD(dwdata);		// highlight activate Contrast

						hsx = (pdecctl->HLI.hli.StartX);		// highlight Start X
						hex = (pdecctl->HLI.hli.StopX);		// highlight End X
						hsy = (pdecctl->HLI.hli.StartY);		// highlight Start Y
						hey = (pdecctl->HLI.hli.StopY);		// highlight End Y

						if ( hsy < sy )	// highligh start Y less than SP start Y
							hsy = sy;

						if ( hDCIaddress != 0 )
						{
							if ( ( hey - hsy ) == 1 )	// ??? , H/W problem ???
								DVWriteDRAM(hDCIaddress,(DWORD)(hsy-1)<<16|((WORD)0x3<<12)|hey);
							else
								DVWriteDRAM(hDCIaddress,(DWORD)hsy<<16|((WORD)0x3<<12)|hey);

							DVWriteDRAM(hDCIaddress+4,(DWORD)m_set_contr<<16|sx);

							if ( ( hsx - sx ) <= 1 )	// ??? , H/W problem ???
								DVWriteDRAM(hDCIaddress+8,(DWORD)(hsx+2)<<16|m_set_color);
							else 
								DVWriteDRAM(hDCIaddress+8,(DWORD)hsx<<16|m_set_color);

							DVWriteDRAM(hDCIaddress+12,(DWORD)hcolor<<16|hcontr);
							DVWriteDRAM(hDCIaddress+16,(DWORD)m_set_contr<<16|(pdecctl->HLI.hli.StopX));
							DVWriteDRAM(hDCIaddress+20,0xffff0000|m_set_color);
							DVWriteDRAM(hDCIaddress+24,0xffffffff);
							DVWriteDRAM(hDCIaddress+52,0xffffffff);
							DVWriteDRAM(hDCIaddress+56,0xffffffff);
						}
						//

						//pgm StartY and EndY of Current Button
						dwdata = (DWORD)( (pdecctl->HLI.hli.StartY << 16) | (pdecctl->HLI.hli.StopY) );
						#ifdef DBG
							//DbgPrint("SPSetProp : BASE (Current StartY and EndY) = 0x%lx\n",dwdata);
						#endif
						DVWriteDRAM(BASE,dwdata);
				
						//pgm StartX and EndX of Current Button
						dwdata = (DWORD)( (pdecctl->HLI.hli.StartX << 16) | (pdecctl->HLI.hli.StopX) );
						#ifdef DBG
							//DbgPrint("SPSetProp : BASE+4 (Current StartX and EndX) = 0x%lx\n",dwdata);
						#endif
						DVWriteDRAM(BASE+4,dwdata);

						//tell HW HLI exists
//						DVWriteREG(0x3d0,DVReadDRAM(0x3d0)|0x4);

						//flush out any remaining video
//						LUXVideoFlush();

						pSrb->Status = STATUS_SUCCESS;
					#endif//ORIGINAL_CODE
					break;
				}


				case KSPROPERTY_DVDSUBPIC_COMPOSIT_ON:
				{
					#ifdef DBG
						DbgPrint("luxdvd : SPSetProp -KSPROPERTY_DVDSUBPIC_COMPOSIT_ON\n");			
					#endif

					if (*((PKSPROPERTY_COMPOSIT_ON)pSrb->CommandData.PropertyInfo->PropertyInfo))
					{
						#ifdef DBG
							DbgPrint("luxdvd : SPSetProp - SubPic ON\n");
						#endif
						DVWriteREG(0x3d0,DVReadDRAM(0x3d0)|0x1);			// enable sub-pict
						phwdevext->ShowSP = 1;
					}
					else
					{
						#ifdef DBG
							DbgPrint("luxdvd : SPSetProp - SubPic OFF\n");
						#endif
						DVWriteREG(0x3d0,DVReadDRAM(0x3d0)&0xfffffffe);			// enable sub-pict
						phwdevext->ShowSP = 0;
					}
					pSrb->Status = STATUS_SUCCESS;
					break;
				}

				default:

					pSrb->Status = STATUS_NOT_IMPLEMENTED;
					break;
		
			}
			break;


		case 1:

			// this is a copy protection property go handle it there
			#ifdef DBG
				//DbgPrint("luxdvd : SPSetProp calling CopyProtSetProp\n");
			#endif

			CopyProtSetProp(pSrb);
			pSrb->Status = STATUS_SUCCESS;
			break;

		case 2:
		{
			#ifdef DBG
				DbgPrint("luxdvd : SPSetprop calling SPRateChnageSetProp\n");
			#endif
			SPRateChangeSetProp(pSrb);
			pSrb->Status = STATUS_SUCCESS;
			break;
		}

		default:
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
	}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////

void SPGetProp(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	if( !pSrb)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : SPGetProp - invalid arg !!!\n");
		#endif
		return;
	}

	switch (pSrb->CommandData.PropertyInfo->PropertySetID)
	{
		case 1:
		{
			#ifdef DBG
				//DbgPrint("luxdvd : SPGetProp calling CopyProtGetProp\n");
			#endif
			CopyProtGetProp(pSrb);
			pSrb->Status = STATUS_SUCCESS;
			break;
		}

		case 2:
		{
			#ifdef DBG
				DbgPrint("luxdvd : SPSetprop calling SPRateChnageGetProp\n");
			#endif
			SPRateChangeGetProp(pSrb);
			pSrb->Status = STATUS_SUCCESS;
			break;
		}

		default:
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
	}

}

//////////////////////////////////////////////////////////////////////////////////////////////

//Rate Chnage functions

void InitSPRate(PHW_DEVICE_EXTENSION pHwDevExt)
{
	pHwDevExt->SubpicStartTime = 0;
	pHwDevExt->SubpicInterceptTime = 0;
	pHwDevExt->SubpicRate = 1 * 10000;
	pHwDevExt->SubpicMaxFullRate = 1 * 10000;
}

//////////////////////////////////////////////////////////////////////////////////////////////

void SPRateChangeGetProp(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION pHwDevExt = (PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension;

	#ifdef DBG
		//DbgPrint("luxdvd : SPRateChangeGetProp\n");
	#endif

	switch( pSrb->CommandData.PropertyInfo->Property->Id ) 
	{
		case KS_AM_RATE_SimpleRateChange :
		{
		KS_AM_SimpleRateChange* pRateChange;

			#ifdef DBG
				//DbgPrint("luxdvd : SPRateChangeGetProp - KS_AM_RATE_SimpleRateChange\n");
			#endif
			pSrb->ActualBytesTransferred = sizeof (KS_AM_RATE_SimpleRateChange);
			pRateChange = (KS_AM_SimpleRateChange*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			pRateChange->StartTime = pHwDevExt->SubpicStartTime;
			pRateChange->Rate = pHwDevExt->SubpicRate;
			pSrb->Status = STATUS_SUCCESS;
			break;
		}

		case KS_AM_RATE_ExactRateChange :
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;

		case KS_AM_RATE_MaxFullDataRate :
		{
		KS_AM_MaxFullDataRate* pMaxRate;

			#ifdef DBG
				//DbgPrint("luxdvd : SPRateChangeGetProp - KS_AM_RATE_MaxFullDataRate\n");
			#endif
			pSrb->ActualBytesTransferred = sizeof (KS_AM_RATE_MaxFullDataRate);
			pMaxRate = (KS_AM_MaxFullDataRate*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			*pMaxRate = pHwDevExt->SubpicMaxFullRate;
			pSrb->Status = STATUS_SUCCESS;
			break;
		}

		case KS_AM_RATE_Step :
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////

void SPRateChangeSetProp(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef DBG
		//DbgPrint("luxdvd : SPRateChangeSetProp\n");
	#endif

	switch( pSrb->CommandData.PropertyInfo->Property->Id ) 
	{

		case KS_AM_RATE_SimpleRateChange :
		{
		KS_AM_SimpleRateChange* pRateChange;
		PHW_DEVICE_EXTENSION pHwDevExt;
		REFERENCE_TIME NewStartTime;
		LONG NewRate;

			#ifdef DBG
				//DbgPrint("luxdvd : SPRateChangeSetProp - KS_AM_RATE_SimpleRateChange\n");
			#endif

			pRateChange = (KS_AM_SimpleRateChange*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			pHwDevExt = (PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension;
			NewStartTime = pRateChange->StartTime;
			NewRate = ( pRateChange->Rate < 0 ) ? -pRateChange->Rate : pRateChange->Rate;
			#ifdef DBG
				//DbgPrint("luxdvd : Received StartTime = 0x%08x\n",NewStartTime);
				//DbgPrint("luxdvd : Received Rate = 0x%08x\n",NewRate);
			#endif
			//				pHwDevExt->SubpicInterceptTime
			//					= (pHwDevExt->SubpicInterceptTime - NewStartTime)
			//					* pHwDevExt->SubpicRate
			//					/ NewRate
			//					+ NewStartTime;

			pHwDevExt->SubpicRate = NewRate;
			if( NewRate == 10000 ) 
			{
				#ifdef DBG
					//DbgPrint("luxdvd : New SP rate is NORMAL\n");
				#endif
				pHwDevExt->SubpicInterceptTime = 0;
				pHwDevExt->SubpicStartTime = 0;
			}
			else 
			{
				#ifdef DBG
					//DbgPrint("luxdvd : New SP rate is DIFFERENT\n");
				#endif
				pHwDevExt->SubpicInterceptTime = (ULONG)((-NewStartTime) * 10000 / NewRate + NewStartTime);
				pHwDevExt->SubpicStartTime = NewStartTime;
			}

			SetRateChange( pHwDevExt, 0x04 );
			pSrb->Status = STATUS_SUCCESS;
			break;
		}

		case KS_AM_RATE_ExactRateChange :
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;

		case KS_AM_RATE_MaxFullDataRate :
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;

		case KS_AM_RATE_Step :
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
	}
}
