Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | #include "xf86Modes.h" | |
28 | ||
29 | /* FatalError implementation used by the server code we built in */ | |
30 | void | |
31 | FatalError(const char *f, ...) | |
32 | { | |
33 | va_list args; | |
34 | ||
35 | va_start(args, f); | |
36 | vfprintf(stderr, f, args); | |
37 | va_end(args); | |
38 | exit(1); | |
39 | } | |
40 | ||
41 | /* xnfalloc implementation used by the server code we built in */ | |
42 | pointer | |
43 | XNFalloc(unsigned long n) | |
44 | { | |
45 | pointer r; | |
46 | ||
47 | r = malloc(n); | |
48 | if (!r) { | |
49 | perror("malloc failed"); | |
50 | exit(1); | |
51 | } | |
52 | return r; | |
53 | } | |
54 | ||
55 | /* xnfcalloc implementation used by the server code we built in */ | |
56 | pointer | |
57 | XNFcalloc(unsigned long n) | |
58 | { | |
59 | pointer r; | |
60 | ||
61 | r = calloc(1, n); | |
62 | if (!r) { | |
63 | perror("calloc failed"); | |
64 | exit(1); | |
65 | } | |
66 | return r; | |
67 | } | |
68 | ||
69 | /* | |
70 | * Quickly check wether this is a CVT standard mode. | |
71 | */ | |
72 | static Bool | |
73 | CVTCheckStandard(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, | |
74 | Bool Verbose) | |
75 | { | |
76 | Bool IsCVT = TRUE; | |
77 | ||
78 | if ((!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) || | |
79 | (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) || | |
80 | (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) || | |
81 | (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) || | |
82 | (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))); | |
83 | else { | |
84 | if (Verbose) | |
85 | fprintf(stderr, "Warning: Aspect Ratio is not CVT standard.\n"); | |
86 | IsCVT = FALSE; | |
87 | } | |
88 | ||
89 | if ((VRefresh != 50.0) && (VRefresh != 60.0) && | |
90 | (VRefresh != 75.0) && (VRefresh != 85.0)) { | |
91 | if (Verbose) | |
92 | fprintf(stderr, "Warning: Refresh Rate is not CVT standard " | |
93 | "(50, 60, 75 or 85Hz).\n"); | |
94 | IsCVT = FALSE; | |
95 | } | |
96 | ||
97 | return IsCVT; | |
98 | } | |
99 | ||
100 | /* | |
101 | * I'm not documenting --interlaced for obvious reasons, even though I did | |
102 | * implement it. I also can't deny having looked at gtf here. | |
103 | */ | |
104 | static void | |
105 | PrintUsage(char *Name) | |
106 | { | |
107 | fprintf(stderr, "\n"); | |
108 | fprintf(stderr, "usage: %s [-v|--verbose] [-r|--reduced] X Y [refresh]\n", | |
109 | Name); | |
110 | fprintf(stderr, "\n"); | |
111 | fprintf(stderr, " -v|--verbose : Warn about CVT standard adherance.\n"); | |
112 | fprintf(stderr, " -r|--reduced : Create a mode with reduced blanking " | |
113 | "(default: normal blanking).\n"); | |
114 | fprintf(stderr, " X : Desired horizontal resolution " | |
115 | "(multiple of 8, required).\n"); | |
116 | fprintf(stderr, | |
117 | " Y : Desired vertical resolution (required).\n"); | |
118 | fprintf(stderr, | |
119 | " refresh : Desired refresh rate (default: 60.0Hz).\n"); | |
120 | fprintf(stderr, "\n"); | |
121 | ||
122 | fprintf(stderr, "Calculates VESA CVT (Coordinated Video Timing) modelines" | |
123 | " for use with X.\n"); | |
124 | } | |
125 | ||
126 | /* | |
127 | * | |
128 | */ | |
129 | static void | |
130 | PrintComment(DisplayModeRec * Mode, Bool CVT, Bool Reduced) | |
131 | { | |
132 | printf("# %dx%d %.2f Hz ", Mode->HDisplay, Mode->VDisplay, Mode->VRefresh); | |
133 | ||
134 | if (CVT) { | |
135 | printf("(CVT %.2fM", | |
136 | ((float) Mode->HDisplay * Mode->VDisplay) / 1000000.0); | |
137 | ||
138 | if (!(Mode->VDisplay % 3) && | |
139 | ((Mode->VDisplay * 4 / 3) == Mode->HDisplay)) | |
140 | printf("3"); | |
141 | else if (!(Mode->VDisplay % 9) && | |
142 | ((Mode->VDisplay * 16 / 9) == Mode->HDisplay)) | |
143 | printf("9"); | |
144 | else if (!(Mode->VDisplay % 10) && | |
145 | ((Mode->VDisplay * 16 / 10) == Mode->HDisplay)) | |
146 | printf("A"); | |
147 | else if (!(Mode->VDisplay % 4) && | |
148 | ((Mode->VDisplay * 5 / 4) == Mode->HDisplay)) | |
149 | printf("4"); | |
150 | else if (!(Mode->VDisplay % 9) && | |
151 | ((Mode->VDisplay * 15 / 9) == Mode->HDisplay)) | |
152 | printf("9"); | |
153 | ||
154 | if (Reduced) | |
155 | printf("-R"); | |
156 | ||
157 | printf(") "); | |
158 | } | |
159 | else | |
160 | printf("(CVT) "); | |
161 | ||
162 | printf("hsync: %.2f kHz; ", Mode->HSync); | |
163 | printf("pclk: %.2f MHz", ((float) Mode->Clock) / 1000.0); | |
164 | ||
165 | printf("\n"); | |
166 | } | |
167 | ||
168 | /* | |
169 | * Originally grabbed from xf86Mode.c. | |
170 | * | |
171 | * Ignoring the actual Mode->name, as the user will want something solid | |
172 | * to grab hold of. | |
173 | */ | |
174 | static void | |
175 | PrintModeline(DisplayModePtr Mode, int HDisplay, int VDisplay, float VRefresh, | |
176 | Bool Reduced) | |
177 | { | |
178 | if (Reduced) | |
179 | printf("Modeline \"%dx%dR\" ", HDisplay, VDisplay); | |
180 | else | |
181 | printf("Modeline \"%dx%d_%.2f\" ", HDisplay, VDisplay, VRefresh); | |
182 | ||
183 | printf("%6.2f %i %i %i %i %i %i %i %i", Mode->Clock / 1000., | |
184 | Mode->HDisplay, Mode->HSyncStart, Mode->HSyncEnd, Mode->HTotal, | |
185 | Mode->VDisplay, Mode->VSyncStart, Mode->VSyncEnd, Mode->VTotal); | |
186 | ||
187 | if (Mode->Flags & V_INTERLACE) | |
188 | printf(" interlace"); | |
189 | if (Mode->Flags & V_PHSYNC) | |
190 | printf(" +hsync"); | |
191 | if (Mode->Flags & V_NHSYNC) | |
192 | printf(" -hsync"); | |
193 | if (Mode->Flags & V_PVSYNC) | |
194 | printf(" +vsync"); | |
195 | if (Mode->Flags & V_NVSYNC) | |
196 | printf(" -vsync"); | |
197 | ||
198 | printf("\n"); | |
199 | } | |
200 | ||
201 | /* | |
202 | * | |
203 | */ | |
204 | int | |
205 | main(int argc, char *argv[]) | |
206 | { | |
207 | DisplayModeRec *Mode; | |
208 | int HDisplay = 0, VDisplay = 0; | |
209 | float VRefresh = 0.0; | |
210 | Bool Reduced = FALSE, Verbose = FALSE, IsCVT; | |
211 | Bool Interlaced = FALSE; | |
212 | int n; | |
213 | ||
214 | if ((argc < 3) || (argc > 7)) { | |
215 | PrintUsage(argv[0]); | |
216 | return 1; | |
217 | } | |
218 | ||
219 | /* This doesn't filter out bad flags properly. Bad flags get passed down | |
220 | * to atoi/atof, which then return 0, so that these variables can get | |
221 | * filled next time round. So this is just a cosmetic problem. | |
222 | */ | |
223 | for (n = 1; n < argc; n++) { | |
224 | if (!strcmp(argv[n], "-r") || !strcmp(argv[n], "--reduced")) | |
225 | Reduced = TRUE; | |
226 | else if (!strcmp(argv[n], "-i") || !strcmp(argv[n], "--interlaced")) | |
227 | Interlaced = TRUE; | |
228 | else if (!strcmp(argv[n], "-v") || !strcmp(argv[n], "--verbose")) | |
229 | Verbose = TRUE; | |
230 | else if (!strcmp(argv[n], "-h") || !strcmp(argv[n], "--help")) { | |
231 | PrintUsage(argv[0]); | |
232 | return 0; | |
233 | } | |
234 | else if (!HDisplay) { | |
235 | HDisplay = atoi(argv[n]); | |
236 | if (!HDisplay) { | |
237 | PrintUsage(argv[0]); | |
238 | return 1; | |
239 | } | |
240 | } | |
241 | else if (!VDisplay) { | |
242 | VDisplay = atoi(argv[n]); | |
243 | if (!VDisplay) { | |
244 | PrintUsage(argv[0]); | |
245 | return 1; | |
246 | } | |
247 | } | |
248 | else if (!VRefresh) { | |
249 | VRefresh = atof(argv[n]); | |
250 | if (!VRefresh) { | |
251 | PrintUsage(argv[0]); | |
252 | return 1; | |
253 | } | |
254 | } | |
255 | else { | |
256 | PrintUsage(argv[0]); | |
257 | return 1; | |
258 | } | |
259 | } | |
260 | ||
261 | if (!HDisplay || !VDisplay) { | |
262 | PrintUsage(argv[0]); | |
263 | return 0; | |
264 | } | |
265 | ||
266 | /* Default to 60.0Hz */ | |
267 | if (!VRefresh) | |
268 | VRefresh = 60.0; | |
269 | ||
270 | /* Horizontal timing is always a multiple of 8: round up. */ | |
271 | if (HDisplay & 0x07) { | |
272 | HDisplay &= ~0x07; | |
273 | HDisplay += 8; | |
274 | } | |
275 | ||
276 | if (Reduced) { | |
277 | if ((VRefresh / 60.0) != floor(VRefresh / 60.0)) { | |
278 | fprintf(stderr, | |
279 | "\nERROR: Multiple of 60Hz refresh rate required for " | |
280 | " reduced blanking.\n"); | |
281 | PrintUsage(argv[0]); | |
282 | return 0; | |
283 | } | |
284 | } | |
285 | ||
286 | IsCVT = CVTCheckStandard(HDisplay, VDisplay, VRefresh, Reduced, Verbose); | |
287 | ||
288 | Mode = xf86CVTMode(HDisplay, VDisplay, VRefresh, Reduced, Interlaced); | |
289 | ||
290 | PrintComment(Mode, IsCVT, Reduced); | |
291 | PrintModeline(Mode, HDisplay, VDisplay, VRefresh, Reduced); | |
292 | ||
293 | return 0; | |
294 | } |