当前位置: 首页 > news >正文

【ZYNQ Linux开发】gpio子系统相关驱动先于Xgpio注册完成而加载失败的问题分析与探究

1 问题描述

​       最近在开发过程中,想把一个涉及按键的驱动编译进内核中,让内核在启动时,自动加载,但是 Linux 系统启动以后吗,尝试使用驱动发现并无 key 设备,但在Linux系统完全启动后,通过insmod命令去加载对应代码编译出的模块 .ko 文件,却能够成功加载。查看内核的启动日志,结果如下(中间的那一条打印是后续打印时添加的):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

       对应驱动初始化部分的代码如下(只保留关键部分):

struct device_node *nd;
const char *str;
int ret;printk("mykey_init succeed in kernel!\n");/* 获取key节点 */
nd = of_find_node_by_path("/key");
if(NULL == nd) {printk(KERN_ERR "key: Failed to get key node\n");return -EINVAL;
}/* 读取status属性 */
ret = of_property_read_string(nd, "status", &str);
if(!ret) {if (strcmp(str, "okay"))return -EINVAL;
}/* 获取compatible属性值并进行匹配 */
ret = of_property_read_string(nd, "compatible", &str);
if(ret)return ret;if (strcmp(str, "my_key")) {printk(KERN_ERR "key: Compatible match failed\n");return -EINVAL;
}/* 获取设备树中的key-gpio属性,得到按键的GPIO编号 */
key.key_gpio = of_get_named_gpio(nd, "key-gpio", 0);
printk(KERN_INFO "key: Got GPIO num = %d\n", key.key_gpio); // 打印实际获取的值
if(!gpio_is_valid(key.key_gpio)) {printk(KERN_ERR "key: Failed to get key-gpio\n");return -EINVAL;
}

       说明从设备树获取gpio子系统的相关信息出了问题

2 问题分析与探究

       由以上代码,结合在 uboot 中使用 boot.scr 成功加载了设备树文件,并有以下日志记录:

[    0.000000] efi: Getting EFI parameters from FDT:

​       可以分析得知,设备树确实在 uboot 中成功加载。但错误信息的打印发生在获取设备树中的 key-gpio 属性,而前面获取 key 节点、读取 status 和 compatible 属性均没有问题,可以进一步说明不是设备树的问题

       进而,本着哪里出错,就把对应地方的错误返回值打印出来的原则,在驱动中添加了对应的打印。得到的打印结果也如 1 中所示,为 -517,代表的是宏EPROBE_DEFER,说明用于设备驱动探测过程中的依赖资源未就绪。而我这里所使用的资源,便是 GPIO 资源。

       这时,继续分析系统日志,发现:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

       系统对于驱动的加载发生在 3.255697s,而 XGPIO 控制器注册完成却是发生在 3.310812s,也就是在驱动加载之后

       进一步佐证了错误码 -517 (EPROBE_DEFER)打印的问题。

       既然如此,那就考虑怎么把驱动的加载放在 XGPIO 控制器注册之后

       在此之前,我在驱动中对于驱动入口函数使用以下形式进行声明:

module_init(mykey_init);

       那么如果换成以下形式:

late_initcall(mykey_init);

       使用最迟的初始化呢?很遗憾,问题仍然存在

       那再尝试了一个 Deepseeker 提供的方法:在驱动中加入阻塞判断,在确保所有设备都 probe

/* 获取设备树中的key-gpio属性,得到按键的GPIO编号 */
key.key_gpio = of_get_named_gpio(nd, "key-gpio", 0);
printk(KERN_INFO "key: Got GPIO num = %d\n", key.key_gpio); // 打印实际获取的值
if (key.key_gpio == -EPROBE_DEFER) {wait_for_device_probe();key.key_gpio = of_get_named_gpio(nd, "key-gpio", 0); // 重试
}if(!gpio_is_valid(key.key_gpio)) {printk(KERN_ERR "key: Failed to get key-gpio\n");return -EINVAL;
}

       但也没有效果。调试到这,似乎就陷入了死局,**难道必须要编译为 .ko 模块且启动后用命令加载才能成功地加载驱动?**作为非常成熟的系统,Linux必不可能是这个样子。

       没有思路,就从头开始分析,一步步看看我是如何把对应的驱动代码放进内核源码,再进而编译进内核的。

       1,首先,由于是与 GPIO 相关的代码,我直接就把它放在了 内核源码根目录/drivers/gpio 中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

       2,然后就是修改这个文件夹的 Makefile,在尾部添加:

obj-$(CONFIG_GPIO_ASYNCNOTI)	+= asyncnoti.o

       3,最后在这个文件夹的 Kconfig 中添加:

config GPIO_ASYNCNOTItristate "GPIO Async notice kernel test"default yhelpSay Y to enable the async notice driver for kernel test.

       对比其他人的方法,仔细去核对了一下步骤和内容,都没有发现有什么问题。

       这时突发奇想,因为我的驱动用到了 GPIO 子系统,我才把它放在了 /gpio 中,但有没有一种可能,对于Linux系统来说,它会先加载这里的所有驱动,最后再初始化 Xgpio 呢?如果是这样,那肯定我们前面所有的把驱动加载的时候延后的尝试都是徒劳的!

       直接实验一下就好了,这次,我把驱动源文件放在了/drivers/leds 中,采用与上面相同的方法编译内核,再使用板子启动。接着,就成功加载了!

       想想也是够离谱的,不过,还没有完全结束。这时我的驱动,初始化宏还是使用了 late_initcall ,也还保留了上面的阻塞操作确保所有 probe 完成,那如果把它们都改回最初状态(使用 module_init 声明,不使用阻塞等待)呢?结果发现,也是没有问题的。

       那到底是哪个起了作用呢?经过测试,用wait_for_device_probe(); 等待所有设备匹配完成是不必要的,但是对驱动的入口函数声明为最晚初始化是必须的

3总结

       通过以上分析,问题的关键就很明了了。就跟我前面的猜测一样,对于Linux系统来说,它会先加载 drivers/gpio 所有驱动,最后再初始化 Xgpio!

       具体的解决方法为:

       1,而我们的驱动如果涉及 gpio 子系统,则不要把源文件放到 drivers/gpio 这个文件夹中

       2,在驱动的入口函数声明采用最晚初始化:

late_initcall(mykey_init);

相关文章:

  • 《从IaaS到容器化:深度解析云计算三层架构与阿里云ECS+K8s协同实践》
  • 快速入门数据结构--栈
  • 【云计算领域数学基础】组合数学优化
  • 1.19集成开发环境(IDE)
  • 从loader和plugin开始了解webpack
  • Alova 封装与 Vue 3 集成示例
  • 大模型笔记3:通过插件增强大模型的能力
  • RabbitMQ消息队列实战指南
  • 【Go语言-Day 1】扬帆起航:从零到一,精通 Go 语言环境搭建与首个程序
  • qt信号与槽--02
  • SpringBoot电脑商城项目--项目分析及搭建
  • 2011-2020年各省互联网接入端口数数据
  • 项目实训个人工作梳理
  • 抽象工厂1
  • Go实战项目OneX介绍(2/12):项目功能列表介绍
  • 力扣第 454 场周赛
  • Seata 全面深入学习指南
  • LeetCode 第75题:颜色分类
  • IDEA21中文乱码解决办法
  • Redis-CPP通用接口
  • 仿阿里百秀网站模板/网站开发框架
  • 广东高端网站建设/重庆网站快速排名提升
  • 有了域名之后怎么做网站/全球搜索网站排名
  • 微信视频网站怎么做/宁波seo网站排名
  • 网站建设 嘉定/全球最大的中文搜索引擎
  • 泉州软件开发公司/图片seo优化是什么意思