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

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.hqwc.cn/news/154801.html

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

相关文章

强大易于编辑的流程图组织图绘制工具draw.io Mac苹果中文版

draw.io可以绘制多种类型的图表,包括但不限于流程图、组织结构图、网络图、UML图、电气工程图等。draw.io提供了丰富的图形元素和编辑功能,使用户能够轻松地创建和编辑各种复杂的图表。同时,该软件还支持多种导出格式,方便用户在不…

岩土工程监测利器:多通道振弦数据记录仪应用铁路隧道监测

岩土工程监测利器:多通道振弦数据记录仪应用铁路隧道监测 岩土工程监测是工程建设中十分重要的一环,特别是在铁路隧道工程中,岩土工程监测更是不可或缺的一项。其中,振弦数据记录仪是一种非常重要的仪器,可以帮助监测…

python设计模式笔记1:创建型模式 工厂模式和抽象工厂模式

1.工厂模式 (1) 导入所需的模块( json 和 ElementTree )。 (2) 定义 JSON数据提取器类( JSONDataExtractor )。 (3) 定义 XML数据提取器类( XMLDataExtractor )。 (4) 添加工厂函数 dataextraction_factor…

【Docker 内核详解】cgroups 资源限制(二):组织结构与基本规则、子系统简介

cgroups 资源限制(二):组织结构与基本规则、子系统简介 1.组织结构与基本规则2.子系统简介 1.组织结构与基本规则 在之前的博客已经介绍过,传统的 Unix 任务管理,实际上是先启动 init 任务作为根节点,再由…

基于RFID技术的智能医疗柜管理系统解决方案

一、行业背景 当前,医疗机构面临着药物过期、召回、空货架、放错产品和库存缺失等问题,这些问题导致医院项目效率低下,患者护理不足,医护人员备受困扰。为了应对全球医疗体系面临的压力,医疗保健机构急需寻找新技术来…

Xubuntu16.04系统中create_ap开启5G网络的踩坑记录

Xubuntu16.04系统中安装create_ap创建无线AP: https://blog.csdn.net/qq_45445740/article/details/133972642?spm1001.2014.3001.5501 目录 1.create_ap.conf 配置文件解析2.关于信号强度和延时2.1 信号强度2.2 信号延时2.3 网络延时测试工具推荐——PingPlotter …

【RTOS学习】CubeMX对FreeRTOS的适配

🐱作者:一只大喵咪1201 🐱专栏:《RTOS学习》 🔥格言:你只管努力,剩下的交给时间! 经过前面的学习,现在我已经对FreeRTOS有了一个初步的认识,而且也可以使用F…

易基因:ChIP-seq等揭示BRWD3调控KDM5活性以维持H3K4甲基化水平的表观机制|PNAS

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 组蛋白修饰对调控染色质结构和基因表达至关重要,组蛋白修饰失调可能导致疾病状态和癌症。染色质结合蛋白BRWD3(Bromodomain and WD repeat-containing protein 3&…

PHP在线客服系统平台系统源码+完全开源 带完整的搭建教程

在线客服系统已经成为企业与用户进行实时沟通的重要工具。PHP作为一种流行的服务器端脚本语言,具有高效、稳定和易用性等优点,因此被广泛应用于在线客服系统的开发。今天罗峰来给大家介绍一款PHP在线客服系统平台系统源码,源码完全开源&#…

低功耗设计-ir drop的signoff corner怎么选择?

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 相关文章链接: Multi Voltage Flow笔记 有几个方向,看公司需求吧 1.功耗最差的; 2.tt的(tt85 是比较接近芯片真实工作情况的&#xff09…

MySQL数据库操作、表操作和常用数据类型

1、数据库操作 1.1 创建数据库 语法:CREATE DATABASE [IF NOT EXISTS] 数据库名 charset utf8;(注意字母不区分大小写,分号为英文输入法),[ ]为可选项,意思为如果系统没有想要创建(数据库名&am…

万字解析设计模式之原型模式与建造者模式

一、原型模式 1.1概述 原型模式是一种创建型设计模式,其目的是使用已有对象作为原型来创建新的对象。原型模式的核心是克隆,即通过复制已有对象来创建新对象,而不是通过创建新对象的过程中独立地分配和初始化所有需要的资源。这种方式可以节…