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.rhkb.cn/news/176505.html

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

相关文章

robot framework导入库和资源

robot framework导入库和资源 一 导入系统库和第三方库(Library)二 导入自己写的py文件三 建立资源作为关键字3.1 创建资源3.2 在资源里创建用户关键字3.3 使用用户关键字 四 将自己写的py文件中类的函数作为关键字4. 1编写py文件,文件名和里…

搭建VM虚拟机+Centos7 Oracle版 + 配置ssh + Xftp + secureCRT

文章目录 1 视频地址1.1 基本参数1.2 ISO下载地址:1.3 开启ssh1.3.1 使用root用户进行1.3.2 修改ssh配置1.3.3 关闭 SELINUX 2 查询虚拟机的ip2.1 联网2.2 桌面打开终端查询虚拟机ip 3 连接Xftp4 连接SecureRT 1 视频地址 01-搭建VM虚拟机Centos7 Oracle版 配置ss…

计算机网络-IP地址

文章目录 子网划分定长子网划分子网划分的方法子网掩码 可变长子网划分 无类别编址网络前缀路由聚合 特殊用途的IP地址专用网络地址链路本地地址运营商级NAT共享地址用于文档的测试网络地址 IP地址的规划和分配IP地址的规划和分配方法IP地址的规划和分配实例 子网划分 定长子网…

基于未来搜索算法的无人机航迹规划-附代码

基于未来搜索算法的无人机航迹规划 文章目录 基于未来搜索算法的无人机航迹规划1.未来搜索搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要:本文主要介绍利用未来搜索算法来优化无人机航迹规划。 …

装备制造行业云MES解决方案

一、装备制造行业发展现状: 机械制造业主要是通过对金属原材料物理形状的改变、加工组装进而成为产品。机械制造业生产的主要特点是:离散为主、流程为辅、装配为重点。 工业生产基本上分为两大方式: 1.离散型:离散型是指以一个…

《数据安全与流通:技术、架构与实践》新书发布

随着数据成为关键生产资料和要素,国内外数据安全相关的法律法规在快速完善,数据安全技术也在快速发展。5月25-26日,由星环科技、上海数据交易所、上海大数据联盟、财联社联合主办的向星力未来数据技术峰会 (FDTC)上&am…

C#__委托delegate

委托存储的是函数的引用(把某个函数赋值给一个委托类型的变量,这样的话这个变量就可以当成这个函数来进行使用了) 委托类型跟整型类型、浮点型类型一样,也是一种类型,是一种存储函数引用的类型 using System.Reflec…

目标检测理论知识

目标检测 1.基本概念 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,…

安装最新版vue-cli,并搭建一个vue2项目

安装最新版vue-cli,并搭建一个vue2项目 卸载旧版本环境 卸载node.js 可以使用qq电脑管家,找到nodejs卸载即可 cmd查看vue cli版本(可以看到我们是vue cli 2.x) C:\Users\youzhengjie666> vue -V 2.9.6卸载vue cli 2.x np…

CMake:构建时为特定目标运行自定义命令

CMake:构建时为特定目标运行自定义命令 导言项目结构相关源码结果 导言 add_custom_command 是 CMake 中用于添加自定义构建规则的命令,通常用于在编译项目时执行一些自定义操作,例如生成文件、运行脚本等。 项目结构 . ├── CMakeLists…

VMware虚拟网络连接的三种方式

桥接模式(Bridged) 什么是桥接模式?桥接模式就是将主机网卡与虑拟机虑拟的网卡利用虑拟网桥进行通信。在桥接的作用下,类似于把物理主机虑拟为一个交换机,所有桥接设置的虚拟机连接到这个交换机的一个接口上,物理主机也同样插在这个交换机当…

IDEA MyBatisX插件介绍

一、前言 前几年写代码的时候,要一键生成DAO、XML、Entity基础代码会采用第三方工具,比如mybatis-generator-gui等,现在IDEA或Eclipse都有对应的插件,像IDEA中MyBatisX就是一个比较好用的插件。 二、MyBatisX安装配置使用 MyBa…

HTML光速入门----(有这一篇就够了~!)

前言 因为是博主的平时自己的笔记所以截图和写的方式有点随意,还请大家多多谅解,有什么不对的地方,可以直接在评论区指出问题,感谢大家的指点和阅读我的文章 如果需要这里面演示的html,可以私信我,我会统一…

[黑马程序员Pandas教程]——Pandas快速体验

目录: 为什么要使用Python做数据开发Python在数据开发领域的优势为什么要学习Pandas其他常用Python库介绍主要内容介绍Anaconda安装Anaconda的虚拟环境管理虚拟环境的作用可以通过Anaconda界面创建虚拟环境通过命令行创建虚拟环境通过Anaconda管理界面安装包也可以…

Web3 React项目Dapp获取智能合约对象

上文Web3 整理React项目 导入Web3 并获取区块链信息中,我们在react搭建的dapp中简单拿到了我们区块链中的账号授权信息 那 我们继续 先终端运行 ganache -d将ganache环境起起来 然后 我们运行 dapp 拿到授权列表 回到上文结束的一个状态 然后 我们发布一下自己的…

【设计模式】第22节:行为型模式之“状态模式”

一、简介 状态模式一般用来实现状态机,而状态机常用在游戏、工作流引擎等系统开发中。不过,状态机的实现方式有多种,除了状态模式,比较常用的还有分支逻辑法和查表法。该模式允许对象内部状态改变使改变它的行为。 二、适用场景…

「Qt中文教程指南」如何创建基于Qt Widget的应用程序(四)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。 本文描述了如何使用…

如何选一个质量好的超声波清洗机、超声波清洗机推荐

超声波清洗机的品牌这么多,到底该如何选择一个质量好的超声波清洗机呢?其实选购超声波清洗机还是有讲究的,并非说说超声波清洗机越贵就是越好的,入手之前还是需要多看一下参数之类的,不然容易买回来后悔,作…

dash--项目的前端展示简单基础

1.前置工作 创建虚拟环境: sudo apt-get install python3-venv # 安装 python3 -m venv venv # 在本目录下创建venv虚拟环境(也是一个文件夹。如果用不到这个虚拟环境以后就rm -rf venv) source venv/bin/activate # 激活虚拟环境临时使用清华…

基于platform驱动模型完成LED驱动的编写

添加设备树文件信息 myplatform{compatible"hqyj,myplatform";//厂商信息&#xff0c;用于驱动端进行匹配interrupt-parent<&gpiof>; //关联中断父节点interrupts<9 0>; //和中断父节点的关系描述符led1-gpio<&gpioe 10 0>; led2-gpio<…