Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Nicolas Ferre and committed by
Linus Torvalds
968910bd 84c41ce8

+35
+35
drivers/video/atmel_lcdfb.c
··· 256 256 return 0; 257 257 } 258 258 259 + static 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 274 * atmel_lcdfb_check_var - Validates a var passed in. 261 275 * @var: frame buffer variable screen structure ··· 303 289 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; 304 290 305 291 dev_dbg(dev, "%s:\n", __func__); 292 + 293 + if (!(var->pixclock && var->bits_per_pixel)) { 294 + /* choose a suitable mode if possible */ 295 + if (!atmel_lcdfb_choose_mode(var, info)) { 296 + dev_err(dev, "needed value not specified\n"); 297 + return -EINVAL; 298 + } 299 + } 300 + 306 301 dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres); 307 302 dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock)); 308 303 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); ··· 321 298 dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock)); 322 299 return -EINVAL; 323 300 } 301 + 302 + /* Do not allow to have real resoulution larger than virtual */ 303 + if (var->xres > var->xres_virtual) 304 + var->xres_virtual = var->xres; 305 + 306 + if (var->yres > var->yres_virtual) 307 + var->yres_virtual = var->yres; 324 308 325 309 /* Force same alignment for each line */ 326 310 var->xres = (var->xres + 3) & ~3UL; ··· 770 740 struct fb_info *info; 771 741 struct atmel_lcdfb_info *sinfo; 772 742 struct atmel_lcdfb_info *pdata_sinfo; 743 + struct fb_videomode fbmode; 773 744 struct resource *regs = NULL; 774 745 struct resource *map = NULL; 775 746 int ret; ··· 936 905 dev_err(dev, "failed to register framebuffer device: %d\n", ret); 937 906 goto free_cmap; 938 907 } 908 + 909 + /* add selected videomode to modelist */ 910 + fb_var_to_videomode(&fbmode, &info->var); 911 + fb_add_videomode(&fbmode, &info->modelist); 939 912 940 913 /* Power up the LCDC screen */ 941 914 if (sinfo->atmel_lcdfb_power_control)