Commit c428f35a authored by Daniel Vetter's avatar Daniel Vetter

fb: Flatten control flow in fb_set_var

Instead of wiring almost everything down to the very last line using
goto soup (but not consistently, where would the fun be otherwise)
drop out early when checks fail. This allows us to flatten the huge
indent levels to just 1.

Aside: If a driver doesn't set ->fb_check_var, then FB_ACTIVATE_NOW
does nothing. This bug exists ever since this code was extracted as a
common helper in 2002, hence I decided against fixing it. Everyone
just better have a fb_check_var to make sure things work correctly.
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
Reviewed-by: default avatarSam Ravnborg <sam@ravnborg.org>
Reviewed-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Cc: "Michał Mirosław" <mirq-linux@rere.qmqm.pl>
Cc: Peter Rosin <peda@axentia.se>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Mikulas Patocka <mpatocka@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190528090304.9388-28-daniel.vetter@ffwll.ch
parent 36676173
...@@ -954,6 +954,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -954,6 +954,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{ {
int flags = info->flags; int flags = info->flags;
int ret = 0; int ret = 0;
u32 activate;
struct fb_var_screeninfo old_var;
struct fb_videomode mode;
if (var->activate & FB_ACTIVATE_INV_MODE) { if (var->activate & FB_ACTIVATE_INV_MODE) {
struct fb_videomode mode1, mode2; struct fb_videomode mode1, mode2;
...@@ -970,87 +973,84 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -970,87 +973,84 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
fb_delete_videomode(&mode1, &info->modelist); fb_delete_videomode(&mode1, &info->modelist);
ret = (ret) ? -EINVAL : 0; return ret ? -EINVAL : 0;
goto done;
} }
if ((var->activate & FB_ACTIVATE_FORCE) || if (!(var->activate & FB_ACTIVATE_FORCE) &&
memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { !memcmp(&info->var, var, sizeof(struct fb_var_screeninfo)))
u32 activate = var->activate; return 0;
/* When using FOURCC mode, make sure the red, green, blue and activate = var->activate;
* transp fields are set to 0.
*/
if ((info->fix.capabilities & FB_CAP_FOURCC) &&
var->grayscale > 1) {
if (var->red.offset || var->green.offset ||
var->blue.offset || var->transp.offset ||
var->red.length || var->green.length ||
var->blue.length || var->transp.length ||
var->red.msb_right || var->green.msb_right ||
var->blue.msb_right || var->transp.msb_right)
return -EINVAL;
}
if (!info->fbops->fb_check_var) { /* When using FOURCC mode, make sure the red, green, blue and
*var = info->var; * transp fields are set to 0.
goto done; */
} if ((info->fix.capabilities & FB_CAP_FOURCC) &&
var->grayscale > 1) {
if (var->red.offset || var->green.offset ||
var->blue.offset || var->transp.offset ||
var->red.length || var->green.length ||
var->blue.length || var->transp.length ||
var->red.msb_right || var->green.msb_right ||
var->blue.msb_right || var->transp.msb_right)
return -EINVAL;
}
ret = info->fbops->fb_check_var(var, info); if (!info->fbops->fb_check_var) {
*var = info->var;
return 0;
}
if (ret) ret = info->fbops->fb_check_var(var, info);
goto done;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { if (ret)
struct fb_var_screeninfo old_var; return ret;
struct fb_videomode mode;
if (info->fbops->fb_get_caps) { if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
ret = fb_check_caps(info, var, activate); return 0;
if (ret) if (info->fbops->fb_get_caps) {
goto done; ret = fb_check_caps(info, var, activate);
}
old_var = info->var; if (ret)
info->var = *var; return ret;
}
if (info->fbops->fb_set_par) { old_var = info->var;
ret = info->fbops->fb_set_par(info); info->var = *var;
if (ret) { if (info->fbops->fb_set_par) {
info->var = old_var; ret = info->fbops->fb_set_par(info);
printk(KERN_WARNING "detected "
"fb_set_par error, " if (ret) {
"error code: %d\n", ret); info->var = old_var;
goto done; printk(KERN_WARNING "detected "
} "fb_set_par error, "
} "error code: %d\n", ret);
return ret;
}
}
fb_pan_display(info, &info->var); fb_pan_display(info, &info->var);
fb_set_cmap(&info->cmap, info); fb_set_cmap(&info->cmap, info);
fb_var_to_videomode(&mode, &info->var); fb_var_to_videomode(&mode, &info->var);
if (info->modelist.prev && info->modelist.next && if (info->modelist.prev && info->modelist.next &&
!list_empty(&info->modelist)) !list_empty(&info->modelist))
ret = fb_add_videomode(&mode, &info->modelist); ret = fb_add_videomode(&mode, &info->modelist);
if (!ret && (flags & FBINFO_MISC_USEREVENT)) { if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
struct fb_event event; struct fb_event event;
int evnt = (activate & FB_ACTIVATE_ALL) ? int evnt = (activate & FB_ACTIVATE_ALL) ?
FB_EVENT_MODE_CHANGE_ALL : FB_EVENT_MODE_CHANGE_ALL :
FB_EVENT_MODE_CHANGE; FB_EVENT_MODE_CHANGE;
info->flags &= ~FBINFO_MISC_USEREVENT; info->flags &= ~FBINFO_MISC_USEREVENT;
event.info = info; event.info = info;
event.data = &mode; event.data = &mode;
fb_notifier_call_chain(evnt, &event); fb_notifier_call_chain(evnt, &event);
}
}
} }
done:
return ret; return ret;
} }
EXPORT_SYMBOL(fb_set_var); EXPORT_SYMBOL(fb_set_var);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment