#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include "main.h"
#include "defines.h"
#include "regdef.h"

void ReadCaptureRegs (void)
{
    WORD x, loop;
    DWORD temp;
    FILE *op;
    char *names[] = {
        "VID_BUFFER_CONTROL",
        "CAP_INT_CNTL",
        "CAP_INT_STATUS",
        "CAP0_BUF0_OFFSET",
        "CAP0_BUF1_OFFSET",
        "CAP0_BUF0_EVEN_OFFSET",
        "CAP0_BUF1_EVEN_OFFSET",
        "CAP0_BUF_PITCH",
        "CAP0_V_WINDOW",
        "CAP0_H_WINDOW",
        "CAP0_VBI_ODD_OFFSET",
        "CAP0_VBI_EVEN_OFFSET",
        "CAP0_VBI_V_WINDOW",
        "CAP0_VBI_H_WINDOW",
        "CAP0_PORT_MODE_CNTL",
        "CAP0_TRIG_CNTL",
        "CAP0_DEBUG",
        "CAP0_CONFIG",
        "CAP0_ANC_ODD_OFFSET",
        "CAP0_ANC_EVEN_OFFSET",
        "CAP0_ANC_H_WINDOW",
        "CAP0_VIDEO_SYNC_TEST",
        "CAP0_ONESHOT_BUF_OFFSET",
        "CAP0_BUF_STATUS",
        "CAP0_DWNSC_XRATIO",
        "CAP0_XSHARPNESS",
        NULL };

    op = fopen ("capregs.txt", "w");

    R128_WaitForFifo (1);
    temp = regr (0x900);
    fprintf (op, "\n%s = %8.8X", names[0], temp);
    R128_WaitForFifo (1);
    temp = regr (0x908);
    fprintf (op, "\n%s = %8.8X", names[1], temp);
    R128_WaitForFifo (1);
    temp = regr (0x90C);
    fprintf (op, "\n%s = %8.8X", names[2], temp);


    for (x = 0x0920, loop = 3; x < 0x097F; x+=4, loop++)
    {
        if (x == 0x974) x+=4;
        R128_WaitForFifo (1);
        temp = regr (x);
        fprintf (op, "\n%s = %8.8X", names[loop], temp);
    }

    for (x = 0x1; x < 0x14; x++)
    {
        //R128_WaitForFifo (1);
        temp = PLL_regr (x);
        fprintf (op, "\nPLL %2.2X: %8.8X", x, temp);
    }
    temp = regr (AMCGPIO_MASK);
    fprintf (op, "\nAMCGPIO_MASK = %8.8X", temp);

    temp = regr (AMCGPIO_A_REG);
    fprintf (op, "\nAMCGPIO_A_REG = %8.8X", temp);

    fclose (op);

}

void ReadBTRegs (void)
{
    BYTE data[16];
    BYTE test, retval, counter;
    FILE *op;
    _I2C_PACKET Packet;

    // we assume that I2C is up and running.
    op = fopen ("btregs.txt", "w");

    Packet.start = 1;
    Packet.stop = 1;
    Packet.data = data;

    for (test = 0; test < 0x1F; test++)
    {
        // we want to set the Bt819 to register 'test'
        data [0] = test;
        Packet.number_of_bytes = 1;
        Packet.address = AddressInfo.Decoder;
        counter = 0;
        do
        {
            //retval = I2C_Set (AIW_BT829_WRITE, 1, &data);
            retval = I2C_Set (&Packet);
            counter++;
        }
        while ((retval != I2C_DONE) && (counter < 5));

        // Now let's read the contents of register 'test' on the Bt819
        Packet.address = AddressInfo.Decoder | 0x1;
        Packet.number_of_bytes = 1;
        counter = 1;
        do
        {
            //retval = I2C_Get (AIW_BT829_READ, 1, &data);
            retval = I2C_Get (&Packet);
            counter++;
        }
        while ((retval != I2C_DONE) && (counter < 5));

        fprintf (op, "\nData read from register %2.2X: %2.2X", test, data[0]);

    }
}


void ReadOverlayRegs (void)
{
    DWORD temp, loop;
    FILE *op;
    _reg_name_offset ovregs[43] =
    {
        {"OV0_Y_X_START", 0x400 },
        {"OV0_Y_X_END", 0x404 },
        {"OV0_EXCLUSIVE_HORZ", 0x408},
        {"OV0_EXCLUSIVE_VERT", 0x40C},
        {"OV0_REG_LOAD_CNTL", 0x410},
        {"OV0_SCALE_CNTL", 0x420},
        {"OV0_V_INC", 0x424},
        {"OV0_P1_V_ACCUM_INIT", 0x428},
        {"OV0_P23_V_ACCUM_INIT", 0x42C},
        {"OV0_P1_BLANK_LINES_AT_TOP", 0x0430},
        {"OV0_P23_BLANK_LINES_AT_TOP", 0x0434},
        {"OV0_VID_BUF0_BASE_ADRS", 0x0440},
        {"OV0_VID_BUF1_BASE_ADRS", 0x0444},
        {"OV0_VID_BUF2_BASE_ADRS", 0x0448},
        {"OV0_VID_BUF3_BASE_ADRS", 0x044c},
        {"OV0_VID_BUF4_BASE_ADRS", 0x0450},
        {"OV0_VID_BUF5_BASE_ADRS", 0x0454},
        {"OV0_VID_BUF_PITCH0_VALUE", 0x0460},
        {"OV0_VID_BUF_PITCH1_VALUE", 0x0464},
        {"OV0_OCTWORDS_PER_LINE_M1", 0x046c},
        {"OV0_AUTO_FLIP_CNTRL", 0x0470},
        {"OV0_DEINTERLACE_PATTERN", 0x0474},
        {"OV0_H_INC", 0x0480},
        {"OV0_STEP_BY", 0x0484},
        {"OV0_P1_H_ACCUM_INIT", 0x0488},
        {"OV0_P23_H_ACCUM_INIT", 0x048c},
        {"OV0_P1_X_START_END", 0x0494},
        {"OV0_P2_X_START_END", 0x0498},
        {"OV0_P3_X_START_END", 0x049c},
        {"OV0_FILTER_CNTL", 0x04a0},
        {"OV0_FOUR_TAP_COEF_0", 0x04b0},
        {"OV0_FOUR_TAP_COEF_1", 0x04b4},
        {"OV0_FOUR_TAP_COEF_2", 0x04b8},
        {"OV0_FOUR_TAP_COEF_3", 0x04bc},
        {"OV0_FOUR_TAP_COEF_4", 0x04c0},
        {"OV0_COLOR_CNTL", 0x04e0},
        {"OV0_VIDEO_KEY_CLR", 0x04e4},
        {"OV0_VIDEO_KEY_MASK", 0x04e8},
        {"OV0_GRAPHICS_KEY_CLR", 0x04ec},
        {"OV0_GRAPHICS_KEY_MASK", 0x04f0},
        {"OV0_KEY_CNTL", 0x04f4},
        {"OV0_TEST", 0x04f8},
        {NULL, 0}
    };

    op = fopen ("ovregs.txt", "w");

    for (loop = 0; ovregs[loop].name != NULL; loop++)
    {
        R128_WaitForFifo (1);
        temp = regr (ovregs[loop].offset);
        fprintf (op, "\n%s: %8.8X", ovregs[loop].name, temp);
    }

    fclose (op);
}

void ReadI2CRegs (void)
{
    DWORD temp;

    temp = regr (I2C_CNTL_0);
    printf ("\nI2C_CNTL_0: %8.8X", temp);

    temp = regr (I2C_CNTL_1);
    printf ("\nI2C_CNTL_1: %8.8X", temp);

}


/****************************************************************************
 * R128_GetMMTable (_MMTABLE *mmtable)                                      *
 *  Function: retrieves the multimedia table from the BIOS, and copies it   *
 *            to the _MMTABLE structure pointed to by mmtable               *
 *    Inputs: _MMTABLE *mmtable - pointer to a _MMTABLE structure           *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void R128_GetMMTable (_MMTABLE *mmtable)
{
    DWORD ptr_addr;
    BYTE *ptr_to_header, *vidtbl_ptr;
    BYTE size;
	BYTE *rom_base;
	char *rom;
	int stage, i;
	char ati_rom_sig[] = "761295520";
	char R128_sig[] = "R128";

//    ptr_addr = 0xC000;
//    ptr_addr = ptr_addr << 4;
	for(ptr_addr = 0x000C0000; ptr_addr < 0x000F0000; ptr_addr += 0x00001000)
	{
		stage = 1;
		rom_base = (BYTE *)ptr_addr;
		if((*rom_base == 0x55) && (*(rom_base + 1) == 0xAA))
			stage = 2;
		if(stage != 2)
			continue;
		//Search for ATI signature
        for (i = 0; (i < 128 - strlen (ati_rom_sig)) && (stage != 3); i++)
        {
            if (ati_rom_sig[0] == *rom)
            {
                if (strncmp (ati_rom_sig, rom, strlen (ati_rom_sig)) == 0)
                {
                    stage = 3;          // Found ATI signature.
                } // if
            } // if
            rom++;
        } // for
        if (stage != 3) 
			continue;       // ATI signature not found.
        rom = rom_base;

        // Search for R128 signature (stage 3).
        for (i = 0; (i < 512) && (stage != 4); i++)
        {
            if (R128_sig[0] == *rom)
            {
                if (strncmp (R128_sig, rom, strlen (R128_sig)) == 0)
                {
                    stage = 4;          // Found R128 signature.
                } // if
            } // if
            rom++;
        } // for
        if (stage != 4) 
			continue;       // R128 signature not found.
		//Success
	    ptr_to_header = (BYTE *)(ptr_addr + *((DWORD *)(ptr_addr + 0x48)));
		vidtbl_ptr = (BYTE *)(ptr_addr + *((DWORD *)(ptr_to_header + 0x38)));

		// The multimedia table pointer is defined as being at offset 0x38
		// within the BIOS header.  There are actually two relevant bytes
		// (revision and size) that are at the multimedia table - 2 bytes.
		vidtbl_ptr -= 2; // back up two bytes to get table revision and size.
		size = *(vidtbl_ptr + 1) + 2; // add two for the revision and size bytes
		memcpy (mmtable, vidtbl_ptr, size);
	}

    return;
}

void R128_SetOverlayDetailedSurface (void)
{
    DWORD offset, offset2, offset3, offset4;
    DWORD SRCHEIGHT = 240;
    DWORD SRCWIDTH = 640;

    offset = R128_AdapterInfo.xres * R128_AdapterInfo.bytepp * R128_AdapterInfo.yres;
    offset2 = offset + R128_AdapterInfo.xres * R128_AdapterInfo.bytepp * SRCHEIGHT;
    offset3 = offset4 = offset2;
    //offset3 = R128_AdapterInfo.xres * R128_AdapterInfo.bytepp * SRCHEIGHT;
    //offset4 = R128_AdapterInfo.xres * R128_AdapterInfo.bytepp * (SRCHEIGHT+SRCHEIGHT/2);

    OverlayDescriptor.USE_DETAILED_SURFACE_DESCRIPTION = 1;
    OverlayDescriptor.AutoFlipVideoProvider = 0; // use cap port 0

    OverlayDescriptor.BaseOffsetOfSurface[0] = offset;
    OverlayDescriptor.BaseOffsetOfSurface[1] = offset2;
    OverlayDescriptor.BaseOffsetOfSurface[2] = offset3;
    OverlayDescriptor.BaseOffsetOfSurface[3] = offset4;
    OverlayDescriptor.PitchSelectOfSurface[0] = 0;
    OverlayDescriptor.PitchSelectOfSurface[1] = 0;
    OverlayDescriptor.TiledFlagOfSurface[0] = 0;
    OverlayDescriptor.TiledFlagOfSurface[1] = 0;
    OverlayDescriptor.SurfacePitch[0] = SRCWIDTH*2;
    OverlayDescriptor.SurfacePitch[1] = SRCWIDTH*2;
    R128_SetupOverlay (&OverlayDescriptor, &OverlayRegFields);

    OverlayRegFields.val_OV0_VID_PORT_SELECT = 0;
    OverlayRegFields.val_OV0_DEINT_PAT = 0xAAAAA;
    R128_WriteOverlayFields (&OverlayRegFields);

}


/****************************************************************************
 * R128_GetI2CAddressInfo (void)                                            *
 *  Function: Determine the I2C addresses of the board ID, video decoder,   *
 *            tuner, and audio chip.                                        *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void R128_GetI2CAddressInfo (void)
{
    BYTE retval, data[16];
    BYTE counter;
    _I2C_PACKET Packet;

    // First, determine the BOARD_ID.
    // Try 0x70 first.
    data[0] = 0;
    Packet.data = data;
    Packet.start = 1;
    Packet.stop = 1;
    Packet.address = 0x71;
    Packet.number_of_bytes = 1;
    counter = 0;
    do
    {
        retval = I2C_Get (&Packet);
        counter++;
    }
    while ((retval != I2C_DONE) && (counter < 5));

    if (data[0] == 0xFF)
    {
        data[0] = 0;
        Packet.address = 0x41;
        Packet.number_of_bytes = 1;
        do
        {
            retval = I2C_Get (&Packet);
            counter++;
        }
        while ((retval != I2C_DONE) && (counter < 5));

        if (data[0] == 0xFF)
        {
            AddressInfo.BoardID = 0;
        }
        else
        {
            AddressInfo.BoardID = 0x40;
        }

    }
    else
    {
        AddressInfo.BoardID = 0x70;
    }

    if (AddressInfo.BoardID != 0)
    {
        // Get I/O expander setting
        data[0] = 0;
        data[1] = 0;
        Packet.address = AddressInfo.BoardID | 0x1;
        Packet.number_of_bytes = 1;
        counter = 0;
        do
        {
            retval = I2C_Get (&Packet);
            counter++;
        }
        while ((retval != I2C_DONE) && (counter < 5));

        // enable access to the decoder.
        data[0] &= 0x7F;
        Packet.address = AddressInfo.BoardID;
        Packet.number_of_bytes = 1;
        counter = 0;
        do
        {
            retval = I2C_Set (&Packet);
            counter++;
        }
        while ((retval != I2C_DONE) && (counter < 5));
    }

} // R128_GetI2CAddressInfo ()...

void EnableDecoder(void)
{
    BYTE retval, data[16], counter;
    _I2C_PACKET Packet;

    if(AddressInfo.BoardID == 0)
    {
	data[0] = 0x16;
        Packet.start = 1;
        Packet.stop = 1;
        Packet.data = data;
        Packet.number_of_bytes = 1;
        Packet.address = AddressInfo.Decoder;
	counter = 0;
        do
        {
	    retval = I2C_Set(&Packet);
	    counter++;
        }
        while ((retval != I2C_DONE) && (counter < 5));

	Packet.address = AddressInfo.Decoder | 0x1;
	Packet.number_of_bytes = 1;
	counter = 0;
	do
	{
	    retval = I2C_Get(&Packet);
	    counter++;
	}
	while ((retval != I2C_DONE) && (counter < 5));

	data[1] = (data[0] & 0x7F) | 0x80;
	data[0] = 0x16;
        Packet.start = 1;
        Packet.stop = 1;
        Packet.data = data;
        Packet.number_of_bytes = 2;
        Packet.address = AddressInfo.Decoder;
	counter = 0;
        do
        {
	    retval = I2C_Set(&Packet);
	    counter++;
        }
        while ((retval != I2C_DONE) && (counter < 5));
    }
}

void DisableDecoder (void)
{
    BYTE retval, data[16], counter;
    _I2C_PACKET Packet;

    Packet.start = 1;
    Packet.stop = 1;
    Packet.data = data;
    Packet.number_of_bytes = 1;
    Packet.address = AddressInfo.BoardID | 0x1;
    // Get I/O expander setting
    data[0] = 0;
    do
    {
        retval = I2C_Get (&Packet);
    }
    while (retval != I2C_DONE);

    // disable access to the decoder.
    data[0] |= 0x80;
    Packet.address = AddressInfo.BoardID;
    counter = 0;
    do
    {
        retval = I2C_Set (&Packet);
        counter++;
    }
    while ((retval != I2C_DONE) && (counter < 5));

}

void GetCaptureCardType (void)
{
    DWORD ptr_addr, temp;
    BYTE *ptr_to_header, *vidtbl_ptr;
    BYTE retval;

    ptr_addr = 0xC000;
    ptr_addr = ptr_addr << 4;

    // Let's see first if there is an All-in-Wonder type card installed.
    // We'll check to see if there is a multimedia BIOS table, which
    // will tell us that an AiW is installed.  Otherwise, it's just a graphics
    // card, and we'll have to check to see if an I2C I/O expander is present
    // at address 0x70, to see if an ATI TV Tuner card is installed.
    temp = *((DWORD *)ptr_addr);
    printf("ptr_addr %x: %x\n",ptr_addr,temp);
    ptr_to_header = (BYTE *)(ptr_addr + *((DWORD *)(ptr_addr + 0x48)));
    temp = *((DWORD *)(ptr_to_header));
    printf("ptr_to_header %x: %x\n",ptr_to_header, temp);
    vidtbl_ptr = (BYTE *)(ptr_addr + *((DWORD *)(ptr_to_header + 0x38)));
    
    // if there's no mmtable in the BIOS, this should be 0.
    temp = (DWORD)((DWORD)vidtbl_ptr & 0x0000FFFF);
    printf("temp & 0x0000FFFF: %d\n",temp);
    if (temp != 0x0L)
    {
        AddressInfo.BoardID = 0;
        AddressInfo.Decoder = 0x8A;
        AddressInfo.Tuner = 0xC6;
    }
    else
    {
        retval = R128_IsTVTunerInstalled ();
        if (retval)
        {
            AddressInfo.Decoder = 0x88;
            AddressInfo.Tuner = 0xC0;
        }
        else
        {
            AddressInfo.Decoder = 0;
            AddressInfo.Tuner = 0;
        }
    }


} // GetCaptureCardType ()...

/****************************************************************************
 * R128_IsTVTunerInstalled (void)                                           *
 *  Function: checks relevant I2C address to see if an I/O expander is      *
 *            installed, thus detecting an ATI TV Tuner                     *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
BYTE R128_IsTVTunerInstalled (void)
{
    BYTE data[16];
    BYTE retval;
    _I2C_PACKET Packet;

    // See if the I/O expander is installed.
    Packet.address = 0x71;
    Packet.data = data;
    Packet.start = 1;
    Packet.stop = 1;
    Packet.number_of_bytes = 1;
    data[0] = 0;
    do
    {
        retval = I2C_Get (&Packet);
    }
    while (retval != I2C_DONE);

    // Try secondary I/O expander address if 0x71 returns 0xFF
    if (data[0] == 0xFF)
    {
        Packet.address = 0x41;
        do
        {
            retval = I2C_Get (&Packet);
        }
        while (retval != I2C_DONE);
    }

    if (data[0] != 0xFF)
    {
        return 1;
    }
    else
    {
        return 0;
    }

} // R128_IsTVTunerInstalled ()...
