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 <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <math.h>
30
31 #include <libxcvt/libxcvt.h>
32
33 bool
cvt_is_standard(int hdisplay,int vdisplay,float vrefresh,bool reduced,bool verbose)34 cvt_is_standard(int hdisplay, int vdisplay, float vrefresh, bool reduced, bool verbose)
35 {
36 bool is_cvt = true;
37
38 if ((!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay)) ||
39 (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay)) ||
40 (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay)) ||
41 (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay)) ||
42 (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay)));
43 else {
44 if (verbose)
45 fprintf(stderr, "Warning: Aspect Ratio is not CVT standard.\n");
46 is_cvt = false;
47 }
48
49 if ((vrefresh != 50.0) && (vrefresh != 60.0) &&
50 (vrefresh != 75.0) && (vrefresh != 85.0)) {
51 if (verbose)
52 fprintf(stderr, "Warning: Refresh Rate %.2f is not CVT standard "
53 "(50, 60, 75 or 85Hz).\n", vrefresh);
54 is_cvt = false;
55 }
56
57 return is_cvt;
58 }
59 /*
60 * I'm not documenting --interlaced for obvious reasons, even though I did
61 * implement it. I also can't deny having looked at gtf here.
62 */
63 static void
print_usage(char * Name)64 print_usage(char *Name)
65 {
66 fprintf(stderr, "\n");
67 fprintf(stderr, "usage: %s [-v|--verbose] [-r|--reduced] X Y [refresh]\n",
68 Name);
69 fprintf(stderr, "\n");
70 fprintf(stderr, " -v|--verbose : Warn about CVT standard adherence.\n");
71 fprintf(stderr, " -r|--reduced : Create a mode with reduced blanking "
72 "(default: normal blanking).\n");
73 fprintf(stderr, " X : Desired horizontal resolution "
74 "(multiple of 8, required).\n");
75 fprintf(stderr,
76 " Y : Desired vertical resolution (required).\n");
77 fprintf(stderr,
78 " refresh : Desired refresh rate (default: 60.0Hz).\n");
79 fprintf(stderr, "\n");
80
81 fprintf(stderr, "Calculates VESA CVT (Coordinated Video Timing) modelines"
82 " for use with X.\n");
83 }
84
85 /*
86 *
87 */
88 static void
print_comment(struct libxcvt_mode_info * mode_info,bool is_cvt,bool reduced)89 print_comment(struct libxcvt_mode_info *mode_info, bool is_cvt, bool reduced)
90 {
91 printf("# %dx%d %.2f Hz ", mode_info->hdisplay, mode_info->vdisplay, mode_info->vrefresh);
92
93 if (is_cvt) {
94 printf("(CVT %.2fM",
95 ((float) mode_info->hdisplay * mode_info->vdisplay) / 1000000.0);
96
97 if (!(mode_info->vdisplay % 3) &&
98 ((mode_info->vdisplay * 4 / 3) == mode_info->hdisplay))
99 printf("3");
100 else if (!(mode_info->vdisplay % 9) &&
101 ((mode_info->vdisplay * 16 / 9) == mode_info->hdisplay))
102 printf("9");
103 else if (!(mode_info->vdisplay % 10) &&
104 ((mode_info->vdisplay * 16 / 10) == mode_info->hdisplay))
105 printf("A");
106 else if (!(mode_info->vdisplay % 4) &&
107 ((mode_info->vdisplay * 5 / 4) == mode_info->hdisplay))
108 printf("4");
109 else if (!(mode_info->vdisplay % 9) &&
110 ((mode_info->vdisplay * 15 / 9) == mode_info->hdisplay))
111 printf("9");
112
113 if (reduced)
114 printf("-R");
115
116 printf(") ");
117 }
118 else
119 printf("(CVT) ");
120
121 printf("hsync: %.2f kHz; ", mode_info->hsync);
122 printf("pclk: %.2f MHz", ((float) mode_info->dot_clock) / 1000.0);
123
124 printf("\n");
125 }
126
127 /*
128 * Originally grabbed from xf86Mode.c.
129 *
130 * Ignoring the actual mode_info->name, as the user will want something solid
131 * to grab hold of.
132 */
133 static void
print_mode_line(struct libxcvt_mode_info * mode_info,int hdisplay,int vdisplay,float vrefresh,bool reduced)134 print_mode_line(struct libxcvt_mode_info *mode_info, int hdisplay, int vdisplay, float vrefresh,
135 bool reduced)
136 {
137 if (reduced)
138 printf("Modeline \"%dx%dR\" ", hdisplay, vdisplay);
139 else
140 printf("Modeline \"%dx%d_%.2f\" ", hdisplay, vdisplay, vrefresh);
141
142 printf("%6.2f %i %i %i %i %i %i %i %i", mode_info->dot_clock / 1000.,
143 mode_info->hdisplay, mode_info->hsync_start, mode_info->hsync_end, mode_info->htotal,
144 mode_info->vdisplay, mode_info->vsync_start, mode_info->vsync_end, mode_info->vtotal);
145
146 if (mode_info->mode_flags & LIBXCVT_MODE_FLAG_INTERLACE)
147 printf(" interlace");
148 if (mode_info->mode_flags & LIBXCVT_MODE_FLAG_HSYNC_POSITIVE)
149 printf(" +hsync");
150 if (mode_info->mode_flags & LIBXCVT_MODE_FLAG_HSYNC_NEGATIVE)
151 printf(" -hsync");
152 if (mode_info->mode_flags & LIBXCVT_MODE_FLAG_VSYNC_POSITIVE)
153 printf(" +vsync");
154 if (mode_info->mode_flags & LIBXCVT_MODE_FLAG_VSYNC_NEGATIVE)
155 printf(" -vsync");
156
157 printf("\n");
158 }
159
160 /*
161 *
162 */
163 int
main(int argc,char * argv[])164 main(int argc, char *argv[])
165 {
166 struct libxcvt_mode_info *mode_info;
167 int hdisplay = 0, vdisplay = 0;
168 float vrefresh = 0.0;
169 bool reduced = false, verbose = false, is_cvt;
170 bool interlaced = false;
171 int n;
172
173 if ((argc < 3) || (argc > 7)) {
174 print_usage(argv[0]);
175 return 1;
176 }
177
178 /* This doesn't filter out bad flags properly. Bad flags get passed down
179 * to atoi/atof, which then return 0, so that these variables can get
180 * filled next time round. So this is just a cosmetic problem.
181 */
182 for (n = 1; n < argc; n++) {
183 if (!strcmp(argv[n], "-r") || !strcmp(argv[n], "--reduced"))
184 reduced = true;
185 else if (!strcmp(argv[n], "-i") || !strcmp(argv[n], "--interlaced"))
186 interlaced = true;
187 else if (!strcmp(argv[n], "-v") || !strcmp(argv[n], "--verbose"))
188 verbose = true;
189 else if (!strcmp(argv[n], "-h") || !strcmp(argv[n], "--help")) {
190 print_usage(argv[0]);
191 return 0;
192 }
193 else if (!hdisplay) {
194 hdisplay = atoi(argv[n]);
195 if (!hdisplay) {
196 print_usage(argv[0]);
197 return 1;
198 }
199 }
200 else if (!vdisplay) {
201 vdisplay = atoi(argv[n]);
202 if (!vdisplay) {
203 print_usage(argv[0]);
204 return 1;
205 }
206 }
207 else if (!vrefresh) {
208 vrefresh = atof(argv[n]);
209 if (!vrefresh) {
210 print_usage(argv[0]);
211 return 1;
212 }
213 }
214 else {
215 print_usage(argv[0]);
216 return 1;
217 }
218 }
219
220 if (!hdisplay || !vdisplay) {
221 print_usage(argv[0]);
222 return 0;
223 }
224
225 /* Default to 60.0Hz */
226 if (!vrefresh)
227 vrefresh = 60.0;
228
229 /* Horizontal timing is always a multiple of 8: round up. */
230 if (hdisplay & 0x07) {
231 hdisplay &= ~0x07;
232 hdisplay += 8;
233 }
234
235 if (reduced) {
236 if ((vrefresh / 60.0) != floor(vrefresh / 60.0)) {
237 fprintf(stderr,
238 "\nERROR: Multiple of 60Hz refresh rate required for "
239 " reduced blanking.\n");
240 print_usage(argv[0]);
241 return 0;
242 }
243 }
244
245 mode_info = libxcvt_gen_mode_info(hdisplay, vdisplay, vrefresh, reduced, interlaced);
246 if (!mode_info) {
247 fprintf(stderr, "Out of memory!\n");
248 return 0;
249 }
250
251 is_cvt = cvt_is_standard(hdisplay, vdisplay, vrefresh, reduced, verbose);
252 print_comment(mode_info, is_cvt, reduced);
253 print_mode_line(mode_info, hdisplay, vdisplay, vrefresh, reduced);
254 free(mode_info);
255
256 return 0;
257 }
258