[Linux 驱动] -- 驱动调试技巧点滴分享

引言

作为驱动工程师,主要的工作就是移植各种驱动,接触各种硬件。接触最多的就是 dts、中断、gpio、sysfs、proc。如何利用 sysfs、proc 及内核提供的接口为我们降低调试难度,快速解决问题呢?

注:部分代码分析举例基于 Linux-4.15。

如何利用 dts ?

首先我们关注的主要是两点,gpio 和 irq。其他的选择忽略。先展示一下我期望的 gpio 和 irq 的使用方法。dts 如下:

device {
    rst-gpio = <&gpioc_ctl 10 OF_GPIO_ACTIVE_LOW>;
    irq-gpio = <&gpioc_ctl 11 0>;
    interrupts-extended = <&vic 11 IRQF_TRIGGER_RISING>;
};

对于以上的 dts 你应该再熟悉不过,当然这里不是教你如何使用 dts,而是关注 gpio 和 irq 最后一个数字可以如何利用。

例如 rst-gpio 的 OF_GPIO_ACTIVE_LOW 代表什么意思呢?可以理解为低有效。对于一个程序员来说,我们可以封装一个函数,写 1 就是打开灯,写 0 就是关灯。但是对于硬件来说,变化的是 gpio 口的电平状态。如果 gpio 输出高电平灯亮,那么这就是高有效。如果硬件设计是 gpio 输出低电平灯亮,那么就是低有效。对于一个软件工程师来说,我们期望的是写 1 就是灯亮,写 0 就是关灯。

我们可以认为 dts 是描述具体的硬件。因此对于驱动来说,硬件的这种变化,只需要修改 dts 即可。软件不用任何修改,软件可以如下实现:

int device_probe(struct platform_device *pdev)
{
    rst_gpio = of_get_named_gpio_flags(np, "rst-gpio", 0, &flags);
    
    if(flags & OF_GPIO_ACTIVE_LOW){
        struct gpio_desc *desc;
        desc = gpio_to_desc(rst_gpio);
        set_bit(FLAG_ACTIVE_LOW, &desc->flags);
    }
    
    irq = of_irq_get(np, 0);
    trigger_type = irq_get_trigger_type(irq);
    request_threaded_irq(irq, NULL, irq_handler, trigger_type, "irq", NULL);
}

驱动按照以上代码实现的话,如果修改中断触发类型或者电平有效状态只需要修改 dts 即可。例如不同的 IC 复位电平是不一样的,有的 IC 是高电平复位,有的 IC 是低电平复位。

如何调试 gpio ?

移植驱动阶段或者调试节点的工程中,难免想知道当前 gpio 的电平状态。当然很 easy,万用表戳上去不就行了。是啊!硬件工程师的思维。作为软件工程师自然是要软件的方法。下面介绍两个 api 接口。自己摸索使用吧,点到为止。

static inline int gpio_export(unsigned gpio, bool direction_may_change);
static inline int gpio_export_link(struct device *dev,const char *name,unsigned gpio);

在你的 driver 中调用以上 api 后,编译下载。去 /sys/class/gpio 目录看看有什么发现。

如何调试 irq ?

调试的时候也难免会确定硬件是否产生中断。我们该怎么办呢?也很easy。

cat /proc/interrupts

输出信息不想多余的介绍。看代码去。根据输出的 irq num,假设是 irq_num。请进入以下目录。看看下面都有什么文件。摸索这些文件可以为你调试带来哪些方便。

cd /proc/irq/irq_num

dts 和 sysfs 有什么关联?

曾经写过一篇 dts 解析的文章 http://www.wowotech.net/device_model/dt-code-file-struct-parse.html。最后一节其实说了一个很有意思的东西。但是仅仅是寥寥结尾。并没有展开。因为它不关乎我写的文章的主题。但是,它却和调试息息相关。

cd /sys/firmware/devicetree/base

该目录的信息就是整个 dts。将整个 dts 的节点以及属性全部展现在 sysfs 中。它对我们的调试有什么用呢? Let me tell you。如果你的项目非常复杂,例如一套代码兼容多种硬件配置。这些硬件配置的差异信息主要是依靠 dts 进行区分。当编译 kernel 的时候,你发现你很难确定就是你用的是哪个 dts。可能你就会凭借自己多年的工作经验去猜测。

是的,你的经验很厉害。但是,如何确定你的 dts 信息是否添加到 kernel 使用的 dts 呢?我觉得你应该 got it。就到整个目录去查找是否包含你添加的 node 和property。dts 中有status 属性可以设置某个 device 是否使能。当你发现你的 driver 的 probe 没有执行的时候,我觉得你就需要确定一遍 status 是不是 "ok"、"okay" 或者没有这个属性。

远不止我所说的这个功能,还可以判断当前的硬件是匹配哪个 dts 文件。你还不去探索一波源码的设计与实现吗?节点为什么出现在某些目录?为什么有些节点的属性 cat 确是乱码?就是乱码,你没有看错。至于为什么。点到为止。

sysfs 可以看出什么猫腻?

sysfs 有什么用?sysfs 可以看出 device 是否注册成功、存在哪些 device、driver 是否注册、device 和 driver 是否匹配、device 匹配的 driver 是哪个等等。先说第一项技能。device 是否注册。

就以 i2c 设备为例说明。/sys/bus/i2c/devices 该目录下面全是 i2c 总线下面的 devices。如何确定自己的 device 是否注册呢?首先你需要确定自己的 device 挂接的总线是哪个 i2c(i2c0,i2c1 ...)。假设设备挂接 i2c3,从地址假设 0x55。那么 devices 目录只需要查看是否有 3-0055目录即可。

如何确定 device 是否匹配了驱动?

进入 3-0055 目录,其实你可以看到 driver 的符号链接。如果没有,那么就是没有 driver。driver 是否注册如何确定呢?方法类似。/sys/bus/i2c/drivers 目录就是所有注册的 i2c driver。方法如上,不在举例。

你以为就这些简单的功能了吗?其实不是,还有很多待你探讨。主要是各种目录之间的关系,device 注册会出现什么目录?那么 driver 呢?各种符号链接会在哪些目录?等等。

如何排查 driver 的 probe 没有执行的问题?

我想这类问题是移植过程中极容易出现的第一个拦路虎。这里需要声明一点。可能有些驱动工程师认为 probe 没有执行就是 driver 没有注册成功。其实这两个没有半毛钱的关系。probe 是否执行只是和 device 和driver 是否匹配成功有关。我们有什么思路排查这类问题呢?

主要排查方法可以如下:

通过 sysfs 确定对应的 device 是否注册成功;

通过 sysfs 确定对应的 driver 是否注册成功;

通过 sysfs 中的 dts 的展开信息得到 compatible 属性的值,然后和 driver 的 compatible 进行对比。

如果发现 device 没有注册,如何确定问题。首先通过 sysfs 中的 dts 展开文件查看是否有你添加的 device 信息。如果没有的话,没有 device 注册就是正常的,去找到正确的 dts 添加正确的 device 信息。如果发现 sysfs 有 device 的 dts 信息,那么就看看 status 属性的值是不是 ok 的。

如果也是 ok 的,那么就非常奇怪了,这种情况一般出现在 kernel 的 device 注册路径出错了。曾经就有一个小伙伴提出问题,现象就是这样。最后我帮他确定问题原因是 dts 的 reg 属性的地址是 0xC0,这是一个大于 0x7F 的值。在 i2c 总线注册驱动的时候会解析当前总线下所有 device,然后注册所有的从设备。就是这里的地址检查出了问题,因此这个 device 没有注册上。

如果发现 driver 没有注册,那么去看看对应的 Makefile 是否参与编译,如果参与了编译,就查看 log 信息,是不是驱动注册的时候有错误信息。

最后一点的 compatible 属性的值只需要 cat 一下,然后 compare 即可,不多说。

后记

sysfs 还有很多的其他的调试信息可以查看。一次,我建议驱动工程师都应该掌握 sysfs 的使用和原理,看看代码实现。我始终坚信只有更好地掌握技术的原理才能更好地利用技术。

文章内容不想展开。我告诉你的结果,你永远记忆不深刻,而且我说的也不一定对。还是需要自己专研。我只是给你指条明路,剩下的就需要自己去走。最后说一句,代码不会骗你,还会告诉你别人不能告诉你的。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值