Commit d609f60a authored by Maarten Lankhorst's avatar Maarten Lankhorst

Merge branch 'topic/remove-fbcon-notifiers' into drm-misc-next

topic/remove-fbcon-notifiers:
- remove fbdev notifier usage for fbcon, as prep work to clean up the fbcon locking
- assorted locking checks in vt/console code
- assorted notifier and cleanups in fbdev and backlight code

This is the pull request that was sent out, plus the compile fix for
sh4 reported by kbuild.
Acked-by: default avatarBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
parents bcb7416e 24430914
...@@ -347,8 +347,17 @@ int __init am200_init(void) ...@@ -347,8 +347,17 @@ int __init am200_init(void)
{ {
int ret; int ret;
/* before anything else, we request notification for any fb /*
* creation events */ * Before anything else, we request notification for any fb
* creation events.
*
* FIXME: This is terrible and needs to be nuked. The notifier is used
* to get at the fb base address from the boot splash fb driver, which
* is then passed to metronomefb. Instaed of metronomfb or this board
* support file here figuring this out on their own.
*
* See also the #ifdef in fbmem.c.
*/
fb_register_client(&am200_fb_notif); fb_register_client(&am200_fb_notif);
pxa2xx_mfp_config(ARRAY_AND_SIZE(am200_pin_config)); pxa2xx_mfp_config(ARRAY_AND_SIZE(am200_pin_config));
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/fbcon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
...@@ -734,14 +735,8 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) ...@@ -734,14 +735,8 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (!active->driver_power_control) if (!active->driver_power_control)
set_audio_state(active->id, VGA_SWITCHEROO_OFF); set_audio_state(active->id, VGA_SWITCHEROO_OFF);
if (new_client->fb_info) { if (new_client->fb_info)
struct fb_event event; fbcon_remap_all(new_client->fb_info);
console_lock();
event.info = new_client->fb_info;
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
console_unlock();
}
mutex_lock(&vgasr_priv.mux_hw_lock); mutex_lock(&vgasr_priv.mux_hw_lock);
ret = vgasr_priv.handler->switchto(new_client->id); ret = vgasr_priv.handler->switchto(new_client->id);
......
...@@ -1246,11 +1246,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p) ...@@ -1246,11 +1246,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
struct osd_info *oi = itv->osd_info; struct osd_info *oi = itv->osd_info;
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) { unregister_framebuffer(&itv->osd_info->ivtvfb_info);
IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
itv->instance);
return 0;
}
IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance); IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
itv->ivtvfb_restore = NULL; itv->ivtvfb_restore = NULL;
ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info); ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
......
...@@ -891,7 +891,9 @@ int fbtft_unregister_framebuffer(struct fb_info *fb_info) ...@@ -891,7 +891,9 @@ int fbtft_unregister_framebuffer(struct fb_info *fb_info)
if (par->fbtftops.unregister_backlight) if (par->fbtftops.unregister_backlight)
par->fbtftops.unregister_backlight(par); par->fbtftops.unregister_backlight(par);
fbtft_sysfs_exit(par); fbtft_sysfs_exit(par);
return unregister_framebuffer(fb_info); unregister_framebuffer(fb_info);
return 0;
} }
EXPORT_SYMBOL(fbtft_unregister_framebuffer); EXPORT_SYMBOL(fbtft_unregister_framebuffer);
......
TODO: TODO:
- complete rewrite:
1. The underlying fbdev drivers need to be converted into drm kernel
modesetting drivers.
2. The dcon low-power display mode can then be integrated using the
drm damage tracking and self-refresh helpers.
This bolted-on self-refresh support that digs around in fbdev
internals, but isn't properly integrated, is not the correct solution.
- see if vx855 gpio API can be made similar enough to cs5535 so we can - see if vx855 gpio API can be made similar enough to cs5535 so we can
share more code share more code
- convert all uses of the old GPIO API from <linux/gpio.h> to the - convert all uses of the old GPIO API from <linux/gpio.h> to the
......
...@@ -250,11 +250,7 @@ static bool dcon_blank_fb(struct dcon_priv *dcon, bool blank) ...@@ -250,11 +250,7 @@ static bool dcon_blank_fb(struct dcon_priv *dcon, bool blank)
int err; int err;
console_lock(); console_lock();
if (!lock_fb_info(dcon->fbinfo)) { lock_fb_info(dcon->fbinfo);
console_unlock();
dev_err(&dcon->client->dev, "unable to lock framebuffer\n");
return false;
}
dcon->ignore_fb_events = true; dcon->ignore_fb_events = true;
err = fb_blank(dcon->fbinfo, err = fb_blank(dcon->fbinfo,
......
...@@ -3822,6 +3822,8 @@ int con_is_bound(const struct consw *csw) ...@@ -3822,6 +3822,8 @@ int con_is_bound(const struct consw *csw)
{ {
int i, bound = 0; int i, bound = 0;
WARN_CONSOLE_UNLOCKED();
for (i = 0; i < MAX_NR_CONSOLES; i++) { for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (con_driver_map[i] == csw) { if (con_driver_map[i] == csw) {
bound = 1; bound = 1;
...@@ -3833,6 +3835,20 @@ int con_is_bound(const struct consw *csw) ...@@ -3833,6 +3835,20 @@ int con_is_bound(const struct consw *csw)
} }
EXPORT_SYMBOL(con_is_bound); EXPORT_SYMBOL(con_is_bound);
/**
* con_is_visible - checks whether the current console is visible
* @vc: virtual console
*
* RETURNS: zero if not visible, nonzero if visible
*/
bool con_is_visible(const struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
return *vc->vc_display_fg == vc;
}
EXPORT_SYMBOL(con_is_visible);
/** /**
* con_debug_enter - prepare the console for the kernel debugger * con_debug_enter - prepare the console for the kernel debugger
* @sw: console driver * @sw: console driver
...@@ -4166,6 +4182,8 @@ void do_blank_screen(int entering_gfx) ...@@ -4166,6 +4182,8 @@ void do_blank_screen(int entering_gfx)
struct vc_data *vc = vc_cons[fg_console].d; struct vc_data *vc = vc_cons[fg_console].d;
int i; int i;
might_sleep();
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
if (console_blanked) { if (console_blanked) {
......
...@@ -47,7 +47,7 @@ static int fb_notifier_callback(struct notifier_block *self, ...@@ -47,7 +47,7 @@ static int fb_notifier_callback(struct notifier_block *self,
int fb_blank = 0; int fb_blank = 0;
/* If we aren't interested in this event, skip it immediately ... */ /* If we aren't interested in this event, skip it immediately ... */
if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK) if (event != FB_EVENT_BLANK)
return 0; return 0;
bd = container_of(self, struct backlight_device, fb_notif); bd = container_of(self, struct backlight_device, fb_notif);
......
...@@ -30,18 +30,6 @@ static int fb_notifier_callback(struct notifier_block *self, ...@@ -30,18 +30,6 @@ static int fb_notifier_callback(struct notifier_block *self,
struct lcd_device *ld; struct lcd_device *ld;
struct fb_event *evdata = data; struct fb_event *evdata = data;
/* If we aren't interested in this event, skip it immediately ... */
switch (event) {
case FB_EVENT_BLANK:
case FB_EVENT_MODE_CHANGE:
case FB_EVENT_MODE_CHANGE_ALL:
case FB_EARLY_EVENT_BLANK:
case FB_R_EARLY_EVENT_BLANK:
break;
default:
return 0;
}
ld = container_of(self, struct lcd_device, fb_notif); ld = container_of(self, struct lcd_device, fb_notif);
if (!ld->ops) if (!ld->ops)
return 0; return 0;
......
...@@ -34,6 +34,8 @@ static bool dummycon_putc_called; ...@@ -34,6 +34,8 @@ static bool dummycon_putc_called;
void dummycon_register_output_notifier(struct notifier_block *nb) void dummycon_register_output_notifier(struct notifier_block *nb)
{ {
WARN_CONSOLE_UNLOCKED();
raw_notifier_chain_register(&dummycon_output_nh, nb); raw_notifier_chain_register(&dummycon_output_nh, nb);
if (dummycon_putc_called) if (dummycon_putc_called)
...@@ -42,11 +44,15 @@ void dummycon_register_output_notifier(struct notifier_block *nb) ...@@ -42,11 +44,15 @@ void dummycon_register_output_notifier(struct notifier_block *nb)
void dummycon_unregister_output_notifier(struct notifier_block *nb) void dummycon_unregister_output_notifier(struct notifier_block *nb)
{ {
WARN_CONSOLE_UNLOCKED();
raw_notifier_chain_unregister(&dummycon_output_nh, nb); raw_notifier_chain_unregister(&dummycon_output_nh, nb);
} }
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
{ {
WARN_CONSOLE_UNLOCKED();
dummycon_putc_called = true; dummycon_putc_called = true;
raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
} }
......
...@@ -2350,70 +2350,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) ...@@ -2350,70 +2350,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
return -EINVAL; return -EINVAL;
} }
#if 0
/*
* Accelerated functions
*/
static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
u_int width, u_int height,
struct fb_info_aty128 *par)
{
u32 save_dp_datatype, save_dp_cntl, dstval;
if (!width || !height)
return;
dstval = depth_to_dst(par->current_par.crtc.depth);
if (dstval == DST_24BPP) {
srcx *= 3;
dstx *= 3;
width *= 3;
} else if (dstval == -EINVAL) {
printk("aty128fb: invalid depth or RGBA\n");
return;
}
wait_for_fifo(2, par);
save_dp_datatype = aty_ld_le32(DP_DATATYPE);
save_dp_cntl = aty_ld_le32(DP_CNTL);
wait_for_fifo(6, par);
aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR);
aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
par->blitter_may_be_busy = 1;
wait_for_fifo(2, par);
aty_st_le32(DP_DATATYPE, save_dp_datatype);
aty_st_le32(DP_CNTL, save_dp_cntl);
}
/*
* Text mode accelerated functions
*/
static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy,
int dx, int height, int width)
{
sx *= fontwidth(p);
sy *= fontheight(p);
dx *= fontwidth(p);
dy *= fontheight(p);
width *= fontwidth(p);
height *= fontheight(p);
aty128_rectcopy(sx, sy, dx, dy, width, height,
(struct fb_info_aty128 *)p->fb_info);
}
#endif /* 0 */
static void aty128_set_suspend(struct aty128fb_par *par, int suspend) static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
{ {
u32 pmgt; u32 pmgt;
......
...@@ -3916,8 +3916,7 @@ static int atyfb_reboot_notify(struct notifier_block *nb, ...@@ -3916,8 +3916,7 @@ static int atyfb_reboot_notify(struct notifier_block *nb,
if (!reboot_info) if (!reboot_info)
goto out; goto out;
if (!lock_fb_info(reboot_info)) lock_fb_info(reboot_info);
goto out;
par = reboot_info->par; par = reboot_info->par;
......
...@@ -285,11 +285,7 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) ...@@ -285,11 +285,7 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
goto out; goto out;
} }
umap.start = cmap->start; umap.start = cmap->start;
if (!lock_fb_info(info)) { lock_fb_info(info);
rc = -ENODEV;
goto out;
}
rc = fb_set_cmap(&umap, info); rc = fb_set_cmap(&umap, info);
unlock_fb_info(info); unlock_fb_info(info);
out: out:
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/crc32.h> /* For counting font checksums */ #include <linux/crc32.h> /* For counting font checksums */
#include <linux/uaccess.h>
#include <asm/fb.h> #include <asm/fb.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -87,13 +88,32 @@ ...@@ -87,13 +88,32 @@
# define DPRINTK(fmt, args...) # define DPRINTK(fmt, args...)
#endif #endif
/*
* FIXME: Locking
*
* - fbcon state itself is protected by the console_lock, and the code does a
* pretty good job at making sure that lock is held everywhere it's needed.
*
* - access to the registered_fb array is entirely unprotected. This should use
* proper object lifetime handling, i.e. get/put_fb_info. This also means
* switching from indices to proper pointers for fb_info everywhere.
*
* - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it
* means concurrent access to the same fbdev from both fbcon and userspace
* will blow up. To fix this all fbcon calls from fbmem.c need to be moved out
* of fb_lock/unlock protected sections, since otherwise we'll recurse and
* deadlock eventually. Aside: Due to these deadlock issues the fbdev code in
* fbmem.c cannot use locking asserts, and there's lots of callers which get
* the rules wrong, e.g. fbsysfs.c entirely missed fb_lock/unlock calls too.
*/
enum { enum {
FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */ FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */
FBCON_LOGO_DRAW = -2, /* draw the logo to a console */ FBCON_LOGO_DRAW = -2, /* draw the logo to a console */
FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */ FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */
}; };
static struct display fb_display[MAX_NR_CONSOLES]; static struct fbcon_display fb_display[MAX_NR_CONSOLES];
static signed char con2fb_map[MAX_NR_CONSOLES]; static signed char con2fb_map[MAX_NR_CONSOLES];
static signed char con2fb_map_boot[MAX_NR_CONSOLES]; static signed char con2fb_map_boot[MAX_NR_CONSOLES];
...@@ -112,7 +132,6 @@ static int softback_lines; ...@@ -112,7 +132,6 @@ static int softback_lines;
static int first_fb_vc; static int first_fb_vc;
static int last_fb_vc = MAX_NR_CONSOLES - 1; static int last_fb_vc = MAX_NR_CONSOLES - 1;
static int fbcon_is_default = 1; static int fbcon_is_default = 1;
static int fbcon_has_exited;
static int primary_device = -1; static int primary_device = -1;
static int fbcon_has_console_bind; static int fbcon_has_console_bind;
...@@ -185,11 +204,11 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count); ...@@ -185,11 +204,11 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count);
static __inline__ void ywrap_down(struct vc_data *vc, int count); static __inline__ void ywrap_down(struct vc_data *vc, int count);
static __inline__ void ypan_up(struct vc_data *vc, int count); static __inline__ void ypan_up(struct vc_data *vc, int count);
static __inline__ void ypan_down(struct vc_data *vc, int count); static __inline__ void ypan_down(struct vc_data *vc, int count);
static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
int dy, int dx, int height, int width, u_int y_break); int dy, int dx, int height, int width, u_int y_break);
static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
int unit); int unit);
static void fbcon_redraw_move(struct vc_data *vc, struct display *p, static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
int line, int count, int dy); int line, int count, int dy);
static void fbcon_modechanged(struct fb_info *info); static void fbcon_modechanged(struct fb_info *info);
static void fbcon_set_all_vcs(struct fb_info *info); static void fbcon_set_all_vcs(struct fb_info *info);
...@@ -220,7 +239,7 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate) ...@@ -220,7 +239,7 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate)
fb_info = registered_fb[con2fb_map[ops->currcon]]; fb_info = registered_fb[con2fb_map[ops->currcon]];
if (info == fb_info) { if (info == fb_info) {
struct display *p = &fb_display[ops->currcon]; struct fbcon_display *p = &fb_display[ops->currcon];
if (rotate < 4) if (rotate < 4)
p->con_rotate = rotate; p->con_rotate = rotate;
...@@ -235,7 +254,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) ...@@ -235,7 +254,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
{ {
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct vc_data *vc; struct vc_data *vc;
struct display *p; struct fbcon_display *p;
int i; int i;
if (!ops || ops->currcon < 0 || rotate > 3) if (!ops || ops->currcon < 0 || rotate > 3)
...@@ -900,7 +919,7 @@ static int set_con2fb_map(int unit, int newidx, int user) ...@@ -900,7 +919,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
* Low Level Operations * Low Level Operations
*/ */
/* NOTE: fbcon cannot be __init: it may be called from do_take_over_console later */ /* NOTE: fbcon cannot be __init: it may be called from do_take_over_console later */
static int var_to_display(struct display *disp, static int var_to_display(struct fbcon_display *disp,
struct fb_var_screeninfo *var, struct fb_var_screeninfo *var,
struct fb_info *info) struct fb_info *info)
{ {
...@@ -925,7 +944,7 @@ static int var_to_display(struct display *disp, ...@@ -925,7 +944,7 @@ static int var_to_display(struct display *disp,
} }
static void display_to_var(struct fb_var_screeninfo *var, static void display_to_var(struct fb_var_screeninfo *var,
struct display *disp) struct fbcon_display *disp)
{ {
fb_videomode_to_var(var, disp->mode); fb_videomode_to_var(var, disp->mode);
var->xres_virtual = disp->xres_virtual; var->xres_virtual = disp->xres_virtual;
...@@ -946,7 +965,7 @@ static void display_to_var(struct fb_var_screeninfo *var, ...@@ -946,7 +965,7 @@ static void display_to_var(struct fb_var_screeninfo *var,
static const char *fbcon_startup(void) static const char *fbcon_startup(void)
{ {
const char *display_desc = "frame buffer device"; const char *display_desc = "frame buffer device";
struct display *p = &fb_display[fg_console]; struct fbcon_display *p = &fb_display[fg_console];
struct vc_data *vc = vc_cons[fg_console].d; struct vc_data *vc = vc_cons[fg_console].d;
const struct font_desc *font = NULL; const struct font_desc *font = NULL;
struct module *owner; struct module *owner;
...@@ -1050,23 +1069,26 @@ static const char *fbcon_startup(void) ...@@ -1050,23 +1069,26 @@ static const char *fbcon_startup(void)
info->var.bits_per_pixel); info->var.bits_per_pixel);
fbcon_add_cursor_timer(info); fbcon_add_cursor_timer(info);
fbcon_has_exited = 0;
return display_desc; return display_desc;
} }
static void fbcon_init(struct vc_data *vc, int init) static void fbcon_init(struct vc_data *vc, int init)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info;
struct fbcon_ops *ops; struct fbcon_ops *ops;
struct vc_data **default_mode = vc->vc_display_fg; struct vc_data **default_mode = vc->vc_display_fg;
struct vc_data *svc = *default_mode; struct vc_data *svc = *default_mode;
struct display *t, *p = &fb_display[vc->vc_num]; struct fbcon_display *t, *p = &fb_display[vc->vc_num];
int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256; int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256;
int cap, ret; int cap, ret;
if (info_idx == -1 || info == NULL) if (WARN_ON(info_idx == -1))
return; return;
if (con2fb_map[vc->vc_num] == -1)
con2fb_map[vc->vc_num] = info_idx;
info = registered_fb[con2fb_map[vc->vc_num]];
cap = info->flags; cap = info->flags;
if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET) if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET)
...@@ -1203,7 +1225,7 @@ static void fbcon_init(struct vc_data *vc, int init) ...@@ -1203,7 +1225,7 @@ static void fbcon_init(struct vc_data *vc, int init)
ops->p = &fb_display[fg_console]; ops->p = &fb_display[fg_console];
} }
static void fbcon_free_font(struct display *p, bool freefont) static void fbcon_free_font(struct fbcon_display *p, bool freefont)
{ {
if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
...@@ -1215,7 +1237,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set); ...@@ -1215,7 +1237,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set);
static void fbcon_deinit(struct vc_data *vc) static void fbcon_deinit(struct vc_data *vc)
{ {
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
struct fb_info *info; struct fb_info *info;
struct fbcon_ops *ops; struct fbcon_ops *ops;
int idx; int idx;
...@@ -1288,7 +1310,7 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, ...@@ -1288,7 +1310,7 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
u_int y_break; u_int y_break;
if (fbcon_is_inactive(vc, info)) if (fbcon_is_inactive(vc, info))
...@@ -1324,7 +1346,7 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, ...@@ -1324,7 +1346,7 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
int count, int ypos, int xpos) int count, int ypos, int xpos)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
if (!fbcon_is_inactive(vc, info)) if (!fbcon_is_inactive(vc, info))
...@@ -1388,7 +1410,7 @@ static int scrollback_current = 0; ...@@ -1388,7 +1410,7 @@ static int scrollback_current = 0;
static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
int unit) int unit)
{ {
struct display *p, *t; struct fbcon_display *p, *t;
struct vc_data **default_mode, *vc; struct vc_data **default_mode, *vc;
struct vc_data *svc; struct vc_data *svc;
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
...@@ -1457,7 +1479,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) ...@@ -1457,7 +1479,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
p->yscroll += count; p->yscroll += count;
if (p->yscroll >= p->vrows) /* Deal with wrap */ if (p->yscroll >= p->vrows) /* Deal with wrap */
...@@ -1476,7 +1498,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count) ...@@ -1476,7 +1498,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
p->yscroll -= count; p->yscroll -= count;
if (p->yscroll < 0) /* Deal with wrap */ if (p->yscroll < 0) /* Deal with wrap */
...@@ -1494,7 +1516,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count) ...@@ -1494,7 +1516,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count)
static __inline__ void ypan_up(struct vc_data *vc, int count) static __inline__ void ypan_up(struct vc_data *vc, int count)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
p->yscroll += count; p->yscroll += count;
...@@ -1519,7 +1541,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) ...@@ -1519,7 +1541,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
p->yscroll += count; p->yscroll += count;
...@@ -1542,7 +1564,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) ...@@ -1542,7 +1564,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
static __inline__ void ypan_down(struct vc_data *vc, int count) static __inline__ void ypan_down(struct vc_data *vc, int count)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
p->yscroll -= count; p->yscroll -= count;
...@@ -1567,7 +1589,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) ...@@ -1567,7 +1589,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
p->yscroll -= count; p->yscroll -= count;
...@@ -1587,7 +1609,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) ...@@ -1587,7 +1609,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
scrollback_current = 0; scrollback_current = 0;
} }
static void fbcon_redraw_softback(struct vc_data *vc, struct display *p, static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
long delta) long delta)
{ {
int count = vc->vc_rows; int count = vc->vc_rows;
...@@ -1680,7 +1702,7 @@ static void fbcon_redraw_softback(struct vc_data *vc, struct display *p, ...@@ -1680,7 +1702,7 @@ static void fbcon_redraw_softback(struct vc_data *vc, struct display *p,
} }
} }
static void fbcon_redraw_move(struct vc_data *vc, struct display *p, static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
int line, int count, int dy) int line, int count, int dy)
{ {
unsigned short *s = (unsigned short *) unsigned short *s = (unsigned short *)
...@@ -1715,7 +1737,7 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p, ...@@ -1715,7 +1737,7 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
} }
static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
struct display *p, int line, int count, int ycount) struct fbcon_display *p, int line, int count, int ycount)
{ {
int offset = ycount * vc->vc_cols; int offset = ycount * vc->vc_cols;
unsigned short *d = (unsigned short *) unsigned short *d = (unsigned short *)
...@@ -1764,7 +1786,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, ...@@ -1764,7 +1786,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
} }
} }
static void fbcon_redraw(struct vc_data *vc, struct display *p, static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
int line, int count, int offset) int line, int count, int offset)
{ {
unsigned short *d = (unsigned short *) unsigned short *d = (unsigned short *)
...@@ -1848,7 +1870,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, ...@@ -1848,7 +1870,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
enum con_scroll dir, unsigned int count) enum con_scroll dir, unsigned int count)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
if (fbcon_is_inactive(vc, info)) if (fbcon_is_inactive(vc, info))
...@@ -2052,7 +2074,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, ...@@ -2052,7 +2074,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
int height, int width) int height, int width)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
if (fbcon_is_inactive(vc, info)) if (fbcon_is_inactive(vc, info))
return; return;
...@@ -2071,7 +2093,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, ...@@ -2071,7 +2093,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
p->vrows - p->yscroll); p->vrows - p->yscroll);
} }
static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
int dy, int dx, int height, int width, u_int y_break) int dy, int dx, int height, int width, u_int y_break)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
...@@ -2113,7 +2135,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s ...@@ -2113,7 +2135,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s
height, width); height, width);
} }
static void updatescrollmode(struct display *p, static void updatescrollmode(struct fbcon_display *p,
struct fb_info *info, struct fb_info *info,
struct vc_data *vc) struct vc_data *vc)
{ {
...@@ -2165,7 +2187,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, ...@@ -2165,7 +2187,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
struct fb_var_screeninfo var = info->var; struct fb_var_screeninfo var = info->var;
int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
...@@ -2210,7 +2232,7 @@ static int fbcon_switch(struct vc_data *vc) ...@@ -2210,7 +2232,7 @@ static int fbcon_switch(struct vc_data *vc)
{ {
struct fb_info *info, *old_info = NULL; struct fb_info *info, *old_info = NULL;
struct fbcon_ops *ops; struct fbcon_ops *ops;
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
struct fb_var_screeninfo var; struct fb_var_screeninfo var;
int i, ret, prev_console, charcnt = 256; int i, ret, prev_console, charcnt = 256;
...@@ -2348,8 +2370,6 @@ static int fbcon_switch(struct vc_data *vc) ...@@ -2348,8 +2370,6 @@ static int fbcon_switch(struct vc_data *vc)
static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
int blank) int blank)
{ {
struct fb_event event;
if (blank) { if (blank) {
unsigned short charmask = vc->vc_hi_font_mask ? unsigned short charmask = vc->vc_hi_font_mask ?
0x1ff : 0xff; 0x1ff : 0xff;
...@@ -2360,14 +2380,6 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, ...@@ -2360,14 +2380,6 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
vc->vc_video_erase_char = oldc; vc->vc_video_erase_char = oldc;
} }
if (!lock_fb_info(info))
return;
event.info = info;
event.data = &blank;
fb_notifier_call_chain(FB_EVENT_CONBLANK, &event);
unlock_fb_info(info);
} }
static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
...@@ -2394,9 +2406,8 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) ...@@ -2394,9 +2406,8 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
ops->cursor_flash = (!blank); ops->cursor_flash = (!blank);
if (!(info->flags & FBINFO_MISC_USEREVENT)) if (fb_blank(info, blank))
if (fb_blank(info, blank)) fbcon_generic_blank(vc, info, blank);
fbcon_generic_blank(vc, info, blank);
} }
if (!blank) if (!blank)
...@@ -2553,7 +2564,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, ...@@ -2553,7 +2564,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
int resize; int resize;
int cnt; int cnt;
char *old_data = NULL; char *old_data = NULL;
...@@ -2601,7 +2612,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, ...@@ -2601,7 +2612,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
static int fbcon_copy_font(struct vc_data *vc, int con) static int fbcon_copy_font(struct vc_data *vc, int con)
{ {
struct display *od = &fb_display[con]; struct fbcon_display *od = &fb_display[con];
struct console_font *f = &vc->vc_font; struct console_font *f = &vc->vc_font;
if (od->fontdata == f->data) if (od->fontdata == f->data)
...@@ -2826,7 +2837,7 @@ static void fbcon_scrolldelta(struct vc_data *vc, int lines) ...@@ -2826,7 +2837,7 @@ static void fbcon_scrolldelta(struct vc_data *vc, int lines)
{ {
struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fb_info *info = registered_fb[con2fb_map[fg_console]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct display *disp = &fb_display[fg_console]; struct fbcon_display *disp = &fb_display[fg_console];
int offset, limit, scrollback_old; int offset, limit, scrollback_old;
if (softback_top) { if (softback_top) {
...@@ -2918,7 +2929,7 @@ static int fbcon_set_origin(struct vc_data *vc) ...@@ -2918,7 +2929,7 @@ static int fbcon_set_origin(struct vc_data *vc)
return 0; return 0;
} }
static void fbcon_suspended(struct fb_info *info) void fbcon_suspended(struct fb_info *info)
{ {
struct vc_data *vc = NULL; struct vc_data *vc = NULL;
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
...@@ -2931,7 +2942,7 @@ static void fbcon_suspended(struct fb_info *info) ...@@ -2931,7 +2942,7 @@ static void fbcon_suspended(struct fb_info *info)
fbcon_cursor(vc, CM_ERASE); fbcon_cursor(vc, CM_ERASE);
} }
static void fbcon_resumed(struct fb_info *info) void fbcon_resumed(struct fb_info *info)
{ {
struct vc_data *vc; struct vc_data *vc;
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
...@@ -2947,7 +2958,7 @@ static void fbcon_modechanged(struct fb_info *info) ...@@ -2947,7 +2958,7 @@ static void fbcon_modechanged(struct fb_info *info)
{ {
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct vc_data *vc; struct vc_data *vc;
struct display *p; struct fbcon_display *p;
int rows, cols; int rows, cols;
if (!ops || ops->currcon < 0) if (!ops || ops->currcon < 0)
...@@ -2987,7 +2998,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) ...@@ -2987,7 +2998,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
{ {
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct vc_data *vc; struct vc_data *vc;
struct display *p; struct fbcon_display *p;
int i, rows, cols, fg = -1; int i, rows, cols, fg = -1;
if (!ops || ops->currcon < 0) if (!ops || ops->currcon < 0)
...@@ -3018,11 +3029,21 @@ static void fbcon_set_all_vcs(struct fb_info *info) ...@@ -3018,11 +3029,21 @@ static void fbcon_set_all_vcs(struct fb_info *info)
fbcon_modechanged(info); fbcon_modechanged(info);
} }
static int fbcon_mode_deleted(struct fb_info *info,
struct fb_videomode *mode) void fbcon_update_vcs(struct fb_info *info, bool all)
{
if (all)
fbcon_set_all_vcs(info);
else
fbcon_modechanged(info);
}
EXPORT_SYMBOL(fbcon_update_vcs);
int fbcon_mode_deleted(struct fb_info *info,
struct fb_videomode *mode)
{ {
struct fb_info *fb_info; struct fb_info *fb_info;
struct display *p; struct fbcon_display *p;
int i, j, found = 0; int i, j, found = 0;
/* before deletion, ensure that mode is not in use */ /* before deletion, ensure that mode is not in use */
...@@ -3045,7 +3066,7 @@ static int fbcon_mode_deleted(struct fb_info *info, ...@@ -3045,7 +3066,7 @@ static int fbcon_mode_deleted(struct fb_info *info,
} }
#ifdef CONFIG_VT_HW_CONSOLE_BINDING #ifdef CONFIG_VT_HW_CONSOLE_BINDING
static int fbcon_unbind(void) static void fbcon_unbind(void)
{ {
int ret; int ret;
...@@ -3054,25 +3075,21 @@ static int fbcon_unbind(void) ...@@ -3054,25 +3075,21 @@ static int fbcon_unbind(void)
if (!ret) if (!ret)
fbcon_has_console_bind = 0; fbcon_has_console_bind = 0;
return ret;
} }
#else #else
static inline int fbcon_unbind(void) static inline void fbcon_unbind(void) {}
{
return -EINVAL;
}
#endif /* CONFIG_VT_HW_CONSOLE_BINDING */ #endif /* CONFIG_VT_HW_CONSOLE_BINDING */
/* called with console_lock held */ /* called with console_lock held */
static int fbcon_fb_unbind(int idx) void fbcon_fb_unbind(struct fb_info *info)
{ {
int i, new_idx = -1, ret = 0; int i, new_idx = -1, ret = 0;
int idx = info->node;
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
if (!fbcon_has_console_bind) if (!fbcon_has_console_bind)
return 0; return;
for (i = first_fb_vc; i <= last_fb_vc; i++) { for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] != idx && if (con2fb_map[i] != idx &&
...@@ -3105,26 +3122,24 @@ static int fbcon_fb_unbind(int idx) ...@@ -3105,26 +3122,24 @@ static int fbcon_fb_unbind(int idx)
idx, 0); idx, 0);
if (ret) { if (ret) {
con2fb_map[i] = idx; con2fb_map[i] = idx;
return ret; return;
} }
} }
} }
} }
ret = fbcon_unbind(); fbcon_unbind();
} }
return ret;
} }
/* called with console_lock held */ /* called with console_lock held */
static int fbcon_fb_unregistered(struct fb_info *info) void fbcon_fb_unregistered(struct fb_info *info)
{ {
int i, idx; int i, idx;
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
if (deferred_takeover) if (deferred_takeover)
return 0; return;
idx = info->node; idx = info->node;
for (i = first_fb_vc; i <= last_fb_vc; i++) { for (i = first_fb_vc; i <= last_fb_vc; i++) {
...@@ -3153,21 +3168,18 @@ static int fbcon_fb_unregistered(struct fb_info *info) ...@@ -3153,21 +3168,18 @@ static int fbcon_fb_unregistered(struct fb_info *info)
if (!num_registered_fb) if (!num_registered_fb)
do_unregister_con_driver(&fb_con); do_unregister_con_driver(&fb_con);
return 0;
} }
/* called with console_lock held */ void fbcon_remap_all(struct fb_info *info)
static void fbcon_remap_all(int idx)
{ {
int i; int i, idx = info->node;
WARN_CONSOLE_UNLOCKED();
console_lock();
if (deferred_takeover) { if (deferred_takeover) {
for (i = first_fb_vc; i <= last_fb_vc; i++) for (i = first_fb_vc; i <= last_fb_vc; i++)
con2fb_map_boot[i] = idx; con2fb_map_boot[i] = idx;
fbcon_map_override(); fbcon_map_override();
console_unlock();
return; return;
} }
...@@ -3180,6 +3192,7 @@ static void fbcon_remap_all(int idx) ...@@ -3180,6 +3192,7 @@ static void fbcon_remap_all(int idx)
first_fb_vc + 1, last_fb_vc + 1); first_fb_vc + 1, last_fb_vc + 1);
info_idx = idx; info_idx = idx;
} }
console_unlock();
} }
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
...@@ -3213,7 +3226,7 @@ static inline void fbcon_select_primary(struct fb_info *info) ...@@ -3213,7 +3226,7 @@ static inline void fbcon_select_primary(struct fb_info *info)
#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
/* called with console_lock held */ /* called with console_lock held */
static int fbcon_fb_registered(struct fb_info *info) int fbcon_fb_registered(struct fb_info *info)
{ {
int ret = 0, i, idx; int ret = 0, i, idx;
...@@ -3247,7 +3260,7 @@ static int fbcon_fb_registered(struct fb_info *info) ...@@ -3247,7 +3260,7 @@ static int fbcon_fb_registered(struct fb_info *info)
return ret; return ret;
} }
static void fbcon_fb_blanked(struct fb_info *info, int blank) void fbcon_fb_blanked(struct fb_info *info, int blank)
{ {
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct vc_data *vc; struct vc_data *vc;
...@@ -3269,7 +3282,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank) ...@@ -3269,7 +3282,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank)
ops->blank_state = blank; ops->blank_state = blank;
} }
static void fbcon_new_modelist(struct fb_info *info) void fbcon_new_modelist(struct fb_info *info)
{ {
int i; int i;
struct vc_data *vc; struct vc_data *vc;
...@@ -3290,11 +3303,11 @@ static void fbcon_new_modelist(struct fb_info *info) ...@@ -3290,11 +3303,11 @@ static void fbcon_new_modelist(struct fb_info *info)
} }
} }
static void fbcon_get_requirement(struct fb_info *info, void fbcon_get_requirement(struct fb_info *info,
struct fb_blit_caps *caps) struct fb_blit_caps *caps)
{ {
struct vc_data *vc; struct vc_data *vc;
struct display *p; struct fbcon_display *p;
if (caps->flags) { if (caps->flags) {
int i, charcnt; int i, charcnt;
...@@ -3326,80 +3339,47 @@ static void fbcon_get_requirement(struct fb_info *info, ...@@ -3326,80 +3339,47 @@ static void fbcon_get_requirement(struct fb_info *info,
} }
} }
static int fbcon_event_notify(struct notifier_block *self, int fbcon_set_con2fb_map_ioctl(void __user *argp)
unsigned long action, void *data)
{ {
struct fb_event *event = data; struct fb_con2fbmap con2fb;
struct fb_info *info = event->info; int ret;
struct fb_videomode *mode;
struct fb_con2fbmap *con2fb;
struct fb_blit_caps *caps;
int idx, ret = 0;
/*
* ignore all events except driver registration and deregistration
* if fbcon is not active
*/
if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED ||
action == FB_EVENT_FB_UNREGISTERED))
goto done;
switch(action) { if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
case FB_EVENT_SUSPEND: return -EFAULT;
fbcon_suspended(info); if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
break; return -EINVAL;
case FB_EVENT_RESUME: if (con2fb.framebuffer >= FB_MAX)
fbcon_resumed(info); return -EINVAL;
break; if (!registered_fb[con2fb.framebuffer])
case FB_EVENT_MODE_CHANGE: request_module("fb%d", con2fb.framebuffer);
fbcon_modechanged(info); if (!registered_fb[con2fb.framebuffer]) {
break; return -EINVAL;
case FB_EVENT_MODE_CHANGE_ALL:
fbcon_set_all_vcs(info);
break;
case FB_EVENT_MODE_DELETE:
mode = event->data;
ret = fbcon_mode_deleted(info, mode);
break;
case FB_EVENT_FB_UNBIND:
idx = info->node;
ret = fbcon_fb_unbind(idx);
break;
case FB_EVENT_FB_REGISTERED:
ret = fbcon_fb_registered(info);
break;
case FB_EVENT_FB_UNREGISTERED:
ret = fbcon_fb_unregistered(info);
break;
case FB_EVENT_SET_CONSOLE_MAP:
/* called with console lock held */
con2fb = event->data;
ret = set_con2fb_map(con2fb->console - 1,
con2fb->framebuffer, 1);
break;
case FB_EVENT_GET_CONSOLE_MAP:
con2fb = event->data;
con2fb->framebuffer = con2fb_map[con2fb->console - 1];
break;
case FB_EVENT_BLANK:
fbcon_fb_blanked(info, *(int *)event->data);
break;
case FB_EVENT_NEW_MODELIST:
fbcon_new_modelist(info);
break;
case FB_EVENT_GET_REQ:
caps = event->data;
fbcon_get_requirement(info, caps);
break;
case FB_EVENT_REMAP_ALL_CONSOLE:
idx = info->node;
fbcon_remap_all(idx);
break;
} }
done:
console_lock();
ret = set_con2fb_map(con2fb.console - 1,
con2fb.framebuffer, 1);
console_unlock();
return ret; return ret;
} }
int fbcon_get_con2fb_map_ioctl(void __user *argp)
{
struct fb_con2fbmap con2fb;
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
return -EFAULT;
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
console_lock();
con2fb.framebuffer = con2fb_map[con2fb.console - 1];
console_unlock();
return copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
}
/* /*
* The console `switch' structure for the frame buffer based console * The console `switch' structure for the frame buffer based console
*/ */
...@@ -3431,10 +3411,6 @@ static const struct consw fb_con = { ...@@ -3431,10 +3411,6 @@ static const struct consw fb_con = {
.con_debug_leave = fbcon_debug_leave, .con_debug_leave = fbcon_debug_leave,
}; };
static struct notifier_block fbcon_event_notifier = {
.notifier_call = fbcon_event_notify,
};
static ssize_t store_rotate(struct device *device, static ssize_t store_rotate(struct device *device,
struct device_attribute *attr, const char *buf, struct device_attribute *attr, const char *buf,
size_t count) size_t count)
...@@ -3443,9 +3419,6 @@ static ssize_t store_rotate(struct device *device, ...@@ -3443,9 +3419,6 @@ static ssize_t store_rotate(struct device *device,
int rotate, idx; int rotate, idx;
char **last = NULL; char **last = NULL;
if (fbcon_has_exited)
return count;
console_lock(); console_lock();
idx = con2fb_map[fg_console]; idx = con2fb_map[fg_console];
...@@ -3468,9 +3441,6 @@ static ssize_t store_rotate_all(struct device *device, ...@@ -3468,9 +3441,6 @@ static ssize_t store_rotate_all(struct device *device,
int rotate, idx; int rotate, idx;
char **last = NULL; char **last = NULL;
if (fbcon_has_exited)
return count;
console_lock(); console_lock();
idx = con2fb_map[fg_console]; idx = con2fb_map[fg_console];
...@@ -3491,9 +3461,6 @@ static ssize_t show_rotate(struct device *device, ...@@ -3491,9 +3461,6 @@ static ssize_t show_rotate(struct device *device,
struct fb_info *info; struct fb_info *info;
int rotate = 0, idx; int rotate = 0, idx;
if (fbcon_has_exited)
return 0;
console_lock(); console_lock();
idx = con2fb_map[fg_console]; idx = con2fb_map[fg_console];
...@@ -3514,9 +3481,6 @@ static ssize_t show_cursor_blink(struct device *device, ...@@ -3514,9 +3481,6 @@ static ssize_t show_cursor_blink(struct device *device,
struct fbcon_ops *ops; struct fbcon_ops *ops;
int idx, blink = -1; int idx, blink = -1;
if (fbcon_has_exited)
return 0;
console_lock(); console_lock();
idx = con2fb_map[fg_console]; idx = con2fb_map[fg_console];
...@@ -3543,9 +3507,6 @@ static ssize_t store_cursor_blink(struct device *device, ...@@ -3543,9 +3507,6 @@ static ssize_t store_cursor_blink(struct device *device,
int blink, idx; int blink, idx;
char **last = NULL; char **last = NULL;
if (fbcon_has_exited)
return count;
console_lock(); console_lock();
idx = con2fb_map[fg_console]; idx = con2fb_map[fg_console];
...@@ -3668,9 +3629,6 @@ static void fbcon_exit(void) ...@@ -3668,9 +3629,6 @@ static void fbcon_exit(void)
struct fb_info *info; struct fb_info *info;
int i, j, mapped; int i, j, mapped;
if (fbcon_has_exited)
return;
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
if (deferred_takeover) { if (deferred_takeover) {
dummycon_unregister_output_notifier(&fbcon_output_nb); dummycon_unregister_output_notifier(&fbcon_output_nb);
...@@ -3695,7 +3653,7 @@ static void fbcon_exit(void) ...@@ -3695,7 +3653,7 @@ static void fbcon_exit(void)
for (j = first_fb_vc; j <= last_fb_vc; j++) { for (j = first_fb_vc; j <= last_fb_vc; j++) {
if (con2fb_map[j] == i) { if (con2fb_map[j] == i) {
mapped = 1; mapped = 1;
break; con2fb_map[j] = -1;
} }
} }
...@@ -3718,8 +3676,6 @@ static void fbcon_exit(void) ...@@ -3718,8 +3676,6 @@ static void fbcon_exit(void)
info->queue.func = NULL; info->queue.func = NULL;
} }
} }
fbcon_has_exited = 1;
} }
void __init fb_console_init(void) void __init fb_console_init(void)
...@@ -3727,7 +3683,6 @@ void __init fb_console_init(void) ...@@ -3727,7 +3683,6 @@ void __init fb_console_init(void)
int i; int i;
console_lock(); console_lock();
fb_register_client(&fbcon_event_notifier);
fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL, fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL,
"fbcon"); "fbcon");
...@@ -3763,7 +3718,6 @@ static void __exit fbcon_deinit_device(void) ...@@ -3763,7 +3718,6 @@ static void __exit fbcon_deinit_device(void)
void __exit fb_console_exit(void) void __exit fb_console_exit(void)
{ {
console_lock(); console_lock();
fb_unregister_client(&fbcon_event_notifier);
fbcon_deinit_device(); fbcon_deinit_device();
device_destroy(fb_class, MKDEV(0, 0)); device_destroy(fb_class, MKDEV(0, 0));
fbcon_exit(); fbcon_exit();
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
* low-level frame buffer device * low-level frame buffer device
*/ */
struct display { struct fbcon_display {
/* Filled in by the low-level console driver */ /* Filled in by the low-level console driver */
const u_char *fontdata; const u_char *fontdata;
int userfont; /* != 0 if fontdata kmalloc()ed */ int userfont; /* != 0 if fontdata kmalloc()ed */
...@@ -68,7 +68,7 @@ struct fbcon_ops { ...@@ -68,7 +68,7 @@ struct fbcon_ops {
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
struct timer_list cursor_timer; /* Cursor timer */ struct timer_list cursor_timer; /* Cursor timer */
struct fb_cursor cursor_state; struct fb_cursor cursor_state;
struct display *p; struct fbcon_display *p;
struct fb_info *info; struct fb_info *info;
int currcon; /* Current VC. */ int currcon; /* Current VC. */
int cur_blink_jiffies; int cur_blink_jiffies;
...@@ -225,7 +225,7 @@ extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); ...@@ -225,7 +225,7 @@ extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
#define FBCON_ATTRIBUTE_REVERSE 2 #define FBCON_ATTRIBUTE_REVERSE 2
#define FBCON_ATTRIBUTE_BOLD 4 #define FBCON_ATTRIBUTE_BOLD 4
static inline int real_y(struct display *p, int ypos) static inline int real_y(struct fbcon_display *p, int ypos)
{ {
int rows = p->vrows; int rows = p->vrows;
......
...@@ -80,17 +80,6 @@ static void put_fb_info(struct fb_info *fb_info) ...@@ -80,17 +80,6 @@ static void put_fb_info(struct fb_info *fb_info)
fb_info->fbops->fb_destroy(fb_info); fb_info->fbops->fb_destroy(fb_info);
} }
int lock_fb_info(struct fb_info *info)
{
mutex_lock(&info->lock);
if (!info->fbops) {
mutex_unlock(&info->lock);
return 0;
}
return 1;
}
EXPORT_SYMBOL(lock_fb_info);
/* /*
* Helpers * Helpers
*/ */
...@@ -943,16 +932,13 @@ EXPORT_SYMBOL(fb_pan_display); ...@@ -943,16 +932,13 @@ EXPORT_SYMBOL(fb_pan_display);
static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
u32 activate) u32 activate)
{ {
struct fb_event event;
struct fb_blit_caps caps, fbcaps; struct fb_blit_caps caps, fbcaps;
int err = 0; int err = 0;
memset(&caps, 0, sizeof(caps)); memset(&caps, 0, sizeof(caps));
memset(&fbcaps, 0, sizeof(fbcaps)); memset(&fbcaps, 0, sizeof(fbcaps));
caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
event.info = info; fbcon_get_requirement(info, &caps);
event.data = &caps;
fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
info->fbops->fb_get_caps(info, &fbcaps, var); info->fbops->fb_get_caps(info, &fbcaps, var);
if (((fbcaps.x ^ caps.x) & caps.x) || if (((fbcaps.x ^ caps.x) & caps.x) ||
...@@ -968,6 +954,10 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -968,6 +954,10 @@ 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;
struct fb_event event;
if (var->activate & FB_ACTIVATE_INV_MODE) { if (var->activate & FB_ACTIVATE_INV_MODE) {
struct fb_videomode mode1, mode2; struct fb_videomode mode1, mode2;
...@@ -977,100 +967,90 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -977,100 +967,90 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
/* make sure we don't delete the videomode of current var */ /* make sure we don't delete the videomode of current var */
ret = fb_mode_is_equal(&mode1, &mode2); ret = fb_mode_is_equal(&mode1, &mode2);
if (!ret) { if (!ret)
struct fb_event event; fbcon_mode_deleted(info, &mode1);
event.info = info;
event.data = &mode1;
ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
}
if (!ret) if (!ret)
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, "
"error code: %d\n", ret);
goto done;
}
}
fb_pan_display(info, &info->var); if (ret) {
fb_set_cmap(&info->cmap, info); info->var = old_var;
fb_var_to_videomode(&mode, &info->var); printk(KERN_WARNING "detected "
"fb_set_par error, "
"error code: %d\n", ret);
return ret;
}
}
if (info->modelist.prev && info->modelist.next && fb_pan_display(info, &info->var);
!list_empty(&info->modelist)) fb_set_cmap(&info->cmap, info);
ret = fb_add_videomode(&mode, &info->modelist); fb_var_to_videomode(&mode, &info->var);
if (!ret && (flags & FBINFO_MISC_USEREVENT)) { if (info->modelist.prev && info->modelist.next &&
struct fb_event event; !list_empty(&info->modelist))
int evnt = (activate & FB_ACTIVATE_ALL) ? ret = fb_add_videomode(&mode, &info->modelist);
FB_EVENT_MODE_CHANGE_ALL :
FB_EVENT_MODE_CHANGE;
info->flags &= ~FBINFO_MISC_USEREVENT; if (ret)
event.info = info; return ret;
event.data = &mode;
fb_notifier_call_chain(evnt, &event);
}
}
}
done: event.info = info;
return ret; event.data = &mode;
fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event);
if (flags & FBINFO_MISC_USEREVENT)
fbcon_update_vcs(info, activate & FB_ACTIVATE_ALL);
return 0;
} }
EXPORT_SYMBOL(fb_set_var); EXPORT_SYMBOL(fb_set_var);
...@@ -1112,17 +1092,14 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -1112,17 +1092,14 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
struct fb_ops *fb; struct fb_ops *fb;
struct fb_var_screeninfo var; struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix; struct fb_fix_screeninfo fix;
struct fb_con2fbmap con2fb;
struct fb_cmap cmap_from; struct fb_cmap cmap_from;
struct fb_cmap_user cmap; struct fb_cmap_user cmap;
struct fb_event event;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
long ret = 0; long ret = 0;
switch (cmd) { switch (cmd) {
case FBIOGET_VSCREENINFO: case FBIOGET_VSCREENINFO:
if (!lock_fb_info(info)) lock_fb_info(info);
return -ENODEV;
var = info->var; var = info->var;
unlock_fb_info(info); unlock_fb_info(info);
...@@ -1132,10 +1109,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -1132,10 +1109,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
if (copy_from_user(&var, argp, sizeof(var))) if (copy_from_user(&var, argp, sizeof(var)))
return -EFAULT; return -EFAULT;
console_lock(); console_lock();
if (!lock_fb_info(info)) { lock_fb_info(info);
console_unlock();
return -ENODEV;
}
info->flags |= FBINFO_MISC_USEREVENT; info->flags |= FBINFO_MISC_USEREVENT;
ret = fb_set_var(info, &var); ret = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_USEREVENT; info->flags &= ~FBINFO_MISC_USEREVENT;
...@@ -1145,8 +1119,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -1145,8 +1119,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
ret = -EFAULT; ret = -EFAULT;
break; break;
case FBIOGET_FSCREENINFO: case FBIOGET_FSCREENINFO:
if (!lock_fb_info(info)) lock_fb_info(info);
return -ENODEV;
fix = info->fix; fix = info->fix;
if (info->flags & FBINFO_HIDE_SMEM_START) if (info->flags & FBINFO_HIDE_SMEM_START)
fix.smem_start = 0; fix.smem_start = 0;
...@@ -1162,8 +1135,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -1162,8 +1135,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
case FBIOGETCMAP: case FBIOGETCMAP:
if (copy_from_user(&cmap, argp, sizeof(cmap))) if (copy_from_user(&cmap, argp, sizeof(cmap)))
return -EFAULT; return -EFAULT;
if (!lock_fb_info(info)) lock_fb_info(info);
return -ENODEV;
cmap_from = info->cmap; cmap_from = info->cmap;
unlock_fb_info(info); unlock_fb_info(info);
ret = fb_cmap_to_user(&cmap_from, &cmap); ret = fb_cmap_to_user(&cmap_from, &cmap);
...@@ -1172,10 +1144,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -1172,10 +1144,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
if (copy_from_user(&var, argp, sizeof(var))) if (copy_from_user(&var, argp, sizeof(var)))
return -EFAULT; return -EFAULT;
console_lock(); console_lock();
if (!lock_fb_info(info)) { lock_fb_info(info);
console_unlock();
return -ENODEV;
}
ret = fb_pan_display(info, &var); ret = fb_pan_display(info, &var);
unlock_fb_info(info); unlock_fb_info(info);
console_unlock(); console_unlock();
...@@ -1186,58 +1155,22 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -1186,58 +1155,22 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
ret = -EINVAL; ret = -EINVAL;
break; break;
case FBIOGET_CON2FBMAP: case FBIOGET_CON2FBMAP:
if (copy_from_user(&con2fb, argp, sizeof(con2fb))) ret = fbcon_get_con2fb_map_ioctl(argp);
return -EFAULT;
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
con2fb.framebuffer = -1;
event.data = &con2fb;
if (!lock_fb_info(info))
return -ENODEV;
event.info = info;
fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
unlock_fb_info(info);
ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
break; break;
case FBIOPUT_CON2FBMAP: case FBIOPUT_CON2FBMAP:
if (copy_from_user(&con2fb, argp, sizeof(con2fb))) ret = fbcon_set_con2fb_map_ioctl(argp);
return -EFAULT;
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
if (con2fb.framebuffer >= FB_MAX)
return -EINVAL;
if (!registered_fb[con2fb.framebuffer])
request_module("fb%d", con2fb.framebuffer);
if (!registered_fb[con2fb.framebuffer]) {
ret = -EINVAL;
break;
}
event.data = &con2fb;
console_lock();
if (!lock_fb_info(info)) {
console_unlock();
return -ENODEV;
}
event.info = info;
ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
unlock_fb_info(info);
console_unlock();
break; break;
case FBIOBLANK: case FBIOBLANK:
console_lock(); console_lock();
if (!lock_fb_info(info)) { lock_fb_info(info);
console_unlock();
return -ENODEV;
}
info->flags |= FBINFO_MISC_USEREVENT;
ret = fb_blank(info, arg); ret = fb_blank(info, arg);
info->flags &= ~FBINFO_MISC_USEREVENT; /* might again call into fb_blank */
fbcon_fb_blanked(info, arg);
unlock_fb_info(info); unlock_fb_info(info);
console_unlock(); console_unlock();
break; break;
default: default:
if (!lock_fb_info(info)) lock_fb_info(info);
return -ENODEV;
fb = info->fbops; fb = info->fbops;
if (fb->fb_ioctl) if (fb->fb_ioctl)
ret = fb->fb_ioctl(info, cmd, arg); ret = fb->fb_ioctl(info, cmd, arg);
...@@ -1357,8 +1290,7 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, ...@@ -1357,8 +1290,7 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
{ {
struct fb_fix_screeninfo fix; struct fb_fix_screeninfo fix;
if (!lock_fb_info(info)) lock_fb_info(info);
return -ENODEV;
fix = info->fix; fix = info->fix;
if (info->flags & FBINFO_HIDE_SMEM_START) if (info->flags & FBINFO_HIDE_SMEM_START)
fix.smem_start = 0; fix.smem_start = 0;
...@@ -1418,8 +1350,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) ...@@ -1418,8 +1350,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
if (!info) if (!info)
return -ENODEV; return -ENODEV;
fb = info->fbops; fb = info->fbops;
if (!fb)
return -ENODEV;
mutex_lock(&info->mm_lock); mutex_lock(&info->mm_lock);
if (fb->fb_mmap) { if (fb->fb_mmap) {
int res; int res;
...@@ -1483,7 +1413,7 @@ __releases(&info->lock) ...@@ -1483,7 +1413,7 @@ __releases(&info->lock)
if (IS_ERR(info)) if (IS_ERR(info))
return PTR_ERR(info); return PTR_ERR(info);
mutex_lock(&info->lock); lock_fb_info(info);
if (!try_module_get(info->fbops->owner)) { if (!try_module_get(info->fbops->owner)) {
res = -ENODEV; res = -ENODEV;
goto out; goto out;
...@@ -1499,7 +1429,7 @@ __releases(&info->lock) ...@@ -1499,7 +1429,7 @@ __releases(&info->lock)
fb_deferred_io_open(info, inode, file); fb_deferred_io_open(info, inode, file);
#endif #endif
out: out:
mutex_unlock(&info->lock); unlock_fb_info(info);
if (res) if (res)
put_fb_info(info); put_fb_info(info);
return res; return res;
...@@ -1512,11 +1442,11 @@ __releases(&info->lock) ...@@ -1512,11 +1442,11 @@ __releases(&info->lock)
{ {
struct fb_info * const info = file->private_data; struct fb_info * const info = file->private_data;
mutex_lock(&info->lock); lock_fb_info(info);
if (info->fbops->fb_release) if (info->fbops->fb_release)
info->fbops->fb_release(info,1); info->fbops->fb_release(info,1);
module_put(info->fbops->owner); module_put(info->fbops->owner);
mutex_unlock(&info->lock); unlock_fb_info(info);
put_fb_info(info); put_fb_info(info);
return 0; return 0;
} }
...@@ -1621,13 +1551,13 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, ...@@ -1621,13 +1551,13 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena,
return false; return false;
} }
static int do_unregister_framebuffer(struct fb_info *fb_info); static void do_unregister_framebuffer(struct fb_info *fb_info);
#define VGA_FB_PHYS 0xA0000 #define VGA_FB_PHYS 0xA0000
static int do_remove_conflicting_framebuffers(struct apertures_struct *a, static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
const char *name, bool primary) const char *name, bool primary)
{ {
int i, ret; int i;
/* check all firmware fbs and kick off if the base addr overlaps */ /* check all firmware fbs and kick off if the base addr overlaps */
for_each_registered_fb(i) { for_each_registered_fb(i) {
...@@ -1643,13 +1573,9 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a, ...@@ -1643,13 +1573,9 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
printk(KERN_INFO "fb%d: switching to %s from %s\n", printk(KERN_INFO "fb%d: switching to %s from %s\n",
i, name, registered_fb[i]->fix.id); i, name, registered_fb[i]->fix.id);
ret = do_unregister_framebuffer(registered_fb[i]); do_unregister_framebuffer(registered_fb[i]);
if (ret)
return ret;
} }
} }
return 0;
} }
static bool lockless_register_fb; static bool lockless_register_fb;
...@@ -1660,17 +1586,14 @@ MODULE_PARM_DESC(lockless_register_fb, ...@@ -1660,17 +1586,14 @@ MODULE_PARM_DESC(lockless_register_fb,
static int do_register_framebuffer(struct fb_info *fb_info) static int do_register_framebuffer(struct fb_info *fb_info)
{ {
int i, ret; int i, ret;
struct fb_event event;
struct fb_videomode mode; struct fb_videomode mode;
if (fb_check_foreignness(fb_info)) if (fb_check_foreignness(fb_info))
return -ENOSYS; return -ENOSYS;
ret = do_remove_conflicting_framebuffers(fb_info->apertures, do_remove_conflicting_framebuffers(fb_info->apertures,
fb_info->fix.id, fb_info->fix.id,
fb_is_primary_device(fb_info)); fb_is_primary_device(fb_info));
if (ret)
return ret;
if (num_registered_fb == FB_MAX) if (num_registered_fb == FB_MAX)
return -ENXIO; return -ENXIO;
...@@ -1723,20 +1646,22 @@ static int do_register_framebuffer(struct fb_info *fb_info) ...@@ -1723,20 +1646,22 @@ static int do_register_framebuffer(struct fb_info *fb_info)
fb_add_videomode(&mode, &fb_info->modelist); fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info; registered_fb[i] = fb_info;
event.info = fb_info; #ifdef CONFIG_GUMSTIX_AM200EPD
{
struct fb_event event;
event.info = fb_info;
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
}
#endif
if (!lockless_register_fb) if (!lockless_register_fb)
console_lock(); console_lock();
else else
atomic_inc(&ignore_console_lock_warning); atomic_inc(&ignore_console_lock_warning);
if (!lock_fb_info(fb_info)) { lock_fb_info(fb_info);
ret = -ENODEV; ret = fbcon_fb_registered(fb_info);
goto unlock_console;
}
ret = 0;
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
unlock_fb_info(fb_info); unlock_fb_info(fb_info);
unlock_console:
if (!lockless_register_fb) if (!lockless_register_fb)
console_unlock(); console_unlock();
else else
...@@ -1744,44 +1669,44 @@ static int do_register_framebuffer(struct fb_info *fb_info) ...@@ -1744,44 +1669,44 @@ static int do_register_framebuffer(struct fb_info *fb_info)
return ret; return ret;
} }
static int unbind_console(struct fb_info *fb_info) static void unbind_console(struct fb_info *fb_info)
{ {
struct fb_event event;
int ret;
int i = fb_info->node; int i = fb_info->node;
if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
return -EINVAL; return;
console_lock(); console_lock();
if (!lock_fb_info(fb_info)) { lock_fb_info(fb_info);
console_unlock(); fbcon_fb_unbind(fb_info);
return -ENODEV;
}
event.info = fb_info;
ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
unlock_fb_info(fb_info); unlock_fb_info(fb_info);
console_unlock(); console_unlock();
return ret;
} }
static int __unlink_framebuffer(struct fb_info *fb_info); void unlink_framebuffer(struct fb_info *fb_info)
static int do_unregister_framebuffer(struct fb_info *fb_info)
{ {
struct fb_event event; int i;
int ret;
i = fb_info->node;
if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
return;
ret = unbind_console(fb_info); if (!fb_info->dev)
return;
if (ret) device_destroy(fb_class, MKDEV(FB_MAJOR, i));
return -EINVAL;
pm_vt_switch_unregister(fb_info->dev); pm_vt_switch_unregister(fb_info->dev);
__unlink_framebuffer(fb_info); unbind_console(fb_info);
fb_info->dev = NULL;
}
EXPORT_SYMBOL(unlink_framebuffer);
static void do_unregister_framebuffer(struct fb_info *fb_info)
{
unlink_framebuffer(fb_info);
if (fb_info->pixmap.addr && if (fb_info->pixmap.addr &&
(fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
kfree(fb_info->pixmap.addr); kfree(fb_info->pixmap.addr);
...@@ -1789,46 +1714,21 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) ...@@ -1789,46 +1714,21 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
registered_fb[fb_info->node] = NULL; registered_fb[fb_info->node] = NULL;
num_registered_fb--; num_registered_fb--;
fb_cleanup_device(fb_info); fb_cleanup_device(fb_info);
event.info = fb_info; #ifdef CONFIG_GUMSTIX_AM200EPD
{
struct fb_event event;
event.info = fb_info;
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
}
#endif
console_lock(); console_lock();
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); fbcon_fb_unregistered(fb_info);
console_unlock(); console_unlock();
/* this may free fb info */ /* this may free fb info */
put_fb_info(fb_info); put_fb_info(fb_info);
return 0;
} }
static int __unlink_framebuffer(struct fb_info *fb_info)
{
int i;
i = fb_info->node;
if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
return -EINVAL;
if (fb_info->dev) {
device_destroy(fb_class, MKDEV(FB_MAJOR, i));
fb_info->dev = NULL;
}
return 0;
}
int unlink_framebuffer(struct fb_info *fb_info)
{
int ret;
ret = __unlink_framebuffer(fb_info);
if (ret)
return ret;
unbind_console(fb_info);
return 0;
}
EXPORT_SYMBOL(unlink_framebuffer);
/** /**
* remove_conflicting_framebuffers - remove firmware-configured framebuffers * remove_conflicting_framebuffers - remove firmware-configured framebuffers
* @a: memory range, users of which are to be removed * @a: memory range, users of which are to be removed
...@@ -1842,7 +1742,6 @@ EXPORT_SYMBOL(unlink_framebuffer); ...@@ -1842,7 +1742,6 @@ EXPORT_SYMBOL(unlink_framebuffer);
int remove_conflicting_framebuffers(struct apertures_struct *a, int remove_conflicting_framebuffers(struct apertures_struct *a,
const char *name, bool primary) const char *name, bool primary)
{ {
int ret;
bool do_free = false; bool do_free = false;
if (!a) { if (!a) {
...@@ -1856,13 +1755,13 @@ int remove_conflicting_framebuffers(struct apertures_struct *a, ...@@ -1856,13 +1755,13 @@ int remove_conflicting_framebuffers(struct apertures_struct *a,
} }
mutex_lock(&registration_lock); mutex_lock(&registration_lock);
ret = do_remove_conflicting_framebuffers(a, name, primary); do_remove_conflicting_framebuffers(a, name, primary);
mutex_unlock(&registration_lock); mutex_unlock(&registration_lock);
if (do_free) if (do_free)
kfree(a); kfree(a);
return ret; return 0;
} }
EXPORT_SYMBOL(remove_conflicting_framebuffers); EXPORT_SYMBOL(remove_conflicting_framebuffers);
...@@ -1959,16 +1858,12 @@ EXPORT_SYMBOL(register_framebuffer); ...@@ -1959,16 +1858,12 @@ EXPORT_SYMBOL(register_framebuffer);
* that the driver implements fb_open() and fb_release() to * that the driver implements fb_open() and fb_release() to
* check that no processes are using the device. * check that no processes are using the device.
*/ */
int void
unregister_framebuffer(struct fb_info *fb_info) unregister_framebuffer(struct fb_info *fb_info)
{ {
int ret;
mutex_lock(&registration_lock); mutex_lock(&registration_lock);
ret = do_unregister_framebuffer(fb_info); do_unregister_framebuffer(fb_info);
mutex_unlock(&registration_lock); mutex_unlock(&registration_lock);
return ret;
} }
EXPORT_SYMBOL(unregister_framebuffer); EXPORT_SYMBOL(unregister_framebuffer);
...@@ -1983,15 +1878,14 @@ EXPORT_SYMBOL(unregister_framebuffer); ...@@ -1983,15 +1878,14 @@ EXPORT_SYMBOL(unregister_framebuffer);
*/ */
void fb_set_suspend(struct fb_info *info, int state) void fb_set_suspend(struct fb_info *info, int state)
{ {
struct fb_event event; WARN_CONSOLE_UNLOCKED();
event.info = info;
if (state) { if (state) {
fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); fbcon_suspended(info);
info->state = FBINFO_STATE_SUSPENDED; info->state = FBINFO_STATE_SUSPENDED;
} else { } else {
info->state = FBINFO_STATE_RUNNING; info->state = FBINFO_STATE_RUNNING;
fb_notifier_call_chain(FB_EVENT_RESUME, &event); fbcon_resumed(info);
} }
} }
EXPORT_SYMBOL(fb_set_suspend); EXPORT_SYMBOL(fb_set_suspend);
...@@ -2059,7 +1953,6 @@ subsys_initcall(fbmem_init); ...@@ -2059,7 +1953,6 @@ subsys_initcall(fbmem_init);
int fb_new_modelist(struct fb_info *info) int fb_new_modelist(struct fb_info *info)
{ {
struct fb_event event;
struct fb_var_screeninfo var = info->var; struct fb_var_screeninfo var = info->var;
struct list_head *pos, *n; struct list_head *pos, *n;
struct fb_modelist *modelist; struct fb_modelist *modelist;
...@@ -2079,14 +1972,12 @@ int fb_new_modelist(struct fb_info *info) ...@@ -2079,14 +1972,12 @@ int fb_new_modelist(struct fb_info *info)
} }
} }
err = 1; if (list_empty(&info->modelist))
return 1;
if (!list_empty(&info->modelist)) { fbcon_new_modelist(info);
event.info = info;
err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
}
return err; return 0;
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/fbcon.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -175,10 +176,7 @@ static ssize_t store_modes(struct device *device, ...@@ -175,10 +176,7 @@ static ssize_t store_modes(struct device *device,
return -EINVAL; return -EINVAL;
console_lock(); console_lock();
if (!lock_fb_info(fb_info)) { lock_fb_info(fb_info);
console_unlock();
return -ENODEV;
}
list_splice(&fb_info->modelist, &old_list); list_splice(&fb_info->modelist, &old_list);
fb_videomode_to_modelist((const struct fb_videomode *)buf, i, fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
...@@ -304,12 +302,13 @@ static ssize_t store_blank(struct device *device, ...@@ -304,12 +302,13 @@ static ssize_t store_blank(struct device *device,
{ {
struct fb_info *fb_info = dev_get_drvdata(device); struct fb_info *fb_info = dev_get_drvdata(device);
char *last = NULL; char *last = NULL;
int err; int err, arg;
arg = simple_strtoul(buf, &last, 0);
console_lock(); console_lock();
fb_info->flags |= FBINFO_MISC_USEREVENT; err = fb_blank(fb_info, arg);
err = fb_blank(fb_info, simple_strtoul(buf, &last, 0)); /* might again call into fb_blank */
fb_info->flags &= ~FBINFO_MISC_USEREVENT; fbcon_fb_blanked(fb_info, arg);
console_unlock(); console_unlock();
if (err < 0) if (err < 0)
return err; return err;
...@@ -405,10 +404,7 @@ static ssize_t store_fbstate(struct device *device, ...@@ -405,10 +404,7 @@ static ssize_t store_fbstate(struct device *device,
state = simple_strtoul(buf, &last, 0); state = simple_strtoul(buf, &last, 0);
console_lock(); console_lock();
if (!lock_fb_info(fb_info)) { lock_fb_info(fb_info);
console_unlock();
return -ENODEV;
}
fb_set_suspend(fb_info, (int)state); fb_set_suspend(fb_info, (int)state);
......
...@@ -61,7 +61,6 @@ ...@@ -61,7 +61,6 @@
struct cfb_info { struct cfb_info {
struct fb_info fb; struct fb_info fb;
struct display_switch *dispsw; struct display_switch *dispsw;
struct display *display;
unsigned char __iomem *region; unsigned char __iomem *region;
unsigned char __iomem *regs; unsigned char __iomem *regs;
u_int id; u_int id;
......
...@@ -2122,14 +2122,7 @@ static void neofb_remove(struct pci_dev *dev) ...@@ -2122,14 +2122,7 @@ static void neofb_remove(struct pci_dev *dev)
DBG("neofb_remove"); DBG("neofb_remove");
if (info) { if (info) {
/* unregister_framebuffer(info);
* If unregister_framebuffer fails, then
* we will be leaving hooks that could cause
* oopsen laying around.
*/
if (unregister_framebuffer(info))
printk(KERN_WARNING
"neofb: danger danger! Oopsen imminent!\n");
neo_unmap_video(info); neo_unmap_video(info);
fb_destroy_modedb(info->monspecs.modedb); fb_destroy_modedb(info->monspecs.modedb);
......
...@@ -60,8 +60,7 @@ static ssize_t store_rotate_type(struct device *dev, ...@@ -60,8 +60,7 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB) if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
return -EINVAL; return -EINVAL;
if (!lock_fb_info(fbi)) lock_fb_info(fbi);
return -ENODEV;
r = 0; r = 0;
if (rot_type == ofbi->rotation_type) if (rot_type == ofbi->rotation_type)
...@@ -112,8 +111,7 @@ static ssize_t store_mirror(struct device *dev, ...@@ -112,8 +111,7 @@ static ssize_t store_mirror(struct device *dev,
if (r) if (r)
return r; return r;
if (!lock_fb_info(fbi)) lock_fb_info(fbi);
return -ENODEV;
ofbi->mirror = mirror; ofbi->mirror = mirror;
...@@ -149,8 +147,7 @@ static ssize_t show_overlays(struct device *dev, ...@@ -149,8 +147,7 @@ static ssize_t show_overlays(struct device *dev,
ssize_t l = 0; ssize_t l = 0;
int t; int t;
if (!lock_fb_info(fbi)) lock_fb_info(fbi);
return -ENODEV;
omapfb_lock(fbdev); omapfb_lock(fbdev);
for (t = 0; t < ofbi->num_overlays; t++) { for (t = 0; t < ofbi->num_overlays; t++) {
...@@ -208,8 +205,7 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, ...@@ -208,8 +205,7 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
if (buf[len - 1] == '\n') if (buf[len - 1] == '\n')
len = len - 1; len = len - 1;
if (!lock_fb_info(fbi)) lock_fb_info(fbi);
return -ENODEV;
omapfb_lock(fbdev); omapfb_lock(fbdev);
if (len > 0) { if (len > 0) {
...@@ -340,8 +336,7 @@ static ssize_t show_overlays_rotate(struct device *dev, ...@@ -340,8 +336,7 @@ static ssize_t show_overlays_rotate(struct device *dev,
ssize_t l = 0; ssize_t l = 0;
int t; int t;
if (!lock_fb_info(fbi)) lock_fb_info(fbi);
return -ENODEV;
for (t = 0; t < ofbi->num_overlays; t++) { for (t = 0; t < ofbi->num_overlays; t++) {
l += snprintf(buf + l, PAGE_SIZE - l, "%s%d", l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
...@@ -369,8 +364,7 @@ static ssize_t store_overlays_rotate(struct device *dev, ...@@ -369,8 +364,7 @@ static ssize_t store_overlays_rotate(struct device *dev,
if (buf[len - 1] == '\n') if (buf[len - 1] == '\n')
len = len - 1; len = len - 1;
if (!lock_fb_info(fbi)) lock_fb_info(fbi);
return -ENODEV;
if (len > 0) { if (len > 0) {
char *p = (char *)buf; char *p = (char *)buf;
...@@ -453,8 +447,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, ...@@ -453,8 +447,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
if (!lock_fb_info(fbi)) lock_fb_info(fbi);
return -ENODEV;
if (display && display->driver->sync) if (display && display->driver->sync)
display->driver->sync(display); display->driver->sync(display);
......
...@@ -974,35 +974,10 @@ static void sa1100fb_task(struct work_struct *w) ...@@ -974,35 +974,10 @@ static void sa1100fb_task(struct work_struct *w)
*/ */
static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi) static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
{ {
#if 0
unsigned int min_period = (unsigned int)-1;
int i;
for (i = 0; i < MAX_NR_CONSOLES; i++) {
struct display *disp = &fb_display[i];
unsigned int period;
/*
* Do we own this display?
*/
if (disp->fb_info != &fbi->fb)
continue;
/*
* Ok, calculate its DMA period
*/
period = sa1100fb_display_dma_period(&disp->var);
if (period < min_period)
min_period = period;
}
return min_period;
#else
/* /*
* FIXME: we need to verify _all_ consoles. * FIXME: we need to verify _all_ consoles.
*/ */
return sa1100fb_display_dma_period(&fbi->fb.var); return sa1100fb_display_dma_period(&fbi->fb.var);
#endif
} }
/* /*
......
...@@ -2333,14 +2333,7 @@ static void savagefb_remove(struct pci_dev *dev) ...@@ -2333,14 +2333,7 @@ static void savagefb_remove(struct pci_dev *dev)
DBG("savagefb_remove"); DBG("savagefb_remove");
if (info) { if (info) {
/* unregister_framebuffer(info);
* If unregister_framebuffer fails, then
* we will be leaving hooks that could cause
* oopsen laying around.
*/
if (unregister_framebuffer(info))
printk(KERN_WARNING "savagefb: danger danger! "
"Oopsen imminent!\n");
#ifdef CONFIG_FB_SAVAGE_I2C #ifdef CONFIG_FB_SAVAGE_I2C
savagefb_delete_i2c_busses(info); savagefb_delete_i2c_busses(info);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fbcon.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -213,7 +214,6 @@ struct sh_mobile_lcdc_priv { ...@@ -213,7 +214,6 @@ struct sh_mobile_lcdc_priv {
struct sh_mobile_lcdc_chan ch[2]; struct sh_mobile_lcdc_chan ch[2];
struct sh_mobile_lcdc_overlay overlays[4]; struct sh_mobile_lcdc_overlay overlays[4];
struct notifier_block notifier;
int started; int started;
int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
}; };
...@@ -534,89 +534,9 @@ static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch) ...@@ -534,89 +534,9 @@ static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
ch->tx_dev->ops->display_off(ch->tx_dev); ch->tx_dev->ops->display_off(ch->tx_dev);
} }
static bool
sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
const struct fb_videomode *new_mode)
{
dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
ch->display.mode.xres, ch->display.mode.yres,
new_mode->xres, new_mode->yres);
/* It can be a different monitor with an equal video-mode */
if (fb_mode_is_equal(&ch->display.mode, new_mode))
return false;
dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
ch->display.mode.yres, new_mode->yres);
ch->display.mode = *new_mode;
return true;
}
static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var, static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
struct fb_info *info); struct fb_info *info);
static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
enum sh_mobile_lcdc_entity_event event,
const struct fb_videomode *mode,
const struct fb_monspecs *monspec)
{
struct fb_info *info = ch->info;
struct fb_var_screeninfo var;
int ret = 0;
switch (event) {
case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
/* HDMI plug in */
console_lock();
if (lock_fb_info(info)) {
ch->display.width = monspec->max_x * 10;
ch->display.height = monspec->max_y * 10;
if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
info->state == FBINFO_STATE_RUNNING) {
/* First activation with the default monitor.
* Just turn on, if we run a resume here, the
* logo disappears.
*/
info->var.width = ch->display.width;
info->var.height = ch->display.height;
sh_mobile_lcdc_display_on(ch);
} else {
/* New monitor or have to wake up */
fb_set_suspend(info, 0);
}
unlock_fb_info(info);
}
console_unlock();
break;
case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
/* HDMI disconnect */
console_lock();
if (lock_fb_info(info)) {
fb_set_suspend(info, 1);
unlock_fb_info(info);
}
console_unlock();
break;
case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
/* Validate a proposed new mode */
fb_videomode_to_var(&var, mode);
var.bits_per_pixel = info->var.bits_per_pixel;
var.grayscale = info->var.grayscale;
ret = sh_mobile_lcdc_check_var(&var, info);
break;
}
return ret;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Format helpers * Format helpers
*/ */
...@@ -1838,8 +1758,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) ...@@ -1838,8 +1758,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_chan *ch = info->par;
struct fb_var_screeninfo var; struct fb_var_screeninfo var;
struct fb_videomode mode; struct fb_videomode mode;
struct fb_event event;
int evnt = FB_EVENT_MODE_CHANGE_ALL;
if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
/* More framebuffer users are active */ /* More framebuffer users are active */
...@@ -1861,14 +1779,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) ...@@ -1861,14 +1779,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
/* Couldn't reconfigure, hopefully, can continue as before */ /* Couldn't reconfigure, hopefully, can continue as before */
return; return;
/* fbcon_update_vcs(info, true);
* fb_set_var() calls the notifier change internally, only if
* FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
* user event, we have to call the chain ourselves.
*/
event.info = info;
event.data = &ch->display.mode;
fb_notifier_call_chain(evnt, &event);
} }
/* /*
...@@ -2319,37 +2230,6 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { ...@@ -2319,37 +2230,6 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
* Framebuffer notifier * Framebuffer notifier
*/ */
/* locking: called with info->lock held */
static int sh_mobile_lcdc_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct fb_event *event = data;
struct fb_info *info = event->info;
struct sh_mobile_lcdc_chan *ch = info->par;
if (&ch->lcdc->notifier != nb)
return NOTIFY_DONE;
dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
__func__, action, event->data);
switch(action) {
case FB_EVENT_SUSPEND:
sh_mobile_lcdc_display_off(ch);
sh_mobile_lcdc_stop(ch->lcdc);
break;
case FB_EVENT_RESUME:
mutex_lock(&ch->open_lock);
sh_mobile_fb_reconfig(info);
mutex_unlock(&ch->open_lock);
sh_mobile_lcdc_display_on(ch);
sh_mobile_lcdc_start(ch->lcdc);
}
return NOTIFY_OK;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Probe/remove and driver init/exit * Probe/remove and driver init/exit
*/ */
...@@ -2377,8 +2257,6 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) ...@@ -2377,8 +2257,6 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
unsigned int i; unsigned int i;
fb_unregister_client(&priv->notifier);
for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]); sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
for (i = 0; i < ARRAY_SIZE(priv->ch); i++) for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
...@@ -2540,8 +2418,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch) ...@@ -2540,8 +2418,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
unsigned int max_size; unsigned int max_size;
unsigned int i; unsigned int i;
ch->notify = sh_mobile_lcdc_display_notify;
/* Validate the format. */ /* Validate the format. */
format = sh_mobile_format_info(cfg->fourcc); format = sh_mobile_format_info(cfg->fourcc);
if (format == NULL) { if (format == NULL) {
...@@ -2770,10 +2646,6 @@ static int sh_mobile_lcdc_probe(struct platform_device *pdev) ...@@ -2770,10 +2646,6 @@ static int sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1; goto err1;
} }
/* Failure ignored */
priv->notifier.notifier_call = sh_mobile_lcdc_notify;
fb_register_client(&priv->notifier);
return 0; return 0;
err1: err1:
sh_mobile_lcdc_remove(pdev); sh_mobile_lcdc_remove(pdev);
......
...@@ -87,11 +87,6 @@ struct sh_mobile_lcdc_chan { ...@@ -87,11 +87,6 @@ struct sh_mobile_lcdc_chan {
unsigned long base_addr_c; unsigned long base_addr_c;
unsigned int line_size; unsigned int line_size;
int (*notify)(struct sh_mobile_lcdc_chan *ch,
enum sh_mobile_lcdc_entity_event event,
const struct fb_videomode *mode,
const struct fb_monspecs *monspec);
/* Backlight */ /* Backlight */
struct backlight_device *bl; struct backlight_device *bl;
unsigned int bl_brightness; unsigned int bl_brightness;
......
...@@ -168,9 +168,6 @@ extern void vc_SAK(struct work_struct *work); ...@@ -168,9 +168,6 @@ extern void vc_SAK(struct work_struct *work);
#define CUR_DEFAULT CUR_UNDERLINE #define CUR_DEFAULT CUR_UNDERLINE
static inline bool con_is_visible(const struct vc_data *vc) bool con_is_visible(const struct vc_data *vc);
{
return *vc->vc_display_fg == vc;
}
#endif /* _LINUX_CONSOLE_STRUCT_H */ #endif /* _LINUX_CONSOLE_STRUCT_H */
...@@ -126,39 +126,15 @@ struct fb_cursor_user { ...@@ -126,39 +126,15 @@ struct fb_cursor_user {
/* The resolution of the passed in fb_info about to change */ /* The resolution of the passed in fb_info about to change */
#define FB_EVENT_MODE_CHANGE 0x01 #define FB_EVENT_MODE_CHANGE 0x01
/* The display on this fb_info is being suspended, no access to the
* framebuffer is allowed any more after that call returns #ifdef CONFIG_GUMSTIX_AM200EPD
*/ /* only used by mach-pxa/am200epd.c */
#define FB_EVENT_SUSPEND 0x02
/* The display on this fb_info was resumed, you can restore the display
* if you own it
*/
#define FB_EVENT_RESUME 0x03
/* An entry from the modelist was removed */
#define FB_EVENT_MODE_DELETE 0x04
/* A driver registered itself */
#define FB_EVENT_FB_REGISTERED 0x05 #define FB_EVENT_FB_REGISTERED 0x05
/* A driver unregistered itself */
#define FB_EVENT_FB_UNREGISTERED 0x06 #define FB_EVENT_FB_UNREGISTERED 0x06
/* CONSOLE-SPECIFIC: get console to framebuffer mapping */ #endif
#define FB_EVENT_GET_CONSOLE_MAP 0x07
/* CONSOLE-SPECIFIC: set console to framebuffer mapping */ /* A display blank is requested */
#define FB_EVENT_SET_CONSOLE_MAP 0x08
/* A hardware display blank change occurred */
#define FB_EVENT_BLANK 0x09 #define FB_EVENT_BLANK 0x09
/* Private modelist is to be replaced */
#define FB_EVENT_NEW_MODELIST 0x0A
/* The resolution of the passed in fb_info about to change and
all vc's should be changed */
#define FB_EVENT_MODE_CHANGE_ALL 0x0B
/* A software display blank change occurred */
#define FB_EVENT_CONBLANK 0x0C
/* Get drawing requirements */
#define FB_EVENT_GET_REQ 0x0D
/* Unbind from the console if possible */
#define FB_EVENT_FB_UNBIND 0x0E
/* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga_switcheroo */
#define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
/* A hardware display blank early change occurred */ /* A hardware display blank early change occurred */
#define FB_EARLY_EVENT_BLANK 0x10 #define FB_EARLY_EVENT_BLANK 0x10
/* A hardware display blank revert early change occurred */ /* A hardware display blank revert early change occurred */
...@@ -633,8 +609,8 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, ...@@ -633,8 +609,8 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
/* drivers/video/fbmem.c */ /* drivers/video/fbmem.c */
extern int register_framebuffer(struct fb_info *fb_info); extern int register_framebuffer(struct fb_info *fb_info);
extern int unregister_framebuffer(struct fb_info *fb_info); extern void unregister_framebuffer(struct fb_info *fb_info);
extern int unlink_framebuffer(struct fb_info *fb_info); extern void unlink_framebuffer(struct fb_info *fb_info);
extern int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, int res_id, extern int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, int res_id,
const char *name); const char *name);
extern int remove_conflicting_framebuffers(struct apertures_struct *a, extern int remove_conflicting_framebuffers(struct apertures_struct *a,
...@@ -660,7 +636,10 @@ extern struct class *fb_class; ...@@ -660,7 +636,10 @@ extern struct class *fb_class;
for (i = 0; i < FB_MAX; i++) \ for (i = 0; i < FB_MAX; i++) \
if (!registered_fb[i]) {} else if (!registered_fb[i]) {} else
extern int lock_fb_info(struct fb_info *info); static inline void lock_fb_info(struct fb_info *info)
{
mutex_lock(&info->lock);
}
static inline void unlock_fb_info(struct fb_info *info) static inline void unlock_fb_info(struct fb_info *info)
{ {
......
...@@ -4,9 +4,39 @@ ...@@ -4,9 +4,39 @@
#ifdef CONFIG_FRAMEBUFFER_CONSOLE #ifdef CONFIG_FRAMEBUFFER_CONSOLE
void __init fb_console_init(void); void __init fb_console_init(void);
void __exit fb_console_exit(void); void __exit fb_console_exit(void);
int fbcon_fb_registered(struct fb_info *info);
void fbcon_fb_unregistered(struct fb_info *info);
void fbcon_fb_unbind(struct fb_info *info);
void fbcon_suspended(struct fb_info *info);
void fbcon_resumed(struct fb_info *info);
int fbcon_mode_deleted(struct fb_info *info,
struct fb_videomode *mode);
void fbcon_new_modelist(struct fb_info *info);
void fbcon_get_requirement(struct fb_info *info,
struct fb_blit_caps *caps);
void fbcon_fb_blanked(struct fb_info *info, int blank);
void fbcon_update_vcs(struct fb_info *info, bool all);
void fbcon_remap_all(struct fb_info *info);
int fbcon_set_con2fb_map_ioctl(void __user *argp);
int fbcon_get_con2fb_map_ioctl(void __user *argp);
#else #else
static inline void fb_console_init(void) {} static inline void fb_console_init(void) {}
static inline void fb_console_exit(void) {} static inline void fb_console_exit(void) {}
static inline int fbcon_fb_registered(struct fb_info *info) { return 0; }
static inline void fbcon_fb_unregistered(struct fb_info *info) {}
static inline void fbcon_fb_unbind(struct fb_info *info) {}
static inline void fbcon_suspended(struct fb_info *info) {}
static inline void fbcon_resumed(struct fb_info *info) {}
static inline int fbcon_mode_deleted(struct fb_info *info,
struct fb_videomode *mode) { return 0; }
static inline void fbcon_new_modelist(struct fb_info *info) {}
static inline void fbcon_get_requirement(struct fb_info *info,
struct fb_blit_caps *caps) {}
static inline void fbcon_fb_blanked(struct fb_info *info, int blank) {}
static inline void fbcon_update_vcs(struct fb_info *info, bool all) {}
static inline void fbcon_remap_all(struct fb_info *info) {}
static inline int fbcon_set_con2fb_map_ioctl(void __user *argp) { return 0; }
static inline int fbcon_get_con2fb_map_ioctl(void __user *argp) { return 0; }
#endif #endif
#endif /* _LINUX_FBCON_H */ #endif /* _LINUX_FBCON_H */
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