I2C子系统框架二

学习资料:韦东山第三期
 
本节为i2c-dev.c流程分析:
i2c-dev.c提供了上层直接访问I2C设备的接口,其中包括了I2C控制器的注册,字符设备接口的提供等
 

i2c-dev.c注册过程:

 static int __init i2c_dev_init(void)
 {
         int res;

         pr_err("i2c /dev entries driver\n");

         res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c");    // 注册字符设备的主设备号
         if (res)
                 goto out;

         i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");    // 创建类i2c-dev,在/sys/class下可看到i2c-dev目录
         if (IS_ERR(i2c_dev_class)) {
                 res = PTR_ERR(i2c_dev_class);
                 goto out_unreg_chrdev;
         }
         i2c_dev_class->dev_groups = i2c_groups;

         /* Keep track of adapters which will be added or removed later */
         res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);    // 注册总线通知器,见下节
         if (res)
                 goto out_unreg_class;

         /* Bind to already existing adapters right away */
         i2c_for_each_dev(NULL, i2cdev_attach_adapter);

         return 0;

... ...
 }
i2c控制器注册的时候就会产生总线通知:
 static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
                          void *data)
 {
         struct device *dev = data;

         switch (action) {
         case BUS_NOTIFY_ADD_DEVICE:
                 return i2cdev_attach_adapter(dev, NULL);    // i2c总线设备添加时调用
         case BUS_NOTIFY_DEL_DEVICE:
                 return i2cdev_detach_adapter(dev, NULL);    // i2c总线设备删除时调用
         }

         return 0;
 }

 static struct notifier_block i2cdev_notifier = {
         .notifier_call = i2cdev_notifier_call,
 };
i2cdev_attach_adapter调用:
 static int i2cdev_detach_adapter(struct device *dev, void *dummy)
 {
         struct i2c_adapter *adap;
         struct i2c_dev *i2c_dev;

         if (dev->type != &i2c_adapter_type)
                 return 0;
         adap = to_i2c_adapter(dev);

         i2c_dev = i2c_dev_get_by_minor(adap->nr);
         if (!i2c_dev) /* attach_adapter must have failed */
                 return 0;

         put_i2c_dev(i2c_dev, true);

         pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
         return 0;
 }

 

 

应用层调用函数:

i2c-dev.c核心操作
 static const struct file_operations i2cdev_fops = {
         .owner          = THIS_MODULE,
         .llseek         = no_llseek,
         .read           = i2cdev_read,
         .write          = i2cdev_write,
         .unlocked_ioctl = i2cdev_ioctl,
         .compat_ioctl   = compat_i2cdev_ioctl,
         .open           = i2cdev_open,
         .release        = i2cdev_release,
 };
主要调用接口:open、ioctl
0
 
i2cdev_open:
 static int i2cdev_open(struct inode *inode, struct file *file)
 {
         unsigned int minor = iminor(inode);
         struct i2c_client *client;
         struct i2c_adapter *adap;

         adap = i2c_get_adapter(minor);    // 根据设备节点找到i2c_adapter
         if (!adap)
                 return -ENODEV;


         client = kzalloc(sizeof(*client), GFP_KERNEL);    // 分配i2c_client,表示设备,但还没设备地址
         if (!client) {
                 i2c_put_adapter(adap);
                 return -ENOMEM;
         }
         snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);

         client->adapter = adap;    // client和adapter建立联系,设置私有数据暂存
         file->private_data = client;

         return 0;
 }

 

i2cdev_ioctl: I2C_SLAVE/I2C_SLAVE_FORCE:
 static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
         struct i2c_client *client = file->private_data;        // 取出私有数据,也就是i2c_client
         unsigned long funcs;

         dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
                 cmd, arg);

         switch (cmd) {
         case I2C_SLAVE:
         case I2C_SLAVE_FORCE:
                 if ((arg > 0x3ff) ||
                     (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
                         return -EINVAL;
                 if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))    // I2C_SLAVE和I2C_SLAVE_FORCE区别在于I2C_SLAVE会检查addr是否有驱动
                         return -EBUSY;
                 /* REVISIT: address could become busy later */
                 client->addr = arg;    // 设置地址
                 return 0;
... ...
         case I2C_RDWR: {
                 struct i2c_rdwr_ioctl_data rdwr_arg;
                 struct i2c_msg *rdwr_pa;

                 if (copy_from_user(&rdwr_arg,
                                    (struct i2c_rdwr_ioctl_data __user *)arg,
                                    sizeof(rdwr_arg)))
                         return -EFAULT;

                 if (!rdwr_arg.msgs || rdwr_arg.nmsgs == 0)
                         return -EINVAL;

                 /*
                  * Put an arbitrary limit on the number of messages that can
                  * be sent at once
                  */
                 if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
                         return -EINVAL;

                 rdwr_pa = memdup_user(rdwr_arg.msgs,
                                       rdwr_arg.nmsgs * sizeof(struct i2c_msg));
                 if (IS_ERR(rdwr_pa))
                         return PTR_ERR(rdwr_pa);

                 return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa);
         }
... ...
}

 static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
                 unsigned int nmsgs, struct i2c_msg *msgs)
{
... ...
         res = i2c_transfer(client->adapter, msgs, nmsgs);    // 此处设置传输
         while (i-- > 0) {
                 if (res >= 0 && (msgs[i].flags & I2C_M_RD)) {
                         if (copy_to_user(data_ptrs[i], msgs[i].buf,
                                          msgs[i].len))
                                 res = -EFAULT;
                 }
                 kfree(msgs[i].buf);
         }
... ...
}

 

i2cdev_ioctl:I2C_SMBus
... ...
          case I2C_SMBUS: {
                 struct i2c_smbus_ioctl_data32   data32;

                 if (copy_from_user(&data32,
                                    (void __user *) arg,
                                    sizeof(data32)))
                         return -EFAULT;
                 return i2cdev_ioctl_smbus(client, data32.read_write,
                                           data32.command,
                                           data32.size,
                                           compat_ptr(data32.data));
         }

... ...
         if ((size == I2C_SMBUS_QUICK) ||
             ((size == I2C_SMBUS_BYTE) &&
             (read_write == I2C_SMBUS_WRITE)))
                 /* These are special: we do not use data */
                 return i2c_smbus_xfer(client->adapter, client->addr,
                                       client->flags, read_write,
                                       command, size, NULL);        // 发起SMBus传输
... ...

 

 

 

 

 

 

 

 
posted @ 2024-03-31 01:21  lethe1203  阅读(8)  评论(0编辑  收藏  举报