linux framebuffer设备驱动

来源:互联网 发布:博世opcon 编程语言 编辑:程序博客网 时间:2024/06/05 04:32

一. framebuffer结构体

     1. fb_info

struct fb_info {int node;//次设备号int flags;struct mutex lock;struct mutex mm_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;//显示模式#ifdef CONFIG_FB_BACKLIGHTstruct backlight_device *bl_dev;//背光设备struct mutex bl_curve_mutex;u8 bl_curve[FB_BACKLIGHT_LEVELS]; //背光级别#endif#ifdef CONFIG_FB_DEFERRED_IOstruct delayed_work deferred_work;struct fb_deferred_io *fbdefio;#endifstruct fb_ops *fbops;//fb操作函数集struct device *device;//设备文件struct device *dev;//设备文件int class_flag;#ifdef CONFIG_FB_TILEBLITTINGstruct fb_tile_ops *tileops;#endifchar __iomem *screen_base;//虚拟基地址unsigned long screen_size; //虚拟显存大小void *pseudo_palette;//调色板 一般设置为PALETTE_BUFF_CLEAR #define FBINFO_STATE_RUNNING0#define FBINFO_STATE_SUSPENDED1u32 state;//状态 状态值为上面两个宏void *fbcon_par;void *par;struct apertures_struct {unsigned int count;struct aperture {resource_size_t base;resource_size_t size;} ranges[0];} *apertures;};

     2. fb_var_screeninfo

struct fb_var_screeninfo {__u32 xres;//水平分辨率__u32 yres;//垂直分辨率__u32 xres_virtual;//水平虚拟分辨率__u32 yres_virtual;//存执虚拟分辨率__u32 xoffset;//水平可视区域的偏移__u32 yoffset;//垂直可视区域的偏移__u32 bits_per_pixel;//每像素占用多少bit__u32 grayscale;//灰度等级struct fb_bitfield red;//红色位域offset=11 length=5 (RGB565)struct fb_bitfield green;//绿色位域offset=5  length=6struct fb_bitfield blue;//蓝色位域offset=0 length=5struct fb_bitfield transp;//透明度位域__u32 nonstd;//非标准标志__u32 activate;//激活标志__u32 height;//物理高度__u32 width;//物理宽度__u32 accel_flags;//硬件加速标志__u32 pixclock;__u32 left_margin;//左边缘宽度__u32 right_margin;//右边缘宽度__u32 upper_margin;//上边缘宽度__u32 lower_margin;//下边缘宽度__u32 hsync_len;//水平同步长度__u32 vsync_len;//垂直同步长度__u32 sync;__u32 vmode;__u32 rotate;//旋转__u32 reserved[5];};

     2.1 位域 fb_bitfield

struct fb_bitfield {__u32 offset;//偏移量__u32 length;//长度__u32 msb_right;//高位有效?对齐方式};

 

     3.fb_fix_screeninfo

struct fb_fix_screeninfo {char id[16];unsigned long smem_start;//物理显存起始地址__u32 smem_len;//显示长度(xres*yres*bits_per_pixel/8)__u32 type;//显示类型(FB_TYPE_PACKED_PIXELS)__u32 type_aux;__u32 visual;//颜色模式(FB_VISUAL_TRUECOLOR)__u16 xpanstep;__u16 ypanstep;__u16 ywrapstep;__u32 line_length;//一行像素的字节数(xres*bits_per_pixel/8)unsigned long mmio_start;__u32 mmio_len;__u32 accel;//加速类型__u16 reserved[3];};


     4. 操作函数集

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);//同步 等待blit空闲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);//32位兼容控制int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);//映射void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,struct fb_var_screeninfo *var);void (*fb_destroy)(struct fb_info *info);//销毁int (*fb_debug_enter)(struct fb_info *info);int (*fb_debug_leave)(struct fb_info *info);};

二. fb系统初始化

     1. 主设备号

#define FB_MAJOR29

     2. fbmem_init

static int __init fbmem_init(void){proc_create("fb", 0, NULL, &fb_proc_fops);//创建"/proc/fb"文件if (register_chrdev(FB_MAJOR,"fb",&fb_fops))//注册所有的fb字符设备,并捆绑fb_fops操作函数集合printk("unable to get major %d for fb devs\n", FB_MAJOR);fb_class = class_create(THIS_MODULE, "graphics");//创建"/sys/class/graphics"if (IS_ERR(fb_class)) {printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));fb_class = NULL;}return 0;}

    3. /proc下的接口fb_proc_fops

    3.1 操作函数集

static const struct file_operations fb_proc_fops = {.owner= THIS_MODULE,.open= proc_fb_open,//打开.read= seq_read,//读取.llseek= seq_lseek,//读写指针.release= seq_release,};

     3.2 cat /prco/fb

cat /proc/fb0 ti81xxfb1 ti81xxfb2 ti81xxfb

     先调用open方法

static int proc_fb_open(struct inode *inode, struct file *file){return seq_open(file, &proc_fb_seq_ops);//主要做了file->private_data->op=proc_fb_seq_ops}

     proc_fb_seq_ops

static const struct seq_operations proc_fb_seq_ops = {.start= fb_seq_start,//读写位置开头.next= fb_seq_next,//下一个读写位置.stop= fb_seq_stop,//无操作.show= fb_seq_show,//显示};

     fb_seq_show函数

static int fb_seq_show(struct seq_file *m, void *v){int i = *(loff_t *)v;struct fb_info *fi = registered_fb[i];//获取fb_info结构体if (fi)seq_printf(m, "%d %s\n", fi->node, fi->fix.id);//打印其设备编号及设备信息到seq_file文件return 0;}

     接着调用read方法

seq_read方法调用proc_fb_seq_ops的各个方法,最终将seq_file文件里的打印信息,复制到用户空间的buf里面

     4. 字符设备捆绑的fb_fops

     4.1 操作函数集

static const struct file_operations fb_fops = {.owner =THIS_MODULE,//模块所有者.read =fb_read,//读.write =fb_write,//写.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.llseek =default_llseek,//读写指针};

     4.1.1 打开

static int fb_open(struct inode *inode, struct file *file)__acquires(&info->lock)__releases(&info->lock){int fbidx = iminor(inode);//根据节点算出次设备号struct fb_info *info;int res = 0;if (fbidx >= FB_MAX)return -ENODEV;info = registered_fb[fbidx];//从全局registered_fb数组中获取fb_infoif (!info)request_module("fb%d", fbidx);info = registered_fb[fbidx];if (!info)return -ENODEV;mutex_lock(&info->lock);if (!try_module_get(info->fbops->owner)) {res = -ENODEV;goto out;}file->private_data = info;//将fb_info数据存放在文件的私有数据里if (info->fbops->fb_open) {//若fb_info的fb操作函数集有实现open方法res = info->fbops->fb_open(info,1);//则调用其open方法if (res)module_put(info->fbops->owner);}#ifdef CONFIG_FB_DEFERRED_IOif (info->fbdefio)fb_deferred_io_open(info, inode, file);#endifout:mutex_unlock(&info->lock);return res;}

     4.1.2 读

static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){unsigned long p = *ppos;struct inode *inode = file->f_path.dentry->d_inode;int fbidx = iminor(inode);//通过节点算出次设备号struct fb_info *info = registered_fb[fbidx];//从全局数组获取fb_infou8 *buffer, *dst;u8 __iomem *src;int c, cnt = 0, err = 0;unsigned long total_size;if (!info || ! info->screen_base)//fb_info为空或者虚拟地址不存在return -ENODEV;//错误if (info->state != FBINFO_STATE_RUNNING)//处于运行态return -EPERM;//错误if (info->fbops->fb_read)//fb操作函数集存在read方法return info->fbops->fb_read(info, buf, count, ppos); //则调用 否则继续运行total_size = info->screen_size;//获取屏幕尺寸if (total_size == 0)//屏幕尺寸没设置total_size = info->fix.smem_len;//则获取显存长度if (p >= total_size)//读写位置已经超出return 0;if (count >= total_size)//读数据长度限制在total_size范围你count = total_size;if (count + p > total_size)//有效读取的数据个数count = total_size - p;buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,GFP_KERNEL);//分配临时缓冲区if (!buffer)return -ENOMEM;src = (u8 __iomem *) (info->screen_base + p);//设置源地址if (info->fbops->fb_sync)//存在同步方法info->fbops->fb_sync(info);//则调用该方法while (count) {//判断是否读完c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;//按页读数据dst = buffer;//设置目的地址fb_memcpy_fromfb(dst, src, c);//复制数据dst += c;//重置目的地址src += c;//重置目的地址if (copy_to_user(buf, buffer, c)) {//内核空间拷贝到用户空间err = -EFAULT;break;}*ppos += c;//移动读写指针buf += c;//用户空间缓冲区指针cnt += c;//已读数据计数count -= c;//待读数据计数}kfree(buffer);//释放临时缓冲区return (err) ? err : cnt;//返回读取数据大小}

     4.1.3 写

static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){unsigned long p = *ppos;struct inode *inode = file->f_path.dentry->d_inode;int fbidx = iminor(inode);//根据节点计算次设备号struct fb_info *info = registered_fb[fbidx];//全局数组中获取fb_infou8 *buffer, *src;u8 __iomem *dst;int c, cnt = 0, err = 0;unsigned long total_size;if (!info || !info->screen_base)//没有虚拟地址return -ENODEV;//错误if (info->state != FBINFO_STATE_RUNNING)//运行态return -EPERM;//错误if (info->fbops->fb_write)//fb函数集存在写方法return info->fbops->fb_write(info, buf, count, ppos);//则调用其方法total_size = info->screen_size;//获取屏幕尺寸if (total_size == 0)//没设置screen_size参数total_size = info->fix.smem_len;//则获取显存长度if (p > total_size)//读写指针已超过return -EFBIG;if (count > total_size) {//控制写长度在total_size以内err = -EFBIG;count = total_size;}if (count + p > total_size) {//计算合理的写数据长度if (!err)err = -ENOSPC;count = total_size - p;}buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,GFP_KERNEL);//分配临时缓冲区if (!buffer)return -ENOMEM;dst = (u8 __iomem *) (info->screen_base + p);//设置目的地址为显存物理地址起始位置+读写指针if (info->fbops->fb_sync)//存在同步方法info->fbops->fb_sync(info);//则调用while (count) {//检测待写数据长度c = (count > PAGE_SIZE) ? PAGE_SIZE : count;//按页写src = buffer;//设置源地址if (copy_from_user(src, buf, c)) {//用户空间拷贝数据到内核空间err = -EFAULT;break;}fb_memcpy_tofb(dst, src, c);//数据存到显存上dst += c;//重置目的地址src += c;//重置源地址*ppos += c;//重置读写指针buf += c;//重置缓冲区地址cnt += c;//更新写入数据个数count -= c;//重新换算待写数据长度}kfree(buffer);//释放临时缓冲区return (cnt) ? cnt : err;//返回已经写了的数据长度}

     4.1.4 控制

static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg){struct inode *inode = file->f_path.dentry->d_inode;int fbidx = iminor(inode);//根据节点获取次设备号struct fb_info *info = registered_fb[fbidx];//在全局数组中获取fb_inforeturn do_fb_ioctl(info, cmd, arg);//调用do_fb_ioctl函数}

    4.1.4.1 do_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;acquire_console_sem();//锁定fbconinfo->flags |= FBINFO_MISC_USEREVENT;ret = fb_set_var(info, &var);info->flags &= ~FBINFO_MISC_USEREVENT;release_console_sem();//释放fbconunlock_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;acquire_console_sem();ret = fb_pan_display(info, &var);release_console_sem();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;acquire_console_sem();//锁定fbconinfo->flags |= FBINFO_MISC_USEREVENT;ret = fb_blank(info, arg);info->flags &= ~FBINFO_MISC_USEREVENT;release_console_sem();//释放fbconunlock_fb_info(info);break;default:if (!lock_fb_info(info))return -ENODEV;fb = info->fbops;if (fb->fb_ioctl)//若fb操作函数集存在操作方法ret = fb->fb_ioctl(info, cmd, arg);//则调用其方法,这样就可以针对具体设备添加自定义的命令elseret = -ENOTTY;unlock_fb_info(info);}return ret;}

     4.1.5 映射

static int fb_mmap(struct file *file, struct vm_area_struct * vma){int fbidx = iminor(file->f_path.dentry->d_inode);struct fb_info *info = registered_fb[fbidx];struct fb_ops *fb = info->fbops;unsigned long off;unsigned long start;u32 len;if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))return -EINVAL;off = vma->vm_pgoff << PAGE_SHIFT;if (!fb)return -ENODEV;mutex_lock(&info->mm_lock);if (fb->fb_mmap) {//fb操作函数集存在mmap方法int res;res = fb->fb_mmap(info, vma);//则调用其方法mutex_unlock(&info->mm_lock);return res;}/* frame buffer memory */start = info->fix.smem_start;//显存起始地址len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);//页对齐if (off >= len) {/* memory mapped io */off -= len;if (info->var.accel_flags) {mutex_unlock(&info->mm_lock);return -EINVAL;}start = info->fix.mmio_start;len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);}mutex_unlock(&info->mm_lock);start &= PAGE_MASK;if ((vma->vm_end - vma->vm_start + off) > len)return -EINVAL;off += start;vma->vm_pgoff = off >> PAGE_SHIFT;/* This is an IO map - tell maydump to skip this VMA */vma->vm_flags |= VM_IO | VM_RESERVED;vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);fb_pgprotect(file, vma, off);if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,vma->vm_end - vma->vm_start, vma->vm_page_prot))return -EAGAIN;return 0;}

 

三. 分配fb_info

struct fb_info *framebuffer_alloc(size_t size, struct device *dev){#define BYTES_PER_LONG (BITS_PER_LONG/8)#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))int fb_info_size = sizeof(struct fb_info);//fb_info的大小struct fb_info *info;char *p;if (size)fb_info_size += PADDING;p = kzalloc(fb_info_size + size, GFP_KERNEL);//分配内存if (!p)return NULL;info = (struct fb_info *) p;if (size)info->par = p + fb_info_size;info->device = dev;//设备文件#ifdef CONFIG_FB_BACKLIGHTmutex_init(&info->bl_curve_mutex);#endifreturn info;#undef PADDING#undef BYTES_PER_LONG}

 

四. 注册与注销framebuffer

     1.注册framebuffer

     1.1 register_framebuffer

int register_framebuffer(struct fb_info *fb_info){int i;struct fb_event event;struct fb_videomode mode;if (num_registered_fb == FB_MAX)//最多32个return -ENXIO;if (fb_check_foreignness(fb_info))return -ENOSYS;remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,fb_is_primary_device(fb_info));num_registered_fb++;//注册的fb设备计数加1for (i = 0 ; i < FB_MAX; i++)//查找分配次设备号if (!registered_fb[i])break;fb_info->node = i;//设置次设备号mutex_init(&fb_info->lock);mutex_init(&fb_info->mm_lock);fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), NULL, "fb%d", i);//创建"/sys/class/graphics/fb%d"if (IS_ERR(fb_info->dev)) {printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));fb_info->dev = NULL;} elsefb_init_device(fb_info);//创建"sys/class/graphics/fbX/"下的属性文件if (fb_info->pixmap.addr == NULL) {fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);if (fb_info->pixmap.addr) {fb_info->pixmap.size = FBPIXMAPSIZE;fb_info->pixmap.buf_align = 1;fb_info->pixmap.scan_align = 1;fb_info->pixmap.access_align = 32;fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;}}fb_info->pixmap.offset = 0;if (!fb_info->pixmap.blit_x)fb_info->pixmap.blit_x = ~(u32)0;if (!fb_info->pixmap.blit_y)fb_info->pixmap.blit_y = ~(u32)0;if (!fb_info->modelist.prev || !fb_info->modelist.next)INIT_LIST_HEAD(&fb_info->modelist);fb_var_to_videomode(&mode, &fb_info->var);fb_add_videomode(&mode, &fb_info->modelist);registered_fb[i] = fb_info;//填充registered全局数组event.info = fb_info;if (!lock_fb_info(fb_info))return -ENODEV;fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);//发送通知unlock_fb_info(fb_info);return 0;}

      1.2 fb_init_device

int fb_init_device(struct fb_info *fb_info){int i, error = 0;dev_set_drvdata(fb_info->dev, fb_info);fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {error = device_create_file(fb_info->dev, &device_attrs[i]);//"/sys/class/graphics/fbX/"下属性文件if (error)break;}if (error) {while (--i >= 0)device_remove_file(fb_info->dev, &device_attrs[i]);fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;}return 0;}
     1.2.1 属性文件device_attrs
static struct device_attribute device_attrs[] = {__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),__ATTR(name, S_IRUGO, show_name, NULL),__ATTR(stride, S_IRUGO, show_stride, NULL),__ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),__ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),#ifdef CONFIG_FB_BACKLIGHT__ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),#endif};

     2.注销framebuffer

int unregister_framebuffer(struct fb_info *fb_info){struct fb_event event;int i, ret = 0;i = fb_info->node;//获取次设备号if (!registered_fb[i]) {ret = -EINVAL;goto done;}if (!lock_fb_info(fb_info))return -ENODEV;event.info = fb_info;ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);//发送通知unlock_fb_info(fb_info);if (ret) {ret = -EINVAL;goto done;}if (fb_info->pixmap.addr &&(fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))kfree(fb_info->pixmap.addr);fb_destroy_modelist(&fb_info->modelist);registered_fb[i]=NULL;//清空全局数组num_registered_fb--;//注册了的fb计数减1fb_cleanup_device(fb_info);device_destroy(fb_class, MKDEV(FB_MAJOR, i));移除"/sys/class/graphics/fbX"event.info = fb_info;fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);//发送通知if (fb_info->fbops->fb_destroy)//若fb操作函数集存在销毁方法fb_info->fbops->fb_destroy(fb_info);//则调用其方法done:return ret;}


五. 编写framebuffer驱动步骤

1.framebuffer_alloc分配fb_info,设置其重要成员

2.填充可变fb_var_screeninfo和不可变参数fb_fix_screeninfo

3.定义并实现fb_ops并与fb_info捆绑

4.注册设备register_framebuffer

六. 应用层的一个测试实例

 如果不是使用fb0那么修改下open函数啊,显示结果是rgb三个方块

//gcc fb_test.c#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <linux/fb.h>#include <linux/kd.h>#include <sys/mman.h>#include <sys/ioctl.h>#include <sys/time.h>#include <string.h>#include <errno.h>struct fb_var_screeninfo vinfo;struct fb_fix_screeninfo finfo;char *frameBuffer = 0;//打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。void printFixedInfo (){    printf ("Fixed screen info:\n"            "\tid: %s\n"            "\tsmem_start: 0x%lx\n"            "\tsmem_len: %d\n"            "\ttype: %d\n"            "\ttype_aux: %d\n"            "\tvisual: %d\n"            "\txpanstep: %d\n"            "\typanstep: %d\n"            "\tywrapstep: %d\n"            "\tline_length: %d\n"            "\tmmio_start: 0x%lx\n"            "\tmmio_len: %d\n"            "\taccel: %d\n"            "\n",            finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,            finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,            finfo.ywrapstep, finfo.line_length, finfo.mmio_start,            finfo.mmio_len, finfo.accel);}//打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置void printVariableInfo (){    printf ("Variable screen info:\n"            "\txres: %d\n"            "\tyres: %d\n"            "\txres_virtual: %d\n"            "\tyres_virtual: %d\n"            "\tyoffset: %d\n"            "\txoffset: %d\n"            "\tbits_per_pixel: %d\n"            "\tgrayscale: %d\n"            "\tred: offset: %2d, length: %2d, msb_right: %2d\n"            "\tgreen: offset: %2d, length: %2d, msb_right: %2d\n"            "\tblue: offset: %2d, length: %2d, msb_right: %2d\n"            "\ttransp: offset: %2d, length: %2d, msb_right: %2d\n"            "\tnonstd: %d\n"            "\tactivate: %d\n"            "\theight: %d\n"            "\twidth: %d\n"            "\taccel_flags: 0x%x\n"            "\tpixclock: %d\n"            "\tleft_margin: %d\n"            "\tright_margin: %d\n"            "\tupper_margin: %d\n"            "\tlower_margin: %d\n"            "\thsync_len: %d\n"            "\tvsync_len: %d\n"            "\tsync: %d\n"            "\tvmode: %d\n"            "\n",            vinfo.xres, vinfo.yres, vinfo.xres_virtual, vinfo.yres_virtual,            vinfo.xoffset, vinfo.yoffset, vinfo.bits_per_pixel,            vinfo.grayscale, vinfo.red.offset, vinfo.red.length,            vinfo.red.msb_right, vinfo.green.offset, vinfo.green.length,            vinfo.green.msb_right, vinfo.blue.offset, vinfo.blue.length,            vinfo.blue.msb_right, vinfo.transp.offset, vinfo.transp.length,            vinfo.transp.msb_right, vinfo.nonstd, vinfo.activate,            vinfo.height, vinfo.width, vinfo.accel_flags, vinfo.pixclock,            vinfo.left_margin, vinfo.right_margin, vinfo.upper_margin,            vinfo.lower_margin, vinfo.hsync_len, vinfo.vsync_len,            vinfo.sync, vinfo.vmode);}//画大小为width*height的同色矩阵,8alpha+8reds+8greens+8bluesvoid drawRect_rgb32 (int x0, int y0, int width, int height, int color){    const int bytesPerPixel = 4;    const int stride = finfo.line_length / bytesPerPixel;    int *dest = (int *) (frameBuffer)        + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);    int x, y;    for (y = 0; y < height; ++y)    {        for (x = 0; x < width; ++x)        {            dest[x] = color;        }        dest += stride;    }}//画大小为width*height的同色矩阵,5reds+6greens+5bluesvoid drawRect_rgb16 (int x0, int y0, int width, int height, int color){    const int bytesPerPixel = 2;    const int stride = finfo.line_length / bytesPerPixel;    const int red = (color & 0xff0000) >> (16 + 3);    const int green = (color & 0xff00) >> (8 + 2);    const int blue = (color & 0xff) >> 3;    const short color16 = blue | (green << 5) | (red << (5 + 6));    short *dest = (short *) (frameBuffer)        + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);    int x, y;    for (y = 0; y < height; ++y)    {        for (x = 0; x < width; ++x)        {            dest[x] = color16;        }        dest += stride;    }}//画大小为width*height的同色矩阵,5reds+5greens+5bluesvoid drawRect_rgb15 (int x0, int y0, int width, int height, int color){    const int bytesPerPixel = 2;    const int stride = finfo.line_length / bytesPerPixel;    const int red = (color & 0xff0000) >> (16 + 3);    const int green = (color & 0xff00) >> (8 + 3);    const int blue = (color & 0xff) >> 3;    const short color15 = blue | (green << 5) | (red << (5 + 5)) | 0x8000;    short *dest = (short *) (frameBuffer)        + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);    int x, y;    for (y = 0; y < height; ++y)    {        for (x = 0; x < width; ++x)        {            dest[x] = color15;        }        dest += stride;    }}void drawRect (int x0, int y0, int width, int height, int color){    switch (vinfo.bits_per_pixel)    {    case 32:        drawRect_rgb32 (x0, y0, width, height, color);        break;    case 16:        drawRect_rgb16 (x0, y0, width, height, color);        break;    case 15:        drawRect_rgb15 (x0, y0, width, height, color);        break;    default:        printf ("Warning: drawRect() not implemented for color depth %i\n",                vinfo.bits_per_pixel);        break;    }}#define PERFORMANCE_RUN_COUNT 5void performSpeedTest (void *fb, int fbSize){    int i, j, run;    struct timeval startTime, endTime;    unsigned long long results[PERFORMANCE_RUN_COUNT];    unsigned long long average;    unsigned int *testImage;    unsigned int randData[17] = {        0x3A428472, 0x724B84D3, 0x26B898AB, 0x7D980E3C, 0x5345A084,        0x6779B66B, 0x791EE4B4, 0x6E8EE3CC, 0x63AF504A, 0x18A21B33,        0x0E26EB73, 0x022F708E, 0x1740F3B0, 0x7E2C699D, 0x0E8A570B,        0x5F2C22FB, 0x6A742130    };    printf ("Frame Buffer Performance test...\n");    for (run = 0; run < PERFORMANCE_RUN_COUNT; ++run)    {        /* Generate test image with random(ish) data: */        testImage = (unsigned int *) malloc (fbSize);        j = run;        for (i = 0; i < (int) (fbSize / sizeof (int)); ++i)        {            testImage[i] = randData[j];            j++;            if (j >= 17)                j = 0;        }        gettimeofday (&startTime, NULL);        memcpy (fb, testImage, fbSize);        gettimeofday (&endTime, NULL);        long secsDiff = endTime.tv_sec - startTime.tv_sec;        results[run] =            secsDiff * 1000000 + (endTime.tv_usec - startTime.tv_usec);        free (testImage);    }    average = 0;    for (i = 0; i < PERFORMANCE_RUN_COUNT; ++i)        average += results[i];    average = average / PERFORMANCE_RUN_COUNT;    printf (" Average: %llu usecs\n", average);    printf (" Bandwidth: %.03f MByte/Sec\n",            (fbSize / 1048576.0) / ((double) average / 1000000.0));    printf (" Max. FPS: %.03f fps\n\n",            1000000.0 / (double) average);    /* Clear the framebuffer back to black again: */    memset (fb, 0, fbSize);}int main (int argc, char **argv){    const char *devfile = "/dev/fb0";    long int screensize = 0;    int fbFd = 0;    /* Open the file for reading and writing */    fbFd = open (devfile, O_RDWR);    if (fbFd == -1)    {        perror ("Error: cannot open framebuffer device");        exit (1);    }    //获取finfo信息并显示    if (ioctl (fbFd, FBIOGET_FSCREENINFO, &finfo) == -1)    {        perror ("Error reading fixed information");        exit (2);    }    printFixedInfo ();    //获取vinfo信息并显示    if (ioctl (fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1)    {        perror ("Error reading variable information");        exit (3);    }    printVariableInfo ();    /* Figure out the size of the screen in bytes */    screensize = finfo.smem_len;    /* Map the device to memory */    frameBuffer =        (char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,                     fbFd, 0);    if (frameBuffer == MAP_FAILED)    {        perror ("Error: Failed to map framebuffer device to memory");        exit (4);    }    //测试virt fb的性能    performSpeedTest (frameBuffer, screensize);    printf ("Will draw 3 rectangles on the screen,\n"            "they should be colored red, green and blue (in that order).\n");    drawRect (vinfo.xres / 8, vinfo.yres / 8,             vinfo.xres / 4, vinfo.yres / 4, 0xffff0000);    drawRect (vinfo.xres * 3 / 8, vinfo.yres * 3 / 8,             vinfo.xres / 4, vinfo.yres / 4, 0xff00ff00);    drawRect (vinfo.xres * 5 / 8, vinfo.yres * 5 / 8,             vinfo.xres / 4, vinfo.yres / 4, 0xff0000ff);    sleep (5);    printf (" Done.\n");    munmap (frameBuffer, screensize);    //解除内存映射,与mmap对应    close (fbFd);    return 0;}


七. 截图方法

cat /dev/fb0 >0.raw./ffmpeg -vcodec rawvideo -pix_fmt rgb565 -s 1920*1080 -i 0.raw -f image2 -vcodec mjpeg 0.jpg

借助ffmpeg工具
或者用qt的demo有个screenshot

八. 显示图片方法(针对565 A8平台)

先编译ljpeg库,然后交叉编译下面的c代码 编译时候加上 -ljpeg

#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <string.h>#include <linux/fb.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <jpeglib.h>#include <jerror.h>#define        FB_DEV        "/dev/fb0"/***************** function declaration ******************/void            usage(char *msg);unsigned short  RGB888toRGB565(unsigned char red,        unsigned char green, unsigned char blue);int             fb_open(char *fb_device);int             fb_close(int fd);int             fb_stat(int fd, int *width, int *height, int *depth);void           *fb_mmap(int fd, unsigned int screensize);int             fb_munmap(void *start, size_t length);int             fb_pixel(void *fbmem, int width, int height,        int x, int y, unsigned short color);/************ function implementation ********************/    intmain(int argc, char *argv[]){    /*     * declaration for jpeg decompression     */    struct jpeg_decompress_struct cinfo;    struct jpeg_error_mgr jerr;    FILE           *infile;    unsigned char  *buffer;    /*     * declaration for framebuffer device     */    int             fbdev;    char           *fb_device;    unsigned char  *fbmem;    unsigned int    screensize;    unsigned int    fb_width;    unsigned int    fb_height;    unsigned int    fb_depth;    unsigned int    x;    unsigned int    y;    /*     * check auguments     */    if (argc != 2) {        usage("insuffient auguments");        exit(-1);    }        /*         * open framebuffer device         */        if ((fb_device = getenv("FRAMEBUFFER")) == NULL)            fb_device = FB_DEV;        fbdev = fb_open(fb_device);        /*         * get status of framebuffer device         */        fb_stat(fbdev, &fb_width, &fb_height, &fb_depth);        /*         * map framebuffer device to shared memory         */        screensize = fb_width * fb_height * fb_depth / 8;        fbmem = fb_mmap(fbdev, screensize);        /*         * open input jpeg file         */        if ((infile = fopen(argv[1], "rb")) == NULL) {            fprintf(stderr, "open %s failed\n", argv[1]);            exit(-1);        }        /*         * init jpeg decompress object error handler         */        cinfo.err = jpeg_std_error(&jerr);        jpeg_create_decompress(&cinfo);        /*         * bind jpeg decompress object to infile         */        jpeg_stdio_src(&cinfo, infile);        /*         * read jpeg header         */        jpeg_read_header(&cinfo, TRUE);        /*         * decompress process.         * note: after jpeg_start_decompress() is called         * the dimension infomation will be known,         * so allocate memory buffer for scanline immediately         */        jpeg_start_decompress(&cinfo);        if ((cinfo.output_width > fb_width) ||                (cinfo.output_height > fb_height)) {            printf("too large JPEG file,cannot display\n");            return (-1);        }        buffer = (unsigned char *) malloc(cinfo.output_width *                cinfo.output_components);        y = 0;        while (cinfo.output_scanline < cinfo.output_height) {            jpeg_read_scanlines(&cinfo, &buffer, 1);            if (fb_depth == 16) {                unsigned short  color;                for (x = 0; x < cinfo.output_width; x++) {                    color = RGB888toRGB565(buffer[x * 3],                            buffer[x * 3 + 1], buffer[x * 3 + 2]);                    fb_pixel(fbmem, fb_width, fb_height, x, y, color);                }            } else if (fb_depth == 24) {                memcpy((unsigned char *) fbmem + y * fb_width * 3,                        buffer, cinfo.output_width * cinfo.output_components);            }            y++;                                        // next scanline        }        /*         * finish decompress, destroy decompress object         */        jpeg_finish_decompress(&cinfo);        jpeg_destroy_decompress(&cinfo);        /*         * release memory buffer         */        free(buffer);        /*         * close jpeg inputing file         */        fclose(infile);        /*         * unmap framebuffer's shared memory         */        fb_munmap(fbmem, screensize);        /*         * close framebuffer device         */        fb_close(fbdev);        return (0);    }    void        usage(char *msg)        {            fprintf(stderr, "%s\n", msg);            printf("Usage: fv some-jpeg-file.jpg\n");        }    /*     * convert 24bit RGB888 to 16bit RGB565 color format     */    unsigned short        RGB888toRGB565(unsigned char red, unsigned char green, unsigned char blue)        {            unsigned short  B = (blue >> 3) & 0x001F;            unsigned short  G = ((green >> 2) << 5) & 0x07E0;            unsigned short  R = ((red >> 3) << 11) & 0xF800;            return (unsigned short) (R | G | B);        }    /*     * open framebuffer device.     * return positive file descriptor if success,     * else return -1.     */    int        fb_open(char *fb_device)        {            int             fd;            if ((fd = open(fb_device, O_RDWR)) < 0) {                perror(__func__);                return (-1);            }            return (fd);        }    /*     * get framebuffer's width,height,and depth.     * return 0 if success, else return -1.     */    int        fb_stat(int fd, int *width, int *height, int *depth)        {            struct fb_fix_screeninfo fb_finfo;            struct fb_var_screeninfo fb_vinfo;            if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_finfo)) {                perror(__func__);                return (-1);            }            if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_vinfo)) {                perror(__func__);                return (-1);            }            *width = fb_vinfo.xres;            *height = fb_vinfo.yres;            *depth = fb_vinfo.bits_per_pixel;            return (0);        }    /*     * map shared memory to framebuffer device.     * return maped memory if success,     * else return -1, as mmap dose.     */    void           *        fb_mmap(int fd, unsigned int screensize)        {            caddr_t         fbmem;            if ((fbmem = mmap(0, screensize, PROT_READ | PROT_WRITE,                            MAP_SHARED, fd, 0)) == MAP_FAILED) {                perror(__func__);                return (void *) (-1);            }            return (fbmem);        }    /*     * unmap map memory for framebuffer device.     */    int        fb_munmap(void *start, size_t length)        {            return (munmap(start, length));        }    /*     * close framebuffer device     */    int        fb_close(int fd)        {            return (close(fd));        }    /*     * display a pixel on the framebuffer device.     * fbmem is the starting memory of framebuffer,     * width and height are dimension of framebuffer,     * x and y are the coordinates to display,     * color is the pixel's color value.     * return 0 if success, otherwise return -1.     */    int        fb_pixel(void *fbmem, int width, int height,                int x, int y, unsigned short color)        {            if ((x > width) || (y > height))                return (-1);            unsigned short *dst = ((unsigned short *) fbmem + y * width + x);            *dst = color;            return 0;        }


 

原创粉丝点击