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; }
- linux framebuffer设备驱动
- Linux设备驱动之Framebuffer
- Linux设备驱动之Framebuffer分析
- Linux设备驱动之Framebuffer分析
- Linux设备驱动--FrameBuffer的创建方法
- Linux设备驱动之Framebuffer分析
- 68 linux framebuffer设备驱动之spi lcd屏驱动
- Linux中LCD设备驱动--framebuffer(帧缓冲)
- Linux中LCD设备驱动 framebuffer(帧缓冲)
- 66 最简单的linux framebuffer设备驱动实现
- 67 linux内核里的framebuffer设备驱动模型
- linux ------ framebuffer 驱动
- linux-framebuffer设备相关参数
- linux-framebuffer设备相关参数
- linux-framebuffer设备相关参数
- 面向对象地分析Linux内核设备驱动(3)——用面向对象思想分析vfb Framebuffer设备驱动
- 面向对象地分析Linux内核设备驱动(3)——用面向对象思想分析vfb Framebuffer设备驱动
- s3c2410 framebuffer 设备驱动 相关结构体
- Matlab R2008a版安装教程
- 解放军承认对战争有些生疏 没全理解高技术战争
- 图的递归非递归深度优先搜索和广度优先搜索,两种最小生成树算法
- ModelBuilder.class) needs 2.1 API.
- oracle 索引聚簇表的工作原理
- linux framebuffer设备驱动
- SQL 脚本优化
- 【算法】查找第k小的数【JS实现】
- 使用 pgfouine 分析 postgresql的log
- linux input设备驱动
- 操作系统十一文件系统实现
- c语言中相关文件输入输出小结
- jquery验证电话号码
- poj1458