Commit 0fcf6ada2b8eb42d132c0846384f1299889609e3

Authored by Florian Tobias Schandinat
Committed by Linus Torvalds
1 parent 360fa58828

fb: do not ignore fb_set_par errors

At the moment about half of the framebuffer drivers can return an error
code in fb_set_par. Until now it would be silently ignored by fbmem.c
and fbcon.c. This patch fixes fbmem.c to return the error code and
restore var on error.

But it is not clear in which video mode the device is when fb_set_par
fails.  It would be good and reasonable if it were in the old state but
there is no guarantee that this is true for all existing drivers.
Additionally print a message if a failing fb_set_par is detected in
fbmem.c or fbcon.c.

Although most errors should be caught by the previous fb_check_var some
errors can't as they are dynamic (memory allocations, ...) and can only be
detected while performing the operations which is forbidden in
fb_check_var.

This patch shouldn't have a negative impact on normal operation as all
drivers return 0 on success.  The impact in case of error depends heavily
on the driver and caller but it's expected to be better than before.

Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
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>

Showing 2 changed files with 50 additions and 13 deletions Side-by-side Diff

drivers/video/console/fbcon.c
... ... @@ -725,7 +725,7 @@
725 725 int oldidx, int found)
726 726 {
727 727 struct fbcon_ops *ops = oldinfo->fbcon_par;
728   - int err = 0;
  728 + int err = 0, ret;
729 729  
730 730 if (oldinfo->fbops->fb_release &&
731 731 oldinfo->fbops->fb_release(oldinfo, 0)) {
... ... @@ -752,8 +752,14 @@
752 752 newinfo in an undefined state. Thus, a call to
753 753 fb_set_par() may be needed for the newinfo.
754 754 */
755   - if (newinfo->fbops->fb_set_par)
756   - newinfo->fbops->fb_set_par(newinfo);
  755 + if (newinfo->fbops->fb_set_par) {
  756 + ret = newinfo->fbops->fb_set_par(newinfo);
  757 +
  758 + if (ret)
  759 + printk(KERN_ERR "con2fb_release_oldinfo: "
  760 + "detected unhandled fb_set_par error, "
  761 + "error code %d\n", ret);
  762 + }
757 763 }
758 764  
759 765 return err;
760 766  
761 767  
... ... @@ -763,12 +769,19 @@
763 769 int unit, int show_logo)
764 770 {
765 771 struct fbcon_ops *ops = info->fbcon_par;
  772 + int ret;
766 773  
767 774 ops->currcon = fg_console;
768 775  
769   - if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT))
770   - info->fbops->fb_set_par(info);
  776 + if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) {
  777 + ret = info->fbops->fb_set_par(info);
771 778  
  779 + if (ret)
  780 + printk(KERN_ERR "con2fb_init_display: detected "
  781 + "unhandled fb_set_par error, "
  782 + "error code %d\n", ret);
  783 + }
  784 +
772 785 ops->flags |= FBCON_FLAGS_INIT;
773 786 ops->graphics = 0;
774 787 fbcon_set_disp(info, &info->var, unit);
... ... @@ -1006,7 +1019,7 @@
1006 1019 struct vc_data *svc = *default_mode;
1007 1020 struct display *t, *p = &fb_display[vc->vc_num];
1008 1021 int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256;
1009   - int cap;
  1022 + int cap, ret;
1010 1023  
1011 1024 if (info_idx == -1 || info == NULL)
1012 1025 return;
... ... @@ -1092,8 +1105,15 @@
1092 1105 */
1093 1106 if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {
1094 1107 if (info->fbops->fb_set_par &&
1095   - !(ops->flags & FBCON_FLAGS_INIT))
1096   - info->fbops->fb_set_par(info);
  1108 + !(ops->flags & FBCON_FLAGS_INIT)) {
  1109 + ret = info->fbops->fb_set_par(info);
  1110 +
  1111 + if (ret)
  1112 + printk(KERN_ERR "fbcon_init: detected "
  1113 + "unhandled fb_set_par error, "
  1114 + "error code %d\n", ret);
  1115 + }
  1116 +
1097 1117 ops->flags |= FBCON_FLAGS_INIT;
1098 1118 }
1099 1119  
... ... @@ -2119,7 +2139,7 @@
2119 2139 struct fbcon_ops *ops;
2120 2140 struct display *p = &fb_display[vc->vc_num];
2121 2141 struct fb_var_screeninfo var;
2122   - int i, prev_console, charcnt = 256;
  2142 + int i, ret, prev_console, charcnt = 256;
2123 2143  
2124 2144 info = registered_fb[con2fb_map[vc->vc_num]];
2125 2145 ops = info->fbcon_par;
... ... @@ -2174,8 +2194,14 @@
2174 2194  
2175 2195 if (old_info != NULL && (old_info != info ||
2176 2196 info->flags & FBINFO_MISC_ALWAYS_SETPAR)) {
2177   - if (info->fbops->fb_set_par)
2178   - info->fbops->fb_set_par(info);
  2197 + if (info->fbops->fb_set_par) {
  2198 + ret = info->fbops->fb_set_par(info);
  2199 +
  2200 + if (ret)
  2201 + printk(KERN_ERR "fbcon_switch: detected "
  2202 + "unhandled fb_set_par error, "
  2203 + "error code %d\n", ret);
  2204 + }
2179 2205  
2180 2206 if (old_info != info)
2181 2207 fbcon_del_cursor_timer(old_info);
drivers/video/fbmem.c
... ... @@ -954,6 +954,7 @@
954 954 goto done;
955 955  
956 956 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
  957 + struct fb_var_screeninfo old_var;
957 958 struct fb_videomode mode;
958 959  
959 960 if (info->fbops->fb_get_caps) {
960 961  
... ... @@ -963,10 +964,20 @@
963 964 goto done;
964 965 }
965 966  
  967 + old_var = info->var;
966 968 info->var = *var;
967 969  
968   - if (info->fbops->fb_set_par)
969   - info->fbops->fb_set_par(info);
  970 + if (info->fbops->fb_set_par) {
  971 + ret = info->fbops->fb_set_par(info);
  972 +
  973 + if (ret) {
  974 + info->var = old_var;
  975 + printk(KERN_WARNING "detected "
  976 + "fb_set_par error, "
  977 + "error code: %d\n", ret);
  978 + goto done;
  979 + }
  980 + }
970 981  
971 982 fb_pan_display(info, &info->var);
972 983 fb_set_cmap(&info->cmap, info);