介紹
因為不是每個I2C或SMBus適配器都實現了I2C規范中的所有內容,當client被賦予附加到適配器的選項時,它不能相信它需要的所有東西都實現了:client需要一些方法來檢查適配器是否具有所需的功能。
功能常量
關於最新的功能常量列表,請查看<uapi/linux/i2c.h>!
I2C_FUNC_I2C |
純i2c-level命令(純SMBus適配器通常不能執行這些命令) |
I2C_FUNC_10BIT_ADDR |
處理10位地址擴展 |
I2C_FUNC_PROTOCOL_MANGLING |
了解I2C_M_IGNORE_NAK, I2C_M_REV_DIR_ADDR 和 I2C_M_NO_RD_ACK標志(修改I2C協議!) |
I2C_FUNC_NOSTART |
可以跳過重復的啟動順序 |
I2C_FUNC_SMBUS_QUICK |
處理SMBus write_quick命令 |
I2C_FUNC_SMBUS_READ_BYTE |
處理SMBus read_byte命令 |
I2C_FUNC_SMBUS_WRITE_BYTE |
處理SMBus write_byte命令 |
I2C_FUNC_SMBUS_READ_BYTE_DATA |
處理SMBus read_byte_data命令 |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
處理SMBus write_byte_data命令 |
I2C_FUNC_SMBUS_READ_WORD_DATA |
處理SMBus read_word_data命令 |
I2C_FUNC_SMBUS_WRITE_WORD_DATA |
處理SMBus write_byte_data命令 |
I2C_FUNC_SMBUS_PROC_CALL |
處理SMBus process_call命令 |
I2C_FUNC_SMBUS_READ_BLOCK_DATA |
處理SMBus read_block_data命令 |
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA |
處理SMBus write_block_data命令 |
I2C_FUNC_SMBUS_READ_I2C_BLOCK |
處理SMBus read_i2c_block_data命令 |
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
處理SMBus write_i2c_block_data命令 |
為了方便起見,還定義了上述標志的一些組合:
I2C_FUNC_SMBUS_BYTE |
處理SMBus read_byte和write_byte命令 |
I2C_FUNC_SMBUS_BYTE_DATA |
處理SMBus read_byte_data和write_byte_data命令 |
I2C_FUNC_SMBUS_WORD_DATA |
處理SMBus read_word_data和write_word_data命令 |
I2C_FUNC_SMBUS_BLOCK_DATA |
處理SMBus read_block_data和write_block_data命令 |
I2C_FUNC_SMBUS_I2C_BLOCK |
處理SMBus read_i2c_block_data和write_i2c_block_data命令 |
I2C_FUNC_SMBUS_EMUL |
處理所有可以由真正的I2C適配器模擬的SMBus命令 (使用透明仿真層) |
在3.5之前的內核版本中,I2C_FUNC_NOSTART作為I2C_FUNC_PROTOCOL_MANGLING的一部分實現。
適配器(Adapter)實現
當您編寫一個新的適配器驅動程序時,您必須實現一個函數回調功能。下面給出了典型的實現。
典型的僅SMBus適配器將列出它支持的所有SMBus事務。這個例子來自於i2c-piix4驅動程序:
static u32 piix4_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA; }
典型的 full-I2C 適配器將使用以下內容(來自i2c-pxa驅動程序):
static u32 i2c_pxa_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; }
I2C_FUNC_SMBUS_EMUL包含了所有的SMBus事務(添加了I2C塊事務),i2c-core可以使用I2C_FUNC_I2C模擬這些事務,而無需適配器驅動程序的任何幫助。其思想是讓客戶端驅動程序檢查對SMBus函數的支持,而不必關心所述函數是由適配器在硬件中實現的,還是由i2c-core 在I2C適配器上軟件模擬的。
Client 檢查
在client嘗試附加到adapter,或甚至進行測試以檢查其支持的某個設備是否存在於adapter上之前,應該檢查所需的功能是否存在。典型的方法是(從lm75驅動程序摘錄):
static int lm75_detect(...) { (...) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) goto exit; (...) }
在這里,lm75驅動程序檢查適配器是否可以同時執行SMBus字節數據和SMBus字數據事務。如果沒有,那么驅動程序將不能在這個適配器上工作,也就沒有繼續下去的意義。如果上面的檢查成功,那么驅動程序知道它可以調用以下函數: i2c_smbus_read_byte_data(), i2c_smbus_write_byte_data(), i2c_smbus_read_word_data() 和 i2c_smbus_write_word_data()。作為經驗法則,用 i2c_check_functions() 測試的功能常量應該與驅動程序調用的 i2c_smbus_* 函數完全匹配。
注意,上面的檢查並不能說明這些功能是由底層適配器在硬件中實現的,還是由 i2c-core 在軟件中模擬的。Client 驅動程序不必關心這一點,因為 i2c-core 將在I2C適配器上透明地實現SMBus事務。
通過/dev檢查
如果試圖從用戶空間程序訪問適配器,則必須使用/dev接口。當然,您仍然需要檢查您需要的功能是否得到支持。這是使用I2C_FUNCS ioctl完成的。下面是一個改編自i2cdetect程序的示例:
int file; if (file = open("/dev/i2c-0", O_RDWR) < 0) { /* Some kind of error handling */ exit(1); } if (ioctl(file, I2C_FUNCS, &funcs) < 0) { /* Some kind of error handling */ exit(1); } if (!(funcs & I2C_FUNC_SMBUS_QUICK)) { /* Oops, the needed functionality (SMBus write_quick function) is not available! */ exit(1); } /* Now it is safe to use the SMBus write_quick command */