1/*
2 * Copyright 1999 SuSE, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of SuSE not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  SuSE makes no representations about the
11 * suitability of this software for any purpose.  It is provided "as is"
12 * without express or implied warranty.
13 *
14 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
16 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
18 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 * Author:  Keith Packard, SuSE, Inc.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <kdrive-config.h>
26#endif
27#include "kdrive.h"
28
29const KdMonitorTiming  kdMonitorTimings[] = {
30    /*	H	V	Hz	KHz */
31		/*  FP	    BP	    BLANK   POLARITY */
32
33    /* IPAQ modeline:
34     *
35     * Modeline "320x240"      5.7222 320 337 340 352   240 241 244 254"
36     */
37    {   320,	240,	64,	16256,
38	            17,	    12,	    32,     KdSyncNegative,
39	            1,      11,     14,     KdSyncNegative,
40    },
41
42    /* Other VESA modes */
43    {	640,	350,	85,	31500,			    /* VESA */
44		    32,	    96,	    192,    KdSyncPositive, /* 26.413 */
45		    32,	    60,	    95,	    KdSyncNegative, /* 59.354 */
46    },
47    {	640,	400,	60,	31500,			    /* VESA */
48		    32,	    96,	    192,    KdSyncNegative, /* 26.413 */
49		    1,	    41,	    45,	    KdSyncPositive, /* 59.354 */
50    },
51    {	720,	400,	85,	35500,			    /* VESA */
52		    36,	    108,    216,    KdSyncNegative, /* 37.927 */
53		    1,	    42,	    46,	    KdSyncPositive, /* 85.039 */
54    },
55
56
57    /* Modeline "720x576"     29.000 720  736  800  880   576  577  580  625 */
58    {
59        720,    576,    52,     32954,                      /* PAL Video */
60        16,     80,  160, KdSyncPositive, /* 32.954 */
61        1,      45,   49, KdSyncPositive, /* 52.727 */
62    },
63
64    /* 640x480 modes */
65    {	640,	480,	85,	36000,			    /* VESA */
66		    56,	    80,	    192,    KdSyncNegative, /* 43.269 */
67		    1,	    25,	    29,	    KdSyncNegative, /* 85.008 */
68    },
69    {	640,	480,	75,	31500,			    /* VESA */
70		    16,	    120,    200,    KdSyncNegative, /* 37.500 */
71		    1,	    16,	    20,	    KdSyncNegative, /* 75.000 */
72    },
73    {	640,	480,	72,	31500,			    /* VESA */
74		    16,	    120,    176,    KdSyncNegative, /* 37.861 */
75		    1,	    20,	    24,	    KdSyncNegative, /* 72.809 */
76    },
77    {	640,	480,	60,	25175,			    /* VESA */
78		   16,	    48,	    160,    KdSyncNegative, /* 31.469 */
79		   10,	    33,	    45,	    KdSyncNegative, /* 59.940 */
80    },
81
82    /* 800x600 modes */
83    {	800,	600,	85,	56250,			    /* VESA */
84		    32,	    152,    248,    KdSyncPositive, /* 53.674 */
85		    1,	    27,	    31,	    KdSyncPositive, /* 85.061 */
86    },
87    {	800,	600,	75,	49500,			    /* VESA */
88		    16,	    160,    256,    KdSyncPositive, /* 46.875 */
89		    1,	    21,	    25,	    KdSyncPositive, /* 75.000 */
90    },
91    /* DEFAULT */
92#define MONITOR_TIMING_DEFAULT	9
93    {	800,	600,	72,	50000,			    /* VESA */
94		    56,	    64,	    240,    KdSyncPositive, /* 48.077 */
95		    37,	    23,	    66,	    KdSyncPositive, /* 72.188 */
96    },
97    {	800,	600,	60,	40000,			    /* VESA */
98		    40,	    88,	    256,    KdSyncPositive, /* 37.879 */
99		    1,	    23,	    28,	    KdSyncPositive, /* 60.317 */
100    },
101    {	800,	600,	56,	36000,			    /* VESA */
102		    24,	    128,    224,    KdSyncPositive, /* 35.156 */
103		    1,	    22,	    25,	    KdSyncPositive, /* 56.250 */
104    },
105
106    /* 1024x768 modes */
107    {	1024,	768,	85,	94500,			    /* VESA */
108		    48,	    208,    352,    KdSyncPositive, /* 68.677 */
109		    1,	    36,	    40,	    KdSyncPositive, /* 84.997 */
110    },
111    {	1024,	768,	75,	78750,			    /* VESA */
112		    16,	    176,    288,    KdSyncPositive, /* 60.023 */
113		    1,	    28,	    32,	    KdSyncPositive, /* 75.029 */
114    },
115    {	1024,	768,	70,	75000,			    /* VESA */
116		    24,	    144,    304,    KdSyncNegative, /* 56.476 */
117		    3,	    29,	    38,	    KdSyncNegative, /* 70.069 */
118    },
119    {	1024,	768,	60,	65000,			    /* VESA */
120		    24,	    160,    320,    KdSyncNegative, /* 48.363 */
121		    3,	    29,	    38,	    KdSyncNegative, /* 60.004 */
122    },
123
124    /* 1152x864 mode */
125    {	1152,	864,	75,	108000,			    /* VESA */
126		    64,	    256,    448,    KdSyncPositive, /* 67.500 */
127		    1,	    32,	    36,	    KdSyncPositive, /* 75.000 */
128    },
129
130    /* 1152x900 modes */
131    {	1152,	900,	85,	122500,			    /* ADDED */
132		    48,	    208,    384,    KdSyncPositive, /* 79.753 */
133		    1,	    32,	    38,	    KdSyncPositive, /* 85.024 */
134    },
135    {	1152,	900,	75,	108250,			    /* ADDED */
136		    32,	    208,    384,    KdSyncPositive, /* 70.475 */
137		    1,	    32,	    38,	    KdSyncPositive, /* 75.133 */
138    },
139    {	1152,	900,	70,	100250,			    /* ADDED */
140		    32,	    208,    384,    KdSyncPositive, /* 65.267 */
141		    2,	    32,	    38,	    KdSyncPositive, /* 69.581 */
142    },
143    {	1152,	900,	66,	95000,			    /* ADDED */
144		    32,	    208,    384,    KdSyncPositive, /* 61.849 */
145		    1,	    32,	    38,	    KdSyncPositive, /* 65.937 */
146    },
147
148    /* 1280x854 modes */
149    {   1280,   854,   103,     12500,			    /* ADDED */
150	            56,     16,     128,    KdSyncPositive, /* 102.554 */
151	            1,     216,     12,     KdSyncPositive,
152    },
153
154    /* 1280x960 modes */
155    {	1280,	960,	85,	148500,			    /* VESA */
156		    64,	    224,    448,    KdSyncPositive, /* 85.938 */
157		    1,	    47,	    51,	    KdSyncPositive, /* 85.002 */
158    },
159    {	1280,	960,	60,	108000,			    /* VESA */
160		    96,	    312,    520,    KdSyncPositive, /* 60.000 */
161		    1,	    36,	    40,	    KdSyncPositive, /* 60.000 */
162    },
163
164    /* 1280x1024 modes */
165    {	1280,	1024,	85,	157500,			    /* VESA */
166		    64,	    224,    448,    KdSyncPositive, /* 91.146 */
167		    1,	    44,	    48,	    KdSyncPositive, /* 85.024 */
168    },
169    {	1280,	1024,	75,	135000,			    /* VESA */
170		    16,	    248,    408,    KdSyncPositive, /* 79.976 */
171		    1,	    38,	    42,	    KdSyncPositive, /* 75.025 */
172    },
173    {	1280,	1024,	60,	108000,			    /* VESA */
174		    48,	    248,    408,    KdSyncPositive, /* 63.981 */
175		    1,	    38,	    42,	    KdSyncPositive, /* 60.020 */
176    },
177
178    /* 1600x1200 modes */
179    {	1600,	1200,	85,	229500,			    /* VESA */
180		    64,	    304,    560,    KdSyncPositive, /* 106.250 */
181		    1,	    46,	    50,	    KdSyncPositive, /* 85.000 */
182    },
183    {	1600,	1200,	75,	202500,			    /* VESA */
184		    64,	    304,    560,    KdSyncPositive, /* 93.750 */
185		    1,	    46,	    50,	    KdSyncPositive, /* 75.000 */
186    },
187    {	1600,	1200,	70,	189000,			    /* VESA */
188		    64,	    304,    560,    KdSyncPositive, /* 87.500 */
189		    1,	    46,	    50,	    KdSyncPositive, /* 70.000 */
190    },
191    {	1600,	1200,	65,	175500,			    /* VESA */
192		    64,	    304,    560,    KdSyncPositive, /* 81.250 */
193		    1,	    46,	    50,	    KdSyncPositive, /* 65.000 */
194    },
195    {	1600,	1200,	60,	162000,			    /* VESA */
196		    64,	    304,    560,    KdSyncPositive, /* 75.000 */
197		    1,	    46,	    50,	    KdSyncPositive, /* 60.000 */
198    },
199
200    /* 1792x1344 modes */
201    {	1792,	1344,	85,	301500,			    /* ADDED */
202		    96,	    352,    672,    KdSyncNegative, /* 122.362 */
203		    1,	    92,	    96,	    KdSyncPositive, /* 84.974 */
204    },
205    {	1792,	1344,	75,	261000,			    /* VESA */
206		    96,	    352,    664,    KdSyncNegative, /* 106.270 */
207		    1,	    69,	    73,	    KdSyncPositive, /* 74.997 */
208    },
209    {	1792,	1344,	60,	204750,			    /* VESA */
210		    128,    328,    656,    KdSyncNegative, /* 83.640 */
211		    1,	    46,	    50,	    KdSyncPositive, /* 60.000 */
212    },
213
214#if 0
215    { 1800, 1012, 75 },
216    { 1906, 1072, 68 },
217#endif
218
219    /* 1856x1392 modes */
220    {	1856,	1392,	85,	330500,			    /* ADDED */
221		    160,    352,    736,    KdSyncNegative, /* 127.508 */
222		    1,	    104,    108,    KdSyncPositive, /* 85.001 */
223    },
224    {	1856,	1392,	75,	288000,			    /* VESA */
225		    128,    352,    704,    KdSyncNegative, /* 112.500 */
226		    1,	    104,    108,    KdSyncPositive, /* 75.000 */
227    },
228    {	1856,	1392,	60,	218250,			    /* VESA */
229		    96,	    352,    672,    KdSyncNegative, /* 86.333 */
230		    1,	    43,	    47,	    KdSyncPositive, /* 59.995 */
231    },
232
233    /* 1920x1440 modes */
234    {	1920,	1440,	85,	341750,			    /* ADDED */
235		    160,    352,    760,    KdSyncNegative, /* 127.512 */
236		    1,	    56,	    60,	    KdSyncPositive, /* 85.012 */
237    },
238    {	1920,	1440,	75,	297000,			    /* VESA */
239		    144,    352,    720,    KdSyncNegative, /* 112.500 */
240		    1,	    56,	    60,	    KdSyncPositive, /* 75.000 */
241    },
242    {	1920,	1440,	60,	234000,			    /* VESA */
243		    128,    244,    680,    KdSyncNegative, /* 90.000 */
244		    1,	    56,	    60,	    KdSyncPositive, /* 60.000 */
245    },
246};
247
248#define NUM_MONITOR_TIMINGS (sizeof kdMonitorTimings/sizeof kdMonitorTimings[0])
249
250const int kdNumMonitorTimings = NUM_MONITOR_TIMINGS;
251
252const KdMonitorTiming *
253KdFindMode (KdScreenInfo    *screen,
254	    Bool	    (*supported) (KdScreenInfo *,
255					  const KdMonitorTiming *))
256{
257    int			    i;
258    const KdMonitorTiming   *t;
259
260    for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++)
261    {
262	if ((*supported) (screen, t) &&
263	    t->horizontal == screen->width &&
264	    t->vertical == screen->height &&
265	    (!screen->rate || t->rate <= screen->rate))
266	{
267	    return t;
268	}
269    }
270    ErrorF("Warning: mode not found, using default\n");
271    return &kdMonitorTimings[MONITOR_TIMING_DEFAULT];
272}
273
274static const KdMonitorTiming *
275kdFindPrevSize (const KdMonitorTiming *old)
276{
277    const KdMonitorTiming   *new, *prev;
278
279    if (old == kdMonitorTimings)
280	return 0;
281    new = old;
282    /*
283     * Search for the previous size
284     */
285    while (new != kdMonitorTimings)
286    {
287	new--;
288	if (new->horizontal != old->horizontal &&
289	    new->vertical != old->vertical)
290	{
291	    break;
292	}
293    }
294    /*
295     * Match the refresh rate (<=)
296     */
297    while (new != kdMonitorTimings)
298    {
299	prev = new - 1;
300	if (prev->horizontal == new->horizontal &&
301	    prev->vertical == new->vertical &&
302	    prev->rate > old->rate)
303	{
304	    break;
305	}
306	new--;
307    }
308    return new;
309}
310
311Bool
312KdTuneMode (KdScreenInfo    *screen,
313	    Bool	    (*usable) (KdScreenInfo *),
314	    Bool	    (*supported) (KdScreenInfo *,
315					  const KdMonitorTiming *))
316{
317    const KdMonitorTiming   *t;
318
319    while (!(*usable) (screen))
320    {
321	/*
322	 * Fix requested depth and geometry until it works
323	 */
324	if (screen->fb.depth > 16)
325	    screen->fb.depth = 16;
326	else if (screen->fb.depth > 8)
327	    screen->fb.depth = 8;
328	else
329	{
330	    t = kdFindPrevSize (KdFindMode (screen, supported));
331	    if (!t)
332		return FALSE;
333	    screen->width = t->horizontal;
334	    screen->height = t->vertical;
335	    screen->rate = t->rate;
336	}
337    }
338    return TRUE;
339}
340
341#ifdef RANDR
342Bool
343KdRandRGetInfo (ScreenPtr pScreen,
344		int randr,
345		Bool (*supported) (ScreenPtr pScreen,
346				   const KdMonitorTiming *))
347{
348    KdScreenPriv(pScreen);
349    KdScreenInfo	    *screen = pScreenPriv->screen;
350    int			    i;
351    const KdMonitorTiming   *t;
352
353    for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++)
354    {
355	if ((*supported) (pScreen, t))
356	{
357	    RRScreenSizePtr pSize;
358
359	    pSize = RRRegisterSize (pScreen,
360				    t->horizontal,
361				    t->vertical,
362				    screen->width_mm,
363				    screen->height_mm);
364	    if (!pSize)
365		return FALSE;
366	    if (!RRRegisterRate (pScreen, pSize, t->rate))
367		return FALSE;
368	    if (t->horizontal == screen->width &&
369		t->vertical == screen->height &&
370		t->rate == screen->rate)
371		RRSetCurrentConfig (pScreen, randr, t->rate, pSize);
372	}
373    }
374
375    return TRUE;
376}
377
378const KdMonitorTiming *
379KdRandRGetTiming (ScreenPtr	    pScreen,
380		  Bool		    (*supported) (ScreenPtr pScreen,
381						  const KdMonitorTiming *),
382		  int		    rate,
383		  RRScreenSizePtr   pSize)
384{
385    int			    i;
386    const KdMonitorTiming   *t;
387
388    for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++)
389    {
390	if (t->horizontal == pSize->width &&
391	    t->vertical == pSize->height &&
392	    t->rate == rate &&
393	    (*supported) (pScreen, t))
394	    return t;
395    }
396    return 0;
397}
398#endif
399