1 #define GTF
2 /*
3  * Generic mode timing module.
4  */
5 #include <stdlib.h>
6 
7 #include "timing.h"		/* Types. */
8 
9 #include "driver.h"		/* for __svgalib_monitortype (remove me) */
10 
11 /* Standard mode timings. */
12 
13 MonitorModeTiming __svgalib_standard_timings[] =
14 {
15 #define S __svgalib_standard_timings
16 /* 320x200 @ 70 Hz, 31.5 kHz hsync */
17     {12588, 320, 336, 384, 400, 200, 204, 206, 225, DOUBLESCAN, S + 1},
18 /* 320x200 @ 83 Hz, 37.5 kHz hsync */
19     {13333, 320, 336, 384, 400, 200, 204, 206, 225, DOUBLESCAN, S + 2},
20 /* 320x240 @ 60 Hz, 31.5 kHz hsync */
21     {12588, 320, 336, 384, 400, 240, 245, 247, 263, DOUBLESCAN, S + 3},
22 /* 320x240 @ 72Hz, 38.5 kHz hsync */
23     {15000, 320, 336, 384, 400, 240, 244, 246, 261, DOUBLESCAN, S + 4},
24 /* 320x400 @ 70 Hz, 31.5 kHz hsync */
25     {12588, 320, 336, 384, 400, 400, 408, 412, 450, 0, S + 5},
26 /* 320x400 @ 83 Hz, 37.5 kHz hsync */
27     {13333, 320, 336, 384, 400, 400, 408, 412, 450, 0, S + 6},
28 /* 320x480 @ 60 Hz, 31.5 kHz hsync */
29     {12588, 320, 336, 384, 400, 480, 490, 494, 526, 0, S + 7},
30 /* 320x480 @ 72Hz, 38.5 kHz hsync */
31     {15000, 320, 336, 384, 400, 480, 488, 492, 522, 0, S + 8},
32 /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
33     {18000, 400, 416, 448, 512, 300, 301, 302, 312, DOUBLESCAN, S+9},
34 /* 400x300 @ 60 Hz, 37.8 kHz hsync */
35     {20000, 400, 416, 480, 528, 300, 301, 303, 314, DOUBLESCAN, S+10},
36 /* 400x300 @ 72 Hz, 48.0 kHz hsync*/
37     {25000, 400, 424, 488, 520, 300, 319, 322, 333, DOUBLESCAN, S+11},
38 /* 400x600 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
39     {18000, 400, 416, 448, 512, 600, 602, 604, 624, 0, S+12},
40 /* 400x600 @ 60 Hz, 37.8 kHz hsync */
41     {20000, 400, 416, 480, 528, 600, 602, 606, 628, 0, S+13},
42 /* 400x600 @ 72 Hz, 48.0 kHz hsync*/
43     {25000, 400, 424, 488, 520, 600, 639, 644, 666, 0, S+14},
44 /* 512x384 @ 67Hz */
45     {19600, 512, 522, 598, 646, 384, 418, 426, 454, 0, S+15 },
46 /* 512x384 @ 86Hz */
47     {25175, 512, 522, 598, 646, 384, 418, 426, 454,0, S+16},
48 /* 512x480 @ 55Hz */
49     {19600, 512, 522, 598, 646, 480, 500, 510, 550, 0, S+17},
50 /* 512x480 @ 71Hz */
51     {25175, 512, 522, 598, 646, 480, 500, 510, 550,0, S+18},
52 /* 640x400 at 70 Hz, 31.5 kHz hsync */
53     {25175, 640, 664, 760, 800, 400, 409, 411, 450, 0, S + 19},
54 /* 640x480 at 60 Hz, 31.5 kHz hsync */
55     {25175, 640, 664, 760, 800, 480, 491, 493, 525, 0, S + 20},
56 /* 640x480 at 72 Hz, 36.5 kHz hsync */
57     {31500, 640, 680, 720, 864, 480, 488, 491, 521, 0, S + 21},
58 /* 800x600 at 56 Hz, 35.15 kHz hsync */
59     {36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0, S + 22},
60 /* 800x600 at 60 Hz, 37.8 kHz hsync */
61     {40000, 800, 840, 968, 1056, 600, 601, 605, 628, PHSYNC | PVSYNC, S + 23},
62 /* 800x600 at 72 Hz, 48.0 kHz hsync */
63     {50000, 800, 856, 976, 1040, 600, 637, 643, 666, PHSYNC | PVSYNC, S + 24},
64 /* 960x720 @ 70Hz */
65     {66000, 960, 984, 1112, 1248, 720, 723, 729, 756, NHSYNC | NVSYNC, S+25},
66 /* 960x720* interlaced, 35.5 kHz hsync */
67     {40000, 960, 984, 1192, 1216, 720, 728, 784, 817, INTERLACED, S + 26},
68 /* 1024x768 at 87 Hz interlaced, 35.5 kHz hsync */
69     {44900, 1024, 1048, 1208, 1264, 768, 776, 784, 817, INTERLACED, S + 27},
70 /* 1024x768 at 100 Hz, 40.9 kHz hsync */
71     {55000, 1024, 1048, 1208, 1264, 768, 776, 784, 817, INTERLACED, S + 28},
72 /* 1024x768 at 60 Hz, 48.4 kHz hsync */
73     {65000, 1024, 1032, 1176, 1344, 768, 771, 777, 806, NHSYNC | NVSYNC, S + 29},
74 /* 1024x768 at 70 Hz, 56.6 kHz hsync */
75     {75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, NHSYNC | NVSYNC, S + 30},
76 /* 1152x864 at 59.3Hz */
77     {85000, 1152, 1214, 1326, 1600, 864, 870, 885, 895, 0, S+31},
78 /* 1280x1024 at 87 Hz interlaced, 51 kHz hsync */
79     {80000, 1280, 1296, 1512, 1568, 1024, 1025, 1037, 1165, INTERLACED, S + 32},
80 /* 1024x768 at 76 Hz, 62.5 kHz hsync */
81     {85000, 1024, 1032, 1152, 1360, 768, 784, 787, 823, 0, S + 33},
82 /* 1280x1024 at 60 Hz, 64.3 kHz hsync */
83     {110000, 1280, 1328, 1512, 1712, 1024, 1025, 1028, 1054, 0, S + 34},
84 /* 1280x1024 at 74 Hz, 78.9 kHz hsync */
85     {135000, 1280, 1312, 1456, 1712, 1024, 1027, 1030, 1064, 0, S + 35},
86 /* 1600x1200 at 68Hz */
87     {188500, 1600, 1792, 1856, 2208, 1200, 1202, 1205, 1256, 0, S + 36},
88 /* 1600x1200 at 75 Hz */
89     {198000, 1600, 1616, 1776, 2112, 1200, 1201, 1204, 1250, 0, S + 37},
90 /* 720x540 at 56 Hz, 35.15 kHz hsync */
91     {32400, 720, 744, 808, 920, 540, 541, 543, 563, 0, S + 38},
92 /* 720x540 at 60 Hz, 37.8 kHz hsync */
93     {36000, 720, 760, 872, 952, 540, 541, 545, 565, 0, S + 39},
94 /* 720x540 at 72 Hz, 48.0 kHz hsync */
95     {45000, 720, 768, 880, 936, 540, 552, 558, 599, 0, S + 40},
96 /* 1072x600 at 57 Hz interlaced, 35.5 kHz hsync */
97     {44900, 1072, 1096, 1208, 1264, 600, 602, 604, 625, 0, S + 41},
98 /* 1072x600 at 65 Hz, 40.9 kHz hsync */
99     {55000, 1072, 1096, 1208, 1264, 600, 602, 604, 625, 0, S + 42},
100 /* 1072x600 at 78 Hz, 48.4 kHz hsync */
101     {65000, 1072, 1088, 1184, 1344, 600, 603, 607, 625, NHSYNC | NVSYNC, S + 43},
102 /* 1072x600 at 90 Hz, 56.6 kHz hsync */
103     {75000, 1072, 1096, 1200, 1328, 768, 603, 607, 625, NHSYNC | NVSYNC, S + 44},
104 /* 1072x600 at 100 Hz, 62.5 kHz hsync */
105     {85000, 1072, 1088, 1160, 1360, 768, 603, 607, 625, 0, NULL},
106 #undef S
107 };
108 
109 #define NUMBER_OF_STANDARD_MODES \
110 	(sizeof(__svgalib_standard_timings) / sizeof(__svgalib_standard_timings[0]))
111 
112 static MonitorModeTiming *user_timings = NULL;
113 static MonitorModeTiming *current_timing, *force_timing = NULL, new_timing;
114 #ifdef GTF /* Ineed to get rid of the libm.so requirement */
115 static void GTF_calcTimings(double hPixels,double vLines,double freq,
116         int type,int wantMargins,int wantInterlace, int wantDblscan,
117         MonitorModeTiming *mmt);
118 #endif
119 /*
120  * SYNC_ALLOWANCE is in percent
121  * 1% corresponds to a 315 Hz deviation at 31.5 kHz, 1 Hz at 100 Hz
122  */
123 #define SYNC_ALLOWANCE 1
124 
125 #define INRANGE(x,y) \
126     ((x) > __svgalib_##y.min * (1.0f - SYNC_ALLOWANCE / 100.0f) && \
127      (x) < __svgalib_##y.max * (1.0f + SYNC_ALLOWANCE / 100.0f))
128 
129 /*
130  * Check monitor spec.
131  */
timing_within_monitor_spec(MonitorModeTiming * mmtp)132 static int timing_within_monitor_spec(MonitorModeTiming * mmtp)
133 {
134     float hsf;			/* Horz. sync freq in Hz */
135     float vsf;			/* Vert. sync freq in Hz */
136 
137     hsf = mmtp->pixelClock * 1000.0f / mmtp->HTotal;
138     vsf = hsf / mmtp->VTotal;
139     if ((mmtp->flags & INTERLACED))
140 	vsf *= 2.0f;
141     if ((mmtp->flags & DOUBLESCAN))
142 	vsf /= 2.0f;
143 #ifdef DEBUG
144     printf("hsf = %f (in:%d), vsf = %f (in:%d)\n",
145 	   hsf / 1000, (int) INRANGE(hsf, horizsync),
146 	   vsf, (int) INRANGE(vsf, vertrefresh));
147 #endif
148     return INRANGE(hsf, horizsync) && INRANGE(vsf, vertrefresh);
149 }
150 
__svgalib_addusertiming(MonitorModeTiming * mmtp)151 void __svgalib_addusertiming(MonitorModeTiming * mmtp)
152 {
153     MonitorModeTiming *newmmt;
154 
155     if (!(newmmt = malloc(sizeof(*newmmt))))
156 	return;
157     *newmmt = *mmtp;
158     if(newmmt->VSyncStart<newmmt->VDisplay+1)newmmt->VSyncStart=newmmt->VDisplay+1;
159     if(newmmt->VSyncEnd<newmmt->VSyncStart+1)newmmt->VSyncEnd=newmmt->VSyncStart+1;
160     newmmt->next = user_timings;
161     user_timings = newmmt;
162 }
163 
164 /*
165  * The __svgalib_getmodetiming function looks up a mode in the standard mode
166  * timings, choosing the mode with the highest dot clock that matches
167  * the requested svgalib mode, and is supported by the hardware
168  * (card limits, and monitor type). cardlimits points to a structure
169  * of type CardSpecs that describes the dot clocks the card supports
170  * at different depths. Returns non-zero if no mode is found.
171  */
172 
173 /*
174  * findclock is an auxilliary function that checks if a close enough
175  * pixel clock is provided by the card. Returns clock number if
176  * succesful (a special number if a programmable clock must be used), -1
177  * otherwise.
178  */
179 
180 /*
181  * Clock allowance in 1/1000ths. 10 (1%) corresponds to a 250 kHz
182  * deviation at 25 MHz, 1 MHz at 100 MHz
183  */
184 #define CLOCK_ALLOWANCE 10
185 
186 #define PROGRAMMABLE_CLOCK_MAGIC_NUMBER 0x1234
187 
findclock(int clock,CardSpecs * cardspecs)188 static int findclock(int clock, CardSpecs * cardspecs)
189 {
190     int i;
191     /* Find a clock that is close enough. */
192     for (i = 0; i < cardspecs->nClocks; i++) {
193 	int diff;
194 	diff = cardspecs->clocks[i] - clock;
195 	if (diff < 0)
196 	    diff = -diff;
197 	if (diff * 1000 / clock < CLOCK_ALLOWANCE)
198 	    return i;
199     }
200     /* Try programmable clocks if available. */
201     if (cardspecs->flags & CLOCK_PROGRAMMABLE) {
202 	int diff;
203 	diff = cardspecs->matchProgrammableClock(clock) - clock;
204 	if (diff < 0)
205 	    diff = -diff;
206 	if (diff * 1000 / clock < CLOCK_ALLOWANCE)
207 	    return PROGRAMMABLE_CLOCK_MAGIC_NUMBER;
208     }
209     /* No close enough clock found. */
210     return -1;
211 }
212 
search_mode(MonitorModeTiming * timings,int maxclock,ModeInfo * modeinfo,CardSpecs * cardspecs)213 static MonitorModeTiming *search_mode(MonitorModeTiming * timings,
214 				      int maxclock,
215 				      ModeInfo * modeinfo,
216 				      CardSpecs * cardspecs)
217 {
218     int bestclock = 0;
219     MonitorModeTiming *besttiming = NULL, *t;
220 
221     /*
222      * bestclock is the highest pixel clock found for the resolution
223      * in the mode timings, within the spec of the card and
224      * monitor.
225      * besttiming holds a pointer to timing with this clock.
226      */
227 
228     /* Search the timings for the best matching mode. */
229     for (t = timings; t; t = t->next)
230 	if (t->HDisplay == modeinfo->width
231 	    && t->VDisplay == modeinfo->height
232 	    && timing_within_monitor_spec(t)
233 	    && t->pixelClock <= maxclock
234 	    && t->pixelClock > bestclock
235 	    && cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel,
236 					    t->pixelClock,
237 					    t->HTotal)
238 	    <= cardspecs->maxHorizontalCrtc
239 	/* Find the clock (possibly scaled by mapClock). */
240 	    && findclock(cardspecs->mapClock(modeinfo->bitsPerPixel,
241 					 t->pixelClock), cardspecs) != -1
242 	    ) {
243 	    bestclock = t->pixelClock;
244 	    besttiming = t;
245 	}
246     return besttiming;
247 }
248 
__svgalib_getmodetiming(ModeTiming * modetiming,ModeInfo * modeinfo,CardSpecs * cardspecs)249 int __svgalib_getmodetiming(ModeTiming * modetiming, ModeInfo * modeinfo,
250 		  CardSpecs * cardspecs)
251 {
252     int maxclock, desiredclock;
253     MonitorModeTiming *besttiming=NULL;
254 
255     if(force_timing){
256        if(timing_within_monitor_spec(force_timing) &&
257           force_timing->HDisplay == modeinfo->width &&
258           force_timing->VDisplay == modeinfo->height)
259        {
260             besttiming=force_timing;
261        };
262     };
263 
264     /* Get the maximum pixel clock for the depth of the requested mode. */
265     if (modeinfo->bitsPerPixel == 4)
266 	maxclock = cardspecs->maxPixelClock4bpp;
267     else if (modeinfo->bitsPerPixel == 8)
268 	maxclock = cardspecs->maxPixelClock8bpp;
269     else if (modeinfo->bitsPerPixel == 16) {
270 	if ((cardspecs->flags & NO_RGB16_565)
271 	    && modeinfo->greenWeight == 6)
272 	    return 1;		/* No 5-6-5 RGB. */
273 	maxclock = cardspecs->maxPixelClock16bpp;
274     } else if (modeinfo->bitsPerPixel == 24)
275 	maxclock = cardspecs->maxPixelClock24bpp;
276     else if (modeinfo->bitsPerPixel == 32)
277 	maxclock = cardspecs->maxPixelClock32bpp;
278     else
279 	maxclock = 0;
280 
281     /*
282      * Check user defined timings first.
283      * If there is no match within these, check the standard timings.
284      */
285     if(!besttiming)
286         besttiming = search_mode(user_timings, maxclock, modeinfo, cardspecs);
287     if (!besttiming) {
288 	besttiming = search_mode(__svgalib_standard_timings, maxclock, modeinfo, cardspecs);
289 	if (!besttiming)
290 	    return 1;
291     }
292     /*
293      * Copy the selected timings into the result, which may
294      * be adjusted for the chipset.
295      */
296 
297     modetiming->flags = besttiming->flags;
298     modetiming->pixelClock = besttiming->pixelClock;	/* Formal clock. */
299 
300     /*
301      * We know a close enough clock is available; the following is the
302      * exact clock that fits the mode. This is probably different
303      * from the best matching clock that will be programmed.
304      */
305     desiredclock = cardspecs->mapClock(modeinfo->bitsPerPixel,
306 				       besttiming->pixelClock);
307 
308     /* Fill in the best-matching clock that will be programmed. */
309     modetiming->selectedClockNo = findclock(desiredclock, cardspecs);
310     if (modetiming->selectedClockNo == PROGRAMMABLE_CLOCK_MAGIC_NUMBER) {
311 	modetiming->programmedClock =
312 	    cardspecs->matchProgrammableClock(desiredclock);
313 	modetiming->flags |= USEPROGRCLOCK;
314     } else
315 	modetiming->programmedClock = cardspecs->clocks[
316 					    modetiming->selectedClockNo];
317     modetiming->HDisplay = besttiming->HDisplay;
318     modetiming->HSyncStart = besttiming->HSyncStart;
319     modetiming->HSyncEnd = besttiming->HSyncEnd;
320     modetiming->HTotal = besttiming->HTotal;
321     if (cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel,
322 				     modetiming->programmedClock,
323 				     besttiming->HTotal)
324 	!= besttiming->HTotal) {
325 	/* Horizontal CRTC timings are scaled in some way. */
326 	modetiming->CrtcHDisplay =
327 	    cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel,
328 					 modetiming->programmedClock,
329 					 besttiming->HDisplay);
330 	modetiming->CrtcHSyncStart =
331 	    cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel,
332 					 modetiming->programmedClock,
333 					 besttiming->HSyncStart);
334 	modetiming->CrtcHSyncEnd =
335 	    cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel,
336 					 modetiming->programmedClock,
337 					 besttiming->HSyncEnd);
338 	modetiming->CrtcHTotal =
339 	    cardspecs->mapHorizontalCrtc(modeinfo->bitsPerPixel,
340 					 modetiming->programmedClock,
341 					 besttiming->HTotal);
342 	modetiming->flags |= HADJUSTED;
343     } else {
344 	modetiming->CrtcHDisplay = besttiming->HDisplay;
345 	modetiming->CrtcHSyncStart = besttiming->HSyncStart;
346 	modetiming->CrtcHSyncEnd = besttiming->HSyncEnd;
347 	modetiming->CrtcHTotal = besttiming->HTotal;
348     }
349     modetiming->VDisplay = besttiming->VDisplay;
350     modetiming->VSyncStart = besttiming->VSyncStart;
351     modetiming->VSyncEnd = besttiming->VSyncEnd;
352     modetiming->VTotal = besttiming->VTotal;
353     if (modetiming->flags & DOUBLESCAN){
354 	modetiming->VDisplay <<= 1;
355 	modetiming->VSyncStart <<= 1;
356 	modetiming->VSyncEnd <<= 1;
357 	modetiming->VTotal <<= 1;
358     }
359     modetiming->CrtcVDisplay = modetiming->VDisplay;
360     modetiming->CrtcVSyncStart = modetiming->VSyncStart;
361     modetiming->CrtcVSyncEnd = modetiming->VSyncEnd;
362     modetiming->CrtcVTotal = modetiming->VTotal;
363     if (((modetiming->flags & INTERLACED)
364 	 && (cardspecs->flags & INTERLACE_DIVIDE_VERT))
365 	|| (modetiming->VTotal >= 1024
366 	    && (cardspecs->flags & GREATER_1024_DIVIDE_VERT))) {
367 	/*
368 	 * Card requires vertical CRTC timing to be halved for
369 	 * interlaced modes, or for all modes with vertical
370 	 * timing >= 1024.
371 	 */
372 	modetiming->CrtcVDisplay /= 2;
373 	modetiming->CrtcVSyncStart /= 2;
374 	modetiming->CrtcVSyncEnd /= 2;
375 	modetiming->CrtcVTotal /= 2;
376 	modetiming->flags |= VADJUSTED;
377     }
378     current_timing=besttiming;
379     return 0;			/* Succesful. */
380 }
381 
vga_getcurrenttiming(int * pixelClock,int * HDisplay,int * HSyncStart,int * HSyncEnd,int * HTotal,int * VDisplay,int * VSyncStart,int * VSyncEnd,int * VTotal,int * flags)382 int vga_getcurrenttiming(int *pixelClock,
383        			 int *HDisplay,
384                          int *HSyncStart,
385                          int *HSyncEnd,
386                          int *HTotal,
387                          int *VDisplay,
388                          int *VSyncStart,
389                          int *VSyncEnd,
390                          int *VTotal,
391                          int *flags)
392 {
393    if(current_timing){
394       *pixelClock=current_timing->pixelClock;
395       *HDisplay=current_timing->HDisplay;
396       *HSyncStart=current_timing->HSyncStart;
397       *HSyncEnd=current_timing->HSyncEnd;
398       *HTotal=current_timing->HTotal;
399       *VDisplay=current_timing->VDisplay;
400       *VSyncStart=current_timing->VSyncStart;
401       *VSyncEnd=current_timing->VSyncEnd;
402       *VTotal=current_timing->VTotal;
403       *flags=current_timing->flags;
404       return 0;
405    }
406    return 1;
407 };
408 
vga_changetiming(int pixelClock,int HDisplay,int HSyncStart,int HSyncEnd,int HTotal,int VDisplay,int VSyncStart,int VSyncEnd,int VTotal,int flags)409 int vga_changetiming(int pixelClock,
410 		     int HDisplay,
411    		     int HSyncStart,
412                      int HSyncEnd,
413                      int HTotal,
414                      int VDisplay,
415                      int VSyncStart,
416                      int VSyncEnd,
417                      int VTotal,
418                      int flags) {
419   if(current_timing){
420      new_timing=*current_timing;
421      new_timing.pixelClock+=pixelClock;
422      new_timing.HDisplay+=HDisplay;
423      new_timing.HSyncStart+=HSyncStart;
424      new_timing.HSyncEnd+=HSyncEnd;
425      new_timing.HTotal+=HTotal;
426      new_timing.VDisplay+=VDisplay;
427      new_timing.VSyncStart+=VSyncStart;
428      new_timing.VSyncEnd+=VSyncEnd;
429      new_timing.VTotal+=VTotal;
430      force_timing=&new_timing;
431      vga_setmode(CM|0x8000);
432      force_timing=NULL;
433   };
434 
435   return 1;
436 };
437 
find_up_timing(int x,int y,int * bestx,int * besty,MonitorModeTiming ** bestmodetiming)438 static int find_up_timing(int x, int y, int *bestx, int *besty, MonitorModeTiming **bestmodetiming)
439 {
440       MonitorModeTiming *t;
441       int bestclock=0;
442       int mode_ar;
443 
444       *bestmodetiming=NULL;
445       *bestx=*besty=4096;
446       for (t = user_timings; t; t = t->next) {
447 	     if ((mode_ar=1000*t->VDisplay/t->HDisplay)<=765
448                 && mode_ar>=735
449                 && t->HDisplay >= x
450                 && t->VDisplay >= y
451                 && timing_within_monitor_spec(t)
452                 && t->HDisplay <= *bestx
453                 && t->VDisplay <= *besty
454                 && t->pixelClock>=bestclock
455                 ) {
456                    bestclock = t->pixelClock;
457                    *bestx=t->HDisplay;
458                    *besty=t->VDisplay;
459                    *bestmodetiming = t;
460                    };
461       };
462       for (t = __svgalib_standard_timings; t; t = t->next) {
463 	     if (t->HDisplay >= x
464                 && t->VDisplay >= y
465                 && timing_within_monitor_spec(t)
466                 && t->HDisplay <= *bestx
467                 && t->VDisplay <= *besty
468                 && t->pixelClock>=bestclock
469                 ) {
470                    bestclock = t->pixelClock;
471                    *bestx=t->HDisplay;
472                    *besty=t->VDisplay;
473                    *bestmodetiming = t;
474                    };
475       };
476       return *bestmodetiming!=NULL;
477 };
478 
find_down_timing(int x,int y,int * bestx,int * besty,MonitorModeTiming ** bestmodetiming)479 static int find_down_timing(int x, int y, int *bestx, int *besty, MonitorModeTiming **bestmodetiming)
480 {
481       MonitorModeTiming *t;
482       int bestclock=0;
483       int mode_ar;
484 
485       *bestmodetiming=NULL;
486       *bestx=*besty=0;
487       for (t = user_timings; t; t = t->next) {
488 	     if ((mode_ar=1000*t->VDisplay/t->HDisplay)<=765
489                 && mode_ar>=735
490                 && t->HDisplay <= x
491                 && t->VDisplay <= y
492                 && timing_within_monitor_spec(t)
493                 && t->HDisplay >= *bestx
494                 && t->VDisplay >= *besty
495                 && t->pixelClock>=bestclock
496                 ) {
497                    bestclock = t->pixelClock;
498                    *bestx=t->HDisplay;
499                    *besty=t->VDisplay;
500                    *bestmodetiming = t;
501                    };
502       };
503       for (t = __svgalib_standard_timings; t; t = t->next) {
504 	     if (t->HDisplay <= x
505                 && t->VDisplay <= y
506                 && timing_within_monitor_spec(t)
507                 && t->HDisplay >= *bestx
508                 && t->VDisplay >= *besty
509                 && t->pixelClock>=bestclock
510                 ) {
511                    bestclock = t->pixelClock;
512                    *bestx=t->HDisplay;
513                    *besty=t->VDisplay;
514                    *bestmodetiming = t;
515                    };
516       };
517       return *bestmodetiming!=NULL;
518 };
519 
vga_guesstiming(int x,int y,int clue,int arg)520 int vga_guesstiming(int x, int y, int clue, int arg)
521 {
522 /* This functions tries to add timings that fit a specific mode,
523    by changing the timings of a similar mode
524 
525 currently only works for x:y = 4:3, clue means:
526 0- scale down timing of a higher res mode
527 1- scale up timings of a lower res mode
528 */
529 
530    MonitorModeTiming mmt, *bestmodetiming = NULL ;
531    int bestx,besty /*, bestclock */ ;
532 
533    int aspect_ratio=1000*y/x;
534    switch(clue) {
535       case 0:
536       case 1:
537           if((aspect_ratio>765)||(aspect_ratio<735))return 0;
538           if(clue==0)find_up_timing(x,y,&bestx,&besty,&bestmodetiming);
539           if(clue==1)find_down_timing(x,y,&bestx,&besty,&bestmodetiming);
540           if(bestmodetiming){
541 
542              mmt=*bestmodetiming;
543 
544              mmt.pixelClock=(mmt.pixelClock*x)/bestx;
545              mmt.HDisplay=x;
546              mmt.VDisplay=y;
547              mmt.HSyncStart=(mmt.HSyncStart*x)/bestx;
548              mmt.HSyncEnd=(mmt.HSyncEnd*x)/bestx;
549              mmt.HTotal=(mmt.HTotal*x)/bestx;
550              mmt.VSyncStart=(mmt.VSyncStart*x)/bestx;
551              mmt.VSyncEnd=(mmt.VSyncEnd*x)/bestx;
552              mmt.VTotal=(mmt.VTotal*x)/bestx;
553              __svgalib_addusertiming(&mmt);
554              return 1;
555           };
556           break;
557       case 256:
558       case 257: {
559           int mx;
560 
561           mx=y*4/3;
562           if((clue&1)==0)find_up_timing(mx,y,&bestx,&besty,&bestmodetiming);
563           if((clue&1)==1)find_down_timing(mx,y,&bestx,&besty,&bestmodetiming);
564           if(bestmodetiming){
565 
566              mmt=*bestmodetiming;
567 
568              mmt.pixelClock=(mmt.pixelClock*x)/bestx;
569              mmt.HDisplay=x;
570              mmt.HSyncStart=(mmt.HSyncStart*x)/bestx;
571              mmt.HSyncEnd=(mmt.HSyncEnd*x)/bestx;
572              mmt.HTotal=(mmt.HTotal*x)/bestx;
573              mmt.VDisplay=y;
574              mmt.VSyncStart=(mmt.VSyncStart*mx)/bestx;
575              mmt.VSyncEnd=(mmt.VSyncEnd*mx)/bestx;
576              mmt.VTotal=(mmt.VTotal*mx)/bestx;
577              __svgalib_addusertiming(&mmt);
578              return 1;
579           };
580       };
581       case 258:
582       case 259: {
583           int my;
584 
585           my=(x*3)>>2;
586           if((clue&1)==0)find_up_timing(x,my,&bestx,&besty,&bestmodetiming);
587           if((clue&1)==1)find_down_timing(x,my,&bestx,&besty,&bestmodetiming);
588           if(bestmodetiming){
589 
590              mmt=*bestmodetiming;
591 
592              mmt.pixelClock=(mmt.pixelClock*x)/bestx;
593              mmt.HDisplay=x;
594              mmt.HSyncStart=(mmt.HSyncStart*x)/bestx;
595              mmt.HSyncEnd=(mmt.HSyncEnd*x)/bestx;
596              mmt.HTotal=(mmt.HTotal*x)/bestx;
597              mmt.VDisplay=y;
598              mmt.VSyncStart=(mmt.VSyncStart*y)/besty;
599              mmt.VSyncEnd=(mmt.VSyncEnd*y)/besty;
600              mmt.VTotal=(mmt.VTotal*y)/besty;
601              __svgalib_addusertiming(&mmt);
602              return 1;
603           };
604       };
605    };
606    return 0;
607 };
608 
609 #ifdef GTF
610 
611 /* Everything from here to the end of the file is copyright by
612 scitechsoft. See their original program in utils/gtf subdirectory */
613 
614 typedef struct {
615 	double	margin;			/* Margin size as percentage of display		*/
616 	double	cellGran;		/* Character cell granularity			*/
617 	double	minPorch;		/* Minimum front porch in lines/chars		*/
618 	double	vSyncRqd;		/* Width of V sync in lines			*/
619 	double	hSync;			/* Width of H sync as percent of total		*/
620 	double	minVSyncBP;		/* Minimum vertical sync + back porch (us)	*/
621 	double	m;			/* Blanking formula gradient			*/
622 	double	c;			/* Blanking formula offset			*/
623 	double  k;			/* Blanking formula scaling factor		*/
624 	double  j;			/* Blanking formula scaling factor weight	*/
625 } GTF_constants;
626 
627 static GTF_constants GC = {
628 	1.8,				/* Margin size as percentage of display		*/
629 	8,				/* Character cell granularity			*/
630 	1,				/* Minimum front porch in lines/chars		*/
631 	3,				/* Width of V sync in lines			*/
632 	8,				/* Width of H sync as percent of total		*/
633 	550,				/* Minimum vertical sync + back porch (us)	*/
634 	600,				/* Blanking formula gradient			*/
635 	40,				/* Blanking formula offset			*/
636 	128,				/* Blanking formula scaling factor		*/
637 	20,				/* Blanking formula scaling factor weight	*/
638 };
639 
round(double v)640 static double round(double v)
641 {
642    	double u=v;
643         long j;
644 
645         if(u<0) u=-u;
646         u=u+0.5;
647         j=u;
648         if(v<0) j=-j;
649 
650 	return j;
651 }
652 
sqrt(double u)653 static double sqrt(double u)
654 {
655    	double v,w;
656         int i;
657         v=0;
658 
659         if(u==0) return 0;
660         if(u<0) u=-u;
661         w=u;
662         if(u<1) w=1;
663         for(i=0;i<50;i++){
664               w=w/2;
665               if(v*v==u)break;
666               if(v*v<u)v=v+w;
667               if(v*v>u)v=v-w;
668         };
669 
670    	return v;
671 }
GetInternalConstants(GTF_constants * c)672 static void GetInternalConstants(GTF_constants *c)
673 {
674 	c->margin = GC.margin;
675 	c->cellGran = round(GC.cellGran);
676 	c->minPorch = round(GC.minPorch);
677 	c->vSyncRqd = round(GC.vSyncRqd);
678 	c->hSync = GC.hSync;
679 	c->minVSyncBP = GC.minVSyncBP;
680 	if (GC.k == 0)
681 		c->k = 0.001;
682 	else
683 		c->k = GC.k;
684 	c->m = (c->k / 256) * GC.m;
685 	c->c = (GC.c - GC.j) * (c->k / 256) + GC.j;
686 	c->j = GC.j;
687 }
688 
GTF_calcTimings(double hPixels,double vLines,double freq,int type,int wantMargins,int wantInterlace,int wantDblscan,MonitorModeTiming * mmt)689 static void GTF_calcTimings(double hPixels,double vLines,double freq,
690 	int type,int wantMargins,int wantInterlace, int wantDblscan,
691         MonitorModeTiming *mmt)
692 {
693 	double  		interlace,vFieldRate,hPeriod=0;
694 	double  		topMarginLines,botMarginLines;
695 	double  		leftMarginPixels,rightMarginPixels;
696 	double			hPeriodEst=0,vSyncBP=0,vBackPorch=0;
697 	double			vTotalLines=0,vFieldRateEst;
698 	double			hTotalPixels,hTotalActivePixels,hBlankPixels;
699 	double			idealDutyCycle=0,hSyncWidth,hSyncBP,hBackPorch;
700 	double			idealHPeriod;
701 	double			vFreq,hFreq,dotClock;
702 	GTF_constants   c;
703 
704 	/* Get rounded GTF constants used for internal calculations */
705 	GetInternalConstants(&c);
706 
707 	/* Move input parameters into appropriate variables */
708 	vFreq = hFreq = dotClock = freq;
709 
710 	/* Round pixels to character cell granularity */
711 	hPixels = round(hPixels / c.cellGran) * c.cellGran;
712 
713 	/* For interlaced mode halve the vertical parameters, and double
714 	 * the required field refresh rate.
715 	 */
716 
717         if(wantDblscan) vLines = vLines * 2;
718 	if (wantInterlace) {
719 		vLines = round(vLines / 2);
720 		vFieldRate = vFreq * 2;
721 		dotClock = dotClock * 2;
722 		interlace = 0.5;
723 		}
724 	else {
725 		vFieldRate = vFreq;
726 		interlace = 0;
727 		}
728 
729 	/* Determine the lines for margins */
730 	if (wantMargins) {
731 		topMarginLines = round(c.margin / 100 * vLines);
732 		botMarginLines = round(c.margin / 100 * vLines);
733 		}
734 	else {
735 		topMarginLines = 0;
736 		botMarginLines = 0;
737 		}
738 
739 	if (type != GTF_lockPF) {
740 		if (type == GTF_lockVF) {
741 			/* Estimate the horizontal period */
742 			hPeriodEst = ((1/vFieldRate) - (c.minVSyncBP/1000000)) /
743 				(vLines + (2*topMarginLines) + c.minPorch + interlace) * 1000000;
744 
745 			/* Find the number of lines in vSync + back porch */
746 			vSyncBP = round(c.minVSyncBP / hPeriodEst);
747 			}
748 		else if (type == GTF_lockHF) {
749 			/* Find the number of lines in vSync + back porch */
750 			vSyncBP = round((c.minVSyncBP * hFreq) / 1000);
751 			}
752 
753 		/* Find the number of lines in the V back porch alone */
754 		vBackPorch = vSyncBP - c.vSyncRqd;
755 
756 		/* Find the total number of lines in the vertical period */
757 		vTotalLines = vLines + topMarginLines + botMarginLines + vSyncBP
758 			+ interlace + c.minPorch;
759 
760 		if (type == GTF_lockVF) {
761 			/* Estimate the vertical frequency */
762 			vFieldRateEst = 1000000 / (hPeriodEst * vTotalLines);
763 
764 			/* Find the actual horizontal period */
765 			hPeriod = (hPeriodEst * vFieldRateEst) / vFieldRate;
766 
767 			/* Find the actual vertical field frequency */
768 			vFieldRate = 1000000 / (hPeriod * vTotalLines);
769 			}
770 		else if (type == GTF_lockHF) {
771 			/* Find the actual vertical field frequency */
772 			vFieldRate = (hFreq / vTotalLines) * 1000;
773 			}
774 		}
775 
776 	/* Find the number of pixels in the left and right margins */
777 	if (wantMargins) {
778 		leftMarginPixels = round(hPixels * c.margin) / (100 * c.cellGran);
779 		rightMarginPixels = round(hPixels * c.margin) / (100 * c.cellGran);
780 		}
781 	else {
782 		leftMarginPixels = 0;
783 		rightMarginPixels = 0;
784 		}
785 
786 	/* Find the total number of active pixels in image + margins */
787 	hTotalActivePixels = hPixels + leftMarginPixels + rightMarginPixels;
788 
789 	if (type == GTF_lockVF) {
790 		/* Find the ideal blanking duty cycle */
791 		idealDutyCycle = c.c - ((c.m * hPeriod) / 1000);
792 		}
793 	else if (type == GTF_lockHF) {
794 		/* Find the ideal blanking duty cycle */
795 		idealDutyCycle = c.c - (c.m / hFreq);
796 		}
797 	else if (type == GTF_lockPF) {
798 		/* Find ideal horizontal period from blanking duty cycle formula */
799 		idealHPeriod = (((c.c - 100) + (sqrt(((100-c.c)*(100-c.c)) +
800 			(0.4 * c.m * (hTotalActivePixels + rightMarginPixels +
801 			leftMarginPixels) / dotClock)))) / (2 * c.m)) * 1000;
802 
803 		/* Find the ideal blanking duty cycle */
804 		idealDutyCycle = c.c - ((c.m * idealHPeriod) / 1000);
805 		}
806 
807 	/* Find the number of pixels in blanking time */
808 	hBlankPixels = round((hTotalActivePixels * idealDutyCycle) /
809 		((100 - idealDutyCycle) * 2 * c.cellGran)) * (2 * c.cellGran);
810 
811 	/* Find the total number of pixels */
812 	hTotalPixels = hTotalActivePixels + hBlankPixels;
813 
814 	/* Find the horizontal back porch */
815 	hBackPorch = round((hBlankPixels / 2) / c.cellGran) * c.cellGran;
816 
817 	/* Find the horizontal sync width */
818 	hSyncWidth = round(((c.hSync/100) * hTotalPixels) / c.cellGran) * c.cellGran;
819 
820 	/* Find the horizontal sync + back porch */
821 	hSyncBP = hBackPorch + hSyncWidth;
822 
823 	if (type == GTF_lockPF) {
824 		/* Find the horizontal frequency */
825 		hFreq = (dotClock / hTotalPixels) * 1000;
826 
827 		/* Find the horizontal period */
828 		hPeriod = 1000 / hFreq;
829 
830 		/* Find the number of lines in vSync + back porch */
831 		vSyncBP = round((c.minVSyncBP * hFreq) / 1000);
832 
833 		/* Find the number of lines in the V back porch alone */
834 		vBackPorch = vSyncBP - c.vSyncRqd;
835 
836 		/* Find the total number of lines in the vertical period */
837 		vTotalLines = vLines + topMarginLines + botMarginLines + vSyncBP
838 			+ interlace + c.minPorch;
839 
840 		/* Find the actual vertical field frequency */
841 		vFieldRate = (hFreq / vTotalLines) * 1000;
842 		}
843 	else {
844 		if (type == GTF_lockVF) {
845 			/* Find the horizontal frequency */
846 			hFreq = 1000 / hPeriod;
847 			}
848 		else if (type == GTF_lockHF) {
849 			/* Find the horizontal frequency */
850 			hPeriod = 1000 / hFreq;
851 			}
852 
853 		/* Find the pixel clock frequency */
854 		dotClock = hTotalPixels / hPeriod;
855 		}
856 
857 	/* Find the vertical frame frequency */
858 	if (wantInterlace) {
859 		vFreq = vFieldRate / 2;
860 		}
861 	else
862 		vFreq = vFieldRate;
863 
864 	mmt->pixelClock = dotClock;
865 
866 	/* Determine the vertical timing parameters */
867 	mmt->HTotal = hTotalPixels;
868 	mmt->HDisplay = hTotalActivePixels;
869 	mmt->HSyncStart = mmt->HTotal - hSyncBP;
870 	mmt->HSyncEnd = mmt->HTotal - hBackPorch;
871 
872 	/* Determine the vertical timing parameters */
873 	mmt->VTotal = vTotalLines;
874 	mmt->VDisplay = vLines;
875 	mmt->VSyncStart = mmt->VTotal - vSyncBP;
876 	mmt->VSyncEnd = mmt->VTotal - vBackPorch;
877 
878         if(wantDblscan) {
879 	    mmt->VTotal >>= 1;
880 	    mmt->VDisplay >>= 1 ;
881 	    mmt->VSyncStart >>= 1 ;
882 	    mmt->VSyncEnd >>= 1 ;
883         };
884 
885         if(wantInterlace) {
886 	    mmt->VTotal <<= 1;
887 	    mmt->VDisplay <<= 1 ;
888 	    mmt->VSyncStart <<= 1 ;
889 	    mmt->VSyncEnd <<= 1 ;
890         };
891 
892         mmt->flags = NHSYNC | PVSYNC | ((wantInterlace) ? INTERLACED : 0)
893                             | ((wantDblscan) ? DOUBLESCAN : 0);
894 }
895 
896 #endif
897