diff --git a/drivers/video/fb.c b/drivers/video/fb.c index dbda8d4..3672c44 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -31,11 +31,40 @@ return 0; } +static int fb_alloc_shadowfb(struct fb_info *info) +{ + if (info->screen_base_shadow && info->shadowfb) + return 0; + + if (!info->screen_base_shadow && !info->shadowfb) + return 0; + + if (info->shadowfb) { + info->screen_base_shadow = memalign(PAGE_SIZE, + info->line_length * info->yres); + if (!info->screen_base_shadow) + return -ENOMEM; + memcpy(info->screen_base_shadow, info->screen_base, + info->line_length * info->yres); + } else { + free(info->screen_base_shadow); + info->screen_base_shadow = NULL; + } + + return 0; +} + int fb_enable(struct fb_info *info) { + int ret; + if (info->enabled) return 0; + ret = fb_alloc_shadowfb(info); + if (ret) + return ret; + info->fbops->fb_enable(info); info->enabled = true; @@ -188,6 +217,22 @@ fb_print_modes(&info->edid_modes); } +void *fb_get_screen_base(struct fb_info *info) +{ + return info->screen_base_shadow ? + info->screen_base_shadow : info->screen_base; +} + +int fb_set_shadowfb(struct param_d *p, void *priv) +{ + struct fb_info *info = priv; + + if (!info->enabled) + return 0; + + return fb_alloc_shadowfb(info); +} + int register_framebuffer(struct fb_info *info) { int id = get_free_deviceid("fb"); @@ -245,6 +290,8 @@ for (i = 0; i < info->edid_modes.num_modes; i++) names[i + info->modes.num_modes] = info->edid_modes.modes[i].name; dev_add_param_enum(dev, "mode_name", fb_set_modename, NULL, &info->current_mode, names, num_modes, info); + info->shadowfb = 1; + dev_add_param_bool(dev, "shadowfb", fb_set_shadowfb, NULL, &info->shadowfb, info); info->mode = fb_num_to_mode(info, 0); diff --git a/include/fb.h b/include/fb.h index 311d5db..cf113c4 100644 --- a/include/fb.h +++ b/include/fb.h @@ -118,6 +118,7 @@ struct device_d dev; /* This is this fb device */ void *screen_base; + void *screen_base_shadow; unsigned long screen_size; void *priv; @@ -141,6 +142,7 @@ int register_simplefb; /* If true a simplefb device node will * be created. */ + int shadowfb; }; struct display_timings *of_get_display_timings(struct device_node *np); @@ -167,5 +169,6 @@ void fb_of_reserve_add_fixup(struct fb_info *info); int register_fbconsole(struct fb_info *fb); +void *fb_get_screen_base(struct fb_info *info); #endif /* __FB_H */