Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2998613
  • 博文数量: 674
  • 博客积分: 17881
  • 博客等级: 上将
  • 技术积分: 4849
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 10:15
文章分类

全部博文(674)

文章存档

2013年(34)

2012年(146)

2011年(197)

2010年(297)

分类: LINUX

2010-06-22 22:24:24

1、什么是framebuffer?

framebuffer是出现在内核中的驱动程序的接口
他把显示设备抽象的映射到帧缓冲区——可以认为是显存!

可以把它看成是显示内存的一个映像,将其映射到进程地址空间以后,就可以直接进行读写操作,并且写操作可以直接反应在屏幕上。

该驱动程序的设备文件一般是:

/dev/fb0
/dev/fb1
/dev/fb2
……

可以用命令: #dd if=/dev/zero of=/dev/fb 清空屏幕.
如果显示模式是 1024x768-8 位色,用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕;
用命令: #dd if=/dev/fb of=fbfile 可以将fb中的内容保存下来;
可以重新写回屏幕: #dd if=fbfile of=/dev/fb;

我们查看dev可以看到一共到fb31,说明一共有32个设备文件。

2、framebuffer的原理

framebuffer不具备任何运算数据的能力,好比一个暂时存放的水池。CPU好比闸门,经过运算后,把运算后的结果流放到显示器!CPU负担很大啊!O(∩_∩)O哈哈~

先看看下面的原理图:

在应用程序中,一般通过将FrameBuffer设备映射到进程地址空间的方式使用,比如下面的程序就打开/dev/fb0设备,并通过mmap系统调用 进行地址映射,随后用memset 将屏幕清空(这里假设显示模式是 1024×768-8 位色模式,线性内存模式):

int fb;
unsigned char* fb_mem;
fb = open ("/dev/fb0", O_RDWR);//打开设备
fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);//系统调用,并且进行地址映射
memset (fb_mem, 0, 1024*768);//将屏幕清空

说实话,我对mmap和mmset函数还不太了解:(Google一下,O(∩_∩)O哈哈哈~)

UNIX网络编程第二卷进程间通信对mmap函数进行了说明。该函数主要用途有三个:
1、将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能;
2、将特殊文件进行匿名内存映射,可以为关联进程提供共享内存空间;
3、为无关联的进程提供共享内存空间,一般也是将一个普通文件映射到内存中。

函数
:void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);

参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。

参数length:代表将文件中多大的部分映射到内存。

参数prot:映射区域的保护方式。可以为以下几种方式的组合:
PROT_EXEC 映射区域可被执行
PROT_READ 映射区域可被读取
PROT_WRITE 映射区域可被写入
PROT_NONE 映射区域不能存取

参数flags:影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。
MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。

参数fd:要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果。

参数offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。

返回值:

若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。

错误代码:

EBADF 参数fd 不是有效的文件描述词
EACCES 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。
EINVAL 参数start、length 或offset有一个不合法。
EAGAIN 文件被锁住,或是有太多内存被锁住。
ENOMEM 内存不足。

系统调用mmap()用于共享内存的两种方式:

(1)使用普通文件提供的内存映射:

适用于任何进程之间。此时,需要打开或创建一个文件,然后再调用mmap()

典型调用代码如下:

fd=open(name, flag, mode); if(fd<0) ...

ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0);

通过mmap()实现共享内存的通信方式有许多特点和要注意的地方,可以参看UNIX网络编程第二卷。

(2)使用特殊文件提供匿名内存映射:

适用于具有亲缘关系的进程之间。由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后调用 fork()。那么在调用fork()之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap()返回的地址,这样,父子进程就可以通过映射区 域进行通信了。注意,这里不是一般的继承关系。一般来说,子进程单独维护从父进程继承下来的一些变量。而mmap()返回的地址,却由父子进程共同维护。 对于具有亲缘关系的进程实现共享内存最好的方式应该是采用匿名内存映射的方式。此时,不必指定具体的文件,只要设置相应的标志即可。

3、framebuffer 相关的数据结构

(一)、分析Framebuffer设备驱动
    需要特别提出的是在INTEL平台上,老式的VESA 1.2 卡,如CGA/EGA卡,是不能支持Framebuffer的,因为Framebuffer要求显卡支持线性帧缓冲,即CPU可以访问显缓冲中的每一位,但是VESA 1.2 卡只能允许CPU一次访问64K的地址空间。
FrameBuffer设备驱动基于如下两个文件:
1) linux/include/linux/fb.h
2) linux/drivers/video/fbmem.c

下面分析这两个文件。
1、fb.h
   几乎主要的结构都是在这个中文件定义的。这些结构包括:
1)fb_var_screeninfo
   这个结构描述了显示卡的特性:
NOTE::::   __u32 是表示 unsigned 不带符号的 32 bits 的数据类型,其余类推。这是 Linux 内核中所用到的数据类型,如果是开发用户空间(user-space)的程序,可以根据具体计算机平台的情况,用 unsigned long 等等来代替
struct fb_var_screeninfo
{
__u32 xres; /* visible resolution */   //可视区域,X,Y方向的可见分辨率,表示可以看见的屏幕的大小
__u32 yres;
__u32 xres_virtual; /* virtual resolution */ //可视区域,x,y方向的虚拟分辨率,表四可以显示的屏幕的大小
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible resolution */ //x,y方向的可见分辨率和虚拟分辨率的偏移
__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 */ 备用-以后开发
};

2) 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_* */ 绝大多数用FB_TYPE_PACKED_PIXELS
__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 */ 可用的加速类型,一般用FB_ACCEL_NONE
__u16 reserved[3]; /* Reserved for future compatibility */
};

3) 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 */ 透明,可以为零
};

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

struct fb_info {
char modename[40]; /* default video mode */ framebuffer设备名称,在/proc/fb可见
kdev_t node;
int flags;
int open; /* Has this been open already ? */ 被打开过么?
#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
struct fb_var_screeninfo var; /* Current var */ 现在的视频信息
struct fb_fix_screeninfo fix; /* Current fix */ 修正的信息
struct fb_monspecs monspecs; /* Current Monitor specs */ 现在的显示器模式
struct fb_cmap cmap; /* Current cmap */ 当前优先级
struct fb_ops *fbops;
char *screen_base; /* Virtual address */ 物理基址
struct display *disp; /* initial display variable */初始化
struct vc_data *display_fg; /* Console visible on this display */
char fontname[40]; /* default font name */默认的字体
devfs_handle_t devfs_handle; /* Devfs handle for new name */
devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */兼容
int (*changevar)(int); /* tell console var has changed */ 告诉console变量修改了
int (*switch_con)(int, struct fb_info*);
/* tell fb to switch consoles */ 告诉fb选择consoles
int (*updatevar)(int, struct fb_info*);
/* tell fb to update the vars */ 告诉fb更新变量
void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */告诉fb使用黑白模式(或者不黑)
/* arg = 0: unblank */arg=0的时候黑白模式
/* arg > 0: VESA level (arg-1) */ arg>0时候选择VESA模式
void *pseudo_palette; /* Fake palette of 16 colors and
the cursor's color for non
palette mode */ 修正调色板
/* From here on everything is device dependent */ 现在就可以使用了
void *par;
};

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

struct fb_ops {
/* open/release and usage marking */
struct module *owner;
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user);
/* get non settable parameters */
int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);//获取struct fb_fix_screeninfo的结构信息
/* get settable parameters */
int (*fb_get_var)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);//获取struct fb_var_screeninfo的结构信息
/* set settable parameters */
int (*fb_set_var)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);//获取struct fb_var_screeninfo的结构信息
/* get colormap */
int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
/* set colormap */
int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
/* pan display (optional) */
int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, int con, struct fb_info *info);
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
/* switch to/from raster image mode */
int (*fb_rasterimg)(struct fb_info *info, int start);
};

6) 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


[编排有点困难,第一行的第一条竖线和下面的第一列竖线对齐,第一行的第二条竖线和下面的第二列竖线对齐就可以了]
这个结构 fbgen_hwswitch抽象了硬件的操作.虽然它不是必需的,但有时候很有用.

阅读(3274) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~