Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1183069
  • 博文数量: 221
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2139
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(221)

文章存档

2024年(6)

2023年(8)

2022年(2)

2021年(2)

2020年(29)

2019年(11)

2018年(23)

2017年(41)

2016年(76)

2015年(23)

我的朋友
最近访客

分类: LINUX

2017-10-11 16:29:08

 此处是用户空间驱动源码

MODULE_DESCRIPTION("I2C /dev entries driver");
module_init(i2c_dev_init);
static int __init i2c_dev_init(void)
{
    int res;

    printk(KERN_INFO "i2c /dev entries driver\n");
// /dev/i2c这个设备
    res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
    i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");

    /* Keep track of adapters which will be added or removed later */
    res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);

    /* Bind to already existing adapters right away */
//i2cdev_attach_adapter函数很关键
    i2c_for_each_dev(NULL, i2cdev_attach_adapter);

}
////////////////////////////////////////////////////////////

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,
};
///////////////////////////////////////////////////////////////////////////////////////////////////////

static int i2cdev_open(struct inode *inode, struct file *file)
{
    unsigned int minor = iminor(inode);
    struct i2c_client *client;
    struct i2c_adapter *adap;
    struct i2c_dev *i2c_dev;
 //以设备文件的次设备号从i2c_dev_list链表中取得i2c_dev,应该也就是得到了struct device *dev;了。
    i2c_dev = i2c_dev_get_by_minor(minor);
    if (!i2c_dev)
        return -ENODEV;

    adap = i2c_get_adapter(i2c_dev->adap->nr);
    if (!adap)
        return -ENODEV;

    /* This creates an anonymous i2c_client, which may later be
     * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
     *
     * This client is ** NEVER REGISTERED ** with the driver model
     * or I2C core code!!  It just holds private copies of addressing
     * information and maybe a PEC flag.
     */
    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->adapter = adap;
//将client关联到file
    file->private_data = client;

    return 0;
}
////////////////////////////////////////////////////////////////////////////////////


static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
    struct i2c_dev *i2c_dev;

    spin_lock(&i2c_dev_list_lock);
//这个i2c_dev_list是链表串起来
    list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
        if (i2c_dev->adap->nr == index)
            goto found;
    }
    i2c_dev = NULL;
found:
    spin_unlock(&i2c_dev_list_lock);
    return i2c_dev;
}
////////////////////////////////////////////////////////////////

static struct notifier_block i2cdev_notifier = {
    .notifier_call = i2cdev_notifier_call,
};
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 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);
//调用get_free_i2c_dev()分配并初始化了一个struct i2c_dev结构,
//使i2c_dev->adap指向操作的adapter.之后,该i2c_dev会被链入链表i2c_dev_list中

    i2c_dev = get_free_i2c_dev(adap);

// i2c_dev内嵌的device是以adap->dev为父结点,在device_create()中会增次adap->dev的一次引用计数。
    /* register this i2c device with the driver core */
//以I2C_MAJOR,、adap->nr为主次设备号创建了一个device。
//如果此时系统配置了udev或者是hotplug,那么就在/dev下自动创建相关的设备节点了

    i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
                     MKDEV(I2C_MAJOR, adap->nr), NULL,
                     "i2c-%d", adap->nr);
//使用这个函数时要引用 device_create所返回的device*指针,
//作用是在/sys/class/下创建一个属性文件,从而通过对这个属性文件进行读写就能完成对应的数据操作
    res = device_create_file(i2c_dev->dev, &dev_attr_name);


    pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
         adap->name, adap->nr);
    return 0;
error_destroy:
    device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
    return_i2c_dev(i2c_dev);
    return res;
}

///////////////////////////////////////////////////////////////////////////////////
摘自原文http://blog.chinaunix.net/uid-25445243-id-3862576.html

用户空间使用i2c_dev

        对于注册的i2c适配器,用户空间可以使用它们。上面的驱动对每个适配器生成一个主设备号为89的设备节点,实现了文件操作接口,用户空间可以通过i2c设备节点访问i2c适配器。适配器的编号从0开始,和适配器的设备节点的次设备号相同。i2c适配器的设备节点是/dev/i2c-x,其中x是数字,代表适配器的编号。由于适配器编号是动态分配的(和注册次序有关),所以想了解哪一个适配器对应什么编号,可以查看/sys/class/i2c-dev/目录下的文件内容。
///////////////////////////////////////////////////////////////////////// 






阅读(3286) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~