Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2977707
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2014-09-14 16:20:32

原文地址: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 = {  

  1.     .driver = {  
  2.         .name   = "dev_driver",  
  3.     },  
  4.     .attach_adapter = i2cdev_attach_adapter,  
  5.     .detach_adapter = i2cdev_detach_adapter,  
  6. };  
此处注意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)  
  1. {  
  2.     int res;  
  3.   
  4.     /* Can't register until after driver model init */  
  5.     if (unlikely(WARN_ON(!i2c_bus_type.p))){  
  6.         printk("Can't register until after driver model init\n");  
  7.         return -EAGAIN;  
  8.     }  
  9.   
  10.     /* add the driver to the list of i2c drivers in the driver core */  
  11.     driver->driver.owner = owner;  
  12.     driver->driver.bus = &i2c_bus_type;  
  13.   
  14.     /* When registration returns, the driver core 
  15.      * will have called probe() for all matching-but-unbound devices. 
  16.      */  
  17.     res = driver_register(&driver->driver);  
  18.     if (res)  
  19.         return res;  
  20.   
  21.     pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);  
  22.   
  23.     INIT_LIST_HEAD(&driver->clients);  
  24.     /* Walk the adapters that are already present */  
  25.     mutex_lock(&core_lock);  
  26.     bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);  
  27.     mutex_unlock(&core_lock);  
  28.   
  29.     return 0;  
  30. }  

函数通过


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函数,

  1. static int __attach_adapter(struct device *dev, void *data)
  2.   
  3. {  
  4.     /* Detect supported devices on that bus, and instantiate them */  
  5.     i2c_detect(adap, driver);  
  6.   
  7.     /* Let legacy drivers scan this bus for matching devices */  
  8.     if (driver->attach_adapter) {  
  9.         /* We ignore the return code; if it fails, too bad */  
  10.         driver->attach_adapter(adap);  
  11.     }  
  12.     return 0;  
  13. }  


可以发现在__attach_adapter函数主要执行的是i2c_dectect和driver->attach_adapter。


由于此处驱动并未初始化driver->detect,所以i2c_detect函数未执行有效操作就会退出。

接着通过传统方式执行driver->attach_adapter方法。


static int i2cdev_attach_adapter(struct i2c_adapter *adap)  
  1. {  
  2.     struct i2c_dev *i2c_dev;  
  3.     int res;  
  4.   
  5.     i2c_dev = get_free_i2c_dev(adap);  
  6.     if (IS_ERR(i2c_dev))  
  7.         return PTR_ERR(i2c_dev);  
  8.   
  9.     /* register this i2c device with the driver core */  
  10.     i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,  
  11.                      MKDEV(I2C_MAJOR, adap->nr), NULL,  
  12.                      "i2c-%d", adap->nr);  
  13.     if (IS_ERR(i2c_dev->dev)) {  
  14.         res = PTR_ERR(i2c_dev->dev);  
  15.         goto error;  
  16.     }  
  17.     res = device_create_file(i2c_dev->dev, &dev_attr_name);  
  18.     if (res)  
  19.         goto error_destroy;  
  20.   
  21.     pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",  
  22.          adap->name, adap->nr);  
  23.     return 0;  
  24. error_destroy:  
  25.     device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));  
  26. error:  
  27.     return_i2c_dev(i2c_dev);  
  28.     return res;  
  29. }  

可见attach_adapter函数的作用就是调用device_create()函数 通过之前class_create的类信息在/dev下自动创建设备文件。

并且此设备的设备号是由固定的主设备号I2C_MAJOR 和 从设备号组成的,从设备号取的就是adapter的nr,此处为0。

并且可以推断出系统最多可以容纳0~255 总共256个i2c adapter。

到此i2c部分的初始化就完成了,可以通过read write来操作设备了。


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