linux内核部件分析(九)——设备驱动模型之device

合集下载

linux的bus、device、driver介绍

linux的bus、device、driver介绍

linux的bus、device、driver介绍 linux 通过device和driver分别管理系统中的设备和驱动,⽤bus将设备和驱动关联起来,bus可以看成是设备和驱动的媒介,可以匹配设备和驱动。

这样设备和驱动可以独⽴加载,互不影响。

sysfs是⼀个基于内存的⽂件系统,它的作⽤是将内核信息以⽂件的⽅式提供给⽤户程序使⽤。

我们都知道设备和对应的驱动都是由内核管理的,这些对于⽤户空间是不可见的。

现在通过sysfs,可以在⽤户空间直观的了解设备驱动的层次结构。

⼀、bus注册过程bus_type结构体代表⼀条总线,如下所⽰:struct bus_type {const char *name; //名称const char *dev_name;struct device *dev_root;struct device_attribute *dev_attrs; /* use dev_groups instead */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); //device和driver的匹配函数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;};struct subsys_private {struct kset subsys; //对应/sys/bus⽬录struct kset *devices_kset; //对应/sys/bus/devices⽬录struct list_head interfaces;struct mutex mutex;struct kset *drivers_kset; //对应/sys/bus/drivers⽬录struct klist klist_devices; //该bus下的所有devicestruct klist klist_drivers; //该bus下的所有driverstruct blocking_notifier_head bus_notifier;unsigned int drivers_autoprobe:1;struct bus_type *bus;struct kset glue_dirs;struct class *class;};向系统添加⼀条bus_type总线时,改总线会⾃动添加到/sys/bus⽬录下,bus⽬录是系统⾃动创建的,这个bus⽬录为static struct kset *bus_kset,定义在kernel/drivers/base/bus.c中。

linux内核部件分析-设备驱动模型之driver

linux内核部件分析-设备驱动模型之driver

上节我们分析设备驱动模型中的device,主要是drivers/base/core.c,可以说是代码量最大的一个文件。

本节要分析的驱动driver,就要相对简单很多。

原因也很简单,对于driver,我们能定义的公共部分实在不多,能再sysfs中表达的也很少。

本节的分析将围绕drivers/base/driver.c,但头文件仍然是include/linux/device.h和drivers/base/base.h。

先让我们来看看driver的结构。

[cpp]view plaincopyprint?1.struct device_driver {2.const char *name;3.struct bus_type *bus;4.5.struct module *owner;6.const char *mod_name; /* used for built-in modules */7.8.bool suppress_bind_attrs; /* disables bind/unbind via sysfs */9.10.int (*probe) (struct device *dev);11.int (*remove) (struct device *dev);12.void (*shutdown) (struct device *dev);13.int (*suspend) (struct device *dev, pm_message_t state);14.int (*resume) (struct device *dev);15.const struct attribute_group **groups;16.17.const struct dev_pm_ops *pm;18.19.struct driver_private *p;20.};struct device_driver就是模型定义的通用驱动结构。

Linux内核驱动:cdev、misc以及device三者之间的联系和区别

Linux内核驱动:cdev、misc以及device三者之间的联系和区别

Linux内核驱动:cdev、misc以及device三者之间的联系和区别Linux内核驱动:cdev、misc以及device三者之间的联系和区别背景我想在cdev中使⽤dev_err等log打印函数,但是跟踪了⼀下cdev中的原型,发现并不是我想要的。

常见的驱动是这样⼦使⽤dev_err的:// 某个驱动,这⾥是电池有关的static int32_t oz8806_read_byte(struct oz8806_data *data, uint8_t index, uint8_t *dat){struct i2c_client *client = data->myclient;// ...dev_err(&client->dev, "%s: err %d, %d times\n", __func__, ret, i);// ...}⽽i2c_client原型是这样⼦的,dev就是⼀个device:// include/linux/i2c.hstruct i2c_client {// ...struct device dev; /* the device structure */// ...};那么,我想只要找到cdev中的dev,也可以这样⼦⽤,对吧?但是:// include/linux/cdev.hstruct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;} __randomize_layout;⽽dev_t长这个样⼦:// include/linux/types.htypedef u32 __kernel_dev_t;typedef __kernel_dev_t dev_t;我在困惑dev_t是什么东西以后,找到了下⾯这篇⽂章。

linux驱动模型

linux驱动模型

我们将详细的介绍Linux的设备驱动模型。

Linux设备驱动模型是一个相当复杂的系统,对于初学者来说真有些无从入手。

而且更加困难的是,随着新的Linux Kernel的release,Linux 的设备驱动模型总会有或大或小的变化,我们将尽量展现Linux Kernel 的这种变化。

早期的Linux内核(版本2.4之前)并没有实现一个统一的设备模型,设备节点的创建一般是mknod命令手动创建或利用devfs文件系统创建。

早期的Linux发行版一般会采用手动创建的方式预先把通常用到的节点都创建出来,而嵌入式系统则会采用devfs的方式。

起初Linux 2.6 内核还支持devfs,但从2.6.18开始,内核完全移除了devfs系统而采用的udev的方式动态的创建设备节点。

因此,新的Linux发行版都采用udev的方式管理设备节点文件。

Linux2.6设备驱动模型的基本元素是Class、Bus、Device、Driver,下面我们分别介绍各个部分。

Class 和Class Device驱动模型最基本的概念是设备及其类别,Linux中使用struct class 和struct class_device来管理不同类别的设备。

由于设备驱动模型是一个复杂的系统,我们还是从一个简单的例子开始介绍,然后在逐步展开。

其实实现设备节点的动态创建是一个很简单的事情,并不需要太多的代码。

我们修改我们的驱动初始化函数如下:#include <linux/device.h>#define DEVNAME "hello"static dev_t dev;static struct class *hello_c lass;static struct cdev *hello_cdev;static int __init hello_init(void){int error;error = alloc_chrdev_region(&dev, 0, 2, "hello");if (error){printk("hello: alloc_chardev_region failed! ");goto out;}hello_cdev = cdev_alloc();if (hello_cdev == NULL){printk("hello: alloc cdev failed! ");error = -ENOMEM;goto out_chrdev;}hello_cdev->ops = &hello_fops;hello_cdev->owner = THIS_MODULE;error = cdev_add(hello_cdev, dev, 1);if (error){printk("hello: cdev_add failed! ");goto out_cdev;}hello_class = class_create(THIS_MODULE, DEVNAME);if (IS_ERR(hello_class)){error = PTR_ERR(hello_class);goto out_chrdev;}class_device_create(hello_class, NULL, dev, NULL, DEVNAME);memset (hello_buf, 0, sizeof(hello_buf));memcpy(hello_buf, DEFAULT_MSG, sizeof(DEFAULT_MSG));printk("hello: Hello World! ");return 0;out_cdev:cdev_del(hello_cdev);out_chrdev:unregister_chrdev_region(hello_cdev->dev, 2);out:return error;}static void __exit hello_exit(void){class_device_destroy(hello_class, dev);class_destroy(hello_class);unregister_chrdev_region(hello_cdev->dev, 2);cdev_del(hello_cdev);printk("hello: Goodbye World ");}重新编译这个驱动程序,当加载这个驱动到内核中时,系统(一般是hotplug和udev系统)就会自动的创建我们指定的设备名字:/dev/hello,同时,你也可以发现在sysfs系统中添加了新的文件:/sys/class/hello/hello/。

Linux设备驱动模型与sysfs---platform总线设备驱动

Linux设备驱动模型与sysfs---platform总线设备驱动

Linux在2.6版本引入了设备驱动模型,设备驱动模型负责统一实现和维护一些特性,诸如:热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施1.设备驱动模型基本概念设备驱动模型主要包含:类(class)、总线(bus)、设备(device)、驱动(driver),它们的本质都是内核中的几种数据结构的“实例”∙类的本质是class结构体类型,各种不同的类其实就是class的各种实例∙总线的本质是bus_type结构体类型,各种不同的总线其实就是bus_type的各种实例∙设备的本质是device结构体类型,各种不同的设备其实就是device的各种实例∙驱动的本质是device_driver结构体类型,各种不同的驱动其实就是device_driver的各种实例2.sysfs基本概念sysfs其实就是/sys目录,其主要作用就是:展示设备驱动模型中各组件的层次关系,并将各组件的本体——内核中的数据结构以文件形式呈现,方便用户层查看及操作3./sys目录结构与设备驱动模型∙/sys目录结构很好的展示了驱动设备模型,如图:∙注意:同一个设备可能在/sys中存在多个设备文件,比如一颗led的设备文件可能在/sys/bus/platform/devices/led1,同时还有一个在/sys/class/leds/led1。

虽然他们都是同一颗led的设备文件,但是他们的来源、机制、原理都是不同的,不能混为一谈4.各组件的特性与联系∙kobject:设备驱动模型各实例的最基本单元,提供一些公用型服务如:提供该实例在sysfs中的操作方法(show和store);提供在sysfs中以文件形式存在的属性,其实就是应用接口;提供各个实例的层次架构,让sysfs中弄出目录结构。

设备驱动模型中每个实例内部都会包含一个kobject∙总线、设备、驱动,这三者有着密切的联系。

在内核中,设备和驱动是分开注册的,注册设备的时候,并不需要驱动已经存在,而驱动被注册的时候,也不需要对应的设备已经被注册。

Linuxkernel驱动相关抽象概念及其实现之“bus,device,driver”

Linuxkernel驱动相关抽象概念及其实现之“bus,device,driver”

Linuxkernel驱动相关抽象概念及其实现之“bus,device,driver”bus,device,driver三个很重要的概念贯穿Linux内核驱动架构,特转载⼀篇博⽂:内核的开发者将总线,设备,驱动这三者⽤软件思想抽象了出来,巧妙的建⽴了其间的关系,使之更形象化。

结合前⾯所学的知识,总的来说其三者间的关系为bus有两条链表,分别⽤于挂接设备和驱动,指定了其⾃⾝bus的device或者driver最后都会分别连接到对应bus的这两条链表上,⽽总线⼜有其始端,为bus_kset,⼀个driver可以对应于⼏个设备,因此driver同样有其设备链表,⽤于挂接可以操作的设备,其⾃⾝也有bus挂接点,⽤于将⾃⾝挂接到对应bus(每个driver只属于⼀条总线),⽽对于device,⼀个设备只属于⼀条总线,只能有⼀个driver与其对应,因此对于device,都是单⼀的,⼀个driver挂接点,⼀个bus挂接点,device与bus相同的是都有始端,device为devices_kset,因此device的注册同时会出现在对应的bus⽬录和device总⽬录下。

好了,下⾯就以源码为例分别分析⼀下bus,device,driver的注册过程。

⼀、bus的注册bus的注册⽐较简单,⾸先来看⼀下bus的结构:1struct bus_type {2const char *name; //名字3struct bus_attribute *bus_attrs; //bus属性集4struct device_attribute *dev_attrs; //device属性集5struct driver_attribute *drv_attrs; //driver属性集6int (*match)(struct device *dev, struct device_driver *drv);7int (*uevent)(struct device *dev, struct kobj_uevent_env *env);8int (*probe)(struct device *dev);9int (*remove)(struct device *dev);10void (*shutdown)(struct device *dev);11int (*suspend)(struct device *dev, pm_message_t state);12int (*resume)(struct device *dev);13const struct dev_pm_ops *pm;14struct bus_type_private *p; //bus的私有成员15 };16//其中重点看⼀下私有成员结构体:17struct bus_type_private {18struct kset subsys; //bus内嵌的kset,代表其⾃⾝19struct kset *drivers_kset;20struct kset *devices_kset;21struct klist klist_devices; //包含devices链表及其操作函数22struct klist klist_drivers; //driver链表及其操作函数23struct blocking_notifier_head bus_notifier;24 unsigned int drivers_autoprobe:1; //匹配成功⾃动初始化标志25struct bus_type *bus;26 };⽆论是bus,driver,还是device其本⾝特征都放在私有成员⾥,其注册时,都会申请并填充这个结构体,下⾯具体分析⼀下bus的注册流程,从bus_register开始:1int bus_register(struct bus_type *bus)2 {3int retval;4struct bus_type_private *priv;5 priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); //进⼊时bus_type->bus_type_private为NULL6if (!priv) //该函数主要是对其的设置7return -ENOMEM;8 priv->bus = bus; //私有成员的bus回指该bus9 bus->p = priv; //初始化bus->p,即其私有属性10 BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);11 retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //设置该bus的名字,bus是kset的封装12if (retval)13goto out;14//bus_kset即为所有bus的总起始端点15//围绕bus内嵌的kset初始化,和kset的初始化时围绕16 priv->subsys.kobj.kset = bus_kset; //kobj相似,没有parent时,就会⽤kset的kobj,此处即是17 priv->subsys.kobj.ktype = &bus_ktype; //属性操作级别统⼀为bus_ktype18 priv->drivers_autoprobe = 1; //设置该标志,当有driver注册时,会⾃动匹配devices19//上的设备并⽤probe初始化,20//当有device注册时也同样找到 driver并会初始化21 retval = kset_register(&priv->subsys); //注册kset,创建⽬录结构,以及层次关系22if (retval)23goto out;24 retval = bus_create_file(bus, &bus_attr_uevent); //当前bus⽬录下⽣成bus_attr_uevent属性⽂件25if (retval)26goto bus_uevent_fail;27 priv->devices_kset = kset_create_and_add("devices", NULL, //初始化bus⽬录下的devices⽬录,⾥⾯级联了该bus下设备,28 &priv->subsys.kobj); //仍然以kset为原型29if (!priv->devices_kset) {30 retval = -ENOMEM;31goto bus_devices_fail;32 }33 priv->drivers_kset = kset_create_and_add("drivers", NULL, //初始化bus⽬录下的drivers⽬录,⾥⾯级联了该bus下设备的driver34 &priv->subsys.kobj);35if (!priv->drivers_kset) {36 retval = -ENOMEM;37goto bus_drivers_fail;38 }39 klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //初始化klist_devices⾥的操作函数成员40 klist_init(&priv->klist_drivers, NULL, NULL); //klist_drivers⾥的操作函数置空41 retval = add_probe_files(bus); //增加bus_attr_drivers_probe和bus_attr_drivers_autoprobe42if (retval) //属性⽂件43goto bus_probe_files_fail;44 retval = bus_add_attrs(bus); //增加默认的属性⽂件45if (retval)46goto bus_attrs_fail;47 pr_debug("bus: '%s': registered/n", bus->name);48return0;49 bus_attrs_fail: //以下为错误处理50 remove_probe_files(bus);51 bus_probe_files_fail:52 kset_unregister(bus->p->drivers_kset);53 bus_drivers_fail:54 kset_unregister(bus->p->devices_kset);55 bus_devices_fail:56 bus_remove_file(bus, &bus_attr_uevent);57 bus_uevent_fail:58 kset_unregister(&bus->p->subsys);59out:60 kfree(bus->p);61 bus->p = NULL;62return retval;63 }由此可见,bus⼜是kset的封装,bus_register主要完成了其私有成员bus_type_private的初始化,并初始化了其下的两个⽬录devices和drivers,及其属性⽂件,bus有个⾃⼰的根⽬录也就是bus有个起始端点,是bus_kset,经过此番的注册,bus⽬录下将会出现我们注册的bus,并且其下会有device和driver两个⼦⽬录,代表它下⾯的driver和device链表。

linux设备驱动--总线驱动设备

linux设备驱动--总线驱动设备

linux设备驱动--总线,驱动,设备/wh_19910525/article/details/739805120122.6 版本内核是如何管理总线,驱动,设备之间的关系的,关于bus_type、device_driver、device这三个内核结构在内核代码中可以找到。

由于这三个结构的重要性,我们在这里先将它们贴出来;1、设备结构的定义:struct device {struct klist klist_children;struct klist_node knode_parent; /* node in sibling list */ struct klist_node knode_driver;struct klist_node knode_bus;struct device *parent;struct kobject kobj; //kobject结构,关于这个结构与kset 结构以及subsystem结构,笔记中会有描述。

char bus_id[BUS_ID_SIZE]; /* position on parent bus */struct device_type *type;unsigned is_registered:1;unsigned uevent_suppress:1;struct semaphore sem; /* semaphore to synchronize calls to* its driver.*/struct bus_type * bus; /* type of bus device is on */ //这个设备挂接的总线的类型struct device_driver *driver; /* which driver has allocated this device */ //这个设备挂接的驱动void *driver_data; /* data private to the driver */void *platform_data; /* Platform specific data, device core doesn't touch it */struct dev_pm_info power;#ifdef CONFIG_NUMAint numa_node; /* NUMA node this device is close to */#endifu64 *dma_mask; /* dma mask (if dma'able device) */u64 coherent_dma_mask;/* Like dma_mask, but foralloc_coherent mappings asnot all hardware supports64 bit addresses for consistentallocations such descriptors. */struct list_head dma_pools; /* dma pools (if dma'ble) */ struct dma_coherent_mem *dma_mem; /* internal for coherent mem override *//* arch specific additions */struct dev_archdata archdata;spinlock_t devres_lock;struct list_head devres_head;/* class_device migration path */struct list_head node;struct class *class;dev_t devt; /* dev_t, creates the sysfs "dev" */struct attribute_group **groups; /* optional groups */ void (*release)(struct device * dev);};2、设备驱动的结构:struct device_driver {const char * name; //设备驱动的名字struct bus_type * bus; //设备驱动挂接的总线的类型struct kobject kobj; //kobject结构struct klist klist_devices; //这个驱动对应的设备的链表struct klist_node knode_bus;struct module * owner;const char * mod_name; /* used for built-in modules */struct module_kobject * mkobj;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);};3、总线结构:struct bus_type {const char * name; //总线的名字struct module * owner;struct kset subsys; //与该总线相关的subsystemstruct kset drivers; //挂接在该总线上的驱动的集合struct kset devices; //挂接在该总线上的设备的集合struct klist klist_devices;struct klist klist_drivers;struct blocking_notifier_head bus_notifier;struct bus_attribute * bus_attrs; //总线属性struct device_attribute * dev_attrs; //设备属性struct driver_attribute * drv_attrs; //驱动属性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 (*suspend)(struct device * dev, pm_message_t state);int (*suspend_late)(struct device * dev, pm_message_t state); int (*resume_early)(struct device * dev);int (*resume)(struct device * dev);unsigned int drivers_autoprobe:1;};我们注意到只有在bus_type结构中有kset结构,其他两个结构中则没有,我们知道kset结构是用于存放相同类型的kobject的,这究竟是个什么意思呢?kset又是为什么而存在的呢?为什么不能就是kobject呢?(关于kobject结构,我们很难抽象的形容,尽管它就是一个抽象的概念,我们将留待看代码的时候介绍,这里可以将kobject看成一个基类,kset 就是容器了)。

深入解析LinuxPlatform_device及驱动

深入解析LinuxPlatform_device及驱动

深⼊解析LinuxPlatform_device及驱动[导读] 前⽂分析了Linux设备驱动的驱动模型,本⽂来聊聊Platform_driver/Platform_device这个类。

做嵌⼊式Linux的驱动,这个也是绕不开的,所以来学习分析总结⼀下。

上⽂阅读:注:代码分析基于linux-5.4.31为什么有Platform_driver前⽂谈到的总线驱动模型(注这个图是照着bootlin的⽂档绘制的):同时,根据代码分析其基础数据结构框架关系如下(UML关系并不严谨,仅为理解⽅便):可见驱动程序的模型分层有⼀层总线基础层,那么对于嵌⼊式开发领域⽽⾔,有很多SOC芯⽚内置了各种外设,并⽐如LCD,UART、audio、摄像头⼝等等,并没有总线。

为了统⼀驱动架构抽象,所以引⼊了platform bus这个虚拟的总线模型。

做过嵌⼊式开发的⼈应该都有体会,这类设备在嵌⼊式系统中⾮常多,所以在研究具体某类设备的驱动开发之前,有必要研究platform 设备的驱动模型。

在强调⼀下这个是统⼀在总线驱动模型这个体系内的。

驱动模型的实现定义在./include/linux/platform_device.h中,来梳理⼀下这些数据结构间的关系:platform_device ⽤于抽象平台设备platform_driver ⽤于抽象匹配平台设备对应的驱动程序通过继承演化关系分析,platform_device/platform_driver 仍然统⼀于总线驱动模型,只是虚拟出来了⼀条platform bus这样⼀条虚拟总线。

platform_bus在哪⾥实现的呢?该模块的实现位于./driver/base/platform.c中struct device platform_bus = {.init_name = "platform",};platform.c导出了⼀系列内核全局操作接⼝集:EXPORT_SYMBOL_GPL(platform_bus);EXPORT_SYMBOL_GPL(__platform_driver_register);EXPORT_SYMBOL_GPL(__platform_driver_probe);EXPORT_SYMBOL_GPL(platform_get_resource_byname);EXPORT_SYMBOL_GPL(platform_get_irq_byname);....那么既然这条总线并不存在,往往并不能实现设备枚举、热插拔等功能。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

linux内核部件分析(九)——设备驱动模型之device前面我们分析了device、driver、bus三种类型,主要是三者的注册与注销,在sysfs中的目录与属性文件创建等内容。

本节就来详细分析下,在设备注册到总线上时,总线是如何为其寻找对应的驱动的;在驱动注册到总线上时,总线又是如何为其寻找对应的设备的。

本节的实现代码集中在drivers/base/bus.c和drivers/base/dd.c中。

先来回忆下,在device_register()-&gt;device_add()中,先是调用bus_add_device()添加device与bus间的联系,并添加bus 为device定义的属性,然后会调用bus_probe_device()。

bus_probe_device()会试图为已挂在总线上的该设备寻找对应的驱动。

我们的故事就从这里开始。

[cpp] view plaincopyprint?/** * bus_probe_device - probe drivers for a new device * @dev: device to probe * * - Automatically probe for a driver if the bus allows it. */ void bus_probe_device(struct device *dev) { struct bus_type *bus = dev-&gt;bus; int ret; if (bus&amp;&amp; bus-&gt;p-&gt;drivers_autoprobe){ ret = device_attach(dev);WARN_ON(ret &lt; 0); } } bus_probe_device()为总线上的设备寻找驱动。

它先是检查bus-&gt;p-&gt;drivers_autoprobe,看是否允许自动探测。

允许了才会调用device_attach()进行实际的寻找工作。

说到bus-&gt;p-&gt;drivers_autoprobe这个变量,它是在bus_type_private中的,在调用bus_register()前都初始化不了,在bus_register()中自动定为1。

所以,除非是用户空间通过drivers_autoprobe属性文件主动禁止,bus总是允许自动探测的,所有的bus都是如此。

[cpp] view plaincopyprint?/** * device_attach - try to attach device to a driver. * @dev: device. * * Walk the list of drivers that the bus has and call * driver_probe_device() for each pair. If a compatible * pair is found, break out and return. * * Returns 1 if the device was bound to a driver; * 0 if no matching driver was found; * -ENODEV if the device is not registered. * * When called for a USB interface,@dev-&gt;parent-&gt;sem must be held. */ intdevice_attach(struct device *dev) { int ret = 0;down(&amp;dev-&gt;sem); if (dev-&gt;driver){ ret = device_bind_driver(dev); if (ret== 0) ret = 1; else{ dev-&gt;driver = NULL; ret = 0; } } else{ pm_runtime_get_noresume(dev); ret = bus_for_each_drv(dev-&gt;bus, NULL, dev, __device_attach); pm_runtime_put_sync(dev); }up(&amp;dev-&gt;sem); return ret; }device_attach()在实际绑定之前,会用dev-&gt;sem进行加锁。

不错,dev-&gt;sem几乎就是为了在设备与驱动绑定或者解除绑定时加锁用的。

还没有看到它在其它地方被调用。

如果在调用device_attach()前就已经有了dev-&gt;driver(),就调用device_bind_driver()进行绑定,不然还要调用bus_for_each_drv()进行依次匹配。

至于pm_runtime_get_noresume之类的函数,属于电源管理部分,我们现在先忽略。

[cpp] view plaincopyprint?static void driver_bound(struct device *dev) { if(klist_node_attached(&amp;dev-&gt;p-&gt;knode_driver)){ printk(KERN_WARNING "%s: device %s already bound\n", __func__,kobject_name(&amp;dev-&gt;kobj)); return; } pr_debug("driver: '%s': %s: bound to device '%s'\n",dev_name(dev), __func__,dev-&gt;driver-&gt;name); if (dev-&gt;bus)blocking_notifier_call_chain(&amp;dev-&gt;bus-&gt;p-&gt;bus_notifier,BUS_NOTIFY_BOUND_DRIVER, dev);klist_add_tail(&amp;dev-&gt;p-&gt;knode_driver,&amp;dev-&gt;driver-&gt;p-&gt;klist_devices); } static int driver_sysfs_add(struct device *dev) { int ret;ret = sysfs_create_link(&amp;dev-&gt;driver-&gt;p-&gt;kobj, &amp;dev-&gt;kobj,kobject_name(&amp;dev-&gt;kobj)); if (ret == 0){ ret = sysfs_create_link(&amp;dev-&gt;kobj,&amp;dev-&gt;driver-&gt;p-&gt;kobj,"driver"); if (ret)sysfs_remove_link(&amp;dev-&gt;driver-&gt;p-&gt;kobj, kobject_name(&amp;dev-&gt;kobj)); } return ret; } static void driver_sysfs_remove(struct device *dev) { struct device_driver *drv = dev-&gt;driver; if (drv){ sysfs_remove_link(&amp;drv-&gt;p-&gt;kobj, kobject_name(&amp;dev-&gt;kobj));sysfs_remove_link(&amp;dev-&gt;kobj, "driver"); } } /** * device_bind_driver - bind a driver to one device. *@dev: device. * * Allow manual attachment of a driver to a device. * Caller must have already set @dev-&gt;driver. ** Note that this does not modify the bus reference count * nor take the bus's rwsem. Please verify those are accounted * for before calling this. (It is ok to call with no other effort * from a driver's probe() method.) * * This function must be called with @dev-&gt;sem held. */ int device_bind_driver(struct device *dev) { int ret; ret =driver_sysfs_add(dev); if (!ret)driver_bound(dev); return ret; }device_bind_driver()将device与driver绑定。

它调用了两个内部函数。

其中drivers_sysfs_add()负责创建sysfs中driver和device指向对方的软链接。

还有一个与它相对的函数drivers_sysfs_remove()。

driver_bound()则实际将device加入驱动的设备链表。

因为在调用device_bind_driver()之前就已经设置过dev-&gt;driver了,所以这样就将device和driver绑定了。

相关文档
最新文档