Linux驱动开发—平台总线模型详解
文章目录
- 1.平台总线介绍
- 1.1平台总线模型的组成部分
- 1.2平台总线模型的优势
- 2.使用平台总线模型开发驱动
- 2.1注册platform设备
- 2.2注册platform驱动
- 2.3效果演示
1.平台总线介绍
Linux 平台总线模型(Platform Bus Model)是一种设备驱动框架,用于处理那些没有标准总线(如 PCI、USB 等)的嵌入式设备。它为这些设备提供了统一的设备驱动模型,简化了设备驱动程序的编写和管理。
1.1平台总线模型的组成部分
平台总线模型主要由以下几个组成部分构成:
- 平台设备(Platform Device)
- 平台驱动(Platform Driver)
- 平台总线(Platform Bus)
平台设备(Platform Device)
平台设备表示硬件设备,它们通常通过设备树(Device Tree)或者板文件(Board File)进行描述。平台设备通常包括设备名称、资源(如 I/O 端口、内存区域、中断号等)以及其他平台数据。
平台驱动(Platform Driver)
平台驱动是与平台设备匹配并管理这些设备的软件模块。平台驱动提供了 probe
和 remove
函数,用于设备的初始化和清理。
平台总线(Platform Bus)
平台总线在内核中自动管理,不需要显式地定义。它用于匹配平台设备和平台驱动。
1.2平台总线模型的优势
平台总线模型(Platform Bus Model)在 Linux 内核中的引入为嵌入式设备和驱动程序的开发带来了多项显著的优势。以下是平台总线模型的一些主要优势:
- 抽象和统一的设备管理
平台总线模型为没有标准总线的设备提供了统一的抽象和管理方法。通过统一的接口和机制,开发者可以更容易地管理和控制不同类型的设备,无需考虑底层硬件差异。
- 简化驱动开发
通过使用平台总线模型,驱动程序开发者不再需要为每种硬件设备编写特定的初始化和资源管理代码。平台设备和平台驱动的标准化接口使得驱动程序的开发和调试更加简单和一致。
- 设备树支持
平台总线模型支持设备树(Device Tree),这是一种硬件描述语言,广泛用于描述嵌入式系统中的硬件配置。设备树使得硬件配置从代码中分离出来,可以通过修改设备树文件而不是驱动代码来适应不同的硬件配置,极大地提高了代码的可维护性和可移植性。
- 自动匹配和管理
平台总线模型通过内核自动完成平台设备和平台驱动的匹配和管理。这意味着驱动程序不需要显式地查找和初始化设备,内核会自动调用合适的 probe
和 remove
函数来管理设备的生命周期。
- 资源管理
平台总线模型提供了简化的资源管理机制。平台设备可以通过设备树或板文件描述其所需的资源(如 I/O 端口、内存区域、中断号等),驱动程序可以通过标准接口获取和使用这些资源,避免了手动管理资源的复杂性和潜在错误。
- 模块化和可移植性
通过将硬件特定的配置与驱动代码分离,平台总线模型提高了驱动程序的模块化和可移植性。驱动程序可以更容易地在不同的硬件平台之间移植,只需调整设备树或板文件中的硬件配置即可。
- 代码重用
由于平台总线模型提供了标准化的接口和机制,不同驱动程序之间可以共享通用的代码和逻辑。这种代码重用不仅减少了开发时间和成本,还提高了代码的稳定性和可靠性。
8. 内核维护
平台总线模型的标准化和统一管理机制使得内核代码更易于维护和升级。通过减少硬件特定的代码和逻辑,内核开发者可以更专注于改进和优化内核的通用部分,提高内核的整体性能和稳定性。
2.使用平台总线模型开发驱动
2.1注册platform设备
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/atomic.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>// 描述硬件资源 结构体数组
static struct resource my_device_resources[] = {{.start = 0x12340000,.end = 0x123400FF,.flags = IORESOURCE_MEM,},{.start = 5,.end = 5,.flags = IORESOURCE_IRQ,}};
void my_device_release(struct device *dev)
{printk("This is my device release");
}static struct platform_device my_platform_device = {.name = "my_platform_device",.id = -1,.num_resources = ARRAY_SIZE(my_device_resources),.resource = my_device_resources,.dev = {.release = my_device_release},
};static int __init platform_device_init(void)
{platform_device_register(&my_platform_device);printk("platform_device_init!");return 0;
}static void __exit platform_device_exit(void)
{platform_device_unregister(&my_platform_device);printk("platform_device_exit!");
}module_init(platform_device_init);
module_exit(platform_device_exit);
MODULE_AUTHOR("Marxist");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("a simple of platform_device");
其中有两个关键的结构体 platform_device
和resource
struct platform_device
功能描述
platform_device
结构体表示一个平台设备,它包含了设备的名称、资源、设备数据以及其他属性。这个结构体在平台总线模型中非常重要,用于描述那些没有标准总线(如 PCI、USB 等)支持的嵌入式设备。
struct platform_device {const char *name; // 设备名称int id; // 设备ID,通常用于区分同名设备struct device dev; // 嵌入的设备结构体u32 num_resources; // 资源数量struct resource *resource; // 指向资源数组的指针const struct platform_device_id *id_entry; // 设备ID表char *driver_override; // 用于覆盖默认的驱动程序
};
主要字段解释
- name: 设备的名称,用于匹配设备和驱动程序。
- id: 设备ID,用于区分具有相同名称的多个设备。通常设置为 -1。
- dev: 嵌入的
struct device
结构体,表示通用设备结构,包含设备的通用属性和方法。 - num_resources: 资源数量,表示设备所使用的资源数量。
- resource: 指向资源数组的指针,资源数组包含了设备所使用的各种资源(如内存、I/O 端口、中断等)。
- id_entry: 指向设备ID表的指针,用于在驱动程序中匹配特定的设备。
- driver_override: 用于指定一个特定的驱动程序覆盖默认的驱动程序。
一般只需要关注name,id, dev,以及使用的资源描述
struct resource 结构体描述
resource
结构体描述了设备使用的硬件资源,例如内存地址范围、中断号等。每个设备可以有多个资源,这些资源通过 platform_device
结构体中的 resource
字段进行管理。
struct resource {resource_size_t start; // 资源的起始地址resource_size_t end; // 资源的结束地址const char *name; // 资源的名称unsigned long flags; // 资源的类型和属性struct resource *parent, *sibling, *child; // 资源树结构中的节点关系
};
主要字段解释
- start: 资源的起始地址或起始值,例如内存映射地址的开始位置。
- end: 资源的结束地址或结束值,例如内存映射地址的结束位置。
- name: 资源的名称,用于识别资源。
- flags: 资源的类型和属性,通过标志位表示。例如,
IORESOURCE_MEM
表示内存资源,IORESOURCE_IRQ
表示中断资源。 - parent: 指向父资源的指针,用于构建资源层次结构。
- sibling: 指向兄弟资源的指针,用于构建资源层次结构。
- child: 指向子资源的指针,用于构建资源层次结构。
编译加载之后,就会在 /sys/bus/platform/devices/ 下注册新的设备
2.2注册platform驱动
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
static const struct platform_device_id driver_id_table[] = {{ .name = "my_platform_device" },{ } // 结尾必须有一个空的元素
};
static int my_platform_driver_probe(struct platform_device *dev )
{printk("my_platform_driver_probe");// 通过 probe 函数 拿到硬件资源描述, probe函数将传递 platform_device结构体函数struct resource *res;int irq;//获取内存资源res = platform_get_resource(dev,IORESOURCE_MEM,0);printk("IORESOURCE_MEM start addr is %x ",res->start);//获取中断资源res = platform_get_resource(dev,IORESOURCE_IRQ,0);printk("IRQ number is %d ",res->start);//获取完资源进行下一步的操作return 0;
}
static int my_platform_driver_remove(struct platform_device *dev )
{printk("my_platform_driver_remove");return 0;
}static struct platform_driver my_platform_driver = {.probe = my_platform_driver_probe,.remove = my_platform_driver_remove,.driver = {.name = "my_platform_device", // 平台设备名一致.owner = THIS_MODULE,},.id_table = driver_id_table, // id_table 的优先级更高
};
static int __init platform_driver_init(void)
{int ret = platform_driver_register(&my_platform_driver);if (ret)printk(KERN_ALERT "Failed to register platform driver\n");elseprintk( "platform_driver_init!\n");return ret;
}
static void __exit platform_driver_exit(void)
{platform_driver_unregister(&my_platform_driver);printk(KERN_ALERT "platform_driver_exit!\n");
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_AUTHOR("Marxist");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("a simple of platform_driver");
我们只需要注册驱动即可,重点为platform_driver
结构体
platform_driver
结构体为 Linux 内核中用于描述和管理平台驱动程序的一个重要结构体。它定义了驱动程序的主要回调函数和一些元数据,这些信息允许内核在设备插入和移除时正确地调用驱动程序的相关函数。
结构体定义:
struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;bool prevent_deferred_probe;
};
probe:
- 类型:
int (*probe)(struct platform_device *);
- 功能: 当匹配的设备被注册时,内核调用此函数来初始化设备。通常在此函数中进行设备的硬件资源获取和初始化。
- 返回值: 返回0表示成功,负值表示失败。
remove:
- 类型:
int (*remove)(struct platform_device *);
- 功能: 当设备被移除时,内核调用此函数来清理和释放设备资源。
- 返回值: 返回0表示成功,负值表示失败。
shutdown:
- 类型:
void (*shutdown)(struct platform_device *);
- 功能: 当系统关闭或重启时,内核调用此函数来关闭设备。通常用于执行设备的关机操作。
suspend:
- 类型:
int (*suspend)(struct platform_device *, pm_message_t state);
- 功能: 当设备进入挂起(suspend)状态时,内核调用此函数来保存设备的状态。
- 返回值: 返回0表示成功,负值表示失败。
resume:
- 类型:
int (*resume)(struct platform_device *);
- 功能: 当设备从挂起状态恢复时,内核调用此函数来恢复设备的状态。
- 返回值: 返回0表示成功,负值表示失败。
driver:
- 类型:
struct device_driver
- 功能: 包含通用的驱动程序信息,如驱动程序的名字、模块所有者等。
platform_driver
通过嵌入device_driver
结构体继承了大部分通用的驱动程序接口。 - 关键字段:
name
: 驱动程序的名字,应该与platform_device
的名字匹配。owner
: 指向该驱动程序模块的指针,通常设置为THIS_MODULE
。
id_table:
- 类型:
const struct platform_device_id *
- 功能: **指向设备 ID 表的指针,用于设备和驱动程序之间的匹配。**优先使用id_table进行名称匹配,如果匹配不上,将会进行
device_driver
中的名字匹配
prevent_deferred_probe:
- 类型:
bool
- 功能: 控制是否防止延迟探测。默认值是 false。
注意:必须要实现probe 函数,当平台设备和平台驱动匹配成功,就会调用probe函数,通常在此完成一些资源的初始化和调用。
例如:
static int my_platform_driver_probe(struct platform_device *dev )
{printk("my_platform_driver_probe");// 通过 probe 函数 拿到硬件资源描述, probe函数将传递 platform_device结构体函数struct resource *res;int irq;//获取内存资源res = platform_get_resource(dev,IORESOURCE_MEM,0);printk("IORESOURCE_MEM start addr is %x ",res->start);//获取中断资源res = platform_get_resource(dev,IORESOURCE_IRQ,0);printk("IRQ number is %d ",res->start);//获取完资源进行下一步的操作return 0;
}
2.3效果演示
无论先加载平台设备模块还是平台驱动模块,就会调用probe函数,具体效果如下
相关文章:

Linux驱动开发—平台总线模型详解
文章目录 1.平台总线介绍1.1平台总线模型的组成部分1.2平台总线模型的优势 2.使用平台总线模型开发驱动2.1注册platform设备2.2注册platform驱动2.3效果演示 1.平台总线介绍 Linux 平台总线模型(Platform Bus Model)是一种设备驱动框架,用于…...
说一下网络层,传输层,数据链路层做什么的,之间的关系?
网络层主要负责为数据包选择最佳路径,将数据从源主机传输到目标主机。它的关键任务包括路由选择、拥塞控制和网络互联等。通过网络层的功能,不同网络之间能够实现通信和数据传输。 传输层的作用是在源端和目的端之间提供可靠或不可靠的端到端的数据传输…...

解锁AI新纪元:Milvus Cloud与Zilliz Cloud的高可用之道
在当今数字化时代,系统的持续稳定运行与数据的即时访问性已成为衡量技术服务质量的关键指标。面对复杂多变的运行环境,包括电力波动、网络故障乃至人为操作失误等不可预见因素,数据库系统的高可用性(High Availability, HA)成为了保障业务连续性的重要基石。特别是在大数据…...
svn安装
579 yum install subversion 580 rpm -qa|grep subversion 581 yum -y install subversion 582 rpm -ql subversion 583 /usr/bin/svnversion --version 584 mkdir /data/svnrepos 585 svnadmin create /data/svnrepos/abc 586 svnadmin create /data/svnrepos/gzss 587 cd…...

【隐私计算篇】混淆电路之深入浅出
入门隐私计算的阶段,一般都会涉及对于混淆电路的学习,这是因为混淆电路是多方安全计算中的基础密码原语,也是隐私保护中重要的技术。为了帮助更好地理解混淆电路的原理,今天对其进行原理以及相关优化手段进行解析和分享。 1. 混淆…...
基于GRU神经网络的微博分类预测
目录 背影 摘要 LSTM的基本定义 LSTM实现的步骤 gru的原理 GRU神经网络微博分类 结果分析 展望 参考论文 背影 传统的方法微博分类预测准确率低,为提高精度,本文用gru进行预测 摘要 LSTM原理,GRU原理,MATALB编程gru的微博分类预测 LSTM的基本定义 LSTM是一种含有LST…...

LVS-DR模式集群:案例与概念
DR模式(直接路由) 概念 Direct Routing,简称DR模式采用半开放式的网络结构,与TUN模式的结构类似,但内网服务器并不是分散在各地,而是与调度器位于同一个物理网络负载调度器与内网服务器通过本地网络连接&a…...
拓扑排序:Kahn算法与DFS算法
引言 拓扑排序是有向无环图(DAG)中的一种线性排序,使得对于图中的每一条有向边 ( u \rightarrow v ),顶点 ( u ) 在排序中出现在顶点 ( v ) 之前。本文将详细介绍两种实现拓扑排序的算法:Kahn算法和基于深度优先搜索&…...
图像处理 -- Sobel滤波器的实现原理与使用案例
Sobel滤波器 概述 Sobel滤波器是一种边缘检测方法,用于图像处理和计算机视觉领域。它通过计算图像灰度值的梯度来检测边缘。Sobel滤波器结合了高斯平滑和微分操作,以减少噪声并增强边缘检测效果。 实现原理 Sobel滤波器通过使用两个3x3卷积核&#x…...

机器学习 第10章-降维与度量学习
机器学习 第10章-降维与度量学习 10.1 k近邻学习 k近邻(k-Nearest Neighbor,简称kNN)学习是一种常用的监督学习方法其工作机制非常简单:给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。通…...
linux驱动:(7)物理地址到虚拟地址映射
单片机、裸机、linux操控硬件方法 在单片机和裸机中操作硬件是通过指针来对寄存器赋值来进行操控 但对于linux中不能这样,不能直接对物理地址直接修改,因为linux使能了mmu,所以不能直接菜操作物理地址 如果要操作硬件,需要先把…...

浏览器用户文件夹详解 - Preferences(十)
1.Preferences简介 1.1 什么是Preferences文件? Preferences文件是Chromium浏览器中用于存储用户个性化设置和配置的一个重要文件。每当用户在浏览器中更改设置或安装扩展程序时,这些信息都会被记录在Preferences文件中。通过这些记录,浏览…...
Robot Operating System——电池电量通知
大纲 应用场景定义字段解释 案例 sensor_msgs::msg::BatteryState 是 ROS 2 中定义的消息类型,用于表示电池状态。它包含了电池电量、电压、电流、温度等信息。 应用场景 机器人 电池监控:在移动机器人中,电池是主要的电源。BatteryState 消…...
二进制安装docker
目录 一、准备 Docker CE 二进制包 二、解压.tgz包 三、复制二进制文件到/usr/bin/目录 四、创建用户组 五、配置相关服务配置文件 六、拷贝配置文件到指定目录 七、启动 dockerd 服务进程 八、shell脚本一键安装 一、准备 Docker CE 二进制包 https://download.docker…...
@SpringBootConfiguration重复加载报错
Junit单元测试Test启动报错,SpringBootConfiguration注解重复问题排查: SpringBootApplication 注解的 exclude 属性用于排除特定的自动配置类,而不是用于排除主配置类本身。因此,不能通过 exclude 属性来排除主配置类的加载。 …...
【SpringBoot】数据验证之分组校验
分组校验 在不同情况下,可能对JavaBean对象的数据校验规则有所不同,有时需要根据数据状态对JavaBean中的某些属性字段进行单独验证。这时就可以使用分组校验功能,即根据状态启用一组约束。 Hibernate Validator的注解提供了groups参数&#…...

MySQL Galera Cluster 部署与介绍
目录 主要特点 组件 一. 环境准备 二. 配置 1. 配置 galera1 主机的my.cnf的文件 2. 配置 galera2 主机的my.cnf的文件 3. 配置 galera3 主机的my.cnf的文件 4. 在给galera1 主机的my.cnf的文件增加节点 5. 写入数据验证同步 6. 配置 galera4 主机的my.cnf的文件 M…...

RuoYi-Vue-Plus (XXL-JOB任务调度中心二:配置管理与定时任务编写、执行策略、命令行任务、邮件报警等等
一、后端xxl job的配置属性介绍 enabled : 是否开启执行器,如果为false,调度中心就调用不了后端定时任务admin-addresses:调度中心的地址,多个则可以逗号拼接: url1,url2,url3access-token: 执行器通讯TOKEN ,必须和x…...

【docker】虚拟化与docker基础
一、虚拟化 1.虚拟化概述 什么是虚拟化? 虚拟化:将应用程序和系统内核资源进行解耦,以操作系统级别进行隔离,目的是提高资源利用率 2、虚拟化的功能 将虚拟化的性能优化趋近于物理资源的性能,主要用于提高资源利用…...

Vue3安装ffmpeg做视频截取报错
通过 yarn 安装 ffmpeg 时报错。 即,执行以下指令时报错: yarn add ffmpeg/ffmpeg^0.10.0 yarn add ffmpeg/core^0.10.0错误信息: node_modules\pngquant-bin: Command failed. Error: pngquant failed to build, make sure that libpng-d…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...