File:  [DVB] / margi2 / decoder.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Dec 3 22:41:13 2000 UTC (23 years, 6 months ago) by cvs
Branches: CIM
CVS tags: margi043
initial public CVS release 

/* 
    decoder.c

    Copyright (C) Christian Wolff for convergence integrated media.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#define __NO_VERSION__

#include "decoder.h"
#include "l64021.h"
#include "video.h"
#include "audio.h"
#include "streams.h"
#include "osd.h"
#include "dram.h"

int DecoderGetNavi(struct cvdv_cards *card, u8 *navidata) 
{
	if (card->navihead == card->navitail) return 0;
//      printk(KERN_DEBUG LOGNAME ": Retreiving NaviPack\n");
	memcpy(navidata, &card->navibuffer[card->navitail], NAVISIZE);
	card->navitail += NAVISIZE;
	if (card->navitail >= NAVIBUFFERSIZE) card->navitail = 0;
	return NAVISIZE;
}

// returns 1 on overrun, 0 on no error
int DecoderQueueNavi(struct cvdv_cards *card, u8 *navidata) 
{
	memcpy(&card->navibuffer[card->navihead], navidata, NAVISIZE);
	card->navihead += NAVISIZE;
	if (card->navihead >= NAVIBUFFERSIZE) card->navihead = 0;
	if (card->navihead == card->navitail) {
//      printk(KERN_DEBUG LOGNAME ": NaviPack buffer overflow\n");
		card->navitail += NAVISIZE;
		if (card->navitail >= NAVIBUFFERSIZE) card->navitail = 0;
		return 1;
	}
	return 0;
}

u32 ParseSCR(const u8 *scrdata) 
{
	u32 SCR_base=0;
	
	if ((!scrdata[0]) && (!scrdata[1]) && (scrdata[2]==1) 
	    && (scrdata[3]==0xBA) && ((scrdata[4]&0xC0)==0x40)) {
		SCR_base=((scrdata[4]>>3)&0x07);
		SCR_base=(SCR_base<<2) | (scrdata[4]&0x03);
		SCR_base=(SCR_base<<8) | scrdata[5];
		SCR_base=(SCR_base<<5) | ((scrdata[6]>>3)&0x1F);
		SCR_base=(SCR_base<<2) | (scrdata[6]&0x03);
		SCR_base=(SCR_base<<8) | scrdata[7];
		SCR_base=(SCR_base<<5) | ((scrdata[8]>>3)&0x1F);
	}
	return SCR_base;
}

u32 SetSCR(struct cvdv_cards *card, u32 SCR_base) 
{
//  printk(KERN_ERR LOGNAME ": SCR in DVD Pack: 0x%08X\n",SCR_base);
	if (DecoderReadByte(card, 0x007) & 0x10) {  // SCR already stopped
		DecoderWriteByte(card,0x009,SCR_base&0xFF);  // Set SCR counter
		DecoderWriteByte(card,0x00A,(SCR_base>>8)&0xFF);
		DecoderWriteByte(card,0x00B,(SCR_base>>16)&0xFF);
		DecoderWriteByte(card,0x00C,(SCR_base>>24)&0xFF);
	} else {
		DecoderMaskByte(card,0x007,0xD2,0xD2);   
                // Set 0x10, halt SCR counter
		DecoderWriteByte(card,0x009,SCR_base&0xFF);  // Set SCR counter
		DecoderWriteByte(card,0x00A,(SCR_base>>8)&0xFF);
		DecoderWriteByte(card,0x00B,(SCR_base>>16)&0xFF);
		DecoderWriteByte(card,0x00C,(SCR_base>>24)&0xFF);
		DecoderMaskByte(card,0x007,0xD2,0xC2);   
               // Del 0x10, SCR counter run
	}
	return SCR_base;
}

void DecoderPause(struct cvdv_cards *card) 
{
	DecoderMaskByte(card, 0x007, 0xD2, 0xD2);   
        // Set 0x010, halt SCR counter
	AudioSetPlayMode(card, AUDIO_PAUSE);
	DecoderStopDecode(card);
	card->paused = 1;
}

void DecoderUnPause(struct cvdv_cards *card) 
{
	DecoderStartDecode(card);
	AudioSetPlayMode(card, AUDIO_PLAY);
	DecoderMaskByte(card, 0x007, 0xD2, 0xC2);   
        // Del 0x010, SCR counter run
	card->paused = 0;
}

void CloseCard(struct cvdv_cards *card) 
{
	printk(KERN_DEBUG LOGNAME ": Closing card\n");
	DecoderStreamReset(card);
	DecoderSetupReset(card);
	DecoderUnPrepare(card);
	DecoderClose(card);

	AudioClose(card);
	OSDClose(card);
}


void DecoderReadAudioInfo(struct cvdv_cards *card) 
{
	u8 data;
	static int bitrates[17] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 
				   128, 160, 192, 224, 256, 320, 384, 0};
	struct AudioParam *audio = &card->stream.audio;
	data = DecoderReadByte(card, 0x150);
	audio->mpeg.present = data & 0x60;  
        // MPEG Layer Code 00 reserverd, we can assume valid MPEG params
	if (audio->mpeg.present) {
		audio->mpeg.MPEG2 = data & 0x80;
		audio->mpeg.layer = 4 - ((data >> 5) & 0x03);
		if (data & 0x0F) {
			if ((data & 0x0F) == 1) audio->mpeg.bitrate = 32; 
			else switch (audio->mpeg.layer) {
			case 1: 
				audio->mpeg.bitrate = 32 * (data & 0x0F); 
				break;  // Layer I
			case 2: 
				audio->mpeg.bitrate = bitrates[(data & 0x0F) +
							      1]; 
				break;  // Layer II
			default: 
				audio->mpeg.bitrate = bitrates[data & 0x0F];
				// Layer III
			}
		} else audio->mpeg.bitrate = 0;
		data = DecoderReadByte(card, 0x151);
		switch ((data >> 6) & 0x03) {
		case 0: 
			audio->mpeg.samplefreq = 44; 
			break;
		case 1: 
			audio->mpeg.samplefreq = 48; 
			break;
		case 2: 
			audio->mpeg.samplefreq = 32; 
			break;
		default: 
			audio->mpeg.samplefreq = 0; // invalid
		}
		audio->mpeg.mode = (data >> 3) & 0x03;
		audio->mpeg.modeext = (data >> 1) & 0x03;
		audio->mpeg.copyright = data & 0x01;
		data=DecoderReadByte(card, 0x152);
		audio->mpeg.original = data & 0x80;
		audio->mpeg.emphasis = (data >> 5) & 0x03;
	}
	data = DecoderReadByte(card, 0x153);
	audio->ac3.present = (data != 0);  
	// value 0 for bits 0..5 forbidden, we can assume valid ac3 params
	if (audio->ac3.present) {
		audio->ac3.acmod = (data >> 5) & 0x07;
		audio->ac3.dialnorm = data & 0x1F;
		data = DecoderReadByte(card, 0x154);
		audio->ac3.bsmod = (data >> 5) & 0x07;
		audio->ac3.dialnorm2 = data > 0x1F;
		data = DecoderReadByte(card, 0x155);
		audio->ac3.surmixlev = (data >> 6) & 0x03;
		audio->ac3.mixlevel = (data >> 1) & 0x1F;
		data = DecoderReadByte(card, 0x156);
		audio->ac3.cmixlev = (data >> 6) & 0x03;
		audio->ac3.mixlevel2 = (data >> 1) & 0x1F;
		data = DecoderReadByte(card, 0x157);
		audio->ac3.fscod = (data >> 6) & 0x03;
		audio->ac3.lfeon = (data >> 5) & 0x01;
		audio->ac3.bsid = data & 0x1F;
		data = DecoderReadByte(card, 0x158);
		audio->ac3.dsurmod = (data >> 6) & 0x03;
		audio->ac3.frmsizecod = data & 0x3F;
		audio->ac3.langcod = DecoderReadByte(card, 0x159);
		audio->ac3.langcod2 = DecoderReadByte(card, 0x15A);
		audio->ac3.timecod = DecoderReadByte(card, 0x15B);
		data = DecoderReadByte(card, 0x15C);
		audio->ac3.timecod = (audio->ac3.timecod << 6) | 
		  ((data >> 2) & 0x3F);
		audio->ac3.roomtyp = data & 0x03;
		audio->ac3.timecod2 = DecoderReadByte(card, 0x15D);
		data = DecoderReadByte(card, 0x15E);
		audio->ac3.timecod2 = (audio->ac3.timecod2 << 6) | 
		  ((data >> 2) & 0x3F);
		audio->ac3.roomtyp2 = data & 0x03;
	}
	audio->pcm.present =! (DecoderReadByte(card, 0x161) & 0x20);  
	// PCM FIFO not empty? Then, we can assume valid LPCM params
	if (audio->pcm.present) {
		data = DecoderReadByte(card, 0x15F);
		audio->pcm.audio_frm_num = (data >> 3) & 0x1F;
		audio->pcm.num_of_audio_ch = data & 0x07;
		data = DecoderReadByte(card, 0x160);
		audio->pcm.Fs = (data >> 6) & 0x03;
		audio->pcm.quantization = (data >> 4) & 0x03;
		audio->pcm.emphasis = (data >> 2) & 0x03;
		audio->pcm.mute_bit = (data >> 1) & 0x01;
	}
	switch (card->setup.audioselect) {
	case audio_disable:
		audio->valid = 0;
		break;
	case audio_none:
	case audio_DTS:
	case audio_SDDS:
		if ((audio->valid = (audio->ac3.present || 
				     audio->pcm.present || 
				     audio->mpeg.present))) {
			if (audio->mpeg.present) {
				card->setup.audioselect = audio_MPEG;
			} else if (audio->pcm.present) {
				card->setup.audioselect = audio_LPCM;
			} else if (audio->ac3.present) {
				card->setup.audioselect = audio_AC3;
			} 
		} else {
			audio->valid = 0;
			card->setup.audioselect = audio_none;
		}
		break;
	case audio_MPEG:  // MPEG Audio
	case audio_MPEG_EXT:  // MPEG Audio with extension stream
		audio->valid = audio->mpeg.present;
		break;
	case audio_LPCM:  // Linear Pulse Code Modulation LPCM
		audio->valid = audio->pcm.present;
		break;
	case audio_AC3:  // AC-3
		audio->valid = audio->ac3.present;
		break;
	}
	printk(KERN_DEBUG LOGNAME ": -- DecoderReadAudioInfo - type/valid %d/%d:\n", card->setup.audioselect, audio->valid);
	if (audio->mpeg.present || audio->ac3.present || audio->pcm.present)
		printk(KERN_DEBUG LOGNAME ": Audio - Decoded parameters:\n");
	if (audio->mpeg.present) printk(KERN_DEBUG LOGNAME ":   MPEG%s Layer %d, %d kHz, %d kbps, %s, %s%s, %s emphasis\n", 
					((audio->mpeg.MPEG2) ? "2" : "1"), 
					audio->mpeg.layer, 
					audio->mpeg.samplefreq, 
					audio->mpeg.bitrate, 
					((audio->mpeg.mode == 0) ? "stereo" : ((audio->mpeg.mode == 1) ? "joint stereo" : ((audio->mpeg.mode == 2) ? "dual channel" : "single channel"))), 
					((audio->mpeg.copyright) ? "copyrighted " : ""), 
					((audio->mpeg.original) ? "original" : "copy"), 
					((audio->mpeg.emphasis == 0) ? "no" : ((audio->mpeg.emphasis == 1) ? "50/15 usec." : ((audio->mpeg.emphasis == 2) ? "invalid" : "J.17")))
		);
	if (audio->ac3.present) printk(KERN_DEBUG LOGNAME ":   AC3 acmod=%d bsmod=%d dialnorm=%d dialnorm2=%d surmixlev=%d mixlevel=%d cmixlev=%d mixlevel2=%d fscod=%d lfeon=%d bsid=%d dsurmod=%d frmsizecod=%d langcod=%d langcod2=%d timecod=%d roomtyp=%d timecod2=%d roomtyp2=%d\n", 
				       audio->ac3.acmod, 
				       audio->ac3.bsmod, 
				       audio->ac3.dialnorm, 
				       audio->ac3.dialnorm2, 
				       audio->ac3.surmixlev, 
				       audio->ac3.mixlevel, 
				       audio->ac3.cmixlev, 
				       audio->ac3.mixlevel2, 
				       audio->ac3.fscod, 
				       audio->ac3.lfeon, 
				       audio->ac3.bsid, 
				       audio->ac3.dsurmod, 
				       audio->ac3.frmsizecod, 
				       audio->ac3.langcod, 
				       audio->ac3.langcod2, 
				       audio->ac3.timecod, 
				       audio->ac3.roomtyp, 
				       audio->ac3.timecod2, 
				       audio->ac3.roomtyp2);
	if (audio->pcm.present) printk(KERN_DEBUG LOGNAME ":   LPCM audio_frm_num=%d num_of_audio_ch=%d Fs=%d quantization=%d emphasis=%d mute_bit=%d\n", 
				       audio->pcm.audio_frm_num, 
				       audio->pcm.num_of_audio_ch, 
				       audio->pcm.Fs, 
				       audio->pcm.quantization, 
				       audio->pcm.emphasis, 
				       audio->pcm.mute_bit);
}

void DecoderReadAuxFifo(struct cvdv_cards *card) 
{
	int i = 0;
	u8 data;
	int layer;

	struct StreamInfo *stream = &card->stream;
//      printk(KERN_DEBUG LOGNAME ": AUX - ");
//      printk("%03X ", card->AuxFifo[card->AuxFifoTail]);
        while (card->AuxFifoHead != card->AuxFifoTail) {
		
		layer = (card->AuxFifo[card->AuxFifoTail] >> 8) & 0x07;
		data = card->AuxFifo[card->AuxFifoTail] & 0xFF;
		card->AuxFifoTail = (card->AuxFifoTail + 1) & FIFO_MASK;
		if (layer != card->AuxFifoLayer) {  // start of a new layer?
			i = 0;
			card->AuxFifoLayer = layer;
		} else i++;
		switch (layer) {  // layer code
		case 0:  // sequence header
			if (! stream->sh.valid) switch (i) {
			case 0: 
				stream->sh.hsize = data & 0x0F; 
				break;
			case 1: 
				stream->sh.hsize = (stream->sh.hsize << 8)
					| data; 
				stream->hsize =	stream->sh.hsize; 
				break;
			case 2: 
				stream->sh.vsize = data & 0x0F; 
				break;
			case 3: 
				stream->sh.vsize = (stream->sh.vsize << 8) | 
					data; 
				stream->vsize = stream->sh.vsize; 
				break;
			case 4: 
				stream->sh.aspectratio = data & 0x0F; 
				break;
			case 5: 
				stream->sh.frameratecode = data & 0x0F; 
				break;
			case 6: 
				stream->sh.bitrate = data & 0x03; 
				break;
			case 7: 
				stream->sh.bitrate = (stream->sh.bitrate << 8)
					| data; 
				break;
			case 8: 
				stream->sh.bitrate = (stream->sh.bitrate << 8)
					| data; 
				stream->bitrate = stream->sh.bitrate; 
				break;
			case 9: 
				stream->sh.vbvbuffersize = data & 0x03; 
				break;
			case 10: 
				stream->sh.vbvbuffersize = 
					(stream->sh.vbvbuffersize << 8) | 
					data; 
				stream->vbvbuffersize = 
					stream->sh.vbvbuffersize; 
				break;
			case 11: 
				stream->sh.constrained = data & 0x01; 
				stream->sh.valid = 1;
				printk(KERN_DEBUG LOGNAME ": AUX - MPEG1 - %dx%d %s %s fps, %d bps, %d kByte vbv%s\n", stream->sh.hsize, stream->sh.vsize, 
				       ((stream->sh.aspectratio == 1) ? "1:1" : 
					((stream->sh.aspectratio == 2) ? "3:4" : 
					 ((stream->sh.aspectratio == 3) ? "9:16" : 
					  ((stream->sh.aspectratio == 4) ? "1:2.21" : 
					   "?:?")))), 
				       ((stream->sh.frameratecode == 1) ? "23.976" : 
					((stream->sh.frameratecode == 2) ? "24" : 
					 ((stream->sh.frameratecode == 3) ? "25" : 
					  ((stream->sh.frameratecode == 4) ? "29.97" : 
					   ((stream->sh.frameratecode == 5) ? "30" : 
					    ((stream->sh.frameratecode == 6) ? "50" : 
					     ((stream->sh.frameratecode == 7) ? "59.94" : 
					      ((stream->sh.frameratecode == 8) ? "60" : 
					       "?")))))))), 
				       stream->sh.bitrate * 400, 
				       stream->sh.vbvbuffersize * 16, 
				       ((stream->sh.constrained) ? ", constrained" : "")
					);
				break;
			}
			break;
		case 1:  // group of pictures
			if (! stream->gop.valid) 
				switch (i) {
				case 0: 
					stream->gop.timecode = data & 0x01; 
					break;
				case 1: 
					stream->gop.timecode = 
						(stream->gop.timecode << 8) | 
						data; 
					break;
				case 2: 
					stream->gop.timecode = 
						(stream->gop.timecode << 8) | 
						data; 
					break;
				case 3: 
					stream->gop.timecode = 
						(stream->gop.timecode << 8) | 
						data; 
					break;
				case 4: 
					stream->gop.closedgop = data & 0x01; 
					break;
				case 5: 
					stream->gop.brokenlink = data & 0x01;
					stream->gop.valid = 1;
					break;
				}
			break;
		case 2:  // picture
			if (0) 
				switch (i) {
				case 0: 
					break;
				}
			break;
		case 7:  // extension layer
			if (i == 0) card->AuxFifoExt = data;
			else 
				switch (card->AuxFifoExt) {  // extension code
				case 1:  // sequence extension
					if ((stream->sh.valid) && 
					    (! stream->se.valid))
						switch (i) {
						case 1: 
							stream->se.profilelevel
								= data; 
							break;
						case 2: 
							stream->se.progressive
								= data & 0x01; 
							break;
						case 3: 
							stream->se.chroma = 
								(data >> 4) & 
								0x03; 
							stream->se.hsizeext = 
								(data >> 2) & 
								0x03;
							stream->se.vsizeext = 
								data & 0x03;
							stream->hsize |= 
								(stream->se.hsizeext << 12);
							stream->vsize |= 
								(stream->se.vsizeext << 12);
							break;
						case 4: 
							stream->se.bitrateext =
								data & 0x0F; 
							break;
						case 5: 
							stream->se.bitrateext =
								(stream->se.bitrateext << 8) | data; 
							stream->bitrate |= 
								(stream->se.bitrateext << 18); 
							break;
						case 6: 
							stream->se.vbvbuffersizeext = data; 
							stream->vbvbuffersize |= (stream->se.vbvbuffersizeext << 10); 
							break;
						case 7:
							stream->se.lowdelay =
								(data >> 7) & 
								0x01;
							stream->se.frextn = 
								(data >> 5) & 
								0x03;
							stream->se.frextd = 
								data & 0x1F;
							stream->se.valid = 1;
							stream->MPEG2 = 1;
							printk(KERN_DEBUG LOGNAME ": AUX - MPEG2 - %dx%d %s %s*%d/%d fps, %d bps, %d kByte vbv%s%s\n", stream->hsize, stream->vsize, 
							       ((stream->sh.aspectratio == 1) ? "1:1" : 
								((stream->sh.aspectratio == 2) ? "3:4" : 
								 ((stream->sh.aspectratio == 3) ? "9:16" : 
								  ((stream->sh.aspectratio == 4) ? "1:2.21" : 
								   "?:?")))), 
							       ((stream->sh.frameratecode == 1) ? "23.976" : 
								((stream->sh.frameratecode == 2) ? "24" : 
								 ((stream->sh.frameratecode == 3) ? "25" : 
								  ((stream->sh.frameratecode == 4) ? "29.97" : 
								   ((stream->sh.frameratecode == 5) ? "30" : 
								    ((stream->sh.frameratecode == 6) ? "50" : 
								     ((stream->sh.frameratecode == 7) ? "59.94" : 
								      ((stream->sh.frameratecode == 8) ? "60" : 
								       "?")))))))), 
							       stream->se.frextn + 1, 
							       stream->se.frextd + 1, 
							       stream->bitrate * 400, 
							       stream->vbvbuffersize * 16, 
							       ((stream->sh.constrained) ? ", constrained" : ""), 
							       ((stream->se.lowdelay) ? ", low delay" : "")
								);
							break;
						}
					break;
				case 2:  // sequence display extension
					if (0)
						switch (i) {
						case 0: 
							break;
						}
					break;
				case 3:  // quant matrix extension
					if (0) 
						switch (i) {
						case 0: 
							break;
						}
					break;
				case 4:  // copyright  extension
					if (0) 
						switch (i) {
						case 0: 
							break;
						}
					break;
				case 7:  // picture display extension
					if (0) switch (i) {
					case 0: 
						break;
					}
					break;
				case 8:  // picture coding extension
					if (0) 
						switch (i) {
						case 0: 
							break;
						}
					break;
				default:
					break;
				}
			break;
		default:break;
		}
		
	}  
}

void DecoderReadDataFifo(struct cvdv_cards *card) 
{
	//      printk(KERN_DEBUG LOGNAME ": DATA - ");
	while (card->DataFifoHead != card->DataFifoTail) {
//	        printk("%03X ", card->DataFifo[card->DataFifoTail]);
		card->DataFifoTail = (card->DataFifoTail + 1) & FIFO_MASK;
	}
//	printk("\n");
}

int DecoderReadNavipack(struct cvdv_cards *card) 
{
	u32 startaddr, endaddr, writeaddr;
	u8 navipack[1024];
	u16 PacketLength;
	u8 SubStreamID;
	//struct Navi navi;
	int i;
	startaddr = (DecoderReadWord(card, 0x05C) & 0x3FFF) << 7;   
        // 21 bit word address
	endaddr = (DecoderReadWord(card, 0x05E) & 0x3FFF) << 7;     
        // 21 bit word address
	writeaddr = DecoderReadByte(card, 0x075) & 0xFF;
	writeaddr |= (DecoderReadWord(card, 0x077) & 0x0FFF) << 8;
	//writeaddr <<= 3;
//printk(KERN_DEBUG LOGNAME ": -- DecoderReadNavipack 0x%08X-0x%08X, ->0x%08X <-0x%08X\n", startaddr, endaddr, writeaddr, card->NaviPackAddress);
	
	if (DecoderReadByte(card, 0x07B) & 0xC0) {  // navi pack available?
		DRAMReadByte(card, card->NaviPackAddress, 1024, navipack, 0);
		card->reg07B |= 0x20;  // decrement navi counter
		DecoderWriteByte(card, 0x07B, card->reg07B);
		card->reg07B &= ~0x20;
		//DecoderSetByte(card, 0x07B, 0x20);  // decrement navi counter
		card->NaviPackAddress += 512;       // increment in words
		if (card->NaviPackAddress >= endaddr) 
			card->NaviPackAddress = startaddr;
//printk(KERN_DEBUG LOGNAME ": Navipack %02X %02X %02X %02X  %02X %02X %02X %02X\n", 
//  navipack[0], navipack[1], navipack[2], navipack[3], navipack[4], navipack[5], navipack[6], navipack[7]);
		if ((!navipack[0]) && (!navipack[1]) && (navipack[2] == 1) && (navipack[3] == 0xBF)) {
			PacketLength = (navipack[4] << 8) | navipack[5];
			SubStreamID = navipack[6];
//printk(KERN_DEBUG LOGNAME ": Navipack Len=%d, ID=%d\n", PacketLength, SubStreamID);
			i = 7;  // start of payload data in navipack[]
			switch (SubStreamID) {
			case 0:  // Presentation Control Information (PCI)
				if (PacketLength < 980) return 1;  // Packet too small
				DecoderQueueNavi(card, navipack);
				break;
			case 1:  // Data Search Information (DSI)
				if (PacketLength < 1018) return 1;  // Packet too small
				DecoderQueueNavi(card, navipack);
				break;
			default:
				break;
			}
//    } else {
//      printk(KERN_DEBUG LOGNAME ": navi pack format error: %02X %02X %02X %02X %02X %02X %02X %02X.\n", 
//        navipack[0], navipack[1], navipack[2], navipack[3], navipack[4], navipack[5], navipack[6], navipack[7]);
		}
//  } else {
//    printk(KERN_DEBUG LOGNAME ": no navi pack avail.\n");
	}
	return 0;
}

int AudioStart(struct cvdv_cards *card) 
{
	DecoderReadAudioInfo(card);  // detect audio type
	if (card->stream.audio.valid) {
		printk(KERN_DEBUG LOGNAME ": Audio Init in delayed decoder start\n");
		if (card->AudioInitialized) AudioClose(card);
		switch (card->setup.audioselect) {
		case audio_MPEG:  // MPEG Audio
		case audio_MPEG_EXT:  // MPEG Audio with ext.
			printk(KERN_DEBUG LOGNAME ": Using MPEG Audio\n");
			AudioInit(card, card->stream.audio.mpeg.samplefreq, 0);
			if (card->stream.audio.mpeg.mode == 3) AudioDualMono(card, 2);  // left channel only
			else AudioDualMono(card, 0);
			break;
		case audio_DTS:
		case audio_LPCM:  // Linear Pulse Code Modulation LPCM
			printk(KERN_DEBUG LOGNAME ": Using LPCM Audio\n");
			AudioInit(card, 48, 0);  // or 96
			break;
		case audio_AC3:  // AC-3
			printk(KERN_DEBUG LOGNAME ": Using AC-3 Audio\n");
			switch (card->stream.audio.ac3.fscod) {
			case 0:AudioInit(card, 48, 0); break;
			case 1:AudioInit(card, 44, 0); break;
			case 2:AudioInit(card, 32, 0); break;
			}
			break;
		case audio_none:
		case audio_disable:
		case audio_SDDS:
		}
	} else return 1;
	return 0;
}

// Slow mode: displays every field <slowfactor> times
// slowfactor=0 disables this mode.
void VideoSlow(struct cvdv_cards *card, int slowfactor) 
{
	if (!slowfactor && card->slowdown) DecoderWriteByte(card, 0x0ED, 0x00);  // run
	card->lastslow = 0;
	card->slowdown = slowfactor;
}

// Puts decoder in pause after so many fields
void StepsToPause(struct cvdv_cards *card, int steps) 
{
	card->videosteps = steps;
}

u32 DecoderReadSCR(struct cvdv_cards *card, u16 address)
{
	u32 SCR;
	SCR = DecoderReadByte(card, address);
	SCR |= ((u32)DecoderReadByte(card, address+1) << 8);
	SCR |= ((u32)DecoderReadByte(card, address+2) << 16);
	SCR |= ((u32)DecoderReadByte(card, address+3) << 24);
	return SCR;
}

u32 DecoderReadRWAddr(struct cvdv_cards *card, u16 address)
{
	u32 addr;
	addr = DecoderReadByte(card, address) & 0xFF;
	addr |= (((u32)DecoderReadByte(card, address+1) & 0xFF) << 8);
	addr |= (((u32)DecoderReadByte(card, address+2) & 0x0F) << 16);
	return addr;
}

int PTSGetFirstPTS(PTSStorage *store, u32 *PTS)
{
	if ( store->end == store->begin ) {
		return 0;
	} else {
		*PTS = store->PTS[store->begin];
		return 1;
	}
}

void PTSStoreAdd(PTSStorage *store, u32 PTS, u32 AddrB, u32 AddrE)
{
	int new;

//printk(KERN_DEBUG LOGNAME ": PTSStoreAdd - store in [%d] %08X - %08X\n", store->end, AddrB, AddrE);

 // cheap fix: don't store if address rollover
	if ((AddrB & 0x00080000) != (AddrE & 0x00080000)) return;

	new = store->end;

	store->end++;
	if (store->end >= store->size) store->end = 0;
	if (store->end == store->begin) {
		store->begin++;
		if (store->begin >= store->size) store->begin = 0;
	}

	store->AddrB[new] = AddrB;
	store->AddrE[new] = AddrE;
	store->PTS[new] = PTS;
}

int PTSGetPTS (PTSStorage *store, u32 Addr, u32 *PTS )
{
	u32 AddrB;
	u32 AddrE;
	int i;
	int found;
	int search;

//printk(KERN_DEBUG LOGNAME ": PTSGetPTS - search %08X\n", Addr);

	if (store->end == store->begin) {
		store->LastAddr = Addr;
		return 0;
	}

	// Search for the PTS in the array
	found = 0;
	search = 1;
	while (search && !found) {
	 // Get the first value
		i = store->begin;
		AddrB = store->AddrB[i];
		AddrE = store->AddrE[i];

//printk(KERN_DEBUG LOGNAME ": PTSGetPTS - search in [%d] %08X - %08X\n", i, AddrB, AddrE);

	 //If in range, keep it
		if ((Addr >= AddrB) && (Addr <= AddrE)) {
			*PTS = store->PTS[i];
			found = 1;
		} else {
			if ((Addr & 0x00080000) == (AddrB & 0x00080000)) {
				if (Addr < AddrB ) search = 0;
			} else {
				if ((store->LastAddr & 0x00080000) == (Addr & 0x00080000)) search = 0;
			}
		}
		if (search) {
			store->begin++;
			if (store->begin >= store->size) store->begin = 0;
			if (store->end == store->begin ) search = 0;
		}
	}
	store->LastAddr = Addr;
	return found;
}


u32 GetPTS(u8 *data, u32* MediaPointer, int mpeg, int hlength,int off)
{
	u32 PTS = 0xFFFFFFFFUL;
	int p = 0;
	
	// Read PTS, if present
	if ((mpeg == 2 && data[p + 7] & 0x80) ||
	    (mpeg == 1 && off)) {
		if (mpeg == 1) p = off-9;
		PTS = (data[p + 9] >> 1) & 0x03UL;
		PTS = (PTS << 8) | (data[p + 10] & 0xFFUL);
		PTS = (PTS << 7) | ((data[p + 11] >> 1) & 0x7FUL);
		PTS = (PTS << 8) | (data[p + 12] & 0xFFULL);
		PTS = (PTS << 7) | ((data[p + 13] >> 1) & 0x7FUL);
	}
	// Now, skip rest of PES header and stuffing
	if (mpeg == 2){
		p += (9 + (data[p + 8] & 0xFF));
		p = ((p + 7) / 8) * 8;
	} else p = hlength+7;
	if (!(data[p++] | data[p++] | data[p++] | data[p++])) {
		*MediaPointer = (u32)data[p++] & 0xFF;
		*MediaPointer = (*MediaPointer << 8) | ((u32)data[p++] & 0xFF);
		*MediaPointer = (*MediaPointer << 8) | ((u32)data[p++] & 0xFF);
		*MediaPointer = (*MediaPointer << 8) | ((u32)data[p++] & 0xFF);
	} else {
		*MediaPointer = 0xFFFFFFFFUL;
	}
	return PTS;
}

int ReadPESChunk(struct cvdv_cards *card, u32 *addr, u8 *data, u32 start, u32 end)
{
	int i = 5, err = -1;
	while (err && (i--)) err &= DRAMReadByte(card, *addr << 2, 8, &data[0], 0);
	if (err) return 1;
	(*addr)++;
	if (*addr >= end) *addr = start;
	return 0;
}

void ReadPESHeaders(struct cvdv_cards *card)
{
	u8 startcode[] = {0x00, 0x00, 0x01};
	int LoopCount;
	u32 LastVAddr; // Current Video Address
	u32 LastAAddr; // Current Audio Address
	u32 Addr;      // Current Header Address
	u32 PESAddr;   // Pointer from Header Block
	u32 PTS;       // PTS from Header Block
	u8 Data[32];
	u32 AudioPESStart;
	u32 AudioPESEnd;
	int i, j, p, fail;
	u32 FailAddr;
	int hlength=0;
	int mpeg=0;
	int check;
	int mp=0;
	int off=0;
	
	AudioPESStart = (DecoderReadWord(card, 0x058) & 0x3FFF) << 5;
	AudioPESEnd = ((DecoderReadWord(card, 0x05A) & 0x3FFF) + 1) << 5;

	LastVAddr = DecoderReadRWAddr(card, 0x060);
	LastAAddr = DecoderReadRWAddr(card, 0x063);
	
	if (card->LastAddr == 0) card->LastAddr = AudioPESStart;

//card->AudioPES .. (((DecoderReadWord(card,0x05A) & 0x3FFF) + 1) << 5)

	//Read the PES header buffer
	Addr  = DecoderReadRWAddr(card, 0x072) & 0x0007FFFF;
	if (Addr >= AudioPESEnd) {
		Addr = card->LastAddr = AudioPESStart;
	}

	LoopCount = 0;
	while ((card->LastAddr != Addr) && (LoopCount++ < 200)) {
//printk(KERN_DEBUG LOGNAME ": Read PES header: round %d 0x%08X -> 0x%08X\n", LoopCount, card->LastAddr, Addr);
		FailAddr = card->LastAddr;
		fail = 0;
		p = 0;

		if (ReadPESChunk(card, &card->LastAddr, &Data[p], AudioPESStart, AudioPESEnd)) continue;
		p+=8;
		j=1;
		

//printk(KERN_DEBUG LOGNAME ":  PES header: %02X %02X %02X %02X %02X %02X %02X %02X\n", Data[0],Data[1],Data[2],Data[3],Data[4],Data[5],Data[6],Data[7]);
		if (memcmp(Data, startcode, 3)) continue;
 		if ((Data[3] == 0xE0) || (Data[3] == 0xBD) 
		    || ((Data[3] & 0xE0) == 0xC0)) {
		  
			fail |= ReadPESChunk(card, &card->LastAddr, 
					     &Data[p], AudioPESStart, 
					     AudioPESEnd);


			p+=8;
			j++;
			if ( (Data[6] & 0xC0) == 0x80 ){
				hlength = 9+Data[8];
				mpeg = 2;
			} else {
				mpeg = 1;
				mp = 6;
				check = Data[mp];
				mp++;
				while (check == 0xFF){
					if (!fail && mp == p) {
						fail |= ReadPESChunk(
							card, 
							&card->LastAddr, 
							&Data[p], 
							AudioPESStart, 
							AudioPESEnd);
						p+=8;
						j++;
					}
					check = Data[mp];
					mp++;
				}
				if (!fail && mp == p) {
					fail |= ReadPESChunk(
						card, 
						&card->LastAddr, 
						&Data[p], 
						AudioPESStart, 
						AudioPESEnd);
					p+=8;
					j++;
				}
				
				if ( !fail && (check & 0xC0) == 0x40){
					check = Data[mp];
					mp++;
					if (!fail && mp == p) {
						fail |= ReadPESChunk(
							card, 
							&card->LastAddr, 
							&Data[p], 
							AudioPESStart, 
							AudioPESEnd);
					  p+=8;
					  j++;
					}
					check = Data[mp];
					mp++;
				}
				if ( !fail && (check & 0x20)){
					if (check & 0x30) hlength = mp+10;
					else hlength = mp+5;
					off = mp-1;
				}
       //printk(KERN_DEBUG LOGNAME ":  PTS: %02X %02X %02X %02X %02X\n", Data[off],Data[off+1],Data[off+2],Data[off+3],Data[off+4]);
				
				
			}

			for (i = 1; (i < ((hlength+7) / 8)) && (!fail);
			     i++) {
				fail |= ReadPESChunk(card, &card->LastAddr, &Data[p], AudioPESStart, AudioPESEnd);
				p+=8;
				j++;
			}

//printk(KERN_DEBUG LOGNAME ":  PES header: %d chunks read, HL = %d\n", j, Data[8]);
			if (!fail) {
				PTS = GetPTS(Data, &PESAddr, 
					     mpeg, hlength,off);
//printk(KERN_DEBUG LOGNAME ":   PTS from PES header: %d @ 0x%08X\n", PTS, PESAddr);
				if ((PTS != 0xFFFFFFFF) && (PESAddr != 0xFFFFFFFF)) {
			 		if (Data[3] == 0xE0) {  // Video
//printk(KERN_DEBUG LOGNAME ":   Video PTS from PES header: %d @ 0x%08X - 0x%08X\n", PTS, PESAddr, LastVAddr);
						PTSStoreAdd(&card->VideoPTSStore, PTS, PESAddr, LastVAddr);
					} else {  // Audio
//printk(KERN_DEBUG LOGNAME ":   Audio PTS from PES header: %d @ 0x%08X - 0x%08X\n", PTS, PESAddr, LastAAddr);
						PTSStoreAdd(&card->AudioPTSStore, PTS, PESAddr, LastAAddr);
					}
				}
			}
		} else {
			//card->LastAddr = Addr;
		}
		// In case of error, rewind and try again
		if (fail) card->LastAddr = FailAddr; 
		}
}

void L64021Intr(struct cvdv_cards *card) 
{
//static void L64021Intr(struct cvdv_cards *card) {
//  struct cvdv_cards *card=dev_id;
	u32 SCR_base, SCR_compareV, SCR_compareA;
	u32 VideoAddr, AudioAddr, PTS;
	int i, a, v, as, vs, ap, vp;
//  int err, h;
	u8 intr[5];
	u8 layer;
	//u8 oldlayer = 0;
	long ISRTime, DeltaSyncTime, Offset;
	
	int used = 0;
	u8 err;

	err = DecoderReadByte(card, 0x095);
	if (err & 0x17) {
		printk(KERN_DEBUG LOGNAME ": Packet Error: 0x%02X\n", err);
	}

	ISRTime = 0;  // TODO system time
  
	for (i = 0; i < 5; i++) 
		if ((intr[i] = DecoderReadByte(card, i))) used = 1;
	if (used) {
//printk(KERN_DEBUG LOGNAME ": Int - L64021: %02X %02X %02X %02X %02X\n", intr[0], intr[1], intr[2], intr[3], intr[4]);
//printk(KERN_DEBUG LOGNAME ": Int - L64021 Aux/Data Fifo: %02X %02X\n", 
//  DecoderReadByte(card, 0x040), 
//  DecoderReadByte(card, 0x041));
//printk(KERN_DEBUG LOGNAME ": Int - L64021 VideoES w/r addr: %08X %08X\n", 
//  (DecoderReadByte(card, 0x060) | (DecoderReadByte(card, 0x061) << 8) | (DecoderReadByte(card, 0x062) << 16)) << 2, 
//  (DecoderReadByte(card, 0x06C) | (DecoderReadByte(card, 0x06D) << 8) | (DecoderReadByte(card, 0x06E) << 16)) << 2);


//if (DecoderReadByte(card, 0x005) & 0x04) DecoderDelByte(card, 0x005, 0x04);
//if (DecoderReadByte(card, 0x005) & 0x04) DecoderWriteByte(card, 0x005, 0x03);
//DecoderMaskByte(card, 0x007, 0x0C, 1 << 2);  // Stream Select: MPEG1 System / MPEG2 Program Stream
//DecoderWriteByte(card, 0x005, 0x03);
//DecoderWriteByte(card, 0x007, 0xC7);
//printk(KERN_DEBUG LOGNAME ": Int - L64021 Channel Status: %02X %02X\n", 
//  DecoderReadByte(card, 0x007), 
//  DecoderReadByte(card, 0x005));


		if (intr[0] & 0x80) {  // new field
			card->fields++;
			
			if (card->slowdown > 0) {
				if (card->lastslow == 0) {
					DecoderWriteByte(card, 0x0ED, 0x03);  // repeat frame
					card->lastslow++;
				} else if (card->lastslow == card->slowdown) {
					DecoderWriteByte(card, 0x0ED, 0x00);  // run
				} else card->lastslow++;
			}
			
			if (card->videosteps > 0) {
				card->videosteps--;
				if (!card->videosteps) DecoderPause(card);
			}

			if (card->videodelay > 0) {
//printk(KERN_DEBUG LOGNAME ": Video delay %d\n", card->videodelay);
				if( (DecoderReadByte(card, 0x0ED) & 0x01) == 0x00)	{
					card->videodelay--;
					if(card->videodelay){
						DecoderWriteByte(card, 0x0ED, 0x01);
					} else {
						DecoderWriteByte(card, 0x0ED, 0x00);
					}
				}
			} else if (card->videorip > 0) {
//printk(KERN_DEBUG LOGNAME ": Video rip %d\n", card->videorip);
				if ((DecoderReadByte(card, 0x0EC) & 0x03) == 0x00) {
					if (DecoderReadWord(card, 0x096) > 5) {  // pictures in video ES channel
						card->videorip--;
						if(card->videorip) {
							DecoderWriteByte(card, 0x0EC, 0x01);
						} else {
							DecoderWriteByte(card, 0x0EC, 0x00);
						}
					} else {
						card->videorip = 0;
						DecoderWriteByte (card, 0x0EC, 0x00);
					}
				}
			}


			i = (DecoderReadByte(card, 0x113) & 0xFC) | (DecoderReadByte(card, 0x114) & 0x01);
			v = DecoderGetVideoESLevel(card);
			if (card->startingV) {
				vs = card->VideoESSize;
				if (vs > 0) vp = (100 * v) / vs;
				else vp = 0;
				if (vp > 60) {
printk(KERN_DEBUG LOGNAME ": Delayed Video Decoder start\n");
					card->startingV = 0;
					DecoderStartDecode(card);
//DecoderWriteByte(card, 0x0EC, 0x05);  // Skip B Frames
//DecoderWriteByte(card, 0x0EC, 0x06);  // Skip B and P Frames
//DecoderWriteByte(card, 0x0EE, 0x03);  // Rip forward mode
//DecoderWriteByte(card, 0x0ED, 0x03);  // Repeat frame mode
//          DecoderSetVideoPanic(card, 1, 3);  // video panic at 3 pictures
					//DecoderSetVideoPanic(card, 0, DecoderGetVideoESSize(card) / 4);  // video panic at 25 percent
					//VideoSetBackground(card, 0, 0, 0, 0);      // Video on black
				}
			}
			a = DecoderGetAudioESLevel(card);
			if (card->startingA) {
				as = card->AudioESSize;
				if (as > 0) ap = (100 * a) / as;
				else ap = 0;
				if (ap > 60) {
printk(KERN_DEBUG LOGNAME ": Delayed Audio Decoder start\n");
					AudioSetPlayMode(card, AUDIO_PLAY);
					if (!AudioStart(card)) {
						card->startingA = 0;
					}
				}
			}
			if (card->fields >= 250) {  // 5 seconds (PAL)
				//SCR_base = DecoderReadByte(card, 0x09);
				//SCR_base = SCR_base | (DecoderReadMWord(card, 0x0A) << 8);
				SCR_base = DecoderReadSCR(card, 0x009);
				SCR_compareA = DecoderReadSCR(card, 0x014);
				SCR_compareV = DecoderReadSCR(card, 0x00D);
				if (DecoderReadByte(card, 0x013) & 0x03)
//					printk(KERN_DEBUG LOGNAME ": SCR 0x%08X, videocmp=0x%08X, audiocmp=0x%08X %02X\n", SCR_base, SCR_compareV, SCR_compareA, DecoderReadByte(card, 0x013));
				//if (DecoderReadByte(card, 0x013) & 0x03)
					//printk(KERN_DEBUG LOGNAME ": SCR 0x%08X, videocmp=0x%08X, audiocmp=0x%08X %02X\n", SCR_base, DecoderReadDWord(card, 0x00D), DecoderReadDWord(card, 0x014), DecoderReadByte(card, 0x013));
				card->fields = 0;
			}
		}

		if (intr[0] & 0x04) {  // First Slice Start Code
//printk(KERN_DEBUG LOGNAME ": Int - First Slice Start Code\n");
			if (card->showvideo) {
				// Unmute card video if first picture slice detected
				VideoSetBackground(card, 0, 0, 0, 0);      // Video on black
				card->showvideo = 0;
			}
		}
		
		if (intr[0] & 0x02 ) {  // Aux/User Data Fifo
//		  printk(KERN_DEBUG LOGNAME ": Int - Aux/Data FIFO Ready\n");
			used = 0;
			while ( (used++ < 1000) && 
				(layer = DecoderReadByte(card, 0x040)) & 0x03){
				card->AuxFifo[card->AuxFifoHead] = ((layer << 6) & 0x0700) | DecoderReadByte(card, 0x043);
				card->AuxFifoHead = (card->AuxFifoHead + 1) & FIFO_MASK;
			}
			if (used < 1000) DecoderReadAuxFifo(card);
			used = 0;

			while ( (used++ < 1000) && 
				(layer = DecoderReadByte(card, 0x041)) & 0x03){
				card->DataFifo[card->DataFifoHead] = ((layer << 6) & 0x0300) | DecoderReadByte(card, 0x043);
				card->DataFifoHead = (card->DataFifoHead + 1) & FIFO_MASK;
			}
			if (used < 1000 ) DecoderReadDataFifo(card);
		}

		if ((intr[0] & 0x01) != card->intdecodestatus) {  // decode status
			card->intdecodestatus = intr[0] & 0x01;
printk(KERN_DEBUG LOGNAME ": Int - decode status now %s\n", ((card->intdecodestatus) ? "running" : "stopped"));
			if (card->intdecodestatus) {  // now running
//        DecoderSetVideoPanic(card, 1, 3);  // video panic at 3 pictures
				DecoderSetVideoPanic(card, 0, card->VideoESSize / 4);  
			card->showvideo = 1;
				//VideoSetBackground(card, 0, 0, 0, 0);      // Video on black
			} else {  // now stopped
				if (card->closing) {
					card->closing = 0;
					CloseCard(card);
				} 
			}
		 
		}

//		if (intr[1] & 0x80) {  // SCR compare
//printk(KERN_DEBUG LOGNAME ": Int - SCR compare\n");
			//DecoderDelByte(card, 0x013, 0x02);
			//VideoSetBackground(card, 0, 0, 0, 0);      // Video on black
//		}
//		if (intr[1] & 0x40) {  // SCR Overflow
//printk(KERN_DEBUG LOGNAME ": Int - SCR Overflow\n");
//		}
//    if (intr[1] & 0x20) {  // Begin Vertical Blank
//    }
		if (intr[1] & 0x10) {  // Begin Active Video
			if (card->highlight_valid) {
				for (i = 0; i < 10; i++) DecoderWriteByte(card, 0x1C0 + i, card->highlight[i]);
				card->highlight_valid = 0;
			}
		}
		//if (intr[1] & 0x08) {  // SPU Start Code Detected
	   //printk(KERN_DEBUG LOGNAME ": Int - SPU Start Code Detected\n");
		//}
		if (intr[1] & 0x04) {  // SCR compare audio
printk(KERN_DEBUG LOGNAME ": Int - SCR compare audio\n");
			DecoderDelByte(card, 0x013, 0x01);
			AudioStart(card);
		}
		// both follwing are used in A/V-sync below
//		if (intr[1] & 0x02) {  // picture start code detected
//printk(KERN_DEBUG LOGNAME ": Int - picture start code detected\n");
//		}
//		if (intr[1] & 0x01) {  // audio sync code detected
//printk(KERN_DEBUG LOGNAME ": Int - audio sync code detected\n");
//		}

    //      if (! card->stream.audio.valid) DecoderReadAudioInfo(card);

		if (intr[2] & 0x20) {  // DSI PES data ready
//printk(KERN_DEBUG LOGNAME ": Int - DSI PES data ready\n");
			DecoderReadNavipack(card);
		}

		if (intr[2] & 0x06) {  // Audio / Video PES data ready
		  ReadPESHeaders(card);
		}

		if (intr[3] & 0x40) {  // CSS
			card->css.status = DecoderReadByte(card, 0x0B0);
printk(KERN_DEBUG LOGNAME ": Int - CSS Status 0x%02X\n", card->css.status);
			if (card->css.status&0x01) card->css.ChallengeReady = 1;  // challenge ready
			if (card->css.status&0x02) card->css.ResponseReady = 1;   // response ready
			if (card->css.status&0x04) card->css.DiskKey = 1;         // Disk key ready
			if (card->css.status&0x08) card->css.Error = 1;           // Disk key error
			if (card->css.status&0x10) card->css.TitleKey = 1;        // Title key ready
			if (card->css.status&0x20) card->css.TitleKeyDiff = 1;    // Title key error
		}


		if (intr[3] & 0x30) {  // Audio/Video ES channel buffer underflow
//printk(KERN_DEBUG LOGNAME ": Int - ES channel buffer underflow\n");
			if (card->closing) {
				card->closing = 0;
				CloseCard(card);
			}
		}

//    if (intr[3] & 0x08) {  // Data Dump channel PES data ready
//    }

		if (intr[4] & 0x10 ) {  // SPU decode error
printk(KERN_DEBUG LOGNAME ": Int - SPU decode error: (1CA)=0x%02X\n", DecoderReadByte(card, 0x1CA));
			DecoderDelByte(card, 0x1A0, 0x01);  // SPU decode stop
			DecoderSetByte(card, 0x1A0, 0x01);  // SPU decode start
		}
		
		// Audio / Video Syncronisation

		if (card->videosync && !card->videorip && !card->videodelay && !card->slowdown) {
			SCR_base = DecoderReadSCR(card, 0x009);
			SCR_compareV = DecoderReadSCR(card, 0x00D);
//printk(KERN_DEBUG LOGNAME ": Sync: SCR = %08X\n", SCR_compareV);
			if (intr[1] & 0x02) {  // picture start code detected
//printk(KERN_DEBUG LOGNAME ": Sync: picture start code\n");
				DecoderMaskByte(card, 0x011, 0x03, 0x01);   // Set SCR compare/capture mode to capture
				DecoderSetByte(card, 0x11, 0x04);           // Set "capture on picture start"
				if (intr[1] & 0x01) {  // audio sync code detected
//printk(KERN_DEBUG LOGNAME ": Sync: audio sync code, too\n");
					DecoderSetByte(card, 0x11, 0x08);         // Set "capture on audio sync code"
				}
				VideoAddr = DecoderReadRWAddr(card,0x080);
				if (PTSGetPTS(&card->VideoPTSStore, VideoAddr, &PTS)) {
//printk(KERN_DEBUG LOGNAME ": Sync: video PTS found for 0x%08X = %08X\n", VideoAddr, PTS);
					card->oldVPTS = card->VPTS;
					card->VPTS = PTS;
					card->VSCR = ((long)SCR_compareV - (long)PTS) / 2;
//					card->VideoTime = ISRTime;
				}
			} else if (intr[1] & 0x01) {  // audio sync code detected
//printk(KERN_DEBUG LOGNAME ": Sync: audio sync code, only\n");
				DecoderMaskByte(card, 0x011, 0x03, 0x01);   // Set SCR compare/capture mode to capture
				DecoderSetByte(card, 0x11, 0x08);           // Set "capture on audio sync code"
				AudioAddr = DecoderReadRWAddr(card,0x083);
//printk(KERN_DEBUG LOGNAME ": Sync: audio PTS search for 0x%08X\n", AudioAddr);
				if (PTSGetPTS(&card->AudioPTSStore, AudioAddr, &PTS)) {
//printk(KERN_DEBUG LOGNAME ": Sync: audio PTS found for 0x%08X = %08X\n", AudioAddr, PTS);
					card->oldAPTS = card->APTS;
					card->APTS = PTS;
					card->ASCR = ((long)SCR_compareV - (long)PTS) / 2;
//					card->AudioTime = ISRTime;
				} else {
					card->ASCR = 0x7FFFFFFF;
				}

				if (card->VSCR != 0x7FFFFFFF) {
					if (card->ASCR != 0x7FFFFFFF) {
						DeltaSyncTime = ISRTime - card->SyncTime;
						card->SyncTime = ISRTime;
	
						// Calculate Audio and Video SCR difference
						Offset = (card->ASCR - card->VSCR - (10 * 736)) / 736;
//printk(KERN_DEBUG LOGNAME ": Sync: compare SCRs: Audio = %ld  Video = %ld  -> %ld\n", card->ASCR, card->VSCR, Offset);
	
						// if the APTS and SCR are off update SCR to keep SubPic synced
						if ((SCR_compareV > card->APTS) || ((card->APTS - SCR_compareV) > 10000)) {
							Offset = 0;
							SetSCR(card, card->APTS);
						}
	
						// if more than 3 frames away
						if ((Offset > 3) || (Offset < -3)) {
							if (Offset > 0 ) {
								card->videodelay = 0;
								if (Offset < 100) {
									if (Offset < 10) {
										card->videodelay = 1;
									} else {
										card->videodelay = Offset / 2;
										if (card->videodelay > 20) {
											card->videodelay = 20;
										}
									}
printk(KERN_DEBUG LOGNAME ": <<< Pausing  %d\n", card->videodelay);
								} else {
								}
							} else {
								card->videorip = 0;
								if (Offset > -100) {
									if (Offset < -10) {
										card->videorip = 10;
									} else {
										card->videorip = 3;
									}
printk(KERN_DEBUG LOGNAME ": >>> FForward  %d\n", card->videorip);
								}
							}
						} else {
						}
						card->VSCR = 0x7FFFFFFF;
					}
				}
			}
		}
	}
	DecoderWriteByte(card, 0x006, 0x01);  // Clear Interrupt Pin
}

// Enable the IRQ Masks
void L64021InstallIntr(struct cvdv_cards *card) {
	u8 data;
	
	data=0;
	data |= 0x80;  // new field
	data |= 0x40;  // audio sync recovery
	data |= 0x20;  // SPU SCR compare
	// data |= 0x10;  // SDRAM Transfer Done
	// data |= 0x08;  // Sequence End Code Detect
	data |= 0x04;  // First Slice Start Code
	data |= 0x02;  // Aux/User Data Fifo
	data |= 0x01;  // decode status
	DecoderWriteByte(card, 0x000, (~data) & 0xFF);

	data = 0;
	// data |= 0x80;  // SCR compare
	// data |= 0x40;  // SCR Overflow
	// data |= 0x20;  // Begin Vertical Blank
	data |= 0x10;  // Begin Active Video
	data |= 0x08;  // SPU Start Code Detected
	data |= 0x04;  // SCR compare audio
	data |= 0x02;  // picture start code detected
	data |= 0x01;  // audio sync code detected
	DecoderWriteByte(card, 0x001, (~data) & 0xFF);

	data = 0;
	// data |= 0x80;  // DTS video event
	// data |= 0x40;  // DTS audio event
	data |= 0x20;  // DSI PES data ready
	// data |= 0x10;  // Seq end code in video channel
	data |= 0x08;  // SPU PES data ready
	data |= 0x04;  // Video PES data ready
	data |= 0x02;  // Audio PES data ready
	// data |= 0x01;  // Pack data ready
	DecoderWriteByte(card, 0x002, (~data) & 0xFF);

	data = 0;
	// data |= 0x80;  // Reserved
	data |= 0x40;  // CSS
	data |= 0x20;  // Video ES channel buffer underflow
	data |= 0x10;  // Audio ES channel buffer underflow
	// data |= 0x08;  // Data Dump channel PES data ready
	data |= 0x04;  // SPU channel buffer overflow
	data |= 0x02;  // Video ES channel buffer overflow
	data |= 0x01;  // Audio ES channel buffer overflow
	DecoderWriteByte(card, 0x003, (~data) & 0xFF);

	data = 0;
//	data |= 0x80;  // S/PDIF channel buffer underflow
	// data |= 0x40;  // packet error
	// data |= 0x20;  // reserved
	data |= 0x10;  // SPU decode error
//	data |= 0x08;  // Audio Sync error
//	data |= 0x04;  // Audio CRC or illegal bit error
//	data |= 0x02;  // context error
//	data |= 0x01;  // VLC or Run length error
	DecoderWriteByte(card, 0x004, (~data) & 0xFF);
	card->IntInstalled = 1;
}

int L64021RemoveIntr(struct cvdv_cards *card) {
	// Disable the IRQ Masks
	DecoderWriteByte(card, 0x000, 0xFF);   // No ints
	DecoderWriteByte(card, 0x001, 0xFF);   // No ints
	DecoderWriteByte(card, 0x002, 0xFF);   // No ints
	DecoderWriteByte(card, 0x003, 0xFF);   // No ints
	DecoderWriteByte(card, 0x004, 0xFF);   // No ints
	card->IntInstalled = 0;
	return 0;
}

int L64021Reset(struct cvdv_cards *card) {
	L64021RemoveIntr(card);  // Stop interrupts
	// Reset
	printk(KERN_DEBUG LOGNAME ": L64021 Software reset...\n");
	//DecoderSetByte(card, 0x007, 0x20);  // reset on
	DecoderMaskByte(card, 0x007, 0xE2, 0xE2);  // reset on
	while (!(DecoderReadByte(card, 0x007) & 0x02)) ;  // wait until reset is done
	//DecoderDelByte(card, 0x007, 0x20);  // reset off
	DecoderMaskByte(card, 0x007, 0xE2, 0xC2);  // reset off
	printk(KERN_DEBUG LOGNAME ": L64021 Software reset done.\n");
	L64021RemoveIntr(card);  // Stop interrupts
	DecoderStopChannel(card);
	DecoderStopDecode(card);
	DecoderStreamReset(card);
	DecoderSetupReset(card);
	printk(KERN_INFO LOGNAME ": L64021 Rev. 0x%02X reset successfully.\n", DecoderReadByte(card, 0x0F5));
	return 0;
}

int L64021Setup(struct cvdv_cards *card) {
printk(KERN_DEBUG LOGNAME ": -- L64021Setup\n");
	DecoderWriteByte(card, 0x0C1, 0x88);  // 
	switch (card->videomode) {
		case NTSC:  // NTSC M, N. America, Taiwan, Japan
			DecoderMaskByte(card, 0x122, 0x03, 0x01);  // Television Standard: NTSC
			/* Default values:
			DecoderWriteByte(card, 0x116, 90);    // Main Reads per Line
			DecoderWriteByte(card, 0x11A, 4);     // Vline Count Init
			DecoderWriteByte(card, 0x11C, 0x13);  // Pixel State Reset Value / BT.656 Mode / Sync Active Low
			DecoderWriteByte(card, 0x129, 23);    // Start- and End Row
			DecoderWriteByte(card, 0x12A, 262 & 0xFF);
			DecoderWriteByte(card, 0x12B, (262>>4)&0x70);
			DecoderWriteByte(card, 0x12C, 244 & 0xFF);    // Start- and End Column
			DecoderWriteByte(card, 0x12D, 1683 & 0xFF);
			DecoderWriteByte(card, 0x12E, ((1683>>4)&0x70)|((244>>8)&0x07));
			DecoderWriteByte(card, 0x132, 240 & 0xFF);    // SAV Column
			DecoderWriteByte(card, 0x133, 1684 & 0xFF);   // EAV Column
			DecoderWriteByte(card, 0x134, ((1684>>4)&0x70)|((240>>8)&0x07));
			DecoderWriteByte(card, 0x12F, (21&0x1F)|((262>>3)&0x20)|(1<<6)|((265>>1)&0x80));  // VCode Zero...
			DecoderWriteByte(card, 0x130, 262&0xFF);      // ... and VCode Even
			DecoderWriteByte(card, 0x131, 265&0xFF);      // ... and FCode
			*/
			break;
		case PAL:  // PAL-B, D, G, H, I, Europe, Asia
			DecoderMaskByte(card, 0x122, 0x03, 0x02);  // Television Standard: PAL
			/* Default values:
			DecoderWriteByte(card, 0x116, 90);    // Main Reads per Line
			DecoderWriteByte(card, 0x11A, 1);     // Vline Count Init
			DecoderWriteByte(card, 0x11C, 0x13);  // Pixel State Reset Value / BT.656 Mode / Sync Active Low
			DecoderWriteByte(card, 0x129, 23);    // Start- and End Row
			DecoderWriteByte(card, 0x12A, 310 & 0xFF);
			DecoderWriteByte(card, 0x12B, (310>>4)&0x70);
			DecoderWriteByte(card, 0x12C, 264 & 0xFF);    // Start- and End Column
			DecoderWriteByte(card, 0x12D, 1703 & 0xFF);
			DecoderWriteByte(card, 0x12E, ((1703>>4)&0x70)|((264>>8)&0x07));
			DecoderWriteByte(card, 0x132, 260 & 0xFF);    // SAV Column
			DecoderWriteByte(card, 0x133, 1704 & 0xFF);   // EAV Column
			DecoderWriteByte(card, 0x134, ((1704>>4)&0x70)|((260>>8)&0x07));
			DecoderWriteByte(card, 0x12F, (21&0x1F)|((310>>3)&0x20)|(0<<6)|((312>>1)&0x80));  // VCode Zero...
			DecoderWriteByte(card, 0x130, 310&0xFF);      // ... and VCode Even
			DecoderWriteByte(card, 0x131, 312&0xFF);      // ... and FCode
			*/
			break;
		case PAL60:  // PAL 60Hz
		case NTSC60:  // NTSC 60Hz, USA HDTV
		case PALM:  // PAL-M normal, Brazil
		case PALM60:  // PAL-M HDTV, Brazil
		case PALN:  // PAL-N, Uruguay, Paraguay
		case PALNc:  // PAL-Nc, Argentinia
		default:  // TODO: set mode according to other standards
			DecoderMaskByte(card, 0x122, 0x03, 0x00);  // Television Standard: User programmed
			DecoderWriteByte(card, 0x116, 90);    // Main Reads per Line
			DecoderWriteByte(card, 0x11A, 1);     // Vline Count Init
			DecoderWriteByte(card, 0x11C, 0x13);  // Pixel State Reset Value / BT.656 Mode / Sync Active Low
			DecoderWriteByte(card, 0x129, 23);    // Start- and End Row
			DecoderWriteByte(card, 0x12A, 310 & 0xFF);
			DecoderWriteByte(card, 0x12B, (310>>4)&0x70);
			DecoderWriteByte(card, 0x12C, 264 & 0xFF);    // Start- and End Column
			DecoderWriteByte(card, 0x12D, 1703 & 0xFF);
			DecoderWriteByte(card, 0x12E, ((1703>>4)&0x70)|((264>>8)&0x07));
			DecoderWriteByte(card, 0x132, 260 & 0xFF);    // SAV Column
			DecoderWriteByte(card, 0x133, 1704 & 0xFF);   // EAV Column
			DecoderWriteByte(card, 0x134, ((1704>>4)&0x70)|((260>>8)&0x07));
			DecoderWriteByte(card, 0x12F, (21&0x1F)|((310>>3)&0x20)|(0<<6)|((312>>1)&0x80));  // VCode Zero...
			DecoderWriteByte(card, 0x130, 310&0xFF);      // ... and VCode Even
			DecoderWriteByte(card, 0x131, 312&0xFF);      // ... and FCode
			break;
	}
	DecoderWriteByte(card, 0x045, 0x00);  // disable compares and panic mode
	DecoderWriteByte(card, 0x094, 0x00);    // disable TOS Detect
	DecoderMaskByte(card, 0x109, 0x30, 0x00);  // Display Override off, don't change OSD, Background
	DecoderWriteByte(card, 0x112, 0x00);  // Disable Horizontal 2:1 Filter
	DecoderWriteByte(card, 0x113, 0x14);  // FreezeMode 1 / 3:2 Pulldown / Repeat First Field / Top Field First
	DecoderWriteByte(card, 0x114, ( 5 <<3)|( 0 <<1)|( 0 <<2)|( 1 <<7));  // VideoMode/FilterEnable/FilterAB/FieldSyncEnable
	DecoderWriteByte(card, 0x115, 0);     // Horizontal Filter Scale
	DecoderWriteByte(card, 0x117, 0x80);  // Automatic Field Inversion Correction
//  DecoderWriteByte(card, 0x117, 0x00);  // no Automatic Field Inversion Correction
	DecoderWriteByte(card, 0x118, 0);     // Horizontal Pan and Scan Word Offset (signed)
	DecoderWriteByte(card, 0x119, 0);     // Vertical Pan and Scan Line Offset
	DecoderWriteByte(card, 0x11B, 0x00);  // Override Picture Width
//    if (0) {  // letterbox
//      DecoderWriteByte(card, 0x114, (DecoderReadByte(card, 0x114) & ~0x78) | 0x40);  // mode 8
//      DecoderWriteByte(card, 0x129, 0x35);
//      DecoderWriteByte(card, 0x12A, 0xE7);
//      DecoderWriteByte(card, 0x114, DecoderReadByte(card, 0x114) & ~0x77);  // ???
//    } else {
//      if (0) {  // MPEG-1
//        DecoderWriteByte(card, 0x114, (DecoderReadByte(card, 0x114) & ~0x78) | 0x10);  // mode 2
//      } else {  // MPEG-2
//        DecoderWriteByte(card, 0x114, (DecoderReadByte(card, 0x114) & ~0x78) | 0x28);  // mode 5
//      }
//    }
	L64021InstallIntr(card);  // Set the interrupt masks, again
	
	return 0;
}

int L64021Init(struct cvdv_cards *card) {
printk(KERN_DEBUG LOGNAME ": -- L64021Init\n");
	L64021Reset(card);
	L64021Setup(card);
	VideoSetBackground(card, 1, 0, 0, 0);  // black
	DecoderWriteByte(card, 0x135, 0x01);  // Enable Video Out, Disable SPU Mix
	DecoderWriteByte(card,0x11C,0x13);  // Pixel State Reset Value / BT.656 Mode / Sync Active Low
	L64021InstallIntr(card);
	return 0;
}



LinuxTV legacy CVS <linuxtv.org/cvs>