Linux设备驱动模型之platform设备

Linux设备驱动模型之platform设备

上一章节介绍了Linux字符设备驱动,它是比较基础的,让大家理解Linux内核的设备驱动是如何注册、使用的。但在工作中,个人认为完全手写一个字符设备驱动的机会比较少,更多的都是基于前人的代码修修补补过三年。在内核驱动中,你会看到比较多的platform相关的字样,他们具体是什么呢,下面我们一起来看看。

platform bus

在嵌入式Linux中,可能会听到过I2C总线、SPI总线、USB总线等,但是platform总线是什么呢,它有什么规范呢?platform总线是一个虚拟的总线,它没有像上述介绍的总线有通信协议规范,它仅仅是为了更好的管理Linux内核设备驱动而虚化出来的。

项目开发过程中,会有很多的设备驱动需要注册,但是这些设备都会具有很多共同点,比如休眠唤醒时需要注意的操作,每个设备都会有差异,但是都会有需要,开关机时也是如此。为了方便管理这些设备驱动,Linux增加了platform设备和驱动,方便驱动在开发过程做到统一管理,将设备和驱动都挂载在总线上,当有新的设备或者驱动加入时,都会进行比较,当设备和驱动信息一致时,则进行相应的操作,完成资源申请和设备注册。

Linux内核提供了注册总线的接口,下面我们来看看platform的总线都提供了那些信息:

/* 从platform_bus的定义来看,虽然我们说platform总线,实际上它还是一个设备 */
struct device platform_bus = {.init_name      = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);/* 定义platform设备的默认属性 */
static struct attribute *platform_dev_attrs[] = {&dev_attr_modalias.attr,&dev_attr_driver_override.attr,NULL,
};
ATTRIBUTE_GROUPS(platform_dev);/* 提供设备的休眠唤醒接口函数,platform设备的休眠唤醒都通过这个接口完成调用 */
static const struct dev_pm_ops platform_dev_pm_ops = {.runtime_suspend = pm_generic_runtime_suspend,.runtime_resume = pm_generic_runtime_resume,USE_PLATFORM_PM_SLEEP_OPS
};/* 定义platform总线的一些总要接口 */
struct bus_type platform_bus_type = {.name           = "platform",.dev_groups     = platform_dev_groups,	/* 总线上设备的默认属性 */.match          = platform_match,		/* 前面我们说到注册分别注册设备和驱动之后,将会进行设备驱动匹配,platform设备就是通过该函数实现的 */.uevent         = platform_uevent,		/* 当添加、删除设备的时候,生成uevent添加到环境变量,实际上可以理解为有设备添加、删除时发送广播  */.pm             = &platform_dev_pm_ops,	/* 这个就是上面的休眠唤醒时的调用接口了 */
};
EXPORT_SYMBOL_GPL(platform_bus_type);int __init platform_bus_init(void)
{int error;early_platform_cleanup();/* 注册platform设备 */error = device_register(&platform_bus);if (error)return error;/* 向系统注册platform总线 */error =  bus_register(&platform_bus_type);if (error)device_unregister(&platform_bus);of_platform_register_reconfig_notifier();return error;
}

bus_register函数主要进行下面几个操作:

  1. 将驱动自探测标志drivers_autoprobe设置为1,这样后续只要有device或driver加入bus,都将会触发设备驱动探测;
  2. 创建bus的默认属性节点;
  3. 创建bus的probe等文件节点;

向系统注册platform总线之后,又是怎么使用呢?下面我们一起看看platform设备和驱动的操作。

platform device

platform device一般在内核驱动中都是添加到各个SOC接口或者外设中出现的,作为一个对接内核设备的接口,使各自的设备驱动可更具灵活性。我们先看看内核是怎么定义这个platform device。

struct platform_device {const char      *name;			/* 设备属于什么名字的 */int             id;				/* 设备的索引,比如有多个类似的设备 */struct device   dev;			/* 内核设备的基础 */...u32             num_resources;struct resource *resource;		/* 用于这个设备的资源保存了,比如中断和寄存器地址等 */...
};

上面基本了解了platform device的类型之后,那么它又是怎么登记注册到Linux内核的呢?主要是通过下面的两个接口函数。

/* 登记注册platform device */
int platform_device_register(struct platform_device *pdev);
/* 登记注册num个platform device */
int platform_add_devices(struct platform_device **devs, int num);

那么platform_device_register()函数的操作主要是什么呢?

  1. 通过 device_initialize 初始化 pdev->dev,也就是初始化上述的struct device;
  2. 设置platform device的 DMA mask;
  3. 初始化pdev->dev的parent为platform_bus以及bus为platform_bus_type;
  4. 更新platform device资源;
  5. 通过device_add()向内核添加pdev->dev设备;

似乎完成了注册,现在只有设备,还没有驱动,接着看驱动又是怎样的。

platform driver

内核就是将设备与驱动分离的,设备可以是看得见、摸得着的实体,也可以是一些虚拟的、远端的设备,而驱动则是使设备可以正常工作的代码。platform driver的定义如下:

struct platform_device_id {char name[PLATFORM_NAME_SIZE];kernel_ulong_t driver_data;
};struct platform_driver {/* probe函数用于探测是否存在和该驱动一致的platform device,由各自driver实现,驱动加载时调用 */int (*probe)(struct platform_device *);/* remove函数则是在卸载模块时调用,释放相关资源 */int (*remove)(struct platform_device *);/* 系统关机时将会调用shutdown */void (*shutdown)(struct platform_device *);/* suspend和resume则是系统进入休眠和唤醒时调用 */int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);/* 内核驱动的基础 */struct device_driver driver;/* platform device和driver匹配信息 */const struct platform_device_id *id_table;
};

上面罗列了platform driver的基本成员,各自驱动将会实现,基础需要完成probe、remove和id_table信息的填充。而向内核注册驱动则是通过platform_driver_register完成驱动的注册,而platform_driver_register又主要是进行几个操作:

  1. 将driver的bus设置为platform_bus_type;
  2. 而driver为platform driver,所以device_driver的probe、remove、shutdown函数设置为plaform driver的函数;
  3. 通过driver_register函数向内核注册驱动;

probe的意义

单纯只有硬件机器而没有软件,或许它就是一堆废铜烂铁;而只有软件驱动,也是毫无用处,没有载体,发挥不出它们的作用。虽然我们有注册device、driver,但是如果没有匹配,也是不行,就像用一个ARM64的固件放在mips架构的芯片上运行失败一样,所以probe的意义就是通过driver确认当前的device是否与自身一致,一致则可进行系统节点的注册等。

上面在介绍platform device时有name成员,而platform driver中有id_table,什么时候会触发设备和驱动进行匹配呢?

回头看通过platform_driver_register()函数注册驱动时,driver_register()中会调用bus_add_driver()向总线注册driver,在bus_add_driver()中由因为总线已经设置了drivers_autoprobe,将会通过driver_attach()进行device、driver的匹配,这个过程如下:

platform_driver_registerdriver_registerbus_add_driverdriver_attach__driver_attachdriver_match_devicebus->match

而driver_attach中,将从bus的klist_devices(总线上的所有设备信息都在该链表上)逐个device与driver进行匹配,匹配是通过__driver_attach()函数完成,在__driver_attach中,通过driver_match_device()调用bus的match函数,platform bus的match函数为platform_match()。platform_match将会依次进行以下的对比:

  1. 如果platform device的driver_override置位,则对比pdev的driver_override和drv的name是否一致;
  2. 进行设备树的匹配,将对比drv的of_match_table和dev的of_node信息是否一致;
  3. 进行acpi的信息对比,这点有点不是很清晰,平常没有使用;
  4. 进行pdrv->id_table与pdev->name的对比,平常这个使用较多;
  5. 最后则是直接对比pdev->name和drv->name;

如果上述对比下来都不一致,则没有匹配,否则匹配成功。设备驱动匹配成功,将会通过device_driver_attach()函数进行匹配。

device_driver_attach将会进行以下的操作:

  1. 获取device所属的引脚配置信息;
  2. 在/sys目录下建立driver与device的链接;
  3. 优先调用设备所在bus的probe函数,如果没有则调用driver的probe函数;
  4. 将设备所有的引脚配置为默认状态;

像platform bus是没有实现probe函数的,所以将会调用在注册驱动时赋值的platform_drv_probe()函数,而在这里,实际上就是调用platform driver的probe函数,也就是驱动自己实现的probe函数了。

当调用到probe函数时,证明整个Linux内核的设备驱动模型已经跑通,但实际上这个设备是否存在,需要probe函数实现,probe函数确认device存在之后,将会可以进行资源的申请以及相关设备节点的注册操作。

设备驱动模型

platform设备驱动模型

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

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

相关文章

深入理解Serverless架构:构建无服务器应用的完全指南

💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 Serverless架构是一种现…

AOSP Android 系统源码编译出的framework.jar和android.jar之间的区别

简介 AOSP(Android Open Source Project)编译出的 android.jar 和 framework.jar 都是 Android 平台开发中的重要组件,但它们有不同的作用和用途: android.jar: 用途:android.jar 包含了 Android API 的定…

远程计算机控制软件

远程控制软件允许您连接和控制位于不同位置的设备,对于 IT 帮助台技术人员来说,这是一个很好的工具,可以通过与用户协作、与他们聊天以及安全地访问他们的文件来轻松排除故障和修复远程设备。使用远程控制软件,距离不再是提供技术…

LVS + Keepalived群集

文章目录 1. Keepalived工具概述1.1 什么是Keepalived1.2 工作原理1.3 Keepailved实现原理1.4 Keepalived体系主要模块及其作用1.5 keepalived的抢占与非抢占模式 2. 脑裂现象 (拓展)2.1 什么是脑裂2.2 脑裂的产生原因2.3 如何解决脑裂2.4 如何预防脑裂 …

VMware虚拟机如何设置网络

一直没弄明白怎么能让虚拟机正常上网和访问,最近总结一个小经验 要在宿主机访问虚拟机电脑服务器,要设置成nat格式,虚拟机可以上网,宿主机访问虚拟机上的ip即可访问虚拟机里的服务器,也就是这样设置就行。 这时候ip不…

ubunutu20/18/22 编译android 5相关的问题汇总-千里马framework开源代码平板编译过程

hi,粉丝朋友们: 闲鱼50块钱淘到了一个开源平板,注意这个平板是有源码的,可以进行相关的编译修改。哈哈哈,马哥这边就体验了一下50块钱平板是否可以拿来做framework呢? 哈哈,说好就开干了&#x…

Centos nginx配置文档

1、安装nginx: yum install nginx 2、Nginx常用命令 查看版本:nginx -v 启动:nginx -c /etc/nginx/nginx.conf 重新加载配置:nginx -s reload 停止:nginx -s stop 3、Nginx反向代理配置 nginx配置详解 1、Nginx配置图 详情可以查看:http://nginx.org/ru/docs/example…

华为云云服务器云耀L实例评测 | 智能不卡顿:如何实现流畅的业务运行

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…

Typora偏好设置中图床的配置文件点击打开没有反应

Typora偏好设置中图床的配置文件点击打开没有反应 突然发现Typora偏好设置中图床打开配置文件点击没有反应&#xff0c;如下按钮所示 可能是因为系统不知道用什么软件打开json&#xff0c;直接进入配置文件json目录&#xff0c;一般位置在C:\Users\<your_user_name>\.pi…

Qt 围炉札记

文章目录 一、Qt 调试二、vscode 与 Qt1、安装插件&#xff1a;2、设置中配置插件 一、Qt 调试 【Qt调试技巧】Profile配置使用及一些坑 QT运行时的Debug、Release、Profile选项区别 Qt Creator release版本进行调试 【Qt调试技巧】如何在Release下调试Qt程序&#xff1f; …

辅助驾驶功能开发-功能规范篇(21)-4-XP行泊一体方案功能规范

XPilot Parking 自动泊车系统 • 超级自动泊车辅助(Super AutoParking Assist)、语音控制泊车辅助(Autoparking with Speech) - 产品定义 超级自动泊车辅助是⼀个增强的自动泊车辅助系统。在超级自动泊车辅助系统中,识别车位将会变得实时可见, 并且不可泊入的⻋位也将…

GIS前端-地图事件编程

GIS前端-地图事件编程 图层操作事件地图状态事件交互事件弹出框事件导出PDF 在地图上的一切操作均要采用地图事件机制来实现&#xff0c;即通过鼠标、键盘等交互&#xff0c;触发地图相关事件&#xff0c;进而调用相关功能接口函数实现相应的GIS功能。在具体的实现过程中&#…

利用transform和border 创造简易图标,以适应uniapp中多字体大小情况下的符号问题

html: <text class"icon-check"></text> css: .icon-check {border: 2px solid black;border-left: 0;border-top: 0;height: 12px;width: 6px;transform-origin: center;transform: rotate(45deg);} 实际上就是声明一个带边框的div 将其中相邻的两边去…

驱动开发,IO多路复用(select,poll,epoll三种实现方式的比较)

1.IO多路复用介绍 在使用单进程或单线程情况下&#xff0c;同时处理多个输入输出请求&#xff0c;需要用到IO多路复用&#xff1b;IO多路复用有select/poll/epoll三种实现方式&#xff1b;由于不需要创建新的进程和线程&#xff0c;减少了系统资源的开销&#xff0c;减少了上下…

1. 快速体验 VSCode 和 CMake 创建 C/C++项目

1. 快速体验 VSCode 和 CMake 创建 C/C项目 本章的全部代码和markdown文件地址: CMake_Tutorial&#xff0c;欢迎互相交流. 此次介绍的内容都是针对于 Linux 操作系统上的开发过程. 1.1 安装开发工具 VSCode: 自行下载安装, 然后安装插件 Cmake:在 Ubuntu 系统上, 可以采用 ap…

Ae 效果:CC Hair

模拟/CC Hair Simulation/CC Hair CC Hair&#xff08;CC 毛发&#xff09;可以在源图像上模拟生成毛发、绒线等&#xff0c;并可调整它们的长度、方向、重量等属性&#xff0c;从而创建出非常独特的效果。 CC Hair 本质上是基于 Alpha 通道来生成毛发&#xff0c;无毛发处将变…

Debian 12安装Docker

1.更新系统包 #apt update 2.安装依赖包 #apt install apt-transport-https ca-certificates curl gnupg lsb-release 3.添加Docker源 &#xff08;1&#xff09;添加Docker 官方GPG密钥 #curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/s…

GraphQL基础知识与Spring for GraphQL使用教程

文章目录 1、数据类型1.1、标量类型1.2. 高级数据类型 基本操作2、Spring for GraphQL实例2.1、项目目录2.2、数据库表2.3、GraphQL的schema.graphql2.4、Java代码 3、运行效果3.1、添加用户3.2、添加日志3.3、查询所有日志3.4、查询指定用户日志3.5、数据订阅 4、总结 GraphQL…

基于LUT查找表方法的图像gamma校正算法FPGA实现,包括tb测试文件和MATLAB辅助验证

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 将gamma2.2和gamma1/2.2的数据分别导入到matlab进行对比&#xff1a; 2.算法运行软件版本 matlab2022a 3.部分核心程序 timescale 1ns / 1ps //…

C2基础设施威胁情报对抗策略

威胁情报是指在信息安全和安全防御领域&#xff0c;收集、分析和解释与潜在威胁相关的信息&#xff0c;以便预先发现并评估可能对组织资产造成损害的潜在威胁&#xff0c;是一种多维度、综合性的方法&#xff0c;其通过信息的收集、分析和研判&#xff0c;帮助组织了解可能对其…