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