总线设备驱动模型----驱动篇

总线设备驱动模型---platform篇 2012-09-02 10:57:50 分类: LINUX     linux从2.6起就加入了一套新的驱动管理和注册的机制platform平台总线,是一条虚拟的总线,设备用platform_device表示,驱 动用platform_driver进行注册。于传统的bus/device/driver机制相比,platform由内核进行统一管理,在驱动中使用 资源,提高了代码的安全性和可移植性。 阅读详情

 源自 http://blog.chinaunix.net/uid-27664726-id-3334923.html

 如果你了解了前面总线、设备模型,分析总线设备驱动模型的driver相对来说会轻松很多。开始也是看看其数据结构。

点击(此处)折叠或打开

  1. struct device_driver {
  2.     const char        *name;                 //驱动的名字
  3.     struct bus_type        *bus;             //驱动呈现属于的总线类型

  4.     struct module        *owner;
  5.     const char        *mod_name;    /* used for built-in modules */

  6.     bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */

  7.     const struct of_device_id    *of_match_table;

  8.     int (*probe) (struct device *dev);     //驱动挂载的时候调用
  9.     int (*remove) (struct device *dev);    //卸载的时候调用
  10.     void (*shutdown) (struct device *dev);
  11.     int (*suspend) (struct device *dev, pm_message_t state);
  12.     int (*resume) (struct device *dev);
  13.     const struct attribute_group **groups;

  14.     const struct dev_pm_ops *pm;

  15.     struct driver_private *p;
  16. };
与device类型相似,其中有一个指向driver_private的指针p,一些与其他的组件相关的联系都被移到这个结构变量中。

点击(此处)折叠或打开

  1. struct driver_private {
  2.     struct kobject kobj;      //在sysfs中代表目录本身
  3.     struct klist klist_devices;//驱动链表
  4.     struct klist_node knode_bus; //挂载在总线的驱动链表的节点
  5.     struct module_kobject *mkobj;//driver与相关的module之间的联系
  6.     struct device_driver *driver;
  7. };
  8. #define to_driver(obj) container_of(obj, struct driver_private, kobj)
由上面可以看出driver指针最后也有driver_private回到了device_driver之中,下面也来看看驱动的属性文件的表示方法

点击(此处)折叠或打开

  1. struct driver_attribute {
  2.     struct attribute attr;
  3.     ssize_t (*show)(struct device_driver *driver, char *buf);
  4.     ssize_t (*store)(struct device_driver *driver, const char *buf,
  5.              size_t count);
  6. };

  7. #define DRIVER_ATTR(_name, _mode, _show, _store)    \
  8. struct driver_attribute driver_attr_##_name =        \
  9.     __ATTR(_name, _mode, _show, _store)
上面只是有两个读写函数,看完了关于驱动的一些重要的数据结构,那么开始重要的,如何向内核注册一个drv呢?我们使用driver_register

点击(此处)折叠或打开

  1. int driver_register(struct device_driver *drv)
  2. {
  3.     int ret;
  4.     struct device_driver *other;

  5.     BUG_ON(!drv->bus->p);

  6.     if ((drv->bus->probe && drv->probe) ||
  7.      (drv->bus->remove && drv->remove) ||
  8.      (drv->bus->shutdown && drv->shutdown))
  9.         printk(KERN_WARNING "Driver '%s' needs updating - please use "
  10.             "bus_type methods\n", drv->name);

  11.     other = driver_find(drv->name, drv->bus);
  12.     if (other) {
  13.         put_driver(other);
  14.         printk(KERN_ERR "Error: Driver '%s' is already registered, "
  15.             "aborting...\n", drv->name);
  16.         return -EBUSY;
  17.     }

  18.     ret = bus_add_driver(drv);
  19.     if (ret)
  20.         return ret;
  21.     ret = driver_add_groups(drv, drv->groups);
  22.     if (ret)
  23.         bus_remove_driver(drv);
  24.     return ret;
  25. }
从函数可以看出,首先drv->bus一定要预先设置。在使用driver_find从bus的驱动链表中特定名字的driver,那么就进入这个函数的重点的东西bus_add_driver,几乎注册所有的工作都是由它来完成。

点击(此处)折叠或打开

  1. int bus_add_driver(struct device_driver *drv)
  2. {
  3.     struct bus_type *bus;
  4.     struct driver_private *priv;
  5.     int error = 0;

  6.     bus = bus_get(drv->bus);//增加对bus的引用
  7.     if (!bus)
  8.         return -EINVAL;

  9.     pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

  10.     priv = kzalloc(sizeof(*priv), GFP_KERNEL);//分配初始化一个drv->p,也就是上面的driver_private结构
  11.     if (!priv) {
  12.         error = -ENOMEM;
  13.         goto out_put_bus;
  14.     }
  15.     klist_init(&priv->klist_devices, NULL, NULL);
  16.     priv->driver = drv;
  17.     drv->p = priv;
  18.     priv->kobj.kset = bus->p->drivers_kset;
  19.     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
  20.                  "%s", drv->name);//将drv加入sysfs
  21.     if (error)
  22.         goto out_unregister;

  23.     if (drv->bus->p->drivers_autoprobe) {
  24.         error = driver_attach(drv);//如果总线可以自动的probe,就会调用匹配函数
  25.         if (error)
  26.             goto out_unregister;
  27.     }
  28.     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);//将drv挂入到总线的链表中
  29.     module_add_driver(drv->owner, drv);//创建driver相关的模块

  30.     error = driver_create_file(drv, &driver_attr_uevent);//在drv目录下创建event属性文件
  31.     if (error) {
  32.         printk(KERN_ERR "%s: uevent attr (%s) failed\n",
  33.             __func__, drv->name);
  34.     }
  35.     error = driver_add_attrs(bus, drv);//添加属性
  36.     if (error) {
  37.         /* How the hell do we get out of this pickle? Give up */
  38.         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
  39.             __func__, drv->name);
  40.     }

  41.     if (!drv->suppress_bind_attrs) {
  42.         error = add_bind_files(drv);
  43.         if (error) {
  44.             /* Ditto */
  45.             printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
  46.                 __func__, drv->name);
  47.         }
  48.     }

  49.     kobject_uevent(&priv->kobj, KOBJ_ADD);//向用户空间发布kobj_add消息
  50.     return 0;

  51. out_unregister:
  52.     kobject_put(&priv->kobj);
  53.     kfree(drv->p);
  54.     drv->p = NULL;
  55. out_put_bus:
  56.     bus_put(bus);
  57.     return error;
  58. }
其实上面的处理过程相对于设备来说,会简单很多,下面主要对当驱动挂接的时候,怎么去匹配进行分析。

点击(此处)折叠或打开

  1. int driver_attach(struct device_driver *drv)
  2. {
  3.     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
  4. }

点击(此处)折叠或打开

  1. static int __driver_attach(struct device *dev, void *data)
  2. {
  3.     struct device_driver *drv = data;

  4.     /*
  5.      * Lock device and try to bind to it. We drop the error
  6.      * here and always return 0, because we need to keep trying
  7.      * to bind to devices and some drivers will return an error
  8.      * simply if it didn't support the device.
  9.      *
  10.      * driver_probe_device() will spit a warning if there
  11.      * is an error.
  12.      */

  13.     if (!driver_match_device(drv, dev))
  14.         return 0;

  15.     if (dev->parent)    /* Needed for USB */
  16.         device_lock(dev->parent);
  17.     device_lock(dev);
  18.     if (!dev->driver)
  19.         driver_probe_device(drv, dev);
  20.     device_unlock(dev);
  21.     if (dev->parent)
  22.         device_unlock(dev->parent);

  23.     return 0;

点击(此处)折叠或打开

  1. static inline int driver_match_device(struct device_driver *drv,
  2.                  struct device *dev)
  3. {
  4.     return drv->bus->match ? drv->bus->match(dev, drv) : 1;
  5. }
最终也是调用总线的match函数来完成设备与驱动的匹配的过程。
以上分析了总线、设备、驱动三种类型,主要是在注册上,其主要是在sysfs中创建目录和属性文件。在设备或者驱动注册到总线上,总线是如何为其找到对应的驱动的过程,下面一个图能很好的说明这一过程。
由图可以清楚的看出,bus的作用是向内核注册一条总线,并将drv一一加入到总线的drv链表,dev一一加入到总线的dev链表。当有设备或驱动注册的时候,在驱动或者设备链表一一取出,调用总线的match函数来完成匹配,匹配成功后调用总线的probe函数。
回顾下driver_register的作用,首先会将drv放入到bus得drv链表,从bus的dev链表取出每一个dev,用总线的match函数来判断能否支持drv
device_register的作用和driver一样,将dev放入到bus得dev链表,从bus的drv链表取出每一个drv,用总线的match函数来判断能否支持dev。

点击(此处)折叠或打开

  1. extern struct bus_type my_bus_type;

  2. static int my_probe(struct device *dev)
  3. {
  4.     printk("Driver found device which my driver can handle!\n");
  5.     return 0;
  6. }

  7. static int my_remove(struct device *dev)
  8. {
  9.     printk("Driver found device unpluged!\n");
  10.     return 0;
  11. }

  12. struct device_driver my_driver = {
  13.     .name = "my_dev",
  14.     .bus = &my_bus_type,
  15.     .probe = my_probe,
  16.         .remove    = my_remove,
  17. };

  18. /*
  19.  * Export a simple attribute.
  20.  */
  21. static ssize_t mydriver_show(struct device_driver *driver, char *buf)
  22. {
  23.     return sprintf(buf, "%s\n", "This is my driver!");
  24. }

  25. static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);

  26. static int __init my_driver_init(void)
  27. {
  28.     int ret = 0;
  29.         
  30.         /*注册驱动*/
  31.     driver_register(&my_driver);
  32.         
  33.     /*创建属性文件*/
  34.     driver_create_file(&my_driver, &driver_attr_drv);
  35.     
  36.     return ret;    

  37. }

  38. static void my_driver_exit(void)
  39. {
  40.     driver_unregister(&my_driver);
  41. }

  42. module_init(my_driver_init);
  43. module_exit(my_driver_exit);
RK3568平台开发系列讲解(platform虚拟总线驱动篇)总线设备驱动模型的引入 使用哪个引脚,怎么操作引脚,都写死在代码中。最简单,不考虑扩展性,可以快速实现功能。修改引脚时,需要重新编译。,将“资源”与“驱动”分离开来。代码稍微复杂,但是易于扩展。冗余代码太多,修改引脚时设备端的代码需要重新编译。通过配置文件──设备树来定义“资源”。代码稍微复杂,但是易于扩展。无冗余代码,修改引脚时只需要修改。文件,把它传 给内核。无需重新编译内核/驱动。沉淀、分享、成长,让自己和他人都能有所收获!基本不用改,但是需要修改。二、总线设备驱动模型。 阅读详情

相关推荐

25年PINN创新点大盘点!

在科研论文的激烈角逐中,想轻松产出高含金量成果?物理信息神经网络(PINN)堪称“宝藏研究方向”,是冲击高分区论文的绝佳赛道!对于渴望发表优质论文的科研伙伴,这三大研究路径值得重点关注。首先是自适应PINN,在PINN训练过程中,物理方程与实测数据间的矛盾常常导致权重调节困难,而恰好直击这一痛点,是极具价值的研究方向。其次,同样前景广阔,传统多物理场同时训练效果欠佳,如今分阶段训练方法脱颖而出,成效显著且竞争较小。最后,探索及多任务学习等技术的融合,能实现优势叠加,碰撞出创新火花。

Malaai的博客 1971

linux驱动篇之 driver_register 过程分析(二)bus_add_driver

linux驱动篇之 driver_register 过程分析(二)bus_add_driver

wufan88的博客 677

ArcGIS-裁剪遥感影像及dem图像

6、选择【工具箱】-【数据管理工具】-【栅格】-【裁剪】。在【输入栅格】里选择要裁剪的dem,在【输出范围】里选择刚创建的裁剪范围。选择一个输出路径,其他参数保存默认。2、起一个名称,要素类型选择【面】。点击【编辑】选择与要裁剪的dem一致的地理坐标系。1、创建需要裁剪区域的面层shp,右击选择【新建】-【shapefile】3、点击编辑器,选择开始编辑。4、选择【裁剪范围】,点击确定。5、画出想要裁剪的范围并保存。

siwenaiyou的博客 1万+

linux设备驱动模型一上层容器之driver

备驱动程序 使计算机系统可以与设备进行通信的一个软件组。在大多数情况下,驱动程序也会对硬件进行操作以便将数据传送给设备。有些设备,尤其是 PC 兼容机上的一些视频示配器,在系统中没有安装正确的设备驱动程序时,这些设备将无法正常工作. 首先还是看一下其结构: struct device_driver { const char *name; //名字 struct bus_type *bu

new_abc的专栏 3274

使用Dify打造视频生成工作流:从提示词到视频的完整指南

Dify作为开源LLM应用开发平台,通过可视化工作流编排实现从文本到视频的端到端生成,将创意周期从天级缩短至分钟级。核心流程包括提示词工程、视频API调用、存储分发和结果反馈。

牛奶夹心巧克力 3435

Autosar中CAN信号传输的模块化解析与实战应用

本文深入解析了AUTOSAR架构下CAN信号传输的模块化流程,详细阐述了从应用层软件组件(SWC)到COM模块打包、PduR路由、CanIf硬件抽象直至Can Driver驱动的完整“流水线”。文章通过实战案例,重点说明了模块化设计如何实现解耦与可移植性,并提供了关键模块配置要点与调试技巧,旨在帮助开发者构建高可靠、实时的车载通信系统。

g9h0i1的博客 902

设备驱动模型:总线-设备-驱动

总线是连接处理器和设备之间的桥梁代表着同类设备需要共同遵循的工作时序。总线驱动:负责实现总线行为,管理两个链表。name:指定总线的名称,当新注册一种总线类型时,会在 /sys/bus 目录创建一个新的目录,目录名就是该参数的值;bus_groups、dev_groups、drv_groups:分别表示 总线、设备、驱动的属性。通常会在对应的 /sys 目录下在以文件的形式存在,对于驱动而言,在目录 /sys/bus//driver/ 存放了驱动的默认属性;

u013921164的博客 2739

lidar360 V8.0 & lidar360MLS V8.0雷达点云数据处理软件

机载林业 — 基于机载激光雷达点云数据提取一系列森林结构参数(如:高度分位数、叶面积指数、郁闭度等),分割单木并提取单木参数(包括树的位置、树高、胸径、枝下高、冠幅等属性),利用软件的多种回归分析功能可以结合地面调查数据反演森林生物量、蓄积量等功能参数。还可以生成等高线、山体阴影、坡度、坡向、粗糙度等多种产品。分类 — LiDAR360提供多种分类功能,包括地面点分类、模型关键点分类、选择区域地面点分类、机器学习模型分类(可高效地分离建筑、植被、路灯等通用类别)、深度学习模型分类、自定义深度学习分类等。

2403_83796253的博客 5155

linux驱动开发篇(三)—— 总线设备驱动模型

linux系列目录: linux基础篇(一)——GCC和Makefile编译过程 linux基础篇(二)——静态和动态链接 ARM裸机篇(一)——i.MX6ULL介绍 ARM裸机篇(二)——i.MX6ULL启动过程 ARM裸机篇(三)——i.MX6ULL第一个裸机程序 ARM裸机篇(四)——重定位和地址无关码 ARM裸机篇(五)——异常和中断 linux系统移植篇(一)—— linux系统组成 linux系统移植篇(二)—— Uboot使用介绍 linux系统移植篇(三)—— Linux 内核使用介绍 li

sinat_31039061的博客 4163

[毕设项目-大模型微调]现代文翻译文言文【基于LLaMA3.1-8B微调】

教你基于LLaMA3.1-8B微调如何做到现代文翻译文言文

逐梦苍穹的博客 2296

代谢组数据分析(一):生成代谢组数据SummarizedExperiment对象

本文介绍了基于Zeybel 2022年发布的多组学数据集的分析脚本,该数据集包含微生物组、宿主人体学指标、临床学指标、血浆代谢组和免疫因子等多维度数据,涵盖56位患者的横截面数据和22位患者的纵向时间序列数据。脚本旨在生成适用于下游分析的数据对象,主要包括phyloseq和SummarizedExperiment两类。phyloseq对象用于整合微生物群落数据,支持多数据整合、可视化、丰富分析功能和便捷的数据处理;SummarizedExperiment对象则广泛应用于基因组学和转录组学研究,便于数据整合、

专注生信领域 2991

总线设备驱动模型——总线篇

总线struct bus_type     总线是处理器与设备之间的通道,在设备模型中,所有的设备都是通过总线相连的。在设备模型中,总线由bus_type表示。 struct bus_type {     const char        *name;                   //总线类型名称     struct bus_attribute    *bus_

ivy_reny的专栏 1151

零基础学simulink仿真建模--基于Simulink进行近端策略优化(PPO)路径规划的仿真建模

特点高效性与稳定性:通过引入剪裁机制,在更新策略时限制步长,从而提高了训练过程的稳定性和效率。适用于多种动作空间:可以处理连续和离散的动作空间问题。无需模型:不需要预先知道环境的确切模型,适合复杂或未知环境。挑战收敛速度与稳定性:确保算法能够在合理的时间内找到近似最优解,并保持训练过程的稳定性。探索与利用平衡:在探索新路径和利用已知信息之间取得平衡。计算资源:对于大规模状态空间和动作空间,计算资源需求较高。首先明确要模拟的任务内容。目标(例如到达指定地点、避开障碍物等)。

amy_mhd的博客 250

总线设备驱动模型——platform篇

Linux从2.6起加入了一套新的驱动管理和注册的机制。platform平台总线是一条虚拟的总线,设备用platform_device表示,驱动用platform_driver进行注册。与传统的bus/device/driver机制相比,platform由内核进行统一管理,在驱动中使用资源,提高了代码的安全性和可移植性。     下面来看看内核注册platform总线的过程。 platform

ivy_reny的专栏 664

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

20150226 IMX257 总线设备驱动模型编程之驱动篇

20150226 IMX257 总线设备驱动模型编程之驱动篇 2015-02-26 11:42 李海沿 前面我们已经实现了 总线和设备 的驱动程序,接下来我们的任务就是 实现 驱动 了 地址:http://www.cnblogs.com/lihaiyan/p/4301079.html http://www.cnblogs.com/lihaiyan/p/4301072.html 在实现驱...

|~~~热爱生活、努力学习的小伙汁~~~| 655

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

总线设备驱动模型——设备篇

strcut device_type struct device_type {     const char *name;     const struct attribute_group **groups;     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);     char *(*

ivy_reny的专栏 549

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

总线设备驱动模型——驱动篇

驱动struct device_driver struct device_driver {     const char        *name;                 //驱动的名字     struct bus_type        *bus;             //驱动呈现属于的总线类型       struct module       

ivy_reny的专栏 667

总线设备驱动模型篇一

概述 设备驱动模型最初是为了解决设备的电源管理而产生的,但是最后发展 起来之后,作用就越来越大了,特别适合设备管理。对于linux设备驱动工程师来说,掌握设备驱动模型非常重要。 linux的设备驱动模型的底层机制主要包括:kobject,kset等几个结构。这几个结构定义在include/linux/kobject.h中 sysfs文件系统 sysfs文件系统是基于ramfs的一种文件系统,它

code_fei的专栏 461

20150226 IMX257 总线设备驱动模型编程之设备篇

20150226 IMX257 总线设备驱动模型编程之设备篇 2015-02-26 李海沿   前面我们呢实现了总线-设备-驱动模型中的总线,自然,我们的目标就是在我们建立的总线下面创建一个设备。  http://www.cnblogs.com/lihaiyan/p/4301072.html  一、程序分析 1. 包含总线 既然我们的设备在总线上,自然我们既要包含总线了 如...

|~~~热爱生活、努力学习的小伙汁~~~| 645

20150225 IMX257 总线设备驱动模型编程之总线篇

20150225 IMX257 总线设备驱动模型编程之总线篇 2015-02-25 19:40 李海沿 从现在开始,我们开始来实现 总线-设备-驱动模型中的总线。、 我们这个程序的目标是在 sysfs文件系统的/sys/bus/ 目录下面建立一个文件夹。 一、总线介绍 1. 总线数据结构bus_type struct bus_type 结构体的定义如下: struct ...

|~~~热爱生活、努力学习的小伙汁~~~| 609
上一篇: 总线设备驱动模型---platform篇
下一篇: mini2440 platform 驱动模型
denjackson
博客等级 码龄22年 51粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值