[PATCH] tgafb: fix mode setting with fbset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi

This is backport of the upstream patch 
624966589041deb32a2626ee2e176e8274581101. It is suitable for all stable 
kernels up to and including 3.13.

Mikulas


commit 624966589041deb32a2626ee2e176e8274581101
Author: Mikulas Patocka <mpatocka@xxxxxxxxxx>
Date:   Thu Jan 23 14:42:43 2014 -0500

    tgafb: fix mode setting with fbset
    
    Mode setting in the TGA driver is broken for these reasons:
    
    - info->fix.line_length is set just once in tgafb_init_fix function. If
      we change videomode, info->fix.line_length is not recalculated - so
      the video mode is changed but the screen is corrupted because of wrong
      info->fix.line_length.
    
    - info->fix.smem_len is set in tgafb_init_fix to the size of the default
      video mode (640x480). If we set a higher resolution,
      info->fix.smem_len is smaller than the current screen size, preventing
      the userspace program from mapping the framebuffer.
    
    This patch fixes it:
    
    - info->fix.line_length initialization is moved to tgafb_set_par so that
      it is recalculated with each mode change.
    
    - info->fix.smem_len is set to a fixed value representing the real
      amount of video ram (the values are taken from xfree86 driver).
    
    - add a check to tgafb_check_var to prevent us from setting a videomode
      that doesn't fit into videoram.
    
    - in tgafb_register, tgafb_init_fix is moved upwards, to be called
      before fb_find_mode (because fb_find_mode already needs the videoram
      size set in tgafb_init_fix).
    
    Signed-off-by: Mikulas Patocka <mpatocka@xxxxxxxxxx>
    Cc: stable@xxxxxxxxxxxxxx
    Signed-off-by: Tomi Valkeinen <tomi.valkeinen@xxxxxx>

---
 drivers/video/tgafb.c |   15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

Index: linux-stable/drivers/video/tgafb.c
===================================================================
--- linux-stable.orig/drivers/video/tgafb.c	2014-05-14 15:16:05.000000000 +0200
+++ linux-stable/drivers/video/tgafb.c	2014-05-14 15:28:27.000000000 +0200
@@ -188,6 +188,8 @@ tgafb_check_var(struct fb_var_screeninfo
 
 	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
 		return -EINVAL;
+	if (var->xres * var->yres * (var->bits_per_pixel >> 3) > info->fix.smem_len)
+		return -EINVAL;
 	if (var->nonstd)
 		return -EINVAL;
 	if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ)
@@ -268,6 +270,7 @@ tgafb_set_par(struct fb_info *info)
 	par->yres = info->var.yres;
 	par->pll_freq = pll_freq = 1000000000 / info->var.pixclock;
 	par->bits_per_pixel = info->var.bits_per_pixel;
+	info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
 
 	tga_type = par->tga_type;
 
@@ -1476,6 +1479,7 @@ tgafb_init_fix(struct fb_info *info)
 	int tga_bus_tc = TGA_BUS_TC(par->dev);
 	u8 tga_type = par->tga_type;
 	const char *tga_type_name = NULL;
+	unsigned memory_size;
 
 	switch (tga_type) {
 	case TGA_TYPE_8PLANE:
@@ -1483,21 +1487,25 @@ tgafb_init_fix(struct fb_info *info)
 			tga_type_name = "Digital ZLXp-E1";
 		if (tga_bus_tc)
 			tga_type_name = "Digital ZLX-E1";
+		memory_size = 2097152;
 		break;
 	case TGA_TYPE_24PLANE:
 		if (tga_bus_pci)
 			tga_type_name = "Digital ZLXp-E2";
 		if (tga_bus_tc)
 			tga_type_name = "Digital ZLX-E2";
+		memory_size = 8388608;
 		break;
 	case TGA_TYPE_24PLUSZ:
 		if (tga_bus_pci)
 			tga_type_name = "Digital ZLXp-E3";
 		if (tga_bus_tc)
 			tga_type_name = "Digital ZLX-E3";
+		memory_size = 16777216;
 		break;
 	default:
 		tga_type_name = "Unknown";
+		memory_size = 16777216;
 		break;
 	}
 
@@ -1509,9 +1517,8 @@ tgafb_init_fix(struct fb_info *info)
 			    ? FB_VISUAL_PSEUDOCOLOR
 			    : FB_VISUAL_DIRECTCOLOR);
 
-	info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
 	info->fix.smem_start = (size_t) par->tga_fb_base;
-	info->fix.smem_len = info->fix.line_length * par->yres;
+	info->fix.smem_len = memory_size;
 	info->fix.mmio_start = (size_t) par->tga_regs_base;
 	info->fix.mmio_len = 512;
 
@@ -1635,6 +1642,9 @@ static int tgafb_register(struct device 
 		modedb_tga = &modedb_tc;
 		modedbsize_tga = 1;
 	}
+
+	tgafb_init_fix(info);
+
 	ret = fb_find_mode(&info->var, info,
 			   mode_option ? mode_option : mode_option_tga,
 			   modedb_tga, modedbsize_tga, NULL,
@@ -1652,7 +1662,6 @@ static int tgafb_register(struct device 
 	}
 
 	tgafb_set_par(info);
-	tgafb_init_fix(info);
 
 	if (register_framebuffer(info) < 0) {
 		printk(KERN_ERR "tgafb: Could not register framebuffer\n");
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]