一:
i2c通用接口调用过程:
i2c_dev_init--》register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops) //I2c-dev.c (drivers\i2c)
static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
对一个设备操作过程如下:
应用层调用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函数。
1 static int i2cdev_open(struct inode *inode, struct file *file)
2 {
3 。。。 。。。
4 adap = i2c_get_adapter(i2c_dev->adap->nr);
5 if (!adap)
6 return -ENODEV;
7
8 。。。 。。。
9 client = kzalloc(sizeof(*client), GFP_KERNEL);
10 if (!client) {
11 i2c_put_adapter(adap);
12 return -ENOMEM;
13 }
14 snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
15 client->driver = &i2cdev_driver;
16
17 client->adapter = adap;
18 file->private_data = client;
19
20 return 0;
21 }
可以发现此函数的作用是根据/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函数
[cpp] view plain
22 static ssize_t i2cdev_write(struct file *file, const char __user *buf,
23 size_t count, loff_t *offset)
24 {
25 。。。 。。。
26 struct i2c_client *client = file->private_data;
27 。。。 。。。
28 tmp = memdup_user(buf, count);
29 。。。 。。。
30 ret = i2c_master_send(client, tmp, count);
31 。。。 。。。
32 }
可以发现,在write函数中首先做的就是将在open操作中保存到file->private_data中的client取出然后通过memdup_user函数将用户空间的缓冲区拷贝到内核空间。最后调用函数i2c_master_send()
[cpp] view plain