Commit af5d0f7e authored by Antonino A. Daplas's avatar Antonino A. Daplas Committed by Linus Torvalds

[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: default avatarAntonino Daplas <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0a484a3a
...@@ -317,26 +317,29 @@ static int edid_is_monitor_block(unsigned char *block) ...@@ -317,26 +317,29 @@ static int edid_is_monitor_block(unsigned char *block)
static void calc_mode_timings(int xres, int yres, int refresh, static void calc_mode_timings(int xres, int yres, int refresh,
struct fb_videomode *mode) struct fb_videomode *mode)
{ {
struct fb_var_screeninfo var; struct fb_var_screeninfo *var;
struct fb_info info;
memset(&var, 0, sizeof(struct fb_var_screeninfo)); var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
var.xres = xres;
var.yres = yres; if (var) {
var->xres = xres;
var->yres = yres;
fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
refresh, &var, &info); refresh, var, NULL);
mode->xres = xres; mode->xres = xres;
mode->yres = yres; mode->yres = yres;
mode->pixclock = var.pixclock; mode->pixclock = var->pixclock;
mode->refresh = refresh; mode->refresh = refresh;
mode->left_margin = var.left_margin; mode->left_margin = var->left_margin;
mode->right_margin = var.right_margin; mode->right_margin = var->right_margin;
mode->upper_margin = var.upper_margin; mode->upper_margin = var->upper_margin;
mode->lower_margin = var.lower_margin; mode->lower_margin = var->lower_margin;
mode->hsync_len = var.hsync_len; mode->hsync_len = var->hsync_len;
mode->vsync_len = var.vsync_len; mode->vsync_len = var->vsync_len;
mode->vmode = 0; mode->vmode = 0;
mode->sync = 0; mode->sync = 0;
kfree(var);
}
} }
static int get_est_timing(unsigned char *block, struct fb_videomode *mode) 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) ...@@ -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) 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 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 * If monspecs are invalid, use values that are enough
* for 640x480@60 * for 640x480@60
*/ */
if (!info->monspecs.hfmax || !info->monspecs.vfmax || if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax ||
!info->monspecs.dclkmax || !info->monspecs.dclkmax ||
info->monspecs.hfmax < info->monspecs.hfmin || info->monspecs.hfmax < info->monspecs.hfmin ||
info->monspecs.vfmax < info->monspecs.vfmin || 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 ...@@ -1130,65 +1139,66 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
dclkmax = info->monspecs.dclkmax; dclkmax = info->monspecs.dclkmax;
} }
memset(&timings, 0, sizeof(struct __fb_timings)); timings->hactive = var->xres;
timings.hactive = var->xres; timings->vactive = var->yres;
timings.vactive = var->yres;
if (var->vmode & FB_VMODE_INTERLACED) { if (var->vmode & FB_VMODE_INTERLACED) {
timings.vactive /= 2; timings->vactive /= 2;
interlace = 2; interlace = 2;
} }
if (var->vmode & FB_VMODE_DOUBLE) { if (var->vmode & FB_VMODE_DOUBLE) {
timings.vactive *= 2; timings->vactive *= 2;
dscan = 2; dscan = 2;
} }
switch (flags & ~FB_IGNOREMON) { switch (flags & ~FB_IGNOREMON) {
case FB_MAXTIMINGS: /* maximize refresh rate */ case FB_MAXTIMINGS: /* maximize refresh rate */
timings.hfreq = hfmax; timings->hfreq = hfmax;
fb_timings_hfreq(&timings); fb_timings_hfreq(timings);
if (timings.vfreq > vfmax) { if (timings->vfreq > vfmax) {
timings.vfreq = vfmax; timings->vfreq = vfmax;
fb_timings_vfreq(&timings); fb_timings_vfreq(timings);
} }
if (timings.dclk > dclkmax) { if (timings->dclk > dclkmax) {
timings.dclk = dclkmax; timings->dclk = dclkmax;
fb_timings_dclk(&timings); fb_timings_dclk(timings);
} }
break; break;
case FB_VSYNCTIMINGS: /* vrefresh driven */ case FB_VSYNCTIMINGS: /* vrefresh driven */
timings.vfreq = val; timings->vfreq = val;
fb_timings_vfreq(&timings); fb_timings_vfreq(timings);
break; break;
case FB_HSYNCTIMINGS: /* hsync driven */ case FB_HSYNCTIMINGS: /* hsync driven */
timings.hfreq = val; timings->hfreq = val;
fb_timings_hfreq(&timings); fb_timings_hfreq(timings);
break; break;
case FB_DCLKTIMINGS: /* pixelclock driven */ case FB_DCLKTIMINGS: /* pixelclock driven */
timings.dclk = PICOS2KHZ(val) * 1000; timings->dclk = PICOS2KHZ(val) * 1000;
fb_timings_dclk(&timings); fb_timings_dclk(timings);
break; break;
default: default:
return -EINVAL; err = -EINVAL;
} }
if (!(flags & FB_IGNOREMON) && if (err || (!(flags & FB_IGNOREMON) &&
(timings.vfreq < vfmin || timings.vfreq > vfmax || (timings->vfreq < vfmin || timings->vfreq > vfmax ||
timings.hfreq < hfmin || timings.hfreq > hfmax || timings->hfreq < hfmin || timings->hfreq > hfmax ||
timings.dclk < dclkmin || timings.dclk > dclkmax)) timings->dclk < dclkmin || timings->dclk > dclkmax))) {
return -EINVAL; err = -EINVAL;
} else {
var->pixclock = KHZ2PICOS(timings.dclk/1000); var->pixclock = KHZ2PICOS(timings->dclk/1000);
var->hsync_len = (timings.htotal * 8)/100; var->hsync_len = (timings->htotal * 8)/100;
var->right_margin = (timings.hblank/2) - var->hsync_len; var->right_margin = (timings->hblank/2) - var->hsync_len;
var->left_margin = timings.hblank - var->right_margin - var->hsync_len; var->left_margin = timings->hblank - var->right_margin -
var->hsync_len;
var->vsync_len = (3 * interlace)/dscan; var->vsync_len = (3 * interlace)/dscan;
var->lower_margin = (1 * interlace)/dscan; var->lower_margin = (1 * interlace)/dscan;
var->upper_margin = (timings.vblank * interlace)/dscan - var->upper_margin = (timings->vblank * interlace)/dscan -
(var->vsync_len + var->lower_margin); (var->vsync_len + var->lower_margin);
}
return 0; kfree(timings);
return err;
} }
#else #else
int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment