Linux 驱动 – Frame Buffer (帧缓冲)显示驱动

一、Frame Buffer

Frame Buffer 翻译过来是帧缓冲的意思,帧指的是一帧图像,缓冲是暂时存放的意思,连起来就是暂时存放一帧图像,相当于模拟了台式机中显卡的显存作用。在嵌入式中,因为没有显卡这样的单独的机构去处理图片,所以就使用了Frame Buffer用软件去模拟显存。
Frame Buffer为显示设备提供一个统一的接口,屏蔽硬件底层的差异,允许上层应用在图形模式下直接对帧缓冲区进行读写操作。对于设备而言,只需要在缓冲区对应的区域写入颜色值,就能在屏幕对应的地方显示颜色。
Frame Buffer是一个标准的字符设备,主设备号为29,对应于/dev/fbx

Framebuffer驱动并不提供任何有关图形的 API给用户,它仅完成将显示缓冲的数据显示在 LCD上。

二、Frame Buffer 框架结构


Frame Buffer的核心代码在fbmem.c中,向上层提供了完整的字符设备操作的接口(open,read,write,ioctl,mmap)。向下给硬件设备提供了统一的接口,把接口抽象为一个fb_info结构体,实现一个显示驱动就需要填充这个结构体,并使用fb_mem.c提供的注册register_framebuffer与注销unregister_framebuffer函数加载和卸载驱动。

三、主要结构体

在看主体代码之前,先看几个结构体,只有在了解了结构体之后,才能更清楚的了解代码的流程。

1、fb_info

struct fb_info {atomic_t count;int node;int flags;int fbcon_rotate_hint;struct mutex lock;               /* 互斥锁*/struct mutex mm_lock;           /* 互斥锁,用于 fb_mmap 和 smem_*域 */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_BACKLIGHT /* LCD 背光 */struct 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;    /* 帧缓冲操作函数集 */struct device *device;   /* 父设备 */struct device *dev;       /* 当前 fb 设备 */int class_flag;          /* 私有 sysfs 标志 */
#ifdef CONFIG_FB_TILEBLITTINGstruct fb_tile_ops *tileops;  /* Tile Blitting */
#endifunion {char __iomem *screen_base; /*虚拟内存基地址(屏幕显存) */char *screen_buffer;};unsigned long screen_size;  /* 虚拟内存大小(屏幕显存大小) */ void *pseudo_palette;      /* 伪 16 位调色板 */
#define FBINFO_STATE_RUNNING    0
#define FBINFO_STATE_SUSPENDED  1u32 state;         /* Hardware state i.e suspend */void *fbcon_par;                /* fbcon use-only private area *//* From here on everything is device dependent */void *par;struct apertures_struct {unsigned int count;struct aperture {resource_size_t base;resource_size_t size;} ranges[0];} *apertures;bool skip_vt_switch; /* no VT switch on suspend/resume required */
};

其中,最主要的的就是var, fix, fbops, screen_base这四个成员。

var – 可变参数主要是用来存放时序,bpp等,主要特征就是会给应用提供接口去改变它。
fix – 主要用来存放显存信息,一旦分配之后就不会改变。
fbops – 设备函数集(open,read,write……)
screen_base – LCD虚拟显存地址

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; /*每个像素的位数即BPP,比如:RGB565则填入16*/__u32 grayscale;      /* 0 = 彩色, 1 = 灰度屏    */struct fb_bitfield red;       /* 红色的长度和偏移信息 */struct fb_bitfield green;   /* 绿色的长度和偏移信息 */struct fb_bitfield blue;    /* 蓝色的长度和偏移信息 */struct fb_bitfield transp;  /* 透明色的长度和偏移信息  */  __u32 nonstd;           /* 不等于0则为非标准像素格式 */__u32 activate;          /* see FB_ACTIVATE_*        *///存放物理屏的物理尺寸,是外观尺寸,单位是mm,可选择填充的项  非重点__u32 height;           /* height of picture in mm    */__u32 width;            /* width of picture in mm     */__u32 accel_flags;      /* (OBSOLETE) see fb_info.flags *///下面是LCD屏的工作时序,参数从datasheet来__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 colorspace;        /* colorspace for FOURCC-based modes */__u32 reserved[4];       /* Reserved for future compatibility */
};

3、fb_fix_screeninfo

固定参数, 主要用来存放显存信息,一旦分配之后就不会改变。

struct fb_fix_screeninfo {char id[16];           /* LCD标识名 填写一个16字符以内字符串即可 */unsigned long smem_start;   /*显存的物理起始地址,不是虚拟地址 *//* (physical address) */__u32 smem_len;     /*显存的内存长度 */__u32 type;         /* 表示像素类型 see FB_TYPE_*     */__u32 type_aux;       /* Interleave for interleaved Planes */__u32 visual;        /* 表示颜色类型 see FB_VISUAL_*   */ __u16 xpanstep;      /* 如果没有硬件panning就赋值为0  */__u16 ypanstep;        /* 如果没有硬件panning就赋值为0  */__u16 ywrapstep;   /* 如果没有硬件panning就赋值为0    */__u32 line_length;   /*一行的字节数 ,例:(RGB565)240*320,那么这里就等于240*16/8*/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 capabilities;       /* see FB_CAP_*         */__u16 reserved[2];        /* Reserved for future compatibility */
};

4、fb_ops

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);/* blank display */int (*fb_blank)(int blank, 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);/* perform fb specific mmap */int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
………………
};
  • fb_open:当你的lcd不需要做什么特殊的初始化操作,这个方法可以不实现
  • fb_release:当你的应用程序不使用lcd设备的时候,需要做的事情在这里实现
  • fb_read:当你的lcd控制器使用的内存是独立显存的时候才需要使用,直接使用核心层read
  • fb_write:当你的lcd控制器使用的内存是独立显存的时候才需要使用,直接使用核心层write
  • fb_check_var:检测应用程序传递下来的可变参数是否合法。当你不提供给应用程序通过ioctl命令动态修改LCD可变参数时不需要实现。
  • fb_set_par:实现的功能是把可变参数设置到硬件寄存器中去
  • fb_blank:实现屏幕的黑屏白屏模式(开屏,关屏)
  • fb_fillrect:实现功能是填充矩形
  • fb_copyarea:实现功能是区域复制
  • fb_imageblit:实现功能是绘制位图
  • fb_mmap:实现的功能是把内核空间的分配的显存映射到用户空间中对应的mmap系统调用,当你的控制器是独显的时候才需要

四、主要的API函数


/*
函数功能:申请一个`fb_info`结构体
参数说明  :size 额外的内存*dev 指针, 这里填0,表示这个申请的结构体里没有内容
*/
struct fb_info *framebuffer_alloc(size_t size, struct device *dev);/*
函数功能:注册fb_info
*/
int register_framebuffer(struct fb_info *fb_info)/*
函数功能:注销fb_info
*/
int unregister_framebuffer(struct fb_info *fb_info)/*
函数功能:动态分配DMA内存,同时可以得到分配内存的虚拟地址和物理地址
分配一段`DMA`缓存区,分配出来的内存会禁止`cache`缓存(因为`DMA`传输不需要`CPU`);它和` dma_alloc_coherent ()`函数相似,不过 `dma_alloc_coherent ()`函数是分配出来的内存会禁止`cache`缓存以及禁止写入缓冲区。参数说明 :dev 指针,这里填0,表示这个申请的缓冲区里没有内容size 分配的地址大小(字节单位)*handle 申请到的物理起始地址gfp 分配出来的内存参数,标志定义在<linux/gfp.h>,常用标志如下://GFP_ATOMIC 用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.//GFP_KERNEL 内核内存的正常分配. 可能睡眠.//GFP_USER 用来为用户空间页来分配内存; 它可能睡眠.
返回值: 申请到的DMA缓冲区的虚拟地址,若为NULL,表示分配失败,则需要使用dma_free_writecombine()释放内存,避免内存泄漏
*/
void *dma_alloc_writecombine(struct device *dev, size_t size,dma_addr_t *dma_handle, gfp_t flag)/*
功能:释放由dma_alloc_writecombine分配的dma内存
参数:
dev:设备指针如果没有赋值NULL
size:内存大小
cpu_addr:dma_alloc_writecombine得到的虚拟地址首地址
dma_handle:作为输出参数使用,存放分配到的内存对应的物理地址
*/
void dma_free_writecombine(struct device *dev, size_t size,void *cpu_addr, dma_addr_t dma_handle)

lcd每屏显示的数据量很大,所以lcd一般是利用DMA来搬运数据,而DMA模块只会使用物理地址,所以LCD驱动中需要记录物理地址。

五、fb_mem.c源码分析

在阅读源码前你需要知道,主设备号注册的的字符设备所绑定的fops,该主设备下的次设备也是也会调用的该fops,而并不是调用的次设备中的fops

1、fbmem_init

fbmem_init函数是fb驱动的入口函数,主要就是注册了字符设备和创建类,可以看到做的工作其实很少。

2、register_framebuffer

register_framebuffer中主要是在/dev下创建了设备节点,和初始化fb_info结构体,并在fb_class下创建属性文件

这里只截取了重要的一部分,其余部分都在初始化设备的fb_info结构体。

3、unregister_framebuffer

unregister_framebuffer中,主要是删除设备和释放内存

4、fb_open

通过次设备号,获得索引值,并调用open方法。


其他fb_opf方法(read,write,mmap)类似,最终都是会调用到设备驱动中的方法里去,这里就不做重复的描述了。

6、总结

总的来说,Frame Buffer的驱动还是很简单的,与misc驱动一样,都是通过主设备号的file_fops方法去控制下面的子设备。一般来说驱动都是芯片厂家写好了的,我们只需要去配置参数就可以了,但对于入这一行的人来说,也需要去了解驱动的原理,遇事则不慌。至于驱动的实现则放在我另一个专栏里,欢迎大家去看并指正。

Linux 驱动 – Frame Buffer (帧缓冲)显示驱动相关推荐

  1. LED显示驱动(三):显示驱动底层学习小结

    一.DE硬件架构 显示系统可划分为三个层面,驱动层,框架层及底层. 底层与图形硬件相接,将上层配置的功能参数转换成硬件需要的参数,配置相应寄存器. 显示框架层对底层进行抽象封装成功能模块. 驱动层对外 ...

  2. LDE显示驱动(四):显示驱动内核底层代码分析

    作者:DayInAI 日期:20190124 一.RTMX 1)int de_rtmx_set_route(unsigned int sel, unsigned char pno, unsigned ...

  3. LED显示驱动(二):显示驱动FPGA验证流程与注意细节

    显示驱动FPGA验证流程与注意细节 验证流程 :                                                                             ...

  4. autocad显卡驱动文件hdi_AUTOCAD启动提示显示驱动文件丢失怎么办?hdi是什么文件?...

    有网友说他的AUTOCAD 2014启动的时候提示缺少显示驱动文件,如下图所示. 其实这种问题不是真正缺少文件,也不是什么direct X的事儿,而是注册表中记录驱动的路径错误,只需要将注册表中的相关 ...

  5. Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————H264压缩视频

    H264视频压缩主要步骤 压缩前的一些初始化 压缩帧再写入文件 压缩完成后资源的一些清理 /* encode.h */ #ifndef ENCODE_H #define ENCODE_Hint Enc ...

  6. LED显示驱动(八):显示驱动调试问题

    1.编译layer_demo常见问题 1)修改display_fb_request 图层属性内容,显示如下stray错误? 解决办法:代码文件存在中文的空格或者字符.去掉空格.中文字符. 2.用户空间 ...

  7. 全志t3linux驱动_全志T3 Linux显示驱动分析

    1.总体架构 全志T3处理器的显示框架是基于标准Linux的帧缓冲架构,其结构如图 1.1所示.显示控制器DE的驱动架构如图 1.2所示,包括屏蔽差异的显示管理抽象层,以及显示图层驱动.显示设备驱动. ...

  8. 全志T3 Linux显示驱动分析

    1.总体架构 全志T3处理器的显示框架是基于标准Linux的帧缓冲架构,其结构如图 1.1所示.显示控制器DE的驱动架构如图 1.2所示,包括屏蔽差异的显示管理抽象层,以及显示图层驱动.显示设备驱动. ...

  9. android系统平台显示驱动开发简要:Samsung LCD接口篇『三』

    平台信息: 内核:linux3.4.39 系统:android4.4  平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新 ...

最新文章

  1. 速度超Mask RCNN四倍,仅在单个GPU训练的实时实例分割算法 | 技术头条
  2. 使用深度神经网络进行自动呼叫评分(一)
  3. 奇迹服务器维护,奇迹MU 3月31日服务器维护更新公告
  4. 军队可以用oracle,使用Oracle JRockit 提高tomcat性能
  5. 互联网协议 — TLS — SNI
  6. AutoCompleteTextView的简单用法
  7. ubuntu下搭建eclipse+tomcat的web开发环境
  8. 修改html时webpack热更新,利用webpack实现对html文件的热更新
  9. 【.net 深呼吸】自定义应用程序配置节
  10. java地图瓦片_百度地图瓦片层级范围对照表
  11. python中的requests模块的使用大全
  12. 魅族魅蓝mirror简单打开usb调试模式的步骤
  13. 小程序分享到朋友圈_如何给小程序添加分享朋友圈
  14. C/C++:各类型变量占用字节
  15. phpstorm xdebug本地调试断点不生效_PHPSTORM与xdebug配置
  16. 《Cocos2D-x权威指南》——3.1 节点类
  17. 视觉检测售价_视觉自动化检测设备多少钱一台,它是如何报价的?
  18. 二维离散傅里叶变换最详手算
  19. 产品设计 - AARRR模型,增长和变现
  20. 【2021全国高校计算机能力挑战赛Python题目】17.学科竞赛 现有六门功课(语文、数学、物理、化学、政治、历史)的成绩,现在需要从中选拔优秀同学参加如下学科竞赛

热门文章

  1. 天魔 The Omen
  2. GamingAnywhere 一:GA初览
  3. 360安全卫士,还有这么多,小兄弟?
  4. 京东商品比价分析-数据分析项目
  5. 浅谈学术论文的撰写与发表(听讲座的总结)
  6. 路由器的基本配置和Talent配置
  7. 分享77个NET源码,总有一款适合您
  8. mysql 整理 是什么意思_MySQL问答整理
  9. 分枝限界法求解流水线作业调度问题
  10. 未来五年 LED智慧透明屏未来3大发展趋势