"阻塞--中断"驱动模型在i2c在子系统、uart驱动、spi子系统中的实现
2016-06-10 16:01
525 查看
最近总结了这个kernel中的这个模型,下面我们 开始欣赏吧。
先上一符图
阻塞
唤醒
阻塞的过程
唤醒的过程
先看是在什么时候注册的中断处理函数
好,那么我们来看看这个中断处理函数是 怎么来 设计的
代码分析 请见 我以前的博文
http://blog.csdn.net/leesagacious/article/details/50488949
这里主要说 是怎么来实现的
先看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中的实现
实验验证
相关文章推荐
- uva11400 lighting system design
- 博弈论
- CPU标志寄存器
- 无缝滑动展示图片
- 几个visual studio 的快捷键
- WPF开发之限制输入的控件
- 匈牙利算法(二分图)
- hive-0
- tomcat 内存溢出解决方案
- VC中ADO Data控件的使用
- 设计模式 II ——策略模式(Strategy)
- Java 直接插入排序
- hive 入门
- 使用git了解代码编写过程
- String类的编码和解码问题
- [Alfred]替代Spotlight
- 直接修改user1的家目录
- Activity的生命周期
- 使用VNC进行远程控制
- webService学习4:客户端调用服务端的代码