我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何解析Linux驱动中的platform总线

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何解析Linux驱动中的platform总线

如何解析Linux驱动中的platform总线,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

    1、platform 总线简介

    1.1、Linux 驱动的分离和分层思想

    1.1.1、Linux 驱动的分离

            先讲 Linux 驱动的分离,Linux 操作系统支持在各类 CPU 上运行,因为每一种 CPU 对设备的驱动不一样,这样就造成了 Linux 内核中积累了大量代码,并且这些代码关于同一设备的描述大致相同,这就使得内核代码很冗余。以 CPU 通过 I2C 控制 MPU6050 为例:

    如何解析Linux驱动中的platform总线

            从图可以看出每一种平台下都有一套主机驱动和一套设备驱动,因为每个平台的 I2C 控制器不同,所以这个主机驱动得每个平台配一个自己的,但大家所用的 MPU6050 是一样的,所以完全可以就共用一套设备驱动代码。完善后框架如下:

    如何解析Linux驱动中的platform总线

            当然,这只是对于 I2C 下的 MPU6050 这个设备,实际情况下,I2C 下肯定会挂载很多设备,根据这个思路,我们可以得到框架为:

    如何解析Linux驱动中的platform总线

             而在实际开发中,I2C 主机驱动半导体厂家会编写好,设备驱动也由设备厂家编写好,我们只需要提供设备信息即可,如设备接到那个 I2C 接口上,I2C 速度为多少。这样就相当于把设备信息从设备驱动中剥离出来,而设备驱动也会用标准方法去获取设备信息(如从设备树中获取设备信息)。这样就相当于驱动只负责驱动,设备(信息)只负责设备,想办法将两者进行匹配即可,来做这个匹配工作的就是总线,这就构成了 Linux 中的 总线-驱动-设备 模型。结构图如下:

    如何解析Linux驱动中的platform总线

    1.2、platform 平台驱动模型

            上面我们讲做设备驱动的分离,得到 总线-驱动-设备 模型,这个总线就是我平常所说的 I2C、SPI、USB 等总线。但问题是有些设备是不需要通过某一跟总线的,这是就引入了 platform 总线。

            这里需要注意的是,platform 总线是区别于 USB、SPI、I2C 这些总线的虚拟总线。说它虚拟是因为 SoC 与一些外设如 LED、定时器、蜂鸣器是通过内存的寻址空间来进行寻址的,所以 CPU 与这些设备通信压根就不需要总线,那么硬件上也就没有这样一个总线。但内核有对这些设备做统一管理的需求,所以就对这些直接通过内存寻址的设备虚拟了一条 platform 总线,所有直接通过内存寻址的设备都映射到这条虚拟总线上。

            platform 总线的优点:

            1、通过 platform 总线,可以遍历所有挂载在 platform 总线上的设备;

            2、实现设备和驱动的分离,通过 platform 总线,设备和驱动是分开注册的,因为有 probe 函数,可以随时检测与设备匹配的驱动,匹配成功就会把这个驱动向内核注册;

            3、一个驱动可供同类的几个设备使用,这个功能的实现是因为驱动注册过程中有一个遍历设备的操作。      

    2、platform 框架

    2.1、platform 总线

            Linux 内核用 bus_type 结构体来表示总线,我们所用的 I2C、SPI、USB 都是用这个结构体来定义的。该结构体如下:

     struct bus_type {    const char *name;                                      const char *dev_name;     struct device *dev_root;    struct device_attribute *dev_attrs;    const struct attribute_group **bus_groups;             const struct attribute_group **dev_groups;             const struct attribute_group **drv_groups;              int (*match)(struct device *dev, struct device_driver *drv);          int (*uevent)(struct device *dev, struct kobj_uevent_env *env);    int (*probe)(struct device *dev);    int (*remove)(struct device *dev);    void (*shutdown)(struct device *dev);     int (*online)(struct device *dev);    int (*offline)(struct device *dev);    int (*suspend)(struct device *dev, pm_message_t state);    int (*resume)(struct device *dev);    const struct dev_pm_ops *pm;    const struct iommu_ops *iommu_ops;    struct subsys_private *p;    struct lock_class_key lock_key;};

             platform 总线是 bus_type 类型的常量,之所以说它是常量是因为这个变量已经被 Linux 内核赋值好了,其结构体成员对应的函数也已经在内核里面写好。

    定义如下:

     struct bus_type platform_bus_type = {    .name = "platform",    .dev_groups = platform_dev_groups,    .match = platform_match,           .uevent = platform_uevent,    .pm = &platform_dev_pm_ops,};

            platform_bus_type 中的 platform_match 就是我们前面所说的做驱动和设备匹配的函数,该函数定义如下:

     static int platform_match(struct device *dev, struct device_driver *drv){    struct platform_device *pdev = to_platform_device(dev);    struct platform_driver *pdrv = to_platform_driver(drv);         if (pdev->driver_override)        return !strcmp(pdev->driver_override, drv->name);         if (of_driver_match_device(dev, drv))        return 1;         if (acpi_driver_match_device(dev, drv))        return 1;         if (pdrv->id_table)        return platform_match_id(pdrv->id_table, pdev) != NULL;         return (strcmp(pdev->name, drv->name) == 0);}

            这个匹配函数什么时候用,在哪里用,我们不妨先留一个悬念。

    2.2、platform 驱动

    2.2.1、platform 驱动定义

            platform 驱动用结构体 platform_driver 来表示,该结构体内容为:

     struct platform_driver {    int (*probe)(struct platform_device *);        int (*remove)(struct platform_device *);    void (*shutdown)(struct platform_device *);    int (*suspend)(struct platform_device *, pm_message_t state);    int (*resume)(struct platform_device *);    struct device_driver driver;                    const struct platform_device_id *id_table;      bool prevent_deferred_probe;};

             platform_driver 中 const struct platform_device_id *id_table 是 id_table 表,在 platform 总线匹配驱动和设备时 id_table 表匹配法时使用的,这个 id_table 表其实是一个数组,里面的每个元素类型都为 platform_device_id,platform_device_id 是一个结构体,内容如下:

    struct platform_device_id {    char name[PLATFORM_NAME_SIZE];    kernel_ulong_t driver_data;};

            platform_driver 中 driver 是一个驱动基类,相当于驱动具有的最基础的属性,在不同总线下具有的属性则存放在 platform_driver 结构体下。

            驱动基类结构体 device_driver 内容为:

     struct device_driver {    const char *name;                                   struct bus_type *bus;    struct module *owner;    const char *mod_name;     bool suppress_bind_attrs;     const struct of_device_id *of_match_table;          const struct acpi_device_id *acpi_match_table;    int (*probe) (struct device *dev);    int (*remove) (struct device *dev);    void (*shutdown) (struct device *dev);    int (*suspend) (struct device *dev, pm_message_t state);    int (*resume) (struct device *dev);    const struct attribute_group **groups;    const struct dev_pm_ops *pm;    struct driver_private *p;};

             driver 中 of_match_table 也是一个匹配表,这个匹配表是 platform 总线给驱动和设备做匹配时使用设备树匹配时用的,也是一个数组,数组元素都为 of_device_id 类型,该类型结构体如下:

     struct of_device_id {    char name[32];    char type[32];    char compatible[128];       const void *data;};
    2.2.2、platform 驱动注册

            用 platform_driver 结构体定义好 platform 驱动后,用 platform_driver_register 函数向 Linux 内核注册 platform 驱动,函数大致流程如下:

    platform_driver_register (drv)    -> __platform_driver_register        -> drv->driver.probe = platform_drv_probe;               -> driver_registe (&drv->driver)                             -> ......                 -> drv->driver->probe                                        -> platform_drv_probe                        -> drv->probe                    

            上面的分析中从 driver_register (&drv->driver) 到 drv->driver->probe 这一步我们用省略号代替了,现在来做一下分析:

    driver_register(&drv->driver)    -> bus_add_driver                                     -> driver_attach             -> bus_for_each_dev                                    -> __driver_attach                                    -> driver_match_device                                -> 调用bus下的match匹配函数                    -> driver_probe_device                                -> really_probe                             -> drv->probe         

            根据 driver_register 函数流程,我们就知道了总线的 match 匹配函数会在这里遍历使用,这就回答了我们之前留下的一个问题:总线 match 函数在哪里用,一旦匹配成功就会进入到驱动的 probe 函数。 

            根据 platform_driver_register 函数流程,我们可以得出一个结论:向 Linux 内核注册 platform driver 过程里面会有一个遍历驱动和设备匹配的过程,匹配成功后最终会执行 platform driver 的 probe 函数,过程中 的驱动基类 driver 的 probe 函数和 platform_drv_probe 函数都是达到这个目的的中转函数而已。

            值得注意的是,最终会执行的 platform driver 的 probe 函数是由我们来写的,所以主动权又回到我们手里。

    2.3、platform 设备

    2.3.1、platform 设备定义

            如果我们用的 Linux 版本支持设备树,那就在设备树中去描述设备,如果不支持设备树,就要定义好 platform 设备。这里我们需要考虑的一个点是,总线下的匹配函数 match 在做匹配时是先设备树匹配,然后 id_table 表匹配,然后才是 name 字段匹配。支持设备树时,直接在设备树节点里面改设备信息,内核启动时会自动遍历设备树节点,匹配成功就会自动生成一个 platform_device,给下一步来使用。不是设备树的话,这个 platform_device 就是由开发者来写。

            这里我们先不用设备树,自己来定义 platform 设备。platform 设备用 platform_device 结构体来表示,该结构体定义如下:

     struct platform_device {    const char *name;                       int id;     bool id_auto;    struct device dev;    u32 num_resources;     struct resource *resource;    const struct platform_device_id *id_entry;    char *driver_override;         struct mfd_cell *mfd_cell;        struct pdev_archdata archdata;};

    2.4、platform 匹配过程

            platform 总线对驱动和设备的匹配过程其实上面零零碎碎也已经讲的差不多了,现在我们汇总起来在过一遍。

            前面也说过,总线下的驱动和设备的匹配是通过总线下的 match 函数来实现的,不同的总线对应的 match 函数肯定不一样,这个我们不用管,内核都会写好。我们所用的 platform 总线对应的 match 函数是 platform_match 函数,分析一下这个函数:

    platform_match    -> of_driver_match_device              -> acpi_driver_match_device            -> platform_match_id                   -> strcmp(pdev->name, drv->name)   

             通过对上面匹配函数的一个简单分析,我们知道匹配函数做匹配的顺序是先匹配设备树,然后匹配 id_table 表,然后才是暴力匹配 name 字段。对于支持设备树的 Linux 版本,我们一上来做设备树匹配就完事。不支持设备树时,我们就得定义 platform 设备,再用 id_tabale 表或 name 匹配,一般情况下都是选用 name 匹配。

            现在我们来具体看一下设备树条件下的匹配过程:

    of_driver_match_device         -> of_match_device (drv->of_match_table, dev)            -> of_match_node              -> __of_match_node                -> __of_device_is_compatible                    -> __of_find_property(device, "compatible", NULL)   

            看上面的分析我们就知道了这个匹配过程最终是驱动基类的 of_match_table 里的 compatible 去设备树节点里面的 compatible 属性作比较。这个就是把设备树与 platform 总线串起来的一个机理,从而实现了在设备树对应节点里面写设备信息,驱动另外单独写的目的,也就是我们前面讲的驱动分离。

     3、总结

            在具体的开发过程中我们并不需要真的去写一个 platform 总线模型,内核中都已经给我们定义好了。我们对 platform 总线模型的分析主要是搞清楚如何将驱动和设备匹配的,即当我们插入设备是如何找到对应驱动或插入驱动如何找到对应设备的,并最终调用 probe 函数。其实不管是先有驱动后有设备、还是先有设备后有驱动,最终匹配成功后第一件事都是执行驱动的 probe 函数,所以我们尽可放心的忽略中间曲折的情感纠葛,直接把注意力放在最终的 probe 函数。

    看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网行业资讯频道,感谢您对编程网的支持。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    如何解析Linux驱动中的platform总线

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    如何解析Linux驱动中的platform总线

    如何解析Linux驱动中的platform总线,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1、platform 总线简介1.1、Linux 驱动的分离和分层思
    2023-06-22

    Linux驱动之platform总线详解

    目录1、platform 总线简介1.1、linux 驱动的分离和分层思想1.1.1、Linux 驱动的分离1.2、platform 平台驱动模型2、platform 框架2.1、platform 总线2.2、platform 驱动2.2.
    2022-06-04

    如何解析Linux 驱动架构

    今天就跟大家聊聊有关如何解析Linux 驱动架构,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。首先,需要熟悉操作系统的设计与实现,推荐大家看 MINIX作者的那部书,同时把MINIX
    2023-06-28

    解析如何在android中增加gsensor驱动(MMA7660)

    系统原来用的是BOSCH_BMA222的gsensor, 现在要求换成使用MMA7660,我们来看一下怎样增加驱动和调试过程。 1. 修改Makefie首先,修改放置驱动的目录里的Makefile(kernel/driver/misc),添
    2022-06-06

    如何理解Linux驱动中内核互斥锁

    如何理解Linux驱动中内核互斥锁,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 互斥体概述信号量是在并行处理环境中对多个处理器访问某个公共资源进行保护的机制,mutex用于互
    2023-06-15

    电脑中的无线网卡驱动如何安装

    小编给大家分享一下电脑中的无线网卡驱动如何安装,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!1.点击桌面左下方“主菜单”,点击“控制面板”。2.进入控制面板后点击“管理工具”。3.点击“计算机管理”。4.点击“设备管理”,
    2023-06-28

    如何理解Linux内核驱动的编码风格

    本篇文章给大家分享的是有关如何理解Linux内核驱动的编码风格,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代
    2023-06-16

    Linux设备驱动指的定时与延时如何理解

    本篇文章为大家展示了Linux设备驱动指的定时与延时如何理解,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Linux通过系统硬件定时器以规律的间隔(由HZ度量)产生定时器中断,每次中断使得一个内核计
    2023-06-16

    教你如何深度解析Windows7的设备驱动管理原理

    1、Windows 7系统的设备驱动文件解读 在Windows7系统中包含了一个覆盖范围很广的身边驱动程序库。在该操作系统的基本安装中,这些驱动程序都会保www.cppcns.com存在驱动程序存储区中,它们位于%SystemRoot%\S
    2023-05-25

    如何解决新装Linux系统没有网卡驱动的问题

    本篇内容主要讲解“如何解决新装Linux系统没有网卡驱动的问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何解决新装Linux系统没有网卡驱动的问题”吧!刚安装的linux系统没有网卡驱动,
    2023-06-13

    windows无法读取驱动器f:\中的光盘如何解决

    以下是一些可能的解决方法:1. 检查驱动器连接:确保光盘驱动器正确连接到计算机上,并且电缆没有松动。2. 检查驱动器状态:打开设备管理器,检查光盘驱动器是否显示在“DVD/CD-ROM 驱动器”下,并且没有任何警告或错误提示。如果有错误提示
    2023-09-28

    如何解析混乱的Linux内核实时线程优先级

    本篇文章给大家分享的是有关如何解析混乱的Linux内核实时线程优先级,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。背景Linux会把进程分为普通进程和实时进程,普通进程采用CF
    2023-06-16

    如何解析Java线程池在使用中的问题

    本篇文章为大家展示了如何解析Java线程池在使用中的问题,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java线程池需要我们不断的学习,其实我们在使用的时候还是有不少问题需要我们解决。我们实现了一个
    2023-06-17

    如何解析Linux系统架构中的内核

    如何解析Linux系统架构中的内核,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。概述Linux系统一般有4个主要部分组成,内核、shell、文件系统和应用程序。内核、shell
    2023-06-16

    如何解析Kubernetes中的StorageClass和动态卷供给

    如何解析Kubernetes中的StorageClass和动态卷供给,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。存储是容器运行环境的重要一环,Kubernetes 提供了一些
    2023-06-05

    如何解决笔记本电脑无线wifi总是自动断开连接的问题

    这篇文章主要介绍如何解决笔记本电脑无线wifi总是自动断开连接的问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、右键点击计算机,然后选择属性。二、在系统属性界面,点击“设备管理器”。三、在弹出的设备管理器中,点
    2023-06-28

    解析Android中如何做到Service被关闭后又自动启动的实现方法

    首先要说的是,用户可能把这种做法视为流氓软件。大部分时候,程序员也不想把软件做成流氓软件,没办法,领导说了算。 我们在使用某些Android应用的时候,可能会发现安装了某应用以后,会有一些服务也会随之运行。而且,这些服务每次都会随着手机开机
    2022-06-06

    如何解析 Linux 中“一切都是文件”概念和相应的文件类型

    今天就跟大家聊聊有关如何解析 Linux 中“一切都是文件”概念和相应的文件类型,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在 Unix 和它衍生的比如 Linux 系统中,一切
    2023-06-16

    编程热搜

    目录