嵌入式 linux中probe函数中传递的参数来源(上)

2024-01-05 11:58

本文主要是介绍嵌入式 linux中probe函数中传递的参数来源(上),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

应该是设备注册的时候,内核将设备信息挂到上面去的,按照这个猜想,我们应该先从设备注册入手,但是这么多函数到底朝哪个方向努力呀?所以,先从传递的参数入手,查看下,等走不通了在去从设备注册入手,起码有了努力的方向了。

调用probe函数的是:static int really_probe(struct device *dev, struct device_driver*drv),里面有调用ret = dev->bus->probe(dev)和ret =drv->probe(dev)。函数如下:

static int really_probe(struct device *dev, struct device_driver *drv)

{

         intret = 0;

......

 

         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;

         }

 

......

         returnret;

}

这里的参数dev是上一个函数传递进来的,上一个函数为:int driver_probe_device(struct device_driver *drv, struct device*dev)

int driver_probe_device(structdevice_driver *drv, struct device *dev)

{

         intret = 0;

 ......

         ret = really_probe(dev, drv);


...... 

         returnret;

}

这里的dev又是上一个函数传递进来的,上一个函数为:static int __driver_attach(struct device *dev, void *data)

static int __driver_attach(struct device *dev, void *data)

{

         structdevice_driver *drv = data;

 ......

         device_lock(dev);

         if(!dev->driver)

                   driver_probe_device(drv, dev);

         device_unlock(dev);

        ......

         return0;

}

这里的dev又是上一个函数传递进来的,调用__driver_attach的函数为:int driver_attach(struct device_driver *drv),但本函数没有给__driver_attach传递参数。

int driver_attach(structdevice_driver *drv)

{

         returnbus_for_each_dev(drv->bus, NULL, drv,__driver_attach);

}

         这里面调用了__driver_attach,对应error =fn(dev, data)。第一个参数dev为while ((dev = next_device(&i)) && !error)产生。即dev有i间接产生。

int bus_for_each_dev(struct bus_type *bus, struct device *start,

                        void *data, int (*fn)(struct device *,void *))

{

         structklist_iter i;

         structdevice *dev;

         interror = 0;

....

 

         klist_iter_init_node(&bus->p->klist_devices, &i,

                                 (start ? &start->p->knode_bus :NULL));

         while ((dev = next_device(&i)) && !error)

                   error = fn(dev, data);

         klist_iter_exit(&i);

         returnerror;

}

之所以是next_device(&i),因为第一个节点为头节点,需要从下一个开始,先看看klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->p->knode_bus : NULL))对i干了什么?因为start为NULL,故传递的第三个参数n为NULL。

void klist_iter_init_node(struct klist *k,struct klist_iter *i,

                              struct klist_node *n)

{

         i->i_klist= k;

         i->i_cur= n;

         if(n)

                   kref_get(&n->n_ref);

}

         看来ta没干什么,就是赋了两个值。然后再看最重要的next_device(&i)

static struct device *next_device(struct klist_iter *i)

{

         structklist_node *n = klist_next(i);

         structdevice *dev = NULL;

         structdevice_private *p;

 

         if(n) {

                   p = to_device_private_parent(n);

                   dev = p->device;

         }

         returndev;

}

#define to_device_private_parent(obj)  \

         container_of(obj,struct device_private, knode_parent)

         看到dev由p->device赋值,p为struct device_private,n = i->i_cur为structklist_node 型(后面分析)。为了看懂这个函数,需要补充N多知识,先上几个struct:

struct klist_iter {

         structklist                 *i_klist;

         structklist_node      *i_cur;

};

 

struct klist {

         spinlock_t                  k_lock;

         structlist_head        k_list;

         void                    (*get)(struct klist_node *);

         void                    (*put)(struct klist_node *);

} __attribute__ ((aligned (sizeof(void*))));

 

struct klist_node {

         void                    *n_klist;   /* never access directly */

         structlist_head        n_node;

         structkref                  n_ref;

};

 

struct kref {

         atomic_trefcount;

};

 

         其中的klist_iter_init_node(&bus->p->klist_devices, &i,(start ?&start->p->knode_bus : NULL))作用是定义个klist_iter指向此klist,以便以后直接使用,如图:

 

         再把关键的函数拷到此处,以遍分析:

         while ((dev = next_device(&i)) && !error)

                   error = fn(dev, data);

static struct device *next_device(struct klist_iter *i)

{

         structklist_node *n = klist_next(i);

         structdevice *dev = NULL;

         structdevice_private *p;

 

         if(n) {

                   p = to_device_private_parent(n);

                   dev = p->device;

         }

         returndev;

}

 

/**

 *klist_next - Ante up next node in list.

 *@i: Iterator structure.

 *

 *First grab list lock. Decrement the reference count of the previous

 *node, if there was one. Grab the next node, increment its reference

 *count, drop the lock, and return that next node.

 */

struct klist_node *klist_next(struct klist_iter *i)

{

         void(*put)(struct klist_node *) = i->i_klist->put;

         structklist_node *last = i->i_cur;//NULL

         structklist_node *next;

 

         spin_lock(&i->i_klist->k_lock);

 

         if(last) {

                   next= to_klist_node(last->n_node.next);

                   if(!klist_dec_and_del(last))

                            put= NULL;

         }else

                   next= to_klist_node(i->i_klist->k_list.next);

 

         i->i_cur= NULL;

         while(next != to_klist_node(&i->i_klist->k_list)){

                   if(likely(!knode_dead(next))) {

                            kref_get(&next->n_ref);

                            i->i_cur = next;

                            break;

                   }

                   next= to_klist_node(next->n_node.next);

         }

 

         spin_unlock(&i->i_klist->k_lock);

 

         if(put && last)

                   put(last);

         returni->i_cur;

}

         这里last =i->i_cur;为NULL,然后执行next = to_klist_node(i->i_klist->k_list.next);从这个函数来看,就是取出了包含i->i_klist->k_list.next的n_node指针。不过next所指的和n_node地址偏差一个head指针(list_head包括head和next俩指针)。while循环是从第一个目标to_klist_node(i->i_klist->k_list.next)循环,当再次循环到头节点to_klist_node(&i->i_klist->k_list)时截止(这是个循环链表,总会再次循环回来的)。还一个结束的条件,当循环到knode_dead(next)为真时break,不过,likely说明了next通常不会是dead的,(struct klist_node的第一个成员最后一位做标志dead位,网上还说有指针的作用,我觉得好像做了标志位了就不能做指向头节点的指针了,不过void *n_klist名字起得确实很有迷惑性)。

static struct klist_node*to_klist_node(struct list_head *n)

{

         returncontainer_of(n, struct klist_node, n_node);

}

         还一个i的来源,ta是一切的来源。在klist_iter_init_node(&bus->p->klist_devices,&i,                               (start ? &start->p->knode_bus :NULL))中,       i->i_klist = &bus->p->klist_devices;i->i_cur = NULL;

 

         Klist_iter找到合适的即停止搜索,找到此处的device_private的device,此结构即为传入probe函数的参数。device源于i(i只是暂时用于查找定义的一个临时变量),而i源于bus,bus源于drv->bus,drv源于sdrv->driver,sdrv即为mx25lx_driver,不过mx25lx_driver->driver中的bus,只给赋了一个值,而在后来调用标准的spi函数时,又重新对bus赋了值spi_bus_type,spi_bus_type是spi.c中的struct bus_type定义的全局变量。

这篇关于嵌入式 linux中probe函数中传递的参数来源(上)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/572788

相关文章

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法

《ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法》本文介绍了Elasticsearch的基本概念,包括文档和字段、索引和映射,还详细描述了如何通过Docker... 目录1、ElasticSearch概念2、ElasticSearch、Kibana和IK分词器部署

Linux流媒体服务器部署流程

《Linux流媒体服务器部署流程》文章详细介绍了流媒体服务器的部署步骤,包括更新系统、安装依赖组件、编译安装Nginx和RTMP模块、配置Nginx和FFmpeg,以及测试流媒体服务器的搭建... 目录流媒体服务器部署部署安装1.更新系统2.安装依赖组件3.解压4.编译安装(添加RTMP和openssl模块

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

Java通过反射获取方法参数名的方式小结

《Java通过反射获取方法参数名的方式小结》这篇文章主要为大家详细介绍了Java如何通过反射获取方法参数名的方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、解决方式方式2.1: 添加编译参数配置 -parameters方式2.2: 使用Spring的内部工具类 -

异步线程traceId如何实现传递

《异步线程traceId如何实现传递》文章介绍了如何在异步请求中传递traceId,通过重写ThreadPoolTaskExecutor的方法和实现TaskDecorator接口来增强线程池,确保异步... 目录前言重写ThreadPoolTaskExecutor中方法线程池增强总结前言在日常问题排查中,