說時遲,那時快,馬上進入I2C驅動的最後一個小節了,在這個小節裏,我們主要探討i2c_algorithm 數據結構和i2c-core.c 的一些主要函數及其作用。有鑑於i2c-core.c 代碼達2000行,所以本文僅對導出的函數(EXPORT_SYMBOL)進行簡單註釋,其它函數想必也是爲前者服務的啦。好,馬上進入正題:
i2c_algorithm 結構體
一個 i2c 適配器上的i2c 總線通信方法由其驅動程序提供的i2c_algorithm 數據結構描述,由algo 指針指向。i2c_algorithm 數據結構即爲i2c_adapter 數據結構與具體i2c 適配器的總線通信方法的中間層,正是這個中間層使得上層的i2c 框架代碼與與具體i2c 適配器的總線通信方法無關,從而實現了i2c 框架的
可移植性和重用性。當安裝具體i2c 適配器的驅動程序時由相應驅動程序實現具體的i2c_algorithm 數據結構,其中的函數指針指向操作具體i2c 適配器的代碼。
master_xfer/smbus_xfer 指針指向i2c 適配器驅動程序模塊實現的i2c 通信協議或者smbus 通信協議。在用戶進程通過i2c-dev 提供的/dev/i2c/%d 設備節點訪問i2c 設備時,最終是通過調用
master_xfer 或者smbus_xfer 指向的方法完成的。
i2c-core.c
i2c.h 和i2c-core.c 爲i2c 框架的主體,提供了核心數據結構的定義、i2c 適配器驅動和設備驅
動的註冊、註銷管理,i2c 通信方法上層的、與具體適配器無關的代碼、檢測設備地址的上層代碼等;
i2c-dev.c 用於創建i2c 適配器的/dev/i2c/%d 設備節點,提供i2c 設備訪問方法等。
下面介紹其主要的函數
函數i2c_init
主要做了以下幾件事情:
1.i2c_add_driver(&dummy_driver);
註冊i2c總線
2.class_compat_register("i2c-adapter");
註冊一個可兼容的類
3.i2c_add_driver(&dummy_driver);
加載驅動
函數i2c_exit
這個就不解釋了呀~~
結構體i2c_bus_type
本結構體被導出,其裏面包含了6個函數,其作用看名字就能猜到個大概。下面貼出以上6個函數的代碼。
函數i2c_add_adapter
函數主要作用是添加一個適配器
1.idr_get_new_above(&i2c_adapter_idr, adapter,
__i2c_first_dynamic_bus_num, &id);
確認是否還能分配得到適配器id,該操作不能被打斷。
2.i2c_register_adapter(adapter);
註冊一個適配器
函數i2c_del_adapter
對應於i2c_add_adapter,此函數刪除一個適配器。
函數 i2c_register_driver
註冊一個設備
1.driver_register(&driver->driver);
開始先註冊一個設備
2.bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
調用相對應的__attach_adapter 函數,並傳遞參數driver 給它。完成設備綁定適配器的動作。至於__attach_adapter 的代碼粘貼如下
函數i2c_del_driver
相對應i2c_register_driver,本函數執行卸載設備的動作。
1.bus_for_each_dev(&i2c_bus_type, NULL, driver, __detach_adapter);
調用__detach_adapter 函數,並傳遞函數driver 給它,完成分離設備和適配器的功能。
2.driver_unregister(&driver->driver);
卸載設備。
__detach_adapter 代碼如下
最後來看3個重要的i2c總線操作函數
函數 i2c_transfer
該函數幾乎與 i2c_master_recv 和i2c_master_send (接下來馬上敘述)函數一模一樣,都是在持有i2c_adapter 的lock 信號量的情況下利用i2c 適配器的algo 所指的i2c_algorithm 數據結構的master_xfer 方法執行實際的i2c 操作。
整個函數最重要的,當數for 循環裏面的內容,而for 循環裏面的內容,最最重要的,肯定就是
ret = adap->algo->master_xfer(adap, msgs, num); 經過前文提及的內容,master_xfer用於產生I2C訪問週期需要的信號,以I2C消息爲單位。
函數 i2c_master_send
把需要發送的數據以及其信息保存到msg 結構體,通過i2c_transfer 函數發送。
函數 i2c_master_recv
跟發送函數i2c_master_send 對應的一個接收函數,具體不作解釋啦。
由於篇幅問題,故不能肆意展開全部代碼,但我還是在這裏羅列一下關於smbus協議需要注意的函數:
s32 i2c_smbus_read_byte(struct i2c_client *client);
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value);
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value);
s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command);
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value);
s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,
u8 *values);
s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
u8 length, const u8 *values);
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
unsigned short flags,
char read_write, u8 command, int size,
union i2c_smbus_data * data);
以上一系列的函數,都是在i2c_smbus_xfer 函數的基礎上建立起來的,只要理解了基石,其上的函數就不足爲懼了。最後的最後,看一下這個藏在代碼最後的基石吧!
函數 i2c_smbus_xfer
該函數通過適配器驅動提供的總線訪問方法(i2c_algorithm 的smbus_xfer 方法)嘗試訪問處於addr 地址上的設備。其實函數裏面最核心的一句是:
res = adapter->algo->smbus_xfer(adapter, addr, flags,
read_write, command,
protocol, data);
哈哈,這豈不妙哉,到最後我們還是回到結構體i2c_algorithm 的smbus_xfef 成員函數(見本文起始部分)。真是衆裏尋他千百度,驀然回首,此函數卻在燈火闌珊處。
經過這一個i2c系列4個小節的學習,自己對代碼的分析,特別是驅動代碼的分析有了一定的提高,起碼在心理上不會感到畏懼。希望各位初學的朋友能夠跟我一起堅持下去,踏踏實實地走好每一步!
本系列博文鏈接:
I2C驅動(1)http://blog.csdn.net/jarvis_xian/archive/2011/05/27/6449939.aspx
I2C驅動(2)http://blog.csdn.net/jarvis_xian/archive/2011/05/27/6451168.aspx
I2C驅動(3)http://blog.csdn.net/jarvis_xian/archive/2011/05/28/6452431.aspx
I2C驅動(4)http://blog.csdn.net/jarvis_xian/archive/2011/05/30/6455697.aspx