linux中 probe函数的何时调用的?
點擊打開鏈接
linux中 probe函數何時調用的
???????? 所以的驅動教程上都說:只有設備和驅動的名字匹配,BUS就會調用驅動的probe函數,但是有時我們要看看probe函數里面到底做了什么,還有傳遞給probe函數的參數我們就不知道在哪定義(反正不是我們在驅動里定義的),如果不知道傳遞進的參數,去看probe函數總是感覺不求甚解的樣子(你對系統不求甚解,系統也會對你的要求不求甚解的),心里對自己寫出的程序沒底,保不齊那天來個bug,就悲劇了。
???????? 這里以static int__devinit sst25l_probe(struct spi_device *spi)為例看看傳遞進的參數structspi_device *spi到底是什么,在哪定義,什么時候定義,定義了有什么用…?(本著“five W and H”的原則打破沙鍋問到底)。首先struct spi_device *spi不是我們定義的驅動里定義的;其次在read,write等函數里都有struct spi_device *spi的影子,不過不是直接傳遞進去的,而是通過傳遞進去struct mtd_info *mtd,然后to_sst25l_flash(mtd),即container_of()出包含mtd的struct sst25l_flash *flash,其中flash里的第一個成員就是structspi_device *spi,而此成員的賦值就是將傳遞給probe中的struct spi_device *spi賦值給struct sst25l_flash *flash的,有代碼為證:
static int __devinit sst25l_probe(structspi_device *spi)
{
???????? structflash_info *flash_info;
???????? structsst25l_flash *flash;
???????? ……
???????? flash->spi = spi;//?將structspi_device *spi賦值給struct sst25l_flash *flash
???????? mutex_init(&flash->lock);
???????? dev_set_drvdata(&spi->dev,flash);// &spi->dev ->p->driver_data = flash保持flash
???????? ……
}
???????? 所以搞清楚structspi_device *spi的來源是搞清楚設備驅動與主控驅動的聯系紐帶的關鍵之一,當然要首先搞清楚probe函數什么時候調用才能搞清楚struct spi_device *spi怎么傳遞的,其重要性不言而喻(雖然言了很多,^-^,有點唐僧了)。我們先從驅動的init開始入手,畢竟這是驅動注冊開始的地方,也是一系列后續操作引發的地方:
static int __init sst25l_init(void)
{
???????? returnspi_register_driver(&sst25l_driver);
}
???????? 里面只有一個函數,最喜歡這樣的函數了:
int spi_register_driver(struct spi_driver*sdrv)
{
???????? sdrv->driver.bus= &spi_bus_type;
???????? if(sdrv->probe)
?????????????????? sdrv->driver.probe= spi_drv_probe;
???????? if(sdrv->remove)
?????????????????? sdrv->driver.remove= spi_drv_remove;
???????? if(sdrv->shutdown)
?????????????????? sdrv->driver.shutdown= spi_drv_shutdown;
?????????return driver_register(&sdrv->driver);
}
???????? 前面都是賦值,直接最后一個語句:
int driver_register(struct device_driver*drv)
{
???????? intret;
???????? structdevice_driver *other;
???????? ……
?????????ret = bus_add_driver(drv);
???????? if(ret)
?????????????????? returnret;
???????? ret= driver_add_groups(drv, drv->groups);
???????? if(ret)
?????????????????? bus_remove_driver(drv);
???????? returnret;
}
???????? bus_add_driver(drv)看著就像“好人”:
int bus_add_driver(struct device_driver*drv)
{
???????? structbus_type *bus;
???????? structdriver_private *priv;
???????? interror = 0;
???????? ……
???????? if(drv->bus->p->drivers_autoprobe) {
?????????????????? error=?driver_attach(drv);
?????????????????? if(error)
?????????????????? ???????? goto out_unregister;
???????? }
???????? ……
}
???????? driver_attach看著也很“友善”(函數名中帶get,init的一般都不是,如果里面有幾個“友善”的,一首歌中已經告訴了我們解決的辦法:“xx就像偶爾撥不通的電話號碼,多試幾次總會回答,……”,如果網上找不到,只好挨個跟蹤了,我就這樣找的,笨人只好采取笨辦法,也是沒有辦法的辦法了):
int driver_attach(struct device_driver*drv)
{
???????? returnbus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
???????? 里面只有一個函數,goon:
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;
????????
???????? if(!bus)
???????? ???????? return -EINVAL;
????????
???????? 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;
}
???????? 看到這里好像沒有我們想要找的attach,只執行了個fn()函數,腫么回事?到回頭看看哪里漏了,在bus_for_each_dev中傳遞了個 __driver_attach,也就是在bus_for_each_dev執行了__driver_attach(dev, data),那么它里面到底執行了什么?
static int __driver_attach(struct device*dev, void *data)
{
???????? structdevice_driver *drv = data;
????????
?????????if (!driver_match_device(drv, dev))
???????? ?????????return 0;
????????
???????? if(dev->parent)/* Needed for USB */
?????????????????? device_lock(dev->parent);
???????? device_lock(dev);
???????? if(!dev->driver)
???????????????????driver_probe_device(drv, dev);
???????? device_unlock(dev);
???????? if(dev->parent)
?????????????????? device_unlock(dev->parent);
????????
???????? return0;
}
???????? 有個driver_probe_device(drv,dev),繼續跟蹤:
int driver_probe_device(structdevice_driver *drv, struct device *dev)
{
???????? intret = 0;
???????? ……
?????????ret = really_probe(dev, drv);
???????? pm_runtime_put_sync(dev);
?
???????? returnret;
}
???????? 有個really_probe(dev,drv),linux神馬的就喜歡這樣,經常一個函數傳遞給另一函數,后一個函數就是在前一個函數前加“do_”、“really_”、“__”,還經常的就是宏定義的或inline的。
static int really_probe(struct device *dev,struct device_driver *drv)
{
???????? intret = 0;
???????? ……
???????? if(dev->bus->probe) {
???????????????????ret = dev->bus->probe(dev);
?????????????????? if(ret)
??????????????????????????? gotoprobe_failed;
???????? }else if (drv->probe) {
???????????????????ret = drv->probe(dev);
?????????????????? if(ret)
??????????????????????????? gotoprobe_failed;
???????? }
???????? ……
???????? returnret;
}
???????? 這里如果有總線上的probe函數就調用總線的probe函數,如果沒有則調用drv的probe函數。
???????? 在static int__driver_attach(struct device *dev, void *data)中先調用了driver_match_device(drv,dev),用于匹配,成功才繼續執行,否則直接返回了。driver_match_device(drv, dev)中:
static inline intdriver_match_device(struct device_driver *drv,
???????????????????????????????????? ????? struct device *dev)
{
???????? returndrv->bus->match ? drv->bus->match(dev, drv) : 1;
}
???????? 即如果match函數的指針不為空,則執行此bus的match函數,也就是為什么資料上老是說總線負責匹配設備和驅動了。這里也傳遞了參數struct device *dev,到底這個dev來自何方,會在下一篇文章中繼續跟蹤。
???????? 本文章參考:http://blog.chinaunix.net/space.php?uid=15887868&do=blog&id=2758294,對原作者表示感謝!
總結
以上是生活随笔為你收集整理的linux中 probe函数的何时调用的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 打开CMDLINE中的 ” earlyp
- 下一篇: linux中probe函数中传递的参数来