在 Linux 内核中添加自己的驱动并进行验证:从 Kconfig 配置到设备创建

在 Linux 内核中添加自己的驱动并进行验证:从 Kconfig 配置到设备创建

在 Linux 内核中,驱动程序通常通过 KconfigMakefile 进行配置和编译,最终生成 内建驱动模块驱动。关于如何在标准的内核源码中添加属于自己的驱动配置并编译和测试可以参考这位佬的文章:
Kconfig 编译驱动到内核

本文将详细介绍在将自定义的驱动程序添加到 Linux 内核,配置内核后的验证驱动是否已正确编译并创建设备文件。


概念和流程概述

在 Linux 内核中,驱动程序的工作流程大致分为两个阶段:

  1. 编译阶段
    • 通过 Kconfig 配置驱动是否被编译到内核中或作为模块编译。
    • Makefile 控制驱动文件的编译和链接过程,生成 .ko 文件(模块)或直接编译进内核。
  2. 运行阶段
    • 驱动程序根据设备类型(如 platform 设备、PCI 设备等)将设备注册到内核,创建 struct device 对象。
    • 驱动通过 probe() 函数将设备与驱动程序绑定,随后可以创建设备文件供用户访问。

无论采用何种方式编写驱动,都有一个共同的目标:驱动能够正常加载并使设备文件在 /dev 下可见


三种驱动编写方式

驱动编写方式通常有三种:传统方式平台总线方式设备树方式。以下将详细介绍每种方式的设备创建流程以及如何验证驱动是否编译成功并成功创建设备。

1. 传统方式

传统方式通常用于不依赖设备树和总线机制的简单驱动,设备通过 class_createdevice_create/sys/class 下创建,用户态通过 udevmdev/dev 下创建对应的设备节点。

设备创建

在驱动代码中,创建设备和注册字符设备的流程如下:

static dev_t mydev_num;
static struct class *mydev_class;

static int __init mydev_init(void)
{
    int ret;

    // 申请设备号
    ret = alloc_chrdev_region(&mydev_num, 0, 1, "mydev");
    if (ret)
        return ret;

    // 注册 cdev
    cdev_add(&my_cdev, mydev_num, 1);

    // 创建 sysfs 下的 class
    mydev_class = class_create(THIS_MODULE, "mydev");

    // 创建逻辑 device
    device_create(mydev_class, NULL, mydev_num, NULL, "mydev0");

    return 0;
}

通过上述代码,在 /sys/class/mydev/mydev0/dev/mydev0 下会创建对应的设备。

验证驱动是否编译并生成设备
  1. 检查配置是否生效

    在内核源码目录或目标板上,查看配置是否正确:

    grep CONFIG_MY_DRIVER .config   # 编译前检查配置
    zcat /proc/config.gz | grep CONFIG_MY_DRIVER  # 编译后检查配置
    
  2. 检查内核模块是否编译

    • 如果是模块 (CONFIG_MY_DRIVER=m),可以使用以下命令查看模块文件:

      find /lib/modules/$(uname -r) -name "my_driver.ko"
      
    • 如果是内建驱动 (CONFIG_MY_DRIVER=y),则不会生成 .ko 文件,但可以通过以下命令检查内核模块:

      ls /sys/module | grep my_driver
      
  3. 查看驱动是否正常加载

    • 使用 lsmod 检查模块是否加载:

      lsmod | grep my_driver
      
    • 使用 dmesg 查看启动日志,确认驱动是否成功加载:

      dmesg | grep -i my_driver
      
  4. 查看设备文件是否生成
    如果是字符设备,udev 会自动在 /dev 下创建设备文件:

    ls /dev | grep mydev
    

2. 平台总线方式

在平台总线方式下,设备通常通过 platform_device 注册,而驱动通过 platform_driver 绑定到设备。设备的创建通常在 /sys/bus/platform/devices 目录下。

设备创建

在设备树或板级代码中,创建一个平台设备:

static struct platform_device mydev_device = {
    .name = "mydev",
    .id = -1,
    .num_resources = ARRAY_SIZE(mydev_resources),
    .resource = mydev_resources,
};

static struct platform_driver mydev_driver = {
    .probe = mydev_probe,
    .driver = {
        .name = "mydev",
    },
};

module_platform_driver(mydev_driver);

内核启动时会自动加载并绑定驱动,调用 probe() 函数进行初始化。

验证驱动是否编译并生成设备
  1. 检查内核配置
    使用与传统方式相同的方法检查内核配置。

  2. 检查设备和驱动是否绑定

    查看 /sys/bus/platform/devices/sys/bus/platform/drivers 目录,确认设备和驱动是否成功绑定:

    ls /sys/bus/platform/devices | grep mydev
    ls /sys/bus/platform/drivers | grep mydev
    

    如果设备和驱动成功绑定, /sys/bus/platform/drivers/mydev/ 中会出现指向设备的符号链接。

  3. 查看设备文件是否生成

    如果驱动成功绑定设备,可以在 /dev 目录下查看设备文件:

    ls /dev | grep mydev
    

3. 设备树方式

设备树方式适用于 ARM 等嵌入式平台,设备信息通过 DTS 文件描述,内核启动时解析设备树创建设备并绑定驱动。

设备创建

设备树节点示例如下:

mydev@12340000 {
    compatible = "myvendor,mydev";
    reg = <0x12340000 0x1000>;
    interrupt-parent = <&gic>;
    interrupts = <10>;
    status = "okay";
};

驱动代码中使用 of_device_id 表示驱动与设备的匹配关系:

static const struct of_device_id mydev_of_match[] = {
    { .compatible = "myvendor,mydev", },
    { /* sentinel */ }
};

static struct platform_driver mydev_driver = {
    .probe = mydev_probe,
    .driver = {
        .name = "mydev",
        .of_match_table = mydev_of_match,
    },
};

module_platform_driver(mydev_driver);

当内核启动时,设备树中的节点会被解析为 platform_device,并与相应的驱动进行匹配,调用 probe() 函数进行初始化。

验证驱动是否编译并生成设备
  1. 检查设备树节点是否存在

    在目标板上,使用以下命令查看设备树是否包含你的设备:

    ls /sys/firmware/devicetree/base | grep mydev
    
  2. 检查平台设备和驱动是否绑定

    同平台总线方式,查看 /sys/bus/platform/devices/sys/bus/platform/drivers 目录,确认设备和驱动是否成功绑定:

    ls /sys/bus/platform/devices | grep mydev
    ls /sys/bus/platform/drivers | grep mydev
    
  3. 查看设备文件是否生成

    如果设备绑定成功,可以查看 /dev 目录下的设备文件:

    ls /dev | grep mydev
    

验证驱动是否成功加载

无论你采用哪种驱动方式,以下是几种通用的验证方法:

  1. 查看内核日志

    使用 dmesg 查看内核日志,确保驱动已成功加载并执行了 probe() 函数:

    dmesg | grep -i my_driver
    
  2. 查看设备文件

    查看 /dev 目录下是否已创建相应的设备文件:

    ls /dev | grep mydev
    
  3. 检查模块

    如果使用模块,使用 lsmod 确认模块是否加载:

    lsmod | grep my_driver
    

总结

通过本文的讲解,你应该能够理解如何通过 KconfigMakefile 配置自己的驱动程序,并在编译内核时将其编译进内核或作为模块加载。验证驱动是否成功编译和加载,可以通过查看 /dev 下的设备文件、内核日志以及 lsmod 等工具来确认驱动是否正常运行。

无论你选择传统的方式、平台总线方式还是设备树方式,这些方法都能确保你的驱动成功加载并在系统中生成设备文件供用户使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值