linux 3.4 hisi i2c用户空间驱动/dev/i2c-0

此处是用户空间驱动源码

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/目录下的文件内容。

/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xx-xx-xxx-xxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值