LCD 设备驱动框架分析及核心结构


Linux 下很多东西都是和结构体相关,举个例子,时钟大家都知道吧,Linux 下对应时钟的东西就有好几个结构体,所以你要是想明白Linux 下那些东西,对结构体要有所了解,LCD 是基础的驱动设备,里面涉及到的东西很多,这篇文章只讨论Linux 下的LCD 框架,还有框架里面涵盖的几个结构体,涉及 android 的话会复杂很多,这里就不做讨论,希望大家看完文章能够知道LCD 在内核理解的如何构成的。


一、LCD 设备驱动框架分析

核心层是通用的,不需要做任何修改「这和其他很多驱动框架类似,比如input子系统的核心层也是不需要修改,但是要懂如何调用」

驱动开发者只需要实现硬件驱动层。

  • 帧缓冲设备可以是一个完整的子系统,主要由核心层的 fbmem.c和硬件设备驱动层构成。

  • 核心层代码 fbmem.c 向上提供了完整的字符设备操作接口,也就是实现注册字符设备,提供通用的open,read,write,ioctl,mmap 等接口;

    向下给硬件设备驱动层提供标准的驱动编程接口;

  • 在 Linux 系统中,一个硬件 LCD 控制器(显卡)抽象为一个 fb_info 结构,要实现一个 LCD 驱动就是要实现这个结构,并且使用核心层提供的注册函数注册。

  • fb_info 中通过其中的 fb_ops 结构指针提供了实际硬件操作方法。

  • fb_info 中通过其中的 fb_var_screeninfo 结构和 fb_fix_screeninfo 结构提供了具体 lcd 屏基本信息。

  • 注册:register_framebuffer
  • 注销:

    unregister_framebuffer

二、LCD 设备驱动核心结构 struct fb_info

该结构体记录了帧缓冲设备的全部信息,包括有:

1、 设备的设置参数

2、 状态

3、 对底层硬件操作的函数指针。

在 Linux 中, 每一个帧缓冲设备都必须对应一个 fb_info。fb_info 在/linux/fb.h 中的定义如下:

struct fb_info {
atomic_t count;/* 原子变量 */
int node;/*存放屏的序号, 也可以说是次设备号*/
int flags;
struct mutex lock; /* Lock for open/release/ioctl funcs */
struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
struct fb_var_screeninfo var; /* LCD 可变参数结构体 */
struct fb_fix_screeninfo fix; /* LCD 固定参数结构体 */
struct fb_monspecs monspecs; /* LCD 显示器标准 */
struct work_struct queue; /* 帧缓冲事件队列 */
struct fb_pixmap pixmap; /* 图像硬件 mapper*/
struct fb_pixmap sprite; /* 光标硬件 mapper */
struct fb_cmap cmap; /* 当前的颜色表 */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* 当前的显示模式 */

#ifdef CONFIG_FB_BACKLIGHT
/* assigned backlight device */
/* set before framebuffer registration,
remove after unregister */
struct backlight_device *bl_dev;/* 对应的背光设备 */

/* Backlight level curve */
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];/* 背光调整 */
#endif
#ifdef CONFIG_FB_DEFERRED_IO
struct delayed_work deferred_work;/*延时工作队列*/
struct fb_deferred_io *fbdefio;
#endif

struct fb_ops *fbops;/* 真正操作 LCD 硬件寄存器的方法集合*/
struct device *device; /* 内嵌的设备模型 */
struct device *dev; /* fb 设备 */
int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* 图块 Blitting */
#endif
char __iomem *screen_base; /* LCD显存虚拟基地址 */
unsigned long screen_size; /* LCD IO 映射的虚拟内存大小 */
void *pseudo_palette; /* 指向 16 种颜色调试板,其实就是一块内存 */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* LCD 的挂起或恢复状态 */
void *fbcon_par; /* fbcon use-only private area */
/* From here on everything is device dependent */
void *par; /*私有数据,驱动编程者可以用来存放自己的数据结构地址*/
/* we need the PCI or similar aperture base/size not
smem_start/size as smem_start may just be an object
allocated inside the aperture so may not actually overlap */
struct apertures_struct {
unsigned int count;
struct aperture {
resource_size_t base;
resource_size_t size;
} ranges[0];
} *apertures;
};

重要成员:var, fix, fbops, screen_base , 使用标准的 LCD 框架编写, 这 4 个成员是一定实现。

2.1、LCD 设备驱动可变参数结构 struct fb_var_screeninfo

struct fb_var_screeninfo 表示一个 LCD 控制器,主要记录用户可以修改的控制器的参数(指的是在程序运行过程中可修改的 LCD 参数) , 比如屏幕的分辨率和每个像素的比特数等,这个结构的存放的参数大部分就是 LCD 屏的时序参数, 驱动程序者根据自己使用的LCD 屏的资料设置。该结构体定义如下:

struct fb_var_screeninfo {
__u32 xres; /* 可见屏幕一行有多少个像素点*/
__u32 yres; /* 可见屏幕一屏有多少行*/
__u32 xres_virtual; /* 虚拟屏幕一行有多少个像素点*/
__u32 yres_virtual; /* 虚拟屏幕一屏有多少行*/
__u32 xoffset; /* 虚拟屏到实际屏的水平偏移量 */
__u32 yoffset; /*虚拟屏到实际屏的垂直偏移量*/

__u32 bits_per_pixel; /* LCD 屏工作时 BPP*/
__u32 grayscale; /*0 = 彩屏, 1 = 灰度,非彩屏,一般不使用了 */

struct fb_bitfield red; /* 红色的长度和偏移信息 */
struct fb_bitfield green; /* 绿色的长度和偏移信息 */
struct fb_bitfield blue; /* 蓝色的长度和偏移信息*/
struct fb_bitfield transp; /* 透明度的长度和偏移信息*/

__u32 nonstd; /* 0 表示标准像素格式,基本都是标准 */
//修改可变参数生效时刻,一般是马上生效,对应值是 0,宏名是 FB_ACTIVATE_NOW
__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 屏的工作时序,
//对应的前面移植 LCD 传递下来的 struct fb_videomode 结构
//除 pixclock 本身外, 其他都以像素时钟为单位
/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* 像素时钟(皮秒) */
__u32 left_margin; /* 左边距, 对应 TFT 控制器时序的水平前沿信 */
__u32 right_margin; /* 右边距, 对应 TFT 控制器时序的水平后沿信 */
__u32 upper_margin; /* 上边距, 对应 TFT 控制器时序的垂直前沿信 */
__u32 lower_margin; /* 下边距, 对应 TFT 控制器时序的垂直后沿信 */
__u32 hsync_len; /* 水平同步的长度 */
__u32 vsync_len; /* 垂直同步的长度*/
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* 顺时针旋转的角度 */
__u32 colorspace; /* colorspace for FOURCC-based modes */
__u32 reserved[4]; /* Reserved for future compatibility */
};
struct fb_bitfield结构说明:
struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right; /* != 0 : Most significant bit is */
/* right */
};

表示颜色的长度和偏移量,如RGB=888

struct fb_bitfield R:
R.offset : 16
R.length : 8
struct fb_bitfield G:
G.offset : 8
G.length : 8
struct fb_bitfield B:
G.offset : 0
G.length : 8

2.2、LCD 设备驱动固定参数结构 struct fb_fix_screeninfo

该结构存放的是屏的一些固定不可修改的参数,在 LCD 正常使用运行期间是不能修改。所以这些值一般是在驱动程序的初始化阶段完成填充, 当 LCD工作起来后就不能再修改了。结构定义如下:

struct fb_fix_screeninfo {
char id[16]; /* 字符串形式的标识符, 实际上就是 lcd 设备的别名 */
unsigned long smem_start; /* fb 缓存的开始位置(物理地址) */
/* (physical address) */
__u32 smem_len; /* fb 缓存的长度 */
//表示像素类型,一般都标准像素格式
//FB_TYPE_PACKED_PIXELS
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /*FB_VISUAL_TRUECOLOR,FB_VISUAL_PSEUDOCOLOR*/
__u16 xpanstep; /* 如果没有硬件平移功能设置为 0 */
__u16 ypanstep; /* 如果没有硬件平移功能设置为 0 */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* 一行占用的内存字节数 */
unsigned long mmio_start; /* 内存映射 IO 的开始位置 */
/* (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 */
};

重要成员:id:lcd 设备的别名,即标识名,随便 smem_start:显存物理起始地址,注意,是物理地址,不是虚拟地址。驱动中定义的变量,普通动态分配内存的方法得到的都是虚拟址,要得到物理地址必须使用专用的 DMA 内存分配函数:

void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag)

功能:动态分配 DMA 内存,同时可以得到分配 的内存虚拟地址和物理地址 参数:dev 设备指针,如果没有 NULL, size:内存大小 dma_handle:做为输出参数使用, 存放分配到的内存对应的物理地址 flag:是内存分配方式 返回值:分配到的内存的首地址。DMA 缓冲区释放函数:

void dma_free_writecombine(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle)

功能:释放由 dma_alloc_writecombine 分配的 dma 内存 参数:dev 设备指针,如果没有 NULL,

  • size:内存大小
  • cpu_addr:dma_alloc_writecombin 得到的虚拟地址首地址
  • dma_handle:做为输出参数使用,存放分配到的内存对应的物理地址
  • PS: 因为 LCD 是使用 DMA 模块来搬运数据的,而 DMA 模块只涉及物理地址,所以 LCD 驱动中需要记录物理地址。
  • line_length:一行占用的内存字节数
  • smem_len:显存长度

2.3、LCD 设备驱动硬件操作方法结构 struct fb_ops

fb_ops 结构体是对底层硬件操作的函数指针,是内核用来描述真正硬件操作方法的数据结构。该结构体中定义了对硬件的操作如下:

struct fb_ops {
/* open/release and usage marking */
struct module *owner;
/* 1.打开 lcd ,一般不用实现, 如果实现也是写一些 lcd 初始化的代码*/
int (*fb_open)(struct fb_info *info, int user);
/* 2.关闭 lcd ,一般不用实现, 如果实现也是写一些 lcd 初始化的代码*/
int (*fb_release)(struct fb_info *info, int user);

/* 3.读 lcd 缓冲区的数据到用户空间 */
ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
size_t count, loff_t *ppos);
/* 4.把用户空间中传递下来的缓冲区的数据写入 lcd 的显示缓冲区*/
ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos);

/* 5.检查可变参数, 如果不支持则进行修正*/
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
/*6.把设置的可变参数值更新到硬件寄存器中, 使之有效*/
int (*fb_set_par)(struct fb_info *info);

/* 7.设置颜色寄存器*/
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info);

/* set color registers in batch */
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);

/* 9.显示黑白模式, 一般要实现 */
int (*fb_blank)(int blank, struct fb_info *info);

/* 10.pan display */
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);

/* 11.矩形填充 */
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
/* 12.把一个区域的内容复制到另一个区域 Rotates the display */
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
/* 13.绘制图像 */
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);

/* 14.绘制光标 Draws cursor */
int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);

/* 15.旋转 LCD 显示 */
void (*fb_rotate)(struct fb_info *info, int angle);

/* 16.wait for blit idle, optional */
int (*fb_sync)(struct fb_info *info);

/* 17.ioctl 控制命令 */
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
unsigned long arg);

/* 18.Handle 32bit compat ioctl (optional) */
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
unsigned long arg);

/* 19.mmap 内存映射函数 */
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);

/* 20.获取 lcd 可变参数 */
void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
struct fb_var_screeninfo *var);

/* teardown any resources to do with this framebuffer */
void (*fb_destroy)(struct fb_info *info);

/* called at KDB enter and leave time to prepare the console */
int (*fb_debug_enter)(struct fb_info *info);
int (*fb_debug_leave)(struct fb_info *info);
};

常用重要成员:

  • fb_open: 当你的 lcd 不需要做什么特殊初始操作,这个方法可以不实现,一般不实现;
  • fb_release:当你的应用程序不使用 lcd 设备时候,需要做的事情就在这里实现,一般不实现;
  • fb_read:当你 LCD 控制器使用的内存是独立显存时候才需要实现,直接使用核心层通用 read。
  • fb_write:当你 LCD 控制器使用的内存是独立显存时候才需要实现,直接使用核心层通用 write。
  • fb_check_var: 实现的功能检测应用程序传递下来的可变参数是否合法。当不提供给应用程序,通过 ioctl 命令动态修改 LCD 可变参数时候不需要实现。
  • fb_set_par:实现的功能是把可变参数设置到硬件寄存器中去。当不提供给应用程序,通过 ioctl 命令动态修改 LCD 可变参数时候不需要实现。
  • fb_blank:实现的功能是黑屏白屏模式(开屏,关屏)。
  • fb_fillrect:实现的功能是填充矩形,如果是非独立显卡直接使用内核自带的函数 cfb_fillrect。
  • fb_copyarea:实现的功能是区域复制数据,如果是非独立显卡直接使用内核自带的函数 cfb_copyarea
  • fb_imageblit:实现的功能是区域显示图像,如果是非独立显卡直接使用内核自带的函数 cfb_imageblit
  • fb_ioctl:实现功能是让用户通过 ioctl 接口调用这个函数来对 LCD 特殊器特殊功能控制,如控制器只实现了一般的标准功能,不需要实现,使用核心层默认的 ioctl 接口就行可以了。
  • fb_mmap:  实现的是把内核空间的分配的显存映射到用户空间中对应的 mmap 系统调用,当你控制是独立显卡时候才需要实现。

这个结构是真正实际实现不同 LCD 的硬件操作函数功能, 但是一般情况下, 如果我们的 LCD 控制器不属于独立显卡类型, 那这个结构的很多成员都是不用实现的, 比如像结构的 fb_open, fb_release, fb_read, fb_write 等这些函数不用实现, 而是使用 Framebuffer 的核心层 fnmem.c 实现的通用函数就可以了。

以上结构中如果要实现和控制台相关的功能, 结构中的 fb_check_var, fb_set_par, fb_blank, fb_cursor,fb_fillrect, fb_copyarea, fb_imageblit 接口是要实现的, 但是这几个中除 fb_check_var, fb_set_par, fb_blank 这三个要根据用户自己的硬件特征来实现不同的代码外,余下的都可以直接使用内核中已经实现的默认函数(当然,内核实现的通用代码),这些在后面的代码分析中看到。

—————END—————

扫码或长按关注
回复「 加群 」进入技术群聊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka 启动_Kafka管理工具Kafka Manager

Kafka作为分布式消息系统以其轻量级、可扩展、高通吐等特点而得到广泛应用,最近在项目中用Kafka作为中间件进行数据交互。为了监控Kafka的运行情况,在网上找了个开源的Kafka监控工具Kafka-manager对Kafka集群监控。为什么选用Kafka-manager而不是KafkaOf…

Linux背后的思想

01Linus TorvaldsLinus Torvalds两次改变了技术,第一次是Linux内核,它帮助互联网的发展;第二次是Git,全球开发者使用的源代码管理系统。在一次TED的采访中,Torvalds以极其开放的态度讨论了他独特的工作方式和性格特点。…

linux执行sh提示非标准环境,Linux执行.sh文件时提示No such file or directory该怎么办(三种解决办法)...

先给大家看下问题描述,下图是我在运行时出现错误截图:解决方法分析原因,可能因为我平台迁移碰到权限问题我们来进行权限转换1)在Windows下转换:利用一些编辑器如UltraEdit或EditPlus等工具先将脚本编码转换,再放到Linu…

你应该知道Linux内核softirq

说起这个softirq ,很多人还是一头雾水,觉得这个是什么东西,跟tasklets 和 workqueue有什么不同。每次谈到这个,很多人,包括我,都是有点紧张,特别是面试的时候,因为你一旦说错了什么&…

linux 查看磁盘分区,文件系统,使用情况的命令和相关工具介绍,Linux 查看磁盘分区、文件系统、使用情况的命令和相关工具介绍...

Linux 查看磁盘分区、文件系统、使用情况的命令和相关工具介绍作者:北南南北来自:http://doc.xuehai.net提要:Linux 磁盘分区表、文件系统的查看、统计的工具很多,有些工具是多功能的,不仅仅是查看磁盘的分区表&#x…

C语言,链表

定义一个链表的节点之前说到树,里面也有一个节点,节点是用来存数据的,不管是树还是其他什么数据结构,最终的目的都是用来处理数据的,所以节点里面包含两个东西,一个是指针,指针可以指向其他位置…

linux hosts文件如何修改_3 种方法教你在 Linux 中修改打开文件数量限制

当文件被打开访问时,操作系统临时分配一个名为文件句柄的数字。主内存的一个特殊区域是为文件句柄预留的,这个区域的大小决定了一次可以打开多少个文件。Linux上的进程受到许多限制,这些限制也阻碍它们正确地执行,而且每个进程都有…

10个高效Linux技巧及Vim命令对比

写在前面:今天没来得及唱歌~一个多星期没更新了,今天记录下我自己用得比较多的Linux命令行快捷键,小伙伴们别嘲笑我哈~不知道为啥,每次发文就有好几个小伙伴取消关注离开之前,可以告诉我为什么吗~~Vim的很多命令和功能…

python 微信机器人_Python 微信机器人

一、写在前边的话 如何做一个自动回复的微信机器人?机器人的功能有,自动加好友,关键字回复,等等,它甚至可以成为你的私人管家,只要你的代码到位。今天,主要讲解下,微信机器人-图灵版…

linux 控制台存储,技术|使用 Stratis 从命令行管理 Linux 存储

通过从命令行运行它,得到这个易于使用的 Linux 存储工具的主要用途。正如本系列的第一部分和第二部分中所讨论的,Stratis 是一个具有与 ZFS 和 Btrfs 相似功能的卷管理文件系统。在本文中,我们将介绍如何在命令行上使用 Stratis。安装 Strati…

你想要的江湖,可能不在这时候笑傲

昨天看知识星球看到的一个码农的经历,然后我看了,也回答了,想把回答分享给大家,我觉得这应该是很多人都会遇到的。困扰的问题潜水这么久,有一个问题想问一下,帅张。可能有点啰嗦。就是在一家公司做开发&…

mysql binlog 备份_MySQL的binlog知识梳理

1、binlog概念:binlog是一个二进制格式的文件,用于记录“修改数据或可能引起数据变更”的SQL语句(查询的SQL不会记录)。2、binlog功能:(1)恢复: 利用binlog日志恢复数据库数据。(2)复制: 主从架构通过binlog同步数据。(3)审计: 可以用binlog中的信息进行审计&#x…

你需要知道的Linux 系统下外设时钟管理

嵌入式系统一般要求低功耗,出于这个原因,一般只把需要使用到的外设时钟源打开,其他不需要使用到的模块,则默认关闭它们。LCD 模块,上电时候默认情况是关闭的,所以,要想使用 LCD 模块&#xff0c…

千万级大表如何更快速的创建索引_分享一份生产环境mysql数据库大表归档方案,值得收藏...

概述分享下最近做的一个mysql大表归档方案,仅供参考。整体思路一、明确哪些大表需做归档1、数据库表概要信息统计SELECTt1.table_schema,t1.table_name,ENGINE,table_rows,CAST( data_length / 1024.0 / 1024.0 AS DECIMAL ( 10, 2 ) ) data_size(M),CAST( index_le…

载波和LoRa

最近lora这个很火,火的原因是因为国家出了一个政策,这个政策呢,有很多人解读了,我身边也有好几个朋友做这方面的,然后我今天找他们聊了下,得到的结果是,这个政策肯定是或多或少对现在的行情和市…

imread函数 matlab_【MATLAB图像处理学习】1.读取和显示图片

CHAPTER2 图像处理的基础函数【使用的教材:冈萨雷斯 数字图像处理MATLAB(Digital image processing with Matlab】【原书图片下载地址:点这里】先介绍三个MATLAB中图片基本操作:imread imshow imwrite2.2读取图片imread(filename)imread是读取…

一场不能只看结果的较量

林书豪的比赛看得真的很舒服,虽然输掉了比赛,但是看到两边不断改变打法,不断试图侵犯对方的夺取分数,就好比看了一场战争电影,过程酣畅淋漓,结果差点令人满意。第一节广东的双后卫给北京制造了非常多的麻烦…

嘻哈帝国第一季/全集Empire迅雷下载

英文译名Empire,第1季(2015-01-08)FOX.本季看点:《嘻哈帝国》卢西奥斯莱恩是一名超级音乐明星兼Empire娱乐公司的创始人,故事讲述了他如何在困境和失败中运营公司的故事。拥有庞大帝国的老板得了绝症,于是他决定培养继承人&#x…

cassandra可视化工具_一位数据科学家的私房工具清单

作为一位万人敬仰的数据科学家,不但需要培育一棵参天技能树,私人武器库里没有一票玩得转的大火力工具也是没法在江湖中呼风唤雨的。近日北卡来罗纳大学CTO,一位数据科学家Jefferson Heard分享了多年来收集沉淀的数据分析工具集:处…

Dev C++,一个好玩的猜数字游戏

周末了,看了一点代码,发现有一个好玩的数字游戏,贡献给大家,个人觉得还是挺好玩的。说个题外话,之前写的文章,都是零散的,主要是时间的原因,最近事情有点杂,一说到这个事…