1 /* gtf.c  Generate mode timings using the GTF Timing Standard
2  *
3  * gcc gtf.c -o gtf -lm -Wall
4  *
5  * Copyright (c) 2001, Andy Ritger  aritger@nvidia.com
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * o Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * o Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer
16  *   in the documentation and/or other materials provided with the
17  *   distribution.
18  * o Neither the name of NVIDIA nor the names of its contributors
19  *   may be used to endorse or promote products derived from this
20  *   software without specific prior written permission.
21  *
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
25  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
26  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27  * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  *
37  *
38  * This program is based on the Generalized Timing Formula(GTF TM)
39  * Standard Version: 1.0, Revision: 1.0
40  *
41  * The GTF Document contains the following Copyright information:
42  *
43  * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards
44  * Association. Duplication of this document within VESA member
45  * companies for review purposes is permitted. All other rights
46  * reserved.
47  *
48  * While every precaution has been taken in the preparation
49  * of this standard, the Video Electronics Standards Association and
50  * its contributors assume no responsibility for errors or omissions,
51  * and make no warranties, expressed or implied, of functionality
52  * of suitability for any purpose. The sample code contained within
53  * this standard may be used without restriction.
54  *
55  *
56  *
57  * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive)
58  * implementation of the GTF Timing Standard, is available at:
59  *
60  * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls
61  *
62  *
63  *
64  * This program takes a desired resolution and vertical refresh rate,
65  * and computes mode timings according to the GTF Timing Standard.
66  * These mode timings can then be formatted as an XServer modeline
67  * or a mode description for use by fbset(8).
68  *
69  *
70  *
71  * NOTES:
72  *
73  * The GTF allows for computation of "margins" (the visible border
74  * surrounding the addressable video); on most non-overscan type
75  * systems, the margin period is zero.  I've implemented the margin
76  * computations but not enabled it because 1) I don't really have
77  * any experience with this, and 2) neither XServer modelines nor
78  * fbset fb.modes provide an obvious way for margin timings to be
79  * included in their mode descriptions (needs more investigation).
80  *
81  * The GTF provides for computation of interlaced mode timings;
82  * I've implemented the computations but not enabled them, yet.
83  * I should probably enable and test this at some point.
84  *
85  *
86  *
87  * TODO:
88  *
89  * o Add support for interlaced modes.
90  *
91  * o Implement the other portions of the GTF: compute mode timings
92  *   given either the desired pixel clock or the desired horizontal
93  *   frequency.
94  *
95  * o It would be nice if this were more general purpose to do things
96  *   outside the scope of the GTF: like generate double scan mode
97  *   timings, for example.
98  *
99  * o Printing digits to the right of the decimal point when the
100  *   digits are 0 annoys me.
101  *
102  * o Error checking.
103  *
104  */
105 
106 #ifdef HAVE_XORG_CONFIG_H
107 #include <xorg-config.h>
108 #endif
109 
110 #include <stdio.h>
111 #include <stdlib.h>
112 #include <string.h>
113 #include <math.h>
114 
115 #define MARGIN_PERCENT    1.8   /* % of active vertical image                */
116 #define CELL_GRAN         8.0   /* assumed character cell granularity        */
117 #define MIN_PORCH         1     /* minimum front porch                       */
118 #define V_SYNC_RQD        3     /* width of vsync in lines                   */
119 #define H_SYNC_PERCENT    8.0   /* width of hsync as % of total line         */
120 #define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
121 #define M                 600.0 /* blanking formula gradient                 */
122 #define C                 40.0  /* blanking formula offset                   */
123 #define K                 128.0 /* blanking formula scaling factor           */
124 #define J                 20.0  /* blanking formula scaling factor           */
125 
126 /* C' and M' are part of the Blanking Duty Cycle computation */
127 
128 #define C_PRIME           (((C - J) * K/256.0) + J)
129 #define M_PRIME           (K/256.0 * M)
130 
131 /* struct definitions */
132 
133 typedef struct __mode {
134     int hr, hss, hse, hfl;
135     int vr, vss, vse, vfl;
136     float pclk, h_freq, v_freq;
137 } mode;
138 
139 typedef struct __options {
140     int x, y;
141     int xorgmode, fbmode;
142     float v_freq;
143 } options;
144 
145 /* prototypes */
146 
147 void print_value(int n, const char *name, float val);
148 void print_xf86_mode(mode * m);
149 void print_fb_mode(mode * m);
150 mode *vert_refresh(int h_pixels, int v_lines, float freq,
151                    int interlaced, int margins);
152 options *parse_command_line(int argc, char *argv[]);
153 
154 /*
155  * print_value() - print the result of the named computation; this is
156  * useful when comparing against the GTF EXCEL spreadsheet.
157  */
158 
159 int global_verbose = 0;
160 
161 void
print_value(int n,const char * name,float val)162 print_value(int n, const char *name, float val)
163 {
164     if (global_verbose) {
165         printf("%2d: %-27s: %15f\n", n, name, val);
166     }
167 }
168 
169 /* print_xf86_mode() - print the XServer modeline, given mode timings. */
170 
171 void
print_xf86_mode(mode * m)172 print_xf86_mode(mode * m)
173 {
174     printf("\n");
175     printf("  # %dx%d @ %.2f Hz (GTF) hsync: %.2f kHz; pclk: %.2f MHz\n",
176            m->hr, m->vr, m->v_freq, m->h_freq, m->pclk);
177 
178     printf("  Modeline \"%dx%d_%.2f\"  %.2f"
179            "  %d %d %d %d"
180            "  %d %d %d %d"
181            "  -HSync +Vsync\n\n",
182            m->hr, m->vr, m->v_freq, m->pclk,
183            m->hr, m->hss, m->hse, m->hfl, m->vr, m->vss, m->vse, m->vfl);
184 
185 }
186 
187 /*
188  * print_fb_mode() - print a mode description in fbset(8) format;
189  * see the fb.modes(8) manpage.  The timing description used in
190  * this is rather odd; they use "left and right margin" to refer
191  * to the portion of the hblank before and after the sync pulse
192  * by conceptually wrapping the portion of the blank after the pulse
193  * to infront of the visible region; ie:
194  *
195  *
196  * Timing description I'm accustomed to:
197  *
198  *
199  *
200  *     <--------1--------> <--2--> <--3--> <--4-->
201  *                                _________
202  *    |-------------------|_______|       |_______
203  *
204  *                        R       SS      SE     FL
205  *
206  * 1: visible image
207  * 2: blank before sync (aka front porch)
208  * 3: sync pulse
209  * 4: blank after sync (aka back porch)
210  * R: Resolution
211  * SS: Sync Start
212  * SE: Sync End
213  * FL: Frame Length
214  *
215  *
216  * But the fb.modes format is:
217  *
218  *
219  *    <--4--> <--------1--------> <--2--> <--3-->
220  *                                       _________
221  *    _______|-------------------|_______|       |
222  *
223  * The fb.modes(8) manpage refers to <4> and <2> as the left and
224  * right "margin" (as well as upper and lower margin in the vertical
225  * direction) -- note that this has nothing to do with the term
226  * "margin" used in the GTF Timing Standard.
227  *
228  * XXX always prints the 32 bit mode -- should I provide a command
229  * line option to specify the bpp?  It's simple enough for a user
230  * to edit the mode description after it's generated.
231  */
232 
233 void
print_fb_mode(mode * m)234 print_fb_mode(mode * m)
235 {
236     printf("\n");
237     printf("mode \"%dx%d %.2fHz 32bit (GTF)\"\n", m->hr, m->vr, m->v_freq);
238     printf("    # PCLK: %.2f MHz, H: %.2f kHz, V: %.2f Hz\n",
239            m->pclk, m->h_freq, m->v_freq);
240     printf("    geometry %d %d %d %d 32\n", m->hr, m->vr, m->hr, m->vr);
241     printf("    timings %d %d %d %d %d %d %d\n", (int)lrint(1000000.0 / m->pclk),       /* pixclock in picoseconds */
242            m->hfl - m->hse,     /* left margin (in pixels) */
243            m->hss - m->hr,      /* right margin (in pixels) */
244            m->vfl - m->vse,     /* upper margin (in pixel lines) */
245            m->vss - m->vr,      /* lower margin (in pixel lines) */
246            m->hse - m->hss,     /* horizontal sync length (pixels) */
247            m->vse - m->vss);    /* vert sync length (pixel lines) */
248     printf("    hsync low\n");
249     printf("    vsync high\n");
250     printf("endmode\n\n");
251 
252 }
253 
254 /*
255  * vert_refresh() - as defined by the GTF Timing Standard, compute the
256  * Stage 1 Parameters using the vertical refresh frequency.  In other
257  * words: input a desired resolution and desired refresh rate, and
258  * output the GTF mode timings.
259  *
260  * XXX All the code is in place to compute interlaced modes, but I don't
261  * feel like testing it right now.
262  *
263  * XXX margin computations are implemented but not tested (nor used by
264  * XServer of fbset mode descriptions, from what I can tell).
265  */
266 
267 mode *
vert_refresh(int h_pixels,int v_lines,float freq,int interlaced,int margins)268 vert_refresh(int h_pixels, int v_lines, float freq, int interlaced, int margins)
269 {
270     float h_pixels_rnd;
271     float v_lines_rnd;
272     float v_field_rate_rqd;
273     float top_margin;
274     float bottom_margin;
275     float interlace;
276     float h_period_est;
277     float vsync_plus_bp;
278     float v_back_porch;
279     float total_v_lines;
280     float v_field_rate_est;
281     float h_period;
282     float v_field_rate;
283     float v_frame_rate;
284     float left_margin;
285     float right_margin;
286     float total_active_pixels;
287     float ideal_duty_cycle;
288     float h_blank;
289     float total_pixels;
290     float pixel_freq;
291     float h_freq;
292 
293     float h_sync;
294     float h_front_porch;
295     float v_odd_front_porch_lines;
296 
297     mode *m = (mode *) malloc(sizeof(mode));
298 
299     /*  1. In order to give correct results, the number of horizontal
300      *  pixels requested is first processed to ensure that it is divisible
301      *  by the character size, by rounding it to the nearest character
302      *  cell boundary:
303      *
304      *  [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND])
305      */
306 
307     h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
308 
309     print_value(1, "[H PIXELS RND]", h_pixels_rnd);
310 
311     /*  2. If interlace is requested, the number of vertical lines assumed
312      *  by the calculation must be halved, as the computation calculates
313      *  the number of vertical lines per field. In either case, the
314      *  number of lines is rounded to the nearest integer.
315      *
316      *  [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0),
317      *                                     ROUND([V LINES],0))
318      */
319 
320     v_lines_rnd = interlaced ?
321         rint((float) v_lines) / 2.0 : rint((float) v_lines);
322 
323     print_value(2, "[V LINES RND]", v_lines_rnd);
324 
325     /*  3. Find the frame rate required:
326      *
327      *  [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2,
328      *                                          [I/P FREQ RQD])
329      */
330 
331     v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
332 
333     print_value(3, "[V FIELD RATE RQD]", v_field_rate_rqd);
334 
335     /*  4. Find number of lines in Top margin:
336      *
337      *  [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
338      *          ROUND(([MARGIN%]/100*[V LINES RND]),0),
339      *          0)
340      */
341 
342     top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
343 
344     print_value(4, "[TOP MARGIN (LINES)]", top_margin);
345 
346     /*  5. Find number of lines in Bottom margin:
347      *
348      *  [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
349      *          ROUND(([MARGIN%]/100*[V LINES RND]),0),
350      *          0)
351      */
352 
353     bottom_margin =
354         margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
355 
356     print_value(5, "[BOT MARGIN (LINES)]", bottom_margin);
357 
358     /*  6. If interlace is required, then set variable [INTERLACE]=0.5:
359      *
360      *  [INTERLACE]=(IF([INT RQD?]="y",0.5,0))
361      */
362 
363     interlace = interlaced ? 0.5 : 0.0;
364 
365     print_value(6, "[INTERLACE]", interlace);
366 
367     /*  7. Estimate the Horizontal period
368      *
369      *  [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) /
370      *                    ([V LINES RND] + (2*[TOP MARGIN (LINES)]) +
371      *                     [MIN PORCH RND]+[INTERLACE]) * 1000000
372      */
373 
374     h_period_est = (((1.0 / v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP / 1000000.0))
375                     / (v_lines_rnd + (2 * top_margin) + MIN_PORCH + interlace)
376                     * 1000000.0);
377 
378     print_value(7, "[H PERIOD EST]", h_period_est);
379 
380     /*  8. Find the number of lines in V sync + back porch:
381      *
382      *  [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0)
383      */
384 
385     vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est);
386 
387     print_value(8, "[V SYNC+BP]", vsync_plus_bp);
388 
389     /*  9. Find the number of lines in V back porch alone:
390      *
391      *  [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND]
392      *
393      *  XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]?
394      */
395 
396     v_back_porch = vsync_plus_bp - V_SYNC_RQD;
397 
398     print_value(9, "[V BACK PORCH]", v_back_porch);
399 
400     /*  10. Find the total number of lines in Vertical field period:
401      *
402      *  [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] +
403      *                    [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] +
404      *                    [MIN PORCH RND]
405      */
406 
407     total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp +
408         interlace + MIN_PORCH;
409 
410     print_value(10, "[TOTAL V LINES]", total_v_lines);
411 
412     /*  11. Estimate the Vertical field frequency:
413      *
414      *  [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000
415      */
416 
417     v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
418 
419     print_value(11, "[V FIELD RATE EST]", v_field_rate_est);
420 
421     /*  12. Find the actual horizontal period:
422      *
423      *  [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST])
424      */
425 
426     h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
427 
428     print_value(12, "[H PERIOD]", h_period);
429 
430     /*  13. Find the actual Vertical field frequency:
431      *
432      *  [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000
433      */
434 
435     v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
436 
437     print_value(13, "[V FIELD RATE]", v_field_rate);
438 
439     /*  14. Find the Vertical frame frequency:
440      *
441      *  [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE]))
442      */
443 
444     v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
445 
446     print_value(14, "[V FRAME RATE]", v_frame_rate);
447 
448     /*  15. Find number of pixels in left margin:
449      *
450      *  [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
451      *          (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
452      *                   [CELL GRAN RND]),0)) * [CELL GRAN RND],
453      *          0))
454      */
455 
456     left_margin = margins ?
457         rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN :
458         0.0;
459 
460     print_value(15, "[LEFT MARGIN (PIXELS)]", left_margin);
461 
462     /*  16. Find number of pixels in right margin:
463      *
464      *  [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
465      *          (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
466      *                   [CELL GRAN RND]),0)) * [CELL GRAN RND],
467      *          0))
468      */
469 
470     right_margin = margins ?
471         rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN :
472         0.0;
473 
474     print_value(16, "[RIGHT MARGIN (PIXELS)]", right_margin);
475 
476     /*  17. Find total number of active pixels in image and left and right
477      *  margins:
478      *
479      *  [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] +
480      *                          [RIGHT MARGIN (PIXELS)]
481      */
482 
483     total_active_pixels = h_pixels_rnd + left_margin + right_margin;
484 
485     print_value(17, "[TOTAL ACTIVE PIXELS]", total_active_pixels);
486 
487     /*  18. Find the ideal blanking duty cycle from the blanking duty cycle
488      *  equation:
489      *
490      *  [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000)
491      */
492 
493     ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
494 
495     print_value(18, "[IDEAL DUTY CYCLE]", ideal_duty_cycle);
496 
497     /*  19. Find the number of pixels in the blanking time to the nearest
498      *  double character cell:
499      *
500      *  [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] *
501      *                               [IDEAL DUTY CYCLE] /
502      *                               (100-[IDEAL DUTY CYCLE]) /
503      *                               (2*[CELL GRAN RND])), 0))
504      *                       * (2*[CELL GRAN RND])
505      */
506 
507     h_blank = rint(total_active_pixels *
508                    ideal_duty_cycle /
509                    (100.0 - ideal_duty_cycle) /
510                    (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
511 
512     print_value(19, "[H BLANK (PIXELS)]", h_blank);
513 
514     /*  20. Find total number of pixels:
515      *
516      *  [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)]
517      */
518 
519     total_pixels = total_active_pixels + h_blank;
520 
521     print_value(20, "[TOTAL PIXELS]", total_pixels);
522 
523     /*  21. Find pixel clock frequency:
524      *
525      *  [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD]
526      */
527 
528     pixel_freq = total_pixels / h_period;
529 
530     print_value(21, "[PIXEL FREQ]", pixel_freq);
531 
532     /*  22. Find horizontal frequency:
533      *
534      *  [H FREQ] = 1000 / [H PERIOD]
535      */
536 
537     h_freq = 1000.0 / h_period;
538 
539     print_value(22, "[H FREQ]", h_freq);
540 
541     /* Stage 1 computations are now complete; I should really pass
542        the results to another function and do the Stage 2
543        computations, but I only need a few more values so I'll just
544        append the computations here for now */
545 
546     /*  17. Find the number of pixels in the horizontal sync period:
547      *
548      *  [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] /
549      *                             [CELL GRAN RND]),0))*[CELL GRAN RND]
550      */
551 
552     h_sync =
553         rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
554 
555     print_value(17, "[H SYNC (PIXELS)]", h_sync);
556 
557     /*  18. Find the number of pixels in the horizontal front porch period:
558      *
559      *  [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)]
560      */
561 
562     h_front_porch = (h_blank / 2.0) - h_sync;
563 
564     print_value(18, "[H FRONT PORCH (PIXELS)]", h_front_porch);
565 
566     /*  36. Find the number of lines in the odd front porch period:
567      *
568      *  [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE])
569      */
570 
571     v_odd_front_porch_lines = MIN_PORCH + interlace;
572 
573     print_value(36, "[V ODD FRONT PORCH(LINES)]", v_odd_front_porch_lines);
574 
575     /* finally, pack the results in the mode struct */
576 
577     m->hr = (int) (h_pixels_rnd);
578     m->hss = (int) (h_pixels_rnd + h_front_porch);
579     m->hse = (int) (h_pixels_rnd + h_front_porch + h_sync);
580     m->hfl = (int) (total_pixels);
581 
582     m->vr = (int) (v_lines_rnd);
583     m->vss = (int) (v_lines_rnd + v_odd_front_porch_lines);
584     m->vse = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
585     m->vfl = (int) (total_v_lines);
586 
587     m->pclk = pixel_freq;
588     m->h_freq = h_freq;
589     m->v_freq = freq;
590 
591     return m;
592 
593 }
594 
595 /*
596  * parse_command_line() - parse the command line and return an
597  * alloced structure containing the results.  On error print usage
598  * and return NULL.
599  */
600 
601 options *
parse_command_line(int argc,char * argv[])602 parse_command_line(int argc, char *argv[])
603 {
604     int n;
605 
606     options *o = (options *) calloc(1, sizeof(options));
607 
608     if (argc < 4)
609         goto bad_option;
610 
611     o->x = atoi(argv[1]);
612     o->y = atoi(argv[2]);
613     o->v_freq = atof(argv[3]);
614 
615     /* XXX should check for errors in the above */
616 
617     n = 4;
618 
619     while (n < argc) {
620         if ((strcmp(argv[n], "-v") == 0) || (strcmp(argv[n], "--verbose") == 0)) {
621             global_verbose = 1;
622         }
623         else if ((strcmp(argv[n], "-f") == 0) ||
624                  (strcmp(argv[n], "--fbmode") == 0)) {
625             o->fbmode = 1;
626         }
627         else if ((strcmp(argv[n], "-x") == 0) ||
628                  (strcmp(argv[n], "--xorgmode") == 0) ||
629                  (strcmp(argv[n], "--xf86mode") == 0)) {
630             o->xorgmode = 1;
631         }
632         else {
633             goto bad_option;
634         }
635 
636         n++;
637     }
638 
639     /* if neither xorgmode nor fbmode were requested, default to
640        xorgmode */
641 
642     if (!o->fbmode && !o->xorgmode)
643         o->xorgmode = 1;
644 
645     return o;
646 
647  bad_option:
648 
649     fprintf(stderr, "\n");
650     fprintf(stderr, "usage: %s x y refresh [-v|--verbose] "
651             "[-f|--fbmode] [-x|--xorgmode]\n", argv[0]);
652 
653     fprintf(stderr, "\n");
654 
655     fprintf(stderr, "            x : the desired horizontal "
656             "resolution (required)\n");
657     fprintf(stderr, "            y : the desired vertical "
658             "resolution (required)\n");
659     fprintf(stderr, "      refresh : the desired refresh " "rate (required)\n");
660     fprintf(stderr, " -v|--verbose : enable verbose printouts "
661             "(traces each step of the computation)\n");
662     fprintf(stderr, "  -f|--fbmode : output an fbset(8)-style mode "
663             "description\n");
664     fprintf(stderr, " -x|--xorgmode : output an " __XSERVERNAME__ "-style mode "
665             "description (this is the default\n"
666             "                if no mode description is requested)\n");
667 
668     fprintf(stderr, "\n");
669 
670     free(o);
671     return NULL;
672 
673 }
674 
675 int
main(int argc,char * argv[])676 main(int argc, char *argv[])
677 {
678     mode *m;
679     options *o;
680 
681     o = parse_command_line(argc, argv);
682     if (!o)
683         exit(1);
684 
685     m = vert_refresh(o->x, o->y, o->v_freq, 0, 0);
686     if (!m)
687         exit(1);
688 
689     if (o->xorgmode)
690         print_xf86_mode(m);
691 
692     if (o->fbmode)
693         print_fb_mode(m);
694 
695     free(m);
696 
697     return 0;
698 
699 }
700