i2c-dev

obj-$(CONFIG_I2C_CHARDEV)    += i2c-dev.o
假如打开了CONFIG_I2C_CHARDEV的话,就可以将i2c 作为一个标准的字符设备来访问
static int __init i2c_dev_init(void)
{
    int res;

    printk(KERN_INFO "i2c /dev entries driver\n");

    res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c");
    if (res)
        goto out;
//注册i2c对应的class,之后就可以看到/sys/class/i2c-dev,这样如果有i2c总线设备的话,就会在/sys/class/i2c-dev/i2c-0等设备
    i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
    if (IS_ERR(i2c_dev_class)) {
        res = PTR_ERR(i2c_dev_class);
        goto out_unreg_chrdev;
    }
//i2c-dev对应的group ,会显示i2c-dev下每个字符设备的name
    i2c_dev_class->dev_groups = i2c_groups;
//bus_register_notifier和i2c_for_each_dev 都是为新的i2c 总线设备insmod 后调用i2cdev_attach_adapter。这不过i2c_for_each_dev 针对当前已经存在的i2c 总线设备,而bus_register_notifier是为未来可能insmod i2c设备调用i2cdev_attach_adapter
    /* 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;

out_unreg_class:
    class_destroy(i2c_dev_class);
out_unreg_chrdev:
    unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
out:
    printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
    return res;
}

module_init(i2c_dev_init);
在i2c_dev_init 中i2c_dev_class->dev_groups = i2c_groups;中用到的i2c_groups 定义如下
static ssize_t name_show(struct device *dev,
             struct device_attribute *attr, char *buf)
{
    struct i2c_dev *i2c_dev = i2c_dev_get_by_minor(MINOR(dev->devt));

    if (!i2c_dev)
        return -ENODEV;
    return sprintf(buf, "%s\n", i2c_dev->adap->name);
}
static DEVICE_ATTR_RO(name);

static struct attribute *i2c_attrs[] = {
    &dev_attr_name.attr,
    NULL,
};
ATTRIBUTE_GROUPS(i2c);
可见这个通过cat name就key打印这个adapter对应的name.
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
{
    int res;

    mutex_lock(&core_lock);
    res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn);
    mutex_unlock(&core_lock);

    return res;
}
为bus_type 为i2c_bus_type的设备调用i2cdev_attach_adapter
而bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); 则是为未来肯能增加或减少的adapter调用i2cdev_notifier
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);
    case BUS_NOTIFY_DEL_DEVICE:
        return i2cdev_detach_adapter(dev, NULL);
    }

    return 0;
}

static struct notifier_block i2cdev_notifier = {
    .notifier_call = i2cdev_notifier_call,
};
可见如果是新增的adapter 同样调用的是i2cdev_attach_adapter,这是就和i2c_for_each_dev做的事情一样了
总结一下i2c_dev_init主要就是注册了一个i2c-dev,并为每个已经存在或者未来可能存在的adapter调用i2cdev_attach_adapter
static int i2cdev_attach_adapter(struct device *dev, void *dummy)
{
    struct i2c_adapter *adap;
    struct i2c_dev *i2c_dev;
    int res;

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

    i2c_dev = get_free_i2c_dev(adap);
    if (IS_ERR(i2c_dev))
        return PTR_ERR(i2c_dev);

    cdev_init(&i2c_dev->cdev, &i2cdev_fops);
    i2c_dev->cdev.owner = THIS_MODULE;
    res = cdev_add(&i2c_dev->cdev, MKDEV(I2C_MAJOR, adap->nr), 1);
    if (res)
        goto error_cdev;

    /* register this i2c device with the driver core */
    i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
                     MKDEV(I2C_MAJOR, adap->nr), NULL,
                     "i2c-%d", adap->nr);
    if (IS_ERR(i2c_dev->dev)) {
        res = PTR_ERR(i2c_dev->dev);
        goto error;
    }

    pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
         adap->name, adap->nr);
    return 0;
error:
    cdev_del(&i2c_dev->cdev);
error_cdev:
    put_i2c_dev(i2c_dev);
    return res;
}
而在i2cdev_attach_adapter 中会为每个i2c adapter生产一个字符设备,这样就可以在user space方位i2c 设备了
linux-zpo1:/sys/class/i2c-dev/i2c-0 # ls /dev |grep i2c
i2c-0
i2c-1

linux-zpo1:/sys/class/i2c-dev # ls
i2c-0  i2c-1

下面的name就是通过i2c_dev_class->dev_groups = i2c_groups;产生的
linux-zpo1:/sys/class/i2c-dev/i2c-0 # cat name
Synopsys DesignWare I2C adapter


你可能感兴趣的:(Linux,源码分析)