Linux源代码包中/document/fb/framebuffer.txt有例如以下介绍:
The frame buffer device provides an abstraction for the graphics hardware. It represents the frame buffer of some video hardware and allows application software to access the graphics hardware through a well-defined interface, so the software doesn't need to know anything about the low-level (hardware register) stuff.
Frame buffer机制为图形显示卡提供了一个抽象层。
能够使得应用程序不用考虑底层硬件的实现细节而通过一些API接口就可以訪问到显示设备。 但Framebuffer本身不具备不论什么运算数据的能力,就仅仅好比是一个临时存放水的水池。水池里的水就是显示的东西。CPU将运算后的结果放到这个水池,水池再将结果流到显示器(通常通过DMA传输). 所以应用程序通过读写这个水池。就可以相当于操作了显示卡。系统中能够在/dev/fb*看到framebuffer设备。
以下这幅图非常好的描写叙述了framebuffer执行机制:
framebuffer子系统的层次结构:
上图主要在以下文件里:
drivers/vedio/fbmem.c 该文件是framebuffer实现的核心。与硬件无关
drivers/vedio/xxxfb.c 该文件主要是framebuffer 设备驱动的实现,如s3c2410fb.c实现了framebuffer设备驱动
fbmem.c是实现framebuffer的核心。与硬件无关。
它使用了以下这些数据结构:
struct fb_info *fb_info 该数据结构描写叙述了一个framebuffer device相关一系列信息
struct fb_ops *fb_ops 该数据结构描写叙述了一个framebuffer device的操作函数集合。相似file_operations,但仅仅供内核使用
static const struct file_operations fb_fops 该数据结构为文件操作函数集合。当应用程序打开设备时。用户能够read,write,ioctl等
struct fb_var_screeninfo var 该数据结构描写叙述了framebuffer device显示特性,是能够更改的
struct fb_fix_screeninfo fix 该数据结构用于保存framebuffer device显示特性,是固定不变的,不能够更改
详细数据结构:
[cpp] view plain copy
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 */ __u32 grayscale; /* != 0 Graylevels instead of colors */ struct fb_bitfield red; /* bitfield in fb mem if true color, */ 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 */ };
[cpp] view plain copy
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 */ };
[cpp] view plain copy
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 */ ... 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 */ ... };
[cpp] view plain copy
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); /* For framebuffers with strange non linear layouts or that do not * work with normal memory mapped access */ ssize_t (*fb_read)(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos); ssize_t (*fb_write)(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos); /* checks var and eventually tweaks it to something supported, * DO NOT MODIFY PAR */ int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); /* set the video mode according to info->var */ int (*fb_set_par)(struct fb_info *info); /* set color register */ int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info); /* set color registers in batch */ int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); /* blank display */ int (*fb_blank)(int blank, struct fb_info *info); /* pan display */ int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info); /* Draws a rectangle */ void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); /* Copy data from area to another */ void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); /* Draws a image to the display */ void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); /* Draws cursor */ int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); /* Rotates the display */ void (*fb_rotate)(struct fb_info *info, int angle); /* wait for blit idle, optional */ int (*fb_sync)(struct fb_info *info); /* perform fb specific ioctl (optional) */ int (*fb_ioctl)(struct fb_info *info, unsigned int cmd, unsigned long arg); /* Handle 32bit compat ioctl (optional) */ int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd, unsigned long arg); /* perform fb specific mmap */ int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); /* save current hardware state */ void (*fb_save_state)(struct fb_info *info); /* restore saved state */ void (*fb_restore_state)(struct fb_info *info); /* get capability given var */ void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps, struct fb_var_screeninfo *var); };
[cpp] view plain copy
static const struct file_operations fb_fops = { .owner = THIS_MODULE, .read = fb_read, .write = fb_write, .check_flags = my_check, .unlocked_ioctl = fb_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = fb_compat_ioctl, #endif .mmap = fb_mmap, .open = fb_open, .release = fb_release, #ifdef HAVE_ARCH_FB_UNMAPPED_AREA .get_unmapped_area = get_fb_unmapped_area, #endif #ifdef CONFIG_FB_DEFERRED_IO .fsync = fb_deferred_io_fsync, #endif };
framebuffer设备的注冊与注销:
register_framebuffer(struct fb_info *fb_info);
unregister_framebuffer(struct fb_info *fb_info);
以下看看fb_ioctl 都做了什么?
static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { struct fb_ops *fb; struct fb_var_screeninfo var; struct fb_fix_screeninfo fix; struct fb_con2fbmap con2fb; struct fb_cmap cmap_from; struct fb_cmap_user cmap; struct fb_event event; void __user *argp = (void __user *)arg; long ret = 0;
switch (cmd) {
case FBIOGET\_VSCREENINFO:
if (!lock\_fb\_info(info))
return -ENODEV;
var = info->var;
unlock\_fb\_info(info);
ret = copy\_to\_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
break;
case FBIOPUT\_VSCREENINFO:
if (copy\_from\_user(&var, argp, sizeof(var)))
return -EFAULT;
if (!lock\_fb\_info(info))
return -ENODEV;
console\_lock();
info->flags |= FBINFO\_MISC\_USEREVENT;
ret = fb\_set\_var(info, &var);
info->flags &= ~FBINFO\_MISC\_USEREVENT;
console\_unlock();
unlock\_fb\_info(info);
if (!ret && copy\_to\_user(argp, &var, sizeof(var)))
ret = -EFAULT;
break;
case FBIOGET\_FSCREENINFO:
if (!lock\_fb\_info(info))
return -ENODEV;
fix = info->fix;
unlock\_fb\_info(info);
ret = copy\_to\_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
break;
case FBIOPUTCMAP:
if (copy\_from\_user(&cmap, argp, sizeof(cmap)))
return -EFAULT;
ret = fb\_set\_user\_cmap(&cmap, info);
break;
case FBIOGETCMAP:
if (copy\_from\_user(&cmap, argp, sizeof(cmap)))
return -EFAULT;
if (!lock\_fb\_info(info))
return -ENODEV;
cmap\_from = info->cmap;
unlock\_fb\_info(info);
ret = fb\_cmap\_to\_user(&cmap\_from, &cmap);
break;
case FBIOPAN\_DISPLAY:
if (copy\_from\_user(&var, argp, sizeof(var)))
return -EFAULT;
if (!lock\_fb\_info(info))
return -ENODEV;
console\_lock();
ret = fb\_pan\_display(info, &var);
console\_unlock();
unlock\_fb\_info(info);
if (ret == 0 && copy\_to\_user(argp, &var, sizeof(var)))
return -EFAULT;
break;
case FBIO\_CURSOR:
ret = -EINVAL;
break;
case FBIOGET\_CON2FBMAP:
if (copy\_from\_user(&con2fb, argp, sizeof(con2fb)))
return -EFAULT;
if (con2fb.console < 1 || con2fb.console > MAX\_NR\_CONSOLES)
return -EINVAL;
con2fb.framebuffer = -1;
event.data = &con2fb;
if (!lock\_fb\_info(info))
return -ENODEV;
event.info = info;
fb\_notifier\_call\_chain(FB\_EVENT\_GET\_CONSOLE\_MAP, &event);
unlock\_fb\_info(info);
ret = copy\_to\_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
break;
case FBIOPUT\_CON2FBMAP:
if (copy\_from\_user(&con2fb, argp, sizeof(con2fb)))
return -EFAULT;
if (con2fb.console < 1 || con2fb.console > MAX\_NR\_CONSOLES)
return -EINVAL;
if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB\_MAX)
return -EINVAL;
if (!registered\_fb\[con2fb.framebuffer\])
request\_module("fb%d", con2fb.framebuffer);
if (!registered\_fb\[con2fb.framebuffer\]) {
ret = -EINVAL;
break;
}
event.data = &con2fb;
if (!lock\_fb\_info(info))
return -ENODEV;
event.info = info;
ret = fb\_notifier\_call\_chain(FB\_EVENT\_SET\_CONSOLE\_MAP, &event);
unlock\_fb\_info(info);
break;
case FBIOBLANK:
if (!lock\_fb\_info(info))
return -ENODEV;
console\_lock();
info->flags |= FBINFO\_MISC\_USEREVENT;
ret = fb\_blank(info, arg);
info->flags &= ~FBINFO\_MISC\_USEREVENT;
console\_unlock();
unlock\_fb\_info(info);
break;
default:
if (!lock\_fb\_info(info))
return -ENODEV;
fb = info->fbops;
if (fb->fb\_ioctl)
ret = fb->fb\_ioctl(info, cmd, arg);
else
ret = -ENOTTY;
unlock\_fb\_info(info);
}
return ret;
}
static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct fb_info *info = file_fb_info(file);
printk(\nfb_ioctl mem\n); if (!info) return -ENODEV; return do_fb_ioctl(info, cmd, arg); }
依据文件操作的static const struct file_operations fb_fops,应用程序在打开一个framebuffer设备时。能够使用read,write,ioctl来直接操作设备。
应用例程:
[cpp] view plain copy
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; static void fb_var_printf(struct fb_var_screeninfo tmp) { printf("fb_var_screeninfo:\n"); printf("xres =%d, yres =%d, bits_per_pixel = %d\n",tmp.xres,tmp.yres,tmp.bits_per_pixel); printf("height=%d,width = %d\n",tmp.height,tmp.width); printf("xres_virtual =%d, yres_virtual =%d, xoffset=%d,yoffset=%d\n",tmp.xres_virtual,tmp.yres_virtual,tmp.xoffset,tmp.yoffset); return ; } int main(void) { int fbfd; int fbsize; unsigned char *fbbuf; char buf[100]; int i,res,adc_data; for (i=0; i<100; i++) buf[i] = 0xaa; if ((fbfd = open("/dev/fb0", O_RDWR)) < 0) { printf("open fb0 failed\n"); return 1; } printf("fbfd = %d\n", fbfd); if ((res =ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))) { //获取设备显示特性信息 printf("bad vscreeninfo ioctl.error = %d\n",res); } fb_var_printf(vinfo); fbsize = vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel/8); //计算显卡(LCD控制器)显存大小。也就是一整屏共占多少个字节 printf("fbisze: %d\n",fbsize); if ((fbbuf = mmap(0, fbsize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0)) == (void*) -1) //映射显卡设备的内存到用户控件,使得用户直接訪问设备内存(显存) { printf("map video error.\n"); } for (i = 0; i< fbsize; i++) { //填充farmebuffer缓冲区 *(fbbuf+i) = 0xaa; //颜色信息 } munmap(fbbuf, fbsize); close(fbfd); return 0; }