无论是device还是driver都注册到bus总线上,bus负责driver和device的匹配

#mermaid-svg-JITPsVTSAG44Swoq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JITPsVTSAG44Swoq .error-icon{fill:#552222;}#mermaid-svg-JITPsVTSAG44Swoq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JITPsVTSAG44Swoq .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-JITPsVTSAG44Swoq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JITPsVTSAG44Swoq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JITPsVTSAG44Swoq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JITPsVTSAG44Swoq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JITPsVTSAG44Swoq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JITPsVTSAG44Swoq .marker.cross{stroke:#333333;}#mermaid-svg-JITPsVTSAG44Swoq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JITPsVTSAG44Swoq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JITPsVTSAG44Swoq .cluster-label text{fill:#333;}#mermaid-svg-JITPsVTSAG44Swoq .cluster-label span{color:#333;}#mermaid-svg-JITPsVTSAG44Swoq .label text,#mermaid-svg-JITPsVTSAG44Swoq span{fill:#333;color:#333;}#mermaid-svg-JITPsVTSAG44Swoq .node rect,#mermaid-svg-JITPsVTSAG44Swoq .node circle,#mermaid-svg-JITPsVTSAG44Swoq .node ellipse,#mermaid-svg-JITPsVTSAG44Swoq .node polygon,#mermaid-svg-JITPsVTSAG44Swoq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JITPsVTSAG44Swoq .node .label{text-align:center;}#mermaid-svg-JITPsVTSAG44Swoq .node.clickable{cursor:pointer;}#mermaid-svg-JITPsVTSAG44Swoq .arrowheadPath{fill:#333333;}#mermaid-svg-JITPsVTSAG44Swoq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JITPsVTSAG44Swoq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JITPsVTSAG44Swoq .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-JITPsVTSAG44Swoq .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-JITPsVTSAG44Swoq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JITPsVTSAG44Swoq .cluster text{fill:#333;}#mermaid-svg-JITPsVTSAG44Swoq .cluster span{color:#333;}#mermaid-svg-JITPsVTSAG44Swoq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JITPsVTSAG44Swoq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

device1
device2
device3
bus
driver1
driver2
driver3

bus的结构体如下所示:

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);   //匹配设备和驱动的函数int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);                               //如果设备和驱动匹配成功,则会调用此函数,这个函数由//struct device_driver里面的probe函数实现,bus里面//probe最后会调用device_driver里面的probe函数。//这个函数用来初始化设备。这个函数Linux内核里面已经实现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总线为例,讲解总线的注册。

int __init platform_bus_init(void){int error;early_platform_cleanup();error = device_register(&platform_bus);if (error)return error;error =  bus_register(&platform_bus_type); //这里调用总线的注册函数。if (error)device_unregister(&platform_bus);of_platform_register_reconfig_notifier();return error;
}

主要看platform_bus_type结构体

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_match函数原型如下:

static int platform_match(struct device *dev, struct device_driver *drv){return (strcmp(pdev->name, drv->name) == 0);
}

从上面可以看出,platform总线是通过设备和驱动的名字来实现匹配的。

内核实现的probe函数如下:

int driver_probe_device(struct device_driver *drv, struct device *dev){int ret = 0;if (!device_is_registered(dev))return -ENODEV;pr_debug("bus: '%s': %s: matched device %s with driver %s\n",drv->bus->name, __func__, dev_name(dev), drv->name);pm_runtime_get_suppliers(dev);if (dev->parent)pm_runtime_get_sync(dev->parent);pm_runtime_barrier(dev);ret = really_probe(dev, drv); //调用驱动中的probe函数.pm_request_idle(dev);if (dev->parent)pm_runtime_put(dev->parent);pm_runtime_put_suppliers(dev);return ret;
}

really_probe函数中调用驱动中的probe函数的源码:

   if (dev->bus->probe) {  //platform总线的bus中的probe为空ret = dev->bus->probe(dev);if (ret)goto probe_failed;} else if (drv->probe) { //drv->probe的条件满足,所以调用drv中proberet = drv->probe(dev);if (ret)goto probe_failed;}

2.设备device

设备device的结构体如下所示:

struct device {struct device     *parent;//父设备struct device_private  *p;//设备的私有数据struct kobject kobj;        //表示该设备并把它链接到设备模型中的kobject中const char       *init_name; /* initial name of the device */const struct device_type *type; //设备的类型struct mutex     mutex;  /* mutex 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        *platform_data; /* 平台的特有数据Platform specific data, device core doesn't touch it */void      *driver_data;   /* 驱动的特有数据Driver data, set and get with dev_set/get_drvdata */struct dev_links_info links;struct dev_pm_info    power; struct dev_pm_domain *pm_domain;#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAINstruct irq_domain    *msi_domain;
#endif#ifdef CONFIG_PINCTRLstruct dev_pin_info  *pins;
#endif#ifdef CONFIG_GENERIC_MSI_IRQstruct list_head Smsi_list;
#endif#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. */unsigned long  dma_pfn_offset;struct device_dma_parameters *dma_parms;struct list_head dma_pools;  /* dma pools (if dma'ble) */struct dma_coherent_mem    *dma_mem; /* internal for coherent memoverride */
\#ifdef CONFIG_DMA_CMAstruct cma *cma_area;     /* contiguous memory area for dmaallocations */
\#endif/* arch specific additions */struct dev_archdata archdata;struct device_node *of_node; /* associated device tree node */struct fwnode_handle *fwnode; /* firmware device node */dev_t            devt;   /* dev_t, creates the sysfs "dev" */u32           id; /* device instance */spinlock_t     devres_lock;struct list_head    devres_head;struct klist_node   knode_class;struct class        *class; //指向所属的类const struct attribute_group **groups;  /* optional groups */void   (*release)(struct device *dev);struct iommu_group   *iommu_group;struct iommu_fwspec    *iommu_fwspec;bool          offline_disabled:1;bool         offline:1;};// 它一般作为一个基类,就像kobject一样,比如在struct platform_device中就包含了这个结构体。它包含了设备的基本信息,设备所属的bus、管理设备的驱动、设备的私有数据等内容。// 设备device的API如下所示:int device_register(struct device *dev){device_initialize(dev);            //初始化struct device  return device_add(dev);         //在内核中添加一个设备并在内核中建立目录层次结构,
}int device_add(struct device *dev){dev = get_device(dev); //struct device中的struct kobject引用计数+1if (!dev->p) {error = device_private_init(dev); //dev->p->device = }if (dev->init_name) {dev_set_name(dev, "%s", dev->init_name);  //将名字赋值给struct device里面的kobject  dev->init_name = NULL;}/* subsystems can specify simple device enumeration */if (!dev_name(dev) && dev->bus && dev->bus->dev_name)dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);if (!dev_name(dev)) {error = -EINVAL;goto name_error;}parent = get_device(dev->parent);//返回父节点,且父节点的引用计数+1kobj = get_device_parent(dev, parent);if (kobj)dev->kobj.parent = kobj; //重新设计父节点/* use parent numa_node */if (parent && (dev_to_node(dev) == NUMA_NO_NODE))set_dev_node(dev, dev_to_node(parent));/* first, register with generic layer. *//* we require the name to be set before, and pass NULL */error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); //建立文件夹if (error) {glue_dir = get_glue_dir(dev);goto Error;}/* notify platform of device entry */if (platform_notify)platform_notify(dev);error = device_create_file(dev, &dev_attr_uevent); //在dev所创建的文件夹下创建属性文件if (error)goto attrError;//建立subsystem链接文件到所属class   //sys文件夹下的目标文件夹建立软链接error = device_add_class_symlinks(dev);if (error)goto SymlinkError;//添加dev的属性描述文件error = device_add_attrs(dev);if (error)goto AttrsError;//添加链接文件到所属buserror = bus_add_device(dev);if (error)goto BusError;error = dpm_sysfs_add(dev);if (error)goto DPMError;device_pm_add(dev);if (MAJOR(dev->devt)) {//建立设备的属性文件error = device_create_file(dev, &dev_attr_dev);if (error)goto DevAttrError;error = device_create_sys_dev_entry(dev);if (error)goto SysEntryError;devtmpfs_create_node(dev);}/* Notify clients of device addition.  This call must come* after dpm_sysfs_add() and before kobject_uevent().*/if (dev->bus)blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);kobject_uevent(&dev->kobj, KOBJ_ADD);bus_probe_device(dev);        //检测驱动中有无适合的设备进行匹配,现在只添加了设备,还没有加载驱动,if (parent)klist_add_tail(&dev->p->knode_parent,&parent->p->klist_children);if (dev->class) {mutex_lock(&dev->class->p->mutex);/* tie the class to the device */klist_add_tail(&dev->knode_class,&dev->class->p->klist_devices);/* notify any interfaces that the device is here */list_for_each_entry(class_intf,&dev->class->p->interfaces, node)if (class_intf->add_dev)class_intf->add_dev(dev, class_intf);mutex_unlock(&dev->class->p->mutex);}}
void bus_probe_device(struct device *dev){struct bus_type *bus = dev->bus;struct subsys_interface *sif;if (!bus)return;if (bus->p->drivers_autoprobe)//设置了自动匹配初始化那么就开始匹配device_initial_probe(dev);mutex_lock(&bus->p->mutex);list_for_each_entry(sif, &bus->p->interfaces, node)if (sif->add_dev)sif->add_dev(dev, sif);mutex_unlock(&bus->p->mutex);}void device_initial_probe(struct device *dev){__device_attach(dev, true);
}
static int __device_attach(struct device *dev, bool allow_async){int ret = 0;device_lock(dev);if (dev->driver) {  //默认制定了driver就直接绑定if (device_is_bound(dev)) {ret = 1;goto out_unlock;}ret = device_bind_driver(dev);if (ret == 0)ret = 1;else {dev->driver = NULL;ret = 0;}} else {//如果没有就进行遍历struct device_attach_data data = {.dev = dev,.check_async = allow_async,.want_async = false,};if (dev->parent)pm_runtime_get_sync(dev->parent);ret = bus_for_each_drv(dev->bus, NULL, &data,__device_attach_driver);if (!ret && allow_async && data.have_async) {/** If we could not find appropriate driver* synchronously and we are allowed to do* async probes and there are drivers that* want to probe asynchronously, we'll* try them.*/dev_dbg(dev, "scheduling asynchronous probe\n");get_device(dev);async_schedule(__device_attach_async_helper, dev);} else {pm_request_idle(dev);}if (dev->parent)pm_runtime_put(dev->parent);}
out_unlock:device_unlock(dev);return ret;
}
static int __device_attach_driver(struct device_driver *drv, void *_data)
{struct device_attach_data *data = _data;struct device *dev = data->dev;bool async_allowed;int ret;/** Check if device has already been claimed. This may* happen with driver loading, device discovery/registration,* and deferred probe processing happens all at once with* multiple threads.*/if (dev->driver)return -EBUSY;ret = driver_match_device(drv, dev); //内核写的设备和驱动的匹配函数if (ret == 0) {/* no match */return 0;} else if (ret == -EPROBE_DEFER) {dev_dbg(dev, "Device match requests probe deferral\n");driver_deferred_probe_add(dev);} else if (ret < 0) {dev_dbg(dev, "Bus failed to match device: %d", ret);return ret;} /* ret > 0 means positive match */async_allowed = driver_allows_async_probing(drv);if (async_allowed)data->have_async = true;if (data->check_async && async_allowed != data->want_async)return 0;return driver_probe_device(drv, dev);//内核写的探测函数,如果匹配成功就会执行此函数}

匹配函数原型如下:

static inline int driver_match_device(struct device_driver *drv,struct device *dev)
{ return drv->bus->match ? drv->bus->match(dev, drv) : 1; //bind driver_probe_device
}

从里面可以看出,还是调用的bus注册时候的match函数。

探测函数原型如下:

int driver_probe_device(struct device_driver *drv, struct device *dev)
{int ret = 0;if (!device_is_registered(dev))return -ENODEV;pr_debug("bus: '%s': %s: matched device %s with driver %s\n",drv->bus->name, __func__, dev_name(dev), drv->name);pm_runtime_get_suppliers(dev);if (dev->parent)pm_runtime_get_sync(dev->parent);pm_runtime_barrier(dev);if (initcall_debug)ret = really_probe_debug(dev, drv);elseret = really_probe(dev, drv); //really_probepm_request_idle(dev);if (dev->parent)pm_runtime_put(dev->parent);pm_runtime_put_suppliers(dev);return ret;
}static int really_probe(struct device *dev, struct device_driver *drv)
{ret = device_links_check_suppliers(dev);  //suppliers检查,仅在device的所有suppliers状态正常时才会触发probeif (ret == -EPROBE_DEFER)driver_deferred_probe_add_trigger(dev, local_trigger_count); if (ret)return ret;    if (dev->bus->probe) {ret = dev->bus->probe(dev);if (ret)goto probe_failed;} else if (drv->probe) {ret = drv->probe(dev);if (ret)goto probe_failed;}
}

在里面首先要检查驱动所需要的supplier是否正常,例如上下电,时钟等驱动,检查之后会调用bus注册时候的probe函数,如果没有则调用驱动中的函数。如果检查失败,驱动会延后再次触发driver_probe_device。

3.设备驱动driver

driver结构体如下所示:

struct device_driver {const char     *name;struct bus_type       *bus;struct module      *owner;const char       *mod_name;  /* used for built-in modules */bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */enum probe_type probe_type;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_register

​ bus_add_driver

​ driver_attach

​ bus_for_each_dev

​ __driver_attach

​ driver_match_device()

​ driver_probe_device

driver,bus,device相关推荐

  1. LINUX设备模型BUS,DEVICE,DRIVER

    虽然看了上面一篇转载的<使用/sys/访问系统>对总线,驱动,设备都讲得比较细但还是没有太多的感觉.在此就先把自己今天所学回忆一下. 为了满足新的要求,linux2.6提供了新的设备模型: ...

  2. bus,device,driver三者关系

    bus,device,driver三者关系 bus: 总线作为主机和外设的连接通道,有些总线是比较规范的,形成了很多协议.如 PCI,USB,1394,IIC等.任何设备都可以选择合适的总线连接到主机 ...

  3. Linux Driver 和Device匹配过程分析

    Linux Driver 和Device匹配过程分析 1,总线注册匹配过程 1.1 struct platform_driver 1.2 struct device_driver 1.3 PCIe总线 ...

  4. Driver for device rausb0 has been compiled with version 22

    在使用iwconfig命令的时候提示的一个警告: # iwconfig lo        no wireless extensions. eth0      no wireless extensio ...

  5. linux设备模型bus,device,driver,(kobject、ktype、kset,bus_type、device、device_driver)

    1.1Linux设备驱动模型简介 1.什么是设备驱动模型 (1)类class.总线bus(负责将设备和驱动挂接起来).设备devices.驱动driver(可以看到在驱动源码中,不管是什么样的驱动,都 ...

  6. linux bus、driver、device及三者的关系

    一.概念 1.bus     总线是处理器和设备之间的通道.总线有多种类型,每种总线可以挂载多个设备. 2.driver     驱动程序是在CPU运行时,提供操作的软件接口.所有的设备必须有与之配套 ...

  7. framebuffer驱动详解3——framebuffer驱动分析(driver和device的配套查找)

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 一.framebuffer驱动分析1 1.s3cfb.c (1)实现为平台总线,因为使用SoC内部的LCD控制器,属于内部外设,可以借用平台 ...

  8. linux设备驱动模型 - device/bus/driver

    在linux驱动模型中,为了便于管理各种设备,我们把不同设备分别挂在他们对应的总线上,设备对应的驱动程序也在总线上找,这样就提出了deivce-bus-driver的模型,硬件上有许多设备总线,那么我 ...

  9. 设备驱动模型:device, bus, driver之间的联系

    对于驱动工程师而言,在移植porting对应设备的driver时,要在devicetree中增加对应的设备节点,其中有一个compatible属性,这个属性的字符串要和driver里面的of_devi ...

最新文章

  1. mysql plsql循环语句吗,Oracle PLSQL 在游标中用while循环实例程序
  2. 浙大赵俊博:重新审视模型 vs 数据这个问题!
  3. 人工智能进阶-CIFAR-10数据集介绍
  4. 理解和配置 Linux 下的 OOM Killer
  5. python编程学习笔记_python编程:从入门到实践学习笔记-Django开发用户账户(一)...
  6. 97 岁诺奖得主的励志人生:本科学文学,博士转物理,54 岁才开始锂电池研究...
  7. Oracle asm aix盘,AIX/HP UX/LINUX上ORACLE ASM添加磁盘
  8. python类库32[多线程同步Lock+RLock+Semaphore+Event]
  9. python中属于私有属性的是_Python中的实例属性和私有属性
  10. oracle关于字符串函数,Oracle字符串处理函数
  11. Python 手写数字识别实战分享
  12. excel 自定义参数(text函数)
  13. 为什么宁愿工资低点,也不建议去外包公司?
  14. 论文阅读《Context-Transformer:Tackling Object Confusion for Few-Shot Detection》
  15. Android自定义圆角矩形图片ImageView
  16. java计算机毕业设计列车票务信息管理系统源程序+mysql+系统+lw文档+远程调试
  17. 解决Mac苹果电脑没有声音,喇叭会显示为灰色禁用状态
  18. 猿创征文|【简单】微信公众号推送教程 ·可直接下载运行 ·超详细
  19. 键盘输入盲打训练, 打字练习,打字游戏 打字教程推荐
  20. 验证码获取及解加密(模拟人进入网页获取数据)

热门文章

  1. 微机原理 17-地址传送指令
  2. html div 堆叠,HTML – 棘手的div堆叠
  3. php聚丙烯酰胺,高分子聚丙烯酰胺
  4. 【音乐随想】道,流浪者之歌 与神思者
  5. 40岁程序员遭劝退找不到工作,大龄码农注定被淘汰?
  6. 晶体管图示仪曲线追踪扫描仪 IV曲线CV曲线伏安特性
  7. wangEditor上传本地视频
  8. 据说是美团最缺人的部门了
  9. BLS12-381 pairing-friendly 曲线
  10. ROS2极简总结-Nav2-地图和自适应蒙特卡洛定位