linux i2c_driver 結構體解析

本文主要轉載自:http://blog.csdn.net/string19820108/article/details/7236854

驅動程序的主要工作就是定義並初始化一個i2c_driver結構體(定義於i2c.h中),i2c_driver的成員參考下面。

struct i2c_driver {
unsigned int
class;
/* Notifies the driver that a new bus has appeared. You should avoid
* using this, it will be removed in a near future. */
int (*
attach_adapter)(struct i2c_adapter *) __deprecated;
/* Standard driver model interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration  */
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag"). */
void (*alert)(struct i2c_client *, unsigned int data);
/* a ioctl like command that can be used to perform specific functions
* with the device. */
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driverdriver;
const struct i2c_device_id *id_table;
/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_headclients;
}; 
i2c_driver中的driver成員至少應該初始化它的name成員。

Legacy model的驅動i2c_driver的函數指針至少應該初始化attach_adapter和detach_ client,另外attach_adapter會使用example_attach函數,這個函數主要是將我們的client註冊到系統中。這兩個函數指針對應的函數實現比較固定。

Standard driver model的驅動需要註冊板級信息。板級信息必須要有driver的id name還有設備的7位從機地址。驅動中不再需要創建i2c_client結構體,它是由i2c內核創建的。驅動中不需要定義設備的地址,取而代之的是i2c_device_id,用來保存支持的設備類型。這裏面保存的設備名將會和板級信息中註冊的i2c_board_info的名字進行比較,在i2c_device_id中存在的名字才能依附於本驅動。i2c_driver函數指針成員只需要初始化probe和remove就就夠了。其它的函數都是可選的。特別需要注意的是,如果同時初始化兩種模式需要用到的i2c_driver的成員,那麼會報錯,因爲i2c內核無法判斷是哪種模式的驅動i2c_driver中的probe、remove、detect任何一個被初始化意味着這是一個Standard driver model模式的驅動,attach_adapter和detach_adapter絕對不可以初始化。

PS: Linux下的i2c驅動的編寫有兩種類型:Legacy modelStandard driver modelnew style)。

第一種風格的驅動需要自己創建i2c_client,並且需要驅動作者知道i2c設備的地址。第二種風格的驅動不需要自己創建i2c_client,但是需要填寫支持的設備列表或者支持設備的地址列表。

另外,i2c_driver的shutdown、suspend、resume這三個函數指針是否初始化是可選的。這三個函數指針分別對應關機、掛起、喚醒。

如果已經將i2c驅動正確的編譯並插入內核,那麼內核中提供了一些接口和設備通信:

extern int i2c_master_send(struct i2c_client *client, const char* buf, int len);

extern int i2c_master_recv(struct i2c_client * client,char* buf, int len);

這兩個函數都是讓client對應的適配器以主機的身份和client->addr地址的設備進行通信,返回值是實際讀寫的字節數。Linux下的i2c適配器不支持從機模式。

上面的兩個函數有個弊端,那就是隻能完成單方向的通信,如果通信的過程既有發送又有接收而且接收和發送不能分開,那就需要調用另一個函數:

extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num);

實際上,上面兩個函數也是直接調用了i2c_transfer。

i2c_transfer中的參數有三個,第一個是適配器結構體的指針,第二個是消息數組的頭指針,第三個是消息的數量。這個函數發送一系列的消息。每個消息可以是讀,也可以是寫,也可以混合。發送過程是連貫的,在發送中沒有停止條件。它的返回值是成功執行的消息數目。

消息的格式定義如下。

struct i2c_msg {
         __u16 addr; // slave address
         __u16 flags;
#define I2C_M_TEN                                0x0010       //10bit地址
#define I2C_M_RD                                  0x0001       //讀取數據標誌,清零表示寫
#define I2C_M_NOSTART                     x4000         //不發送起始位
#define I2C_M_REV_DIR_ADDR        0x2000       // 反轉讀寫標誌
#define I2C_M_IGNORE_NAK            x1000         //忽略I2C器件的ack和nack信號
#define I2C_M_NO_RD_ACK               0x0800       //讀操作時不去ACK
#define I2C_M_RECV_LEN                   0x0400       //length will be first received byte
         __u16 len; // msg length
         __u8 *buf; // pointer to msg data
};
flags各位的含義已經用宏定義好了。如果連續多條消息的話,除了第一條之外,餘下的都不需要發送起始條件。 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章