打印

原创:framebuffer理解

[复制链接]
3103|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
LPC300|  楼主 | 2010-1-20 11:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
FrameBuffer设备驱动基于如下两个文件:
1) linux/include/linux/fb.h
2) linux/drivers/video/fbmem.c

下面分析这两个文件。
1
fb.h

几乎主要的结构都是在这个中文件定义的。这些结构层次可以用下图描述:

structure map
struct fb_info_gen | struct fb_info | fb_var_screeninfo

|
| fb_fix_screeninfo


|
| fb_cmap


|
| modename[40]
模式

|
| fb_ops ---|--->ops on var


|

| ...
| fb_open


|
|
| fb_release


|
|
| fb_ioctl


|
|
| fb_mmap


| struct fbgen_hwswitch



\-----|-> detect

| encode_fix

| encode_var

| decode_fix

| decode_var

| get_var

| set_var

| getcolreg

| setcolreg

| pan_display


| blank

| set_disp


1) fb_info
定义当显卡的当前状态;fb_info结构仅在内核中可见,在这个结构中有一个fb_ops指针, 指向驱动设备工作所需的函数集。

struct fb_info {
char modename[40]; /* default video mode */ 默认的视频卡类型
struct fb_var_screeninfo var; /* Current var */ 现在的视频信息
struct fb_fix_screeninfo fix; /* Current fix */ 修正的信息
struct fb_cmap cmap; /* Current cmap */ 当前优先级
struct fb_ops *fbops;
};

2fb_var_screeninfo

这个结构描述了显示卡的特性:
NOTE::::
__u32 是表示 unsigned 不带符号的 32 bits 的数据类型,其余类推。这是 Linux 内核中所用到的数据类型,如果是开发用户空间(user-space)的程序,可以根据具体计算机平台的情况,用 unsigned long 等等来代替
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 resolution */ //可视区域的偏移
__u32 yoffset;

__u32 bits_per_pixel; /* guess what */
//每一象素的bit
__u32 grayscale; /* != 0 Gray levels instead of colors *///等于零就成黑白

struct fb_bitfield red; /* bitfield in fb mem if true color, */真彩的bit机构
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; /* acceleration flags (hints) */ 加速标志

/* 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 reserved[6]; /* Reserved for future compatibility */ 备用-以后开发
};

相关帖子

沙发
LPC300|  楼主 | 2010-1-20 11:09 | 只看该作者
3) fb_fix_screeninfon
这个结构在显卡被设定模式后创建,它描述显示卡的属性,并且系统运行时不能被修改 ;比如FrameBuffer内存的起始地址。它依赖于被设定的模式,当一个模式被设定后,内存信息由显示卡硬件给出,内存的位置等信息就不可以修改。

struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */ID
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 */内存映射的I/O起始
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */ I/O的大小
__u32 accel; /* Type of acceleration available */ 可用的加速类型
__u16 reserved[3]; /* Reserved for future compatibility */
};

4) fb_cmap
描述设备无关的颜色映射信息。可以通过FBIOGETCMAP 和 FBIOPUTCMAP 对应的ioctl操作设定或获取颜色映射信息.

struct fb_cmap {
__u32 start; /* First entry */ 第一个入口
__u32 len; /* Number of entries */ 入口的数字
__u16 *red; /* Red values */ 红
__u16 *green;
__u16 *blue;
__u16 *transp; /* transparency, can be NULL */ 透明,可以为零
};


5) struct fb_ops
用户应用可以使用ioctl()系统调用来操作设备,这个结构就是用一支持ioctl()的这些操作的。

struct fb_ops {
int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,struct fb_info *info);
/* get settable parameters */
int (*fb_get_var)(struct fb_var_screeninfo *var, int con,struct fb_info *info);
/* set settable parameters */
int (*fb_set_var)(struct fb_var_screeninfo *var, int con,struct fb_info *info);
};

2  fbmem.c
fbmem.c 处于Framebuffer设备驱动技术的中心位置 .它为上层应用程序提供系统调用也为下一层的特定硬件驱动提供接口;那些底层硬件驱动需要用到这儿的接口来向系统内核注册它们自己. fbmem.c 为所有支持FrameBuffer的设备驱动提供了通用的接口,避免重复工作.

1) 全局变量

struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;


这两变量记录了所有fb_info 结构的实例,fb_info 结构描述显卡的当前状态,所有设备对应的fb_info 结构都保存在这个数组中,当一个FrameBuffer设备驱动向系统注册自己时,其对应的fb_info 结构就会添加到这个结构中,同时num_registered_fb 为自动加1.

static struct {
const char *name;
int (*init)(void);
int (*setup)(void);
} fb_drivers[] __initdata= { ....};

如果FrameBuffer设备被静态链接到内核,其对应的入口就会添加到这个表中;如果是动态加载的,即使用insmod/rmmod,就不需要关心这个表。

static struct file_operations fb_ops ={
owner: THIS_MODULE,
read: fb_read,
write: fb_write,
ioctl: fb_ioctl,
mmap: fb_mmap,
open: fb_open,
release: fb_release
};
这是一个提供给应用程序的接口.

2)fbmem.c 实现了如下函数.

register_framebuffer(struct fb_info *fb_info);
unregister_framebuffer(struct fb_info *fb_info);

这两个是提供给下层FrameBuffer设备驱动的接口,设备驱动通过这两函数向系统注册或注销自己。几乎底层设备驱动所要做的所有事情就是填充fb_info结构然后向系统注册或注销它。
总结:
帧缓冲设备驱动file_operation 中VFS接口函数由fbmem.c文件统一实现。这样,驱动工程师的工作重点将是实现针对特定设备的fb_ops的成员函数,另外,理解并能灵活的修改fb_info中的var和fix参数非常关键。fb_info中的var参数直接和LCD控制器的硬件设置以及LCD屏幕对应。


相关网址:
http://blog.csdn.net/jwy1224/archive/2009/10/29/4744957.aspx
http://www.bitscn.com/linux/driver/200710/116237.html
http://verdure11.spaces.live.com ... 5EDA9AB6!1343.entry
http://blog.csdn.net/vrix/archive/2009/06/24/4293707.aspx
http://blog.chinaunix.net/u2/66601/showart_1860781.html

使用特权

评论回复
板凳
LPC300|  楼主 | 2010-1-20 11:10 | 只看该作者
framebuffer驱动编写流程:
编写一个帧缓冲设备驱动程序的主要工作分为5部分。
        编写初始化函数
        编写成员函数
        读/写(read/write)
        映射(map)
        输入/输出控制(I/O)
这里介绍前两个步骤:
1.        初始化函数
Framebuffer驱动首先要初始化LCD控制器,通过相关寄存器来设置LCD相对应的显示模式和颜色数,然后分配显示缓冲区。通常,用vmalloc()函数可以分配一段连续空间,缓冲区的大小可以用“点阵行数*点阵列数*一个像素的位数/8”计算得到。

习惯上,人们将缓冲区分配到容量相对较大的片外SDRAM中,起始地址保存在LCD控制器中。最后,函数会初始化一个fb_info()结构,填充成员变量,同时调用函数register_framebuffer(&fb_info),注册framebuffer驱动程序。

/drivers/video/fbmem.c/
extern int register_framebuffer(struct fb_info *fb_info)
extern int unregister_framebuffer(struct fb_Info *fb_info)
在调用register_framebuffer(struct fb_info *fb_info)之前,fb_info类型结构体必须进行初始化。
如果使用模块化加载方式,加载LCD驱动模块时,系统调用vfb_init()函数:卸载LCD驱动模块时,系统首先调用unregister_framebuffer()取消注册,然后释放显示缓冲区的内存。
通过分析代码可以看出,调用vfb_init()后,程序首先利用vmalloc()函数分配一个显示缓冲区;然后,设定fb_info()结构体中有关显示屏的各项参数,指明与fops()所对应的结构体,设定分辨率、颜色深度等可以设置参数;最后,register_framebuffer()分配一个fb_info()空间。
2、成员函数
这部分主要是编写fb_info结构体中指针fb_ops()对应的底层操作函数。对于嵌入式系统来说,主要实现以下结构中的3个函数:
Struct fb_ops{
……..
int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);
int (*fb_get_var)(struct fb_var_screeninfo *var, int con, struct fb_info *info);
int (*fb_set_var)(struct fb_var_screeninfo *var, int con,struct fb_info *info);
…….
}
从函数名可以看出,fb_get_fix()是取得fb_info()中用户层不能更改的成员变量,fb_get_var()是取得fb_info() 中用户层可以更改的成员变量,而fb_set_var是设置fb_info()中用户层可以更改的成员变量,当应用程序调用ioctl()操作时将会调用他们。
Static struct fb_ops vfb_ops={
fb_get_fix: vfb_get_fix
fb_set_var:vfb_get_var
fb_get_fix:vfb_set_var

……
}
给出了标准接口到针对具体硬件操作函数的跳转指针。编写驱动时,用户仅需要实现特定硬件的底层操作函数即可。用户应用程序通过ioctl()系统调用操作硬件,fb_ops 中的函数就用于支持这些操作。(注: fb_ops结构与file_operations 结构不同,fb_ops是底层操作的抽象,而file_operations是提供给上层系统调用的接口,可以直接调用.)
  ioctl()系统调用在文件fbmem.c中实现,通过观察可以发现ioctl()命令与fb_ops中函数的关系:
FBIOGET_VSCREENINFO fb_get_var
FBIOPUT_VSCREENINFO fb_set_var
FBIOGET_FSCREENINFO fb_get_fix
FBIOPUTCMAP fb_set_cmap
FBIOGETCMAP fb_get_cmap
FBIOPAN_DISPLAY fb_pan_display


如果我们定义了fb_XXX_XXX 方法,用户程序就可以使用FBIOXXXX宏的ioctl()操作来操作硬件。

使用特权

评论回复
地板
LPC300|  楼主 | 2010-1-20 11:10 | 只看该作者
第一个层次图显示的有问题,大家要是想看的话上网上搜一下,这图不是我的!呵呵!

使用特权

评论回复
5
Massif123| | 2010-1-20 11:19 | 只看该作者
好东东

使用特权

评论回复
6
LPC300|  楼主 | 2010-2-24 16:28 | 只看该作者
那是必须的。看的人很少啊。浪费了啊。!

使用特权

评论回复
7
huzixian| | 2010-3-11 23:24 | 只看该作者
见过的最好的frame buffer驱动!

使用特权

评论回复
8
linux1| | 2010-4-25 20:02 | 只看该作者
不错,是最好的frame buffer 驱动啊!呵呵!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

107

主题

525

帖子

0

粉丝