We register each available framebuffer in the system with the fblog driver so we always know all active devices. We directly open the fb-driver, initialize the buffer and load a font so we are ready for drawing operations. If a device cannot be opened, we mark it as dead and ignore it in all other functions. Signed-off-by: David Herrmann <dh.herrmann@xxxxxxxxxxxxxx> --- drivers/video/console/fblog.c | 108 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c index 1504ba9..8038dcc 100644 --- a/drivers/video/console/fblog.c +++ b/drivers/video/console/fblog.c @@ -39,6 +39,14 @@ #include <linux/font.h> #include <linux/module.h> +#define FBLOG_STR(x) x, sizeof(x) - 1 + +enum fblog_flags { + FBLOG_KILLED, + FBLOG_SUSPENDED, + FBLOG_BLANKED, +}; + /** * struct fblog_buf: Console text buffer * @@ -61,6 +69,30 @@ struct fblog_buf { size_t pos_y; }; +/** + * struct fblog_fb: Framebuffer object + * + * For each framebuffer we register this object. It contains all data we need to + * display the console log on it. The index of a framebuffer in registered_fb[] + * is the same as in fblog_fbs[]. So the following must always be true if the + * pointers are non-NULL: + * registered_fb[idx] == fblog_fbs[idx]->info + * fblog_fbs[idx]->info->node == idx + * + * flags: Framebuffer flags (see fblog_flags) + * info: Pointer to the associated framebuffer device + * font: Currently used font + * buf: Console text buffer + */ +struct fblog_fb { + unsigned long flags; + struct fb_info *info; + const struct font_desc *font; + struct fblog_buf buf; +}; + +static struct fblog_fb *fblog_fbs[FB_MAX]; + static void fblog_buf_resize(struct fblog_buf *buf, size_t width, size_t height) { @@ -165,6 +197,82 @@ static void fblog_buf_write(struct fblog_buf *buf, const char *str, size_t len) } } +static struct fblog_fb *fblog_info2fb(struct fb_info *info) +{ + if (!info || info->node < 0 || info->node >= FB_MAX || + !registered_fb[info->node]) + return NULL; + + return fblog_fbs[info->node]; +} + +static void fblog_register(struct fb_info *info) +{ + struct fblog_fb *fb; + struct fb_var_screeninfo var; + const struct fb_videomode *mode; + unsigned int width, height; + + if (!info || info->node < 0 || info->node >= FB_MAX) + return; + if (!registered_fb[info->node] || fblog_fbs[info->node]) + return; + + fb = kzalloc(sizeof(*fb), GFP_KERNEL); + if (!fb) + return; + + fblog_fbs[info->node] = fb; + fb->info = info; + fblog_buf_init(&fb->buf); + fblog_buf_write(&fb->buf, FBLOG_STR("Framebuffer log initialized\n")); + + if (!try_module_get(info->fbops->owner)) + goto out_killed; + if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) + goto out_unref; + + var = info->var; + mode = fb_find_best_mode(&var, &info->modelist); + var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; + fb_set_var(info, &var); + + fb->font = get_default_font(info->var.xres, info->var.yres, + info->pixmap.blit_x, + info->pixmap.blit_y); + if (fb->font) { + width = info->var.xres / fb->font->width; + height = info->var.yres / fb->font->height; + fblog_buf_resize(&fb->buf, width, height); + } + + return; + +out_unref: + module_put(info->fbops->owner); +out_killed: + set_bit(FBLOG_KILLED, &fb->flags); +} + +static void fblog_unregister(struct fblog_fb *fb) +{ + struct fb_info *info; + + if (!fb) + return; + + info = fb->info; + if (!test_bit(FBLOG_KILLED, &fb->flags)) { + if (info->fbops->fb_release) + info->fbops->fb_release(info, 0); + module_put(info->fbops->owner); + } + + fblog_buf_deinit(&fb->buf); + fblog_fbs[info->node] = NULL; + kfree(fb); +} + static int __init fblog_init(void) { return 0; -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html