|
@@ -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)
|