源码包中/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显示特性,是固定不变的,不可以更改
具体数据结构:
- struct fb_fix_screeninfo {
- char id[16];
- unsigned long smem_start;
-
- __u32 smem_len;
- __u32 type;
- __u32 type_aux;
- __u32 visual;
- __u16 xpanstep;
- __u16 ypanstep;
- __u16 ywrapstep;
- __u32 line_length;
- unsigned long mmio_start;
-
- __u32 mmio_len;
- __u32 accel;
-
- __u16 reserved[3];
- };
- struct fb_info {
- int node;
- int flags;
- struct mutex lock;
- struct fb_var_screeninfo var;
- struct fb_fix_screeninfo fix;
- struct fb_monspecs monspecs;
- struct work_struct queue;
- struct fb_pixmap pixmap;
- struct fb_pixmap sprite;
- struct fb_cmap cmap;
- struct list_head modelist;
- struct fb_videomode *mode;
- ...
- struct fb_ops *fbops;
- struct device *device;
- struct device *dev;
- int class_flag;
- #ifdef CONFIG_FB_TILEBLITTING
- struct fb_tile_ops *tileops;
- #endif
- char __iomem *screen_base;
- unsigned long screen_size;
- void *pseudo_palette;
- ...
- };
- struct fb_ops {
-
- struct module *owner;
- int (*fb_open)(struct fb_info *info, int user);
- int (*fb_release)(struct fb_info *info, int user);
-
-
-
-
- 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);
-
-
-
- int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
-
-
- int (*fb_set_par)(struct fb_info *info);
-
-
- int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *info);
-
-
- int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
-
-
- int (*fb_blank)(int blank, struct fb_info *info);
-
-
- int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
-
-
- void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
-
- void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
-
- void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
-
-
- int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
-
-
- void (*fb_rotate)(struct fb_info *info, int angle);
-
-
- int (*fb_sync)(struct fb_info *info);
-
-
- int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
- unsigned long arg);
-
-
- int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
- unsigned long arg);
-
-
- int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
-
-
- void (*fb_save_state)(struct fb_info *info);
-
-
- void (*fb_restore_state)(struct fb_info *info);
-
-
- void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
- struct fb_var_screeninfo *var);
- };
- 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 <span style="color:#ff0000;">FBIOPUT_VSCREENINFO</span>:
- 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来直接操作设备。
应用例程:
- #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);
- 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++) {
- *(fbbuf+i) = 0xaa;
- }
- munmap(fbbuf, fbsize);
- close(fbfd);
- return 0;
- }