/******************************************************************************* * Vt1622 VT1622 TV Chip register tool * T.Barnaby, BEAM Ltd, 15/10/04 ******************************************************************************* * * Copyright (c) 2004-2005 The Unichrome Project [unichrome.sf.net] * * Some code was derived from and inspired by the Xservers I2C interface * as coded in xf86i2c.c (c) 1998 Itai Nahshon, Michael Schimek * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ /* * This program allows you to display and change some of the VIA VT1622's * device registers and the associated VGA CRT registers. * * * Note: Needs to be run as root to gain access to device I/O space. * * WARNING: Playing around with TV settings could seriously damage your TV ! * * */ /* * Some VT1622A registers that are different: * 0x05, 0x06, 0x1F,0x4A,0x4B * 0x14 (PLL_N) reg is half the value of VT1622 */ #include #include #include #include #include #include #include #define VERSION "1.0.5" #define VT1622A 0 // Add code for VT1622A setup (not tested) #define DEBUG 0 #define TESTREGS 0 // Use program arrys for register info #define CRTC_SECONDARY 0 // Use the CLE266's secondary CRTC registers // This has not been tested #define NTSC1 0 // Setup different NTSC settings #define NTSC2 0 // Setup different NTSC settings #define NTSC3 0 // Setup different NTSC settings #if DEBUG #define dprintf(fmt, a...) printf(fmt, ##a); #else #define dprintf(fmt, a...) #endif typedef int Bool; #define TRUE 1 #define FALSE 0 /******************************************************************************* * VGA CRTC Register output routines ******************************************************************************* */ int crtcRead(unsigned int address, unsigned char* data){ #if TESTREGS *data = crtcRegs[address]; #else #if CRTC_SECONDARY outb(0x50 + address, 0x3D4); #else outb(address, 0x3D4); #endif *data =inb(0x3D5); #endif return 0; } unsigned char crtcReadRet(unsigned int address){ unsigned char data; crtcRead(address, &data); return data; } int crtcWrite(unsigned int address, unsigned char data){ #if TESTREGS crtcRegs[address] = data; #else #if CRTC_SECONDARY outb(0x50 + address, 0x3D4); #else outb(address, 0x3D4); #endif outb(data, 0x3D5); #endif return 0; } /******************************************************************************* * I2C Output routines ******************************************************************************* */ #define HoldTime 4 #define RiseFallTime 2 #define DDC_SDA_READ_MASK 0x04 #define DDC_SCL_READ_MASK 0x08 #define DDC_SDA_WRITE_MASK 0x10 #define DDC_SCL_WRITE_MASK 0x20 static usleep(int usecs){ while(usecs--){ inb(0x3c4); } } static void printBits(){ unsigned char v; #if DEBUG outb(0x31, 0x3c4); v = inb(0x3C5); printf("Bits: %2.2x\n", v); #endif } static void putBits(int clock, int data){ unsigned char value = 0x01; /* Enable DDC */ unsigned char v; if(clock & 1) value |= DDC_SCL_WRITE_MASK; if(data & 1) value |= DDC_SDA_WRITE_MASK; outb(0x31, 0x3c4); v = inb(0x3C5) & ~(DDC_SCL_WRITE_MASK|DDC_SDA_WRITE_MASK|0x01); v = v | value; outb(v, 0x3C5); } static void getBits(int* clock, int* data){ unsigned char value; outb(0x31, 0x3c4); value = inb(0x3c5); *clock = (value & DDC_SCL_READ_MASK) != 0; *data = (value & DDC_SDA_READ_MASK) != 0; } static Bool i2cRaiseSCL(int data){ int c; int d; int to = 3000; putBits(1, data); usleep(RiseFallTime); while(1){ getBits(&c, &d); if(c) break; usleep(1000); if(to-- == 0){ printf("I2cRaiseSCL Timeout\n"); exit(1); } } return TRUE; } static Bool i2cPutByte(unsigned char data){ int b; int c; int d; int to = 3000; dprintf("PutByte: %x\n", data); // Send Data (only 8bit address supported) for(b = 7; b >= 0; b--){ putBits(0, data >> b); usleep(RiseFallTime); i2cRaiseSCL(data >> b); usleep(HoldTime); putBits(0, data >> b); usleep(HoldTime); } putBits(0, 1); usleep(RiseFallTime); putBits(1, 1); while(1){ getBits(&c, &d); if(d == 0) break; usleep(1000); if(to-- == 0){ printf("PutByte: Timeout\n"); exit(1); } } putBits(0, 1); usleep(HoldTime); return TRUE; } static Bool i2cGetByte(unsigned char* data, int last){ int c; int d; int b; dprintf("GetByte: last: %d\n", last); putBits(0, 1); usleep(RiseFallTime); // Read Data *data = 0; for(b = 7; b >= 0; b--){ i2cRaiseSCL(1); usleep(HoldTime); getBits(&c, &d); *data |= (d << b); putBits(0, 1); usleep(HoldTime); } // Send Stop bit putBits(0, last); usleep(RiseFallTime); putBits(1, last); usleep(HoldTime); putBits(0, last); usleep(HoldTime); return TRUE; } static Bool i2cAddress(int addr) { // Send Start printBits(); i2cRaiseSCL(1); putBits(1, 0); usleep(HoldTime); printBits(); putBits(0, 0); usleep(HoldTime); printBits(); return i2cPutByte(addr); } static Bool i2cProbe(int address){ int r; r = i2cAddress(address); if(r){ // Send Stop putBits(0, 0); usleep(RiseFallTime); putBits(1, 0); usleep(HoldTime); putBits(1, 1); usleep(HoldTime); } return r; } static Bool i2cWriteRead(int address, unsigned char* WriteBuffer, int nWrite, unsigned char* ReadBuffer, int nRead) { Bool r = TRUE; int s = 0; if (r && nWrite > 0) { dprintf("i2cWriteRead: Send Data\n"); r = i2cAddress(address & ~1); if (r) { for (; nWrite > 0; WriteBuffer++, nWrite--) if (!(r = i2cPutByte(*WriteBuffer))) break; s++; } } if (r && nRead > 0) { dprintf("i2cWriteRead: Read Data\n"); r = i2cAddress(address | 1); if (r) { for (; nRead > 0; ReadBuffer++, nRead--) if (!(r = i2cGetByte(ReadBuffer, nRead == 1))) break; s++; } } if (s){ // Send Stop putBits(0, 0); usleep(RiseFallTime); putBits(1, 0); usleep(HoldTime); putBits(1, 1); usleep(HoldTime); } return r; } /******************************************************************************* * TV Register IO routines ******************************************************************************* */ static int tvRead(unsigned int add, unsigned char* data){ unsigned char txbuf[2]; unsigned char rxbuf[2]; #if TESTREGS *data = tvRegs[add]; #else txbuf[0] = add; i2cWriteRead(0x40, txbuf, 1, rxbuf, 1); *data = rxbuf[0]; #endif return 0; } static unsigned char tvReadRet(unsigned int add){ unsigned char v; tvRead(add, &v); return v; } static int tvWrite(unsigned int add, unsigned char data){ unsigned char txbuf[2]; #if TESTREGS tvRegs[add] = data; #else txbuf[0] = add; txbuf[1] = data; i2cWriteRead(0x40, txbuf, 2, NULL, 0); #endif return 0; } /******************************************************************************* * Generic Register IO routines ******************************************************************************* */ typedef struct { int address; int lowBit; int numBits; } RegBits; typedef struct { char* name; int (*readFunc)(unsigned int address, unsigned char* data); int (*writeFunc)(unsigned int address, unsigned char data); RegBits bits[6]; } RegSetup; RegSetup regSetup[] = { { "CRTC_HTOTAL", crtcRead, crtcWrite, { {0x00,0,8},{0xFF}} }, { "CRTC_HEND", crtcRead, crtcWrite, { {0x01,0,8},{0xFF}} }, { "CRTC_HSTART_BLANK", crtcRead, crtcWrite, { {0x02,0,8},{0xFF}} }, { "CRTC_HEND_BLANK", crtcRead, crtcWrite, { {0x33,5,1},{0x05,7,1},{0x03,0,5},{0xFF}} }, { "CRTC_HSTART_SYNC", crtcRead, crtcWrite, { {0x33,4,1},{0x04,0,8},{0xFF}} }, { "CRTC_HEND_SYNC", crtcRead, crtcWrite, { {0x05,0,5},{0xFF}} }, { "CRTC_VTOTAL", crtcRead, crtcWrite, { {0x35,0,1},{0x07,5,1},{0x07,0,1},{0x06,0,8},{0xFF}} }, { "CRTC_VEND", crtcRead, crtcWrite, { {0x07,6,1},{0x07,1,1},{0x12,0,8},{0xFF}} }, { "CRTC_VSTART_BLANK", crtcRead, crtcWrite, { {0x15,0,8},{0xFF}} }, { "CRTC_VEND_BLANK", crtcRead, crtcWrite, { {0x16,0,8},{0xFF}} }, { "CRTC_VSTART_SYNC", crtcRead, crtcWrite, { {0x35,1,1},{0x07,7,1},{0x07,2,1},{0x10,0,8},{0xFF}} }, { "CRTC_VEND_SYNC", crtcRead, crtcWrite, { {0x11,0,4},{0xFF}} }, { "CRTC_VMAX_SCAN_LINE", crtcRead, crtcWrite, { {0x09,0,8},{0xFF}} }, { "PLL_N", tvRead, tvWrite, { {0x15,0,2},{0x14,0,8},{0xFF}} }, { "PLL_D", tvRead, tvWrite, { {0x13,0,6},{0xFF}} }, { "PLL_P", tvRead, tvWrite, { {0x15,2,5},{0xFF}} }, { "PLL_P2", tvRead, tvWrite, { {0x12,0,5},{0xFF}} }, { "PLL_R", tvRead, tvWrite, { {0x12,5,3},{0xFF}} }, { "SUB_CARRIER", tvRead, tvWrite, { {0x19,0,8},{0x18,0,8},{0x17,0,8},{0x16,0,8}} }, { "SUB_CARRIER_PHASE", tvRead, tvWrite,{ {0x24,2,3},{0x22,0,8},{0xFF}} }, { "GH_TOTAL", tvRead, tvWrite, { {0x52,0,3},{0x50,0,8},{0xFF}} }, { "GH_ACTIVE", tvRead, tvWrite, { {0x52,4,2},{0x51,0,8},{0xFF}} }, { "GV_TOTAL", tvRead, tvWrite, { {0x54,0,3},{0x53,0,8},{0xFF}} }, { "TH_TOTAL", tvRead, tvWrite, { {0x58,0,3},{0x55,0,8},{0xFF}} }, { "TH_ACTIVE", tvRead, tvWrite, { {0x58,4,2},{0x56,0,8},{0xFF}} }, { "START_VIDEO", tvRead, tvWrite, { {0x1C,3,1},{0x07,0,8},{0xFF}} }, { "START_HORIZ", tvRead, tvWrite, { {0x1C,2,1},{0x08,0,8},{0xFF}} }, { "START_VERT", tvRead, tvWrite, { {0x1C,1,1},{0x09,0,8},{0xFF}} }, { "TVIDEO_START", tvRead, tvWrite, { {0x5D,4,1},{0x5B,0,8},{0xFF}} }, { "TVIDEO_END", tvRead, tvWrite, { {0x5D,0,4},{0x5C,0,8},{0xFF}} }, { "THSYNC_WIDTH", tvRead, tvWrite, { {0x57,0,8},{0xFF}} }, { "TBURST_START", tvRead, tvWrite, { {0x58,0,3},{0x59,0,8},{0xFF}} }, /* 0x58,0,3 appears shared with TH_TOTAL */ { "TBURST_END", tvRead, tvWrite, { {0x5D,6,1},{0x5A,0,8},{0xFF}} }, { "TV_BURST_STEP",tvRead, tvWrite, { {0x24,1,1},{0x21,0,8},{0xFF}} }, { "VSCALE_FAC", tvRead, tvWrite, { {0x60,0,4},{0x5E,0,8},{0xFF}} }, { "HSCALE_FAC", tvRead, tvWrite, { {0x60,4,3},{0x5F,0,8},{0xFF}} }, { "SH_TOTAL", tvRead, tvWrite, { {0x64,0,4},{0x63,0,8},{0xFF}} }, { "CR_AMP", tvRead, tvWrite, { {0x0A,0,8},{0xFF}} }, { "BLACK_LEVEL", tvRead, tvWrite, { {0x0B,0,8},{0xFF}} }, { "Y_AMP", tvRead, tvWrite, { {0x0C,0,8},{0xFF}} }, { "CB_AMP", tvRead, tvWrite, { {0x0D,0,8},{0xFF}} }, { "BLANK_LEVEL", tvRead, tvWrite, { {0x24,5,1},{0x23,0,8},{0xFF}} }, { "HUE", tvRead, tvWrite, { {0x11,0,3},{0x10,0,8},{0xFF}} }, { "INPUT_THRESHOLD", tvRead, tvWrite, { {0x4A,0,8},{0xFF}} }, { "INPUT_DELTA", tvRead, tvWrite, { {0x4B,0,8},{0xFF}} }, { 0 } }; static unsigned int bitMask[] = {0, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; int regRead(char* name, unsigned int* data){ RegSetup* r = regSetup; RegBits* b; int i; unsigned int v = 0; unsigned char t = 0; int ret = -1; while(r->name){ if(!strcmp(r->name, name)) break; r++; } if(r->name){ for(i = 0; (i < 4) && (r->bits[i].address != 0xFF); i++){ // printf("Read: Add: %x StartBit: %d NumBits: %d\n", r->bits[i].address, r->bits[i].lowBit, r->bits[i].numBits); r->readFunc(r->bits[i].address, &t); // printf("Read: %02.2x\n", t); t >>= r->bits[i].lowBit; t &= bitMask[r->bits[i].numBits]; v <<= r->bits[i].numBits; v |= t; // printf("V: %04.4x\n", v); } *data = v; ret = 0; } else { printf("Unable to read register: %s\n", name); } return ret; } unsigned int regReadRet(char* name){ unsigned int v; regRead(name, &v); return v; } int regWrite(char* name, unsigned int data){ RegSetup* r = regSetup; RegBits* b; int i; unsigned int v = data; unsigned char t = 0; unsigned char t1 = 0; int ret = -1; while(r->name){ if(!strcmp(r->name, name)) break; r++; } if(r->name){ for(i = 0; (i < 4) && (r->bits[i].address != 0xFF); i++); i--; for(; (i >= 0); i--){ r->readFunc(r->bits[i].address, &t1); t1 &= ~(bitMask[r->bits[i].numBits] << r->bits[i].lowBit); t = v & bitMask[r->bits[i].numBits]; t <<= r->bits[i].lowBit; t |= t1; r->writeFunc(r->bits[i].address, t); v >>= r->bits[i].numBits; } ret = 0; } else { printf("Unable to write register: %s\n", name); } return ret; } void regDisplay(){ RegSetup* r = regSetup; int data; while(r->name){ regRead(r->name, &data); printf("%-16.16s: %08.8x %d\n\r", r->name, data, data); r++; } } /******************************************************************************* * Setup routines ******************************************************************************* */ double clockFreq(int n, int d, int p){ // Work out clock double c = 14.31818e6; #if VT1622A return (c * n * 4) / (d * p); #else return (c * n * 2) / (d * p); #endif } /* * clockSet() This routine should calculate the register settings * for the VT1622 PLL clock. * It does not work as yet .... */ double clockSet(double freq, int* n, int* d, int* p){ double c = 14.31818e6; double e; double me = c; int tn; int td; int tp; int rn = 0; int rd = 0; int found = 0; for(tn = 1; tn < 1024; tn++){ for(td = 0; td < 3000; td += 2){ #if VT1622A e = fabs(freq - (c * 4 * tn) / td); #else e = fabs(freq - (c * 2 * tn) / td); #endif if(e < me){ rn = tn; rd = td; me = e; } } } // printf("Freq: %f (%f, %d %d)\n", freq / 1000000.0, ((c*2*rn)/rd) / 1000000.0, rn, rd); for(td = 1; !found && (td < 64); td++){ for(tp = 1; !found && (tp < 64); tp++){ if((td * tp) == rd){ *n = rn; *d = td; *p = tp; found = 1; } } } return (c * 2 * *n) / (*d * *p); } /* * setUp Sets up display for 720x576 PAL or 720x480 NTSC with no scaling * Note that this does not set all of the required VT1622 registers, * it assumes that the basic mode has been setup already and this * routine just mods those registers that required changing * to get eliminate scaling. */ void setUp(int ntsc){ double clock = 0.0; int h = 0; int hs = 0; int ht = 0; int v = 0; int vt = 0; int n = 0; int d = 0; int p = 0; int p2 = 0; int r = 7; double sc = 0.0; int t = 0; double vsync = 0; double subCarrier; double tvSyncWidth = 0.0; if(ntsc){ // Initial settings, Clock should be set for horizontal scaling // clock = clockSet(28e6, &n, &d, &p); n = 220; d = 25; p = 9; r = 5;// Should have routine to set clock ... #if NTSC2 n = 221; #endif h = 720; v = 480; vt = 525; #if NTSC3 vsync = 59.9; #else vsync = 60; #endif #if NTSC1 tvSyncWidth = 4.8e-6; #else tvSyncWidth = 4.6e-6; #endif subCarrier = 3.579545; } else { // Initial settings, Clock should be set for horizontal scaling // clock = clockSet(28e6, &n, &d, &p); printf("Clock: %f %d %d %d\n", clock, n, d, p); n = 220; d = 25; p = 9; r = 5;// Should have routine to set clock ... h = 720; v = 576; vt = 625; vsync = 50; tvSyncWidth = 5.25e-6; subCarrier = 4.43361875; } #if VT1622A // The VT1622A's PLL runs at 2x the VT1622's one. n = n / 2; #endif // Horizontal sync position #if NTSC1 hs = h + 32; #else hs = h + 16; #endif // Calculate bits p2 = p; clock = clockFreq(n, d, p); ht = round(clock / (vt * vsync)); #if ZAP ht += 8; #endif ht = ((ht + 4) / 8) * 8; // Need to change clock rates to rescale horizontal printf("CLK1: %f\n\r", clockFreq(n, d, p) / 1e6); printf("CLK2: %f\n\r", clockFreq(n, d, p2) / 1e6); printf("VSync: %f\n\r", (clock / (ht * vt)) / 2); printf("HSync: %f\n\r", ((clock / ht) / 2)); printf("HTotal: %d\n\r", ht); // Set clock regWrite("PLL_R", r); regWrite("PLL_D", d); regWrite("PLL_P", p); regWrite("PLL_P2", p2); regWrite("PLL_N", n); // Setup Graphics Input registers regWrite("CRTC_HEND", (h / 8) -1); regWrite("CRTC_HTOTAL", (ht / 8) - 5); regWrite("CRTC_VTOTAL", vt - 2); regWrite("GH_TOTAL", ht - 1); regWrite("GV_TOTAL", vt - 1); regWrite("GH_ACTIVE", h); // Setup TVOut Regs regWrite("TH_TOTAL", ht - 1); regWrite("TH_ACTIVE", h); regWrite("SH_TOTAL", ht - 1); regWrite("HSCALE_FAC", 0); regWrite("VSCALE_FAC", 0); // Setup Subcarrier sc = (pow(2.0, 32.0) * subCarrier * 1e6) / clock; regWrite("SUB_CARRIER", (int)sc); // Setup TvSync regWrite("THSYNC_WIDTH", (int)(clock * tvSyncWidth)); // Position, and Blanking regWrite("CRTC_HSTART_BLANK", (h / 8) - 1); regWrite("CRTC_HEND_BLANK", (ht / 8) - 1); regWrite("CRTC_HSTART_SYNC", (hs) / 8); regWrite("CRTC_HEND_SYNC", (hs + 32) / 8); regWrite("START_VERT", (vt / 2) + 2); regWrite("START_VIDEO", ht - hs); #if NTSC1 regWrite("START_HORIZ", ht - hs - 6); #else regWrite("START_HORIZ", ht - hs); #endif regWrite("TVIDEO_START", (ht - hs) * 2); regWrite("TVIDEO_END", (ht - hs + h) * 2); // Set up brightness and colour regWrite("Y_AMP", 73); // Manual regWrite("CR_AMP", 90); // Manual // Turn off de-flicker filter tvWrite(0x03, tvReadRet(0x03) & 0xFC); // Turn off input blurring tvWrite(0x00, tvReadRet(0x00) & 0x7F); #ifdef ZAP // Turn off Luma and Chroma filters tvWrite(0x04, tvReadRet(0x04) | 0x40); #endif } /******************************************************************************* * Test routines ******************************************************************************* */ void changeTvReg(){ int c; int a = 0; int v = 0; char buf[256]; printf("Enter Address: "); fgets(buf, sizeof(buf), stdin); sscanf(buf, "%x", &a); printf("Value: 0x%2.2x: 0x%2.2x\n\r", a, tvReadRet(a)); while(1){ printf("Enter Data (hex or q to quit): "); fgets(buf, sizeof(buf), stdin); if(buf[0] == 'q') break; sscanf(buf, "%x", &v); tvWrite(a, v); } } void changeParam(char* name){ int c; int v = 0; int ov; regRead(name, &v); ov = v; printf("Value: (q - quit) %d\n\r", v); while(1){ if((c=getchar()) != -1){ if(c == 'q') break; switch(c){ case 'u': v++; break; case 'd': v--; break; case 'U': v += 100; break; case 'D': v -= 100; break; case '0': v = 0; break; case 'o': v = ov; break; } printf("%d\n\r", v); regWrite(name, v); } } } void test(){ int c; int v = 0; int v1 = 0; int ov; char* regName = "PLL_R"; regRead(regName, &v); ov = v; printf("Value: (q - quit) %d\n\r", v); while(1){ if((c=getchar()) != -1){ if(c == 'q') break; switch(c){ case 'u': v++; break; case 'd': v--; break; case 'U': v += 100; break; case 'D': v -= 100; break; case '0': v = 0; break; case 'o': v = ov; break; } printf("%d\n\r", v); regWrite(regName, v); regRead("PLL_N", &v1); regWrite("PLL_N", v1); } } } static void display(){ int i; unsigned char v; int gw,tw; int vs,hs; int t; double clock; printf("TVRegs\n\r"); printf("0x%02x: ", 0); for(i = 0; i < 0x6B; i++){ v = tvReadRet(i); printf("%2.2x ", v); if((i % 16) == 15){ printf("\n\r0x%2x: ", i+1); } } printf("\n\r"); printf("CRTCRegs\n\r"); printf("0x%02x: ", 0); for(i = 0; i < 0x19; i++){ v = crtcReadRet(i); printf("%2.2x ", v); if((i % 16) == 15){ printf("\n\r0x%2x: ", i+1); } } printf("\n\r"); printf("CLK1: %f\n\r", clockFreq(regReadRet("PLL_N"), regReadRet("PLL_D"), regReadRet("PLL_P")) / 1000000); printf("CLK2: %f\n\r", clockFreq(regReadRet("PLL_N"), regReadRet("PLL_D"), regReadRet("PLL_P2")) / 1000000); regDisplay(); } unsigned char crtcRegsSave[0x19]; unsigned char tvRegsSave[0x6b]; void saveRegs(){ int i; for(i = 0; i < 0x19; i++){ crtcRegsSave[i] = crtcReadRet(i); } for(i = 0; i < 0x6b; i++){ tvRegsSave[i] = tvReadRet(i); } } void restoreRegs(){ int i; for(i = 0; i < 0x19; i++){ crtcWrite(i, crtcRegsSave[i]); } for(i = 0; i < 0x6b; i++){ tvWrite(i, tvRegsSave[i]); } } void regsDumpOld(){ FILE* file; int i; if(! (file = fopen("regsdump", "w"))){ fprintf(stderr, "Unable to open file regsdump for writing\n"); return; } fprintf(file, "CARD8 crtcRegs[] = { "); for(i = 0; i < 0x19; i++){ fprintf(file, "0x%02.2x,", crtcReadRet(i)); } fprintf(file, "};\n"); fprintf(file, "CARD8 tvRegs[] = { "); for(i = 0; i < 0x6b; i++){ fprintf(file, "0x%02.2x,", tvReadRet(i)); } fprintf(file, "};\n"); fclose(file); } void regsDump(int ntsc){ FILE* file; int i; int ha, ht, hss, hse; int va, vt, vss, vse; int c; ha = (regReadRet("CRTC_HEND") + 1) * 8; hss = (regReadRet("CRTC_HSTART_SYNC")) * 8; hse = regReadRet("CRTC_HSTART_SYNC"); while((hse & 0x001F) != regReadRet("CRTC_HEND_SYNC")) hse++; hse *= 8; ht = (regReadRet("CRTC_HTOTAL") + 5) * 8, va = regReadRet("CRTC_VEND") + 1; vss = regReadRet("CRTC_VSTART_SYNC"); vse = ((regReadRet("CRTC_VSTART_SYNC") + regReadRet("CRTC_VEND_SYNC") - 1) & 0xFFF0) + regReadRet("CRTC_VEND_SYNC"); vt = regReadRet("CRTC_VTOTAL") + 2; if(ntsc) c = (60 * ht * vt) / 1000; else c = (50 * ht * vt) / 1000; if(! (file = fopen("regsdump", "w"))){ fprintf(stderr, "Unable to open file regsdump for writing\n"); return; } fprintf(file, "{ MODEPREFIX(\"%dx%dNoscale\"), %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, V_NHSYNC | V_NVSYNC, %s },\n", ha, va, c, ha, hss, hse, ht, 0, va, vss, vse, vt, 0, ntsc?"MODESUFFIXNTSC":"MODESUFFIXPAL"); if(ntsc) fprintf(file, "{ \"%dx%dNoscale\", %d, %d, TVTYPE_NTSC, 0, 0,\n", ha, va, ha, va); else fprintf(file, "{ \"%dx%dNoscale\", %d, %d, TVTYPE_PAL, 0, 0,\n", ha, va, ha, va); fprintf(file, " { "); for(i = 0; i < 0x30; i++){ fprintf(file, "0x%02.2x, ", tvReadRet(i)); if(((i + 1) % 16) == 0) fprintf(file, "\n "); } fprintf(file, "}, \n"); fprintf(file, " { "); for(i = 0x4A; i < (0x4A + 0x1B); i++){ fprintf(file, "0x%02.2x, ", tvReadRet(i)); if((((i - 0x4A) + 1) % 16) == 0) fprintf(file, "\n "); } fprintf(file, " }, \n"); // Todo if(ntsc){ fprintf(file, " { 0xBA, 0xB8, 0xB8, 0x90, 0x99, 0 },\n"); fprintf(file, " { 0x58, 0x48, 0x49 },\n"); fprintf(file, " 0x%x, 0,\n", regReadRet("SUB_CARRIER")); fprintf(file, "},\n"); } else { fprintf(file, " 0, 0,\n"); fprintf(file, " 5, { 0xBA65, 0xB866, 0xB867, 0x9027, 0x992B, 0 },\n"); fprintf(file, " 3, { 0x5865, 0x4866, 0x4967 },\n"); fprintf(file, " 0x%x, 0,\n", regReadRet("SUB_CARRIER")); fprintf(file, "},\n"); } fclose(file); } void interactive(){ struct termios tioStd; struct termios tio; int c; tcgetattr(0, &tioStd); tcgetattr(0, &tio); cfmakeraw(&tio); tcsetattr(0, TCSANOW, &tio); saveRegs(); printf("Main commands are:\n\r"); printf("\tq - Quit\n\r"); printf("\tD - Display registers\n\r"); printf("\tA - Set regs for PAL 720x576\n\r"); printf("\tB - Set regs for NTSC 720x480\n\r"); printf("\tS - Save regs for PAL\n\r"); printf("\tT - Save regs for NTSC\n\r"); printf("\tC - Change a TV register\n\r"); printf("\t[1-z] - Change a particular register\n\r"); printf("See the source code for more info ....\n\r"); while(1){ printf("Enter Command Character: "); c = getchar(); printf("%c\n\r", c); if(c == 'q') break; switch(c){ case 'D': display(); break; case 'R': restoreRegs(); break; case 'S': regsDump(0); break; case 'T': regsDump(1); break; case 'C': tcsetattr(0, TCSANOW, &tioStd); changeTvReg(); tcsetattr(0, TCSANOW, &tio); break; // Setup to particular settings case 'A': setUp(0); break; case 'B': setUp(1); break; // Shift Registers case '1': changeParam("START_HORIZ"); break; case '2': changeParam("START_VERT"); break; // Scan rates and scaling registers case '3': changeParam("HSCALE_FAC"); break; case '4': changeParam("VSCALE_FAC"); break; case '5': changeParam("GH_ACTIVE"); break; case '6': changeParam("GH_TOTAL"); break; case '7': changeParam("GV_TOTAL"); break; case '8': changeParam("TH_TOTAL"); break; case '9': changeParam("SH_TOTAL"); break; case 'a': changeParam("TH_ACTIVE"); break; case 'b': changeParam("THSYNC_WIDTH"); break; case 'c': changeParam("TVIDEO_START"); break; case 'd': changeParam("TVIDEO_END"); break; case 'e': changeParam("START_VIDEO"); break; // Other regs case 'f': changeParam("Y_AMP"); break; case 'g': changeParam("CR_AMP"); break; case 'h': changeParam("CB_AMP"); break; case 'i': changeParam("BLACK_LEVEL"); break; case 'j': changeParam("SUB_CARRIER_PHASE"); break; case 'k': changeParam("INPUT_THRESHOLD"); break; case 'l': changeParam("INPUT_DELTA"); break; case 'm': changeParam("SUB_CARRIER"); break; case 'n': changeParam("TBURST_START"); break; case 'o': changeParam("TBURST_END"); break; case 'p': changeParam("HUE"); break; case 't': test(); break; } } tcsetattr(0, TCSANOW, &tioStd); } void testClockSet(){ int n, d, p; double f; f = clockSet(25.174822e6, &n, &d, &p); printf("Freq: %f (%d, %d %d)\n", f / 1000000.0, n, d, p); f = clockSet(27e6, &n, &d, &p); printf("Freq: %f (%d, %d %d)\n", f / 1000000.0, n, d, p); f = clockSet(30e6, &n, &d, &p); printf("Freq: %f (%d, %d %d)\n", f / 1000000.0, n, d, p); f = clockSet(33e6, &n, &d, &p); printf("Freq: %f (%d, %d %d)\n", f / 1000000.0, n, d, p); exit(1); } int main(int argc, char** argv){ int r; unsigned char v; int i; unsigned int d; // testClockSet(); printf("VT1622 Register display/change program: %s\n", VERSION); printf("Please look at source code for information ....\n"); printf("WARNING: Playing around with TV settings could seriously damage your TV !\n"); // VT1622 I2C control registers r = ioperm(0x3c4,2,1); printf("Enable IO Result: %d %s\n", r, strerror(errno)); // VGA CRTC registers r = ioperm(0x3d4,2,1); printf("Enable IO Result: %d %s\n", r, strerror(errno)); // display(); interactive(); return 0; }