函数来源于Linux设备驱动开发详解.pdf。
spin_lock_irq
和spin_unlock_irq
用于保护临界区,防止在访问共享资源时发生中断或上下文切换。
// 18. 定义一个名为`s3c24xx_i2c_do_xfer`的静态函数,用于执行I2C数据传输。
// 参数包括:
// - `struct s3c24xx_i2c *i2c`: I2C控制器的私有数据结构。
// - `struct i2c_msg *msgs`: 指向I2C消息数组的指针。
// - `int num`: 消息数组中的条目数量。
static int s3c24xx_i2c_do_xfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num)
{
// 20-21. 声明一个无符号长整型变量`timeout`和整型变量`ret`,分别用于超时时间和函数返回值。
unsigned long timeout;
int ret;
// 23. 设置I2C为主机模式,调用`s3c24xx_i2c_set_master`函数。
s3c24xx_i2c_set_master(i2c);
// 25-26. 如果设置主机模式失败或发生错误,则跳转到标签`out`结束函数。
if (test_bit(S3C24XX_I2C_STAT_ERR, &i2c->stat))
goto out;
// 27. 进入临界区,锁定中断,以安全地访问共享资源。
spin_lock_irq(&i2c->lock);
// 30-31. 保存传入的消息数组和消息数量到I2C设备结构体中。
i2c->msg = msgs;
i2c->msg_num = num;
// 32. 初始化消息指针。
i2c->msg_ptr = msgs;
// 33. 初始化消息索引为0。
i2c->msg_idx = 0;
// 34. 设置I2C状态为开始状态。
i2c->state = STATE_START;
// 35. 启用I2C中断。
s3c24xx_i2c_enable_irq(i2c);
// 36. 初始化并开始处理I2C消息队列。
s3c24xx_i2c_message_start(i2c, msgs);
// 37. 释放自旋锁,恢复之前的中断状态。
spin_unlock_irq(&i2c->lock);
// 38-39. 使用`wait_event_timeout`宏定义的超时等待机制,等待消息传输完成或超时。
timeout = wait_event_timeout(i2c->wait, (i2c->msg_idx >= num), max_timeout, HZ/10);
// 40-41. 保存消息索引到返回值`ret`。
ret = i2c->msg_idx;
// 44. 如果超时发生,输出调试信息到设备日志。
if (timeout == 0)
dev_dbg(i2c->dev, "timeout, msg_idx=%d, msg_num=%d\n", i2c->msg_idx, i2c->msg_num);
// 45-46. 如果消息传输不完整,输出调试信息到设备日志。
else if (ret < num)
dev_dbg(i2c->dev, "incomplete transfer, msg_idx=%d, msg_num=%d\n", ret, num);
// 47. 如果需要,确保发送停止条件。
// 49. 跳转到标签`out`,结束函数。
// 50. 清理并退出函数,返回`ret`。
out:
return ret;
}