upgrade for xorg-server 1.12.99.905 (for 1.13 RC)
[framework/uifw/xorg/server/xorg-server.git] / hw / xfree86 / utils / cvt / cvt.c
1 /*
2  * Copyright 2005-2006 Luc Verhaegen.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23
24 /* Standalone VESA CVT standard timing modelines generator. */
25
26 #include "xf86.h"
27
28 /* FatalError implementation used by the server code we built in */
29 void
30 FatalError(const char *f, ...)
31 {
32     va_list args;
33
34     va_start(args, f);
35     vfprintf(stderr, f, args);
36     va_end(args);
37     exit(1);
38 }
39
40 /* xnfalloc implementation used by the server code we built in */
41 pointer
42 XNFalloc(unsigned long n)
43 {
44     pointer r;
45
46     r = malloc(n);
47     if (!r) {
48         perror("malloc failed");
49         exit(1);
50     }
51     return r;
52 }
53
54 /* xnfcalloc implementation used by the server code we built in */
55 pointer
56 XNFcalloc(unsigned long n)
57 {
58     pointer r;
59
60     r = calloc(1, n);
61     if (!r) {
62         perror("calloc failed");
63         exit(1);
64     }
65     return r;
66 }
67
68 /*
69  * Quickly check wether this is a CVT standard mode.
70  */
71 static Bool
72 CVTCheckStandard(int HDisplay, int VDisplay, float VRefresh, Bool Reduced,
73                  Bool Verbose)
74 {
75     Bool IsCVT = TRUE;
76
77     if ((!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) ||
78         (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) ||
79         (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) ||
80         (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) ||
81         (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay)));
82     else {
83         if (Verbose)
84             fprintf(stderr, "Warning: Aspect Ratio is not CVT standard.\n");
85         IsCVT = FALSE;
86     }
87
88     if ((VRefresh != 50.0) && (VRefresh != 60.0) &&
89         (VRefresh != 75.0) && (VRefresh != 85.0)) {
90         if (Verbose)
91             fprintf(stderr, "Warning: Refresh Rate is not CVT standard "
92                     "(50, 60, 75 or 85Hz).\n");
93         IsCVT = FALSE;
94     }
95
96     return IsCVT;
97 }
98
99 /*
100  * I'm not documenting --interlaced for obvious reasons, even though I did
101  * implement it. I also can't deny having looked at gtf here.
102  */
103 static void
104 PrintUsage(char *Name)
105 {
106     fprintf(stderr, "\n");
107     fprintf(stderr, "usage: %s [-v|--verbose] [-r|--reduced] X Y [refresh]\n",
108             Name);
109     fprintf(stderr, "\n");
110     fprintf(stderr, " -v|--verbose : Warn about CVT standard adherance.\n");
111     fprintf(stderr, " -r|--reduced : Create a mode with reduced blanking "
112             "(default: normal blanking).\n");
113     fprintf(stderr, "            X : Desired horizontal resolution "
114             "(multiple of 8, required).\n");
115     fprintf(stderr,
116             "            Y : Desired vertical resolution (required).\n");
117     fprintf(stderr,
118             "      refresh : Desired refresh rate (default: 60.0Hz).\n");
119     fprintf(stderr, "\n");
120
121     fprintf(stderr, "Calculates VESA CVT (Coordinated Video Timing) modelines"
122             " for use with X.\n");
123 }
124
125 /*
126  *
127  */
128 static void
129 PrintComment(DisplayModeRec * Mode, Bool CVT, Bool Reduced)
130 {
131     printf("# %dx%d %.2f Hz ", Mode->HDisplay, Mode->VDisplay, Mode->VRefresh);
132
133     if (CVT) {
134         printf("(CVT %.2fM",
135                ((float) Mode->HDisplay * Mode->VDisplay) / 1000000.0);
136
137         if (!(Mode->VDisplay % 3) &&
138             ((Mode->VDisplay * 4 / 3) == Mode->HDisplay))
139             printf("3");
140         else if (!(Mode->VDisplay % 9) &&
141                  ((Mode->VDisplay * 16 / 9) == Mode->HDisplay))
142             printf("9");
143         else if (!(Mode->VDisplay % 10) &&
144                  ((Mode->VDisplay * 16 / 10) == Mode->HDisplay))
145             printf("A");
146         else if (!(Mode->VDisplay % 4) &&
147                  ((Mode->VDisplay * 5 / 4) == Mode->HDisplay))
148             printf("4");
149         else if (!(Mode->VDisplay % 9) &&
150                  ((Mode->VDisplay * 15 / 9) == Mode->HDisplay))
151             printf("9");
152
153         if (Reduced)
154             printf("-R");
155
156         printf(") ");
157     }
158     else
159         printf("(CVT) ");
160
161     printf("hsync: %.2f kHz; ", Mode->HSync);
162     printf("pclk: %.2f MHz", ((float) Mode->Clock) / 1000.0);
163
164     printf("\n");
165 }
166
167 /*
168  * Originally grabbed from xf86Mode.c.
169  *
170  * Ignoring the actual Mode->name, as the user will want something solid
171  * to grab hold of.
172  */
173 static void
174 PrintModeline(DisplayModePtr Mode, int HDisplay, int VDisplay, float VRefresh,
175               Bool Reduced)
176 {
177     if (Reduced)
178         printf("Modeline \"%dx%dR\"  ", HDisplay, VDisplay);
179     else
180         printf("Modeline \"%dx%d_%.2f\"  ", HDisplay, VDisplay, VRefresh);
181
182     printf("%6.2f  %i %i %i %i  %i %i %i %i", Mode->Clock / 1000.,
183            Mode->HDisplay, Mode->HSyncStart, Mode->HSyncEnd, Mode->HTotal,
184            Mode->VDisplay, Mode->VSyncStart, Mode->VSyncEnd, Mode->VTotal);
185
186     if (Mode->Flags & V_INTERLACE)
187         printf(" interlace");
188     if (Mode->Flags & V_PHSYNC)
189         printf(" +hsync");
190     if (Mode->Flags & V_NHSYNC)
191         printf(" -hsync");
192     if (Mode->Flags & V_PVSYNC)
193         printf(" +vsync");
194     if (Mode->Flags & V_NVSYNC)
195         printf(" -vsync");
196
197     printf("\n");
198 }
199
200 /*
201  *
202  */
203 int
204 main(int argc, char *argv[])
205 {
206     DisplayModeRec *Mode;
207     int HDisplay = 0, VDisplay = 0;
208     float VRefresh = 0.0;
209     Bool Reduced = FALSE, Verbose = FALSE, IsCVT;
210     Bool Interlaced = FALSE;
211     int n;
212
213     if ((argc < 3) || (argc > 7)) {
214         PrintUsage(argv[0]);
215         return 1;
216     }
217
218     /* This doesn't filter out bad flags properly. Bad flags get passed down
219      * to atoi/atof, which then return 0, so that these variables can get
220      * filled next time round. So this is just a cosmetic problem.
221      */
222     for (n = 1; n < argc; n++) {
223         if (!strcmp(argv[n], "-r") || !strcmp(argv[n], "--reduced"))
224             Reduced = TRUE;
225         else if (!strcmp(argv[n], "-i") || !strcmp(argv[n], "--interlaced"))
226             Interlaced = TRUE;
227         else if (!strcmp(argv[n], "-v") || !strcmp(argv[n], "--verbose"))
228             Verbose = TRUE;
229         else if (!strcmp(argv[n], "-h") || !strcmp(argv[n], "--help")) {
230             PrintUsage(argv[0]);
231             return 0;
232         }
233         else if (!HDisplay) {
234             HDisplay = atoi(argv[n]);
235             if (!HDisplay) {
236                 PrintUsage(argv[0]);
237                 return 1;
238             }
239         }
240         else if (!VDisplay) {
241             VDisplay = atoi(argv[n]);
242             if (!VDisplay) {
243                 PrintUsage(argv[0]);
244                 return 1;
245             }
246         }
247         else if (!VRefresh) {
248             VRefresh = atof(argv[n]);
249             if (!VRefresh) {
250                 PrintUsage(argv[0]);
251                 return 1;
252             }
253         }
254         else {
255             PrintUsage(argv[0]);
256             return 1;
257         }
258     }
259
260     if (!HDisplay || !VDisplay) {
261         PrintUsage(argv[0]);
262         return 0;
263     }
264
265     /* Default to 60.0Hz */
266     if (!VRefresh)
267         VRefresh = 60.0;
268
269     /* Horizontal timing is always a multiple of 8: round up. */
270     if (HDisplay & 0x07) {
271         HDisplay &= ~0x07;
272         HDisplay += 8;
273     }
274
275     if (Reduced) {
276         if ((VRefresh / 60.0) != floor(VRefresh / 60.0)) {
277             fprintf(stderr,
278                     "\nERROR: Multiple of 60Hz refresh rate required for "
279                     " reduced blanking.\n");
280             PrintUsage(argv[0]);
281             return 0;
282         }
283     }
284
285     IsCVT = CVTCheckStandard(HDisplay, VDisplay, VRefresh, Reduced, Verbose);
286
287     Mode = xf86CVTMode(HDisplay, VDisplay, VRefresh, Reduced, Interlaced);
288
289     PrintComment(Mode, IsCVT, Reduced);
290     PrintModeline(Mode, HDisplay, VDisplay, VRefresh, Reduced);
291
292     return 0;
293 }