#define GTF /* * Generic mode timing module. */ #include #include "timing.h" /* Types. */ #include "driver.h" /* for __svgalib_monitortype (remove me) */ /* Standard mode timings. */ MonitorModeTiming __svgalib_standard_timings[] = { #define S __svgalib_standard_timings /* 320x200 @ 70 Hz, 31.5 kHz hsync */ {12588, 320, 336, 384, 400, 200, 204, 206, 225, DOUBLESCAN, S + 1}, /* 320x200 @ 83 Hz, 37.5 kHz hsync */ {13333, 320, 336, 384, 400, 200, 204, 206, 225, DOUBLESCAN, S + 2}, /* 320x240 @ 60 Hz, 31.5 kHz hsync */ {12588, 320, 336, 384, 400, 240, 245, 247, 263, DOUBLESCAN, S + 3}, /* 320x240 @ 72Hz, 38.5 kHz hsync */ {15000, 320, 336, 384, 400, 240, 244, 246, 261, DOUBLESCAN, S + 4}, /* 320x400 @ 70 Hz, 31.5 kHz hsync */ {12588, 320, 336, 384, 400, 400, 408, 412, 450, 0, S + 5}, /* 320x400 @ 83 Hz, 37.5 kHz hsync */ {13333, 320, 336, 384, 400, 400, 408, 412, 450, 0, S + 6}, /* 320x480 @ 60 Hz, 31.5 kHz hsync */ {12588, 320, 336, 384, 400, 480, 490, 494, 526, 0, S + 7}, /* 320x480 @ 72Hz, 38.5 kHz hsync */ {15000, 320, 336, 384, 400, 480, 488, 492, 522, 0, S + 8}, /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ {18000, 400, 416, 448, 512, 300, 301, 302, 312, DOUBLESCAN, S+9}, /* 400x300 @ 60 Hz, 37.8 kHz hsync */ {20000, 400, 416, 480, 528, 300, 301, 303, 314, DOUBLESCAN, S+10}, /* 400x300 @ 72 Hz, 48.0 kHz hsync*/ {25000, 400, 424, 488, 520, 300, 319, 322, 333, DOUBLESCAN, S+11}, /* 400x600 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ {18000, 400, 416, 448, 512, 600, 602, 604, 624, 0, S+12}, /* 400x600 @ 60 Hz, 37.8 kHz hsync */ {20000, 400, 416, 480, 528, 600, 602, 606, 628, 0, S+13}, /* 400x600 @ 72 Hz, 48.0 kHz hsync*/ {25000, 400, 424, 488, 520, 600, 639, 644, 666, 0, S+14}, /* 512x384 @ 67Hz */ {19600, 512, 522, 598, 646, 384, 418, 426, 454, 0, S+15 }, /* 512x384 @ 86Hz */ {25175, 512, 522, 598, 646, 384, 418, 426, 454,0, S+16}, /* 512x480 @ 55Hz */ {19600, 512, 522, 598, 646, 480, 500, 510, 550, 0, S+17}, /* 512x480 @ 71Hz */ {25175, 512, 522, 598, 646, 480, 500, 510, 550,0, S+18}, /* 640x400 at 70 Hz, 31.5 kHz hsync */ {25175, 640, 664, 760, 800, 400, 409, 411, 450, 0, S + 19}, /* 640x480 at 60 Hz, 31.5 kHz hsync */ {25175, 640, 664, 760, 800, 480, 491, 493, 525, 0, S + 20}, /* 640x480 at 72 Hz, 36.5 kHz hsync */ {31500, 640, 680, 720, 864, 480, 488, 491, 521, 0, S + 21}, /* 800x600 at 56 Hz, 35.15 kHz hsync */ {36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0, S + 22}, /* 800x600 at 60 Hz, 37.8 kHz hsync */ {40000, 800, 840, 968, 1056, 600, 601, 605, 628, PHSYNC | PVSYNC, S + 23}, /* 800x600 at 72 Hz, 48.0 kHz hsync */ {50000, 800, 856, 976, 1040, 600, 637, 643, 666, PHSYNC | PVSYNC, S + 24}, /* 960x720 @ 70Hz */ {66000, 960, 984, 1112, 1248, 720, 723, 729, 756, NHSYNC | NVSYNC, S+25}, /* 960x720* interlaced, 35.5 kHz hsync */ {40000, 960, 984, 1192, 1216, 720, 728, 784, 817, INTERLACED, S + 26}, /* 1024x768 at 87 Hz interlaced, 35.5 kHz hsync */ {44900, 1024, 1048, 1208, 1264, 768, 776, 784, 817, INTERLACED, S + 27}, /* 1024x768 at 100 Hz, 40.9 kHz hsync */ {55000, 1024, 1048, 1208, 1264, 768, 776, 784, 817, INTERLACED, S + 28}, /* 1024x768 at 60 Hz, 48.4 kHz hsync */ {65000, 1024, 1032, 1176, 1344, 768, 771, 777, 806, NHSYNC | NVSYNC, S + 29}, /* 1024x768 at 70 Hz, 56.6 kHz hsync */ {75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, NHSYNC | NVSYNC, S + 30}, /* 1152x864 at 59.3Hz */ {85000, 1152, 1214, 1326, 1600, 864, 870, 885, 895, 0, S+31}, /* 1280x1024 at 87 Hz interlaced, 51 kHz hsync */ {80000, 1280, 1296, 1512, 1568, 1024, 1025, 1037, 1165, INTERLACED, S + 32}, /* 1024x768 at 76 Hz, 62.5 kHz hsync */ {85000, 1024, 1032, 1152, 1360, 768, 784, 787, 823, 0, S + 33}, /* 1280x1024 at 60 Hz, 64.3 kHz hsync */ {110000, 1280, 1328, 1512, 1712, 1024, 1025, 1028, 1054, 0, S + 34}, /* 1280x1024 at 74 Hz, 78.9 kHz hsync */ {135000, 1280, 1312, 1456, 1712, 1024, 1027, 1030, 1064, 0, S + 35}, /* 1600x1200 at 68Hz */ {188500, 1600, 1792, 1856, 2208, 1200, 1202, 1205, 1256, 0, S + 36}, /* 1600x1200 at 75 Hz */ {198000, 1600, 1616, 1776, 2112, 1200, 1201, 1204, 1250, 0, S + 37}, /* 720x540 at 56 Hz, 35.15 kHz hsync */ {32400, 720, 744, 808, 920, 540, 541, 543, 563, 0, S + 38}, /* 720x540 at 60 Hz, 37.8 kHz hsync */ {36000, 720, 760, 872, 952, 540, 541, 545, 565, 0, S + 39}, /* 720x540 at 72 Hz, 48.0 kHz hsync */ {45000, 720, 768, 880, 936, 540, 552, 558, 599, 0, S + 40}, /* 1072x600 at 57 Hz interlaced, 35.5 kHz hsync */ {44900, 1072, 1096, 1208, 1264, 600, 602, 604, 625, 0, S + 41}, /* 1072x600 at 65 Hz, 40.9 kHz hsync */ {55000, 1072, 1096, 1208, 1264, 600, 602, 604, 625, 0, S + 42}, /* 1072x600 at 78 Hz, 48.4 kHz hsync */ {65000, 1072, 1088, 1184, 1344, 600, 603, 607, 625, NHSYNC | NVSYNC, S + 43}, /* 1072x600 at 90 Hz, 56.6 kHz hsync */ {75000, 1072, 1096, 1200, 1328, 768, 603, 607, 625, NHSYNC | NVSYNC, S + 44}, /* 1072x600 at 100 Hz, 62.5 kHz hsync */ {85000, 1072, 1088, 1160, 1360, 768, 603, 607, 625, 0, NULL}, #undef S }; #define NUMBER_OF_STANDARD_MODES \ (sizeof(__svgalib_standard_timings) / sizeof(__svgalib_standard_timings[0])) static MonitorModeTiming *user_timings = NULL; static MonitorModeTiming *current_timing, *force_timing = NULL, new_timing; #ifdef GTF /* Ineed to get rid of the libm.so requirement */ static void GTF_calcTimings(double hPixels,double vLines,double freq, int type,int wantMargins,int wantInterlace, int wantDblscan, MonitorModeTiming *mmt); #endif /* * SYNC_ALLOWANCE is in percent * 1% corresponds to a 315 Hz deviation at 31.5 kHz, 1 Hz at 100 Hz */ #define SYNC_ALLOWANCE 1 #define INRANGE(x,y) \ ((x) > __svgalib_##y.min * (1.0f - SYNC_ALLOWANCE / 100.0f) && \ (x) < __svgalib_##y.max * (1.0f + SYNC_ALLOWANCE / 100.0f)) /* * Check monitor spec. */ static int timing_within_monitor_spec(MonitorModeTiming * mmtp) { float hsf; /* Horz. sync freq in Hz */ float vsf; /* Vert. sync freq in Hz */ hsf = mmtp->pixelClock * 1000.0f / mmtp->HTotal; vsf = hsf / mmtp->VTotal; if ((mmtp->flags & INTERLACED)) vsf *= 2.0f; if ((mmtp->flags & DOUBLESCAN)) vsf /= 2.0f; #ifdef DEBUG printf("hsf = %f (in:%d), vsf = %f (in:%d)\n", hsf / 1000, (int) INRANGE(hsf, horizsync), vsf, (int) INRANGE(vsf, vertrefresh)); #endif return INRANGE(hsf, horizsync) && INRANGE(vsf, vertrefresh); } void __svgalib_addusertiming(MonitorModeTiming * mmtp) { MonitorModeTiming *newmmt; if (!(newmmt = malloc(sizeof(*newmmt)))) return; *newmmt = *mmtp; if(newmmt->VSyncStartVDisplay+1)newmmt->VSyncStart=newmmt->VDisplay+1; if(newmmt->VSyncEndVSyncStart+1)newmmt->VSyncEnd=newmmt->VSyncStart+1; newmmt->next = user_timings; user_timings = newmmt; } /* * The __svgalib_getmodetiming function looks up a mode in the standard mode * timings, choosing the mode with the highest dot clock that matches * the requested svgalib mode, and is supported by the hardware * (card limits, and monitor type). cardlimits points to a structure * of type CardSpecs that describes the dot clocks the card supports * at different depths. Returns non-zero if no mode is found. */ /* * findclock is an auxilliary function that checks if a close enough * pixel clock is provided by the card. Returns clock number if * succesful (a special number if a programmable clock must be used), -1 * otherwise. */ /* * Clock allowance in 1/1000ths. 10 (1%) corresponds to a 250 kHz * deviation at 25 MHz, 1 MHz at 100 MHz */ #define CLOCK_ALLOWANCE 10 #define PROGRAMMABLE_CLOCK_MAGIC_NUMBER 0x1234 static int findclock(int clock, CardSpecs * cardspecs) { int i; /* Find a clock that is close enough. */ for (i = 0; i < cardspecs->nClocks; i++) { int diff; diff = cardspecs->clocks[i] - clock; if (diff < 0) diff = -diff; if (diff * 1000 / clock < CLOCK_ALLOWANCE) return i; } /* Try programmable clocks if available. */ if (cardspecs->flags & CLOCK_PROGRAMMABLE) { int diff; diff = cardspecs->matchProgrammableClock(clock) - clock; if (diff < 0) diff = -diff; if (diff * 1000 / clock < CLOCK_ALLOWANCE) return PROGRAMMABLE_CLOCK_MAGIC_NUMBER; } /* No close enough clock found. */ return -1; } static MonitorModeTiming *search_mode(MonitorModeTiming * timings, int maxclock, ModeInfo * modeinfo, CardSpecs * cardspecs) { int bestclock = 0; MonitorModeTiming *besttiming = NULL, *t; /* * bestclock is the highest pixel clock found for the resolution * in the mode timings, within the spec of the card and * monitor. * besttiming holds a pointer to timing with this clock. */ /* Search the timings for the best matching mode. */ for (t = timings; t; t = t->next) if (t->HDisplay == modeinfo->width && t->VDisplay == modeinfo->height && timing_within_monitor_spec(t) && t->pixelClock <= maxclock && t->pixelClock > bestclock && cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel, t->pixelClock, t->HTotal) <= cardspecs->maxHorizontalCrtc /* Find the clock (possibly scaled by mapClock). */ && findclock(cardspecs->mapClock(modeinfo->bitsPerPixel, t->pixelClock), cardspecs) != -1 ) { bestclock = t->pixelClock; besttiming = t; } return besttiming; } int __svgalib_getmodetiming(ModeTiming * modetiming, ModeInfo * modeinfo, CardSpecs * cardspecs) { int maxclock, desiredclock; MonitorModeTiming *besttiming=NULL; if(force_timing){ if(timing_within_monitor_spec(force_timing) && force_timing->HDisplay == modeinfo->width && force_timing->VDisplay == modeinfo->height) { besttiming=force_timing; }; }; /* Get the maximum pixel clock for the depth of the requested mode. */ if (modeinfo->bitsPerPixel == 4) maxclock = cardspecs->maxPixelClock4bpp; else if (modeinfo->bitsPerPixel == 8) maxclock = cardspecs->maxPixelClock8bpp; else if (modeinfo->bitsPerPixel == 16) { if ((cardspecs->flags & NO_RGB16_565) && modeinfo->greenWeight == 6) return 1; /* No 5-6-5 RGB. */ maxclock = cardspecs->maxPixelClock16bpp; } else if (modeinfo->bitsPerPixel == 24) maxclock = cardspecs->maxPixelClock24bpp; else if (modeinfo->bitsPerPixel == 32) maxclock = cardspecs->maxPixelClock32bpp; else maxclock = 0; /* * Check user defined timings first. * If there is no match within these, check the standard timings. */ if(!besttiming) besttiming = search_mode(user_timings, maxclock, modeinfo, cardspecs); if (!besttiming) { besttiming = search_mode(__svgalib_standard_timings, maxclock, modeinfo, cardspecs); if (!besttiming) return 1; } /* * Copy the selected timings into the result, which may * be adjusted for the chipset. */ modetiming->flags = besttiming->flags; modetiming->pixelClock = besttiming->pixelClock; /* Formal clock. */ /* * We know a close enough clock is available; the following is the * exact clock that fits the mode. This is probably different * from the best matching clock that will be programmed. */ desiredclock = cardspecs->mapClock(modeinfo->bitsPerPixel, besttiming->pixelClock); /* Fill in the best-matching clock that will be programmed. */ modetiming->selectedClockNo = findclock(desiredclock, cardspecs); if (modetiming->selectedClockNo == PROGRAMMABLE_CLOCK_MAGIC_NUMBER) { modetiming->programmedClock = cardspecs->matchProgrammableClock(desiredclock); modetiming->flags |= USEPROGRCLOCK; } else modetiming->programmedClock = cardspecs->clocks[ modetiming->selectedClockNo]; modetiming->HDisplay = besttiming->HDisplay; modetiming->HSyncStart = besttiming->HSyncStart; modetiming->HSyncEnd = besttiming->HSyncEnd; modetiming->HTotal = besttiming->HTotal; if (cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel, modetiming->programmedClock, besttiming->HTotal) != besttiming->HTotal) { /* Horizontal CRTC timings are scaled in some way. */ modetiming->CrtcHDisplay = cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel, modetiming->programmedClock, besttiming->HDisplay); modetiming->CrtcHSyncStart = cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel, modetiming->programmedClock, besttiming->HSyncStart); modetiming->CrtcHSyncEnd = cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel, modetiming->programmedClock, besttiming->HSyncEnd); modetiming->CrtcHTotal = cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel, modetiming->programmedClock, besttiming->HTotal); modetiming->flags |= HADJUSTED; } else { modetiming->CrtcHDisplay = besttiming->HDisplay; modetiming->CrtcHSyncStart = besttiming->HSyncStart; modetiming->CrtcHSyncEnd = besttiming->HSyncEnd; modetiming->CrtcHTotal = besttiming->HTotal; } modetiming->VDisplay = besttiming->VDisplay; modetiming->VSyncStart = besttiming->VSyncStart; modetiming->VSyncEnd = besttiming->VSyncEnd; modetiming->VTotal = besttiming->VTotal; if (modetiming->flags & DOUBLESCAN){ modetiming->VDisplay <<= 1; modetiming->VSyncStart <<= 1; modetiming->VSyncEnd <<= 1; modetiming->VTotal <<= 1; } modetiming->CrtcVDisplay = modetiming->VDisplay; modetiming->CrtcVSyncStart = modetiming->VSyncStart; modetiming->CrtcVSyncEnd = modetiming->VSyncEnd; modetiming->CrtcVTotal = modetiming->VTotal; if (((modetiming->flags & INTERLACED) && (cardspecs->flags & INTERLACE_DIVIDE_VERT)) || (modetiming->VTotal >= 1024 && (cardspecs->flags & GREATER_1024_DIVIDE_VERT))) { /* * Card requires vertical CRTC timing to be halved for * interlaced modes, or for all modes with vertical * timing >= 1024. */ modetiming->CrtcVDisplay /= 2; modetiming->CrtcVSyncStart /= 2; modetiming->CrtcVSyncEnd /= 2; modetiming->CrtcVTotal /= 2; modetiming->flags |= VADJUSTED; } current_timing=besttiming; return 0; /* Succesful. */ } int vga_getcurrenttiming(int *pixelClock, int *HDisplay, int *HSyncStart, int *HSyncEnd, int *HTotal, int *VDisplay, int *VSyncStart, int *VSyncEnd, int *VTotal, int *flags) { if(current_timing){ *pixelClock=current_timing->pixelClock; *HDisplay=current_timing->HDisplay; *HSyncStart=current_timing->HSyncStart; *HSyncEnd=current_timing->HSyncEnd; *HTotal=current_timing->HTotal; *VDisplay=current_timing->VDisplay; *VSyncStart=current_timing->VSyncStart; *VSyncEnd=current_timing->VSyncEnd; *VTotal=current_timing->VTotal; *flags=current_timing->flags; return 0; } return 1; }; int vga_changetiming(int pixelClock, int HDisplay, int HSyncStart, int HSyncEnd, int HTotal, int VDisplay, int VSyncStart, int VSyncEnd, int VTotal, int flags) { if(current_timing){ new_timing=*current_timing; new_timing.pixelClock+=pixelClock; new_timing.HDisplay+=HDisplay; new_timing.HSyncStart+=HSyncStart; new_timing.HSyncEnd+=HSyncEnd; new_timing.HTotal+=HTotal; new_timing.VDisplay+=VDisplay; new_timing.VSyncStart+=VSyncStart; new_timing.VSyncEnd+=VSyncEnd; new_timing.VTotal+=VTotal; force_timing=&new_timing; vga_setmode(CM|0x8000); force_timing=NULL; }; return 1; }; static int find_up_timing(int x, int y, int *bestx, int *besty, MonitorModeTiming **bestmodetiming) { MonitorModeTiming *t; int bestclock=0; int mode_ar; *bestmodetiming=NULL; *bestx=*besty=4096; for (t = user_timings; t; t = t->next) { if ((mode_ar=1000*t->VDisplay/t->HDisplay)<=765 && mode_ar>=735 && t->HDisplay >= x && t->VDisplay >= y && timing_within_monitor_spec(t) && t->HDisplay <= *bestx && t->VDisplay <= *besty && t->pixelClock>=bestclock ) { bestclock = t->pixelClock; *bestx=t->HDisplay; *besty=t->VDisplay; *bestmodetiming = t; }; }; for (t = __svgalib_standard_timings; t; t = t->next) { if (t->HDisplay >= x && t->VDisplay >= y && timing_within_monitor_spec(t) && t->HDisplay <= *bestx && t->VDisplay <= *besty && t->pixelClock>=bestclock ) { bestclock = t->pixelClock; *bestx=t->HDisplay; *besty=t->VDisplay; *bestmodetiming = t; }; }; return *bestmodetiming!=NULL; }; static int find_down_timing(int x, int y, int *bestx, int *besty, MonitorModeTiming **bestmodetiming) { MonitorModeTiming *t; int bestclock=0; int mode_ar; *bestmodetiming=NULL; *bestx=*besty=0; for (t = user_timings; t; t = t->next) { if ((mode_ar=1000*t->VDisplay/t->HDisplay)<=765 && mode_ar>=735 && t->HDisplay <= x && t->VDisplay <= y && timing_within_monitor_spec(t) && t->HDisplay >= *bestx && t->VDisplay >= *besty && t->pixelClock>=bestclock ) { bestclock = t->pixelClock; *bestx=t->HDisplay; *besty=t->VDisplay; *bestmodetiming = t; }; }; for (t = __svgalib_standard_timings; t; t = t->next) { if (t->HDisplay <= x && t->VDisplay <= y && timing_within_monitor_spec(t) && t->HDisplay >= *bestx && t->VDisplay >= *besty && t->pixelClock>=bestclock ) { bestclock = t->pixelClock; *bestx=t->HDisplay; *besty=t->VDisplay; *bestmodetiming = t; }; }; return *bestmodetiming!=NULL; }; int vga_guesstiming(int x, int y, int clue, int arg) { /* This functions tries to add timings that fit a specific mode, by changing the timings of a similar mode currently only works for x:y = 4:3, clue means: 0- scale down timing of a higher res mode 1- scale up timings of a lower res mode */ MonitorModeTiming mmt, *bestmodetiming = NULL ; int bestx,besty /*, bestclock */ ; int aspect_ratio=1000*y/x; switch(clue) { case 0: case 1: if((aspect_ratio>765)||(aspect_ratio<735))return 0; if(clue==0)find_up_timing(x,y,&bestx,&besty,&bestmodetiming); if(clue==1)find_down_timing(x,y,&bestx,&besty,&bestmodetiming); if(bestmodetiming){ mmt=*bestmodetiming; mmt.pixelClock=(mmt.pixelClock*x)/bestx; mmt.HDisplay=x; mmt.VDisplay=y; mmt.HSyncStart=(mmt.HSyncStart*x)/bestx; mmt.HSyncEnd=(mmt.HSyncEnd*x)/bestx; mmt.HTotal=(mmt.HTotal*x)/bestx; mmt.VSyncStart=(mmt.VSyncStart*x)/bestx; mmt.VSyncEnd=(mmt.VSyncEnd*x)/bestx; mmt.VTotal=(mmt.VTotal*x)/bestx; __svgalib_addusertiming(&mmt); return 1; }; break; case 256: case 257: { int mx; mx=y*4/3; if((clue&1)==0)find_up_timing(mx,y,&bestx,&besty,&bestmodetiming); if((clue&1)==1)find_down_timing(mx,y,&bestx,&besty,&bestmodetiming); if(bestmodetiming){ mmt=*bestmodetiming; mmt.pixelClock=(mmt.pixelClock*x)/bestx; mmt.HDisplay=x; mmt.HSyncStart=(mmt.HSyncStart*x)/bestx; mmt.HSyncEnd=(mmt.HSyncEnd*x)/bestx; mmt.HTotal=(mmt.HTotal*x)/bestx; mmt.VDisplay=y; mmt.VSyncStart=(mmt.VSyncStart*mx)/bestx; mmt.VSyncEnd=(mmt.VSyncEnd*mx)/bestx; mmt.VTotal=(mmt.VTotal*mx)/bestx; __svgalib_addusertiming(&mmt); return 1; }; }; case 258: case 259: { int my; my=(x*3)>>2; if((clue&1)==0)find_up_timing(x,my,&bestx,&besty,&bestmodetiming); if((clue&1)==1)find_down_timing(x,my,&bestx,&besty,&bestmodetiming); if(bestmodetiming){ mmt=*bestmodetiming; mmt.pixelClock=(mmt.pixelClock*x)/bestx; mmt.HDisplay=x; mmt.HSyncStart=(mmt.HSyncStart*x)/bestx; mmt.HSyncEnd=(mmt.HSyncEnd*x)/bestx; mmt.HTotal=(mmt.HTotal*x)/bestx; mmt.VDisplay=y; mmt.VSyncStart=(mmt.VSyncStart*y)/besty; mmt.VSyncEnd=(mmt.VSyncEnd*y)/besty; mmt.VTotal=(mmt.VTotal*y)/besty; __svgalib_addusertiming(&mmt); return 1; }; }; }; return 0; }; #ifdef GTF /* Everything from here to the end of the file is copyright by scitechsoft. See their original program in utils/gtf subdirectory */ typedef struct { double margin; /* Margin size as percentage of display */ double cellGran; /* Character cell granularity */ double minPorch; /* Minimum front porch in lines/chars */ double vSyncRqd; /* Width of V sync in lines */ double hSync; /* Width of H sync as percent of total */ double minVSyncBP; /* Minimum vertical sync + back porch (us) */ double m; /* Blanking formula gradient */ double c; /* Blanking formula offset */ double k; /* Blanking formula scaling factor */ double j; /* Blanking formula scaling factor weight */ } GTF_constants; static GTF_constants GC = { 1.8, /* Margin size as percentage of display */ 8, /* Character cell granularity */ 1, /* Minimum front porch in lines/chars */ 3, /* Width of V sync in lines */ 8, /* Width of H sync as percent of total */ 550, /* Minimum vertical sync + back porch (us) */ 600, /* Blanking formula gradient */ 40, /* Blanking formula offset */ 128, /* Blanking formula scaling factor */ 20, /* Blanking formula scaling factor weight */ }; static double round(double v) { double u=v; long j; if(u<0) u=-u; u=u+0.5; j=u; if(v<0) j=-j; return j; } static double sqrt(double u) { double v,w; int i; v=0; if(u==0) return 0; if(u<0) u=-u; w=u; if(u<1) w=1; for(i=0;i<50;i++){ w=w/2; if(v*v==u)break; if(v*vu)v=v-w; }; return v; } static void GetInternalConstants(GTF_constants *c) { c->margin = GC.margin; c->cellGran = round(GC.cellGran); c->minPorch = round(GC.minPorch); c->vSyncRqd = round(GC.vSyncRqd); c->hSync = GC.hSync; c->minVSyncBP = GC.minVSyncBP; if (GC.k == 0) c->k = 0.001; else c->k = GC.k; c->m = (c->k / 256) * GC.m; c->c = (GC.c - GC.j) * (c->k / 256) + GC.j; c->j = GC.j; } static void GTF_calcTimings(double hPixels,double vLines,double freq, int type,int wantMargins,int wantInterlace, int wantDblscan, MonitorModeTiming *mmt) { double interlace,vFieldRate,hPeriod=0; double topMarginLines,botMarginLines; double leftMarginPixels,rightMarginPixels; double hPeriodEst=0,vSyncBP=0,vBackPorch=0; double vTotalLines=0,vFieldRateEst; double hTotalPixels,hTotalActivePixels,hBlankPixels; double idealDutyCycle=0,hSyncWidth,hSyncBP,hBackPorch; double idealHPeriod; double vFreq,hFreq,dotClock; GTF_constants c; /* Get rounded GTF constants used for internal calculations */ GetInternalConstants(&c); /* Move input parameters into appropriate variables */ vFreq = hFreq = dotClock = freq; /* Round pixels to character cell granularity */ hPixels = round(hPixels / c.cellGran) * c.cellGran; /* For interlaced mode halve the vertical parameters, and double * the required field refresh rate. */ if(wantDblscan) vLines = vLines * 2; if (wantInterlace) { vLines = round(vLines / 2); vFieldRate = vFreq * 2; dotClock = dotClock * 2; interlace = 0.5; } else { vFieldRate = vFreq; interlace = 0; } /* Determine the lines for margins */ if (wantMargins) { topMarginLines = round(c.margin / 100 * vLines); botMarginLines = round(c.margin / 100 * vLines); } else { topMarginLines = 0; botMarginLines = 0; } if (type != GTF_lockPF) { if (type == GTF_lockVF) { /* Estimate the horizontal period */ hPeriodEst = ((1/vFieldRate) - (c.minVSyncBP/1000000)) / (vLines + (2*topMarginLines) + c.minPorch + interlace) * 1000000; /* Find the number of lines in vSync + back porch */ vSyncBP = round(c.minVSyncBP / hPeriodEst); } else if (type == GTF_lockHF) { /* Find the number of lines in vSync + back porch */ vSyncBP = round((c.minVSyncBP * hFreq) / 1000); } /* Find the number of lines in the V back porch alone */ vBackPorch = vSyncBP - c.vSyncRqd; /* Find the total number of lines in the vertical period */ vTotalLines = vLines + topMarginLines + botMarginLines + vSyncBP + interlace + c.minPorch; if (type == GTF_lockVF) { /* Estimate the vertical frequency */ vFieldRateEst = 1000000 / (hPeriodEst * vTotalLines); /* Find the actual horizontal period */ hPeriod = (hPeriodEst * vFieldRateEst) / vFieldRate; /* Find the actual vertical field frequency */ vFieldRate = 1000000 / (hPeriod * vTotalLines); } else if (type == GTF_lockHF) { /* Find the actual vertical field frequency */ vFieldRate = (hFreq / vTotalLines) * 1000; } } /* Find the number of pixels in the left and right margins */ if (wantMargins) { leftMarginPixels = round(hPixels * c.margin) / (100 * c.cellGran); rightMarginPixels = round(hPixels * c.margin) / (100 * c.cellGran); } else { leftMarginPixels = 0; rightMarginPixels = 0; } /* Find the total number of active pixels in image + margins */ hTotalActivePixels = hPixels + leftMarginPixels + rightMarginPixels; if (type == GTF_lockVF) { /* Find the ideal blanking duty cycle */ idealDutyCycle = c.c - ((c.m * hPeriod) / 1000); } else if (type == GTF_lockHF) { /* Find the ideal blanking duty cycle */ idealDutyCycle = c.c - (c.m / hFreq); } else if (type == GTF_lockPF) { /* Find ideal horizontal period from blanking duty cycle formula */ idealHPeriod = (((c.c - 100) + (sqrt(((100-c.c)*(100-c.c)) + (0.4 * c.m * (hTotalActivePixels + rightMarginPixels + leftMarginPixels) / dotClock)))) / (2 * c.m)) * 1000; /* Find the ideal blanking duty cycle */ idealDutyCycle = c.c - ((c.m * idealHPeriod) / 1000); } /* Find the number of pixels in blanking time */ hBlankPixels = round((hTotalActivePixels * idealDutyCycle) / ((100 - idealDutyCycle) * 2 * c.cellGran)) * (2 * c.cellGran); /* Find the total number of pixels */ hTotalPixels = hTotalActivePixels + hBlankPixels; /* Find the horizontal back porch */ hBackPorch = round((hBlankPixels / 2) / c.cellGran) * c.cellGran; /* Find the horizontal sync width */ hSyncWidth = round(((c.hSync/100) * hTotalPixels) / c.cellGran) * c.cellGran; /* Find the horizontal sync + back porch */ hSyncBP = hBackPorch + hSyncWidth; if (type == GTF_lockPF) { /* Find the horizontal frequency */ hFreq = (dotClock / hTotalPixels) * 1000; /* Find the horizontal period */ hPeriod = 1000 / hFreq; /* Find the number of lines in vSync + back porch */ vSyncBP = round((c.minVSyncBP * hFreq) / 1000); /* Find the number of lines in the V back porch alone */ vBackPorch = vSyncBP - c.vSyncRqd; /* Find the total number of lines in the vertical period */ vTotalLines = vLines + topMarginLines + botMarginLines + vSyncBP + interlace + c.minPorch; /* Find the actual vertical field frequency */ vFieldRate = (hFreq / vTotalLines) * 1000; } else { if (type == GTF_lockVF) { /* Find the horizontal frequency */ hFreq = 1000 / hPeriod; } else if (type == GTF_lockHF) { /* Find the horizontal frequency */ hPeriod = 1000 / hFreq; } /* Find the pixel clock frequency */ dotClock = hTotalPixels / hPeriod; } /* Find the vertical frame frequency */ if (wantInterlace) { vFreq = vFieldRate / 2; } else vFreq = vFieldRate; mmt->pixelClock = dotClock; /* Determine the vertical timing parameters */ mmt->HTotal = hTotalPixels; mmt->HDisplay = hTotalActivePixels; mmt->HSyncStart = mmt->HTotal - hSyncBP; mmt->HSyncEnd = mmt->HTotal - hBackPorch; /* Determine the vertical timing parameters */ mmt->VTotal = vTotalLines; mmt->VDisplay = vLines; mmt->VSyncStart = mmt->VTotal - vSyncBP; mmt->VSyncEnd = mmt->VTotal - vBackPorch; if(wantDblscan) { mmt->VTotal >>= 1; mmt->VDisplay >>= 1 ; mmt->VSyncStart >>= 1 ; mmt->VSyncEnd >>= 1 ; }; if(wantInterlace) { mmt->VTotal <<= 1; mmt->VDisplay <<= 1 ; mmt->VSyncStart <<= 1 ; mmt->VSyncEnd <<= 1 ; }; mmt->flags = NHSYNC | PVSYNC | ((wantInterlace) ? INTERLACED : 0) | ((wantDblscan) ? DOUBLESCAN : 0); } #endif