linux中probe函数中传递的参数来源(上)
點擊打開鏈接
上一篇中,我們追蹤了probe函數在何時調用,知道了滿足什么條件會調用probe函數,但probe函數中傳遞的參數我們并不知道在何時定義,到底是誰定義的,反正不是我們在驅動中定義的(當然,驅動中也不會定義設備的詳細信息),但也不是在我們設備信息定義時的結構體。這就相當于武林絕學中只打通了任脈,而督脈還沒打通,要想成為武林高手還差一步,本文就致力于打通我們設備驅動probe函數的任督二脈,做到正向逆向全順暢,當任督二脈全都打通后,。。。,就可以獨步武林、指點江山啦,再然后按照武林高手成名后既定的流程,該寂寞地隱去了(好像又再做白日夢了),當然了Linux中值得我們要學的多著呢,除了編寫內核的那幫家伙們偶爾會寂寞下外,我們還是沒有多少時間留給我們寂寞的(^_^)。
???????? 雖然不知道probe函數的參數怎么來的,但沒吃過豬肉,還是見過豬跑的,有點關系就能找到出路。經常聽說:先注冊設備時,內核會將設備信息掛到設備鏈上,然后等待命中注定的有緣的設備驅動mm or gg。so,我們可以猜想:應該是設備注冊的時候,內核將設備信息掛到上面去的,按照這個猜想,我們應該先從設備注冊入手,但是這么多函數到底朝哪個方向努力呀?所以,先從傳遞的參數入手,查看下,等走不通了在去從設備注冊入手,起碼有了努力的方向了。
調用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函数中传递的参数来源(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux中 probe函数的何时调用的
- 下一篇: linux中probe函数传递参数的寻找