1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Linux内核启动logo

Linux内核启动logo

时间:2023-04-22 09:39:02

相关推荐

Linux内核启动logo

之前在分析samsung的fb驱动代码的时候,其中有一段代码是处理内核logo显示相关的,今天就内核logo这个话题来聊一聊!

一、处理内核logo显示相关的代码在哪?

回到samsung的fb驱动代码中,因为fb的驱动代码是基于platform平台总线编写的,所以我们需要找到platform_driver结构体中的probe函数,如下所示:

1、函数执行流程

/***********************************************************************/

s3cfb_probe // "drivers\video\samsung\s3cfb.c"

fb_prepare_logo // 准备logo文件,也就是去找到需要显示的logo文件 "drivers\video\fbmem.c"

fb_find_logo // 找到logo文件 "drivers\video\logo\logo.c"

fb_show_logo // 显示logo "drivers\video\fbmem.c"

fb_show_logo_line // 真正的显示logo的函数 "drivers\video\fbmem.c"

fb_do_show_logo // "drivers\video\fbmem.c"

info->fbops->fb_imageblit(info, image) // 最终操作fb硬件进行显示工作的函数

/***********************************************************************/

从上面可以知道:fb_prepare_logo 和fb_show_logo 都是定义在"drivers\video\fbmem.c" 文件中的,而这个文件之前说过,他是属于fb驱动框架源代码的文件,所以可以知道

上面的处理内核启动logo显示的函数是fb驱动框架提供的,也就是说是由fb驱动框架支持的。

(1)fb_find_logo函数分析:

1 const struct linux_logo * __init_refok fb_find_logo(int depth) 2 { 3const struct linux_logo *logo = NULL; /* 定义一个linux_logo结构体指针变量 */ 4 5if (nologo) 6 return NULL; 7 8if (depth >= 1) { /* 如果depth >= 1 选择下面的logo文件 */ 9 #ifdef CONFIG_LOGO_LINUX_MONO10 /* Generic Linux logo */11 logo = &logo_linux_mono;12 #endif13 #ifdef CONFIG_LOGO_SUPERH_MONO14 /* SuperH Linux logo */15 logo = &logo_superh_mono;16 #endif17}1819if (depth >= 4) { /* 如果depth >= 4 选择下面的logo文件 */ 20 #ifdef CONFIG_LOGO_LINUX_VGA1621 /* Generic Linux logo */22 logo = &logo_linux_vga16;23 #endif24 #ifdef CONFIG_LOGO_BLACKFIN_VGA1625 /* Blackfin processor logo */26 logo = &logo_blackfin_vga16;27 #endif28 #ifdef CONFIG_LOGO_SUPERH_VGA1629 /* SuperH Linux logo */30 logo = &logo_superh_vga16;31 #endif32}3334if (depth >= 8) { /* 如果depth >= 8 选择下面的logo文件 */ 35 #ifdef CONFIG_LOGO_LINUX_CLUT22436 /* Generic Linux logo */37 logo = &logo_linux_clut224;38 #endif39 #ifdef CONFIG_LOGO_LINUX_FULL_CLUT22440 /* Full screen Linux logo */41 logo = &logo_linux_full_clut224;42 #endif43 // lqm added44 #ifdef CONFIG_LOGO_X210_CLUT22445 /* x210 android logo */46 logo = &logo_x210_clut224; 47 #endif48 // end added.49 #ifdef CONFIG_LOGO_BLACKFIN_CLUT22450 /* Blackfin Linux logo */51 logo = &logo_blackfin_clut224;52 #endif53 #ifdef CONFIG_LOGO_DEC_CLUT22454 /* DEC Linux logo on MIPS/MIPS64 or ALPHA */55 logo = &logo_dec_clut224;56 #endif57 #ifdef CONFIG_LOGO_MAC_CLUT22458 /* Macintosh Linux logo on m68k */59 if (MACH_IS_MAC)60 logo = &logo_mac_clut224;61 #endif62 #ifdef CONFIG_LOGO_PARISC_CLUT22463 /* PA-RISC Linux logo */64 logo = &logo_parisc_clut224;65 #endif66 #ifdef CONFIG_LOGO_SGI_CLUT22467 /* SGI Linux logo on MIPS/MIPS64 and VISWS */68 logo = &logo_sgi_clut224;69 #endif70 #ifdef CONFIG_LOGO_SUN_CLUT22471 /* Sun Linux logo */72 logo = &logo_sun_clut224;73 #endif74 #ifdef CONFIG_LOGO_SUPERH_CLUT22475 /* SuperH Linux logo */76 logo = &logo_superh_clut224;77 #endif78 #ifdef CONFIG_LOGO_M32R_CLUT22479 /* M32R Linux logo */80 logo = &logo_m32r_clut224;81 #endif82}83return logo;84 }

// include\linux\linux_logo.h

1 extern const struct linux_logo logo_linux_mono; 2 extern const struct linux_logo logo_linux_vga16; 3 extern const struct linux_logo logo_linux_clut224; 4 extern const struct linux_logo logo_linux_full_clut224; 5 extern const struct linux_logo logo_blackfin_vga16; 6 extern const struct linux_logo logo_blackfin_clut224; 7 extern const struct linux_logo logo_dec_clut224; 8 extern const struct linux_logo logo_mac_clut224; 9 extern const struct linux_logo logo_parisc_clut224;10 extern const struct linux_logo logo_sgi_clut224;11 extern const struct linux_logo logo_sun_clut224;12 extern const struct linux_logo logo_superh_mono;13 extern const struct linux_logo logo_superh_vga16;14 extern const struct linux_logo logo_superh_clut224;15 extern const struct linux_logo logo_m32r_clut224;16 extern const struct linux_logo logo_spe_clut224;17 extern const struct linux_logo logo_x210_clut224;

从函数可以看出,根据色深depth的大小和相应的宏定义来选择我们所需要的logo文件,函数中的linux_logo类型变量是会被重复赋值,只有最后一个赋值的logo才是真正的显示的logo文件。

函数中用到的所有linux_logo类型的变量都是在 "include\linux\linux_logo.h" 文件中进行了申明,每一个变量其实就是对应一个logo文件(注意内核中的提供的logo文件都是ppm格式的

文件,内核中的代码能够识别这种格式并进行显示)。

(2)所以我们如果想要自定义一个内核启动显示logo,应该怎么做?

1):首先我们应该先提供一个ppm格式的logo文件(例如:logo_xxx_clut224.ppm)

2):将logo文件放在内核源码树drivers\video\logo 目录下

3):在include\linux\linux_logo.h 文件中申明logo文件变量 (extern const struct linux_logo logo_xxx_clut224)

4):在drivers\video\logo\logo.c 文件中的fb_find_logo 添加如下

#ifdef CONFIG_LOGO_XXX_CLUT224

logo = &logo_xxx_clut224;

#endif

5):修改 drivers\video\logo目录下的Makefile 和 Kconfig,能够实现通过make menuconfig进行动态配置

(3)struct linux_logo结构体

(4)fb_show_logo_line函数分析:

1 static int fb_show_logo_line(struct fb_info *info, int rotate, 2 const struct linux_logo *logo, int y, 3 unsigned int n) 4 { 5u32 *palette = NULL, *saved_pseudo_palette = NULL; 6unsigned char *logo_new = NULL, *logo_rotate = NULL; 7struct fb_image image;/* 定义一个fb_image类型的结构体变量,这个结构体就是用来描述在LCD上显示的logo的信息 */ 8 9/* Return if the frame buffer is not mapped or suspended */10if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||11 info->flags & FBINFO_MODULE)12 return 0;13 14image.depth = 8;15image.data = logo->data;16 17if (fb_logo.needs_cmapreset)18 fb_set_logocmap(info, logo);19 20if (fb_logo.needs_truepalette ||21 fb_logo.needs_directpalette) {22 palette = kmalloc(256 * 4, GFP_KERNEL);23 if (palette == NULL)24 return 0;25 26 if (fb_logo.needs_truepalette)27 fb_set_logo_truepalette(info, logo, palette);28 else29 fb_set_logo_directpalette(info, logo, palette);30 31 saved_pseudo_palette = info->pseudo_palette;32 info->pseudo_palette = palette;33}34 35if (fb_logo.depth <= 4) {36 logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);37 if (logo_new == NULL) {38 kfree(palette);39 if (saved_pseudo_palette)40 info->pseudo_palette = saved_pseudo_palette;41 return 0;42 }43 image.data = logo_new;44 fb_set_logo(info, logo, logo_new, fb_logo.depth);45}46 47image.dx = 0;/* 在LCD上显示的logo图标的起始水平位置(以像素为单位) */ 48image.dy = y;/* 在LCD上显示的logo图标的起始垂直位置(以像素为单位) */49image.width = logo->width; /* 在LCD上显示的logo图标的宽度(以像素为单位) */50image.height = logo->height; /* 在LCD上显示的logo图标的高度(以像素为单位) */51 52if (rotate) {53 logo_rotate = kmalloc(logo->width *54 logo->height, GFP_KERNEL);55 if (logo_rotate)56 fb_rotate_logo(info, logo_rotate, &image, rotate);57}58 59fb_do_show_logo(info, &image, rotate, n); 60 61kfree(palette);62if (saved_pseudo_palette != NULL)63 info->pseudo_palette = saved_pseudo_palette;64kfree(logo_new);65kfree(logo_rotate);66return logo->height;67 }

函数中有这么一段:

就是用来控制LCD上显示的logo图标在LCD屏幕上的位置,通过分析上层函数可知,image.dy = 0,所以由此可知,内核启动之后logo默认显示在LCD的左上角

所以如果我们需要修改logo图标的位置和大小,则可以通过修改这4个参数来达到我们的要求。

二、修改内核启动logo(自定义logo文件、修改logo图标在LCD上的显示位置)

1、制作ppm格式的logo文件

ppm也是一种图片的格式,但是一般的图片都不是这种格式,所以我们需要将一个logo图片文件转换成ppm格式的文件,所以这里我们需要在Linux中安装这个格式转换工具,

也就是netpbm工具。

sudo apt-get install netpbm // 可以直接在线安装,首先是你的虚拟机能够上网

工具安装成功之后,我们就可以使用工具制作一个ppm格式的logo文件:

pngtopnm logo.png | ppmquant -fs 224 | pnmtoplainpnm >logo_xxx_clut224.ppm // logo.png就是我们提供的png格式的logo源文件,logo_xxx_clut224.ppm

// 就是最后生成的ppm格式的logo文件

需要注意的是:我们制作好的ppm格式的logo文件的文件名最好是以 _clut224.ppm、_vga16.ppm结尾,因为在这个drivers/video/logo/Makefile 文件中会处理以这些名字

结尾的logo文件,这样可以避免很多的问题。

2、将制作好的ppm格式的logo文件放入内核源码目录drivers/video/logo 目录下

3、在include\linux\linux_logo.h 文件中申明:

extern const struct linux_logo logo_xxx_clut224; // 我们只需要仿照里面写的代码

4、在drivers\video\logo\logo.c 文件中的fb_find_logo 函数中添加一个宏控制编译条件

#ifdef CONFIG_LOGO_XXX

logo = &logo_xxx_clut224;

#endif

5、修改drivers\video\logo 目录下的Makefile文件和Kconfig文件,使其能够支持在内核进行make menuconfig配置时能够对显示的logo进行配置

例如在Kconfig中添加:

config LOGO_XXX_CLUT224

bool "linux logo !!!"

default y

例如在Makefile中添加:

obj-$(CONFIG_LOGO_XXX_CLUT224) += logo_xxx_clut224.o

6、如果我们需要修改logo图标的显示位置,则需要修改之前说的那4个参数,默认是显示在LCD的左上角,如果我们需要将logo显示在LCD的中间,可以将参数修改为下面的方式:

image.dx = (info->var.xres - logo->width) / 2;

image.dy = (info->var.yres - logo->height) / 2;

因为调用fb_show_logo_line 函数的时候会将设备的 fb_info(携带了LCD的硬件信息) 结构体变量 和 Linux_logo(携带了logo文件的信息) 结构体变量传进来,

所以我们是可以在函数中获取的,而不需要将代码写成静态的形式,这样影响移植。

至此,本篇文章就已经写完了,,欢迎大家指出错误!!!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。