RK3568驱动指南|第六篇-平台总线-第52章 注册platform驱动实验

news2024/12/23 12:02:28

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。


【公众号】迅为电子

【粉丝群】824412014(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第六期-平台总线_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


第52章 注册platform驱动实验

在上个章节我们学习了如何注册platform设备,而本章节就要学习如何注册platform驱动了。

52.1注册platform驱动

52.1.1 platform_driver_register 函数

platform_driver_register 函数用于在 Linux 内核中注册一个平台驱动程序。下面是对该函数的详细介绍:

函数原型:

int platform_driver_register(struct platform_driver *driver);

头文件:

#include <linux/platform_device.h>

函数作用:

platform_driver_register 函数用于将一个平台驱动程序注册到内核中。通过注册平台驱动程序,内核可以识别并与特定的平台设备进行匹配,并在需要时调用相应的回调函数。

参数含义:

driver:指向 struct platform_driver 结构体的指针,描述了要注册的平台驱动程序的属性和回调函数(会在下面的小节对该结构体进行详细的讲解)。

返回值

返回一个整数值,表示函数的执行状态。如果注册成功,返回 0;如果注册失败,返回一个负数错误码。

该函数在内核源码目录下的“/include/linux/platform_device.h”文件中,具体内容如下所示:

#define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)
extern int __platform_driver_register(struct platform_driver *,					struct module *);

这个宏用于简化平台驱动程序的注册过程。它将实际的注册函数 __platform_driver_register 与当前模块(驱动程序)关联起来。宏的参数 drv 是一个指向 struct platform_driver 结构体的指针,描述了要注册的平台驱动程序的属性和回调函数。THIS_MODULE 是一个宏,用于获取当前模块的指针。

而__platform_driver_register实际定义在“/drivers/base/platform.c”文件中,相关定义如下所示:

int __platform_driver_register(struct platform_driver *drv, struct module *owner)
{
    drv->driver.owner = owner;                   // 将平台驱动程序的所有权设置为当前模块
    drv->driver.bus = &platform_bus_type;    // 将平台驱动程序的总线类型设置为平台总线
    drv->driver.probe = platform_drv_probe;      // 设置平台驱动程序的探测函数
    drv->driver.remove = platform_drv_remove;    // 设置平台驱动程序的移除函数
    drv->driver.shutdown = platform_drv_shutdown;// 设置平台驱动程序的关机函数

    return driver_register(&drv->driver);        // 将平台驱动程序注册到内核
}

第3行:将指向当前模块的指针 owner 赋值给平台驱动程序的 owner 成员。这样做是为了将当前模块与平台驱动程序关联起来,以确保模块的生命周期和驱动程序的注册和注销相关联。

第4行:将指向平台总线类型的指针 &platform_bus_type 赋值给平台驱动程序的 bus 成员。这样做是为了指定该驱动程序所属的总线类型为平台总线,以便内核能够将平台设备与正确的驱动程序进行匹配。

第5行:将指向平台驱动程序探测函数 platform_drv_probe 的指针赋值给平台驱动程序的 probe 成员。这样做是为了指定当内核发现与驱动程序匹配的平台设备时,要调用的驱动程序探测函数。

第6行:将指向平台驱动程序移除函数 platform_drv_remove 的指针赋值给平台驱动程序的 remove 成员。这样做是为了指定当内核需要从系统中移除与驱动程序匹配的平台设备时,要调用的驱动程序移除函数。

第7行 = platform_drv_shutdown;:将指向平台驱动程序关机函数 platform_drv_shutdown 的指针赋值给平台驱动程序的 shutdown 成员。这样做是为了指定当系统关机时,要调用的驱动程序关机函数。

第9行:调用 driver_register 函数,将平台驱动程序的 driver 成员注册到内核中。该函数负责将驱动程序注册到相应的总线上,并在注册成功时返回 0,注册失败时返回一个负数错误码。

通过这些操作,__platform_driver_register 函数将平台驱动程序与内核关联起来,并确保内核能够正确识别和调用驱动程序的各种回调函数,以实现与平台设备的交互和管理。函数的返回值表示注册过程的执行状态,以便在需要时进行错误处理。

52.1.2 platform_device_unregister 函数

platform_device_unregister函数用于取消注册已经注册的平台设备,即从内核中移除设备。在设备不再需要时,调用该函数可以进行设备的清理和释放操作。

函数原型:

void platform_device_unregister(struct platform_device *pdev);

头文件:

#include <linux/platform_device.h>

函数作用:
platform_device_unregister 函数用于从内核中注销平台设备。通过调用该函数,可以将指定的平台设备从系统中移除。

参数含义

pdev:指向要注销的平台设备的指针。

返回值:
无返回值。

该函数在内核源码目录下的“/include/linux/platform_device.h”文件中,具体内容如下所示:

extern void platform_driver_unregister(struct platform_driver *);

函数声明中的extern关键字表示该函数在其他地方定义,而不是在当前文件中实现。这样的声明通常出现在头文件中,用于告诉编译器该函数的定义存在于其他源文件中,以便在编译时能够正确引用该函数。

而platform_driver_unregister实际定义在“/drivers/base/platform.c”文件中,相关定义如下所示:

void platform_driver_unregister(struct platform_driver *drv)
{
	driver_unregister(&drv->driver);
}

该函数又调用了driver_unregister函数进行嵌套,追踪之后找到定义在“/drivers/base/driver.c”目录下的driver_unregister函数,具体内容如下所示:

void driver_unregister(struct device_driver *drv)
{
    // 检查传入的设备驱动程序指针和 p 成员是否有效
    if (!drv || !drv->p) {
        WARN(1, "Unexpected driver unregister!\n");
        return;
    }

    driver_remove_groups(drv, drv->groups); // 移除与设备驱动程序关联的属性组
    bus_remove_driver(drv);    // 从总线中移除设备驱动程序
}

函数内部有三个主要的操作:

第4-7行:检查传入的设备驱动程序指针 drv 是否为空,或者驱动程序的 p 成员是否为空。如果其中任何一个条件为真,表示传入的参数无效,会发出警告并返回。

第9行:调用 driver_remove_groups 函数,用于从内核中移除与设备驱动程序关联的属性组。drv->groups 是指向属性组的指针,指定了要移除的属性组列表。

第10行:调用 bus_remove_driver 函数,用于从总线中移除设备驱动程序。该函数会执行以下操作:

(1)从总线驱动程序列表中移除指定的设备驱动程序。

(2)调用与设备驱动程序关联的 remove 回调函数(如果有定义)。

(3)释放设备驱动程序所占用的资源和内存。

(4)最终销毁设备驱动程序的数据结构。

通过调用 driver_unregister 函数,可以正确地注销设备驱动程序,并在注销过程中进行必要的清理工作。这样可以避免资源泄漏和其他问题。在调用该函数后,应避免继续使用已注销的设备驱动程序指针,因为该驱动程序已不再存在于内核中。

52.1.3 platform_driver结构体

platform_driver 结构体是Linux内核中用于编写平台设备驱动程序的重要数据结构。它提供了与平台设备驱动相关的函数和数据成员,以便与平台设备进行交互和管理。该结构体定义在内核的“/include/linux/platform_device.h”文件中,具体内容如下所示:

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:平台设备的探测函数指针。当系统检测到一个平台设备与该驱动程序匹配时,该函数将被调用以初始化和配置设备。

remove:平台设备的移除函数指针。当平台设备从系统中移除时,该函数将被调用以执行清理和释放资源的操作。

shutdown:平台设备的关闭函数指针。当系统关闭时,该函数将被调用以执行与平台设备相关的关闭操作。

suspend:平台设备的挂起函数指针。当系统进入挂起状态时,该函数将被调用以执行与平台设备相关的挂起操作。

resume:平台设备的恢复函数指针。当系统从挂起状态恢复时,该函数将被调用以执行与平台设备相关的恢复操作。

driver:包含了与设备驱动程序相关的通用数据,它是 struct device_driver 类型的实例。其中包括驱动程序的名称、总线类型、模块拥有者、属性组数组指针等信息,该结构体的name参数需要与上个章节的platform_device的.name参数相同才能匹配成功,从而进入probe函数

id_table:指向 struct platform_device_id 结构体数组的指针,用于匹配平台设备和驱动程序之间的关联关系。通过该关联关系,可以确定哪个平台设备与该驱动程序匹配,和.driver.name起到相同的作用,但是优先级高于.driver.name。

prevent_deferred_probe:一个布尔值,用于确定是否阻止延迟探测。如果设置为 true,则延迟探测将被禁用。

使用 struct platform_driver 结构体,开发人员可以定义平台设备驱动程序,并将其注册到内核中。当系统检测到与该驱动程序匹配的平台设备时,内核将调用相应的函数来执行设备的初始化、配置、操作和管理。驱动程序可以利用提供的函数指针和通用数据与平台设备进行交互,并提供必要的功能和服务。

需要注意的是,struct platform_driver 结构体继承了 struct device_driver 结构体,因此可以直接访问 struct device_driver 中定义的成员。这使得平台驱动程序可以利用通用的驱动程序机制,并与其他类型的设备驱动程序共享代码和功能。

52.2 实验程序的编写

本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\41

本小节的实验只是编写一个platform驱动的一个大体框架,在下一个章节中再讲解platform设备和platform驱动的匹配

编写完成的platform_driver.c代码如下所示:

#include <linux/module.h>
#include <linux/platform_device.h>

// 平台设备的探测函数
static int my_platform_probe(struct platform_device *pdev)
{
    printk(KERN_INFO "my_platform_probe: Probing platform device\n");

    // 添加设备特定的操作
    // ...

    return 0;
}

// 平台设备的移除函数
static int my_platform_remove(struct platform_device *pdev)
{
    printk(KERN_INFO "my_platform_remove: Removing platform device\n");

    // 清理设备特定的操作
    // ...

    return 0;
}

// 定义平台驱动结构体
static struct platform_driver my_platform_driver = {
    .probe = my_platform_probe,
    .remove = my_platform_remove,
    .driver = {
        .name = "my_platform_device",
        .owner = THIS_MODULE,
    },
};

// 模块初始化函数
static int __init my_platform_driver_init(void)
{
    int ret;

    // 注册平台驱动
    ret = platform_driver_register(&my_platform_driver);
    if (ret) {
        printk(KERN_ERR "Failed to register platform driver\n");
        return ret;
    }

    printk(KERN_INFO "my_platform_driver: Platform driver initialized\n");

    return 0;
}

// 模块退出函数
static void __exit my_platform_driver_exit(void)
{
    // 注销平台驱动
    platform_driver_unregister(&my_platform_driver);

    printk(KERN_INFO "my_platform_driver: Platform driver exited\n");
}

module_init(my_platform_driver_init);
module_exit(my_platform_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");

52.3 运行测试

52.3.1 编译驱动程序

在上一小节中的platform_driver.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:

export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += platform_driver.o    #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel    #这里是你的内核目录                                                                                                                            
PWD ?= $(shell pwd)
all:
    make -C $(KDIR) M=$(PWD) modules    #make操作
clean:
    make -C $(KDIR) M=$(PWD) clean    #make clean操作

对于Makefile的内容注释已在上图添加,保存退出之后,来到存放platform_driver.c和Makefile文件目录下,如下图(图52-1)所示:

图 52-1

然后使用命令“make”进行驱动的编译,编译完成如下图(图52-2)所示:

图 52-2

编译完生成platform_driver.ko目标文件,如下图(图52-3)所示:

至此驱动模块就编译成功了。

52.3.2 运行测试

本小节的测试需要用到两个驱动ko文件,即上一章节的注册platform设备ko文件和本章节的注册platform驱动ko文件。

开发板启动之后,使用以下命令进行驱动模块的加载,如下图(图21-7)所示:

insmod platform_driver.ko

然后来到/sys/bus/platform/drivers目录下,可以看到我们创建的my_platform_driver驱动文件夹就成功生成了。

然后使用以下命令加载注册platform设备ko文件,加载成功之后如下图所示:

 insmod platform_device.ko

可以看到匹配成功之后就会进入probe函数,显示出了相应的打印(加载上述两个ko文件不分先后顺序)。然后使用以下命令进行驱动模块的卸载,如下图(图21-7)所示:

rmmod platform_driver.ko
rmmod platform_device.ko

至此,注册platform驱动实验就完成了。


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

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

相关文章

【码银送书第八期】《Python数据挖掘:入门进阶与实用案例分析》

摘要&#xff1a;本案例将主要结合自动售货机的实际情况&#xff0c;对销售的历史数据进行处理&#xff0c;利用pyecharts库、Matplotlib库进行可视化分析&#xff0c;并对未来4周商品的销售额进行预测&#xff0c;从而为企业制定相应的自动售货机市场需求分析及销售建议提供参…

Unity游戏开发客户端面经,六万字面经知识点,一篇就够了

目前这是记录一些被常问的面经&#xff0c;面向初级&#xff0c;总结了大约六万字的常问知识点&#xff0c;有各种大佬的链接可以深入的了解。希望可以帮助正在准备八股的同学们。 C#&#xff1a;Unity游戏开发客户端面经——C#&#xff08;初级&#xff09;_正在奋斗中的小志的…

【css拾遗】粘性布局实现有滚动条的情况下,按钮固定在页面底部展示

效果&#xff1a; 滚动条滚动过程中&#xff0c;按钮的位置位于手机的底部 滚动条滚到底部时&#xff0c;按钮的位置正常 这个position:sticky真的好用&#xff0c;我原先的想法是利用滚动条滚动事件去控制&#xff0c;没想到css就可以解决 <template><view class…

程序员爱写不写注释的智慧

&#x1f935;‍♂️ 个人主页&#xff1a;艾迦洼的个人主页 ✍&#x1f3fb;作者简介&#xff1a;后端程序猿 &#x1f604; 希望大家多多支持&#xff0c;如果文章对你有帮助的话&#xff0c;欢迎 &#x1f4ac;&#x1f44d;&#x1f3fb;&#x1f4c2; 目录 &#x1f44b;程…

数据结构--》连接世界的无限可能—— 图

图作为数据结构中的一种重要概念&#xff0c;扮演着连接世界的纽带。与树和二叉树相比&#xff0c;图更加灵活和多样化&#xff0c;它能够描述各种实际问题中的复杂关系&#xff0c;如社交网络中的人际联系、城市交通中的路线规划以及电子网络中的通信路径等。 无论你是初学者还…

【【萌新的SOC学习之SD卡读写TXT文本实验】】

萌新的SOC学习之SD卡读写TXT文本实验 SD卡 Secure Digital Card SD卡的引脚定义 我们会用的数据脚就这几个 对于我们FPGA 其实更会倾向于选择 SPI的功能 而TF卡相对于SD卡的区别在于 SD卡只有一个电源地 这里相对于原本的SPI多了一个CD引脚 CD信号是相当于一个卡检测…

竞赛选题 深度学习+opencv+python实现车道线检测 - 自动驾驶

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV56 数据集处理7 模型训练8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &am…

光纤激光切割机如何高效的切割铜等高反材料

高反射材料的切割过程往往具有挑战性&#xff0c;对于许多光纤激光切割设备厂商而言都是难以解决的问题。但是作为铜、铝、金等常见的高反射性材料又需要在日常生产中经常进行加工处理。 很多厂家解决的办法之一就是采用相应的辅助气体。在光纤激光切割机切割铜时&#xff0c;辅…

xshell 上传下载文件命令

Windows 和 Linux上传或下载某个文件首先你的 Linux上需要安装安装 lrzsz工具包在Linux 上执行 yum install lrzsz 上传文件&#xff1a; 输入 rz 下载文件&#xff1a;运行命令 sz zcly.tar.gz (zcly.tar.gz)为文件名称

多标签分类论文笔记 | ML-Decoder: Scalable and Versatile Classification Head

个人论文精读笔记&#xff0c;主要是翻译心得&#xff0c;欢迎旁观&#xff0c;如果有兴趣可以在评论区留言&#xff0c;我们一起探讨。 Paper: https://arxiv.org/pdf/2111.12933.pdf Code: https://github.com/Alibaba-MIIL/ML_Decoder 文章目录 0. 摘要1. 介绍2. 方法2.1 Ba…

offer

【录用通知书】 如何判断公司的好坏呢。 注意了&#xff0c;我们软件行业&#xff0c;技术管理类&#xff0c;技术类&#xff0c;产品类 好公司好企业基本都会给你说清楚&#xff0c;一项多少钱&#xff0c;加班多少钱&#xff0c;这样的 像这类公司的薪资结构复杂就要特别…

如何批量导出文件名?

如何批量导出文件名&#xff1f;在电商行业从事工作的一些同事可能经常会遇到这样的问题&#xff1a;需要将产品文件夹中的所有图片或产品名称导出到Excel工作表&#xff0c;在工作表中创建这些名称的超链接&#xff0c;并且可能会为每个产名称的后面填写一些相关信息&#xff…

LeetCode【152】乘积最大子数组

题目&#xff1a; 解析&#xff1a; 理解这个题的过程中&#xff0c;有这样的疑问&#xff1a; -2、0、2、3 子数组最大值是2*3 6&#xff0c;并非dp过程中&#xff0c;从下标0累乘的怎么办&#xff1f;这里不用担心&#xff0c;因为在dp的过程中会逐渐的求Math.max和Math.m…

知识付费小程序的推广与用户增长策略

在知识付费小程序开发完成后&#xff0c;推广和用户增长是关键的成功因素。本文将探讨一些推广策略和用户增长方法&#xff0c;并提供代码示例&#xff0c;帮助您在知识付费小程序中实施这些策略。 1. 社交媒体分享功能 在知识付费小程序中添加社交媒体分享功能&#xff0c;…

多媒体应用设计师 开始

https://www.bilibili.com/video/BV1jv411q7mz/?spm_id_from333.337.search-card.all.click&vd_source25bced4af8c6d5f851758632d0ca8444

【2023年新版】40套BIM+GIS项目案例合集,中建中铁中交企业内部学习资源免费领取

最近有很多做工程的朋友想要学习BIMGIS技术&#xff0c;向我询问相关的学习资源和资料。他们面临的普遍问题是不知道如何入门&#xff0c;找到的资料很多&#xff0c;但是很多却用不上。 为了解决大家的问题&#xff0c;我们团队花了近一个月的时间&#xff0c;精心整理了一份…

Vue3实战(05)-教你快速搭建Vue3工程化项目

除了Vue 3这个库&#xff0c;还需Vue 3 最新全家桶。 1 环境准备 之前语法演示直接使用script引入Vue 3&#xff0c;从而在浏览器里实现所有调试功能。但实际项目中&#xff0c;使用专门调试工具。在项目上线之前&#xff0c;代码也需打包压缩&#xff0c;并考虑到研发效率和…

C语言文件操作(2)

&#x1f649;本文将继续对文件操作相关知识进行讲解 1. 文件的随机读写 1.1 fseek fseek函数原型&#xff1a; fseek简而言之就是设置文件中的光标&#xff0c;stream就指向对象文件的指针&#xff0c;offset是文件中光标处相对于起始位置的偏移量&#xff0c;origin是光标所…

Docker 容器应急

容器网络简单理解 容器拥有n多张veth网卡与一张docker0网卡 docker 五种网络 bridge 默认网络&#xff0c;Docker启动后创建一个docker0网桥&#xff0c;默认创建的容器也是添加到这个网桥中。host 容器不会获得一个独立的network namespace&#xff0c;而是与宿主机共用一个…

关于Win系统提示由于找不到msvcr120.dll文件问题解决办法

在我使用电脑的过程中&#xff0c;突然弹出了一个错误提示框&#xff0c;提示我系统中缺少msvcp120.dll文件。这个文件是系统运行所必需的&#xff0c;缺少它可能会导致一些软件无法正常运行。经过一番搜索和咨询&#xff0c;我找到了以下几种解决方案&#xff0c;分享给大家&a…