diff options
-rw-r--r-- | drivers/video/fbmon.c | 126 |
1 files 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) | |||
317 | static void calc_mode_timings(int xres, int yres, int refresh, | 317 | static void calc_mode_timings(int xres, int yres, int refresh, |
318 | struct fb_videomode *mode) | 318 | struct fb_videomode *mode) |
319 | { | 319 | { |
320 | struct fb_var_screeninfo var; | 320 | struct fb_var_screeninfo *var; |
321 | struct fb_info info; | ||
322 | 321 | ||
323 | memset(&var, 0, sizeof(struct fb_var_screeninfo)); | 322 | var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL); |
324 | var.xres = xres; | 323 | |
325 | var.yres = yres; | 324 | if (var) { |
326 | fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, | 325 | var->xres = xres; |
327 | refresh, &var, &info); | 326 | var->yres = yres; |
328 | mode->xres = xres; | 327 | fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, |
329 | mode->yres = yres; | 328 | refresh, var, NULL); |
330 | mode->pixclock = var.pixclock; | 329 | mode->xres = xres; |
331 | mode->refresh = refresh; | 330 | mode->yres = yres; |
332 | mode->left_margin = var.left_margin; | 331 | mode->pixclock = var->pixclock; |
333 | mode->right_margin = var.right_margin; | 332 | mode->refresh = refresh; |
334 | mode->upper_margin = var.upper_margin; | 333 | mode->left_margin = var->left_margin; |
335 | mode->lower_margin = var.lower_margin; | 334 | mode->right_margin = var->right_margin; |
336 | mode->hsync_len = var.hsync_len; | 335 | mode->upper_margin = var->upper_margin; |
337 | mode->vsync_len = var.vsync_len; | 336 | mode->lower_margin = var->lower_margin; |
338 | mode->vmode = 0; | 337 | mode->hsync_len = var->hsync_len; |
339 | mode->sync = 0; | 338 | mode->vsync_len = var->vsync_len; |
339 | mode->vmode = 0; | ||
340 | mode->sync = 0; | ||
341 | kfree(var); | ||
342 | } | ||
340 | } | 343 | } |
341 | 344 | ||
342 | static int get_est_timing(unsigned char *block, struct fb_videomode *mode) | 345 | 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 | */ | 1108 | */ |
1106 | int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) | 1109 | int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) |
1107 | { | 1110 | { |
1108 | struct __fb_timings timings; | 1111 | struct __fb_timings *timings; |
1109 | u32 interlace = 1, dscan = 1; | 1112 | u32 interlace = 1, dscan = 1; |
1110 | u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; | 1113 | u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0; |
1114 | |||
1115 | |||
1116 | timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL); | ||
1117 | |||
1118 | if (!timings) | ||
1119 | return -ENOMEM; | ||
1111 | 1120 | ||
1112 | /* | 1121 | /* |
1113 | * If monspecs are invalid, use values that are enough | 1122 | * If monspecs are invalid, use values that are enough |
1114 | * for 640x480@60 | 1123 | * for 640x480@60 |
1115 | */ | 1124 | */ |
1116 | if (!info->monspecs.hfmax || !info->monspecs.vfmax || | 1125 | if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax || |
1117 | !info->monspecs.dclkmax || | 1126 | !info->monspecs.dclkmax || |
1118 | info->monspecs.hfmax < info->monspecs.hfmin || | 1127 | info->monspecs.hfmax < info->monspecs.hfmin || |
1119 | info->monspecs.vfmax < info->monspecs.vfmin || | 1128 | 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 | dclkmax = info->monspecs.dclkmax; | 1139 | dclkmax = info->monspecs.dclkmax; |
1131 | } | 1140 | } |
1132 | 1141 | ||
1133 | memset(&timings, 0, sizeof(struct __fb_timings)); | 1142 | timings->hactive = var->xres; |
1134 | timings.hactive = var->xres; | 1143 | timings->vactive = var->yres; |
1135 | timings.vactive = var->yres; | ||
1136 | if (var->vmode & FB_VMODE_INTERLACED) { | 1144 | if (var->vmode & FB_VMODE_INTERLACED) { |
1137 | timings.vactive /= 2; | 1145 | timings->vactive /= 2; |
1138 | interlace = 2; | 1146 | interlace = 2; |
1139 | } | 1147 | } |
1140 | if (var->vmode & FB_VMODE_DOUBLE) { | 1148 | if (var->vmode & FB_VMODE_DOUBLE) { |
1141 | timings.vactive *= 2; | 1149 | timings->vactive *= 2; |
1142 | dscan = 2; | 1150 | dscan = 2; |
1143 | } | 1151 | } |
1144 | 1152 | ||
1145 | switch (flags & ~FB_IGNOREMON) { | 1153 | switch (flags & ~FB_IGNOREMON) { |
1146 | case FB_MAXTIMINGS: /* maximize refresh rate */ | 1154 | case FB_MAXTIMINGS: /* maximize refresh rate */ |
1147 | timings.hfreq = hfmax; | 1155 | timings->hfreq = hfmax; |
1148 | fb_timings_hfreq(&timings); | 1156 | fb_timings_hfreq(timings); |
1149 | if (timings.vfreq > vfmax) { | 1157 | if (timings->vfreq > vfmax) { |
1150 | timings.vfreq = vfmax; | 1158 | timings->vfreq = vfmax; |
1151 | fb_timings_vfreq(&timings); | 1159 | fb_timings_vfreq(timings); |
1152 | } | 1160 | } |
1153 | if (timings.dclk > dclkmax) { | 1161 | if (timings->dclk > dclkmax) { |
1154 | timings.dclk = dclkmax; | 1162 | timings->dclk = dclkmax; |
1155 | fb_timings_dclk(&timings); | 1163 | fb_timings_dclk(timings); |
1156 | } | 1164 | } |
1157 | break; | 1165 | break; |
1158 | case FB_VSYNCTIMINGS: /* vrefresh driven */ | 1166 | case FB_VSYNCTIMINGS: /* vrefresh driven */ |
1159 | timings.vfreq = val; | 1167 | timings->vfreq = val; |
1160 | fb_timings_vfreq(&timings); | 1168 | fb_timings_vfreq(timings); |
1161 | break; | 1169 | break; |
1162 | case FB_HSYNCTIMINGS: /* hsync driven */ | 1170 | case FB_HSYNCTIMINGS: /* hsync driven */ |
1163 | timings.hfreq = val; | 1171 | timings->hfreq = val; |
1164 | fb_timings_hfreq(&timings); | 1172 | fb_timings_hfreq(timings); |
1165 | break; | 1173 | break; |
1166 | case FB_DCLKTIMINGS: /* pixelclock driven */ | 1174 | case FB_DCLKTIMINGS: /* pixelclock driven */ |
1167 | timings.dclk = PICOS2KHZ(val) * 1000; | 1175 | timings->dclk = PICOS2KHZ(val) * 1000; |
1168 | fb_timings_dclk(&timings); | 1176 | fb_timings_dclk(timings); |
1169 | break; | 1177 | break; |
1170 | default: | 1178 | default: |
1171 | return -EINVAL; | 1179 | err = -EINVAL; |
1172 | 1180 | ||
1173 | } | 1181 | } |
1174 | 1182 | ||
1175 | if (!(flags & FB_IGNOREMON) && | 1183 | if (err || (!(flags & FB_IGNOREMON) && |
1176 | (timings.vfreq < vfmin || timings.vfreq > vfmax || | 1184 | (timings->vfreq < vfmin || timings->vfreq > vfmax || |
1177 | timings.hfreq < hfmin || timings.hfreq > hfmax || | 1185 | timings->hfreq < hfmin || timings->hfreq > hfmax || |
1178 | timings.dclk < dclkmin || timings.dclk > dclkmax)) | 1186 | timings->dclk < dclkmin || timings->dclk > dclkmax))) { |
1179 | return -EINVAL; | 1187 | err = -EINVAL; |
1180 | 1188 | } else { | |
1181 | var->pixclock = KHZ2PICOS(timings.dclk/1000); | 1189 | var->pixclock = KHZ2PICOS(timings->dclk/1000); |
1182 | var->hsync_len = (timings.htotal * 8)/100; | 1190 | var->hsync_len = (timings->htotal * 8)/100; |
1183 | var->right_margin = (timings.hblank/2) - var->hsync_len; | 1191 | var->right_margin = (timings->hblank/2) - var->hsync_len; |
1184 | var->left_margin = timings.hblank - var->right_margin - var->hsync_len; | 1192 | var->left_margin = timings->hblank - var->right_margin - |
1185 | 1193 | var->hsync_len; | |
1186 | var->vsync_len = (3 * interlace)/dscan; | 1194 | var->vsync_len = (3 * interlace)/dscan; |
1187 | var->lower_margin = (1 * interlace)/dscan; | 1195 | var->lower_margin = (1 * interlace)/dscan; |
1188 | var->upper_margin = (timings.vblank * interlace)/dscan - | 1196 | var->upper_margin = (timings->vblank * interlace)/dscan - |
1189 | (var->vsync_len + var->lower_margin); | 1197 | (var->vsync_len + var->lower_margin); |
1198 | } | ||
1190 | 1199 | ||
1191 | return 0; | 1200 | kfree(timings); |
1201 | return err; | ||
1192 | } | 1202 | } |
1193 | #else | 1203 | #else |
1194 | int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) | 1204 | int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) |