Subversion Repositories shark

Rev

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