原文地址:http://blog.chinaunix.net/uid-25120309-id-3357579.html
程序运行流程:
1、 module_init(i2c_dev_init); 加载初始化函数。
2、 运行i2c_dev_init函数,注册设备,注册设备驱动,以_init为头的函数,在运行过后系统将回收其内存
static int __init i2c_dev_init(void)
{
int res;
//代码看到这里的时候,顺便看了一眼我的Linux启动时打印出来的LOG,果然找到了这句
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");
if (IS_ERR(i2c_dev_class))
goto out_unreg_chrdev;
res = i2c_add_driver(&i2cdev_driver); //注册设备驱动
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;
}
其中注册设备时用的主设备号I2C_MAJOR是什么,不清楚,不知道是不是头文件里面的宏定义,register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);中的i2c是在/proc/devices中体现的,
其中注册的结构体&i2cdev_fops,给用户空间提供了调用接口,就是个字符型驱动
目前不清楚/dev/i2c/0这个设备文件是在哪里注册的????。
这里面注册的设备驱动&i2cdev_driver,不知道是什么时候用
3、 结构体static const struct file_operations i2cdev_fops 提供了用户空间调用函数的接口,在程序i2c-test.c中使用的就是ioctl函数来对I2C设备进行读写的。
static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE, //所有者
.llseek = no_llseek, //操作位置定位
.read = i2cdev_read, //读操作
.write = i2cdev_write, //写操作
.ioctl = i2cdev_ioctl, //IOCTL操作
.open = i2cdev_open, //打开文件
.release = i2cdev_release, //释放文件
};
用户程序中只用到了ioctl,所以其他的接口没有看。
4、对ioctl函数i2cdev_ioctl进行分析,在用户空间中是使用 ioctl(i2c_fd, I2C_TIMEOUT, 2);//设置超时时间;ioctl(i2c_fd, I2C_RETRIES, 1) //设置重发次数;以及ret = ioctl (i2c_fd, I2C_RDWR, (unsigned long)&TP_data);//读取 ,来对设备进行操作的,其中i2c_fd为打开/dev/i2c/0这个设备文件后返回的文件描述符,第二个参数是命令,第三个参数随命令不同表示的意义也不一样,其中TP_data为i2c_rdwr_ioctl_data结构体:
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
struct i2c_msg {
_ _u16 addr; /* slave address */
_ _u16 flags; /* 标志(读、写) */
_ _u16 len; /* msg length */
_ _u8 *buf; /* pointer to msg data */
};
这其中nmsgs为需要发送的消息数量,msgs为指向i2c_msg结构体的指针。接下来看驱动程序中是怎么样定义ioctl的吧。
static int i2cdev_ioctl (
struct inode *inode,
struct file *file, //文件描述符,也就是打开/dev/下创建的设备文件所返回的文件描述符
unsigned int cmd,//命令
unsigned long arg )//从上层传输过来的参数,视cmd的不同含义有所不同
{
struct i2c_client *client = (struct i2c_client *)file->private_data;
struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_smbus_ioctl_data data_arg;
union i2c_smbus_data temp;
struct i2c_msg *rdwr_pa; //SMBUS的数据结构体
u8 __user **data_ptrs;
int i,datasize,res;
unsigned long funcs;
//打印信息到设备的LOG中
dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
cmd, arg);
//根据不同的命令做响应
switch ( cmd ) {
//设备的读写操作,注意传入参数的类型
case I2C_RDWR:
if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_arg))) //arg是从用户空间传过来的TP_data,rdwr_arg是用户空间,但&rdwr_arg是内核空间,但不知为啥没有先申请内核内存。
return -EFAULT;
//要操作的数据包(msg包)超过最大限制
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);//申请了结构体i2c_msg大小的内核内存,这里要注意一点,申请的内存是装载i2c_msg这个结构体的,其成员buf为指针,申请的内核内存只是装载指针变量的,所以此指针所指向的空间还是用户空间内存
if (rdwr_pa == NULL) return -ENOMEM; //申请失败
//将要操作的数据用用户层复制到内核层
if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
kfree(rdwr_pa);
return -EFAULT;
}
//申请一组指针,每一个元素指向一个msg包,这里也是申请的是装载指针变量的内核内存,所以指针指向的空间仍然是用户空间
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
if ((rdwr_pa[i].len > 8192) || //要操作的数据不能大于8K
(rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
res = -EINVAL;
break;
}
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; //指针和用户层数据缓存关联
//根据长度申请内存,注意,此时buf地址关联上的是新申请的内存的地址
rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
if(rdwr_pa[i].buf == NULL) {
res = -ENOMEM;
break;
}
//将要操作的用户数据COPY到内核缓存中
//如果是读操作,那么这里复制的数据是没有意义的
//如果是写操作,那么这里就将要写入的数据给复制进了缓存中了
if(copy_from_user(rdwr_pa[i].buf,
data_ptrs[i],
rdwr_pa[i].len)) {
++i;
res = -EFAULT;
break;
}
} //for结束
//如果以上操作失败(一般是申请内存失败),则释放内存并返回
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;
}
这个函数的其他命令在用户空间没有调用所以没有列出来,这其中有许多情况都要进行内核空间的内存申请,以及从用户空间拷贝数据到内核空间,以及从内核空间拷贝数据到用户空间;这其中要注意一点就是,要看清申请的是装载数据的空间,还是只是装载指针的空间,如果只是装载指针的空间的话,这个指针指向的空间还是在用户空间。
5、通过i2c driver中的attach_adapter方法来实现将adapter和对应的驱动绑定。
static struct i2c_driver i2cdev_driver = {
-
.driver = {
-
.name = "dev_driver",
-
},
-
.attach_adapter = i2cdev_attach_adapter,
-
.detach_adapter = i2cdev_detach_adapter,
-
};
此处注意attach_adapter这个方法,/dev目录下的设备创建是在通过执行此函数实现的。
下面具体分析i2c_add_driver注册i2cdev_driver的过程
2.i2c_add_driver
i2c_add_driver函数只是对i2c_register_driver做了简单的封装,下面直接分析i2c_register_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
-
{
-
int res;
-
-
-
if (unlikely(WARN_ON(!i2c_bus_type.p))){
-
printk("Can't register until after driver model init\n");
-
return -EAGAIN;
-
}
-
-
-
driver->driver.owner = owner;
-
driver->driver.bus = &i2c_bus_type;
-
-
-
-
-
res = driver_register(&driver->driver);
-
if (res)
-
return res;
-
-
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
-
-
INIT_LIST_HEAD(&driver->clients);
-
-
mutex_lock(&core_lock);
-
bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
-
mutex_unlock(&core_lock);
-
-
return 0;
-
}
函数通过
driver->driver.bus = &i2c_bus_type;
可见此驱动通过函数driver_register()之后 同样会被注册到了i2c总线上。
值得一提的是此处i2cdev_driver中的attach_adapter的执行机会很大,
通过class_for_each_device()函数
class_for_each_device(&i2c_adapter_class, NULL, driver,
__attach_adapter);
会尝试和i2c总线上所有的dev进行一次匹配,只要获取的dev为adapter时,就可执行后续操作。
此处的class_for_each_device函数主要功能就是循环查询一遍i2c总线上所有的dev,包括adapter device和client device。
然后依次将dev和driver作为__attach_adapter的参数并执行__attach_adapter函数,
-
static int __attach_adapter(struct device *dev, void *data)
-
-
{
-
-
i2c_detect(adap, driver);
-
-
-
if (driver->attach_adapter) {
-
-
driver->attach_adapter(adap);
-
}
-
return 0;
-
}
可以发现在__attach_adapter函数主要执行的是i2c_dectect和driver->attach_adapter。
由于此处驱动并未初始化driver->detect,所以i2c_detect函数未执行有效操作就会退出。
接着通过传统方式执行driver->attach_adapter方法。
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
-
{
-
struct i2c_dev *i2c_dev;
-
int res;
-
-
i2c_dev = get_free_i2c_dev(adap);
-
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), 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;
-
}
可见attach_adapter函数的作用就是调用device_create()函数 通过之前class_create的类信息在/dev下自动创建设备文件。
并且此设备的设备号是由固定的主设备号I2C_MAJOR 和 从设备号组成的,从设备号取的就是adapter的nr,此处为0。
并且可以推断出系统最多可以容纳0~255 总共256个i2c adapter。
到此i2c部分的初始化就完成了,可以通过read write来操作设备了。
阅读(1590) | 评论(0) | 转发(0) |