1. 程式人生 > >i2c_driver的註冊及probe探測函式呼叫

i2c_driver的註冊及probe探測函式呼叫

       每一個驅動程式都有 module_init(xxxx_init) 這個語句,它代表系統啟動的時候會自動執行 xxxx 這個函式,也就是說驅動的人口函式是由module_init來定義的。當然還有module_exit(XXXX),它代表系統解除安裝驅動時呼叫(linux系統允許動態載入解除安裝驅動),這一部分這不細說了。

       上文提到的 xxxx_init 是驅動的入口函式,在此函式中,我們一般註冊驅動的driver,比如我今天說的 i2c_driver:

        static int __init xxxx_init(void)
       {
          

return i2c_add_driver(&xxxx_driver);
       }

其中xxxx_driver就是我們今天的主角 i2c_driver :

      static struct i2c_driver xxxx_driver =
     {
         .driver =
         {
             .owner = THIS_MODULE,
             .name = "xxxx",
         },
        .id_table = xxxx_idtable,
        .probe = xxxx_probe,
     }

完整的 i2c_driver 非常複雜,上面的定義只是完成了最基本的部分,當然也是必須,也就代表完成了上面的部分你的驅動就可以工作了,當然還有其他的,這裡不細說了。i2c_driver 中的driver.name 要和i2c_client一致,因為這是他們配備的一個依據,id_table 是i2c_device_id結構體的一個物件,裡面定義了i2c驅動對應裝置的i2c地址,probe函式是個非常重要的函式,等下我再來細說。

     現在我來說說 i2c_add_driver 的執行過程。

   (注意:此函式是linux系統i2c 子系統已經為我們做好了的,我們完全不需要了解它的執行過程,只需要明白,當系統中已經註冊了和上文提到的i2c_driver  xxxx_driver 對應的i2c_client,所謂對應的是說,name一樣,i2c裝置的地址也一樣,那麼i2c_driver 與i2c_client配備成功,接著就會呼叫i2c_driver 的probe函式,在此函式中可以做一系列的初始化工作。)

     i2c_add_driver 函式只是呼叫了i2c_register_driver函式,在i2c_register_driver裡呼叫了driver_register(&i2c_driver->driver),

注意 driver_register 是linux系統裝置模型裡面的函數了,每一類linux裝置驅動的註冊最終都會呼叫它,傳遞的引數也由原來的i2c_driver 變成了 device_driver。driver_register做了一些判斷,最後呼叫了 bus_add_driver,然後呼叫 driver_attach,然後呼叫

bus_for_each_dev,這個函式就是搜尋總線上所有的device,我們這裡是i2c匯流排,也即搜尋i2c總線上的i2c_client,呼叫__driver_attach判斷i2c_driver i2c_client是否配備,再呼叫driver_match_device,driver_match_device最終呼叫了bus的match函式,我們這也就是i2c bus的match函式,再呼叫

i2c_match_id,這裡到最後的id 配備了,如果配備成功則正常返回到__driver_attach函式,呼叫driver_probe_device,再呼叫really_probe,最後呼叫bus的probe函式,在bus的probe函式裡利用to_i2c_driver 將device_driver轉換成了i2c_driver,最後呼叫了i2c_driver的probe函式,這個部分有點複雜,其中我可能也沒說的太清楚,建議用source insight自己跟一邊,因為其中有很多是公用的,跟一邊後,其他驅動註冊也就容易了。

1,driver_register把驅動註冊到匯流排

[cpp] view plaincopyprint?
  1. /**
  2. * driver_register - register driver with bus
  3. * @drv: driver to register
  4. * We pass off most of the work to the bus_add_driver() call,
  5. * since most of the things we have to do deal with the bus
  6. * structures.
  7. */
  8. int driver_register(struct device_driver *drv) 
  9. …………………… 
  10.     if ((drv->bus->probe && drv->probe) || 
  11.         (drv->bus->remove && drv->remove) || 
  12.         (drv->bus->shutdown && drv->shutdown)) 
  13.     ret = bus_add_driver(drv);//把drv驅動,註冊到匯流排
  14. …………………… 
/**
 * driver_register - register driver with bus
 * @drv: driver to register
 * We pass off most of the work to the bus_add_driver() call,
 * since most of the things we have to do deal with the bus
 * structures.
 */
int driver_register(struct device_driver *drv)
{
……………………
	if ((drv->bus->probe && drv->probe) ||
	    (drv->bus->remove && drv->remove) ||
	    (drv->bus->shutdown && drv->shutdown))

	ret = bus_add_driver(drv);//把drv驅動,註冊到匯流排
……………………
}


2,驅動註冊到匯流排的實現函式

[cpp] view plaincopyprint?
  1. /**
  2. * bus_add_driver - Add a driver to the bus.        -----在總線上加入一個驅動
  3. * @drv: driver.
  4. */
  5. int bus_add_driver(struct device_driver *drv) 
  6. ……………… 
  7.     if (drv->bus->p->drivers_autoprobe) { 
  8.         error = driver_attach(drv);      //驅動的匹配函式
  9. ……………… 
/**
 * bus_add_driver - Add a driver to the bus.        -----在總線上加入一個驅動
 * @drv: driver.
 */
int bus_add_driver(struct device_driver *drv)
{
………………
	if (drv->bus->p->drivers_autoprobe) {
		error = driver_attach(drv);      //驅動的匹配函式
………………
}

3,driver_attach()

[cpp] view plaincopyprint?
  1. /**
  2. * driver_attach - try to bind driver to devices.
  3. * @drv: driver.
  4. *
  5. * Walk the list of devices that the bus has on it and try to
  6. * match the driver with each one.  If driver_probe_device()
  7. * returns 0 and the @dev->driver is set, we've found a
  8. * compatible pair.
  9. */
  10. int driver_attach(struct device_driver *drv) 
  11.     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);//注意這裡的__driver_attach
  12. EXPORT_SYMBOL_GPL(driver_attach); 
/**
 * driver_attach - try to bind driver to devices.
 * @drv: driver.
 *
 * Walk the list of devices that the bus has on it and try to
 * match the driver with each one.  If driver_probe_device()
 * returns 0 and the @dev->driver is set, we've found a
 * compatible pair.
 */
int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);//注意這裡的__driver_attach
}
EXPORT_SYMBOL_GPL(driver_attach);

上面真正起作用的是__driver_attach:

[cpp] view plaincopyprint?
  1. staticint __driver_attach(struct device *dev, void *data) 
  2.     struct device_driver *drv = data; 
  3.     /*
  4.      * Lock device and try to bind to it. We drop the error
  5.      * here and always return 0, because we need to keep trying
  6.      * to bind to devices and some drivers will return an error
  7.      * simply if it didn't support the device.
  8.      *
  9.      * driver_probe_device() will spit a warning if there
  10.      * is an error.
  11.      */
  12.     if (!driver_match_device(drv, dev)) 
  13.         return 0; 
  14.     if (dev->parent) /* Needed for USB */
  15.         device_lock(dev->parent); 
  16.     device_lock(dev); 
  17.     if (!dev->driver) 
  18.         driver_probe_device(drv, dev);//看下這個函式的實現過程
  19.     device_unlock(dev); 
  20.     if (dev->parent) 
  21.         device_unlock(dev->parent); 
  22.     return 0; 
  23. int driver_probe_device(structdevice_driver *drv, struct device *dev) 
  24. ... 
  25. //1.先是判斷bus是否match:
  26. if (drv->bus->match && !drv->bus->match(dev, drv)) 
  27.    goto done; 
  28. //2.再具體執行probe:
  29. ret = really_probe(dev, drv); 
  30. ... 
static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;

	/*
	 * Lock device and try to bind to it. We drop the error
	 * here and always return 0, because we need to keep trying
	 * to bind to devices and some drivers will return an error
	 * simply if it didn't support the device.
	 *
	 * driver_probe_device() will spit a warning if there
	 * is an error.
	 */

	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);

	return 0;
}
int driver_probe_device(structdevice_driver *drv, struct device *dev)
{
...
//1.先是判斷bus是否match:
if (drv->bus->match && !drv->bus->match(dev, drv))
   goto done;
//2.再具體執行probe:
ret = really_probe(dev, drv);
...
}

4,really_probe是我們真正要找的函式

[cpp] view plaincopyprint?
  1. staticint really_probe(struct device *dev, struct device_driver *drv) 
  2. …………………… 
  3. //1.先是呼叫的驅動所屬匯流排的probe函式:
  4.     if (dev->bus->probe) { 
  5.         ret = dev->bus->probe(dev); 
  6.         if (ret) 
  7.             goto probe_failed; 
  8.     }  
  9. //2.再呼叫的驅動中的probe函式:
  10.     elseif (drv->probe) { 
  11.         ret = drv->probe(dev); 
  12.         if (ret) 
  13.             goto probe_failed; 
  14.     } 
  15.     driver_bound(dev); 
  16.     ret = 1; 
  17.     pr_debug("bus: '%s': %s: bound device %s to driver %s\n"
  18.          drv->bus->name, __func__, dev_name(dev), drv->name);//這個資訊可以看到我們註冊的總 驅動、裝置和匯流排  資訊
  19.     goto done; 
  20. ……………… 
static int really_probe(struct device *dev, struct device_driver *drv)
{
……………………
//1.先是呼叫的驅動所屬匯流排的probe函式:
	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} 
//2.再呼叫的驅動中的probe函式:
	else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}

	driver_bound(dev);
	ret = 1;
	pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);//這個資訊可以看到我們註冊的總 驅動、裝置和匯流排  資訊
	goto done;
………………
}

打印出的驅動裝置資訊如:

………………

[    0.588087] bus: 'platform': really_probe: bound device power.0to driverpower  //匯流排:platform  裝置:power.0  驅動:power
[    0.661226] bus: 'platform': really_probe: bound device s3c24xx-pwm.0 to driver s3c24xx-pwm
[    0.678552] bus: 'platform': really_probe: bound device s3c24xx-pwm.1 to driver s3c24xx-pwm
[    0.695971] bus: 'platform': really_probe: bound device s3c24xx-pwm.2 to driver s3c24xx-pwm
[    0.713389 bus: 'platform': really_probe: bound device s3c24xx-pwm.3 to driver
……………………

相關推薦

i2c_driver註冊probe探測函式呼叫

       每一個驅動程式都有 module_init(xxxx_init) 這個語句,它代表系統啟動的時候會自動執行 xxxx 這個函式,也就是說驅動的人口函式是由module_init來定義的。當然還有module_exit(XXXX),它代表系統解除安裝驅動時呼叫

win7 64 DLL的遠端注入技術 注入dll函式呼叫

一、DLL注入 DLL的遠端注入技術是目前Win32病毒廣泛使用的一種技術。使用這種技術的病毒體通常位於一個DLL中,在系統啟動的時候,一個EXE程式會將這個DLL載入至某些系統程序(如Explorer.exe)中執行。 這樣一來,普通的程序管理器就很難發現這種病毒了,

platform_device和platform_driver的註冊過程,probe函數何時調用的分析 ???

size strong ive () str bsp 虛擬空間 insmod 一個地方 add platform_device之後,需要註意的一個地方是這裏,add是通過系統初始化裏邊調用platform_add_devices把所有放置在板級platform_devic

sqlalchemy使用相關查詢函式呼叫

sqlalchemy資料庫連線池的使用方式是延遲初始化,就是說一開始你呼叫create_engine(...)後建立的那個資料庫池是空的,你後面通過session.connection()或者engine.connect()才開始建立連線, 每當你建立一個連線,你呼叫engine.pool.st

c# 窗體啟動後自動執行 Form_Load事件註冊呼叫

很多時候我們需要在程式一開始後立即觸發執行一些程式。這時候需要呼叫Form_Load。 首先編寫事件程式塊,編寫完後即可再裡面新增需要執行的程式碼。 在結構體之後寫就行。新增之前的程式碼如下: 新增之後: 然後註冊事件。我寫到窗體初始化之後。註冊語句如下: 貼出程

vue 父子之間函式呼叫引數接收

1.子元件呼叫父元件函式 在父元件裡面進行定於函式 export default { provide(){ return { reload:this.reload,

C函式呼叫過程彙編分析

C程式碼: int fun(int para) {     int a=0;     return 0; } void main() {     fun(1); } 彙編程式碼: 1:

個人js學習例項-點選按鈕實現全選與反選,封裝函式呼叫前後

原始: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="wid

C++父類子類轉化函式呼叫

     這些天分析OGRE原始碼,裡面有關C++繼承及父類子類轉化運用,筆記記錄如下: 一 子類轉化父類      這裡的”轉化“不是真正的轉化,是一種形式上的轉化,主要用於多型,定義父子類函式如下: #include "stdafx.h" #include <

multiprocess模組使用程序池呼叫apply_async()提交的函式回撥函式不執行問題

使用multiprocesss模組遇到各種各樣的問題,這次遇到的問題是呼叫程序池物件的 apply_async() 方法,往程序池傳遞一個例項方法(該例項方法裡有一段程式碼是往同步佇列裡放入資料),然後發現往程序池扔的任務(即例項方法)不會被執行,回撥方法也

x86-64 下函式呼叫棧幀原理

一蓑一笠一扁舟,一丈絲綸一寸鉤。 一曲高歌一樽酒,一人獨釣一江秋。 —— 題秋江獨釣圖 緣起 在 C/C++ 程式中,函式呼叫是十分常見的操作。那麼,這一操作的底層原理是怎樣的?編譯器幫我們做了哪些操作?CPU 中各暫存器及記憶體堆疊

python之追溯函式呼叫錯誤日誌詳細列印

目錄 一、函式呼叫追溯 1.1 原因         在列印日誌時,為實現日誌分層列印,將列印日誌的語句封裝到了print_log_info以及print_log_error中。但是如果在上述函式中直接通過logger.*列印日誌,日誌中的模

函式呼叫約定函式名修飾規則

函式呼叫約定:是指當一個函式被呼叫時,函式的引數會被傳遞給被呼叫的函式和返回值會被返回給呼叫函式。函式的呼叫約定就是描述引數是怎麼傳遞和由誰平衡堆疊的,當然還有返回值。 幾種型別:__stdcall,__cdecl,__fastcall,__thiscall,__n

openstack核心路由和擴充套件路由路由對應的api函式呼叫流程分析

找到對應的url為server的routes: 由之前文章對wsgi的route對映關係分析可以,對應程式碼為該controller的create()方法:詳情請自行參考文章:wsgi-restful-routes詳解 至此則到達了nova模組的底層create()api呼叫。 3、鑑於o

c#呼叫c++dll介面回撥函式

在合作開發時,C#時常需要呼叫C++DLL,當傳遞引數時時常遇到問題,尤其是傳遞和返回字串是,現總結一下,分享給大家: VC++中主要字串型別為:LPSTR,LPCSTR, LPCTSTR, string, CString, LPCWSTR, LPWSTR等 但轉為C#

同步、非同步、堵塞、非堵塞和函式呼叫I/O之間的組合概念

        在我們工作和學習中,經常會接觸到“同步”、“非同步”、“堵塞”和“非堵塞”這些概念,但是並不是每個人都能將它們的關係和區別說清楚。本文將對這些基本概念進行討論,以期讓大家有更清楚的認識。(轉載請指明出於breaksoftware的csdn部落格)      

C語言函式呼叫棧幀結構

一、地址空間與實體記憶體 (1)地址空間與實體記憶體是兩個完全不同的概念,真正的程式碼及資料都存在實體記憶體中。 物理儲存器是指實際存在的具體儲存器晶片,CPU在操縱物理儲存器的時候都把他們當做記憶體來對待,把他們看成由若干個儲存單元組成的邏輯儲存器,這個邏

Hive中建立和呼叫儲存過程自定義函式

前面的文章《在Hive中實現儲存過程–HQL/SQL》中介紹瞭如何使用HPL/SQL在Hive中實現儲存過程,執行類似Oracle PL/SQL的功能。 一般的業務場景是資料開發人員開發好一個儲存過程,然後週期性的呼叫,傳入不同的引數即可。 本文繼續介紹如何在Hive中利

linux核心netfilter模組分析之:HOOKs點的註冊呼叫

-1: 為什麼要寫這個東西?最近在找工作,之前netfilter 這一塊的程式碼也認真地研究過,應該每個人都是這樣的你懂 不一定你能很準確的表達出來。 故一定要化些時間把這相關的東西總結一下。 0:相

C++基礎知識:c 函式呼叫過程原理函式棧幀分析

1.關於棧   首先必須明確一點也是非常重要的一點,棧是向下生長的,所謂向下生長是指從記憶體高地址->地地址的路徑延伸,那麼就很明顯了,棧有棧底和棧頂,那麼棧頂的地址要比棧底低。對x86體系的CPU而言,其中   ---> 暫存器ebp(base pointer