【Linux驱动开发 ---- 4_驱动开发框架和 API】

Linux驱动开发 ---- 4_驱动开发框架和 API

🎯 目标:

掌握 Linux 设备模型、设备树、sysfs 和平台设备的概念,为编写更复杂的驱动程序奠定基础。


📌 1. Linux 设备模型(Linux Device Model)

Linux 内核采用了 设备模型(Device Model) 来管理系统中的所有设备。设备模型为内核提供了一个统一的方式来管理硬件设备和与之交互的驱动程序。

设备模型的核心概念
  • 设备(Device):硬件设备的抽象,通过 struct device 来表示。
  • 驱动程序(Driver):处理设备的内核代码,通过 struct device_driver 来表示。
  • 总线(Bus):设备和驱动程序之间的中介,表示设备所属的类型(例如:PCI 总线、USB 总线)。
  • 类(Class):设备的一类,用于组织设备。
  • 注册(Registration):设备、驱动程序和总线的注册机制,使内核能够识别硬件和驱动之间的关系。

📌 2. 设备树(Device Tree)

设备树(Device Tree)是一个数据结构,描述了硬件设备的布局。在嵌入式系统中,设备树用于帮助内核识别和初始化硬件设备。设备树不依赖于内核代码,它是一个纯粹的数据文件,允许内核在启动时加载硬件信息。

  • 主要作用:在系统启动时,内核通过设备树来获取硬件设备的配置信息,并根据该信息驱动设备。
  • 设备树文件:通常存放在 /boot/dtbs 目录下,文件扩展名为 .dtb
设备树示例
/dts-v1/;
/ {
    model = "My Custom Board";
    compatible = "generic-board";

    memory {
        reg = <0x80000000 0x40000000>;  // 内存起始地址和大小
    };

    uart0: serial@9000000 {
        compatible = "uart16550";
        reg = <0x9000000 0x1000>;
        interrupts = <0x14>;
    };
};

在这个示例中,定义了一个 UART 设备(serial@9000000),它的内存映射基地址是 0x9000000,并且配置了中断。

  • compatible 字段定义了该设备支持的设备类型。
  • reg 表示设备的寄存器地址。
  • interrupts 定义了设备中断号。

📌 3. sysfs:与用户空间交互的接口

sysfs 详细解释

sysfs 是 Linux 提供的一个虚拟文件系统,旨在使内核中的设备信息和状态暴露给用户空间程序。通过读取和写入 sysfs 中的文件,用户可以与设备驱动进行交互,并且通过这种方式进行设备配置、状态查询等操作。sysfs 通过 /sys 目录提供了一种访问内核对象(如设备、驱动、总线等)属性的方式。

  1. sysfs 的常见路径
  • /sys/class/:设备类型目录,每个设备类别(例如 netblock 等)都会在这里有一个子目录。
  • /sys/devices/:所有设备的路径信息,包括硬件设备的具体描述。
  • /sys/bus/:与总线相关的设备,像 PCI、USB 总线等会在这里列出。
  1. sysfs 作用
  • 配置设备参数:通过向 /sys 中的文件写入数据,可以改变设备的配置。
  • 读取设备状态:可以通过读取 /sys 中的文件获取设备的实时状态或参数。
  • 查看内核信息:通过访问 /sys 中的文件,用户可以查看内核的内存、CPU 资源使用情况等信息。
  1. 创建设备属性文件
    设备属性文件允许用户空间程序通过简单的文件 I/O 操作(如读取、写入)来交互。驱动程序可以使用 sysfs 来创建这些文件,并通过文件暴露设备的状态或控制接口。

    代码示例

    struct device_attribute dev_attr_myattribute = {
        .attr = { .name = "myattribute", .mode = S_IRUGO },
        .show = myattribute_show,
    };
    
    • struct device_attribute:这是 Linux 内核中定义的一个结构体,用来表示一个设备的属性。通过这个结构体,设备驱动可以指定属性的名称、访问权限以及读取(show)和写入(store)操作函数。

    • dev_attr_myattribute:这是定义的设备属性结构体实例。每个属性结构体包含了以下信息:

    • .attr:属性的具体信息,包括文件名(name)和访问模式(mode)。S_IRUGO 表示该文件是只读的,且可以被用户空间读取。

    • .show:设备属性文件的读取操作函数。该函数的作用是将设备的状态或配置输出到缓冲区 buf 中。

    show 函数:

    static ssize_t myattribute_show(struct device *dev, struct device_attribute *attr, char *buf) {
        return sprintf(buf, "42\n");
    }
    
    • myattribute_show:这是属性的读取函数,它会在用户空间读取 /sys 文件时调用。

    • dev:设备指针,指向调用该函数的设备实例。

    • attr:属性指针,指向该属性。

    • buf:缓冲区,用于将属性值返回给用户空间。

    • sprintf(buf, "42\n"):将 42 作为属性值写入缓冲区 buf 中。

    • 该函数的作用是当用户读取 /sys/.../myattribute 文件时,返回 “42” 字符串。

  2. 注册设备属性
    设备属性文件需要通过 sysfs_create_file 注册到 sysfs 中。这使得属性文件出现在 /sys 下,并且允许用户空间应用通过文件访问该属性。

    注册属性:

    sysfs_create_file(&dev->kobj, &dev_attr_myattribute.attr);
    
    • dev->kobj:每个设备都有一个 kobject,它是与设备相关的内核对象。在 sysfs 中,所有的设备属性都与 kobject 紧密相关。kobject 是内核对象的一个基本表示,它具有与设备相关的属性。

    • dev_attr_myattribute.attr:这是我们在前面定义的属性结构体 dev_attr_myattribute。通过 sysfs_create_file,该属性会被创建并注册到设备的 kobject 中,形成 /sys 目录下的一个文件。

    • sysfs_create_file:此函数将属性文件添加到 sysfs 文件系统中。如果成功,用户可以通过 /sys 目录访问该文件。例如,如果设备 dev 关联了属性 myattribute,那么该文件将出现在 /sys/.../myattribute 下。

  3. 访问属性文件
    一旦设备属性文件创建并注册到 sysfs 中,用户空间的应用程序就可以通过标准的文件 I/O 操作(如读取)来与设备进行交互。例如,可以使用 cat /sys/.../myattribute 来读取属性值。

    • 当用户空间应用程序读取 /sys/.../myattribute 文件时,myattribute_show 函数会被调用,返回属性值 “42”。
  4. 删除设备属性
    当设备不再需要该属性时,需要通过 sysfs_remove_file 删除该属性文件,防止内存泄漏:

    sysfs_remove_file(&dev->kobj, &dev_attr_myattribute.attr);
    
  5. 总结
    通过 sysfs,驱动程序能够将内核对象的属性暴露给用户空间。sysfs 通过虚拟文件系统提供了一种简单、直观的机制,使得设备、内核信息可以通过文件系统接口访问。驱动程序通过创建和注册设备属性文件,允许用户空间读取和写入设备参数或状态。这种机制简化了内核与用户空间的交互,广泛应用于设备配置、调试和状态查询等场景。


📌 4. 平台设备(Platform Devices)

平台设备(Platform Devices) 是嵌入式系统中用于表示硬件设备的一种设备类型,通常与平台(如 ARM)相关联。平台设备不依赖于总线(例如:PCI、USB),而是通过静态配置或设备树来配置。

  • 用途:嵌入式设备通常使用平台设备,例如 GPIO、SPI 等控制器。
  • 注册方法:平台设备通过 platform_device_register()platform_driver_register() 来注册。
平台设备注册示例
static struct platform_device *pdev;

static int __init platform_dev_init(void) {
    pdev = platform_device_register_simple("my_platform_device", -1, NULL, 0);
    if (IS_ERR(pdev))
        return PTR_ERR(pdev);

    return 0;
}

static void __exit platform_dev_exit(void) {
    platform_device_unregister(pdev);
}

module_init(platform_dev_init);
module_exit(platform_dev_exit);

在这个例子中,我们使用 platform_device_register_simple 来注册一个平台设备,并使用 platform_device_unregister 来注销设备。


📌 5. 驱动 API 及常用操作

  • platform_driver_register:注册平台驱动程序。
  • platform_device_register:注册平台设备。
  • device_create:在 /dev 中创建一个设备文件。
  • class_create:创建一个设备类(/sys/class/)。
  • sysfs_create_file:在 sysfs 中创建一个设备属性文件。
  • alloc_chrdev_region:分配一个字符设备号。
  • cdev_add:注册字符设备。

📌 6. 实践任务:设备树与 sysfs 文件操作

实践 1:设备树配置与查看
  1. 查看设备树文件并理解设备节点的定义。
  2. 在设备树中增加一个自定义设备节点,并让内核启动时加载。
实践 2:sysfs 操作
  1. 编写一个简单的内核模块,创建一个 sysfs 文件,并通过 show 函数读取一个值。
  2. 在用户空间读取该值,检查 sysfs 操作是否成功。

📌 7. 总结回顾

内容项说明
设备模型Linux 使用设备模型管理设备、驱动和总线。
设备树设备树是硬件配置的描述文件,帮助内核识别硬件设备。
sysfs用于内核与用户空间交互的虚拟文件系统,设备信息通过文件暴露。
平台设备嵌入式系统中硬件设备的抽象,通常通过设备树或静态配置。
驱动注册和注销使用 platform_driver_registerplatform_device_register 注册驱动与设备。

🧠 今日练习题(可选)


  1. 解释设备树中的 regcompatible 字段的作用。

    在设备树(Device Tree)中,regcompatible 是两个非常常见且重要的字段,它们用来描述设备的硬件资源和设备类型。它们的作用如下:

    1). compatible 字段

    作用

    • compatible 字段用于描述设备或硬件节点的硬件类型或设备驱动程序类型。
    • 它是一个字符串,通常包含了设备的名称和可能的硬件兼容性信息。它帮助设备树中的设备节点与内核中正确的驱动程序进行匹配。内核根据这个字段来查找并加载适当的驱动程序。

    具体作用

    • 内核会使用 compatible 字段来确定哪个驱动程序适配该设备。
    • 如果 compatible 字段值与内核中驱动程序的 of_match_table 匹配,内核就会选择对应的驱动程序进行初始化。
    • 该字段通常包含主机架构信息(如 ARM、x86)或硬件平台特定信息,确保驱动程序可以正确识别并支持特定硬件。

    示例

    compatible = "vendor,device-model", "arm,platform";
    

    在这个示例中,设备的硬件类型被定义为 vendor,device-model,并且该设备与 arm,platform 兼容。内核会根据这些信息来选择合适的驱动程序。

    2). reg 字段

    作用

    • reg 字段用于定义设备的地址或端口等硬件资源。在设备树中,这个字段通常指定了设备的物理地址、I/O 端口、内存区间等资源位置。
    • 对于某些设备,reg 字段指定了设备寄存器的地址范围或内存映射的区域。
    • reg 通常与设备的硬件资源(如地址空间)一起使用,内核通过这些信息来确定如何访问和控制硬件设备。

    具体作用

    • reg 字段指定了设备在内存中的地址,或者设备的 I/O 地址(如 PCI 总线地址、内存映射寄存器的物理地址)。
    • 该字段的值是一个整数数组或地址范围。内核使用这些地址信息来配置设备并与硬件交互。

    示例

    reg = <0x10000000 0x1000>;
    

    在这个示例中,reg 定义了设备的地址为 0x10000000,大小为 0x1000 字节。

    compatiblereg 结合使用

    设备树中的 compatiblereg 字段通常一起使用,来标识设备类型和资源位置。内核会根据 compatible 字段找到对应的驱动程序,然后根据 reg 字段提供的地址信息来配置硬件设备。

    结合示例

    mydevice@10000000 {
        compatible = "vendor,mydevice";
        reg = <0x10000000 0x1000>;
    };
    
    • 在这个示例中,mydevice 是一个设备节点。
    • compatible = "vendor,mydevice" 指定了设备的类型,内核将使用这个字段来查找驱动程序。
    • reg = <0x10000000 0x1000> 表示该设备的寄存器地址为 0x10000000,并且设备的寄存器空间大小为 0x1000 字节。
    小结
    • compatible:标识设备的类型和兼容性,帮助内核加载合适的驱动程序。
    • reg:定义设备的硬件资源地址,如内存地址、I/O 地址等。

    这些字段帮助设备树描述硬件设备的具体配置,使内核能够识别、初始化和配置硬件设备。


  1. 在你的驱动程序中,使用 sysfs 创建一个简单的属性文件,允许用户空间访问。

  1. 为什么平台设备常用于嵌入式系统?
    平台设备(Platform Devices)在嵌入式系统中常被使用,原因可以从多个方面进行分析,主要包括以下几个关键点:

    1). 不依赖总线的硬件抽象
    • 平台设备不依赖于传统的硬件总线(如 PCI、USB 等)。它们通常通过静态配置或设备树来描述硬件设备,并通过内核直接进行管理和操作。这使得平台设备特别适用于嵌入式系统,因为嵌入式系统的硬件平台通常是固定的且没有复杂的总线系统。
    2). 简化硬件抽象层(HAL)
    • 嵌入式系统中,硬件通常具有固定的配置,且设备间的通信不需要依赖于复杂的总线协议。平台设备为设备驱动提供了一个简单而一致的接口,使得硬件抽象层变得更加简洁且高效。开发者可以使用平台设备直接访问和控制硬件,而不必为每种硬件设计不同的驱动。
    3). 设备树的使用
    • 在许多嵌入式系统中,尤其是基于 ARM 架构的系统,设备树(Device Tree)用于描述硬件信息。在设备树中,平台设备的节点描述了硬件的属性和配置,使得内核能够在启动时根据设备树来配置设备。设备树通常会静态地定义系统中所有设备的属性,因此不需要依赖动态总线扫描机制,这进一步提升了系统的启动速度和效率。
    4). 适应嵌入式硬件
    • 嵌入式设备通常是一些嵌入式控制器、传感器、通信接口等硬件模块,这些硬件设备在嵌入式系统中扮演着重要角色。平台设备使得这些设备可以直接与内核交互而无需复杂的总线支持,这正是嵌入式系统所需要的简洁和高效的方式。
    5). 易于驱动管理
    • 使用平台设备注册的硬件设备通常是与某个平台或某些硬件特性密切相关的。这种设备通常可以通过 platform_driver 与设备驱动进行匹配。通过这种方式,设备驱动和硬件设备之间的关系更加紧密,可以为每种平台硬件设备提供定制化的驱动程序,简化了驱动程序的管理和维护。
    6). 资源的静态配置
    • 在嵌入式系统中,设备通常是预先配置并且是固定的。平台设备通过内核静态地注册设备,使得这些设备在系统启动时自动可用,减少了硬件配置的复杂性。对于大多数嵌入式系统而言,静态配置和简化管理正是系统要求的特性。
    7). 适用范围
    • 平台设备广泛用于嵌入式系统中,如 GPIO、SPI、I2C 控制器、PWM 控制器、UART 控制器等。它们通常不依赖于标准总线协议(如 PCI、USB 等),而是直接与内核和驱动程序交互,提供简单且高效的硬件访问。
    8). 内核和硬件耦合紧密
    • 平台设备的特点是与特定平台硬件紧密耦合。每个平台的硬件都有自己的配置和需求,而通过平台设备机制,内核可以直接控制这些硬件设备,不需要额外的硬件抽象层(HAL)或总线管理,减少了系统开销。
    9). 提升系统启动速度
    • 嵌入式系统中的启动速度通常是至关重要的,平台设备通常不需要设备枚举和动态加载驱动。通过在设备树或内核配置中静态定义设备,系统可以更快地启动,并且能够高效地加载硬件驱动。
    10). 避免复杂的设备管理
    • 嵌入式系统中的设备通常比较简单,没有复杂的硬件总线和设备发现机制。因此,使用平台设备能够避免在设备管理时引入过多的复杂性,简化了设备的注册、驱动绑定和资源管理过程。
    结论:

    平台设备的这些特点使得它非常适合嵌入式系统的应用。嵌入式系统通常有较为固定的硬件配置,并且对启动速度和系统效率有较高的要求,平台设备提供了一个简洁高效的方式来管理这些硬件设备。通过设备树和平台设备,嵌入式系统能够实现高效、可定制的硬件管理,从而满足各种嵌入式应用的需求。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值