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