Browse Source

[PATCH] fbdev: Reduce stack usage

calc_mode_timings() and fb_get_mode() are using more than 500 bytes off the
stack.  Fix.

Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Antonino A. Daplas 19 years ago
parent
commit
af5d0f7e2b
1 changed files with 68 additions and 58 deletions
  1. 68 58
      drivers/video/fbmon.c

+ 68 - 58
drivers/video/fbmon.c

@@ -317,26 +317,29 @@ static int edid_is_monitor_block(unsigned char *block)
 static void calc_mode_timings(int xres, int yres, int refresh,
 			      struct fb_videomode *mode)
 {
-	struct fb_var_screeninfo var;
-	struct fb_info info;
+	struct fb_var_screeninfo *var;
 	
-	memset(&var, 0, sizeof(struct fb_var_screeninfo));
-	var.xres = xres;
-	var.yres = yres;
-	fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 
-		    refresh, &var, &info);
-	mode->xres = xres;
-	mode->yres = yres;
-	mode->pixclock = var.pixclock;
-	mode->refresh = refresh;
-	mode->left_margin = var.left_margin;
-	mode->right_margin = var.right_margin;
-	mode->upper_margin = var.upper_margin;
-	mode->lower_margin = var.lower_margin;
-	mode->hsync_len = var.hsync_len;
-	mode->vsync_len = var.vsync_len;
-	mode->vmode = 0;
-	mode->sync = 0;
+	var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
+
+	if (var) {
+		var->xres = xres;
+		var->yres = yres;
+		fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
+			    refresh, var, NULL);
+		mode->xres = xres;
+		mode->yres = yres;
+		mode->pixclock = var->pixclock;
+		mode->refresh = refresh;
+		mode->left_margin = var->left_margin;
+		mode->right_margin = var->right_margin;
+		mode->upper_margin = var->upper_margin;
+		mode->lower_margin = var->lower_margin;
+		mode->hsync_len = var->hsync_len;
+		mode->vsync_len = var->vsync_len;
+		mode->vmode = 0;
+		mode->sync = 0;
+		kfree(var);
+	}
 }
 
 static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
@@ -1105,15 +1108,21 @@ static void fb_timings_dclk(struct __fb_timings *timings)
  */ 
 int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
 {
-	struct __fb_timings timings;
+	struct __fb_timings *timings;
 	u32 interlace = 1, dscan = 1;
-	u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
+	u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0;
+
+
+	timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL);
+
+	if (!timings)
+		return -ENOMEM;
 
 	/* 
 	 * If monspecs are invalid, use values that are enough
 	 * for 640x480@60
 	 */
-	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+	if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax ||
 	    !info->monspecs.dclkmax ||
 	    info->monspecs.hfmax < info->monspecs.hfmin ||
 	    info->monspecs.vfmax < info->monspecs.vfmin ||
@@ -1130,65 +1139,66 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
 		dclkmax = info->monspecs.dclkmax;
 	}
 
-	memset(&timings, 0, sizeof(struct __fb_timings));
-	timings.hactive = var->xres;
-	timings.vactive = var->yres;
+	timings->hactive = var->xres;
+	timings->vactive = var->yres;
 	if (var->vmode & FB_VMODE_INTERLACED) { 
-		timings.vactive /= 2;
+		timings->vactive /= 2;
 		interlace = 2;
 	}
 	if (var->vmode & FB_VMODE_DOUBLE) {
-		timings.vactive *= 2;
+		timings->vactive *= 2;
 		dscan = 2;
 	}
 
 	switch (flags & ~FB_IGNOREMON) {
 	case FB_MAXTIMINGS: /* maximize refresh rate */
-		timings.hfreq = hfmax;
-		fb_timings_hfreq(&timings);
-		if (timings.vfreq > vfmax) {
-			timings.vfreq = vfmax;
-			fb_timings_vfreq(&timings);
+		timings->hfreq = hfmax;
+		fb_timings_hfreq(timings);
+		if (timings->vfreq > vfmax) {
+			timings->vfreq = vfmax;
+			fb_timings_vfreq(timings);
 		}
-		if (timings.dclk > dclkmax) {
-			timings.dclk = dclkmax;
-			fb_timings_dclk(&timings);
+		if (timings->dclk > dclkmax) {
+			timings->dclk = dclkmax;
+			fb_timings_dclk(timings);
 		}
 		break;
 	case FB_VSYNCTIMINGS: /* vrefresh driven */
-		timings.vfreq = val;
-		fb_timings_vfreq(&timings);
+		timings->vfreq = val;
+		fb_timings_vfreq(timings);
 		break;
 	case FB_HSYNCTIMINGS: /* hsync driven */
-		timings.hfreq = val;
-		fb_timings_hfreq(&timings);
+		timings->hfreq = val;
+		fb_timings_hfreq(timings);
 		break;
 	case FB_DCLKTIMINGS: /* pixelclock driven */
-		timings.dclk = PICOS2KHZ(val) * 1000;
-		fb_timings_dclk(&timings);
+		timings->dclk = PICOS2KHZ(val) * 1000;
+		fb_timings_dclk(timings);
 		break;
 	default:
-		return -EINVAL;
+		err = -EINVAL;
 		
 	} 
 	
-	if (!(flags & FB_IGNOREMON) && 
-	    (timings.vfreq < vfmin || timings.vfreq > vfmax || 
-	     timings.hfreq < hfmin || timings.hfreq > hfmax ||
-	     timings.dclk < dclkmin || timings.dclk > dclkmax))
-		return -EINVAL;
-
-	var->pixclock = KHZ2PICOS(timings.dclk/1000);
-	var->hsync_len = (timings.htotal * 8)/100;
-	var->right_margin = (timings.hblank/2) - var->hsync_len;
-	var->left_margin = timings.hblank - var->right_margin - var->hsync_len;
-	
-	var->vsync_len = (3 * interlace)/dscan;
-	var->lower_margin = (1 * interlace)/dscan;
-	var->upper_margin = (timings.vblank * interlace)/dscan - 
-		(var->vsync_len + var->lower_margin);
+	if (err || (!(flags & FB_IGNOREMON) &&
+	    (timings->vfreq < vfmin || timings->vfreq > vfmax ||
+	     timings->hfreq < hfmin || timings->hfreq > hfmax ||
+	     timings->dclk < dclkmin || timings->dclk > dclkmax))) {
+		err = -EINVAL;
+	} else {
+		var->pixclock = KHZ2PICOS(timings->dclk/1000);
+		var->hsync_len = (timings->htotal * 8)/100;
+		var->right_margin = (timings->hblank/2) - var->hsync_len;
+		var->left_margin = timings->hblank - var->right_margin -
+			var->hsync_len;
+		var->vsync_len = (3 * interlace)/dscan;
+		var->lower_margin = (1 * interlace)/dscan;
+		var->upper_margin = (timings->vblank * interlace)/dscan -
+			(var->vsync_len + var->lower_margin);
+	}
 	
-	return 0;
+	kfree(timings);
+	return err;
 }
 #else
 int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)