diff options
Diffstat (limited to 'drivers/video/fbdev/core/fbmem.c')
-rw-r--r-- | drivers/video/fbdev/core/fbmem.c | 542 |
1 files changed, 1 insertions, 541 deletions
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index ee44a46a66..fc206755f5 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -11,30 +11,12 @@ * for more details. */ -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/mman.h> -#include <linux/vt.h> -#include <linux/init.h> -#include <linux/linux_logo.h> -#include <linux/platform_device.h> #include <linux/console.h> -#include <linux/kmod.h> -#include <linux/err.h> -#include <linux/device.h> -#include <linux/efi.h> +#include <linux/export.h> #include <linux/fb.h> #include <linux/fbcon.h> -#include <linux/mem_encrypt.h> -#include <linux/pci.h> #include <video/nomodeset.h> -#include <video/vga.h> #include "fb_internal.h" @@ -53,10 +35,6 @@ int num_registered_fb __read_mostly; for (i = 0; i < FB_MAX; i++) \ if (!registered_fb[i]) {} else -bool fb_center_logo __read_mostly; - -int fb_logo_count __read_mostly = -1; - struct fb_info *get_fb_info(unsigned int idx) { struct fb_info *fb_info; @@ -184,524 +162,6 @@ char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size } EXPORT_SYMBOL(fb_get_buffer_offset); -#ifdef CONFIG_LOGO - -static inline unsigned safe_shift(unsigned d, int n) -{ - return n < 0 ? d >> -n : d << n; -} - -static void fb_set_logocmap(struct fb_info *info, - const struct linux_logo *logo) -{ - struct fb_cmap palette_cmap; - u16 palette_green[16]; - u16 palette_blue[16]; - u16 palette_red[16]; - int i, j, n; - const unsigned char *clut = logo->clut; - - palette_cmap.start = 0; - palette_cmap.len = 16; - palette_cmap.red = palette_red; - palette_cmap.green = palette_green; - palette_cmap.blue = palette_blue; - palette_cmap.transp = NULL; - - for (i = 0; i < logo->clutsize; i += n) { - n = logo->clutsize - i; - /* palette_cmap provides space for only 16 colors at once */ - if (n > 16) - n = 16; - palette_cmap.start = 32 + i; - palette_cmap.len = n; - for (j = 0; j < n; ++j) { - palette_cmap.red[j] = clut[0] << 8 | clut[0]; - palette_cmap.green[j] = clut[1] << 8 | clut[1]; - palette_cmap.blue[j] = clut[2] << 8 | clut[2]; - clut += 3; - } - fb_set_cmap(&palette_cmap, info); - } -} - -static void fb_set_logo_truepalette(struct fb_info *info, - const struct linux_logo *logo, - u32 *palette) -{ - static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; - unsigned char redmask, greenmask, bluemask; - int redshift, greenshift, blueshift; - int i; - const unsigned char *clut = logo->clut; - - /* - * We have to create a temporary palette since console palette is only - * 16 colors long. - */ - /* Bug: Doesn't obey msb_right ... (who needs that?) */ - redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; - greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; - bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; - redshift = info->var.red.offset - (8 - info->var.red.length); - greenshift = info->var.green.offset - (8 - info->var.green.length); - blueshift = info->var.blue.offset - (8 - info->var.blue.length); - - for ( i = 0; i < logo->clutsize; i++) { - palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | - safe_shift((clut[1] & greenmask), greenshift) | - safe_shift((clut[2] & bluemask), blueshift)); - clut += 3; - } -} - -static void fb_set_logo_directpalette(struct fb_info *info, - const struct linux_logo *logo, - u32 *palette) -{ - int redshift, greenshift, blueshift; - int i; - - redshift = info->var.red.offset; - greenshift = info->var.green.offset; - blueshift = info->var.blue.offset; - - for (i = 32; i < 32 + logo->clutsize; i++) - palette[i] = i << redshift | i << greenshift | i << blueshift; -} - -static void fb_set_logo(struct fb_info *info, - const struct linux_logo *logo, u8 *dst, - int depth) -{ - int i, j, k; - const u8 *src = logo->data; - u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; - u8 fg = 1, d; - - switch (fb_get_color_depth(&info->var, &info->fix)) { - case 1: - fg = 1; - break; - case 2: - fg = 3; - break; - default: - fg = 7; - break; - } - - if (info->fix.visual == FB_VISUAL_MONO01 || - info->fix.visual == FB_VISUAL_MONO10) - fg = ~((u8) (0xfff << info->var.green.length)); - - switch (depth) { - case 4: - for (i = 0; i < logo->height; i++) - for (j = 0; j < logo->width; src++) { - *dst++ = *src >> 4; - j++; - if (j < logo->width) { - *dst++ = *src & 0x0f; - j++; - } - } - break; - case 1: - for (i = 0; i < logo->height; i++) { - for (j = 0; j < logo->width; src++) { - d = *src ^ xor; - for (k = 7; k >= 0 && j < logo->width; k--) { - *dst++ = ((d >> k) & 1) ? fg : 0; - j++; - } - } - } - break; - } -} - -/* - * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), - * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on - * the visual format and color depth of the framebuffer, the DAC, the - * pseudo_palette, and the logo data will be adjusted accordingly. - * - * Case 1 - linux_logo_clut224: - * Color exceeds the number of console colors (16), thus we set the hardware DAC - * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. - * - * For visuals that require color info from the pseudo_palette, we also construct - * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags - * will be set. - * - * Case 2 - linux_logo_vga16: - * The number of colors just matches the console colors, thus there is no need - * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, - * each byte contains color information for two pixels (upper and lower nibble). - * To be consistent with fb_imageblit() usage, we therefore separate the two - * nibbles into separate bytes. The "depth" flag will be set to 4. - * - * Case 3 - linux_logo_mono: - * This is similar with Case 2. Each byte contains information for 8 pixels. - * We isolate each bit and expand each into a byte. The "depth" flag will - * be set to 1. - */ -static struct logo_data { - int depth; - int needs_directpalette; - int needs_truepalette; - int needs_cmapreset; - const struct linux_logo *logo; -} fb_logo __read_mostly; - -static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) -{ - u32 size = width * height, i; - - out += size - 1; - - for (i = size; i--; ) - *out-- = *in++; -} - -static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) -{ - int i, j, h = height - 1; - - for (i = 0; i < height; i++) - for (j = 0; j < width; j++) - out[height * j + h - i] = *in++; -} - -static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) -{ - int i, j, w = width - 1; - - for (i = 0; i < height; i++) - for (j = 0; j < width; j++) - out[height * (w - j) + i] = *in++; -} - -static void fb_rotate_logo(struct fb_info *info, u8 *dst, - struct fb_image *image, int rotate) -{ - u32 tmp; - - if (rotate == FB_ROTATE_UD) { - fb_rotate_logo_ud(image->data, dst, image->width, - image->height); - image->dx = info->var.xres - image->width - image->dx; - image->dy = info->var.yres - image->height - image->dy; - } else if (rotate == FB_ROTATE_CW) { - fb_rotate_logo_cw(image->data, dst, image->width, - image->height); - swap(image->width, image->height); - tmp = image->dy; - image->dy = image->dx; - image->dx = info->var.xres - image->width - tmp; - } else if (rotate == FB_ROTATE_CCW) { - fb_rotate_logo_ccw(image->data, dst, image->width, - image->height); - swap(image->width, image->height); - tmp = image->dx; - image->dx = image->dy; - image->dy = info->var.yres - image->height - tmp; - } - - image->data = dst; -} - -static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, - int rotate, unsigned int num) -{ - unsigned int x; - - if (image->width > info->var.xres || image->height > info->var.yres) - return; - - if (rotate == FB_ROTATE_UR) { - for (x = 0; - x < num && image->dx + image->width <= info->var.xres; - x++) { - info->fbops->fb_imageblit(info, image); - image->dx += image->width + 8; - } - } else if (rotate == FB_ROTATE_UD) { - u32 dx = image->dx; - - for (x = 0; x < num && image->dx <= dx; x++) { - info->fbops->fb_imageblit(info, image); - image->dx -= image->width + 8; - } - } else if (rotate == FB_ROTATE_CW) { - for (x = 0; - x < num && image->dy + image->height <= info->var.yres; - x++) { - info->fbops->fb_imageblit(info, image); - image->dy += image->height + 8; - } - } else if (rotate == FB_ROTATE_CCW) { - u32 dy = image->dy; - - for (x = 0; x < num && image->dy <= dy; x++) { - info->fbops->fb_imageblit(info, image); - image->dy -= image->height + 8; - } - } -} - -static int fb_show_logo_line(struct fb_info *info, int rotate, - const struct linux_logo *logo, int y, - unsigned int n) -{ - u32 *palette = NULL, *saved_pseudo_palette = NULL; - unsigned char *logo_new = NULL, *logo_rotate = NULL; - struct fb_image image; - - /* Return if the frame buffer is not mapped or suspended */ - if (logo == NULL || info->state != FBINFO_STATE_RUNNING || - info->fbops->owner) - return 0; - - image.depth = 8; - image.data = logo->data; - - if (fb_logo.needs_cmapreset) - fb_set_logocmap(info, logo); - - if (fb_logo.needs_truepalette || - fb_logo.needs_directpalette) { - palette = kmalloc(256 * 4, GFP_KERNEL); - if (palette == NULL) - return 0; - - if (fb_logo.needs_truepalette) - fb_set_logo_truepalette(info, logo, palette); - else - fb_set_logo_directpalette(info, logo, palette); - - saved_pseudo_palette = info->pseudo_palette; - info->pseudo_palette = palette; - } - - if (fb_logo.depth <= 4) { - logo_new = kmalloc_array(logo->width, logo->height, - GFP_KERNEL); - if (logo_new == NULL) { - kfree(palette); - if (saved_pseudo_palette) - info->pseudo_palette = saved_pseudo_palette; - return 0; - } - image.data = logo_new; - fb_set_logo(info, logo, logo_new, fb_logo.depth); - } - - if (fb_center_logo) { - int xres = info->var.xres; - int yres = info->var.yres; - - if (rotate == FB_ROTATE_CW || rotate == FB_ROTATE_CCW) { - xres = info->var.yres; - yres = info->var.xres; - } - - while (n && (n * (logo->width + 8) - 8 > xres)) - --n; - image.dx = (xres - (n * (logo->width + 8) - 8)) / 2; - image.dy = y ?: (yres - logo->height) / 2; - } else { - image.dx = 0; - image.dy = y; - } - - image.width = logo->width; - image.height = logo->height; - - if (rotate) { - logo_rotate = kmalloc_array(logo->width, logo->height, - GFP_KERNEL); - if (logo_rotate) - fb_rotate_logo(info, logo_rotate, &image, rotate); - } - - fb_do_show_logo(info, &image, rotate, n); - - kfree(palette); - if (saved_pseudo_palette != NULL) - info->pseudo_palette = saved_pseudo_palette; - kfree(logo_new); - kfree(logo_rotate); - return image.dy + logo->height; -} - - -#ifdef CONFIG_FB_LOGO_EXTRA - -#define FB_LOGO_EX_NUM_MAX 10 -static struct logo_data_extra { - const struct linux_logo *logo; - unsigned int n; -} fb_logo_ex[FB_LOGO_EX_NUM_MAX]; -static unsigned int fb_logo_ex_num; - -void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) -{ - if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) - return; - - fb_logo_ex[fb_logo_ex_num].logo = logo; - fb_logo_ex[fb_logo_ex_num].n = n; - fb_logo_ex_num++; -} - -static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, - unsigned int yres) -{ - unsigned int i; - - /* FIXME: logo_ex supports only truecolor fb. */ - if (info->fix.visual != FB_VISUAL_TRUECOLOR) - fb_logo_ex_num = 0; - - for (i = 0; i < fb_logo_ex_num; i++) { - if (fb_logo_ex[i].logo->type != fb_logo.logo->type) { - fb_logo_ex[i].logo = NULL; - continue; - } - height += fb_logo_ex[i].logo->height; - if (height > yres) { - height -= fb_logo_ex[i].logo->height; - fb_logo_ex_num = i; - break; - } - } - return height; -} - -static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) -{ - unsigned int i; - - for (i = 0; i < fb_logo_ex_num; i++) - y = fb_show_logo_line(info, rotate, - fb_logo_ex[i].logo, y, fb_logo_ex[i].n); - - return y; -} - -#else /* !CONFIG_FB_LOGO_EXTRA */ - -static inline int fb_prepare_extra_logos(struct fb_info *info, - unsigned int height, - unsigned int yres) -{ - return height; -} - -static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) -{ - return y; -} - -#endif /* CONFIG_FB_LOGO_EXTRA */ - - -int fb_prepare_logo(struct fb_info *info, int rotate) -{ - int depth = fb_get_color_depth(&info->var, &info->fix); - unsigned int yres; - int height; - - memset(&fb_logo, 0, sizeof(struct logo_data)); - - if (info->flags & FBINFO_MISC_TILEBLITTING || - info->fbops->owner || !fb_logo_count) - return 0; - - if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - depth = info->var.blue.length; - if (info->var.red.length < depth) - depth = info->var.red.length; - if (info->var.green.length < depth) - depth = info->var.green.length; - } - - if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) { - /* assume console colormap */ - depth = 4; - } - - /* Return if no suitable logo was found */ - fb_logo.logo = fb_find_logo(depth); - - if (!fb_logo.logo) { - return 0; - } - - if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) - yres = info->var.yres; - else - yres = info->var.xres; - - if (fb_logo.logo->height > yres) { - fb_logo.logo = NULL; - return 0; - } - - /* What depth we asked for might be different from what we get */ - if (fb_logo.logo->type == LINUX_LOGO_CLUT224) - fb_logo.depth = 8; - else if (fb_logo.logo->type == LINUX_LOGO_VGA16) - fb_logo.depth = 4; - else - fb_logo.depth = 1; - - - if (fb_logo.depth > 4 && depth > 4) { - switch (info->fix.visual) { - case FB_VISUAL_TRUECOLOR: - fb_logo.needs_truepalette = 1; - break; - case FB_VISUAL_DIRECTCOLOR: - fb_logo.needs_directpalette = 1; - fb_logo.needs_cmapreset = 1; - break; - case FB_VISUAL_PSEUDOCOLOR: - fb_logo.needs_cmapreset = 1; - break; - } - } - - height = fb_logo.logo->height; - if (fb_center_logo) - height += (yres - fb_logo.logo->height) / 2; - - return fb_prepare_extra_logos(info, height, yres); -} - -int fb_show_logo(struct fb_info *info, int rotate) -{ - unsigned int count; - int y; - - if (!fb_logo_count) - return 0; - - count = fb_logo_count < 0 ? num_online_cpus() : fb_logo_count; - y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count); - y = fb_show_extra_logos(info, y, rotate); - - return y; -} -#else -int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } -int fb_show_logo(struct fb_info *info, int rotate) { return 0; } -#endif /* CONFIG_LOGO */ -EXPORT_SYMBOL(fb_prepare_logo); -EXPORT_SYMBOL(fb_show_logo); - int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) { |