此处是用户空间驱动源码
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) |