Package: fbset
Version: 2.1-25
Severity: normal
Tags: upstream patch

fbset discards unknown sync bits in the fb_var_screeninfo structure.

This works ok on the majority of hardware, but it does not work if the
particular framebuffer driver uses some driver-specific proprietary bits in the
sync field. This situation was seen in the wild with a Freescale framebuffer
driver. Using fbset on it for any other purpose than just to display
current framebuffer configuration always resulted in pixel glitches on the
display. This was caused by fbset dropping the proprietary sync bits.

Attached is a patch that resolves the issue by extending fbset to:

* losslessly round-trip the sync value along struct fb_var_screeninfo -> struct
VideoMode -> struct fb_var_screeninfo

* allow for explicit switching of the custom bits via newly-added -sync
argument

The patch was also submitted upstream and it has received an "acked-by" by the
author of fbset (Geert Uytterhoeven).



-- System Information:
Architecture: armel

Target: Freescale i.MX53 Quick Start Board
Kernel: from http://opensource.freescale.com/pub/scm/imx/linux-2.6-imx.git
but the issue is present also when using upstream kernel

-- no debconf information
>From cb00e6fade39afdb2adb0727647e9c97ce0fd02c Mon Sep 17 00:00:00 2001
From: David Kozub <z...@linux.fjfi.cvut.cz>
Date: Thu, 7 Jun 2012 15:46:16 +0200
Subject: [PATCH] add support for custom sync flags

---
 fb.modes.5 |    3 +++
 fbset.8    |    4 ++++
 fbset.c    |   45 +++++++++++++++++++++++++++++++++++++++++++++
 fbset.h    |    3 +++
 modes.l    |    3 ++-
 modes.y    |   10 +++++++++-
 6 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/fb.modes.5 b/fb.modes.5
index 4258683..106d4c7 100644
--- a/fb.modes.5
+++ b/fb.modes.5
@@ -120,6 +120,9 @@ generated by the frame buffer device and must be provided externally
 instead. Note that this option may not be supported by every frame buffer
 device
 .TP
+.IR \fBsync "\ <" number >
+custom sync flags (frame buffer driver dependent)
+.TP
 .IR \fBlaced "\ {" false | true }
 enable or disable interlace. If enabled the display will be split in two
 frames, each frame contains only even and odd lines respectively. These two
diff --git a/fbset.8 b/fbset.8
index acea125..f40ba95 100644
--- a/fbset.8
+++ b/fbset.8
@@ -195,6 +195,10 @@ generated by the frame buffer device and must be provided externally
 instead. Note that this option may not be supported by every frame buffer
 device
 .TP
+.IR \fB\-sync "\ <" \fIvalue >
+set custom sync flags. If specified, this value is bitwise or-ed to the
+other sync flags. This is useful for drivers that use custom sync flags
+.TP
 .IR \fB\-bcast "\ {" false | true }
 enable or disable broadcast modes. If enabled the frame buffer generates the
 exact timings for several broadcast modes (e.g. PAL or NTSC). Note that
diff --git a/fbset.c b/fbset.c
index d0753ff..1e84618 100644
--- a/fbset.c
+++ b/fbset.c
@@ -16,6 +16,9 @@
  *  Brad Midgley <b...@exodus.pht.com>:
  *           -match
  *
+ *  David Kozub <z...@linux.fjfi.cvut.cz>:
+ *           -sync
+ *
  */
 
 
@@ -52,6 +55,12 @@ struct inode;
 
 
     /*
+     *  Mask to zero-out all known sync flags
+     */
+#define FB_CUSTOM_SYNC_MASK ~(FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT| \
+    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_ON_GREEN|FB_SYNC_EXT|FB_SYNC_BROADCAST)
+
+    /*
      *  Command Line Options
      */
 
@@ -86,6 +95,7 @@ static const char *Opt_vsync = NULL;
 static const char *Opt_csync = NULL;
 static const char *Opt_gsync = NULL;
 static const char *Opt_extsync = NULL;
+static const char *Opt_sync = NULL;
 static const char *Opt_bcast = NULL;
 static const char *Opt_laced = NULL;
 static const char *Opt_double = NULL;
@@ -123,6 +133,7 @@ static struct {
     { "-csync", &Opt_csync, 1 },
     { "-gsync", &Opt_gsync, 1 },
     { "-extsync", &Opt_extsync, 1 },
+    { "-sync", &Opt_sync, 1 },
     { "-bcast", &Opt_bcast, 1 },
     { "-laced", &Opt_laced, 1 },
     { "-double", &Opt_double, 1 },
@@ -402,6 +413,7 @@ static void ConvertFromVideoMode(const struct VideoMode *vmode,
 	var->sync |= FB_SYNC_EXT;
     if (vmode->bcast == TRUE)
 	var->sync |= FB_SYNC_BROADCAST;
+    var->sync |= vmode->sync;
     if (vmode->laced == TRUE)
 	var->vmode = FB_VMODE_INTERLACED;
     else if (vmode->dblscan == TRUE)
@@ -445,6 +457,7 @@ static void ConvertToVideoMode(const struct fb_var_screeninfo *var,
     vmode->gsync = var->sync & FB_SYNC_ON_GREEN ? TRUE : FALSE;
     vmode->extsync = var->sync & FB_SYNC_EXT ? TRUE : FALSE;
     vmode->bcast = var->sync & FB_SYNC_BROADCAST ? TRUE : FALSE;
+    vmode->sync = var->sync & FB_CUSTOM_SYNC_MASK;
     vmode->grayscale = var->grayscale;
     vmode->laced = FALSE;
     vmode->dblscan = FALSE;
@@ -554,6 +567,27 @@ void makeRGBA(struct VideoMode *vmode, const char* opt)
 }
 
     /*
+     *  Take known bits from sync and set appropriate flags instead
+     */
+
+void fixCustomSync(struct VideoMode *vmode)
+{
+    if (vmode->sync & FB_SYNC_HOR_HIGH_ACT)
+	vmode->hsync = 1;
+    if (vmode->sync & FB_SYNC_VERT_HIGH_ACT)
+	vmode->vsync = 1;
+    if (vmode->sync & FB_SYNC_COMP_HIGH_ACT)
+	vmode->csync = 1;
+    if (vmode->sync & FB_SYNC_ON_GREEN)
+	vmode->gsync = 1;
+    if (vmode->sync & FB_SYNC_EXT)
+	vmode->extsync =1;
+    if (vmode->sync & FB_SYNC_BROADCAST)
+	vmode->bcast = 1;
+    vmode->sync &= FB_CUSTOM_SYNC_MASK;
+}
+
+    /*
      *  Find a Video Mode
      */
 
@@ -617,6 +651,12 @@ static void ModifyVideoMode(struct VideoMode *vmode)
 	vmode->extsync = atoboolean(Opt_extsync);
     if (Opt_bcast)
 	vmode->bcast = atoboolean(Opt_bcast);
+    if (Opt_sync)
+    {
+	vmode->sync = strtoul(Opt_sync, NULL, 0);
+	// call this only once all the other sync fields are determined!
+	fixCustomSync(vmode);
+    }
     if (Opt_laced)
 	vmode->laced = atoboolean(Opt_laced);
     if (Opt_double)
@@ -693,6 +733,8 @@ static void DisplayVModeInfo(struct VideoMode *vmode)
 	    puts("    extsync true");
 	if (vmode->bcast)
 	    puts("    bcast true");
+	if (vmode->sync)
+	    printf("    sync 0x%x\n", vmode->sync);
 	if (vmode->laced)
 	    puts("    laced true");
 	if (vmode->dblscan)
@@ -745,6 +787,8 @@ static void DisplayVModeInfo(struct VideoMode *vmode)
 	    puts("    # Warning: XFree86 doesn't support extsync\n");
 	if (vmode->bcast)
 	    printf(" \"bcast\"");
+	if (vmode->sync)
+	    puts("    # Warning: XFree86 doesn't support custom sync values\n");
 	if (vmode->accel_flags)
 	    puts("    # Warning: XFree86 doesn't support accel\n");
 	if (vmode->grayscale)
@@ -931,6 +975,7 @@ static void Usage(void)
 	"    -csync <value>     : composite sync polarity (low or high)\n"
 	"    -gsync <value>     : synch on green (false or true)\n"
 	"    -extsync <value>   : external sync enable (false or true)\n"
+	"    -sync <value>      : custom (driver specific) sync value\n"
 	"    -bcast <value>     : broadcast enable (false or true)\n"
 	"    -laced <value>     : interlace enable (false or true)\n"
 	"    -double <value>    : doublescan enable (false or true)\n"
diff --git a/fbset.h b/fbset.h
index 9b1d2ac..f5b8f4f 100644
--- a/fbset.h
+++ b/fbset.h
@@ -64,6 +64,8 @@ struct VideoMode {
     unsigned laced : 1;
     unsigned dblscan : 1;
     unsigned grayscale : 1;
+    /* extra (fb driver specific) sync bits */
+    __u32 sync;
     /* scanrates */
     double drate;
     double hrate;
@@ -80,3 +82,4 @@ extern int yyparse(void);
 extern void Die(const char *fmt, ...) __attribute__ ((noreturn));
 extern void AddVideoMode(const struct VideoMode *vmode);
 extern void makeRGBA(struct VideoMode *vmode, const char* opt);
+extern void fixCustomSync(struct VideoMode *vmode);
diff --git a/modes.l b/modes.l
index a0dd8be..c4af1c3 100644
--- a/modes.l
+++ b/modes.l
@@ -38,6 +38,7 @@ static struct keyword keywords[] = {
     { "csync", CSYNC, 0 },
     { "gsync", GSYNC, 0 },
     { "extsync", EXTSYNC, 0 },
+    { "sync", SYNC, 0 },
     { "bcast", BCAST, 0 },
     { "laced", LACED, 0 },
     { "double", DOUBLE, 0 },
@@ -98,7 +99,7 @@ static const char *CopyString(const char *s)
 %}
 
 keyword	[a-zA-Z][a-zA-Z0-9]*
-number	[0-9]*
+number	(0x)?[0-9]*
 colors	[0-9/,]*
 string	\"[^\"\n]*\"
 comment	\#([^\n]*)
diff --git a/modes.y b/modes.y
index f343d49..bf1a6b5 100644
--- a/modes.y
+++ b/modes.y
@@ -40,7 +40,7 @@ static void ClearVideoMode(void)
 
 %start file
 
-%token MODE GEOMETRY TIMINGS HSYNC VSYNC CSYNC GSYNC EXTSYNC BCAST LACED DOUBLE
+%token MODE GEOMETRY TIMINGS HSYNC VSYNC CSYNC GSYNC EXTSYNC SYNC BCAST LACED DOUBLE
        RGBA NONSTD ACCEL GRAYSCALE
        ENDMODE POLARITY BOOLEAN STRING NUMBER COLORS
 
@@ -91,6 +91,7 @@ options	  : /* empty */
 	  | options csync
 	  | options gsync
 	  | options extsync
+	  | options sync
 	  | options bcast
 	  | options laced
 	  | options double
@@ -130,6 +131,13 @@ extsync	  : EXTSYNC BOOLEAN
 	    }
 	  ;
 
+sync: SYNC NUMBER
+	    {
+		VideoMode.sync = $2;
+		fixCustomSync(&VideoMode);
+	    }
+	  ;
+
 bcast	  : BCAST BOOLEAN
 	    {
 		VideoMode.bcast = $2;
-- 
1.7.10

Reply via email to