Linux驱动编程

Linux驱动编程 cxcc 2023-05-16 14:22:49 637

Linux驱动编程

一、Linux驱动模型

​ Linux中的驱动模型遵循一个基本的逻辑:设备和驱动分离。其中设备是一个结构体,用于描述设备的硬件信息,例如LED的设备应当描述LED的引脚。驱动是另一个结构体,用于描述操作,例如LED的驱动应该包含LED的开或关的控制。只有当两个结构体绑定在一起时。驱动就会根据设备描述的信息操作设备。例如有两个LED灯需要控制,那么就应该有两个LED设备和一个LED驱动。当LED1绑定驱动时就会控制LED1的引脚,当LED2绑定驱动时就会控制LED2的引脚。

​ 硬件设备和驱动的描述方式可能不同,但是在Linux的驱动模型中最终都会转化为设备结构体和驱动结构体。并通过匹配机制将设备和驱动绑定在一起。

​ 在Linux设备模型出现后,Linux中只有一种驱动模型(设备-总线-驱动模型)。初学者可能以为设备树等和基本的总线式驱动模型不同,是不同的模型。其实不然,后面进行详细介绍。

1. 设备-总线-驱动模型

​ 该模型是在Linux系统中有一个结构体,结构体两端分别挂设备和驱动。当有新挂载的驱动时将新的驱动与已经挂载的设备相比较,如果合适则将驱动和设备绑定。这个在设备和驱动之间的结构体就是总线。

​ 这个总线和实际硬件中总线没有什么关系。只是将有公共操作的驱动和设备放在同一个总线上,由总线实现这一部分公共操作,就不用在每个驱动中都实现这一部分公共操作。因此在Linux系统中的i2c总线只是总线模型在i2c接口上的实现。在i2c总线中会实现i2c的基本操作,例如i2c读写。挂载在i2c总线上的驱动就不需要再实现i2c的操作。与实际硬件无关的总线:platform总线,该总线与任何硬件设备无关,完全是虚拟的。

​ 在这个模型中设备和驱动在注册到系统之前都需要描述对应的总线。设备和驱动都是结构体,填充数据后通过注册方法挂载到总线上。

​ 设备和驱动是否合适需要通过总线驱动提供的match函数进行比对。因此总线可以决定总线上的设备和驱动的匹配方式。

2. 设备树

​ 设备树是一个文件,文件中描述了所有的硬件信息,包括处理器本身的信息和开发板的硬件信息。因此设备树在不同的开发板、不同的芯片上都是不同的。下面是uart的描述,关于设备树的细节参考设备树语法。设备树中包括了硬件的基本信息,包括设备寄存器的起始地址,使用的中断等。

uart0: uart@11040000 {
    compatible = "arm,pl011", "arm,primecell";
    reg = <0x11040000 0x1000>;
    interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clock SS928V100_UART0_CLK>;
    clock-names = "apb_pclk";
    /* dmas = <&edmacv310_0 20 20>, <&edmacv310_0 21 21>; */
    /* dma-names = "rx","tx"; */
    status = "disabled";
};  

uart1: uart@11041000 {
    compatible = "arm,pl011", "arm,primecell";
    reg = <0x11041000 0x1000>;
    interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clock SS928V100_UART1_CLK>;
    clock-names = "apb_pclk";
    /* dmas = <&edmacv310_0 22 22>, <&edmacv310_0 23 23>; */
    /* dma-names = "rx","tx"; */
    status = "disabled";
};

​ 设备树并不是区别与总线模型的另一个模型,而是总线模型的补充。在原来的总线模型中只能通过C源文件中的设备结构体描述设备。这种方式导致每次修改设备信息都需要重新编译。设备树出现后通过设备树描述硬件设备,在系统启动时分析设备树并创建设备结构体。此时结构体中并没有设备的全部信息,但是of_node属性已经被填充,of_node代表当前设备对应的设备树节点。随后系统根据设备树节点的compatible属性与驱动的of_match_table中的compatible属性相匹配,匹配成功则将两者绑定并调用驱动的probe函数,将匹配到的设备传递给probe函数。probe函数通过of_node节点分析当前设备的其他属性并填充设备结构体,以保证后续的操作。

3. id_table

​ id_table模型通过id_table表进行驱动和设备的匹配,一般通过匹配id_table中的name属性确定是否匹配,id_table允许一个data属性,当前驱动可以同时驱动不同类型的设备时data属性可以用来描述不同设备间的不同。

​ 任何设备和驱动都有其所在的总线,当设备或驱动挂载成功后调用对应总线的match函数进行匹配,而设备树匹配和id_table匹配则是在match函数中实现的。因此具体的匹配顺序需要根据总线的match函数进行分析。

二、具体驱动结构简介

​ Linux驱动模型的核心结构是device结构体和device_driver结构体。device代表着系统中的设备,device_driver代表着系统中的驱动。其它设备或驱动都是由这两个结构体继承(C语言的方式实现面向对象)而来。

​ 以I2C驱动为例:

struct i2c_driver {
    /* ... */
    struct device_driver driver;//i2c驱动的结构体中包含driver结构体
    /* ... */
};

​ I2C设备的匹配:

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
    struct i2c_client   *client = i2c_verify_client(dev);
    struct i2c_driver   *driver;

    /* 通过设备树的compatible 属性匹配*/
    if (i2c_of_match_device(drv->of_match_table, client))
        return 1;

    /* ACPI 方式匹配 */
    if (acpi_driver_match_device(dev, drv))
        return 1;

    driver = to_i2c_driver(drv);

    /* id_table匹配 */
    if (i2c_match_id(driver->id_table, client))
        return 1;

    return 0;
}

​ 如果以上三种方式都不能匹配到,则匹配失败。首先使用的设备树进行匹配,因此在i2c的设备驱动中,设备树中出现节点的compatible与驱动的compatible属性对应即可匹配成功。也可以使用id_table进行匹配。

附录一:Linux驱动的发展历程

(来自网络查询,未经证实)

在2.5版本内引入include/linux/device.h,其中包括device、device_driver结构体。

在2.6.0版本引入bus_type结构体,同时引入cdev

在2.6.14版本引入设备树

字符设备文件、块设备文件是Linux中描述设备的文件

以下文字是对ChatGPT问答的总结

Linux中最早期使用/dev文件夹管理设备,对应的文件系统是devfs。devfs对每一个设备提供一个设备文件,应用层可以通过读写等方式控制外部设备。后续发展的过程中,Linux开始构建驱动模型,并通过/sys(sysfs文件系统)下的文件描述设备。/sys和/dev的区别是,一个设备在/dev下表现为一个设备文件,在/sys表现为一个目录,目录中包括设备的属性状态等被列为单独的文件。

下面是块设备文件sda在/dev中对应的设备文件

brw-rw---- 1 root disk 8, 0 5月   5 08:59 sda

下面是块设备文件sda在/sys中对应的文件夹

-r--r--r-- 1 root root 4096 5月   5 13:41 alignment_offset
lrwxrwxrwx 1 root root    0 5月   5 13:41 bdi -> ../../../../../../../../../virtual/bdi/8:0
-r--r--r-- 1 root root 4096 5月   5 13:41 capability
-r--r--r-- 1 root root 4096 5月   5 08:59 dev
lrwxrwxrwx 1 root root    0 5月   5 09:01 device -> ../../../2:0:0:0
-r--r--r-- 1 root root 4096 5月   5 13:41 discard_alignment
-r--r--r-- 1 root root 4096 5月   5 13:41 events
-r--r--r-- 1 root root 4096 5月   5 13:41 events_async
-rw-r--r-- 1 root root 4096 5月   5 13:41 events_poll_msecs
-r--r--r-- 1 root root 4096 5月   5 13:41 ext_range
-r--r--r-- 1 root root 4096 5月   5 13:41 hidden
drwxr-xr-x 2 root root    0 5月   5 13:41 holders
-r--r--r-- 1 root root 4096 5月   5 13:41 inflight
drwxr-xr-x 2 root root    0 5月   5 13:41 integrity
drwxr-xr-x 3 root root    0 5月   5 13:41 mq
drwxr-xr-x 2 root root    0 5月   5 13:41 power
drwxr-xr-x 3 root root    0 5月   5 08:59 queue
-r--r--r-- 1 root root 4096 5月   5 13:41 range
-r--r--r-- 1 root root 4096 5月   5 08:59 removable
-r--r--r-- 1 root root 4096 5月   5 08:59 ro
-r--r--r-- 1 root root 4096 5月   5 08:59 size
drwxr-xr-x 2 root root    0 5月   5 13:41 slaves
-r--r--r-- 1 root root 4096 5月   5 13:41 stat
lrwxrwxrwx 1 root root    0 5月   5 08:59 subsystem -> ../../../../../../../../../../class/block
drwxr-xr-x 2 root root    0 5月   5 13:41 trace
-rw-r--r-- 1 root root 4096 5月   5 08:59 uevent

参考文献

  1. 【linux】驱动-6-总线-设备-驱动
  2. 关于platform中的id_table
  3. Linux内核驱动:cdev、misc以及device三者之间的联系和区别
  4. Linux设备树解析
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
cxcc
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
cxcc
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区