1.显示系统(Display system) 架构
显示系统由核心层与各个组件(fb、crt等)部分,其架构图如图1所示。每个组件都是可装载卸载的,即系统不需要实现所有组件,仅需要激活一个组件就能使用该组件在组件指定的特性和范围中运行,本项目其它子系统都是采用这种可装载卸载组件的方法架构和设计的。
图1 显示系统(Display System)架构
Display system core:
显示系统的核心层,用于封装显示功能相关的复杂业务逻辑与数据交换,Book Engine 通过该层的API 与组件名(如 “fb”)来调用显示设备,而不直接放访问显示设备(如"fb")的内部函数。这样使得显示子系统变成一个可扩展的抽象框架,它的设备组件可以根据需要装载和卸载,系统可裁剪,不需要实现所有的组件。
2.显示系统API与核心函数概述
1). API 概述
display
system 的api 在 include/display.h 头文件中声明
display_dev:
显示系统的核心结构描述符 display_dev 的声明如下
typedef struct display_dev{
char *name;
struct disp_dev_attr attr;
int (*dev_init)(void);
int (*clr_screen)(__u32 back_color);
int (*disp_pixel)(int px, int py, __u32 color);
struct display_dev *next;
}display_dev;
attr :
xres, yres 分别存储着对应显示屏设备的x与y轴的分辨率,bpp(bits per pixel) 为显示屏每个像素二进制位数,一般有8、16、24、32这几种值。
dev_init()/clr_screen()/disp_pixel():
这三个函数模板需要开发者根据不同的显示设备相关的驱动与API来在对应的设备组件中实现,即fb、crt等显示设备的组件模块中实现,设备不同,实现方法亦不相同。
next:
显示设备链表,系统初始化时,将所有显示设备组件,注册挂载到该链表上,Book engine 可以在链表头通过设备来名字(name)来查找并激活相应的显示设备。
load_display_md():
被显示系统外部(Book Engine)调用,用于加载所有的被注册(register_display_md)的组件到系统中,加载之后,book engine则可以通过设备名获取设备的display_dev
描述符。
register_display_md():
在组件中被调用,将一个组件(如fb)注册到display system,以便该组件被load_display_md()函数之后加载到系统中。
print_disp_md_lst():
该函数用于调试,打印出系统中已经加载的显示设备组件,之后每个子系统核心层都将遇到该类似api。
select_main_scr_dev():
选择主屏幕的显示设备。目前电子书只支持在一个屏幕上显示(fb 或 crt),函数选中的主屏幕将被初始化激活,之后电子书内容将在该函数激活的显示屏上显示。
get_disp_dev():
通过设备名,在已经加载的显示设备组件中获取name所对应的display_dev 描述符。
get_dis_dev_res():
通过设备名,在已经加载的显示设备组件中设备对应的x与y轴分辨率。
2). 核心函数实现
display
system core 层的的核心函数在 display/display.c 文件中实现。
disp_dev_h:
显示设备的链表头,为display
system core 层的全局变量,所有支持的显示设备都将挂载到该链表上。
load_fb_md()
与 load_crt_md():
显示设备组件的加载函数,只在display.c
声明,在组件对应的C文件中实现,以后每添加一个组件,只需在此加上一个可配置的声明(用 #ifdef CONFIG_XXX 宏开关配置),这样load_display_md() 函数则可以通过该声明加载相关的显示系统组件。
其它核心函数基本作用在api概述中有介绍,主要是处理一些链表相关的业务逻辑,在此不再累述,可以直接参考实现的源代码来理解。
3.fb(Framebuffer)组件实现
本项目所使用的Smart210开发板,提供的S70
LCD电容触屏是一块7寸电容触屏,分辨率为800*480,bpp 是32位的。该LCD电容屏的像素、LCD与framebuffer内存的对应关系如图2所示。
图2 像素结构、LCD屏幕与framebuffer内存
fb组件的相关函数实现位于display/fb.c 源文件中。
开发环境底层相关声明:
Smart210开发板 厂商所提供Linux3.0.8 kernel中已经实现了fb设备驱动,在文件系统中,通过系统调用API访问/dev/fb0设备,即可直接操作底层的采用fb驱动的LCD显示器。在厂商提供的glibc工具链的
include/linux/fb.h 头文件中已经提供与底层fb驱动相关的结构封装。本项目只介绍系统应用编程,如果用户开发环境有差异(Linux kernel无fb驱动、fb设备名不是/dev/fb0、glibc库无 fb.h文件等), 需要查找其它环境相关资料解决相应问题,在此不再累述。
填充 struct display_dev 框架:
static struct display_dev fb_dev = {
.name = "fb",
.dev_init = fb_dev_init,
.clr_screen = fb_clr_screen,
.disp_pixel = fb_disp_pixel,
};
fb设备需要填充实现Display system core 中的相应的函数,并通过
register_display_md()函数将填充后的display_dev 描述符注册到Display system core 中以便上层系统通过API对其进行调用。
fb组件内部使用宏与结构:
typedef struct lcd_fb{
int fb_fd;
__u32 line_bytes;
__u32 pixel_bytes;
__u32 scr_bytes; /*bytes of one screen*/
unsigned char *fbmem;
}lcd_fb;
#define GET_BYTES_OF_LINE(var) (var.xres * var.bits_per_pixel / 8)
#define GET_BYTES_OF_PIXEL(var) (var.bits_per_pixel / 8)
#define GET_BYTES_OF_SCR(var) (var.xres * var.yres * var.bits_per_pixel / 8)
#define CLR_LCD_FB(fbmem,size,color) do{memset(fbmem, color, size);}while(0)
该部分结构与宏与系统framebuffer接口直接相关,只在fb组件中使用,外部无法直接调用。其中,lcd_fb 结构封装着fb设备的文件描述符(fb_fd),行字节数(line-bytes),像素字节(pixel_bytes),显示屏总字节数(scr_bytes),fb设备的framebuffer在DRAM内存中通过mmap方法映射的地址(fbmem)。
其它4个宏顾名思义,用于计算相关的字节数以及清屏。
fb_clr_screen() 与 fb_disp_pixel()实现中的bpp问题:
本系统实验平台采用的LCD显示屏是32位bpp的。但是为了使得该函数具有兼容性,能够兼容8bit 和 16bit bpp的LCD屏,因而在实现时,通过在设备初始化时通过fb_dev_init()获取当前LCD 实际bpp格式,然后在填充像素时,通过获取的bpp值,选择对应的bpp模式填充像素的字节变量。
本实验平台LCD是32位的bpp,其像素位结构如图2所示。实际用到的RGB颜 {MOD}位只有24位,另外8位 alpha值是透明度设置,在此可以忽略。因而只需直接在相关的RGB字节上填充相应的颜 {MOD},即可混合出所需颜 {MOD}。本实验平台采用的背景 {MOD}是泛黄 {MOD}(24位RGB颜 {MOD}码:0xE7DBB5),字体颜 {MOD}是褐 {MOD}(24位RGB颜 {MOD}码:0x514438)。
@韦东山原来的jz2440开发板电子书项目使用的是电阻屏,RGB是16位565结构的,所以需要对颜 {MOD}进行颜 {MOD}合成,用户可根据项目实际情况查找16位与8位RGB颜 {MOD}结构。
该模块其余业务逻辑相关细节,可以参考源代码,在此不再累述。
4.CRT组件实现
crt显示器的相关函数暂时空置,之后将采用svga开源库实现。