aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/atmel_lcdfb.c
diff options
context:
space:
mode:
authorNicolas Ferre <nicolas.ferre@atmel.com>2008-07-24 00:31:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:40 -0400
commit968910bd03b226ed410d092c2da59dffe5bfe8de (patch)
tree8a49cbca6597dd67d6c21515c4c774a9d83ec522 /drivers/video/atmel_lcdfb.c
parent84c41ce83e9b2987ccef352f28ba0055b26c8f8e (diff)
atmel_lcdfb: avoid division by zero
Avoid division by zero in atmel_lcdfb_check_var() function. If pixclock is not specified while passing a var structure in the check_var() funtion, a division by zero occurs (when translating pixclock to KHz). This patch adds a checking of this value and try to choose a video mode in the modelist. The mode found in the probe function in added to the modelist. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> Cc: Haavard Skinnemoen <hskinnemoen@atmel.com> Cc: Andrew Victor <linux@maxim.org.za> Cc: "Antonino A. Daplas" <adaplas@pol.net> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/atmel_lcdfb.c')
-rw-r--r--drivers/video/atmel_lcdfb.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index d335bb96b03b..5b3a15dffb5f 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -256,6 +256,20 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
256 return 0; 256 return 0;
257} 257}
258 258
259static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
260 struct fb_info *info)
261{
262 struct fb_videomode varfbmode;
263 const struct fb_videomode *fbmode = NULL;
264
265 fb_var_to_videomode(&varfbmode, var);
266 fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
267 if (fbmode)
268 fb_videomode_to_var(var, fbmode);
269 return fbmode;
270}
271
272
259/** 273/**
260 * atmel_lcdfb_check_var - Validates a var passed in. 274 * atmel_lcdfb_check_var - Validates a var passed in.
261 * @var: frame buffer variable screen structure 275 * @var: frame buffer variable screen structure
@@ -289,6 +303,15 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
289 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; 303 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
290 304
291 dev_dbg(dev, "%s:\n", __func__); 305 dev_dbg(dev, "%s:\n", __func__);
306
307 if (!(var->pixclock && var->bits_per_pixel)) {
308 /* choose a suitable mode if possible */
309 if (!atmel_lcdfb_choose_mode(var, info)) {
310 dev_err(dev, "needed value not specified\n");
311 return -EINVAL;
312 }
313 }
314
292 dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres); 315 dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
293 dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock)); 316 dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
294 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); 317 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
@@ -299,6 +322,13 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
299 return -EINVAL; 322 return -EINVAL;
300 } 323 }
301 324
325 /* Do not allow to have real resoulution larger than virtual */
326 if (var->xres > var->xres_virtual)
327 var->xres_virtual = var->xres;
328
329 if (var->yres > var->yres_virtual)
330 var->yres_virtual = var->yres;
331
302 /* Force same alignment for each line */ 332 /* Force same alignment for each line */
303 var->xres = (var->xres + 3) & ~3UL; 333 var->xres = (var->xres + 3) & ~3UL;
304 var->xres_virtual = (var->xres_virtual + 3) & ~3UL; 334 var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
@@ -740,6 +770,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
740 struct fb_info *info; 770 struct fb_info *info;
741 struct atmel_lcdfb_info *sinfo; 771 struct atmel_lcdfb_info *sinfo;
742 struct atmel_lcdfb_info *pdata_sinfo; 772 struct atmel_lcdfb_info *pdata_sinfo;
773 struct fb_videomode fbmode;
743 struct resource *regs = NULL; 774 struct resource *regs = NULL;
744 struct resource *map = NULL; 775 struct resource *map = NULL;
745 int ret; 776 int ret;
@@ -906,6 +937,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
906 goto free_cmap; 937 goto free_cmap;
907 } 938 }
908 939
940 /* add selected videomode to modelist */
941 fb_var_to_videomode(&fbmode, &info->var);
942 fb_add_videomode(&fbmode, &info->modelist);
943
909 /* Power up the LCDC screen */ 944 /* Power up the LCDC screen */
910 if (sinfo->atmel_lcdfb_power_control) 945 if (sinfo->atmel_lcdfb_power_control)
911 sinfo->atmel_lcdfb_power_control(1); 946 sinfo->atmel_lcdfb_power_control(1);