Linux 驱动 – Frame Buffer (帧缓冲)显示驱动
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 (帧缓冲)显示驱动相关推荐
- LED显示驱动(三):显示驱动底层学习小结
一.DE硬件架构 显示系统可划分为三个层面,驱动层,框架层及底层. 底层与图形硬件相接,将上层配置的功能参数转换成硬件需要的参数,配置相应寄存器. 显示框架层对底层进行抽象封装成功能模块. 驱动层对外 ...
- LDE显示驱动(四):显示驱动内核底层代码分析
作者:DayInAI 日期:20190124 一.RTMX 1)int de_rtmx_set_route(unsigned int sel, unsigned char pno, unsigned ...
- LED显示驱动(二):显示驱动FPGA验证流程与注意细节
显示驱动FPGA验证流程与注意细节 验证流程 : ...
- autocad显卡驱动文件hdi_AUTOCAD启动提示显示驱动文件丢失怎么办?hdi是什么文件?...
有网友说他的AUTOCAD 2014启动的时候提示缺少显示驱动文件,如下图所示. 其实这种问题不是真正缺少文件,也不是什么direct X的事儿,而是注册表中记录驱动的路径错误,只需要将注册表中的相关 ...
- Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————H264压缩视频
H264视频压缩主要步骤 压缩前的一些初始化 压缩帧再写入文件 压缩完成后资源的一些清理 /* encode.h */ #ifndef ENCODE_H #define ENCODE_Hint Enc ...
- LED显示驱动(八):显示驱动调试问题
1.编译layer_demo常见问题 1)修改display_fb_request 图层属性内容,显示如下stray错误? 解决办法:代码文件存在中文的空格或者字符.去掉空格.中文字符. 2.用户空间 ...
- 全志t3linux驱动_全志T3 Linux显示驱动分析
1.总体架构 全志T3处理器的显示框架是基于标准Linux的帧缓冲架构,其结构如图 1.1所示.显示控制器DE的驱动架构如图 1.2所示,包括屏蔽差异的显示管理抽象层,以及显示图层驱动.显示设备驱动. ...
- 全志T3 Linux显示驱动分析
1.总体架构 全志T3处理器的显示框架是基于标准Linux的帧缓冲架构,其结构如图 1.1所示.显示控制器DE的驱动架构如图 1.2所示,包括屏蔽差异的显示管理抽象层,以及显示图层驱动.显示设备驱动. ...
- android系统平台显示驱动开发简要:Samsung LCD接口篇『三』
平台信息: 内核:linux3.4.39 系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新 ...
最新文章
- 速度超Mask RCNN四倍,仅在单个GPU训练的实时实例分割算法 | 技术头条
- 使用深度神经网络进行自动呼叫评分(一)
- 奇迹服务器维护,奇迹MU 3月31日服务器维护更新公告
- 军队可以用oracle,使用Oracle JRockit 提高tomcat性能
- 互联网协议 — TLS — SNI
- AutoCompleteTextView的简单用法
- ubuntu下搭建eclipse+tomcat的web开发环境
- 修改html时webpack热更新,利用webpack实现对html文件的热更新
- 【.net 深呼吸】自定义应用程序配置节
- java地图瓦片_百度地图瓦片层级范围对照表
- python中的requests模块的使用大全
- 魅族魅蓝mirror简单打开usb调试模式的步骤
- 小程序分享到朋友圈_如何给小程序添加分享朋友圈
- C/C++:各类型变量占用字节
- phpstorm xdebug本地调试断点不生效_PHPSTORM与xdebug配置
- 《Cocos2D-x权威指南》——3.1 节点类
- 视觉检测售价_视觉自动化检测设备多少钱一台,它是如何报价的?
- 二维离散傅里叶变换最详手算
- 产品设计 - AARRR模型,增长和变现
- 【2021全国高校计算机能力挑战赛Python题目】17.学科竞赛 现有六门功课(语文、数学、物理、化学、政治、历史)的成绩,现在需要从中选拔优秀同学参加如下学科竞赛