"阻塞--中断"驱动模型在i2c在子系统、uart驱动、spi子系统中的实现

来源:互联网 发布:软件开发助理工程师 编辑:程序博客网 时间:2024/05/17 23:21

最近总结了这个kernel中的这个模型,下面我们 开始欣赏吧。

先看i2c中的实现

我们需要明白的是 :

     1. 进程为什么要阻塞     2.  阻塞后又是 在什么时候被唤醒的?     3. 从阻塞到唤醒 这中间的过程 是怎么样的 ? 

先上一符图
这里写图片描述

阻塞
这里写图片描述

唤醒
这里写图片描述

阻塞的过程
/**    这个函数,核心就是调用了s3c24xx_i2c_doxfer来将数据i2c_msg传递给iic从设备*/static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msgs, int num){    struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;    /**        传输错误的重发次数。    */    int retry;     int ret;    /**        这里的 adap->retries 被设置为 2.        在哪里设置的?        static int __init i2c_adap_s3c_init(void)        {            return platform_driver_register(&s3c24xx_i2c_driver);        }        static struct platform_driver s3c24xx_i2c_driver = {            .probe      = s3c24xx_i2c_probe,            .remove     = s3c24xx_i2c_remove,            .id_table   = s3c24xx_driver_ids,            .driver     = {                .owner  = THIS_MODULE,                .name   = "s3c-i2c",                .pm = S3C24XX_DEV_PM_OPS,                .of_match_table = s3c24xx_i2c_match,            },        };        导致probe被调用        static int s3c24xx_i2c_probe(struct platform_device *pdev)        {            strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));            i2c->adap.owner   = THIS_MODULE;            i2c->adap.algo    = &s3c24xx_i2c_algorithm; //iic协议的实现。            i2c->adap.retries = 2;                      //传递数据到从设备时,发生错误重传的次数            i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;            i2c->tx_setup     = 50;                     //往寄存器写入数据的延时时间        }    */                      for (retry = 0; retry < adap->retries; retry++) {        /**            msgs : i2c_msg 组成的数组。            num  : 数组中i2c_msg的个数            下面看这个函数。        */        ret = s3c24xx_i2c_doxfer(i2c, msgs, num);  //传输函数,传输到iic设备的具体函数。        if (ret != -EAGAIN) {   //传输成功,返回            clk_disable(i2c->clk);            pm_runtime_put_sync(&adap->dev);            return ret;            }                               /*    下面是传输失败执行的代码                  延时100微秒后重新调用s3c24xx_i2c_doxfer()发送            */        dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);        udelay(100); //延时 100微秒。    }    clk_disable(i2c->clk);     pm_runtime_put_sync(&adap->dev);    return -EREMOTEIO;     //没有成功传输数据.I/O错误}static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,struct i2c_msg *msgs, int num){        ...        /**            你要往总线上放数据,总得看看总线是不是处于忙的状态把。            会尝试400 次 检查 iicstat寄存器bit[5],        */        ret = s3c24xx_i2c_set_master(i2c);        if (ret != 0)         {                               ...        }        /**            这里上锁了。            那也就是要说明 : 一次只允许一个进程进行数据的传输。        */        spin_lock_irq(&i2c->lock);        /**            填充iic_msg 消息 结构体            详细请见我另外一片博文:            http://blog.csdn.net/leesagacious/article/details/50488949        */        i2c->msg     = msgs;             i2c->msg_num = num;        i2c->msg_ptr = 0;        i2c->msg_idx = 0;        i2c->state   = STATE_START; //总线状态 : 总线开始状态        /**            使能中断。为什么要使能中断?   明白这个很重要。            iic设备是一个慢速设备,再读写过程中,进程休眠。            当数据发送完成后,在中断处理函数中会唤醒该休眠的进程。        */        s3c24xx_i2c_enable_irq(i2c);         /**            主角终于闪亮登场了....            这个函数并没有进行数据的传输,数据的传输是放到了中断处理函数中的。            它只做了两件事情                        1  : 写从设备地址到寄存器                        2  : 发送Start信号            下面详细说。        */        s3c24xx_i2c_message_start(i2c, msgs);           spin_unlock_irq(&i2c->lock);        /**            看,进程休眠了吧..............。            它在等待数据发送完成。            具体的是再 s3c24xx_i2c_stop()函数中会调用wake_up()来唤醒该等待队列上的进程        */        timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);        ....        ....        }   }
唤醒的过程

先看是在什么时候注册的中断处理函数

static int s3c24xx_i2c_probe(struct platform_device *pdev){        ....        ....        i2c->irq = ret = platform_get_irq(pdev, 0);        ...        /**            看注册了中断处理函数        */        ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0,  dev_name(&pdev->dev), i2c);        ....}

好,那么我们来看看这个中断处理函数是 怎么来 设计的
代码分析 请见 我以前的博文
http://blog.csdn.net/leesagacious/article/details/50488949

这里主要说 是怎么来实现的

static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id){}

实验验证

UART中的实现

实验验证

spi中的实现

实验验证

0 0