// Copyright (C) 2002 Andreas Thiede ( a.thiede@berlin.de )
// 
// based on:
//
/////////////////////////////////////////////////////////////////////////////
// bt848.c
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000 John Adcock.  All rights reserved.
/////////////////////////////////////////////////////////////////////////////
//
//	This file is subject to the terms of the GNU General Public License as
//	published by the Free Software Foundation.  A copy of this license is
//	included with this software distribution in the file COPYING.  If you
//	do not have a copy, you may obtain a copy by writing to the Free
//	Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
//
//	This software 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
/////////////////////////////////////////////////////////////////////////////
// Change Log
//
// Date          Developer             Changes
//
// 24 Jul 2000   John Adcock           Original Release
//                                     Removed use of WinDrvr
//
//  3 Nov 2000   Michael Eskin         Added override of initial BDELAY setting
//               Conexant Systems      by adding non-zero InitialBDelay in .ini
//                                     File. Changed NTSC defaults to 0x5C
//
// 02 Jan 2001   John Adcock           Made RISC Code linear
//
// 08 Jan 2001   John Adcock           Added C++ like access for strings
//
// 08 Jan 2001   John Adcock           Global Variable Tidy up
//                                     Got rid of global.h structs.h defines.h
//
/////////////////////////////////////////////////////////////////////////////

#include "bt848.h"
#include "Audio.h"
#include "Tuner.h"
//#include "Other.h"
#include "settings.h"

#include <bt8xx/Bt8xxRegs.h>
#include <stdio.h>
#include <unistd.h>

void (*userErrorBox)( const char * ) = 0;

/////////////////////////////////////////////////////////////////////////////
// Private Structures, funtions and data
/////////////////////////////////////////////////////////////////////////////
typedef struct BT848_STRUCT
{
   DWORD dwPhysicalAddress;
   DWORD dwMemoryLength;
   DWORD dwMemoryBase;
   DWORD dwIrqNumber;
   DWORD dwSubSystemID;
} BT848_STRUCT;

void BT848_SaveSettings(LPCSTR szFileName);
int BT848_Open(DWORD dwVendorID, DWORD dwDeviceID, DWORD options, int Lock);
int BT848_WhiteCrush_OnChange(long IgnoreCompletely);
int BT848_Registers_OnChange(long IgnoreCompletely);
int BT848_Brightness_OnChange(long Brightness);
int BT848_WhiteCrush_OnChange(long IgnoreCompletely);
int BT848_Hue_OnChange(long Hue);
int BT848_Contrast_OnChange(long Contrast);
int BT848_Saturation_OnChange(long Sat);
int BT848_SaturationU_OnChange(long SatU);
int BT848_SaturationV_OnChange(long SatV);
int BT848_BDelay_OnChange(long BDelay);
int BT848_Registers_OnChange(long IgnoreCompletely);
int BT848_SetVideoSource(VIDEOSOURCETYPE nInput);
void BT848_SetGeometryEvenOdd(int bOdd, BYTE bVtc, int wHScale, int wVScale, int wHActive, int wVActive, int wHDelay,
                              int wVDelay, BYTE bCrop);

int BT848_SetGeoSize();
void BT848_SetDMA(int bState);
void BT848_SetPLL(PLLFREQ PLL);

extern void Start_Capture();
extern void Stop_Capture();
extern void Reset_Capture();

typedef MemoryDescriptor PMemStruct;
#define dwUser mVirtUser
#define ALLOC_MEMORY_CONTIG 1

void Free_DMA( PMemStruct * p );
void Free_Display_DMA(int NR);
PHYS GetPhysicalAddress( PMemStruct m, DWORD adr, unsigned size, void * unused );
void* GetFirstFullPage(PMemStruct pMem);
int Alloc_DMA(DWORD dwSize, PMemStruct * dma, int Option);


PMemStruct Risc_dma;
PMemStruct Vbi_dma[5];
PMemStruct Display_dma[5];


static mach_port_t  master_port     = -1;
static io_connect_t bt8xx_io_connect = 0;

BYTE* pDisplay[5] = { NULL,NULL,NULL,NULL,NULL };
BYTE* pVBILines[5] = { NULL,NULL,NULL,NULL,NULL };

PHYS    RiscBasePhysical; 
DWORD  *RiscBaseLinear;
long BytesPerRISCField = 1;

char BTVendorID[10] = "";
char BTDeviceID[10] = "";
char BTChipType[10] = "";

int bSaveSettings = FALSE;

// MAE 2 Nov 2000 - Start of change for Macrovision fix
// If non-zero in .ini file, will override TV table setting
long InitialBDelay = 0x00;  // Original hardware default value was 0x5D
// MAE 2 Nov 2000 - End of change for Macrovision fix

long	BtAgcDisable = FALSE;		// Luma AGC, 0 says AGC enabled
long	BtCrush = TRUE;				// Adaptive AGC, 0 says Crush disabled
long	BtEvenChromaAGC = TRUE;		// Even CAGC, 0 says CAGC disable
long	BtOddChromaAGC = TRUE;		// Odd chroma AGC
long	BtEvenLumaPeak = FALSE;		// Even Peak, 0 says normal, not Luma peak
long	BtOddLumaPeak = FALSE;							
long	BtFullLumaRange = TRUE;		// Full Range Luma, 0=normal,1=full
									// should be 1 for NTSC
long	BtEvenLumaDec = FALSE;		// Even Luma decimation,  0 says disable
long	BtOddLumaDec = FALSE;
long	BtEvenComb = TRUE;			// Even Comb, enabled
long	BtOddComb = TRUE;
long	BtColorBars = FALSE;        // Display Color Bars, 0 = no
long	BtGammaCorrection = FALSE;	// Gamma Correction Removal, 0 = Enabled
long    BtCoring = FALSE;           // Coring function: (0,1,2,or 3) << 5
long    BtHorFilter = FALSE;		// Horizontal Filer: (0,1,2,3) << 3
									// maybe only 0,1 valid for full res?
long    BtVertFilter = FALSE;		// Vert. Filter, only 0 and 4 valid here
long    BtColorKill = TRUE;			// Kill color if B/W: (0,1) << 5
long    BtWhiteCrushUp = 0xcf;		// Crush up - entire register value
long    BtWhiteCrushDown = 0x7f;	// Crush down - entire register value

BYTE ColorFormat = kBtColorFmtRGB32;

// MAE, 3 Nov 2000
//    Changed all BDELAY values from 5D to 5C for Macrovision fix
//
// John Adcock, 19 Dec 2000
//    Fixed PAL-N to stop it from crashing, improved PAL-M values
//    These were the old PAL-N Values that crashed dTV
//    /* PAL-M */
//    { 754, 480,  910, 0x70, 0x5c, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
//        910, 754, 135, 754, 0x1a, 0, FALSE, 400},
//    /* PAL-N */
//    { 922, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
//	      1135, 922, 186, 922, 0x1c, 0, TRUE, 400},
//
TTVFORMAT TVFormats[FORMAT_LASTONE] =
{
	/* PAL-BDGHI */
	{ "PAL DBGHI", 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
	    186, 922, 0x20, 0, TRUE, 2048 /*511*/, 16 /*19*/ },
	/* NTSC */
	{ "NTSC", 480, 910, 0x68, 0x5c, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
	    137, 754, 0x1a, 0, FALSE, 400, 13},
	/* SECAM */
	{ "SECAM", 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
	    186, 922, 0x20, 0, TRUE, 511, 19},
	/* PAL-M */
	{ "PAL-M", 480,  910, 0x68, 0x5c, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
	    137, 754, 0x1a, 0, FALSE, 400, 13},
    /* PAL-N */
    { "PAL-N", 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
        186, 922, 0x20, 0, TRUE, 511, 19},
	/* NTSC Japan*/
	{ "NTSC Japan", 480,  910, 0x70, 0x5c, (BT848_IFORM_NTSC_JAP|BT848_IFORM_XT0),
	    135, 754, 0x1a, 0, FALSE, 400, 13},
    /* PAL-60 */
	{ "PAL 60", 480, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
	    186, 922, 0x1a, 0, TRUE, 400, 13},
};

/*
typedef struct
{
        char * szDesc;
        WORD wCropHeight;
        WORD wTotalWidth;
        BYTE bDelayA;
        BYTE bDelayB;
        BYTE bIForm;
        WORD wHDelayx1;
        WORD wHActivex1;
        WORD wVDelay;
        WORD wCropOffset;
        int Is25fps;
        WORD VBIPacketSize;
        WORD VBILines;
} TTVFORMAT;
*/

long TVFormat = 0;

// 10/19/2000 Mark Rejhon
// Better NTSC defaults
// These are the original defaults, likely optimized for PAL (could use refinement).
long InitialHue         = DEFAULT_HUE_NTSC;
long InitialBrightness  = DEFAULT_BRIGHTNESS_NTSC;
long InitialContrast    = DEFAULT_CONTRAST_NTSC;
long InitialSaturation  = (DEFAULT_SAT_U_NTSC + DEFAULT_SAT_V_NTSC) / 2;
long InitialSaturationU = DEFAULT_SAT_U_NTSC;
long InitialSaturationV = DEFAULT_SAT_V_NTSC;
long VideoSource = SOURCE_TUNER;
long CurrentX = 720;
long CustomPixelWidth = 754;
long CurrentY;
long CurrentVBILines = 0;

extern int Capture_VBI;
//===========================================================================
// CCIR656 Digital Input Support
//
// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
//
//===========================================================================
// Timing generator SRAM table values for CCIR601 720x480 NTSC
//===========================================================================
BYTE SRAMTable[ 60 ] =
{
      0x33, // size of table = 51
      0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
      0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
      0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
};

SETTING BT848Settings[BT848_SETTING_LASTONE];

/////////////////////////////////////////////////////////////////////////////
// Start of "real" code
/////////////////////////////////////////////////////////////////////////////

const char* BT848_VendorID()
{
	return BTVendorID;
}

const char* BT848_DeviceID()
{
	return BTDeviceID;
}

const char* BT848_ChipType()
{
	return BTChipType;
}

int BT848_FindTVCard(HWND hWnd)
{
	int ret;

	strcpy(BTVendorID, "0x109e");
	strcpy(BTDeviceID, "0x036e");

	ret = BT848_Open(0x109e, 0x36e, TRUE, FALSE);

	if (ret == 0)
	{
		strcpy(BTChipType, "BT878");
	}
	else if (ret == 3)
	{
		ErrorBox("PCI-Card with Bt878 Cannot be locked");
		return (FALSE);
	}
	else
	{
		strcpy(BTVendorID, "0x109e");
		strcpy(BTDeviceID, "0x0350");
		ret = BT848_Open(0x109e, 0x350, TRUE, FALSE);
		if (ret == 0)
		{
			strcpy(BTChipType, "BT848");
		}
		else if (ret == 3)
		{
			ErrorBox("PCI-Card with Bt848 Cannot be locked");
			return (FALSE);
		}
		else
		{
			strcpy(BTVendorID, "0x109e");
			strcpy(BTDeviceID, "0x0351");
			ret = BT848_Open(0x109e, 0x351, TRUE, FALSE);
			if (ret == 0)
			{
				strcpy(BTChipType, "BT849");
			}
			else if (ret == 3)
			{
				ErrorBox("PCI-Card with Bt849 Cannot be locked");
				return (FALSE);
			}
			else
			{
				strcpy(BTVendorID, "0x109e");
				strcpy(BTDeviceID, "0x036F");
				ret = BT848_Open(0x109e, 0x36F, TRUE, FALSE);
				if (ret == 0)
				{
					strcpy(BTChipType, "BT878a");
				}
				else if (ret == 3)
				{
					ErrorBox("PCI-Card with Bt878a Cannot be locked");
					return (FALSE);
				}
			}
		}
	}

	if (ret != 0)
	{
		return (FALSE);
	}

	if (bSaveSettings == TRUE)
	{
		BT848_SaveSettings("Setting.BT");
	}

	return (TRUE);
}


void BT848_SaveSettings(LPCSTR szFileName)
{
	FILE *SettingFile;
	unsigned short i;

	if ((SettingFile = fopen(szFileName, "w")) != NULL)
	{
		fprintf(SettingFile, "BT848_COLOR_CTL %02x\n", BT848_ReadByte(BT848_COLOR_CTL));
		fprintf(SettingFile, "BT848_CAP_CTL %02x\n", BT848_ReadByte(BT848_CAP_CTL));
		fprintf(SettingFile, "BT848_VBI_PACK_SIZE %02x\n", BT848_ReadByte(BT848_VBI_PACK_SIZE));
		fprintf(SettingFile, "BT848_VBI_PACK_DEL %02x\n", BT848_ReadByte(BT848_VBI_PACK_DEL));
		fprintf(SettingFile, "BT848_GPIO_DMA_CTL %02x\n", BT848_ReadByte(BT848_GPIO_DMA_CTL));
		fprintf(SettingFile, "BT848_IFORM %02x\n", BT848_ReadByte(BT848_IFORM));

		fprintf(SettingFile, "BT848_E_SCLOOP %02x\n", BT848_ReadByte(BT848_E_SCLOOP));
		fprintf(SettingFile, "BT848_O_SCLOOP %02x\n", BT848_ReadByte(BT848_O_SCLOOP));
		fprintf(SettingFile, "BT848_ADELAY %02x\n", BT848_ReadByte(BT848_ADELAY));
		fprintf(SettingFile, "BT848_BDELAY %02x\n", BT848_ReadByte(BT848_BDELAY));

		fprintf(SettingFile, "BT848_E_HSCALE_HI %02x\n", BT848_ReadByte(BT848_E_HSCALE_HI));
		fprintf(SettingFile, "BT848_E_HSCALE_LO %02x\n", BT848_ReadByte(BT848_E_HSCALE_LO));
		fprintf(SettingFile, "BT848_E_VSCALE_HI %02x\n", BT848_ReadByte(BT848_E_VSCALE_HI));
		fprintf(SettingFile, "BT848_E_VSCALE_LO %02x\n", BT848_ReadByte(BT848_E_VSCALE_LO));
		fprintf(SettingFile, "BT848_E_HACTIVE_LO %02x\n", BT848_ReadByte(BT848_E_HACTIVE_LO));
		fprintf(SettingFile, "BT848_E_HDELAY_LO %02x\n", BT848_ReadByte(BT848_E_HDELAY_LO));
		fprintf(SettingFile, "BT848_E_VACTIVE_LO %02x\n", BT848_ReadByte(BT848_E_VACTIVE_LO));
		fprintf(SettingFile, "BT848_E_VDELAY_LO %02x\n", BT848_ReadByte(BT848_E_VDELAY_LO));
		fprintf(SettingFile, "BT848_E_CROP %02x\n", BT848_ReadByte(BT848_E_CROP));

		fprintf(SettingFile, "BT848_O_HSCALE_HI %02x\n", BT848_ReadByte(BT848_O_HSCALE_HI));
		fprintf(SettingFile, "BT848_O_HSCALE_LO %02x\n", BT848_ReadByte(BT848_O_HSCALE_LO));
		fprintf(SettingFile, "BT848_O_VSCALE_HI %02x\n", BT848_ReadByte(BT848_O_VSCALE_HI));
		fprintf(SettingFile, "BT848_O_VSCALE_LO %02x\n", BT848_ReadByte(BT848_E_VSCALE_LO));
		fprintf(SettingFile, "BT848_O_HACTIVE_LO %02x\n", BT848_ReadByte(BT848_O_HACTIVE_LO));
		fprintf(SettingFile, "BT848_O_HDELAY_LO %02x\n", BT848_ReadByte(BT848_O_HDELAY_LO));
		fprintf(SettingFile, "BT848_O_VACTIVE_LO %02x\n", BT848_ReadByte(BT848_O_VACTIVE_LO));
		fprintf(SettingFile, "BT848_O_VDELAY_LO %02x\n", BT848_ReadByte(BT848_O_VDELAY_LO));
		fprintf(SettingFile, "BT848_O_CROP %02x\n", BT848_ReadByte(BT848_O_CROP));

		fprintf(SettingFile, "BT848_PLL_F_LO %02x\n", BT848_ReadByte(BT848_PLL_F_LO));
		fprintf(SettingFile, "BT848_PLL_F_HI %02x\n", BT848_ReadByte(BT848_PLL_F_HI));
		fprintf(SettingFile, "BT848_PLL_XCI %02x\n", BT848_ReadByte(BT848_PLL_XCI));

		fprintf(SettingFile, "BT848_BRIGHT %02x\n", BT848_ReadByte(BT848_BRIGHT));
		fprintf(SettingFile, "BT848_CONTRAST_LO %02x\n", BT848_ReadByte(BT848_CONTRAST_LO));
		fprintf(SettingFile, "BT848_SAT_V_LO %02x\n", BT848_ReadByte(BT848_SAT_V_LO));
		fprintf(SettingFile, "BT848_SAT_U_LO %02x\n", BT848_ReadByte(BT848_SAT_U_LO));
		fprintf(SettingFile, "BT848_GPIO_OUT_EN %04x\n", BT848_ReadWord(BT848_GPIO_OUT_EN));
		fprintf(SettingFile, "BT848_GPIO_OUT_EN_HIBYTE %02x\n", BT848_ReadByte(BT848_GPIO_OUT_EN_HIBYTE));

		fprintf(SettingFile, "BT848_GPIO_REG_INP %04x\n", BT848_ReadWord(BT848_GPIO_REG_INP));
		fprintf(SettingFile, "BT848_GPIO_REG_INP_HIBYTE %02x\n", BT848_ReadByte(BT848_GPIO_REG_INP_HIBYTE));

		fprintf(SettingFile, "BT848_GPIO_DATA %04x\n", BT848_ReadWord(BT848_GPIO_DATA));
		fprintf(SettingFile, "BT848_GPIO_DATA_HIBYTE %02x\n", BT848_ReadByte(BT848_GPIO_DATA_HIBYTE));
		i = ((BT848_ReadByte(BT848_GPIO_OUT_EN_HIBYTE)) << 16) + BT848_ReadWord(BT848_GPIO_OUT_EN);
		fprintf(SettingFile, "*********************************************\n");
		fprintf(SettingFile, "Ausgelesene Einträge für Eigenen KartenTyp\n");
		fprintf(SettingFile, "Eintrag für BT848_GPIO_OUT_EN  %9d     ( Schaltwert )\n", i);
		i = ((BT848_ReadByte(BT848_GPIO_REG_INP_HIBYTE)) << 16) + BT848_ReadWord(BT848_GPIO_REG_INP);
		fprintf(SettingFile, "Eintrag für BT848_GPIO_REG_INP %9d     ( Input-Control )\n", i);
		i = ((BT848_ReadByte(BT848_GPIO_DATA_HIBYTE)) << 16) + BT848_ReadWord(BT848_GPIO_DATA);
		fprintf(SettingFile, "Eintrag für BT848_GPIO_DATA    %9d     ( Eingangswunsch) \n", i);
		fprintf(SettingFile, "*********************************************\n");
		fclose(SettingFile);
	}
}

DWORD BT848_GetSubSystemID()
{
    UInt32 id = 0;
    
    if( Bt8xxGetDeviceID( bt8xx_io_connect, &id ) == KERN_SUCCESS ) {
        return id;
    }
    return 0;
}

int BT848_MemoryInit(void)
{
	int i;

	if (!Alloc_DMA(83968, &Risc_dma, ALLOC_MEMORY_CONTIG))
	{
		ErrorBox("Risc Memory (83 KB Contiguous) not Allocated");
		return (FALSE);
	}

	RiscBaseLinear = (DWORD*) Risc_dma.dwUser;
	RiscBasePhysical = GetPhysicalAddress(Risc_dma, Risc_dma.dwUser, 83968, NULL);
	
	for (i = 0; i < 5; i++)
	{
		// JA 02/01/2001
		// Allocate some extra memory so that we can skip
		// start of buffer that is not page aligned
		if (!Alloc_DMA(2048 * 19 * 2 + 4095, &Vbi_dma[i], 0))
		{
			ErrorBox("VBI Memory for DMA not allocated");
			return (FALSE);
		}
		pVBILines[i] = GetFirstFullPage(Vbi_dma[i]);
		// JA 29/12/2000
		// Allocate some extra memory so that we can skip
		// start of buffer that is not page aligned
		if (!Alloc_DMA(1024 * 576 * 2 + 4095, &Display_dma[i], 0))
		{
			ErrorBox("Display Memory for DMA not allocated");
			return (FALSE);
		}
		pDisplay[i] = GetFirstFullPage(Display_dma[i]);
	}

	return (TRUE);
}

void BT848_MemoryFree()
{
	int i;
	Free_DMA(&Risc_dma);
	for(i = 0; i < 5; i++)
	{
		Free_DMA(&Vbi_dma[i]);
		Free_Display_DMA(i);
	}
}

void BT848_Restart_RISC_Code()
{
    BYTE CapCtl;
    UInt32 base, colorCtl;

#if 1        
    Bt8xxGetVideoPhysAddr( bt8xx_io_connect, &base );
#else
    base = RiscBasePhysical;
#endif

    CapCtl = BT848_ReadByte(BT848_CAP_CTL);
    BT848_MaskDataByte(BT848_CAP_CTL, 0, (BYTE) 0x0f);
    BT848_WriteDword(BT848_INT_STAT, (DWORD) 0x0fffffff);
    BT848_WriteDword(BT848_RISC_STRT_ADD, base );
        
    CapCtl = kBtCapCtlCapEven | kBtCapCtlCapOdd | BT848_CAP_CTL_CAPTURE_VBI_EVEN | BT848_CAP_CTL_CAPTURE_VBI_ODD;
        
    BT848_WriteByte(BT848_CAP_CTL, CapCtl);

    printf("CapCtl %x\n", CapCtl );

    colorCtl = kBtColorCtlWSwapEven | kBtColorCtlBSwapEven ; // | kBtColorCtlWSwapOdd | kBtColorCtlBSwapOdd

    colorCtl |= kBtColorCtlGamma;
    
    BT848_WriteByte(kBtColorCtl, colorCtl);

    BT848_WriteDword(kBtStartAddr, base);
    BT848_WriteDword(kBtIntStat, 0x00FFFFFF);
    BT848_WriteDword(kBtGPIODMACTL, 0xAC | kBtGPIODMACTLRISCEn | kBtGPIODMACTLFIFOEn);
    
    BT848_SetDMA(TRUE);
}

#if 1
void BT848_ResetHardware()
{
        UInt32 base;
        
        Bt8xxGetVideoPhysAddr( bt8xx_io_connect, &base );

	BT848_SetDMA(FALSE);

        // Calling reset too often freezes the machine
        
        //BT848_WriteByte(BT848_SRESET, 0);

	usleep(100*1000);
	
        //BT848_WriteDword(BT848_RISC_STRT_ADD, base );
	//BT848_WriteByte(BT848_CAP_CTL, 0x00);

	BT848_WriteByte(BT848_VBI_PACK_SIZE, (VBI_SPL / 4) & 0xff);
	BT848_WriteByte(BT848_VBI_PACK_DEL, (VBI_SPL / 4) >> 8);
	BT848_WriteWord(BT848_GPIO_DMA_CTL, 0xfc);
	BT848_WriteByte(BT848_IFORM, BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI);
	BT848_Registers_OnChange(0);
	
	BT848_WriteByte(BT848_TDEC, 0x00);

// MAE 2 Nov 2000 - Start of change for Macrovision fix
	if (InitialBDelay != 0)
	{
		// BDELAY override from .ini file
		BT848_BDelay_OnChange(InitialBDelay);
	}
// MAE 2 Nov 2000 - End of change for Macrovision fix


	BT848_WriteDword(BT848_INT_STAT, (DWORD) 0x0fffffff);
	BT848_WriteDword(BT848_INT_MASK, 0);

	BT848_SetPLL(0);

	BT848_Brightness_OnChange(InitialBrightness);
	BT848_Contrast_OnChange(InitialContrast);
	BT848_Hue_OnChange(InitialHue);
	BT848_SaturationU_OnChange(InitialSaturationU);
	BT848_SaturationV_OnChange(InitialSaturationV);
	BT848_SetVideoSource(VideoSource);
	BT848_SetGeoSize();
}
#else

void BT848_ResetHardware()
{
	BT848_SetDMA(FALSE);
	BT848_WriteByte(BT848_SRESET, 0);
	MilliSleep(100);

	BT848_WriteDword(BT848_RISC_STRT_ADD, RiscBasePhysical);
	BT848_WriteByte(BT848_CAP_CTL, 0x00);
	BT848_WriteByte(BT848_VBI_PACK_SIZE, (VBI_SPL / 4) & 0xff);
	BT848_WriteByte(BT848_VBI_PACK_DEL, (VBI_SPL / 4) >> 8);
	BT848_WriteWord(BT848_GPIO_DMA_CTL, 0xfc);
	BT848_WriteByte(BT848_IFORM, BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI);

	BT848_Registers_OnChange(0);
	
	BT848_WriteByte(BT848_TDEC, 0x00);

// MAE 2 Nov 2000 - Start of change for Macrovision fix
	if (InitialBDelay != 0)
	{
		// BDELAY override from .ini file
		BT848_BDelay_OnChange(InitialBDelay);
	}
// MAE 2 Nov 2000 - End of change for Macrovision fix


	BT848_WriteDword(BT848_INT_STAT, (DWORD) 0x0fffffff);
	BT848_WriteDword(BT848_INT_MASK, 0);

	BT848_SetPLL(0);

	BT848_Brightness_OnChange(InitialBrightness);
	BT848_Contrast_OnChange(InitialContrast);
	BT848_Hue_OnChange(InitialHue);
	BT848_SaturationU_OnChange(InitialSaturationU);
	BT848_SaturationV_OnChange(InitialSaturationV);
	BT848_SetVideoSource(VideoSource);
	BT848_SetGeoSize();
}

#endif

PHYS RiscLogToPhys(DWORD * pLog)
{
	return (RiscBasePhysical + (pLog - RiscBaseLinear) * 4);
}

// JA 17012001 Updated to do exactly what it says in the bt848 docs
void BT848_SetPLL(PLLFREQ PLL)
{
	int i = 6;

	// reset the TGCKI bits
	BT848_MaskDataByte(BT848_TGCTRL, BT848_TGCTRL_TGCKI_NOPLL, 0x18);

	switch(PLL)
	{
	case PLL_NONE:
		BT848_WriteByte(BT848_PLL_XCI, 0x00);
		return;
		break;
	case PLL_28:
		BT848_WriteByte(BT848_PLL_F_LO, 0xf9);
		BT848_WriteByte(BT848_PLL_F_HI, 0xdc);
		BT848_WriteByte(BT848_PLL_XCI, 0x8e);
		break;
	case PLL_35:
		BT848_WriteByte(BT848_PLL_F_LO, 0x39);
		BT848_WriteByte(BT848_PLL_F_HI, 0xB0);
		BT848_WriteByte(BT848_PLL_XCI, 0x89);
		break;
	}

	// wait for the PLL to lock
	while(i-- > 0 && BT848_ReadByte(BT848_DSTATUS) & BT848_DSTATUS_PLOCK)
	{
		BT848_WriteByte(BT848_DSTATUS, 0x00);
		usleep(100*1000);
	}

	// Set the TGCKI bits to use PLL rather than xtal
	BT848_MaskDataByte(BT848_TGCTRL, BT848_TGCTRL_TGCKI_PLL, 0x18);

	BT848_WhiteCrush_OnChange(0);
	BT848_WriteByte(BT848_VTOTAL_LO, 0x00);
	BT848_WriteByte(BT848_VTOTAL_HI, 0x00);
	BT848_WriteByte(BT848_DVSIF, 0x00);
}

void BT848_SetDMA(int bState)
{
	if (bState)
	{
		BT848_OrDataWord(BT848_GPIO_DMA_CTL, 3);
	}
	else
	{
		BT848_AndDataWord(BT848_GPIO_DMA_CTL, ~3);
	}
}


int BT848_SetGeoSize()
{
	int vscale, hscale;
	DWORD sr;
	int hdelay, vdelay;
	int hactive, vactive;
	BYTE crop, vtc;
        //BYTE cFormat = ColorFormat << kBtColorFmtEvenShift |  ColorFormat << kBtColorFmtOddShift;
        BYTE cFormat = ColorFormat << kBtColorFmtEvenShift |  ColorFormat << kBtColorFmtOddShift;
        //cFormat = (BYTE)((BT848_COLOR_FMT_YUY2 << 4) | BT848_COLOR_FMT_YUY2);
        //ColourFormat = kBtColorFmtRGB32 << kBtColorFmtEvenShift |  kBtColorFmtRGB32 << kBtColorFmtOddShift;
        //ColorFormat = kBtColorFmtRGB24 << kBtColorFmtEvenShift |  kBtColorFmtRGB24 << kBtColorFmtOddShift;

        //cFormat |= ( kBtColorCtlBSwapEven  );
    
	CurrentY = TVFormats[TVFormat].wCropHeight;
	CurrentVBILines = TVFormats[TVFormat].VBILines;

	// set the pll on the card if appropriate
	if(TVFormats[TVFormat].Is25fps == TRUE && GetCardSetup()->pll != PLL_NONE)
	{
		BT848_SetPLL(GetCardSetup()->pll);
	}
	else
	{
		BT848_SetPLL(0);
	}

	BT848_WriteByte(BT848_ADELAY, TVFormats[TVFormat].bDelayA);
	BT848_WriteByte(BT848_BDELAY, TVFormats[TVFormat].bDelayB);

	BT848_WriteByte(BT848_VBI_PACK_SIZE, (BYTE)(TVFormats[TVFormat].VBIPacketSize & 0xff));
	BT848_WriteByte(BT848_VBI_PACK_DEL, (BYTE)(TVFormats[TVFormat].VBIPacketSize >> 8));

	BT848_MaskDataByte(BT848_IFORM, TVFormats[TVFormat].bIForm, BT848_IFORM_NORM | BT848_IFORM_XTBOTH);
        
        BT848_WriteByte(BT848_COLOR_FMT, cFormat );

// MAE 2 Nov 2000 - Start of change for Macrovision fix
	if (InitialBDelay != 0)
	{
		// BDELAY override from .ini file
		BT848_BDelay_OnChange(InitialBDelay);
	}
// MAE 2 Nov 2000 - End of change for Macrovision fix
	BT848_Registers_OnChange(0);

	hactive = CurrentX;

	vtc = BtVertFilter?BT848_VTC_VFILT_2TAPZ:0;		
	if(CurrentX <= TVFormats[TVFormat].wHActivex1)
	{
		hscale = ((TVFormats[TVFormat].wHActivex1 - CurrentX) * 4096UL) / CurrentX;
	}
	else
	{
		CurrentX = TVFormats[TVFormat].wHActivex1;
		hscale = 0;
	}
	vdelay = TVFormats[TVFormat].wVDelay;
	hdelay = ((CurrentX * TVFormats[TVFormat].wHDelayx1) / TVFormats[TVFormat].wHActivex1) & 0x3fe;

        // @@ aT 26.10.2001
        // adjust y-size
        
        //CurrentY = (long) ( 0.8 * CurrentX );
        
	sr = (TVFormats[TVFormat].wCropHeight * 512) / CurrentY - 512;
	vscale = (WORD) (0x10000UL - sr) & 0x1fff;
	vactive = TVFormats[TVFormat].wCropHeight;
	crop = ((hactive >> 8) & 0x03) | ((hdelay >> 6) & 0x0c) | ((vactive >> 4) & 0x30) | ((vdelay >> 2) & 0xc0);

	BT848_SetGeometryEvenOdd(FALSE, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop);
	BT848_SetGeometryEvenOdd(TRUE, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop);

	return TRUE;
}


int BT848_Brightness_OnChange(long Brightness)
{
	BT848_WriteByte(BT848_BRIGHT, (BYTE) (Brightness & 0xff));
	InitialBrightness = Brightness;
	return FALSE;
}



int BT848_WhiteCrush_OnChange(long IgnoreCompletely)
{
	BT848_WriteByte(BT848_WC_UP, (BYTE)BtWhiteCrushUp);			// TRB 12/00 allow parm
	BT848_WriteByte(BT848_WC_DOWN, (BYTE)BtWhiteCrushDown);		// TRB 12/00 allow parm
	return FALSE;
}

int BT848_Hue_OnChange(long Hue)
{
	BT848_WriteByte(BT848_HUE, (BYTE) (Hue & 0xff));
	InitialHue = Hue;
	return FALSE;
}

int BT848_Contrast_OnChange(long Contrast)
{
	BYTE bContHi;

	bContHi = (BYTE) (Contrast >> 6) & 4;
	BT848_WriteByte(BT848_CONTRAST_LO, (BYTE) (Contrast & 0xff));
	BT848_MaskDataByte(BT848_E_CONTROL, bContHi, 4);
	BT848_MaskDataByte(BT848_O_CONTROL, bContHi, 4);
	InitialContrast = Contrast;
	return FALSE;
}

int BT848_Saturation_OnChange(long Sat)
{
	long NewSaturationU = InitialSaturationU;
	long NewSaturationV = InitialSaturationV;
	long OldSaturation = (InitialSaturationU + InitialSaturationV) / 2;
	NewSaturationU += Sat - OldSaturation;
	NewSaturationV += Sat - OldSaturation;
	BT848_SaturationU_OnChange(NewSaturationU);
	BT848_SaturationV_OnChange(NewSaturationV);
	return TRUE;
}


#if 1

int BT848_SaturationU_OnChange(long SatU)
{
	BYTE bDataHi;

	bDataHi = (BYTE) (SatU >> 7) & 2;
	BT848_WriteByte(BT848_SAT_U_LO, (BYTE) (SatU & 0xff));
	BT848_MaskDataByte(BT848_E_CONTROL, bDataHi, 2);
	BT848_MaskDataByte(BT848_O_CONTROL, bDataHi, 2);
	InitialSaturationU = SatU;
	InitialSaturation = (InitialSaturationU + InitialSaturationV) / 2;
	//BT848Settings[SATURATION].MinValue = abs(InitialSaturationU - InitialSaturationV) / 2;
	//BT848Settings[SATURATION].MaxValue = 255 - abs(InitialSaturationU - InitialSaturationV) / 2;
	return TRUE;
}

int BT848_SaturationV_OnChange(long SatV)
{
	BYTE bDataHi;

	bDataHi = (BYTE) (SatV >> 8) & 1;
	BT848_WriteByte(BT848_SAT_V_LO, (BYTE) (SatV & 0xff));
	BT848_MaskDataByte(BT848_E_CONTROL, bDataHi, 1);
	BT848_MaskDataByte(BT848_O_CONTROL, bDataHi, 1);
	InitialSaturationV = SatV;
	InitialSaturation = (InitialSaturationU + InitialSaturationV) / 2;
	//BT848Settings[SATURATION].MinValue = abs(InitialSaturationU - InitialSaturationV) / 2;
	//BT848Settings[SATURATION].MaxValue = 255 - abs(InitialSaturationU - InitialSaturationV) / 2;
	return TRUE;
}

#else

int BT848_SaturationU_OnChange(long SatU)
{
	BYTE bDataHi;

	bDataHi = (BYTE) (SatU >> 7) & 2;
	BT848_WriteByte(BT848_SAT_U_LO, (BYTE) (SatU & 0xff));
	BT848_MaskDataByte(BT848_E_CONTROL, bDataHi, 2);
	BT848_MaskDataByte(BT848_O_CONTROL, bDataHi, 2);
	InitialSaturationU = SatU;
	InitialSaturation = (InitialSaturationU + InitialSaturationV) / 2;
	BT848Settings[SATURATION].MinValue = abs(InitialSaturationU - InitialSaturationV) / 2;
	BT848Settings[SATURATION].MaxValue = 255 - abs(InitialSaturationU - InitialSaturationV) / 2;
	return TRUE;
}

int BT848_SaturationV_OnChange(long SatV)
{
	BYTE bDataHi;

	bDataHi = (BYTE) (SatV >> 8) & 1;
	BT848_WriteByte(BT848_SAT_V_LO, (BYTE) (SatV & 0xff));
	BT848_MaskDataByte(BT848_E_CONTROL, bDataHi, 1);
	BT848_MaskDataByte(BT848_O_CONTROL, bDataHi, 1);
	InitialSaturationV = SatV;
	InitialSaturation = (InitialSaturationU + InitialSaturationV) / 2;
	BT848Settings[SATURATION].MinValue = abs(InitialSaturationU - InitialSaturationV) / 2;
	BT848Settings[SATURATION].MaxValue = 255 - abs(InitialSaturationU - InitialSaturationV) / 2;
	return TRUE;
}

#endif

#if 1

int BT848_BDelay_OnChange(long BDelay)
{
	InitialBDelay = BDelay;
	if (BDelay > 0) 
    {
        if (InitialBDelay == 0) 
        {
            // We use automatic BDelay if InitialBDelay is 0
            //Reset_Capture();
            //BT848Settings[BDELAY].szDisplayName = "BDelay AUTO";
        }
        else
        {
            //BT848_WriteByte(BT848_BDELAY, (BYTE)BDelay);
            //BT848Settings[BDELAY].szDisplayName = "BDelay";
        }
    }
	return FALSE;
}

#else

int BT848_BDelay_OnChange(long BDelay)
{
	InitialBDelay = BDelay;
	if (BDelay > 0) 
    {
        if (InitialBDelay == 0) 
        {
            // We use automatic BDelay if InitialBDelay is 0
            Reset_Capture();
			BT848Settings[BDELAY].szDisplayName = "BDelay AUTO";
        }
        else
        {
			BT848_WriteByte(BT848_BDELAY, (BYTE)BDelay);
			BT848Settings[BDELAY].szDisplayName = "BDelay";
        }
    }
	return FALSE;
}

#endif

int BT848_Registers_OnChange(long IgnoreCompletely)
{
	BYTE bNewValue;

	// use mask here as we don't want to disturb the s-video stuff
	bNewValue =  BtEvenLumaDec?BT848_CONTROL_LDEC:0;
	BT848_MaskDataByte(BT848_E_CONTROL, bNewValue, BT848_CONTROL_LDEC);

	// use mask here as we don't want to disturb the s-video stuff
	bNewValue =  BtOddLumaDec?BT848_CONTROL_LDEC:0;
	BT848_MaskDataByte(BT848_O_CONTROL, bNewValue, BT848_CONTROL_LDEC);

	bNewValue =  BtEvenChromaAGC?BT848_SCLOOP_CAGC:0;
	bNewValue |= BtEvenLumaPeak?BT848_SCLOOP_LUMA_PEAK:0;
	bNewValue |= BtColorKill?BT848_SCLOOP_CKILL:0;
	bNewValue |= BtHorFilter?BT848_SCLOOP_HFILT_FULL:0;
	BT848_WriteByte(BT848_E_SCLOOP, bNewValue);
	
	bNewValue =  BtOddChromaAGC?BT848_SCLOOP_CAGC:0;
	bNewValue |= BtOddLumaPeak?BT848_SCLOOP_LUMA_PEAK:0;
	bNewValue |= BtColorKill?BT848_SCLOOP_CKILL:0;
	bNewValue |= BtHorFilter?BT848_SCLOOP_HFILT_FULL:0;
	BT848_WriteByte(BT848_O_SCLOOP, bNewValue);

	bNewValue =  BtFullLumaRange?BT848_OFORM_RANGE:0;
	bNewValue |= BtCoring?BT848_OFORM_CORE32:0;
	BT848_WriteByte(BT848_OFORM, bNewValue);
	
	bNewValue =  BtEvenComb?BT848_VSCALE_COMB:0;
	BT848_WriteByte(BT848_E_VSCALE_HI, bNewValue);

	bNewValue =  BtOddComb?BT848_VSCALE_COMB:0;
	BT848_WriteByte(BT848_O_VSCALE_HI, bNewValue);
	
	bNewValue =  BT848_ADC_RESERVED;
	bNewValue |= BtAgcDisable?BT848_ADC_AGC_EN:0;
	bNewValue |= BtCrush?BT848_ADC_CRUSH:0;
	BT848_WriteByte(BT848_ADC, bNewValue); 

	bNewValue =  BtColorBars?BT848_COLOR_CTL_COLOR_BARS:0;
	bNewValue |= BtGammaCorrection?BT848_COLOR_CTL_GAMMA:0;
	BT848_WriteByte(BT848_COLOR_CTL, bNewValue);

	bNewValue =  BtVertFilter?BT848_VTC_VFILT_2TAPZ:0;
	BT848_MaskDataByte(BT848_E_VTC, bNewValue, BT848_VTC_VFILT_2TAPZ);
	BT848_MaskDataByte(BT848_O_VTC, bNewValue, BT848_VTC_VFILT_2TAPZ);

	return FALSE;
}

int BT848_SetVideoSource(VIDEOSOURCETYPE nInput)
{
	DWORD MuxSel;
	// 0= Tuner,
	// 1= Composite,
	// 2= SVideo,
	// 3= Other 1
	// 4= Other 2
	// 5= Composite via SVideo

        printf( "BT848_SetVideoSource %d Muxmask %lx\n", nInput, GetCardSetup()->GPIOMuxMask );
        
	BT848_AndOrDataDword(BT848_GPIO_OUT_EN, GetCardSetup()->GPIOMuxMask, ~GetCardSetup()->GPIOMuxMask );
	BT848_AndDataByte(BT848_IFORM, ~BT848_IFORM_MUXSEL);

	// set the comp bit for svideo
	switch (nInput)
	{
	case SOURCE_TUNER:
		BT848_AndDataByte(BT848_E_CONTROL, ~BT848_CONTROL_COMP);
		BT848_AndDataByte(BT848_O_CONTROL, ~BT848_CONTROL_COMP);
		MuxSel = GetCardSetup()->MuxSelect[GetCardSetup()->TunerInput & 7];
		break;
	case SOURCE_SVIDEO:
		BT848_OrDataByte(BT848_E_CONTROL, BT848_CONTROL_COMP);
		BT848_OrDataByte(BT848_O_CONTROL, BT848_CONTROL_COMP);
		MuxSel = GetCardSetup()->MuxSelect[GetCardSetup()->SVideoInput & 7];
		break;
	case SOURCE_COMPVIASVIDEO:
		BT848_AndDataByte(BT848_E_CONTROL, ~BT848_CONTROL_COMP);
		BT848_AndDataByte(BT848_O_CONTROL, ~BT848_CONTROL_COMP);
		MuxSel = GetCardSetup()->MuxSelect[GetCardSetup()->SVideoInput & 7];
		break;
	case SOURCE_COMPOSITE:
	case SOURCE_OTHER1:
	case SOURCE_OTHER2:
	case SOURCE_CCIR656:
	default:
		BT848_AndDataByte(BT848_E_CONTROL, ~BT848_CONTROL_COMP);
		BT848_AndDataByte(BT848_O_CONTROL, ~BT848_CONTROL_COMP);
		MuxSel = GetCardSetup()->MuxSelect[nInput];
		break;
	}
	
        printf( "BT848_SetVideoSource %d MuxSel %lx\n", nInput, MuxSel );
        
	BT848_MaskDataByte(BT848_IFORM, (BYTE) (((MuxSel) & 3) << 5), BT848_IFORM_MUXSEL);
	BT848_AndOrDataDword(BT848_GPIO_DATA, MuxSel >> 4, ~GetCardSetup()->GPIOMuxMask);
	return TRUE;
}

void BT848_SetGeometryEvenOdd(int bOdd, BYTE bVtc, int wHScale, int wVScale, int wHActive, int wVActive, int wHDelay, int wVDelay, BYTE bCrop)
{
	int nOff = bOdd ? 0x80 : 0x00;


	BT848_WriteByte(BT848_E_VSCALE_HI + nOff, 0xa0 );

	BT848_WriteByte(BT848_E_VTC + nOff, bVtc);
	BT848_WriteByte(BT848_E_HSCALE_HI + nOff, (BYTE) (wHScale >> 8));
	BT848_WriteByte(BT848_E_HSCALE_LO + nOff, (BYTE) (wHScale & 0xFF));
	BT848_MaskDataByte(BT848_E_VSCALE_HI + nOff, (BYTE) (wVScale >> 8), 0x1F);
	BT848_WriteByte(BT848_E_VSCALE_LO + nOff, (BYTE) (wVScale & 0xFF));
	BT848_WriteByte(BT848_E_HACTIVE_LO + nOff, (BYTE) (wHActive & 0xFF));
	BT848_WriteByte(BT848_E_HDELAY_LO + nOff, (BYTE) (wHDelay & 0xFF));
	BT848_WriteByte(BT848_E_VACTIVE_LO + nOff, (BYTE) (wVActive & 0xFF));
	BT848_WriteByte(BT848_E_VDELAY_LO + nOff, (BYTE) (wVDelay & 0xFF));
	BT848_WriteByte(BT848_E_CROP + nOff, bCrop);
}

int BT848_IsVideoPresent()
{
	return ((BT848_ReadByte(BT848_DSTATUS) & (BT848_DSTATUS_PRES | BT848_DSTATUS_HLOC)) == (BT848_DSTATUS_PRES | BT848_DSTATUS_HLOC)) ? TRUE : FALSE;
}

// Creates the RISC code
// First syncs to field
// Then waits for data
// Then tells the bt848 where to put each line of data
void BT848_CreateRiscCode(int nFlags)
{
	DWORD *pRiscCode;
	int nField;
	int nLine;
	LPBYTE pUser;
	PHYS pPhysical;
	DWORD GotBytesPerLine;
	DWORD BytesPerLine = 0;

	pRiscCode = (DWORD*) Risc_dma.dwUser;

	// we create the RISC code for 10 fields
	// the first one (0) is even
	// last one (9) is odd
	for(nField = 0; nField < 10; nField++)
	{
		// First we sync onto either the odd or even field
		if(nField & 1)
		{
			*(pRiscCode++) = (DWORD) (BT848_RISC_SYNC | BT848_RISC_RESYNC | BT848_FIFO_STATUS_VRO);
		}
		else
		{
			*(pRiscCode++) = (DWORD) (BT848_RISC_SYNC | BT848_RISC_RESYNC | BT848_FIFO_STATUS_VRE  | ((0xF1 + nField / 2) << 16));
		}
		*(pRiscCode++) = 0;

		// Create VBI code of required
		if (nField % 2 == 0 && nFlags & BT848_CAP_CTL_CAPTURE_VBI_EVEN ||
			nField % 2 == 1 && nFlags & BT848_CAP_CTL_CAPTURE_VBI_ODD)
		{
			*(pRiscCode++) = (DWORD) (BT848_RISC_SYNC | BT848_FIFO_STATUS_FM1);
			*(pRiscCode++) = 0;

			pUser = pVBILines[nField / 2];
			if(nField & 1)
			{
				pUser += CurrentVBILines * 2048;
			}
			for (nLine = 0; nLine < CurrentVBILines; nLine++)
			{
				pPhysical = GetPhysicalAddress(Vbi_dma[nField / 2], (UInt32) pUser, VBI_SPL, &GotBytesPerLine);
				if(pPhysical == 0 || VBI_SPL > GotBytesPerLine)
				{
					return;
				}
				*(pRiscCode++) = BT848_RISC_WRITE | BT848_RISC_SOL | BT848_RISC_EOL | BytesPerLine;
				*(pRiscCode++) = (UInt32) pPhysical;
				pUser += 2048;
			}
		}

		*(pRiscCode++) = (DWORD) (BT848_RISC_SYNC | BT848_FIFO_STATUS_FM1);
		*(pRiscCode++) = 0;


		// work out the position of the first line
		// first line is line zero an even line
		pUser = pDisplay[nField / 2];
		if(nField & 1)
		{
			pUser += 2048;
		}
		BytesPerLine = CurrentX * 2;
		for (nLine = 0; nLine < CurrentY / 2; nLine++)
		{

			pPhysical = GetPhysicalAddress(Display_dma[nField / 2], (UInt32) pUser, BytesPerLine, &GotBytesPerLine);
			if(pPhysical == 0 || BytesPerLine > GotBytesPerLine)
			{
				return;
			}
			*(pRiscCode++) = BT848_RISC_WRITE | BT848_RISC_SOL | BT848_RISC_EOL | BytesPerLine;
			*(pRiscCode++) = (UInt32) pPhysical;
			// since we are doing all the lines of the same
			// polarity at the same time we skip two lines
			pUser += 4096;
		}
	}

	BytesPerRISCField = ((long)pRiscCode - (long)Risc_dma.dwUser) / 10;
	*(pRiscCode++) = BT848_RISC_JUMP| BT848_RISC_IRQ | (2<<16) ;
	*(pRiscCode++) = (UInt32) RiscBasePhysical;

	BT848_WriteDword(BT848_RISC_STRT_ADD, (UInt32) RiscBasePhysical);
}

// Works out a field number between 0-9 indicating which field we are currently
// sending to memory
int BT848_GetRISCPosAsInt()
{
	int CurrentPos = 10;
	while(CurrentPos > 9)
	{
		DWORD CurrentRiscPos = BT848_ReadDword(BT848_RISC_COUNT);
		CurrentPos = (CurrentRiscPos - (DWORD)RiscBasePhysical) / BytesPerRISCField;
	}

	return CurrentPos;
}


#if defined WIN32

int Alloc_DMA(DWORD dwSize, PMemStruct * dma, int Option)
{
	*dma = NULL;

	memoryAlloc(dwSize, Option, dma);

	if (*dma == NULL)
	{
		return (FALSE);
	}
	return TRUE;
}

#else

int Alloc_DMA( DWORD size, PMemStruct * p, int flags )
{
    p->mLength = size/4096;
    
    if( size % 4096 )
        p->mLength++;
        
    return Bt8xxAllocPages( bt8xx_io_connect, p ) == KERN_SUCCESS;
}

#endif

#if defined WIN32

void Free_DMA(PMemStruct * dma)
{
	memoryFree(*dma);
}

#else

void Free_DMA( PMemStruct * p )
{
    Bt8xxFreePages( bt8xx_io_connect, p );
}

#endif

void Free_Display_DMA(int NR)
{
	if (Display_dma[NR].mLength == 0 )
	{
		return;
	}

	Free_DMA(&Display_dma[NR]);

	Display_dma[NR].mLength = 0;
}

#if ! defined WIN32

PHYS GetPhysicalAddress( PMemStruct m, DWORD adr, unsigned size, void * unused )
{
    DWORD offset = adr - m.mVirtUser;
    
    return (PHYS) ( DWORD) m.mPhysAddr + offset;
}

#else

PHYS GetPhysicalAddress(PMemStruct pMem, LPBYTE pLinear, DWORD dwSizeWanted, DWORD * pdwSizeAvailable)
{
	PPageStruct pPages = (PPageStruct)(pMem + 1);
	DWORD Offset;
        DWORD i; 
        DWORD sum;
	DWORD pRetVal = 0;

	Offset = (DWORD)pLinear - (DWORD)pMem->dwUser;
        sum = 0; 
	i = 0;
	while (i < pMem->dwPages)
	{
		if (sum + pPages[i].dwSize > (unsigned)Offset)
		{
                    Offset -= sum;
		    pRetVal = pPages[i].dwPhysical + Offset;	
                    
                    if ( pdwSizeAvailable != NULL )
			{
				*pdwSizeAvailable = pPages[i].dwSize - Offset;
			}
			break;
		}
		sum += pPages[i].dwSize; 
		i++;
	}
	if(pRetVal == 0)
	{
		sum++;
	}
        
        if ( pdwSizeAvailable != NULL )
	{
		if (*pdwSizeAvailable < dwSizeWanted)
		{
			sum++;
		}
	}

	return pRetVal;	
}
#endif

// JA 29/12/2000
// This function returns the user space address of the first page aligned
// section of an allocated buffer.

#if defined WIN32

void* GetFirstFullPage(PMemStruct pMem)
{
	PPageStruct pPages = (PPageStruct)(pMem + 1);
	DWORD pRetVal;

	pRetVal = (DWORD)pMem->dwUser;

	if(pPages[0].dwSize != 4096)
	{
		pRetVal += pPages[0].dwSize;
	}
	return (void*)pRetVal;	
}

#else
void* GetFirstFullPage(PMemStruct pMem)
{
    return (void*) pMem.mVirtUser;
}
#endif

void BT848_Close()
{
    Stop_Capture();

    IOServiceClose( bt8xx_io_connect);
}

int BT848_Open(DWORD dwVendorID, DWORD dwDeviceID, DWORD options, int Lock)
{
    UInt32 id;
    
    if( Bt8xxGetDeviceID( bt8xx_io_connect, &id ) == KERN_SUCCESS ) {
        
        return ( id == ( ( dwVendorID << 16 ) | dwDeviceID ));
    }
    return false;
}

int BT848_Init()
{
    if( bt8xx_io_connect == 0 ) {
    
        kern_return_t       ret;
        io_iterator_t       cards;
        io_registry_entry_t card;
        
        ret = IOMasterPort(bootstrap_port, &master_port);
  
        if( ret != KERN_SUCCESS ) {
    
            fprintf(stderr, "Failed to get master device port.\n" );
            return ret;
        }
    

        ret = IOServiceGetMatchingServices( master_port, IOServiceNameMatching("Bt8xx"), &cards );

        if( ret != KERN_SUCCESS ) {
            fprintf(stderr, "Failed to get an iterator for the cards.\n" );
            return ret;
        }
  
        while (1) {
    
            card = IOIteratorNext(cards);
  
            if (card == 0) break;
    
            break;
        }
  
        if (card == 0) {

            IOObjectRelease(card);
        
            return -1;
        }

        ret = IOServiceOpen(card, mach_task_self(), 0, &bt8xx_io_connect);
 
        if( ret != kIOReturnSuccess ) {

            printf("Failed to make a bt8xx_io_connection to the card(%x)\n", card);
            return ret;
        }

#if 0   
        BT848_MemoryInit();
    
        {
            int nFlags = BT848_CAP_CTL_CAPTURE_EVEN | BT848_CAP_CTL_CAPTURE_ODD;

            if (Capture_VBI == TRUE)
            {
                    nFlags |= BT848_CAP_CTL_CAPTURE_VBI_EVEN | BT848_CAP_CTL_CAPTURE_VBI_ODD;
            }

            BT848_MaskDataByte(BT848_CAP_CTL, 0, 0x0f);

            BT848_CreateRiscCode(nFlags);

        }
#endif   
    }
    
    return 0;
}

void BT848_MaskDataByte(int Offset, BYTE d, BYTE m)
{
	BYTE a;

	a = BT848_ReadByte(Offset);
	a = (a & ~(m)) | ((d) & (m));
	BT848_WriteByte(Offset, a);
}

void BT848_MaskDataWord(int Offset, WORD d, WORD m)
{
	WORD a;

	a = BT848_ReadWord(Offset);
	a = (a & ~(m)) | ((d) & (m));
	BT848_WriteWord(Offset, a);
}
void BT848_AndOrDataDword(int Offset, DWORD d, DWORD m)
{
	DWORD a;

	a = BT848_ReadDword(Offset);
	a = (a & m) | d;
	BT848_WriteDword(Offset, a);
}

void BT848_AndDataByte(int Offset, BYTE d)
{
	BYTE a;

	a = BT848_ReadByte(Offset);
	a &= d;
	BT848_WriteByte(Offset, a);
}

void BT848_AndDataWord(int Offset, short d)
{
	WORD a;

	a = BT848_ReadWord(Offset);
	a &= d;
	BT848_WriteWord(Offset, a);
}

void BT848_OrDataByte(int Offset, BYTE d)
{
	BYTE a;

	a = BT848_ReadByte(Offset);
	a |= d;
	BT848_WriteByte(Offset, a);
}

void BT848_OrDataWord(int Offset, unsigned short d)
{
	WORD a;

	a = BT848_ReadWord(Offset);
	a |= d;
	BT848_WriteWord(Offset, a);
}

//===========================================================================
// Enable CCIR656 Input mode
//===========================================================================
int BT848_Enable656()
{
	int vscale, hscale;
	int hdelay, vdelay;
	int hactive, vactive;
	BYTE crop;
	int i;

	CurrentX = 720;
	CurrentY = 480;

	// Disable TG mode
	BT848_MaskDataByte(BT848_TGCTRL, 0, BT848_TGCTRL_TGMODE_ENABLE);
	
	// Reset the TG address
	BT848_MaskDataByte(BT848_TGCTRL, 0, BT848_TGCTRL_TGMODE_RESET);
	BT848_MaskDataByte(BT848_TGCTRL, BT848_TGCTRL_TGMODE_RESET, BT848_TGCTRL_TGMODE_RESET);
	BT848_MaskDataByte(BT848_TGCTRL, 0, BT848_TGCTRL_TGMODE_RESET);

	// Load up the TG table for CCIR656
	for (i=0;i<SRAMTable[0];++i)
	{
	  BT848_WriteByte(BT848_TBLG,SRAMTable[i+1]);
	}
	
	// Enable TG mode
	BT848_MaskDataByte(BT848_TGCTRL, BT848_TGCTRL_TGMODE_ENABLE, BT848_TGCTRL_TGMODE_ENABLE);

	// Enable the GPCLOCK
	BT848_MaskDataByte(BT848_TGCTRL, BT848_TGCTRL_TGCKI_GPCLK, BT848_TGCTRL_TGCKI_GPCLK);

	// Set the PLL mode
	BT848_WriteByte(BT848_PLL_XCI, 0x00);

	// Enable 656 Mode, bypass chroma filters
	BT848_WriteByte(BT848_DVSIF, BT848_DVSIF_VSIF_BCF | BT848_DVSIF_CCIR656);
	
	// Enable NTSC mode
	BT848_MaskDataByte(BT848_IFORM, (BT848_IFORM_NTSC | BT848_IFORM_XTBOTH), (BT848_IFORM_NORM | BT848_IFORM_XTBOTH));

	// Disable full range luma
	BT848_WriteByte(BT848_OFORM, 0);

	// Enable the SC loop luma peaking filters
	BT848_WriteByte(BT848_E_SCLOOP, BT848_SCLOOP_LUMA_PEAK);
	BT848_WriteByte(BT848_O_SCLOOP, BT848_SCLOOP_LUMA_PEAK);

	// Standard NTSC 525 line count
	BT848_WriteByte(BT848_VTOTAL_LO, 0x00);
	BT848_WriteByte(BT848_VTOTAL_HI, 0x00);

	// YUV 4:2:2 linear pixel format
	BT848_WriteByte(BT848_COLOR_FMT, (BYTE)((BT848_COLOR_FMT_YUY2 << 4) | BT848_COLOR_FMT_YUY2));

	// Setup parameters for overlay scale and crop calculation
	hactive = CurrentX;
	vactive = CurrentY;
	hscale = 0;
	vdelay = 16;
	hdelay = 0x80;
	vscale = 0;

	crop = ((hactive >> 8) & 0x03) | ((hdelay >> 6) & 0x0c) | ((vactive >> 4) & 0x30) | ((vdelay >> 2) & 0xc0);

	BT848_SetGeometryEvenOdd(FALSE, BT848_VTC_HSFMT_32, hscale, vscale, hactive, vactive, hdelay, vdelay, crop);
	BT848_SetGeometryEvenOdd(TRUE, BT848_VTC_HSFMT_32, hscale, vscale, hactive, vactive, hdelay, vdelay, crop);

	return TRUE;
}

TTVFORMAT* BT848_GetTVFormat()
{
	return TVFormats + TVFormat;
}

int VideoSource_OnChange(long NewValue)
{
	Stop_Capture();
	VideoSource = NewValue;

	switch(NewValue)
	{
	case SOURCE_TUNER:
        
		BT848_ResetHardware();
	
                BT848_SetGeoSize();
		                
		if(Audio_MSP_IsPresent())
		{
			AudioSource = AUDIOMUX_MSP_RADIO;
		}
		else
		{
			AudioSource = AUDIOMUX_TUNER;
		}
		break;

            // MAE 13 Dec 2000 for CCIR656 Digital input
        case SOURCE_CCIR656:
        
		BT848_ResetHardware();
	
                BT848_Enable656();
		
                AudioSource = AUDIOMUX_EXTERNAL;
		break;
/*
        // FIXME: We really need separate picture settings for each input.
		// Reset defaults for brightness, contrast, color U and V
		InitialBrightness = 0;
		InitialContrast = 0x80;
		InitialSaturationU = 0x80;
		InitialSaturationV = 0x80;
		BT848_SetBrightness(InitialBrightness);
		BT848_SetContrast(InitialContrast);
		BT848_SetSaturationU(InitialSaturationU);
		BT848_SetSaturationV(InitialSaturationV);
*/

	case SOURCE_COMPOSITE:
	case SOURCE_SVIDEO:
	case SOURCE_OTHER1:
	case SOURCE_OTHER2:
	case SOURCE_COMPVIASVIDEO:
		
            BT848_ResetHardware();

            BT848_SetGeoSize();

            AudioSource = AUDIOMUX_EXTERNAL;
            
            break;
	default:
            break;
	}

	//if(!System_In_Mute)
	{
                printf("AudioSource is %ld\n", AudioSource);
		Audio_SetSource(AudioSource);
	}
	Start_Capture();
	return FALSE;
}


int TVFormat_OnChange(long NewValue)
{
    
    Stop_Capture();

    TVFormat = NewValue;
    
    BT848_SetGeoSize();

    
    Start_Capture();
    
    return FALSE;
}

int CurrentX_OnChange(long NewValue)
{
	CurrentX = NewValue;
	if(CurrentX != 768 &&
		CurrentX != 720 &&
		CurrentX != 640 &&
		CurrentX != 384 &&
		CurrentX != 320)
	{
		CustomPixelWidth = CurrentX;
	}

	Stop_Capture();

	BT848_SetGeoSize();


	Start_Capture();

	return FALSE;
}



/////////////////////////////////////////////////////////////////////////////
// Start of Settings related code
/////////////////////////////////////////////////////////////////////////////

SETTING BT848Settings[BT848_SETTING_LASTONE] =
{
	{
		"Brightness", SLIDER, 0, &InitialBrightness,
		DEFAULT_BRIGHTNESS_NTSC, -128, 127, 10, NULL,
		"Hardware", "InitialBrightness", BT848_Brightness_OnChange,
	},
	{
		"Contrast", SLIDER, 0, &InitialContrast,
		DEFAULT_CONTRAST_NTSC, 0, 255, 10, NULL,
		"Hardware", "InitialContrast", BT848_Contrast_OnChange,
	},
	{
		"Hue", SLIDER, 0, &InitialHue,
		DEFAULT_HUE_NTSC, -128, 127, 10, NULL,
		"Hardware", "InitialHue", BT848_Hue_OnChange,
	},
	{
		"Saturation", SLIDER, 0, &InitialSaturation,
		(DEFAULT_SAT_V_NTSC + DEFAULT_SAT_U_NTSC) / 2, 0, 255, 10, NULL,
		NULL, NULL, BT848_Saturation_OnChange,
	},
	{
		"SaturationU", SLIDER, 0, &InitialSaturationU,
		DEFAULT_SAT_U_NTSC, 0, 255, 10, NULL,
		"Hardware", "InitialSaturationU", BT848_SaturationU_OnChange,
	},
	{
		"SaturationV", SLIDER, 0, &InitialSaturationV,
		DEFAULT_SAT_V_NTSC, 0, 255, 10, NULL,
		"Hardware", "InitialSaturationV", BT848_SaturationV_OnChange,
	},
	{
		"BDelay", SLIDER, 0, &InitialBDelay,
		0, 0, 255, 10, NULL,
		"Hardware", "InitialBDelay", BT848_BDelay_OnChange,
	},
	{
		"BtAgcDisable", YESNO, 0, &BtAgcDisable,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtAgcDisable", BT848_Registers_OnChange,
	},
	{
		"BtCrush", YESNO, 0, &BtCrush,
		TRUE, 0, 1, 0, NULL,
		"Hardware", "BtCrush", BT848_Registers_OnChange,
	},
	{
		"BtEvenChromaAGC", YESNO, 0, &BtEvenChromaAGC,
		TRUE, 0, 1, 0, NULL,
		"Hardware", "BtEvenChromaAGC", BT848_Registers_OnChange,
	},
	{
		"BtOddChromaAGC", YESNO, 0, &BtOddChromaAGC,
		TRUE, 0, 1, 0, NULL,
		"Hardware", "BtOddChromaAGC", BT848_Registers_OnChange,
	},
	{
		"BtEvenLumaPeak", YESNO, 0, &BtEvenLumaPeak,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtEvenLumaPeak", BT848_Registers_OnChange,
	},
	{
		"BtOddLumaPeak", YESNO, 0, &BtOddLumaPeak,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtOddLumaPeak", BT848_Registers_OnChange,
	},
	{
		"BtFullLumaRange", YESNO, 0, &BtFullLumaRange,
		TRUE, 0, 1, 0, NULL,
		"Hardware", "BtFullLumaRange", BT848_Registers_OnChange,
	},
	{
		"BtEvenLumaDec", YESNO, 0, &BtEvenLumaDec,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtEvenLumaDec", BT848_Registers_OnChange,
	},
	{
		"BtOddLumaDec", YESNO, 0, &BtOddLumaDec,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtOddLumaDec", BT848_Registers_OnChange,
	},
	{
		"BtEvenComb", YESNO, 0, &BtEvenComb,
		TRUE, 0, 1, 0, NULL,
		"Hardware", "BtEvenComb", BT848_Registers_OnChange,
	},
	{
		"BtOddComb", YESNO, 0, &BtOddComb,
		TRUE, 0, 1, 0, NULL,
		"Hardware", "BtOddComb", BT848_Registers_OnChange,
	},
	{
		"BtColorBars", YESNO, 0, &BtColorBars,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtColorBars", BT848_Registers_OnChange,
	},
	{
		"BtGammaCorrection", YESNO, 0, &BtGammaCorrection,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtGammaCorrection", BT848_Registers_OnChange,
	},
	{
		"BtCoring", YESNO, 0, &BtCoring,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtCoring", BT848_Registers_OnChange,
	},
	{
		"BtHorFilter", YESNO, 0, &BtHorFilter,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtHorFilter", BT848_Registers_OnChange,
	},
	{
		"BtVertFilter", YESNO, 0, &BtVertFilter,
		FALSE, 0, 1, 0, NULL,
		"Hardware", "BtVertFilter", BT848_Registers_OnChange,
	},
	{
		"BtColorKill", YESNO, 0, &BtColorKill,
		TRUE, 0, 1, 0, NULL,
		"Hardware", "BtColorKill", BT848_Registers_OnChange,
	},
	{
		"BtWhiteCrushUp", SLIDER, 0, &BtWhiteCrushUp,
		0xcf, 0, 255, 10, NULL,
		"Hardware", "BtWhiteCrushUp", BT848_WhiteCrush_OnChange,
	},
	{
		"BtWhiteCrushDown", SLIDER, 0, &BtWhiteCrushDown,
		0x7f, 0, 255, 10, NULL,
		"Hardware", "BtWhiteCrushDown", BT848_WhiteCrush_OnChange,
	},
	{
		"Pixels per Line", SLIDER, 0, &CurrentX,
		720, 0, 768, 0, NULL,
		"MainWindow", "CurrentX", CurrentX_OnChange,
	},
	{
		"CustomPixelWidth", SLIDER, 0, &CustomPixelWidth,
		754, 0, 768, 0, NULL,
		"MainWindow", "CustomPixelWidth", NULL,
	},
	{
		"Video Source", SLIDER, 0, &VideoSource,
		SOURCE_COMPOSITE, SOURCE_TUNER, SOURCE_CCIR656, 0, NULL,
		"Hardware", "VideoSource", VideoSource_OnChange,
	},
	{
		"Video Format", NUMBER, 0, &TVFormat,
		FORMAT_NTSC, 0, FORMAT_LASTONE - 1, 0, NULL,
		"Hardware", "TVType", TVFormat_OnChange,
	},
};

SETTING* BT848_GetSettingByName( const char * name )
{
    int i;
    
    for( i = 0; i < BT848_SETTING_LASTONE; i++ ) {
        
        if( BT848Settings[i].szIniEntry && ! strcmp( BT848Settings[i].szIniEntry , name ) ) {
            return &BT848Settings[i];
        }
    }
    
    return 0;
}

SETTING* BT848_GetSetting(BT848_SETTING Setting)
{
	if(Setting >= 0 && Setting < BT848_SETTING_LASTONE)
	{
		return &(BT848Settings[Setting]);
	}
	else
	{
		return NULL;
	}
}

void MilliSleep( int msec )
{
    usleep( msec * 1000 );
}

void BT848_WriteByte( int reg, UInt8 data )
{
    Bt8xxWriteReg8( bt8xx_io_connect, reg, data);
}

void BT848_WriteWord( int reg, UInt16 data )  
{
    Bt8xxWriteReg16( bt8xx_io_connect, reg, data);
}

void BT848_WriteDword( int reg, UInt32 data ) 
{
    Bt8xxWriteReg32( bt8xx_io_connect, reg, data);
}

UInt8 BT848_ReadByte( UInt32 reg )
{
    UInt32 r = 0;
    
    Bt8xxReadReg8(bt8xx_io_connect, reg, &r );
    
    return ( r & 0xff );
}

UInt16 BT848_ReadWord( UInt32 reg )
{
    UInt32 r = 0;
    
    Bt8xxReadReg16(bt8xx_io_connect, reg, &r );
    
    return ( r & 0xffff );
}

UInt32 BT848_ReadDword( UInt32 reg )
{
    UInt32 r = 0;
    
    Bt8xxReadReg32(bt8xx_io_connect, reg, &r );
    
    return ( r );
}


int MapVBIMem( void ** buf, unsigned int * size )
{
    return Bt8xxMapVBIMem( bt8xx_io_connect, buf, size );
}


int MapVideoMem( void ** buf, unsigned int * size )
{
    return Bt8xxMapVideoMem( bt8xx_io_connect, buf, size );
}

int MapAudioMem( void ** buf, unsigned int * size )
{
    return Bt8xxMapAudioMem( bt8xx_io_connect, buf, size );
}

static void EnableInterrupts()
{

#define BT848_INT_RISCS   (0xf<<28)
#define BT848_INT_RISC_EN (1<<27)
#define BT848_INT_RACK    (1<<25)
#define BT848_INT_FIELD   (1<<24)
#define BT848_INT_SCERR   (1<<19)
#define BT848_INT_OCERR   (1<<18)
#define BT848_INT_PABORT  (1<<17)
#define BT848_INT_RIPERR  (1<<16)
#define BT848_INT_PPERR   (1<<15)
#define BT848_INT_FDSR    (1<<14)
#define BT848_INT_FTRGT   (1<<13)
#define BT848_INT_FBUS    (1<<12)
#define BT848_INT_RISCI   (1<<11)
#define BT848_INT_GPINT   (1<<9)
#define BT848_INT_I2CDONE (1<<8)
#define BT848_INT_VPRES   (1<<5)
#define BT848_INT_HLOCK   (1<<4)
#define BT848_INT_OFLOW   (1<<3)
#define BT848_INT_HSYNC   (1<<2)
#define BT848_INT_VSYNC   (1<<1)
#define BT848_INT_FMTCHG  (1<<0)


// BT848_INT_GPINT laesst den Rechnder stehen

#define BT848_INT_ENABLE ( BT848_INT_OCERR | BT848_INT_RISCI| BT848_INT_VSYNC | BT848_INT_HLOCK | BT848_INT_SCERR | BT848_INT_FMTCHG | BT848_INT_VPRES | BT848_INT_I2CDONE )
                        
    BT848_WriteDword(BT848_INT_STAT, (UInt32) BT848_INT_ENABLE );
    BT848_WriteDword(BT848_INT_MASK, (UInt32) BT848_INT_ENABLE );

}

void Start_Capture()
{
    
    int fmt = kBtPAL;

#if 0
    
    switch( TVFormat ) {
    case FORMAT_PAL_BDGHI:
    case FORMAT_SECAM:
    case FORMAT_PAL_M:
        fmt = kBtPAL;
        break;
    case FORMAT_PAL_N:
    case FORMAT_PAL60:
    case FORMAT_NTSC:
    case FORMAT_NTSC_J:
        fmt = kBtNTSC;
        break;
    }
#endif

    usleep( 250 * 1000 );
    
    Bt8xxSetup( bt8xx_io_connect, fmt, ColorFormat );

    BT848_ResetHardware();

    BT848_Restart_RISC_Code();
    
    BT848_SetVideoSource( 0 );
        
    Audio_SetSource( 0 );

#if 0
    if( Audio_MSP_Init(0x80, 0x81) == TRUE) {
        printf("MSP Device OK\n");
        Audio_SetVolume(InitialVolume);
    }
    else {
        printf("No MSP Device\n");
    }
#endif

#define HAUP_REMOTE_INT_WADDR 0x30
#define HAUP_REMOTE_INT_RADDR 0x31

#define HAUP_REMOTE_EXT_WADDR 0x34
#define HAUP_REMOTE_EXT_RADDR 0x35

    
    Bt8xxStart( bt8xx_io_connect );

    EnableInterrupts();
    
    {
        int i;
        
        for( i = 128; i < 256 ; i++ ) {
            if( I2CBus_AddDevice( i ) ) {
                printf("found I2C device %x\n", i );
            }
        }
    }

}

void Stop_Capture()
{
    Bt8xxStop( bt8xx_io_connect );

    usleep( 250 * 1000 );
}

void Reset_Capture()
{
    Stop_Capture();
    Start_Capture();
}

int BT848_IRQWait()
{
    int rc = Bt8xxIrqWait( bt8xx_io_connect );
    
    if( rc != KERN_SUCCESS ) {
        return rc;
    }
    else {
    
        UInt32 stat= BT848_ReadDword(  BT848_INT_STAT );
    
        UInt32 mask= BT848_ReadDword(  BT848_INT_MASK ); 
    
        UInt32 astat = stat&mask;
    
        if ( astat != 0  ) {
     
            BT848_WriteDword(  BT848_INT_STAT, stat );

            if( astat & BT848_INT_RISCI )  {

                if( stat&(2<<28) ) {

                    puts("field captured" );
                }
            }
        }
#if 0
        else {
    
            stat= readAudioReg32( kBtIntStat );
    
            mask= readAudioReg32( kBtIntMask ); 
    
            astat = stat&mask;
    
            if ( astat == 0 ) {
                IOErr("Bt8xxImpl::handleInterrupt spurious/shared int(%lx) mask(%lx)\n", stat, mask );
                return;
            }
 
            writeAudioReg32( kBtIntStat, stat );

            //IOLog("Bt8xxImpl::handleInterrupt audio-irq irq(%lx) mask(%lx)\n", stat, mask );
    
            if( stat & BT848_INT_RISCI )  {

                audioCaptured( stat );
            
        
                //IOLog("Bt8xxImpl::handleInterrupt audio-irq BT848_INT_RISCI state(%lx) block(%d)\n", 
                //stat, blocks );
            }
        }
#endif
    }
    return 0;
}

int BT848_Wait4Video()
{
    return Bt8xxWait4Video( bt8xx_io_connect );
}

int BT848_Wait4VBI()
{
    return Bt8xxWait4VBI( bt8xx_io_connect );
}

int BT848_ReadAudio( UInt32 * buffer, UInt32 count )
{
    return Bt8xxReadAudio( bt8xx_io_connect, buffer, count  );        
}


void ErrorBox( const char * text ) 
{
    if( userErrorBox != NULL ) {
        userErrorBox( text );
    }
    else {
        fprintf( stderr, "%s\n", text );
    }
}