From af5d0f7e2b5e9ef369de2aefe51e14ca1e6928f5 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Mon, 9 Jan 2006 20:53:38 -0800 Subject: [PATCH] [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 Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/fbmon.c | 126 +++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 58 deletions(-) diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index fc7965b66775..0ef75a9f84af 100644 --- a/drivers/video/fbmon.c +++ b/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; + 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); + } - 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)