(本文主要内容来自《深度实践嵌入式linux系统移植》)
一、帧缓存
一般的显示设备,都会有一个叫做“显存”的东西,一些高端设备(PC中的显卡)会有自己独立的显存,而在一些嵌入式设备中则是从内存中分出一块用来作为显存;因此简单的说,所谓显存就是实在的一些存储空间;而帧缓存(Frame Buffer)从本质上讲是图形设备的硬件抽象,换句话说就是这些显存的抽象。
1、帧缓存的设备文件
在linux操作系统中,所有的设备都会在dev目录下形成特定的设备节点。帧缓冲设备对应的设备文件为/dev/fb*,该设备最多支持32个,分别为fb0到fb31,而fb则为当前缺省的嵌入式设备,通常指向fb0,帧缓冲设备为标准的字符设备,主设备号为29,次设备号则从0到31。
2、直接操作帧缓存
可以使用下面的具体操作来印证上面的基础理论
dd if=/dev/zero of=/dev/fb0 bs=240 count=320
上面的命令为内存文件拷贝命令,if后面跟的为被拷贝的文件(i表示输入),of后面跟的为拷贝至哪个文件(o表示输出),bs表示的内存块大小,在此为(240字节,图像大小为240*320),count为拷贝的内存块个数;因此上面的命令执行后,则帧缓存应该全部被置0;相应的屏幕应该全部为黑 {MOD},就是黑屏!也可以将实际的图片显示到屏幕上,操作命令如下:
cat 7.bmp >/dev/fb0
二、linux帧缓冲子系统
1、linux帧缓冲子系统总体框架图
2、主要的数据结构及操作
(1)fb_info结构(该结构位于include/linux/fb.h)
struct fb_info {
int node;
int flags;
struct mutex lock; /* Lock for open/release/ioctl funcs */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
#ifdef CONFIG_FB_BACKLIGHT
/* assigned backlight device */
/* set before framebuffer registration,
remove after unregister */
struct backlight_device *bl_dev;
/* Backlight level curve */
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
struct delayed_work deferred_work;
struct fb_deferred_io *fbdefio;
#endif
struct fb_ops *fbops;
struct device *device; /* This is the parent */
struct device *dev; /* This is this fb device */
int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
char __iomem *screen_base; /* Virtual address */
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* Hardware state i.e suspend */
void *fbcon_par; /* fbcon use-only private area */
/* From here on everything is device dependent */
void *par;
};
从上面框架图可以知道,每个帧缓冲设备都必须对应一个fb_info;分配fb_info对象的接口是frame_alloc(),其原型如下
struct fb_info *framebuffer_alloc(size_t size,struct device *dev);
其中size指定帧缓冲设备私有数据大小,dev指定控制器的父设备对象;在分配了fb_info对象后,一般需要将该对象注册到内核中,具体的注册函数如下
int register_framebuffer(struct fb_info *fb_info);
注册的具体流程为:
1、判断num_registered_fb(该全局变量表示当前系统中已有的帧缓冲设备数量)是否等于FB_MAX,是则返回-ENXIO;然后调用fb_check_foreignness(),判断fb_info->flags标志中关于控制器大小端的设置是否正确,不正确则返回-ENOSYS。
2、如果上面两个检测都通过了,则num_registered_fb自增1,并在数组registered_fb(存放当前系统中所有帧缓冲设备的fb_info结构指针)找到为空的项,将该项在数组中的索引i赋值给fb_info->node,同时将fb_info对象放入registered_fb[i]项中。
3、调用device_create()创建设备对象并返回给fb_info->dev,该调用还会导致用户空间创建设备号为MKDEV(FB_MAJOR,i),名称为“fb%d”(%d由i决定)的设备文件,如果device_create返回成功,则还会调用fb_init_device在sysfs中创建更多的属性文件
4、判断fb_info->pixmap.addr是否为空,如果是则为图像硬件映射器分配FBPIXMAPSIZE宏指定大小空间,默认是8192字节,并将fb_info->pixmap主要成员设为默认。
。。。。
函数返回0.
(2)fb_var_screeninfo结构和fb_fix_screeninfo结构
在上面的fb_info结构中有这样两个重要的结构体成员,他们分别表示帧缓冲设备的可变参数和固定参数;他们的声明都在include/linux/fb.h文件中
a、fb_var_screeninfo
struct fb_var_screeninfo {
__u32 xres; /* visible resolution可视屏幕分辨率 */
__u32 yres;
__u32 xres_virtual; /* virtual resolution虚拟屏幕分辨率 */
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible 虚拟屏幕到可视屏幕之间的偏移*/
__u32 yoffset; /* resolution */
__u32 bits_per_pixel; /* guess what每像素所占的位数,简称bpp */
__u32 grayscale; /* != 0 Graylevels instead of colors 非0时灰度显示*/
struct fb_bitfield red; /* bitfield in fb mem if true color, 红 {MOD}位域*/
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency 透明 */
__u32 nonstd; /* != 0 Non standard pixel format */
__u32 activate; /* see FB_ACTIVATE_* */
__u32 height; /* height of picture in mm 屏幕以毫米为单位度量的几何高度 */
__u32 width; /* width of picture in mm */
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 reserved[5]; /* Reserved for future compatibility */
};
为了介绍上面的结构体中的几个时序成员,我们先来看一张通用LCD的时序图
对于接触过驱动的人都知道,器件的时序图对于设备驱动具有至关重要的作用,因此,下面挑出几个比较有意义的简要说明下
1、VBPD:表示在一帧图像开始时,帧同步信号后无效的行数(upper_margin)
2、VFPD:表示在一帧图像结束后,帧同步信号前无效的行数(lower_margin)
3、HBPD:表示从行同步信号有效后,到实际的像素信息之间无效的像素时钟个数(left_margin)
4、HFPD:表示一行的有效数据结束到下一个行同步信号开始之间的像素时钟个数(right_margin)
在上面的结构中还有一个值得提及的概念,那就是虚拟屏幕和可视屏幕,整个帧缓存称为虚拟屏幕,而在屏幕中显示的称为可视屏幕,实际情况如图所示
b、fb_fix_screeninfo
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len; /* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Indicate to driver which */
/* specific chip/card we have */
__u16 reserved[3]; /* Reserved for future compatibility */
};
上面的结构体中有两个成员需要提及,帧缓存存储类型type和屏幕可视模式visual,像素在内存中存储格式是硬件相关的,驱动程序根据硬件需求,将正确格式的图像数据放入帧缓存,才能正常驱动硬件显示,像素格式正是由帧缓存存储类型和可视模式两个因素决定的,可视模式决定使用哪种方式描述一个像素,而存储类型决定像素在帧缓存中的存放方法。
三、platform驱动模型
最后再介绍下关于platform驱动模型的概念,platform驱动主要是通过总线来匹配设备和驱动,一般都是在当前的机器资源文件中注册platform设备,然后再在驱动文件中注册驱动,这两项的名称相同,而总线则是根据注册的名称来将他们联系起来。