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)
{
}
其中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把驅動註冊到匯流排
- /**
- * 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驅動,註冊到匯流排
- ……………………
- }
/**
* 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,驅動註冊到匯流排的實現函式
- /**
- * 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); //驅動的匹配函式
- ………………
- }
/**
* 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?- /**
- * 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 - 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?- staticint __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);
- ...
- }
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?- staticint 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函式:
- elseif (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;
- ………………
- }
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