1. 程式人生 > >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來自何方,會在下一篇文章中繼續跟蹤。