
一個i2c裝置驅動的實作過程: 1首先在裝置樹中配置,将裝置挂載i2c總線的裝置樹節點上,如下圖中的my_i2c@68節點:
2那麼裝置樹配置好了,接下來就該開始寫我們的裝置驅動了,第一步該幹什麼呢,首先你得執行個體化一個i2c_driver驅動對象,如下:
- staticstruct i2c_driver my_i2c_client_driver={
- .driver={
- .name="my_i2c",
- .owner= THIS_MODULE,
- .of_match_table= my_i2c_client_match_table,
- },
- .id_table= my_i2c_client_id,
- .probe= my_i2c_client_probe,
- .remove= my_i2c_client_remove,
- };
這個driver中有一個of_match_table,還有一個id_table,到底他們有什麼用,是不是必須的後面會講到,先來看看他們長什麼樣子
- staticconststruct i2c_device_id my_i2c_client_id[]={
- {"my_i2c",0},
- {}
- };
- staticstruct of_device_id my_i2c_client_match_table[]={
- {.compatible="my_i2c",},
- {},
- };
從上面的類圖可以看到,i2c_driver其實相當于繼承于device_driver,其中這個of_match_table是device_driver的成員,在裝置與驅動的比對過程中,優先級高于i2c_driver的id_table,什麼意思呢,後面慢慢講,先還是來看建立一個簡單的i2c裝置驅動的過程吧! 3i2c_driver對象執行個體話之後,就需要填充這個對象的proble,remove等函數了,probe函數會在裝置與驅動比對成功後調用,remove函數會在裝置解除安裝後調用。這兩個函數實作好以後,接下來将這個driver注冊進系統就好了,注冊代碼如下
- module_i2c_driver(my_i2c_client_driver);
這樣一個簡單的i2c裝置驅動的架構就搭建好了 那下面來具體分析一下我們所關注的問題吧,這個of_match_table 和id_table有什麼用,在什麼時候用,缺一不可嗎? 在比對裝置的時候,系統會首先會檢查是調用of_driver_match_device,檢查of_match_table中是否包含該裝置,包含就比對成功直接傳回,如果比對失敗後,會繼續檢查id_table,如果包含該裝置,就比對成功并傳回,否則比對失敗,傳回-ENODEV 到這大家是不是覺得兩個table有其中任何一個都可以保證比對成功呀,答案是肯定的,就比對過程而言,兩個table描述其中一個都能導緻比對成功,但是你會發現,缺少id_table的時候你寫的裝置驅動程式的probe不會調用,這是為什麼呢,下面我們來看一下比對過程牛逼的時序圖
從上圖可以看出來,要想自己的驅動的probe能被調用,必須要配置id_table,如果不配置id_table,在i2c_device_probe中發現沒有id_table,直接就傳回了,到這是不是豁然開朗了呢! 那麼接下來大家肯定會疑惑,到底什麼時候系統會調用這個match過程,那我們就從我們的驅動程式注冊開始說起,讓大家了解整個來龍去脈! 老樣子,還是先看牛逼的時序圖
從途中可以看到,match實在注冊到總線的過程中去調用的。 driver注冊成功以後,系統會周遊總線上說有的adapter,并檢測總線上支援的裝置,并去執行個體化這些裝置的adapter,并做填充,如果向我們前面的一樣通過裝置樹的方式配置過了,這個檢測直接傳回成功,因為client與adapter的綁定過程在解析裝置樹之後就已經綁定。 那麼這個i2c_client是在哪個階段建立的呢,在裝置樹或者i2c_board_info中配置以後,系統會調用i2c_new_device建立i2c_client,如果知道這個裝置連結在i2c總線上,但是又不知道這個裝置的位址,會調用i2c_new_probed_device建立。 寫到這,大家是不是對i2c裝置驅動的整個來龍去脈都了解的差不多了呢。