Linux学习第27天:Platform设备驱动开发(一): 专注与分散

news2024/11/17 15:44:05

Linux版本号4.1.15   芯片I.MX6ULL                                    大叔学Linux    品人间百味  思文短情长 


       专注与分散是我在题目中着重说明的一个内容。这是今天我们要学习分离与分层概念的延伸。专注是说我们要专注某层驱动的开发,而对于其他层则是芯片厂商需要完成的任务。分散则是要求有分层的概念,明白哪些是我们需要专注的内容,哪些是我们不需要关注的内容。所以专注与分散式相辅相成、不可分割的。

        本篇笔记主要学习了platform设备驱动开发的相关概念。将分成两次笔记进行学习。本次笔记主要学习platform设备驱动开发相关的理论知识。主要内容包括:Linux驱动的分离与分层、platform平台驱动模型简介。其中驱动的分离与分层有包括驱动的分离、驱动的分层。platform平台驱动模型简介主要包括platform总线、platform驱动与platform设备。

        本节的思维导图如下:

一、Linux驱动的分离与分层

1、驱动的分隔与分层

                                                        传统的I2C设备驱动

                                                                改进后的设备驱动

                                                                分割后的驱动框架

                                                        Linux总线、驱动和设备模式

2、驱动的分层

        分层的目的也是为了在不同的层处理不同的内容。分层极大简化我们的驱动编写。

二、platform平台驱动模型简介

1、platform总线

        bus_type结构体表示总线

1 struct bus_type {
2 const char *name; /* 总线名字 */
3 const char *dev_name;
4 struct device *dev_root;
5 struct device_attribute *dev_attrs;
6 const struct attribute_group **bus_groups; /* 总线属性 */
7 const struct attribute_group **dev_groups; /* 设备属性 */
8 const struct attribute_group **drv_groups; /* 驱动属性 */
9
10 int (*match)(struct device *dev, struct device_driver *drv);
11 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
12 int (*probe)(struct device *dev);
13 int (*remove)(struct device *dev);
14 void (*shutdown)(struct device *dev);
15
16 int (*online)(struct device *dev);
17 int (*offline)(struct device *dev);
18 int (*suspend)(struct device *dev, pm_message_t state);
19 int (*resume)(struct device *dev);
20 const struct dev_pm_ops *pm;
21 const struct iommu_ops *iommu_ops;
22 struct subsys_private *p;
23 struct lock_class_key lock_key;
24 };

        match函数完成设备与驱动之间匹配。

       platform 总线是 bus_type 的一个具体实例。

1 struct bus_type platform_bus_type = {
2 .name = "platform",
3 .dev_groups = platform_dev_groups,
4 .match = platform_match,
5 .uevent = platform_uevent,
6 .pm = &platform_dev_pm_ops,
7 };

        platform_bus_type 就是 platform 平台总线,其中 platform_match 就是匹配函数。

        驱动和设备的匹配有四种方法:

a.OF类型匹配;

b.ACPI匹配方式;

c.id_table匹配;

d.直接比较驱动和设备的name字段;

2、platform驱动

        platform_driver 结 构 体 表 示 platform 驱 动。

1 struct platform_driver {
2 int (*probe)(struct platform_device *);
3 int (*remove)(struct platform_device *);
4 void (*shutdown)(struct platform_device *);
5 int (*suspend)(struct platform_device *, pm_message_t state);
6 int (*resume)(struct platform_device *);
7 struct device_driver driver;
8 const struct platform_device_id *id_table;
9 bool prevent_deferred_probe;
10 };

probe 函数,当驱动与设备匹配成功以后 probe 函数就会执行,非常重要的函数!

driver 成员,为 device_driver 结构体变量, Linux 内核里面大量使用到了面向对象的思维, device_driver 相当于基类,提供了最基础的驱动框架。 plaform_driver 继承了这个基类,
然后在此基础上又添加了一些特有的成员变量。

id_table 是个表 (也就是数组 ),每个元素的类型为 platform_device_id,

device_driver 结构体定义在 include/linux/device.h, device_driver 结构体内容如下:

1 struct device_driver {
2 const char *name;
3 struct bus_type *bus;
4
5 struct module *owner;
6 const char *mod_name; /* used for built-in modules */
7
8 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
9
10 const struct of_device_id *of_match_table;
11 const struct acpi_device_id *acpi_match_table;
12
13 int (*probe) (struct device *dev);
14 int (*remove) (struct device *dev);
15 void (*shutdown) (struct device *dev);
16 int (*suspend) (struct device *dev, pm_message_t state);
17 int (*resume) (struct device *dev);
18 const struct attribute_group **groups;
19
20 const struct dev_pm_ops *pm;
21
22 struct driver_private *p;
23 };

        of_match_table 就是采用设备树的时候驱动使用的匹配表,每个匹配项都为 of_device_id 结构体类型,此结构体定义在文件 include/linux/mod_devicetable.h 中,内
容如下:

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

        对于设备树而言,就是通过设备节点的 compatible 属性值和 of_match_table 中每个项目的 compatible 成员变量进行比较,如果有相等的就表示设备和此驱动匹配成功。

        platform_driver_register 函数向 Linux 内核注册一个 platform 驱动:

int platform_driver_register (struct platform_driver *driver)

驱动卸载函数中通过 platform_driver_unregister 函数卸载 platform 驱动:

void platform_driver_unregister(struct platform_driver *drv)

platform 驱动框架如下所示:

/* 设备结构体 */
1 struct xxx_dev{
2 struct cdev cdev;
3 /* 设备结构体其他具体内容 */
4 };
5
6 struct xxx_dev xxxdev; /* 定义个设备结构体变量 */
7
8 static int xxx_open(struct inode *inode, struct file *filp)
9 {
10 /* 函数具体内容 */
11 return 0;
12 }
13
14 static ssize_t xxx_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t *offt)
15 {
16 /* 函数具体内容 */
17 return 0;
18 }
19
20 /*
21 * 字符设备驱动操作集
22 */
23 static struct file_operations xxx_fops = {
24 .owner = THIS_MODULE,
25 .open = xxx_open,
26 .write = xxx_write,
27 };
28
29 /*
30 * platform 驱动的 probe 函数
31 * 驱动与设备匹配成功以后此函数就会执行
32 */
33 static int xxx_probe(struct platform_device *dev)
34 {
35 ......
36 cdev_init(&xxxdev.cdev, &xxx_fops); /* 注册字符设备驱动 */
37 /* 函数具体内容 */
38 return 0;
39 }
40
41 static int xxx_remove(struct platform_device *dev)
42 {
43 ......
44 cdev_del(&xxxdev.cdev);/* 删除 cdev */
45 /* 函数具体内容 */
46 return 0;
47 }
48
49 /* 匹配列表 */
50 static const struct of_device_id xxx_of_match[] = {
51 { .compatible = "xxx-gpio" },
52 { /* Sentinel */ }
53 };
54
55 /*
56 * platform 平台驱动结构体
57 */
58 static struct platform_driver xxx_driver = {
59 .driver = {
60 .name = "xxx",
61 .of_match_table = xxx_of_match,
62 },
63 .probe = xxx_probe,
64 .remove = xxx_remove,
65 };
66
67 /* 驱动模块加载 */
68 static int __init xxxdriver_init(void)
69 {
70 return platform_driver_register(&xxx_driver);
71 }
72
73 /* 驱动模块卸载 */
74 static void __exit xxxdriver_exit(void)
75 {
76 platform_driver_unregister(&xxx_driver);
77 }
78
79 module_init(xxxdriver_init);
80 module_exit(xxxdriver_exit);
81 MODULE_LICENSE("GPL");
82 MODULE_AUTHOR("zuozhongkai");

        总体来说, platform 驱动还是传统的字符设备驱动、块设备驱动或网络设备驱动,只是套
上了一张“ platform” 的皮,目的是为了使用总线、驱动和设备这个驱动模型来实现驱动的分离与分层。

3、platform设备

        platform_device 这个结构体表示 platform 设备:

22 struct platform_device {
23 const char *name;
24 int id;
25 bool id_auto;
26 struct device dev;
27 u32 num_resources;
28 struct resource *resource;
29
30 const struct platform_device_id *id_entry;
31 char *driver_override; /* Driver name to force a match */
32
33 /* MFD cell pointer */
34 struct mfd_cell *mfd_cell;
35
36 /* arch specific additions */
37 struct pdev_archdata archdata;
38 };

使用 platform_device_register 函数将设备信息注册到 Linux 内核中,此函数原型如下所示:
 

int platform_device_register(struct platform_device *pdev)

如果不再使用 platform 的话可以通过 platform_device_unregister 函数注销掉相应的 platform
设备, platform_device_unregister 函数原型如下:

void platform_device_unregister(struct platform_device *pdev)

        platform 设备信息框架实例如下所示:

1 /* 寄存器地址定义*/
2 #define PERIPH1_REGISTER_BASE (0X20000000) /* 外设 1 寄存器首地址 */
3 #define PERIPH2_REGISTER_BASE (0X020E0068) /* 外设 2 寄存器首地址 */
4 #define REGISTER_LENGTH 4
5
6 /* 资源 */
7 static struct resource xxx_resources[] = {
8 [0] = {
9 .start = PERIPH1_REGISTER_BASE,
10 .end = (PERIPH1_REGISTER_BASE + REGISTER_LENGTH - 1),
11 .flags = IORESOURCE_MEM,
12 },
13 [1] = {
14 .start = PERIPH2_REGISTER_BASE,
15 .end = (PERIPH2_REGISTER_BASE + REGISTER_LENGTH - 1),
16 .flags = IORESOURCE_MEM,
17 },
18 };
19
20 /* platform 设备结构体 */
21 static struct platform_device xxxdevice = {
22 .name = "xxx-gpio",
23 .id = -1,
24 .num_resources = ARRAY_SIZE(xxx_resources),
25 .resource = xxx_resources,
26 };
27
28 /* 设备模块加载 */
29 static int __init xxxdevice_init(void)
30 {
31 return platform_device_register(&xxxdevice);
32 }
33
34 /* 设备模块注销 */
35 static void __exit xxx_resourcesdevice_exit(void)
36 {
37 platform_device_unregister(&xxxdevice);
38 }
39
40 module_init(xxxdevice_init);
41 module_exit(xxxdevice_exit);
42 MODULE_LICENSE("GPL");
43 MODULE_AUTHOR("zuozhongkai");

以下内容将在明天的笔记中详细说明:

三、硬件原理图分析

四、驱动开发

1、platform设备与驱动程序开发

2、测试APP开发

五、运行测试

1、编译驱动程序和测试APP

2、运行测试


本文为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。

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

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

相关文章

在centos服务器中完成jdk,tomcat,MySQL的安装以及前后端分离项目中后端的部署

目录 一. jdk,tomcat的安装 1.将要安装的软件压缩包放入到centos服务器上 2. 解压对应的安装包 3. jdk环境变量配置 4. tomcat启动 5. 关闭防火墙 二. MySQL安装 1. 卸载mariadb,否则安装MySql会出现冲突(先查看后删除再查看) 2. 将MySQL安装包解…

【新品】数字化电子智能标签!支持定制服务!!

6年专业研发生产工厂 【NFC防水款】 2.9寸无源NFC电子墨水屏 采用新型无源NFC技术 无须内置电池耗电,没有续航烦恼 新型无源NFC无线刷图技术 采用无源NFC方案,无须内置电池 没有繁琐接线,工作稳定 【电子日历款】 7.5寸单面日历电子墨水屏…

注意力机制 - Transformer

文章目录 1. 简介2. 多头注意力3. 有掩码的多头注意力4. 基于位置的前馈网络5. 层归一化6. 信息传递7. 预测 1. 简介 基于编码器-解码器架构来处理序列对跟使用注意力的seq2seq不同,Transformer是纯基于注意力 2. 多头注意力 对同一key,value&#xff…

竞赛 深度学习手势检测与识别算法 - opencv python

文章目录 0 前言1 实现效果2 技术原理2.1 手部检测2.1.1 基于肤色空间的手势检测方法2.1.2 基于运动的手势检测方法2.1.3 基于边缘的手势检测方法2.1.4 基于模板的手势检测方法2.1.5 基于机器学习的手势检测方法 3 手部识别3.1 SSD网络3.2 数据集3.3 最终改进的网络结构 4 最后…

合肥中科深谷嵌入式项目实战——人工智能与机械臂(五)

订阅:新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列(零基础小白搬砖逆袭) 作者:爱吃饼干的小白鼠。Python领域优质创作者,2022年度博客新星top100入围,荣获多家平台专家称号。…

阿里云2核2G3M带宽轻量服务器87元一年,经济型e实例99元一年

2023阿里云双十一优惠活动2核2G3M轻量应用服务器一年优惠价87元,云服务器ECS经济型e实例优惠价格99元一年,也是2核2G配置,自带3M带宽,并且续费不涨价,阿里云百科aliyunbaike.com还是很建议大家选择e实例的,…

Java日志组件介绍之一

一、前言 前段时间爆出Log4j安全漏洞的事情,XX云因未及时报告漏洞被工信部暂停网络安全威胁和漏洞信息共享平台合作单位(https://www.cstis.cn/),话说Java的日志组件真是多而且也比较乱,后续几篇文章就聊一下各日志组…

大客户销售怎么做?CRM系统来帮您

大客户对企业的重要程度不言而喻,企业该如何更好地维护大客户?想要做好大客户销售,可以借助CRM销售管理系统,实现销售流程的数字化管理,深入挖掘了解客户,从而创造更多的收益。那么CRM系统对大客户销售有什…

Oracle数据库创建Sequence序列的基本使用

1.作用就是批量插入数据的时候可以给一个主键 sequence dose not exist_sequence not exist_拒—绝的博客-CSDN博客 Oracle创建Sequence序列_TheEzreal的博客-CSDN博客 Oracle序列(sequence)创建失败,无法取值(.nextval&#x…

LeetCode:2003. 每棵子树内缺失的最小基因值(C++)

目录 2003. 每棵子树内缺失的最小基因值 题目描述: 实现代码与解析: dfs 启发式合并 原理思路: 2003. 每棵子树内缺失的最小基因值 题目描述: 有一棵根节点为 0 的 家族树 ,总共包含 n 个节点,节点编…

局域网内远程控制电脑的软件

局域网内远程控制电脑的软件在日常办公中,非常常见了。它可以帮助用户在局域网内远程控制其他电脑,实现文件传输、桌面展示、软键盘输入等功能。 局域网内远程控制电脑的软件有很多种,其中比较实用的有域之盾软件、安企神软件、网管家软件等等…

[论文笔记]BGE

引言 今天介绍论文BGE,是智源开源的语义向量模型,BAAI General Embedding。 作者发布了C-Pack,一套显著推进中文嵌入领域的资源包。包括三个重要资源: 1) C-MTEB是一个全面的中文文本嵌入基准,涵盖了6个任务和35个数据集。 2) C-MTP是一个从标记和未标记的中文语料库中选…

RabbitMQ 运维 扩展

1、集群管理与配置 1.1、集群搭建 关于Rabbitmq 集群的搭建,详见以下文章。简单说来就是将多个单机rabbitmq服务,通过给到一致的密钥(.erlang.cookie)并且开放rabbitmq服务的 25672 端口,允许多节点间进行互相通讯&am…

leetCode 137. 只出现一次的数字 II + 位运算 + 模3加法器 + 真值表(数字电路) + 有限状态机

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。 常规解法:哈希(hash) …

运行项目报错error in ./node_modules/marked/lib/marked.umd.js

今天跑项目时发现一个报错,问题出在marked这个包,然后翻看package.json里面也没有这个包,全局搜索项目也没有这个包相关的信息,可它就是报错,索性直接把它给卸载发现还是报错 报错原因:包的版本太高 解决…

AI:47-基于深度学习的人像背景替换研究

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

「完美修复」concrt140.dll丢失的修复方法

concrt140.dll是一个动态链接库文件,它是Microsoft Visual C 2015 Redistributable的一部分。这个文件通常位于Windows系统的System32文件夹中,它提供了一些用于多线程编程的函数和类。当你在运行某些程序时,系统会调用这个文件中的函数来执行…

系列三十五、Spring AOP失效原因以及解决方式

一、Spring AOP失效原因 (1)内部调用不会触发AOP; (2)方法是private修饰的,AOP会失效; 解决方法:改成public (3)目标类没有配置为bean&#xf…

【P2P owt】owt-client-native-p2p-e2e-test vs2017构建7:依赖库及路径

依赖库 G:\CDN\LiveServiceMesh\cdnsignal\third_party\libeva\thirdparty\janbar-openssl\out32\ssl\Debug\libssl-

vue面试题-原理层

虚拟dom 虚拟dom是什么?虚拟dom在vue中做了什么? vue 渲染两条线 虚拟dom是如何提升vue的渲染效率的? 局部更新节点数据将直接操作dom的地方拿到两个js对象之中去做比较 虚拟dom生成三要素 节点类型/目标元素 [必须有]节点属性子节点 Diff中的patch 虚拟dom 虚拟dom是什么…