协议[I2C]_I2C子系统之write()
2015-10-22 16:12
375 查看
应用层调用write()函数后首先进入的是i2c类设备的write函数,即i2cdev_fops中的write方法。
此处的i2cdev_fops对应的是系统中所有i2c类设备的操作。也就是说系统中所有i2c adapter 的read()
write() open() close() ioctl()等操作,首先调用的是i2c类i2cdev_fops中的方法,通过i2c类中的方法再去寻找adapter 对应的算法i2c_algorithm,此处s3c2440对应的为s3c24xx_i2c_algorithm。
对i2c的操作方法
1.首先open
2.ioctl设置at24c02的地址
3.write()
1.open设备/dev/i2c-0
open通过系统调用最后调用到fops的i2cdev_open函数。
static int i2cdev_open(struct inode *inode, struct file *file)
{
。。。 。。。
adap = i2c_get_adapter(i2c_dev->adap->nr);
if (!adap)
return -ENODEV;
。。。 。。。
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
client->adapter = adap;
file->private_data = client;
return 0;
}
可以发现此函数的作用是根据/dev/i2c-0的设备号找到对应的adapter,然后将其保存到新建的client中。
需要注意的是,此处的client与驱动中的client不同,这里的client并不会注册到总线上,和i2c驱动模型的代码无关。
此处的client只是用来保存client地址信息等。
最后将这个clietn保存到file->private_data中,供ioctl() write() open()等操作使用。
2. ioctl
应用层调用ioctl后会调用到i2cdev_ioctl()函数,此处使用的是I2C_SLAVE_FORCE,用于设置at24c02的地址。
3.write
write通过系统调用最后执行fops这中的i2cdev_write函数
static ssize_t i2cdev_write(struct file *file, const char __user *buf,
size_t count, loff_t *offset)
{
。。。 。。。
struct i2c_client *client = file->private_data;
。。。 。。。
tmp = memdup_user(buf, count);
。。。 。。。
ret = i2c_master_send(client, tmp, count);
。。。 。。。
}
可以发现,在write函数中首先做的就是将在open操作中保存到file->private_data中的client取出
然后通过memdup_user函数将用户空间的缓冲区拷贝到内核空间。最后调用函数i2c_master_send()
int i2c_master_send(struct i2c_client *client, const char *buf, int count)
{
。。。 。。。
ret = i2c_transfer(adap, &msg, 1);
。。。 。。。
}
在i2c_mastr_send函数中首先初始化msg结构体,将client的地址、当前需要拷贝的数据长度等信息填充到msg中。最后将此msg作为形参传递给i2c_transfer函数。i2c的读写过程中,发送的信息都是通过msg来完成的,除了device address之外。device address信息单独发送,其余的通过msg.buf来完成
并且可以发现,此处i2c_transfer中的第三个参数为1,这个参数是告诉驱动每次发送的msg个数,这里设置为1
表示每次只能发送一则msg。
i2c_transfer()函数如下:
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
。。。 。。。
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
。。。 。。。
}
在此函数做完相关处理后直接调用adapter的algorithm来发送数据,此处即i2c-s3c2440文件中
s3c24xx_i2c_probe总注册的算法
i2c->adap.algo = &s3c24xx_i2c_algorithm;
s3c24xx_i2c_algorithm算法具体如下:
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
因此相当于直接调用了函数s3c24xx_i2c_xfer
s3c24xx_i2c_xfer只是对s3c24xx_i2c_doxfer的简单封装,实际的处理都在函数s3c24xx_i2c_doxfer中。下面重点分析这个s3c24xx_i2c_doxfer函数
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
struct i2c_msg *msgs, int num)
{
。。。 。。。
ret = s3c24xx_i2c_set_master(i2c);
。。。 。。。
i2c->msg = msgs;
i2c->msg_num = num;
i2c->msg_ptr = 0;
i2c->msg_idx = 0;
i2c->state = STATE_START;
s3c24xx_i2c_enable_irq(i2c);
s3c24xx_i2c_message_start(i2c, msgs);
spin_unlock_irq(&i2c->lock);
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
。。。 。。。
}
在此函数中首先调用的是s3c24xx_i2c_set_master函数,查询master(即adapter)是否处于忙的状态。忙则休眠1ms后再次查询,总共查询400次,相当于在400ms之后i2c还处于忙状态则放弃。
master空闲后,做些相关初始化的操作。初始化操作中需要注意的是i2c->state = STATE_START,通过这个状态位来标记i2c当前是起始状态、写状态还是读状态。
接着通关函数
s3c24xx_i2c_enable_irq(i2c);
打开中断。然后调用函数
s3c24xx_i2c_message_start(i2c, msgs);
来发送第一个字节,即device address。当第一个字节发送完毕后,s3c2440的i2c控制器会产生中断。
s3c2440的i2c中断发生在1.完成1字节的发送或者接收2.广播呼叫或者从地址匹配时3.总线仲裁失败。
并且当第一个字节device address发送完毕后,函数通过
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
此处的i2cdev_fops对应的是系统中所有i2c类设备的操作。也就是说系统中所有i2c adapter 的read()
write() open() close() ioctl()等操作,首先调用的是i2c类i2cdev_fops中的方法,通过i2c类中的方法再去寻找adapter 对应的算法i2c_algorithm,此处s3c2440对应的为s3c24xx_i2c_algorithm。
对i2c的操作方法
1.首先open
2.ioctl设置at24c02的地址
3.write()
1.open设备/dev/i2c-0
open通过系统调用最后调用到fops的i2cdev_open函数。
static int i2cdev_open(struct inode *inode, struct file *file)
{
。。。 。。。
adap = i2c_get_adapter(i2c_dev->adap->nr);
if (!adap)
return -ENODEV;
。。。 。。。
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
client->adapter = adap;
file->private_data = client;
return 0;
}
可以发现此函数的作用是根据/dev/i2c-0的设备号找到对应的adapter,然后将其保存到新建的client中。
需要注意的是,此处的client与驱动中的client不同,这里的client并不会注册到总线上,和i2c驱动模型的代码无关。
此处的client只是用来保存client地址信息等。
最后将这个clietn保存到file->private_data中,供ioctl() write() open()等操作使用。
2. ioctl
应用层调用ioctl后会调用到i2cdev_ioctl()函数,此处使用的是I2C_SLAVE_FORCE,用于设置at24c02的地址。
3.write
write通过系统调用最后执行fops这中的i2cdev_write函数
static ssize_t i2cdev_write(struct file *file, const char __user *buf,
size_t count, loff_t *offset)
{
。。。 。。。
struct i2c_client *client = file->private_data;
。。。 。。。
tmp = memdup_user(buf, count);
。。。 。。。
ret = i2c_master_send(client, tmp, count);
。。。 。。。
}
可以发现,在write函数中首先做的就是将在open操作中保存到file->private_data中的client取出
然后通过memdup_user函数将用户空间的缓冲区拷贝到内核空间。最后调用函数i2c_master_send()
int i2c_master_send(struct i2c_client *client, const char *buf, int count)
{
。。。 。。。
ret = i2c_transfer(adap, &msg, 1);
。。。 。。。
}
在i2c_mastr_send函数中首先初始化msg结构体,将client的地址、当前需要拷贝的数据长度等信息填充到msg中。最后将此msg作为形参传递给i2c_transfer函数。i2c的读写过程中,发送的信息都是通过msg来完成的,除了device address之外。device address信息单独发送,其余的通过msg.buf来完成
并且可以发现,此处i2c_transfer中的第三个参数为1,这个参数是告诉驱动每次发送的msg个数,这里设置为1
表示每次只能发送一则msg。
i2c_transfer()函数如下:
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
。。。 。。。
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
。。。 。。。
}
在此函数做完相关处理后直接调用adapter的algorithm来发送数据,此处即i2c-s3c2440文件中
s3c24xx_i2c_probe总注册的算法
i2c->adap.algo = &s3c24xx_i2c_algorithm;
s3c24xx_i2c_algorithm算法具体如下:
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
因此相当于直接调用了函数s3c24xx_i2c_xfer
s3c24xx_i2c_xfer只是对s3c24xx_i2c_doxfer的简单封装,实际的处理都在函数s3c24xx_i2c_doxfer中。下面重点分析这个s3c24xx_i2c_doxfer函数
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
struct i2c_msg *msgs, int num)
{
。。。 。。。
ret = s3c24xx_i2c_set_master(i2c);
。。。 。。。
i2c->msg = msgs;
i2c->msg_num = num;
i2c->msg_ptr = 0;
i2c->msg_idx = 0;
i2c->state = STATE_START;
s3c24xx_i2c_enable_irq(i2c);
s3c24xx_i2c_message_start(i2c, msgs);
spin_unlock_irq(&i2c->lock);
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
。。。 。。。
}
在此函数中首先调用的是s3c24xx_i2c_set_master函数,查询master(即adapter)是否处于忙的状态。忙则休眠1ms后再次查询,总共查询400次,相当于在400ms之后i2c还处于忙状态则放弃。
master空闲后,做些相关初始化的操作。初始化操作中需要注意的是i2c->state = STATE_START,通过这个状态位来标记i2c当前是起始状态、写状态还是读状态。
接着通关函数
s3c24xx_i2c_enable_irq(i2c);
打开中断。然后调用函数
s3c24xx_i2c_message_start(i2c, msgs);
来发送第一个字节,即device address。当第一个字节发送完毕后,s3c2440的i2c控制器会产生中断。
s3c2440的i2c中断发生在1.完成1字节的发送或者接收2.广播呼叫或者从地址匹配时3.总线仲裁失败。
并且当第一个字节device address发送完毕后,函数通过
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
相关文章推荐
- Tomcat安装与使用
- App项目开发流程(转)
- 【腾讯Bugly干货分享】Android UI:机智的远程动态更新策略
- mongo语法和mysql语法对比学习
- HDOJ 2004 成绩转换
- java学习经典书籍_杂篇
- java学习经典书籍_数据库篇
- 协议[I2C]_I2C子系统之 adapter driver注册——I2C_dev_init()
- JavaWeb扩展--Freemarker(二)
- UIWrapContent
- Android Studio下加入百度地图的使用 (一)——环境搭建
- 《实时控制软件设计》教学计划
- 解决CENTOS7虚拟机更改静态IP无法启动
- __FILE__, __LINE__ __FUNCTION__
- supervisor 使用及管理nginx+gunicorn
- 在Eclipse添加Android兼容包( v4、v7 appcompat )
- swift开发笔记13 - 添加图表(饼状图)
- YuiDoc与JsDoc通用标签归纳汇总
- IBM DeveloperWoirks 技术社区
- HDOJ 2003 求绝对值