linux显示启动logo源码分析以及修改显示logo
Posted 正在起飞的蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux显示启动logo源码分析以及修改显示logo相关的知识,希望对你有一定的参考价值。
1、linux显示启动logo整个流程分析
(1)logo图片在内核源码中是以ppm格式的文件保存,在编译内核时会把ppm格式的文件自动转换成.c文件,在c文件中会构造一个struct linux_logo结构体变量,
变量名字就是文件的名字,struct linux_logo结构体在内核中用来表示一副logo图像信息;
(2)内核在初始化显示器后,会按照配置去匹配合适的struct linux_logo结构体,也就是查找logo图片;
(3)将logo图像显示到默认屏幕上;
2、linux显示启动logo源码分析
2.1、全局变量fb_logo
(1)显示启动logo的代码在fbmem.c中实现,使用struct logo_data结构体来描述启动logo相关的信息;
(2)成员logo表示启动logo图像的具体信息,其他的变量和图像的格式和图像深度有关系;
2.2、struct linux_logo结构体
#define LINUX_LOGO_MONO 1 /* monochrome black/white */
#define LINUX_LOGO_VGA16 2 /* 16 colors VGA text palette */
#define LINUX_LOGO_CLUT224 3 /* 224 colors */
#define LINUX_LOGO_GRAY256 4 /* 256 levels grayscale */
(1)struct linux_logo结构体就是内核中用来描述logo图片的,这个结构体不用我们去构造,是有ppm文件转换成c文件时自动生成;
(2)logo图像有4中格式,其中LINUX_LOGO_CLUT224应用最为广泛,所占空间也最小。LINUX_LOGO_CLUT224类型的图像颜色种类不会超过224中,颜色的具体信息保存在clut成员表示的颜色对照表中,成员data
指向由颜色对照表索引构成的图像数据。
(3)LINUX_LOGO_CLUT224类型的图像空间计算,比如:对于长宽分别是150和100的 Logo,如果bpp为24 使用颜色对照表方式存储这幅Logo最多需要( 150×100+224 × 3)=15672字节,而如果直接
存储 Logo的所有像素信息,就需要(150×100×3)=45000字节。
(4)通常情况下,内核对于bpp大于等于8的情况,会使用颜色对照表的方式存放Logo ,而bpp小于8时,使用颜色对照表反而可能占用更多空间,因此直接将像素信息存放在成员data中;
2.3、函数调用关系
s3cfb_probe() //这是显示器驱动的prob函数
fb_prepare_logo() //查找合适的logo
fb_get_color_depth() //获取显示器的颜色深度
fb_find_logo() //真正找到合适的logo图像,也就是struct linux_logo结构体
fb_prepare_extra_logos() //设置附加的logo数据,不是必须的
fb_set_cmap() //设置显示屏的颜色表
fb_show_logo() //显示logo图像
fb_show_logo_line() //构建struct fb_image结构体
fb_do_show_logo() //执行logo显示
info->fbops->fb_imageblit() //调用显示驱动的fb_imageblit()方法,这里是实际操作硬件的
fb_show_extra_logos() //显示附加的logo数据,非必须
2.4、fb_prepare_logo()函数
int fb_prepare_logo(struct fb_info *info, int rotate)
//计算颜色深度
int depth = fb_get_color_depth(&info->var, &info->fix);
unsigned int yres;
memset(&fb_logo, 0, sizeof(struct logo_data));
if (info->flags & FBINFO_MISC_TILEBLITTING ||
info->flags & FBINFO_MODULE)
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;
/* 根据颜色深度返回找到的struct linux_logo结构体 */
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;
//判断logo图像的高是否超过可视屏幕的高
if (fb_logo.logo->height > yres)
fb_logo.logo = NULL;
return 0;
/* 根据logo图像类型设置图像深度 */
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;
return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
(1)调用fb_get_color_depth()函数,根据info->var和info->fix计算图像深度,并返回给局部变量depth;
(2)调用fb_find_logo()函数,根据图像深度何也找到合适的Logo图像数据并返回给fb_logo.logo;
(3)如果找到了合适的图像数据,则根据 Logo 图像数据的类型给fb_logo.depth赋值
(4)如果由fb_logo.depth和depth 都大于 4,则根据 info->fix且sual 的值设置 fb_logo 剩下的成员:若 info->fix且sual 为 FB_VISUAL_TRUECOLOR,则由1__logo 的 needs二刷刷e出成员被设置,若为 FB_VISUAL_TR四COLOR,则 needs_directpalette 和 needs_cmapreset 均被设置,若为 FB_VISUAL_PSEUDOCOLOR,则 needs_cmapreset 被设置;
(5)调用fb_prepare_extra_logos()函数设置附加Logo数据;
2.5、fb_find_logo()函数
const struct linux_logo * __init_refok fb_find_logo(int depth)
const struct linux_logo *logo = NULL;
if (nologo)
return NULL;
if (depth >= 1)
#ifdef CONFIG_LOGO_LINUX_MONO
/* Generic Linux logo */
logo = &logo_linux_mono;
#endif
if (depth >= 4)
#ifdef CONFIG_LOGO_LINUX_VGA16
/* Generic Linux logo */
logo = &logo_linux_vga16;
#endif
if (depth >= 8)
#ifdef CONFIG_LOGO_LINUX_CLUT224
/* Generic Linux logo */
logo = &logo_linux_clut224;
#endif
//X210开发板的logo图像数据
#ifdef CONFIG_LOGO_X210_CLUT224
/* x210 android logo */
logo = &logo_x210_clut224;
#endif
return logo;
(1)根据depth去查找合适的logo数据,这里的struct linux_logo结构体是由ppm文件转换成C语言文件得到的;
(2)注意这里的查找有后覆盖性,当查找到合适的struct linux_logo结构体函数不会返回,会把所有的结构体都查找一遍,最后一个
匹配的会被返回;
2.6、fb_show_logo_line()函数
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->flags & FBINFO_MODULE)
return 0;
image.depth = 8;
image.data = logo->data; //图像数据
//若needs_cmapreset被设置,则根据logo配置颜色表,设置颜色表
//最终会调用info->fbops中的fb_setcmap()或fb_setcolreg()方法
if (fb_logo.needs_cmapreset)
fb_set_logocmap(info, logo);
//若needs_truepalette或 needs_directpalette被设置,则根据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);
//备份info中原调色板内容,并设置为新的调色板
saved_pseudo_palette = info->pseudo_palette;
info->pseudo_palette = palette;
//对于depth <=4 的情况,既不使用颜色表,也不使用调色板,
//image.data中直接存入像素信息,而不是颜色表或者调色板的索引
if (fb_logo.depth <= 4)
logo_new = kmalloc(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);
//logo显示的起始坐标
image.dx = 0;
image.dy = y;
//logo图像的宽高
image.width = logo->width;
image.height = logo->height;
//根据旋转方式调整图像
if (rotate)
logo_rotate = kmalloc(logo->width *
logo->height, GFP_KERNEL);
if (logo_rotate)
fb_rotate_logo(info, logo_rotate, &image, rotate);
//执行logo显示
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 logo->height;
传参 | 注释 |
---|---|
info | 帧缓冲设备描述结构 |
rotate | 屏幕旋转方式 |
logo | 待显示的 Logo 图像 logo(实际上是 fb_logo.logo) |
y | logo显示起始坐标的y值 |
n | 系统 CPU 数量 |
3、制作ppm文件
//安装工具包
sudo apt-get install netpbm
//将名字为logo.png的图像,转换成logo_linux_clut224.ppm文件
pngtopnm logo.png | ppmquant -fs 224 | pnmtoplainpnm > logo_linux_clut224.ppm
(1)上面是利用命令pngtopnm & ppmquant & pnmtoplainpnm来将png格式图像转换成ppm格式图像,如果linux中没有相关命令则要先安装命令包;
(2)在上面的命令中,注意图片文件的名字和你实际的对应上,放到内核源码中放ppm格式文件的目录下;
4、ppm文件自动转换成C源文件
obj-$(CONFIG_LOGO) += logo.o
obj-$(CONFIG_LOGO_LINUX_MONO) += logo_linux_mono.o
obj-$(CONFIG_SPU_BASE) += logo_spe_clut224.o
//添加宏进行控制
obj-$(CONFIG_LOGO_X210_CLUT224) += logo_x210_clut224.o
# Use logo-cfiles to retrieve list of .c files to be built
logo-cfiles = $(notdir $(patsubst %.$(2), %.c, \\
$(wildcard $(srctree)/$(src)/*$(1).$(2))))
# Mono logos
extra-y += $(call logo-cfiles,_mono,pbm)
# VGA16 logos
extra-y += $(call logo-cfiles,_vga16,ppm)
# 224 Logos
extra-y += $(call logo-cfiles,_clut224,ppm)
# Gray 256
extra-y += $(call logo-cfiles,_gray256,pgm)
pnmtologo := scripts/pnmtologo
# Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..."
quiet_cmd_logo = LOGO $@
cmd_logo = $(pnmtologo) \\
-t $(patsubst $*_%,%,$(notdir $(basename $<))) \\
-n $(notdir $(basename $<)) -o $@ $<
$(obj)/%_mono.c: $(src)/%_mono.pbm $(pnmtologo) FORCE
$(call if_changed,logo)
$(obj)/%_vga16.c: $(src)/%_vga16.ppm $(pnmtologo) FORCE
$(call if_changed,logo)
#将ppm格式转换成c语言文件
$(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE
$(call if_changed,logo)
$(obj)/%_gray256.c: $(src)/%_gray256.pgm $(pnmtologo) FORCE
$(call if_changed,logo)
# Files generated that shall be removed upon make clean
clean-files := *.o *_mono.c *_vga16.c *_clut224.c *_gray256.c
(1)上面是内核中放ppm格式文件目录的Makefile,在匹配规则中,有将各种pbm、ppm等格式的图像转换成C语言文件的规则;
(2)规则的匹配是根据文件的后缀名来匹配,所以我们要注意对ppm文件的名字命名要以"_clut224"结尾;
(3)通过宏控制要编译哪些ppm格式的文件;
5、转换得到的logo_linux_clut224.c文件
static unsigned char logo_x210_clut224_data[] __initdata =
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
······
static unsigned char logo_x210_clut224_clut[] __initdata =
0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x19, 0x09, 0x18, 0x36, 0x14,
······
const struct linux_logo logo_x210_clut224 __initconst =
.type = LINUX_LOGO_CLUT224, //图像类型
.width = 800, //宽
.height = 480, //高
.clutsize = 102, //颜色对照表大小
.clut = logo_x210_clut224_clut, //颜色对照表
.data = logo_x210_clut224_data //Logo 图像数据
;
(1)主要就是构建一个struct linux_logo结构体,这是内核用来描述logo图像信息的结构体;
(2)注意这个结构体的名字是和文件名一致的;
6、ppm文件如何与内核源码关联
(1)ppm格式转换成c语言文件,是根据文件的后缀名去Makefile中进行规则的匹配,自动完成编译;
(2)C语言文件中主体就是struct linux_logo结构体,名字和c文件的名字一致;
(3)在内核源码中就是匹配转换得到的struct linux_logo结构体;
7、替换内核启动logo图像
(1)制作ppm格式的文件,注意文件名字的后缀要符合Makefile的匹配规则,并且图像大小不能超过显示屏的分辨率;
(2)修改ppm文件同级的Makefile文件,按照其他的ppm文件的添加方式,通过宏进行控制;
(3)在内核源码的fb_find_logo()函数中,添加新生成的struct linux_logo结构体变量;
8、修改启动logo图像显示位置
修改fb_show_logo_line()函数中logo显示的起始坐标;
以上是关于linux显示启动logo源码分析以及修改显示logo的主要内容,如果未能解决你的问题,请参考以下文章