Linux驱动程序的数据封装

引言

0

基于ARM内核的SoC在引入设备树技术之后,通过设备树文件来描述不同的设备并匹配不同的驱动代码,使得一个kernel镜像文件可以支持多种设备。这种代码可重用的思想不仅体现在设备树文件中,在驱动代码中同样也有所体现。其中之一就是驱动代码中设备描述表-of_device_id。同一个IP集成到不同SoC或者根据应用场景激活不同功能,可以通过of_device_id这个数据结构来实现。

对于同一个IP集成到不同SoC的应用场景而言,其寄存器基地址以及时钟等参数可能不同,但是IP功能基本一样。那么可以通过of_device_id里的不同data条目获取对应的参数信息。例如exynos的dsi IP,在不同版本的SoC中基地址不同,定义了5种SoC类型。在dsi probe时获取其在SoC中的基地址。

10a2dfee8f1635e822c17739bf9eb056.png

49d7dcd0b310ba1448f841c3cf1724f3.png

下面驱动代码表示该模块需要支持多种不同时钟频率的初始化,可以定义一个of_device_id表,根据匹配到的设备信息为每一种时钟提供独立的初始化函数。由of_device_id_match_data获取到不同的init_fn,按照不同的dev.of_node,执行return init_fn(np);

de921b3b1d16ee878e90cc559d60a243.png

以上应用场景核心的数据结构是of_device_id,关键的处理函数是of_device_get_match_data(),当然,关于of_device_id的应用场景不仅仅限于上面说的这两种。

数据结构of_device_id

1

of_device_id数据结构如下,定义在mod_devicetable.h中,组成也并不复杂。

1struct of_device_id {
2    char    name[32];
3    char    type[32];
4    char    compatible[128];
5    const void *data;
6};

mod_devicetable.h这个文件最初并没有of_device_id这个数据结构,该文件的历史暂时也只能查到2005年的Linux-2.6.12-rc2

f9ab4afa62127f9ca1a48db4961af4aa.png

它的功能从最初的文件中也可以看到,主要是为PCI以及USB设备使用的,将设备的vendor ID、subsystem ID、class等信息提供给scripts/table2alias.c,当系统新插入一个PCI或USB设备时,用户空间程序根据对应的vendor ID等信息来加载对应的驱动程序。

2005年7月Linux-2.6.13-rc2中提交了of_match_id这个数据结构的代码。

adf8836b4d17b896977f44e96ca01ffe.png

         of_device_get_match_data()

2

函数原型位于drivers/of/device.c

1const void *of_device_get_match_data(2    const struct device *dev)3{4    const struct of_device_id *match;56    match = of_match_device(xxx);7    if (!match)8        return NULL;9
10    return match->data;
11}
12EXPORT_SYMBOL(of_device_get_match_data);

这个函数的返回值类型可强制转换成任何类型,取决于驱动程序中例化数据结构of_device_id data。当然,由于of_device_get_match_data的函数返回值类型决定了不做强制类型转换,也不会有问题。


代码中增加下面的内容,来追踪of_device_get_match_data执行流程。

#定义of_device_id并完成例化

cd3668d3f1de250628938882f3d9be4d.png

#在probe函数中增加获取数据的代码

e0ff725ff9181b558463c0952ad17114.png

执行结果显示正确的获取到了of_device_id各个成员例化的value值

db91d3c4c9742f900a467448d4843c63.png

#of_device_get_match_data()代码流程

31d15354076f0bb273f0be748ef13539.png

有几种情况是无法获取到数据的

##解析dtb之后未创建设备结点

##驱动代码未实现of_device_id设备表

##of_device_id成员compatible、name、type的值和设备树中定义的同

基于模块加载的并且可以热插拔的驱动程序,可以在系统启动后查看设备表信息。以定位出未获取到设备表信息的故障原因。

查看设备表信息

3

能够查看到设备表信息的一个前置条件是在定义of_device_id的时候,要将该设备表通过MODULE_DEVICE_TABLE来进行声明注册,否则在用户空间是看不到的。其定义在/include/linux/module.h中。type可以是of、usb、pci等,name为设备表的名字。

38f57c4b7218242b7ab41d8573a29173.png

内核中scripts/mod/file2alias.c,用于将设备表导出到用户空间modules.alias中,所以可以直接查看modules.alias文件。
a8ebcd7c721e34efd98157a5bce41b7b.png


也可以通过modinfo来查看ko文件符号信息

67eb64568cb77590063aab77fd2c38d7.png

设备表的定义如下,代码定义了name、type,那么设备树里同样也要定义:

0eed1a4f6bd9f96fd7c34e8748c1d3de.png

删除MODULE_DEVICE_TABLE,modules.alias里是没有设备表信息的。

0b260a99207e4099e450d6b688b1a7f0.png

对于of_device_id而言,name、type、compatible添加的方法:

017fc9451b30929ee1da9864c29020a0.png

#USB设备表

1struct usb_device_id {2    /* which fields to match against? */3    __u16       match_flags;45    /* Used for product specific matches; range is inclusive */6    __u16       idVendor;7    __u16       idProduct;8    __u16       bcdDevice_lo;9    __u16       bcdDevice_hi;
10
11    /* Used for device class matches */
12    __u8        bDeviceClass;
13    __u8        bDeviceSubClass;
14    __u8        bDeviceProtocol;
15
16    /* Used for interface class matches */
17    __u8        bInterfaceClass;
18    __u8        bInterfaceSubClass;
19    __u8        bInterfaceProtocol;
20
21    /* Used for vendor-specific interface matches */
22    __u8        bInterfaceNumber;
23
24    /* not matched against */
25    kernel_ulong_t  driver_info
26        __attribute__((aligned(sizeof(kernel_ulong_t))));
27};

#PCI设备表

1struct pci_device_id {
2    __u32 vendor, device;       /* Vendor and device ID or PCI_ANY_ID*/
3    __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
4    __u32 class, class_mask;    /* (class,subclass,prog-if) triplet */
5    kernel_ulong_t driver_data; /* Data private to the driver */
6};

对于这两种类型的设备,导出的符号信息和普通设备也不一样。

PCI设备导出到用户空间的设备信息:

27b8bb01c73a35f7482f0e2f70d16ec2.png

导出PCI设备信息的代码

ddf3bc88db419f7fb0b99a18d37131cf.png

USB设备导出到用户空间的设备信息:


d88bc6cc0fe548c8db46a3bc3f81289f.png

导出USB设备信息的代码

51652b03f9423521649945dd0f97d171.png

除了上面三种设备描述table之外,kernel还提供了很多种其他的设备描述表,定义在include/linux/mod_devicetable.h

0e658a5dc60abdbc3b3b5a16e15e5e62.png

mod_devicetable.h的commit log:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/include/linux/mod_devicetable.h


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

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

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

相关文章

计算机沟通方式,雅思阅读练习:计算机改变沟通方式

雅思考试中,我们可以运用一些解题方法和技巧,来帮助我们提高答题的准确率,拿到一个更高的分数。今天小编为大家分享雅思阅读练习:计算机改变沟通方式,一起来学习一下。Almost everyone with or without a computer is …

小小突击队为什么服务器正在维护中,4399小小突击队3月20日5:30更新维护公告!...

亲爱的各位玩家:《小小突击队》将于3月20日5:30-7:30进行维护更新,更新内容如下:一.英雄1.新增:海牙战士为了寻找幼年时走失妹妹,加入了小小突击队2.调整:龙骑士去国外旅游,水深火热,技能效果提…

消息驱动 微服务器,消息驱动的微服务-Spring Cloud Stream整合RocketMQ

系列文章导航: Spring Cloud Alibaba微服务解决方案常用MQ产品的选择目前主流的MQ产品有kafka、RabbitMQ、ActiveMQ、RocketMQ等。在MQ选型时可以参照这篇文章选择合适的MQ产品。RocketMQ及控制台搭建RocketMQ的搭建可以参考这篇文章。RocketMQ控制台的搭建可以参考这篇文章。R…

低并发编程

大家好,我是闪客,感谢 写代码的篮球球痴 提供的平台让我在这里给大家介绍自己,这是我的公众号卡片。为了防止大家看到这里就点击了返回按钮,我先放一张图勾引一下您。这是我公众号做的第一张动图,好多读者当时说被这张…

总结一些调试的心得,ES7243

这两天在调试一个与语音ADC芯片,也遇到了一些问题,到目前位置也解决了问题,所以想说一下嵌入式调试的一些心得,如果大家在调试设备的时候遇到问题,可以回头来看看这篇文章,可能会得到一些启发。我调试的系统…

web存储机制localStorage和sessionStorage

https://www.cnblogs.com/yaoyuqian/p/7901052.html web存储包括两种:sessionStorage 和 localStorage(都是限定在文档源级别,非同源文档间无法共享) 1.sessionStorage 数据放在服务器上(IE不支持)严格用于…

“元宇宙” 是什么东西?

最近元宇宙的概念很火,所以转发一篇文章给大家看看。每当一个新东西出来的时候,有的人觉得这个是个好东西,也有人嗤之以鼻,觉得这个就是用来割韭菜的。就拿比特币来说,比特币有什么价值?他的价值无非就是操…

分布式系统服务器要求,浅谈分布式系统

分布式系统的由来软件系统的架构一直以来随着技术的发展和市场的需求进行着不断的演进。最初,各行业业务相对比较简单,对系统的要求也不高,软件系统的架构均采用单一应用架构,此时单台服务器即可满足系统的要求。之后,…

OCP Java 自测

一个朋友准备去考OCP Java认证,即原来的SCJP。心血来潮也想测测自己什么水平。找了本McGraw.Hill.OCP.Java.SE.6.Programmer.Practice.Exams,开盘就是两套自测题。14个题目,给了42分钟,按书中说法是过了8个就可以去考了。掐上秒表…

内核该怎么学?Linux进程管理工作原理(代码演示)

前言:Linux内核里大部分都是C语言。建议先看《Linux内核设计与实现(Linux Kernel Development)》,Robert Love,也就是LKD。Linux是一种动态系统,能够适应不断变化的计算需求。Linux计算需求的表现是以进程的通用抽象为中心的。进程可以是短期…

如果访问云服务器上的文件,如果访问云服务器上的文件

如果访问云服务器上的文件 内容精选换一换WinSCP工具可以实现在本地与远程计算机之间安全地复制文件。与使用FTP上传代码相比,通过 WinSCP 可以直接使用服务器账户密码访问服务器,无需在服务器端做任何配置。通常本地Windows计算机将文件上传至Linux服务…

int *p = *******a是什么鬼?

这是在朋友圈里面看到有人调侃的一个C语言题目,这里拿出来分享给大家看看。1我们知道int a 120; int* p &a;这样我们可以给指针p赋值。指针很多初学者学习的时候会觉得一脸懵逼,我们只要明白几个关键的东西,会让我们对指针理解更深入一…

你见过的MCU最高GPIO翻转频率是多少?

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT1010上的普通GPIO与高速GPIO极限翻转频率。上一篇文章 《聊聊i.MXRT1xxx上的普通GPIO与高速GPIO差异及其用法》,痞子衡从原理上介绍了 i.MXRT1xxx 系列里普通 GPIO 和 …

django中的admin组件之自定义组件的增删改查的完善

昨天我们将自定义列放在类我们自定义的Bookconfig配置类内,但是这样就写死了,因为当我们访问publish表的时候应该也有这样的自定义列,所以我们应该将我们的自定义列放在默认的配置表里面。应该怎么做? 当我们的自定义列挪到默认配…

“制造商和技术支持商”

1.用优化工具。 2.system32中的OEMINFO.ini和OEMLOGO.bmp文件 转载于:https://blog.51cto.com/honglingjin2011/537680

青春是一列不再回头的火车…

高中那年,我表姐对我说:“不要老想着出去打工赚钱,好好读书,将来肯定有用,也不要想着现在日子长得很,等你像我这样结婚生子后,一天一眨眼就过完了。”当时听了没有多大感觉,如今深以…

我和周立功的聊天

算起来,我和周工认识也有7年了,7年前我在中兴,偶然一次加了周工的微信,有一次年末,周立功在推广他们的示波器,广哥拉我进周立功的示波器技术支持群微信群,说是周工要给大家发红包。那时候&#…

Python 37 进程池与线程池 、 协程

一:进程池与线程池 提交任务的两种方式: 1、同步调用:提交完一个任务之后,就在原地等待,等任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行 2、异步调用:提…

在腾讯做嵌入式是怎么样的

昨天发朋友圈,是我帮忙同学拍的几张照片,自己觉得拍的不错,点赞的人还挺多的,就想着聊聊在腾讯做嵌入式软件开发的情况。我面试的BSP驱动开发工程师,入职后也从事这方面的事情,但是并不仅仅是BSP驱动。现在…

NFS无法启动根文件系统的解决

为了调试驱动,整了一天的NFS启动根文件系统出了各种问题,后来还是一一解决,不过还不太完美,因为不能使用交换机,我只能用PC和目标板直连,导致我上网很麻烦 无法挂载问题一: IP-Config: Cannot a…