函数来源于来源于Linux设备驱动开发详解.pdf。
// 1. 定义中断处理函数`s3c24xx_i2c_irq`,该函数用于处理S3C2410 I2C适配器的中断。
// 参数包括:
// - `irq`: 中断号。
// - `void *dev_id`: 传递给请求中断处理函数的设备标识符。
// - `struct pt_regs *regs`: 指向程序状态寄存器的指针,包含中断发生时的上下文信息。
static irqreturn_t s3c24xx_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)
{
// 3. 声明一个指向`s3c24xx_i2c`结构的指针`i2c`,用于访问I2C设备的私有数据。
struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)dev_id;
// 5-7. 声明两个无符号长整型变量`status`和`tmp`,用于存储从寄存器读取的状态信息。
unsigned long status;
unsigned long tmp;
// 8-9. 读取I2C状态寄存器的值,并存储到`status`变量中。
// `S3C2410_IICSCON`是I2C状态寄存器的偏移。
status = readl(i2c->regs + S3C2410_IICSCON);
// 10-11. 检查状态寄存器中的仲裁丢失位。
// `S3C24XX_I2CSTAT_ARBITR`是仲裁丢失的状态位掩码。
if (status & S3C24XX_I2CSTAT_ARBITR)
// 12-13. 如果发生仲裁丢失,处理相关逻辑。
// `STATE_TX_RX`可能是用于标识I2C总线状态的一个宏。
if (i2c->state == STATE_TX_RX)
// 14-16. 清除I2C控制寄存器中的低功耗模式和中断挂起位。
// `S3C2410_IICCON`是I2C控制寄存器的偏移。
// `tmp`变量用于临时存储控制寄存器的值。
tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_TICCON_LPENPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
// 17. 跳转到标签`out`,结束中断处理。
goto out;
// 18-24. 这部分代码似乎是一个条件执行块,用于在特定条件下调用`s3c_i2c_nextbyte`函数
// 以推进传输工作。但代码不完整,无法提供准确的注释。
// 23. 如果满足某个条件,则返回`IRQ_HANDLED`,表示中断已被处理。
// `IRQ_HANDLED`是一个宏,用于标识中断处理成功。
return IRQ_HANDLED;
// 24. 标签`out`,用于结束中断处理函数。
out:
return 0;
}
// 26. 定义一个名为`i2s_s3c_irq_nextbyte`的静态函数,用于处理I2C中断并推进数据传输。
// 参数包括:
// - `struct s3c24xx_i2c *i2c`: 指向I2C控制器私有数据的指针。
// - `unsigned long cstat`: 当前I2C的状态。
static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long cstat)
{
// 28-29. 声明局部变量`tmp`(无符号长整型),`byte`(无符号字符型),`ret`(整型)。
unsigned long tmp;
unsigned char byte;
int ret = 0;
// 32. 使用`switch`语句根据`i2c`结构中的`state`成员来处理不同的I2C状态。
switch (i2c->state)
{
// 33-35. 如果状态是`STATE_IDLE`(空闲状态),直接跳到函数末尾结束。
case STATE_IDLE:
goto out;
break;
// 37-39. 如果状态是`STATE_STOP`(停止状态),禁用I2C中断,然后跳到末尾。
case STATE_STOP:
s3c24xx_i2c_disable_irq(i2c);
goto out_ack;
break;
// 40-42. 如果状态是`STATE_START`(开始状态),检查是否需要启动新的消息。
// 如果收到的最后一个位是开始位,并且没有收到ACK,则发送停止条件。
case STATE_START:
if (cstat & S3C2410_IICSTAT_LASTBIT &
i2c->flags & I2C_M_RD)
{
// 没有收到ACK,发送远程I/O错误并停止。
s3c24xx_i2c_stop(i2c, -EREMOTEIO);
goto out_ack;
}
// 48-53. 根据消息的读取/写入标志设置状态为读或写。
if (i2c->msg->flags & I2C_M_RD)
i2c->state = STATE_READ;
else
i2c->state = STATE_WRITE;
// 54-56. 如果是最后一条消息,发送停止条件。
if (is_lastmsg(i2c))
s3c24xx_i2c_stop(i2c, 0);
break;
// 59-85. 处理读和写状态,包括发送数据、接收数据、处理ACK等。
case STATE_WRITE:
// 64-66. 发送当前消息缓冲区的第一个字节。
byte = i2c->msg->buf[i2c->msg_ptr++];
writeb(byte, i2c->regs + S3C2410_IICDS);
// 68-85. 如果是当前消息的最后,检查是否需要发送停止条件或继续。
if (is_lastmsg(i2c))
{
// 处理停止条件或继续到下一条消息的逻辑。
}
break;
case STATE_READ:
// 90-123. 处理读取一个字节的情况,包括检查ACK、读取数据、处理消息结束等。
if (/* 条件 */)
{
// 处理读取的逻辑。
}
break;
// 其他状态和默认情况的处理...
}
// 125-128. 在退出前,清除中断挂起位并写回控制寄存器。
tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_IICCON_IROPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
// 129. 返回函数的返回值。
out:
return ret;
// 其他标签用于不同退出点...
out_ack:
// 处理ACK的退出逻辑。
}