前面我们已经说过i2c适配器的具体通信操作时靠struct io_algorithm来实现的。struct io_algorithm的结构非常简单只有三个成员master_xfer只要勇于i2c,smbus_xfer勇于smbus,functionality发挥适配器所提供的功能,在drivers/i2c/algos下提供了常用的struct io_algorithm的实现。前面我们在对驱动中的地址列表的探测中就用到i2c_smbus_xfer这个函数,这里就是让适配器来执行一次操作,我们具体来看看代码:
/**
* i2c_smbus_xfer - execute SMBus protocol operations
* @adapter: Handle to I2C bus
* @addr: Address of SMBus slave on that bus
* @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC)
* @read_write: I2C_SMBUS_READ or I2C_SMBUS_WRITE
* @command: Byte interpreted by slave, for protocols which use such bytes
* @protocol: SMBus protocol operation to execute, such as I2C_SMBUS_PROC_CALL
* @data: Data to be read or written
*
* This executes an SMBus protocol operation, and returns a negative
* errno code else zero on success.
*/
s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
union i2c_smbus_data * data)
{
s32 res;
unsigned short tmp;
flags &= I2C_M_TEN | I2C_CLIENT_PEC; //检测是否是10位地址或设置包错误检验标志
if (adapter->algo->smbus_xfer) {
mutex_lock(&adapter->bus_lock);
res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, //如果适配器是smbus总线则调用这个函数
command, protocol, data);
mutex_unlock(&adapter->bus_lock);
} else
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, //i2c总线的情况
command, protocol, data);
return res;
}
这里我们对smbus适配器的情况不做具体分析,而且是直接调用struct io_algorithm中的成员函数,i2c交互主要最终是调用i2c_transfer,然后这个函数中调用struct io_algorithm 中的master_xfer成员,交互中传递的阐参数主要是struct i2c_msg结构,而i2c_smbus_xfer_emulated函数的主要工作就是对各种操作情况下为i2c_transfer准备好参数,然后调用之,下面我们具体分析i2c_smbus_xfer_emulated源码:
/* Simulate a SMBus command using the i2c protocol
No checking of parameters is done! */
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)
{
/* So we need to generate a series of msgs. In the case of writing, we
need to use only one message; when reading, we need two. We initialize
most things with sane defaults, to keep the code below somewhat
simpler. */
// 从上面的解释中得到
//写操作只会进行一次交互,而读操作,有时会有两次操作.
//因为有时候读操作要先写command,再从总线上读数据
//在这里为了代码的简洁.使用了两个缓存区,将两种情况统一起来.
unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
int num = read_write == I2C_SMBUS_READ?2:1; //读写需要消息的个数
//与设备交互的数据,一般在msg[0]存放写入设备的信息,在msb[1]里存放接收到的信息.不过也有例外的
//msg[2]的初始化,默认发送缓存区占一个字节,无接收缓存
struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, //初始化两个消息默认发送缓存区占一个字节,无接收缓存
{ addr, flags | I2C_M_RD, 0, msgbuf1 }
};
int i;
u8 partial_pec = 0;
int status;
msgbuf0[0] = command;
switch(size) { //交互的字节数
//quick类型的,其它并不传输有效数据,只是将地址写到总线上,等待应答即可
//所以将发送缓存区长度置为0 .再根据读/写操作,调整msg[0]的标志位 ,根据前面的标志,这里肯定是写
//这类传输只需要一次总线交互
case I2C_SMBUS_QUICK:
msg[0].len = 0;
/* Special case: The read/write field is used as data */
msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
num = 1;
break;//BYTE类型指一次写和读只有一个字节.这种情况下,读和写都只会交互一次
//这种类型的读有例外,它读取出来的数据不是放在msg[1]中的,而是存放在msg[0]
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_READ) {
/* Special case: only a read! */
msg[0].flags = I2C_M_RD | flags;
num = 1;
}
break;//Byte_Data是指命令+数据的传输形式.在这种情况下,写只需要一次交互,读却要两次
//第一次将command写到总线上,第二次要转换方向.要将设备地址和read标志写入总线.
//应回答之后再进行read操作
//写操作占两字节,分别是command+data.读操作的有效数据只有一个字节
//交互次数用初始化值就可以了
case I2C_SMBUS_BYTE_DATA:
if (read_write == I2C_SMBUS_READ)
msg[1].len = 1;
else {
msg[0].len = 2;
msgbuf0[1] = data->byte;
}
break;//Word_Data是指命令+双字节的形式.这种情况跟Byte_Data的情况类似
//两者相比只是交互的数据大小不同
case I2C_SMBUS_WORD_DATA:
if (read_write == I2C_SMBUS_READ)
msg[1].len = 2;
else {
msg[0].len=3;
msgbuf0[1] = data->word & 0xff;
msgbuf0[2] = data->word >> 8; //高位在高字节
}
break;//Proc_Call的方式与write 的Word_Data相似,只不过写完Word_Data之后,要等待它的应答
//应该它需要交互两次,一次写一次读
case I2C_SMBUS_PROC_CALL:
num = 2; /* Special case */
read_write = I2C_SMBUS_READ;
msg[0].len = 3;
msg[1].len = 2;
msgbuf0[1] = data->word & 0xff;
msgbuf0[2] = data->word >> 8;
break;//Block_Data:指command+N段数据的情况.
//如果是读操作,它首先要写command到总线,然后再读N段数据.要写的command已经
//放在msg[0]了.现在只需要将msg[1]的标志置I2C_M_RECV_LEN位,msg[1]有效长度为1字节.因为
//adapter驱动会处理好的.现在现在还不知道要传多少段数据.
//对于写的情况:msg[1]照例不需要.将要写的数据全部都放到msb[0]中.相应的也要更新
//msg[0]中的缓存区长度
case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by
the underlying bus driver */
} else {//data->block[0]表示后面有多少段数据.总长度要加2是因为command+count+N段数据
msg[0].len = data->block[0] + 2;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
dev_err(&adapter->dev,
"Invalid block write size %d\n",
data->block[0]);
return -EINVAL;
}
for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
}
break;//Proc_Call:表示写完Block_Data之后,要等它的应答消息它和Block_Data相比,只是多了一部份应答而已
case I2C_SMBUS_BLOCK_PROC_CALL:
num = 2; /* Another special case */
read_write = I2C_SMBUS_READ;
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
dev_err(&adapter->dev,
"Invalid block write size %d\n",
data->block[0]);
return -EINVAL;
}
msg[0].len = data->block[0] + 2;
for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by
the underlying bus driver */
break;//I2c Block_Data与Block_Data相似,只不过read的时候,数据长度是预先定义好了的.另外
//与Block_Data相比,中间不需要传输Count字段.(Count表示数据段数目)
case I2C_SMBUS_I2C_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
msg[1].len = data->block[0];
} else {
msg[0].len = data->block[0] + 1;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
dev_err(&adapter->dev,
"Invalid block write size %d\n",
data->block[0]);
return -EINVAL;
}
for (i = 1; i <= data->block[0]; i++)
msgbuf0[i] = data->block[i];
}
break;
default:
dev_err(&adapter->dev, "Unsupported transaction %d\n", size);
return -EOPNOTSUPP;
}
i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK //没有数据
&& size != I2C_SMBUS_I2C_BLOCK_DATA); //不支持
if (i) {
/* Compute PEC if first message is a write */
if (!(msg[0].flags & I2C_M_RD)) {
if (num == 1) /* Write only */
//如果只有写操作,写缓存区要扩充一个字节,用来存放计算出来的PEC
i2c_smbus_add_pec(&msg[0]);
else /* Write followed by read */
//如果后面还有读操作,先计算前面写部份的PEC(注意这种情况下不需要
//扩充写缓存区,因为不需要发送PEC.只会接收到PEC)
partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
}
/* Ask for PEC if last message is a read */
if (msg[num-1].flags & I2C_M_RD)
msg[num-1].len++;
}
status = i2c_transfer(adapter, msg, num); //执行一个或几个消息的适配器操作
if (status < 0)
return status;
/* Check PEC if last message is a read */
//操作完了之后,如果最后一个操作是PEC的读操作.检验后面的PEC是否正确
if (i && (msg[num-1].flags & I2C_M_RD)) {
status = i2c_smbus_check_pec(partial_pec, &msg[num-1]);
if (status < 0)
return status;
}
if (read_write == I2C_SMBUS_READ) //把读到的数据返回
switch(size) {
case I2C_SMBUS_BYTE:
data->byte = msgbuf0[0];
break;
case I2C_SMBUS_BYTE_DATA:
data->byte = msgbuf1[0];
break;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < data->block[0]; i++)
data->block[i+1] = msgbuf1[i];
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
for (i = 0; i < msgbuf1[0] + 1; i++)
data->block[i] = msgbuf1[i];
break;
}
return 0;
}
i2c_transfer就是在适配器空闲的情况下调用master_xfer完成实际操作。