.driver = {
.name = "dev_driver",
},
.attach_adapter = i2cdev_attach_adapter,
.detach_adapter = i2cdev_detach_adapter,
};
{
int res;
printk(KERN_INFO "i2c /dev entries driver\n");
res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops); //注册字符设备,函数操作集当中提供了大量了读写和操作接口给应用程序
if (res)
goto out;
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); 注册了一个名为“i2c-dev”设备类
if (IS_ERR(i2c_dev_class)) {
res = PTR_ERR(i2c_dev_class);
goto out_unreg_chrdev;
}
res = i2c_add_driver(&i2cdev_driver); 向系统注册i2c设备驱动。
if (res)
goto out_unreg_class;
return 0;
out_unreg_class:
class_destroy(i2c_dev_class);
out_unreg_chrdev:
unregister_chrdev(I2C_MAJOR, "i2c");
out:
printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
return res;
}
{
return i2c_register_driver(THIS_MODULE, driver);
}
{
int res;
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
if (is_newstyle_driver(driver)) {
if (driver->detach_adapter || driver->detach_client) {
printk(KERN_WARNING
"i2c-core: driver [%s] is confused\n",
driver->driver.name);
return -EINVAL;
}
}
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type; //将I2C设备驱动挂到I2C总线上
res = driver_register(&driver->driver);
if (res)
return res;
mutex_lock(&core_lock);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
class_for_each_device(&i2c_adapter_class, NULL, driver, //遍历2c_adapter_class,调用__attach_adapter函数
__attach_adapter);
mutex_unlock(&core_lock);
return 0;
}
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
int res;
i2c_dev = get_free_i2c_dev(adap); //该函数分配了一个i2c_dev的对象,并将该对象添加到全局链表i2c_dev_list上。
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev, //创建设备号为 MKDEV(I2C_MAJOR, adap->nr),名称为“i2c-%d”的字符设备节点。
MKDEV(I2C_MAJOR, adap->nr), NULL,
"i2c-%d", adap->nr);
if (IS_ERR(i2c_dev->dev)) {
res = PTR_ERR(i2c_dev->dev);
goto error;
}
res = device_create_file(i2c_dev->dev, &dev_attr_name);
if (res)
goto error_destroy;
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;
}
i2cdev_attach_adapter这个函数主要做了两件事1.调用 get_free_i2c_dev(adap); //该函数分配了一个i2c_dev的对象,并将该对象添加到全局链表i2c_dev_list上。2.调用
device_create()创建设备号为 MKDEV(I2C_MAJOR, adap->nr),名称为“i2c-%d”的字符设备节点。
除了在注册i2c_driver驱动时会遍历所有的适配器设备外,在调用i2c_add-addpter()注册适配器时也会遍历i2c_bus_type总线上所有的驱动,并调用它们的attcah_adapter成员方法。因此,不管是先注册驱动i2cdev_driver,还是先添加i2c_adapter对象,子系统都会为每个适配器设备创建相应的设备节点。
之前我们讲解了这么多讲述都是I2c设备驱动,那么与I2c设备驱动相对应的设备信息i2c_client是在哪里完成注册的呢?i2c子系统利用i2c_register_board_info()函数在添加i2c_adapter对象之前,将一组i2c_board_info对象注册进内核。i2c_board_info对象描述一条I2C设备信息,它实际上是用于创建i2c_client对象的临时信息,i2c_register_board_info()函数会将所用的i2c_board_info对象添加到一个名为__i2c_board_list链表上。我们通常将一组i2c_board_info写入板级初始化文件,如mach-tq2440.同时在板级初始化函数中调用i2c_register_board_info()。
而我们在I2C总线驱动的proble中使用i2c_add_adapter注册适配器时,就会遍历_i2c_board_liat链表,并取出i2c_board_info对象调用i2c_new_device()创建i2c_client设备对象。
现在我们又会带i2c设备驱动当中,我们重点看一下之提供给用户程序使用的一些read .write .open 函数。
static int i2cdev_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode); //inode中获得次设备号
struct i2c_client *client;
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
int ret = 0;
lock_kernel();
i2c_dev = i2c_dev_get_by_minor(minor); //从链表i2c_dev_list中获得与minor对应的i2c_dev对象(i2c_dev->adap等于minor的对象)
if (!i2c_dev) {
ret = -ENODEV;
goto out;
}
adap = i2c_get_adapter(i2c_dev->adap->nr); //获得id为i2c_dev->adap->nr的适配器对象;
if (!adap) {
ret = -ENODEV;
goto out;
}
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
ret = -ENOMEM;
goto out;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
client->adapter = adap;
file->private_data = client;
out:
unlock_kernel();
return ret;
}
这个open函数主要的做了1:调用iminor(inode)获得次设备号并从链表i2c_dev_list中获得与minor对应的i2c_dev对象。
2:调用 i2c_dev_get_by_minor(minor); 从链表i2c_dev_list中获得与minor对应的i2c_dev对象(i2c_dev->adap等于minor的对象)
3:从 i2c_get_adapter(i2c_dev->对象,并用adap->nr)中获得id为i2c_dev->adap->nr的适配器对象{
struct i2c_client *client = (struct i2c_client *)file->private_data;
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))
return -EBUSY;
client->addr = arg;
return 0;
case I2C_TENBIT:
if (arg)
client->flags |= I2C_M_TEN;
else
client->flags &= ~I2C_M_TEN;
return 0;
case I2C_PEC:
if (arg)
client->flags |= I2C_CLIENT_PEC;
else
client->flags &= ~I2C_CLIENT_PEC;
return 0;
case I2C_FUNCS:
funcs = i2c_get_functionality(client->adapter);
return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR:
return i2cdev_ioctl_rdrw(client, arg); //重点
case I2C_SMBUS:
return i2cdev_ioctl_smbus(client, arg);
case I2C_RETRIES:
client->adapter->retries = arg;
break;
case I2C_TIMEOUT:
client->adapter->timeout = msecs_to_jiffies(arg * 10);
break;
default:
return -ENOTTY;
}
return 0;
}
static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
unsigned long arg)
{
struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_msg *rdwr_pa;
u8 __user **data_ptrs;
int i, res;
if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg, //将arg的数据拷给rdwr_arg
sizeof(rdwr_arg)))
return -EFAULT;
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
rdwr_pa = (struct i2c_msg *)
kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
GFP_KERNEL);
if (!rdwr_pa)
return -ENOMEM;
if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
kfree(rdwr_pa);
return -EFAULT;
}
data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
if (data_ptrs == NULL) {
kfree(rdwr_pa);
return -ENOMEM;
}
res = 0;
for (i = 0; i < rdwr_arg.nmsgs; i++) {
if ((rdwr_pa[i].len > 8192) ||
(rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
res = -EINVAL;
break;
}
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
if (rdwr_pa[i].buf == NULL) {
res = -ENOMEM;
break;
}
if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
rdwr_pa[i].len)) {
++i; /* Needs to be kfreed too */
res = -EFAULT;
break;
}
}
if (res < 0) {
int j;
for (j = 0; j < i; ++j)
kfree(rdwr_pa[j].buf);
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
}
res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
while (i-- > 0) {
if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
rdwr_pa[i].len))
res = -EFAULT;
}
kfree(rdwr_pa[i].buf);
}
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
}
_