diff --git a/xrandr.c b/xrandr.c
index b1e133e..3f3ce14 100644
--- a/xrandr.c
+++ b/xrandr.c
@@ -135,6 +135,8 @@ usage(void)
     fprintf(stderr, "            <hdisp> <hsync-start> <hsync-end> <htotal>\n");
     fprintf(stderr, "            <vdisp> <vsync-start> <vsync-end> <vtotal>\n");
     fprintf(stderr, "            [+HSync] [-HSync] [+VSync] [-VSync]\n");
+    fprintf(stderr, "  --newmode <name> <width> <height> <refresh> [reduced] "
+							    "[interlaced]>\n");
     fprintf(stderr, "  --rmmode <name>\n");
     fprintf(stderr, "  --addmode <output> <name>\n");
     fprintf(stderr, "  --delmode <output> <name>\n");
@@ -1596,6 +1598,510 @@ pick_crtcs (void)
     }
 }
 
+/*****************************************************************************/
+/* generate modeline from width,height,refresh (taken from cvt)              */
+
+#define CLOCK_STEP        0.25  /* Clock steps in MHz */
+#define MARGIN_PERCENT    1.8   /* % of active vertical image                */
+#define H_SYNC_PER        8.0   /* sync % of horizontal image                */
+#define CELL_GRAN         8.4999 /* assumed character cell granularity       */
+#define CELL_GRAN_RND     8.0   /* assumed character cell granularity (round)*/
+#define MIN_V_BPORCH      3.0   /* width of vsync in lines                   */
+#define MIN_V_PORCH_RND   3.0   /* width of vsync in lines                   */
+#define M                 600.0 /* blanking formula gradient                 */
+#define C                 40.0  /* blanking formula offset                   */
+#define K                 128.0 /* blanking formula scaling factor           */
+#define J                 20.0  /* blanking formula scaling factor           */
+
+/* Standard Timing Parameters */
+#define MIN_VSYNC_BP      550.0 /* min time of vsync + back porch (us) */
+#define H_SYNC_PERCENT    8.0   /* width of hsync as % of total line         */
+
+/* Reduced Blanking defines */
+#define RB_MIN_V_BPORCH   6.0   /* lines */
+#define RB_V_FPORCH       3.0   /* lines */
+#define RB_MIN_V_BLANK    460.0 /* us */
+#define RB_H_SYNC         32.0  /* pixels */
+#define RB_H_BLANK        160.0 /* pixels */
+
+/* C' and M' are part of the Blanking Duty Cycle computation */
+
+#define C_PRIME           (((C - J) * K/256.0) + J)
+#define M_PRIME           (K/256.0 * M)
+
+//#define print_value(n,s,v) printf("%2d: %-27s: %15f\n", n, s, v)
+#define print_value(n,s,v) (void)0
+
+/*
+ * cvt() - as defined by the CVT Timing Standard, compute the
+ * Stage 1 Parameters using the vertical refresh frequency.  In other
+ * words: input a desired resolution and desired refresh rate, and
+ * output the CVT mode timings.
+ */
+
+static void
+cvt(XRRModeInfo *m, int h_pixels, int v_lines, float freq,
+			    int interlaced, int reduced_blank, int margins)
+{
+    float h_pixels_rnd;
+    float v_lines_rnd;
+    float v_field_rate_rqd;
+    float top_margin;
+    float bot_margin;
+    float interlace;
+    float h_period_est;
+    float v_sync_bp;
+    float total_v_lines;
+    float left_margin;
+    float right_margin;
+    float total_active_pixels;
+    float ideal_duty_cycle;
+    float h_blank;
+    float total_pixels;
+
+    float cur_duty_cycle;
+    float v_sync;
+    float v_sync_rnd, h_sync_rnd;
+    float h_back_porch, v_front_porch, h_front_porch;
+
+    float vbi_lines, act_vbi_lines, rb_min_vbi;
+    float act_pixel_freq, act_h_freq;
+    float act_field_rate, act_frame_rate;
+    int stage;
+
+    /*  1. Required Field Rate
+     *
+     *  This is slightly different from the spreadsheet because we use
+     *  a different result for interlaced video modes.  Simplifies this
+     *  to the input field rate.
+     *
+     *  [V FIELD RATE RQD] = [I/P FREQ RQD]
+     */
+
+    v_field_rate_rqd = freq;
+
+    print_value(1, "[V FIELD RATE RQD]", v_field_rate_rqd);
+
+
+    /*  2. Horizontal Pixels
+     *
+     *  In order to give correct results, the number of horizontal
+     *  pixels requested is first processed to ensure that it is divisible
+     *  by the character size, by rounding it to the nearest character
+     *  cell boundary.
+     *
+     *  [H PIXELS RND] = ((ROUNDDOWN([H PIXELS]/[CELL GRAN RND],0))
+     *       *[CELLGRAN RND])
+     */
+
+    h_pixels_rnd = floor((float) h_pixels / CELL_GRAN_RND) * CELL_GRAN_RND;
+
+    print_value(2, "[H PIXELS RND]", h_pixels_rnd);
+
+
+    /*  2.5th Calculation, aspect_ratio & v_sync_rnd
+     *
+     *  [ASPECT_RATIO] = IF(H_PIXELS_RND = CELL_GRAN_RND*ROUND((V_LINES*
+     *     4.0/3.0)/CELL_GRAN_RND),"4:3")
+     *     etc...
+     *  [V_SYNC] = [value from table based on aspect ratio]
+     *  [V_SYNC_RND] = ROUND(V_SYNC,0)  // Not needed in principle
+     */
+
+    if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 4.0 / 3.0)
+        / CELL_GRAN_RND)) {
+	v_sync = 4;
+    } else if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 16.0
+        / 9.0) / CELL_GRAN_RND)) {
+	v_sync = 5;
+    } else if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 16.0
+        / 10.0) / CELL_GRAN_RND)) {
+	v_sync = 6;
+    } else if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 5.0
+        / 4.0) / CELL_GRAN_RND)) {
+	v_sync = 7;
+    } else if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 15.0
+        / 9.0) / CELL_GRAN_RND)) {
+	v_sync = 7;
+    } else {
+	/* Default case of unknown aspect ratio */
+	v_sync = 10;
+    }
+    v_sync_rnd = v_sync;
+
+    print_value(2, "[V SYNC]", v_sync_rnd);
+
+    /*
+     *  3. Determine Left & Right Borders
+     *
+     *  Calculate the margins on the left and right side.
+     *
+     *  [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
+     *          (ROUNDDOWN( ([H PIXELS RND] * [MARGIN%] / 100 /
+     *                   [CELL GRAN RND]),0)) * [CELL GRAN RND],
+     *          0))
+     *  [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
+     *          (ROUNDDOWN( ([H PIXELS RND] * [MARGIN%] / 100 /
+     *                   [CELL GRAN RND]),0)) * [CELL GRAN RND],
+     *          0))
+     */
+
+    left_margin = margins ?
+        floor(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN_RND)
+        * CELL_GRAN_RND : 0.0;
+    right_margin = left_margin;
+
+    print_value(3, "[LEFT MARGIN (PIXELS)]", left_margin);
+    print_value(3, "[RIGHT MARGIN (PIXELS)]", right_margin);
+
+
+    /*  4. Find total active pixels.
+     *
+     *  Find total number of active pixels in image and left and right
+     *  margins.
+     *
+     *  [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] +
+     *                          [RIGHT MARGIN (PIXELS)]
+     */
+
+    total_active_pixels = h_pixels_rnd + left_margin + right_margin;
+
+    print_value(4, "[TOTAL ACTIVE PIXELS]", total_active_pixels);
+
+
+    /*  5. Find number of lines per field.
+     *
+     *  If interlace is requested, the number of vertical lines assumed
+     *  by the calculation must be halved, as the computation calculates
+     *  the number of vertical lines per field. In either case, the
+     *  number of lines is rounded to the nearest integer.
+     *
+     *  [V LINES RND] = IF([INT RQD?]="y", ROUNDDOWN([V LINES]/2,0),
+     *                                     ROUNDDOWN([V LINES],0))
+     */
+
+    v_lines_rnd = interlaced ?
+            floor((float) v_lines / 2.0) :
+            floor((float) v_lines);
+
+    print_value(5, "[V LINES RND]", v_lines_rnd);
+
+
+    /*  6. Find Top and Bottom margins.
+     *
+     *  [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
+     *          ROUNDDOWN(([MARGIN%]/100*[V LINES RND]),0),
+     *          0)
+     *  [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
+     *          ROUNDDOWN(([MARGIN%]/100*[V LINES RND]),0),
+     *          0)
+     */
+
+    top_margin = margins ? floor(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
+    bot_margin = top_margin;
+
+    print_value(6, "[TOP MARGIN (LINES)]", top_margin);
+    print_value(6, "[BOT MARGIN (LINES)]", bot_margin);
+
+
+    /*  7. If interlace is required, then set variable [INTERLACE]=0.5:
+     *
+     *  [INTERLACE]=(IF([INT RQD?]="y",0.5,0))
+     */
+
+    interlace = interlaced ? 0.5 : 0.0;
+
+    print_value(7, "[INTERLACE]", interlace);
+
+
+    /*
+     *  Here it diverges for "reduced blanking" or normal blanking modes.
+     */
+
+    if (reduced_blank) {
+	h_blank = RB_H_BLANK;
+
+
+	/*  8. Estimate Horiz. Period (us).
+	 *
+	 *  [H PERIOD EST] = ((1000000/V_FIELD_RATE_RQD)-RB_MIN_V_BLANK)/(V_LINES_RND+TOP_MARGIN+BOT_MARGIN)
+	 */
+
+	h_period_est = (1000000.0/v_field_rate_rqd - RB_MIN_V_BLANK)
+	    / (v_lines_rnd + top_margin + bot_margin);
+
+	print_value(8, "[H PERIOD EST]", h_period_est);
+
+
+	/*  9. Find number of lines in vertical blanking.
+	 *
+	 *  [Actual VBI_LINES] = RB_MIN_V_BLANK/H_PERIOD_EST
+	 *  [VBI_LINES] = ROUNDDOWN(RB_MIN_V_BLANK/H_PERIOD_EST,0) + 1
+	 */
+
+	vbi_lines = RB_MIN_V_BLANK/h_period_est;
+	print_value(9, "[Actual VBI LINES]", vbi_lines);
+
+	vbi_lines = floor(vbi_lines) + 1.0;
+	print_value(9, "[VBI LINES]", vbi_lines);
+
+
+	/*  10. Check Vertical Blanking is sufficient.
+	 *
+	 *  [RB MIN VBI] = RB_V_FPORCH+V_SYNC_RND+RB_MIN_V_BPORCH
+	 *  [ACT VBI LINES] = IF(VBI_LINES<RB_MIN_VBI,RB_MIN_VBI,VBI_LINES)
+	 */
+
+	rb_min_vbi = RB_V_FPORCH + v_sync_rnd + RB_MIN_V_BPORCH;
+	act_vbi_lines = (vbi_lines < rb_min_vbi) ? rb_min_vbi : vbi_lines;
+
+	print_value(10, "[Minimum VBI Lines]", rb_min_vbi);
+	print_value(10, "[ACT VBI LINES]", act_vbi_lines);
+
+
+	/*  11. Find total number of lines in vertical field.
+	 *
+	 *  [TOTAL V LINES] = ACT_VBI_LINES+V_LINES_RND+TOP_MARGIN+BOT_MARGIN+INTERLACE
+	 */
+
+	total_v_lines = act_vbi_lines + v_lines_rnd + top_margin
+	    + bot_margin + interlace;
+
+	print_value(11, "[TOTAL V LINES]", total_v_lines);
+
+
+	/*  12. Find total number of pixels in a line (pixels).
+	 *
+	 *  [TOTAL PIXELS] = RB_H_BLANK+TOTAL_ACTIVE_PIXELS
+	 */
+
+	total_pixels = total_active_pixels + RB_H_BLANK;
+
+	print_value(12, "[TOTAL PIXELS]", total_pixels);
+
+
+	/*  13. Find Pixel Clock Frequency (MHz).
+	 *
+	 *  [Non-rounded PIXEL_FREQ] = V_FIELD_RATE_RQD*TOTAL_V_LINES*TOTAL_PIXELS/1000000
+	 *  [ACT PIXEL FREQ] = CLOCK_STEP * ROUND((V_FIELD_RATE_RQD*TOTAL_V_LINES*TOTAL_PIXELS/1000000)/CLOCK_STEP,0)
+	 */
+
+	act_pixel_freq = v_field_rate_rqd * total_v_lines
+	    * total_pixels / 1000000.0;
+	print_value(13, "[Non-rounded PIXEL FREQ]", act_pixel_freq);
+
+	act_pixel_freq = CLOCK_STEP * floor(act_pixel_freq / CLOCK_STEP);
+	print_value(13, "[ACT PIXEL FREQ]", act_pixel_freq);
+
+
+	stage = 14;
+
+    } else {    /* Normal Blanking */
+
+	/*  8. Estimate Horiz. Period (us).
+	 *
+	 *  [H PERIOD EST] = ((1/V_FIELD_RATE_RQD)-MIN_VSYNC_BP/1000000)/(V_LINES_RND+(2*TOP_MARGIN)+MIN_V_PORCH_RND+INTERLACE)*1000000
+	 */
+
+	h_period_est = ((1/v_field_rate_rqd) - MIN_VSYNC_BP/1000000.0)
+	    / (v_lines_rnd + (2*top_margin) + MIN_V_PORCH_RND + interlace)
+	    * 1000000.0;
+
+	print_value(8, "[H PERIOD EST]", h_period_est);
+
+
+	/*  9. Find number of lines in (SYNC + BACK PORCH).
+	 *
+	 *  [Estimated V_SYNC_BP] = ROUNDDOWN((MIN_VSYNC_BP/H_PERIOD_EST),0)+1
+	 *  [Actual V_SYNC_BP] = MIN_VSYNC_BP/H_PERIOD_EST
+	 *  [V_SYNC_BP] = IF(Estimated V_SYNC_BP<(V_SYNC+MIN_V_BPORCH),
+	 *       V_SYNC+MIN_V_BPORCH,Estimated V_SYNC_BP)
+	 */
+
+	v_sync_bp = MIN_VSYNC_BP/h_period_est;
+	print_value(9, "[Actual V_SYNC_BP]", v_sync_bp);
+
+	v_sync_bp = floor(v_sync_bp) + 1;
+	print_value(9, "[Estimated V_SYNC_BP]", v_sync_bp);
+
+	v_sync_bp = (v_sync_bp < v_sync + MIN_V_BPORCH) ?
+	    v_sync + MIN_V_BPORCH : v_sync_bp;
+	print_value(9, "[V_SYNC_BP]", v_sync_bp);
+
+
+	/*  10. Find number of lines in back porch (Lines).
+	 *
+	 *  [Back porch] = V_SYNC_BP - V_SYNC_RND;
+	 */
+
+	print_value(10, "[Back porch]", v_sync_bp - v_sync_rnd);
+
+
+	/*  11. Find total number of lines in vertical field.
+	 *
+	 *  [TOTAL V LINES] = V_LINES_RND+TOP_MARGIN+BOT_MARGIN
+	 *      +V_SYNC_BP+INTERLACE+MIN_V_PORCH_RND
+	 */
+
+	total_v_lines = v_lines_rnd + top_margin + bot_margin
+	    + v_sync_bp + interlace + MIN_V_PORCH_RND;
+
+	print_value(11, "[TOTAL V LINES]", total_v_lines);
+
+
+	/*  12. Find ideal blanking duty cycle from formula (%):
+	 *
+	 *  [IDEAL DUTY CYCLE] = C_PRIME-(M_PRIME*H_PERIOD_EST/1000)
+	 */
+
+	ideal_duty_cycle = C_PRIME - (M_PRIME * h_period_est / 1000.0);
+
+	print_value(12, "[IDEAL DUTY CYCLE]", ideal_duty_cycle);
+
+
+	/*  13. Find blanking time to nearest cell (Pixels).
+	 *
+	 *  [H BLANK] = IF(IDEAL_DUTY_CYCLE<20,(ROUNDDOWN((TOTAL_ACTIVE_PIXELS*20/(100-20)/(2*CELL_GRAN_RND)),0))*(2*CELL_GRAN_RND),(ROUNDDOWN((TOTAL_ACTIVE_PIXELS*IDEAL_DUTY_CYCLE/(100-IDEAL_DUTY_CYCLE)/(2*CELL_GRAN_RND)),0))*(2*CELL_GRAN_RND))
+	 */
+
+	cur_duty_cycle = (ideal_duty_cycle < 20.0) ? 20.0 : ideal_duty_cycle;
+	h_blank = floor((total_active_pixels * cur_duty_cycle/(100.0 - cur_duty_cycle)/(2.0*CELL_GRAN_RND))) * (2.0*CELL_GRAN_RND);
+
+	print_value(13, "[H BLANK]", h_blank);
+
+
+	/*  14. Find total number of pixels in a line (Pixels).
+	 *
+	 *  [TOTAL PIXELS] = TOTAL_ACTIVE_PIXELS + H_BLANK
+	 */
+
+	total_pixels = total_active_pixels + h_blank;
+
+	print_value(14, "[TOTAL PIXELS]", total_pixels);
+
+
+	/*  15. Find pixel clock frequency (MHz).
+	 *
+	 *  [Non-rounded PIXEL FREQ] = TOTAL_PIXELS / H_PERIOD_EST
+	 *  [ACT PIXEL FREQ] = CLOCK_STEP * ROUNDDOWN(
+	 */
+
+	act_pixel_freq = total_pixels / h_period_est;
+	print_value(15, "[Non-rounded PIXEL FREQ]", act_pixel_freq);
+
+	act_pixel_freq = CLOCK_STEP * floor(act_pixel_freq / CLOCK_STEP);
+	print_value(15, "[ACT PIXEL FREQ]", act_pixel_freq);
+
+
+	stage = 16;
+    }
+
+
+    /*  14/16. Find actual horizontal frequency (kHz)
+     *
+     *  [ACT H FREQ] = 1000*ACT_PIXEL_FREQ/TOTAL_PIXELS
+     */
+
+    act_h_freq = 1000 * act_pixel_freq / total_pixels;
+
+    print_value(stage, "[ACT H FREQ]", act_h_freq);
+    stage += 1;
+
+
+    /*  15/17. Find actual field rate (Hz)
+     *
+     *  [ACT FIELD RATE] = 1000*ACT_H_FREQ/TOTAL_V_LINES
+     */
+
+    act_field_rate = 1000 * act_h_freq / total_v_lines;
+
+    print_value(stage, "[ACT FIELD RATE]", act_field_rate);
+    stage += 1;
+
+
+    /*  16/18. Find actual vertical frame frequency (Hz)
+     *
+     *  [ACT FRAME RATE] = IF(INT_RQD?=Y,ACT_FIELD_RATE/2,ACT_FIELD_RATE)
+     */
+
+    act_frame_rate = interlace ?
+        (act_field_rate / 2) : act_field_rate;
+
+    print_value(stage, "[ACT FRAME RATE]", act_frame_rate);
+
+
+
+    /*
+     *  Extra computations not numbered in the CVT spreadsheet.
+     */
+
+
+    /*  20. Find Horizontal Back Porch.
+     *
+     *  [H BACK PORCH] = H_BLANK/2
+     */
+
+    h_back_porch = h_blank/2;
+
+    print_value(20, "[H BACK PORCH]", h_back_porch);
+
+
+    /*  21. Find Horizontal Front Porch.
+     *
+     *  [H SYNC RND] = IF(RED_BLANK_RQD?="Y",RB_H_SYNC,(ROUNDDOWN((H_SYNC_PER/100*TOTAL_PIXELS/CELL_GRAN_RND),0))*CELL_GRAN_RND)
+     */
+
+    if (reduced_blank) {
+	h_sync_rnd = RB_H_SYNC;
+    } else {
+	h_sync_rnd = floor(H_SYNC_PER/100.0*total_pixels/CELL_GRAN_RND)
+	    * CELL_GRAN_RND;
+    }
+
+    print_value(21, "[H SYNC RND]", h_sync_rnd);
+
+
+    /*  22. Find Horizontal Front Porch.
+     *
+     *  [H FRONT PORCH] = H_BLANK - H_BACK_PORCH - H_SYNC_RND
+     */
+
+    h_front_porch = h_blank - h_back_porch - h_sync_rnd;
+
+    print_value(22, "[H FRONT PORCH]", h_front_porch);
+
+
+    /*  23. Find Vertical Front Porch.
+     *
+     *  [V FRONT PORCH] = IF(RED_BLANK_RQD?="y",RB_V_FPORCH,MIN_V_PORCH_RND)
+     */
+
+    v_front_porch = reduced_blank ? RB_V_FPORCH : MIN_V_PORCH_RND;
+
+    print_value(23, "[V FRONT PORCH]", v_front_porch);
+
+
+    /* finally, pack the results in the mode struct */
+    m->width      = h_pixels_rnd;
+    m->hSyncStart = h_pixels_rnd + h_front_porch;
+    m->hSyncEnd   = h_pixels_rnd + h_front_porch + h_sync_rnd;
+    m->hTotal     = total_pixels;
+
+    m->height     = v_lines_rnd;
+    m->vSyncStart = v_lines_rnd + v_front_porch;
+    m->vSyncEnd   = v_lines_rnd + v_front_porch + v_sync_rnd;
+    m->vTotal     = total_v_lines;
+
+    m->dotClock   = act_pixel_freq * 1e6;
+
+    m->modeFlags  = RR_HSyncNegative | RR_VSyncPositive;
+    if (reduced_blank)
+	m->modeFlags = RR_HSyncPositive | RR_VSyncNegative;
+    if (interlaced)
+	m->modeFlags |= RR_Interlace;
+}
+/**************************************************************************/
+
 int
 main (int argc, char **argv)
 {
@@ -1924,36 +2430,62 @@ main (int argc, char **argv)
 	{
 	    umode_t  *m = malloc (sizeof (umode_t));
 	    float   clock;
-	    
+	    int tmp;
+
 	    ++i;
-	    if (i + 9 >= argc) usage ();
+	    if (i + 4 >= argc) usage ();
 	    m->mode.name = argv[i];
 	    m->mode.nameLength = strlen (argv[i]);
 	    i++;
-	    if (sscanf (argv[i++], "%f", &clock) != 1)
-		usage ();
-	    m->mode.dotClock = clock * 1e6;
-
-	    if (sscanf (argv[i++], "%d", &m->mode.width) != 1) usage();
-	    if (sscanf (argv[i++], "%d", &m->mode.hSyncStart) != 1) usage();
-	    if (sscanf (argv[i++], "%d", &m->mode.hSyncEnd) != 1) usage();
-	    if (sscanf (argv[i++], "%d", &m->mode.hTotal) != 1) usage();
-	    if (sscanf (argv[i++], "%d", &m->mode.height) != 1) usage();
-	    if (sscanf (argv[i++], "%d", &m->mode.vSyncStart) != 1) usage();
-	    if (sscanf (argv[i++], "%d", &m->mode.vSyncEnd) != 1) usage();
-	    if (sscanf (argv[i++], "%d", &m->mode.vTotal) != 1) usage();
-	    m->mode.modeFlags = 0;
-	    while (i < argc) {
-		int f;
-		
-		for (f = 0; mode_flags[f].string; f++)
-		    if (!strcasecmp (mode_flags[f].string, argv[i]))
+	    if (i+4 >= argc || sscanf(argv[i+4], "%d", &tmp) == 0)
+	    {
+		// use "cvt" mode (width height refresh)
+		int w, h, reduced = 0, interlaced = 0;
+		float r;
+		if (sscanf(argv[i++], "%d", &w) != 1) usage();
+		if (sscanf(argv[i++], "%d", &h) != 1) usage();
+		if (sscanf(argv[i++], "%f", &r) != 1) usage();
+		while (i < argc)
+		{
+		    if (strcasecmp(argv[i], "reduced") == 0)
+			reduced = 1;
+		    else if (strcasecmp(argv[i], "interlaced") == 0)
+			interlaced = 1;
+		    else
 			break;
-		
-		if (!mode_flags[f].string)
-		    break;
-    		m->mode.modeFlags |= mode_flags[f].flag;
-    		i++;
+		    i++;
+		}
+		cvt(&m->mode, w, h, r, reduced, interlaced, 0);
+	    }
+	    else
+	    {
+		// use "modeline" mode
+		if (i + 8 >= argc) usage ();
+		if (sscanf (argv[i++], "%f", &clock) != 1)
+		    usage ();
+		m->mode.dotClock = clock * 1e6;
+
+		if (sscanf (argv[i++], "%d", &m->mode.width) != 1) usage();
+		if (sscanf (argv[i++], "%d", &m->mode.hSyncStart) != 1) usage();
+		if (sscanf (argv[i++], "%d", &m->mode.hSyncEnd) != 1) usage();
+		if (sscanf (argv[i++], "%d", &m->mode.hTotal) != 1) usage();
+		if (sscanf (argv[i++], "%d", &m->mode.height) != 1) usage();
+		if (sscanf (argv[i++], "%d", &m->mode.vSyncStart) != 1) usage();
+		if (sscanf (argv[i++], "%d", &m->mode.vSyncEnd) != 1) usage();
+		if (sscanf (argv[i++], "%d", &m->mode.vTotal) != 1) usage();
+		m->mode.modeFlags = 0;
+		while (i < argc) {
+		    int f;
+
+		    for (f = 0; mode_flags[f].string; f++)
+			if (!strcasecmp (mode_flags[f].string, argv[i]))
+			    break;
+
+		    if (!mode_flags[f].string)
+			break;
+		    m->mode.modeFlags |= mode_flags[f].flag;
+		    i++;
+		}
 	    }
 	    m->next = umodes;
 	    m->action = umode_create;
