1 Linux帧缓冲子系统
帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,它把显示设备描述成一个缓冲区,允许应用程序在图形模式下直接对显示显示缓冲区进行读写操作。
帧缓冲是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。通过不断的向帧缓冲写入数据,显示控制器就自动的从帧缓冲中读取数据并显示出来。帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显示设备,Linux下还可支持多个帧缓冲设备,最多可达32个,分别为/dev/fb0~fb31,帧缓冲设备为字符设备,主设备号为29,次设备号则从0~31。
Linux帧缓冲子系统的层次结构图:
帧缓冲子系统由帧缓冲设备层和控制器驱动组成。帧缓冲设备层在drivers/video/fbmem.c中实现,向上给应用程序提供完善的设备文件操作接口,向下提供硬件操作接口。控制器驱动命名为xxxfb.c文件。
2 显示缓冲区和显示点
在帧缓冲设备中,对屏幕显示点的操作通过读写显示缓冲区来完成,在不同的色彩模式下,显示缓冲区和屏幕上的显示点有不同的对应关系。
这里主要介绍16位色:
位 |
15~11 |
10~5 |
4~0 |
RGB565 |
R |
G |
B |
3 帧缓冲数据结构
(1)fb_info
fb_info是帧缓冲子系统中最重要的结构(FBI)。它记录了帧缓冲设备的全部信息,包括设备的设置参数、状态以及操作函数指针。每一个帧缓冲设备都必须对应一个fb_info。
1 /* include/linux/fb.h */ 2 struct fb_info { 3 atomic_t count; 4 int node; 5 int flags; 6 struct mutex lock; // 用于open/release/ioctl的锁 7 struct mutex mm_lock; 8 struct fb_var_screeninfo var; // 可变参数 9 struct fb_fix_screeninfo fix; // 固定参数 10 struct fb_monspecs monspecs; // 显示器标准 11 struct work_struct queue; // 帧缓冲事件队列 12 struct fb_pixmap pixmap; // 图像硬件mapper 13 struct fb_pixmap sprite; // 光标硬件mapper 14 struct fb_cmap cmap; // 目前的颜色表 15 struct list_head modelist; 16 struct fb_videomode *mode; // 目前的video模式 17 18 #ifdef CONFIG_FB_BACKLIGHT 19 /* 对应的背光设备 */ 20 struct backlight_device *bl_dev; 21 22 /* 背光调整 */ 23 struct mutex bl_curve_mutex; 24 u8 bl_curve[FB_BACKLIGHT_LEVELS]; 25 #endif 26 #ifdef CONFIG_FB_DEFERRED_IO 27 struct delayed_work deferred_work; 28 struct fb_deferred_io *fbdefio; 29 #endif 30 31 struct fb_ops *fbops; // fb_ops帧缓冲操作 32 struct device *device; // 父设备 33 struct device *dev; // fb设备 34 int class_flag; // 私有sysfs标志 35 #ifdef CONFIG_FB_TILEBLITTING 36 struct fb_tile_ops *tileops; // 图块Blitting 37 #endif 38 char __iomem *screen_base; // 虚拟基地址 39 unsigned long screen_size; // ioremapped的虚拟内存大小 40 void *pseudo_palette; // 伪16色颜色表 41 #define FBINFO_STATE_RUNNING 0 42 #define FBINFO_STATE_SUSPENDED 1 43 u32 state; // 硬件状态,如挂起 44 void *fbcon_par; 45 void *par; 46 struct apertures_struct { 47 unsigned int count; 48 struct aperture { 49 resource_size_t base; 50 resource_size_t size; 51 } ranges[0]; 52 } *apertures; 53 54 bool skip_vt_switch; 55 };
(2)fb_ops
在fb_info结构体中包含了一个重要的操作集合,即fb_ops,描述了特定帧缓冲设备的具体操作方法。
1 /* include/linux/fb.h */ 2 struct fb_ops { 3 /* 打开/释放 */ 4 struct module *owner; 5 int (*fb_open)(struct fb_info *info, int user); 6 int (*fb_release)(struct fb_info *info, int user); 7 8 /* 对于非线性布局的/常规内存映射无法工作的帧缓冲设备需要 */ 9 ssize_t (*fb_read)(struct fb_info *info, char __user *buf, 10 size_t count, loff_t *ppos); 11 ssize_t (*fb_write)(struct fb_info *info, const char __user *buf, 12 size_t count, loff_t *ppos); 13 14 /* 检测可变参数,并调整到支持的值 */ 15 int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); 16 17 /* 根据info->var设置video模式 */ 18 int (*fb_set_par)(struct fb_info *info); 19 20 /* 设置color寄存器 */ 21 int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, 22 unsigned blue, unsigned transp, struct fb_info *info); 23 24 /* 批量设置color寄存器,设置颜色值 */ 25 int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); 26 27 /* 显示空白 */ 28 int (*fb_blank)(int blank, struct fb_info *info); 29 30 /* pan显示 */ 31 int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info); 32 33 /* 矩形填充 */ 34 void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); 35 /* 数据复制 */ 36 void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); 37 /* 图形填充 */ 38 void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); 39 40 /* 绘制光标 */ 41 int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); 42 43 /* 旋转显示 */ 44 void (*fb_rotate)(struct fb_info *info, int angle); 45 46 /* 等待blit空闲(可选) */ 47 int (*fb_sync)(struct fb_info *info); 48 49 /* fb特定的ioctl(可选) */ 50 int (*fb_ioctl)(struct fb_info *info, unsigned int cmd, 51 unsigned long arg); 52 53 /* 处理32位的compat ioctl(可选) */ 54 int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd, 55 unsigned long arg); 56 57 /* fb特定的mmap */ 58 int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); 59 60 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps, 61 struct fb_var_screeninfo *var); 62 63 /* teardown any resources to do with this framebuffer */ 64 void (*fb_destroy)(struct fb_info *info); 65 66 /* called at KDB enter and leave time to prepare the console */ 67 int (*fb_debug_enter)(struct fb_info *info); 68 int (*fb_debug_leave)(struct fb_info *info);
- fb_check_var()成员函数用于检查可变的屏幕参数并调整到合适的值;
- fb_set_par()则使得用户设置的屏幕参数在硬件上有效。
(3)fb_var_screeninfo/fb_fix_screeninfo
这两个结构用来描述帧缓冲设备的可变参数和固定参数,也是fb_info的成员var和fix的结构体类型。fb_var_screeninfo记录了帧缓冲设备和特定显示模式中设备无关的可变信息,可变是指能被用户空间修改,例如我们可以通过ioctl()命令FBIOGET_VSCREENINFO/FBIOPUT_VSCREENINFO获取和设置这些参数。
fb_fix_screeninfo记录了帧缓冲设备和特定显示模式中设备无关的不可变的信息,也就是说这些信息我们无法在用户空间修改,但可以通过ioctl命令FBIOGET_FSCREENINFO获取固定参数。
1 /* include/linux/fb.h */ 2 struct fb_var_screeninfo { 3 /* 可见分辨率 */ 4 __u32 xres; 5 __u32 yres; 6 /* 虚拟分辨率 */ 7 __u32 xres_virtual; 8 __u32 yres_virtual; 9 /* 虚拟到可见之间的偏移 */ 10 __u32 xoffset; 11 __u32 yoffset; 12 13 __u32 bits_per_pixel; // 每像素位数,BPP 14 __u32 grayscale; // 非0时指灰度 15 16 /* fb缓存的R\\G\\B位域 */ 17 struct fb_bitfield red; 18 struct fb_bitfield green; 19 struct fb_bitfield blue; 20 struct fb_bitfield transp; // 透明度 21 22 __u32 nonstd; // !=0非标准像素格式 23 24 __u32 activate; 25 26 __u32 height; // 高度 27 __u32 width; // 宽度 28 29 __u32 accel_flags; // 看fb_info.flags 30 31 /* 定时,除了pixclock本身外,其他的都以像素时钟为单位 */ 32 __u32 pixclock; // 像素时钟(皮秒) 33 __u32 left_margin; // 行切换,从同步到绘图之间的延迟 34 __u32 right_margin; // 行切换,从绘图到同步之间的延迟 35 __u32 upper_margin; // 帧切换,从绘图到同步之间的延迟 36 __u32 lower_margin; 37 __u32 hsync_len; // 水平同步的长度 38 __u32 vsync_len; // 垂直同步的长度 39 __u32 sync; 40 __u32 vmode; 41 __u32 rotate; // 顺时钟旋转的角度 42 __u32 colorspace; 43 __u32 reserved[4]; // 保留 44 };
重点关注xres、yres、xres_virtual、yres_virtual、xoffset和yoffset这几个成员。
由于LCD控制器或者图像显示卡所支持的最大帧缓冲内存可能大于屏幕可显示的像素内存,于是我们将帧缓冲中屏幕显示的部分称为可视屏幕,将整个帧缓冲内存称为虚拟屏幕。
接着看一下在真彩色可视模式下描述位域的结构fb_bitfield,它的定义如下:
struct fb_bitfield { _u32 offset; // 位域偏移 _u32 length; // 位域长度 _u32 msb_right; // 不等于0时表示最高有效位在右边 };
最后,说一下像素时钟pixclock以及用它度量的那些时序单位。pixclock表示在屏幕上绘制一个像素所用的时间,单位时皮秒(10-12秒)。通常LCD规格书都有“DCLK Frequency”的时序参数,表示在屏幕上绘制点的时钟频率(DCLK是Dot Clock的缩写)。
此结构体成员还有height、width这两个成员,本来它们的作用是描述屏幕以毫米为单位度量的几何尺寸,但由于这两个参数在内核中并没有实际使用,驱动中往往把它们赋值为屏幕的像素尺寸(即与xres和yres相同)。
下面来看看fb_fix_screeninfo这个结构,它的定义如下:
1 /* include/linux/fb.h */ 2 struct fb_fix_screeninfo { 3 char id[16]; // 标识符 4 unsigned long smem_start; // fb缓冲内存的开始位置(物理地址) 5 6 __u32 smem_len; // fb缓冲的长度 7 __u32 type; // FB_TYPE 8 __u32 type_aux; // Interleave 9 __u32 visual; // FB_VISUAL_* 10 __u16 xpanstep; // 如果没有硬件panning 赋0 11 __u16 ypanstep; 12 __u16 ywrapstep; 13 __u32 line_length; // 一行的字节数 14 unsigned long mmio_start; // 内存映射I/O的开始位置 15 16 __u32 mmio_len; // 内存映射I/O长度 17 __u32 accel; // 保留 18 19 __u16 capabilities; 20 __u16 reserved[2]; 21 };
(4)fb_cmap
fb_cmap结构体记录设备无关的颜色表信息,用户空间可以通过ioctl()命令FBIOGETCMAP和FBIOPUTCMAP读取和颜色表。
1 /* include/linux/fb.h */ 2 struct fb_cmap { 3 __u32 start; // 第1个元素入口 4 __u32 len; // 元素数量 5 /* R、G、B透明度 */ 6 __u16 *red; 7 __u16 *green; 8 __u16 *blue; 9 __u16 *transp; 10 };
4 帧缓冲接口
(1)framebuffer_alloc()
framebuffer_alloc()分配一个fb_info结构内存。
头文件 |
#include <linux/fb.h> |
函数原形 |
struct fb_info *framebuffer_alloc(size_t size, struct device *dev); |
函数参数 |
size:指定了帧缓冲设备私有数据的大小 |
dev:指定控制器的父设备对象,通常为NULL |
|
返回值 |
成功:返回指向fb_info结构的指针;失败:返回NULL |
(2)register_framebuffer()
register_framebuffer()函数用于注册帧缓冲设备。
头文件 |
#include <linux/fb.h> |
函数原形 |
int register_framebuffer(struct fb_info *fb_info); |
函数参数 |
fb_info:帧缓冲设备结构 |
返回值 |
成功:返回0;失败:返回相应的错误码(负数) |
(3)unregister_framebuffer()
unregister_framebuffer()函数用于注销帧缓冲设备。
头文件 |
#include <linux/fb.h> |
函数原形 |
int unregister_framebuffer(struct fb_info *fb_info); |
函数参数 |
fb_info:帧缓冲设备结构 |
返回值 |
成功:返回0;失败:返回相应的错误码(负数) |