zoukankan      html  css  js  c++  java
  • 【Linux高级驱动】I2C驱动框架分析

    1.i2c-dev.c(i2c设备驱动组件层)

        功能:1)给用户提供接口

    i2c_dev_init  //入口函数
     /*申请主设备号*/

    register_chrdev(I2C_MAJOR(89), "i2c", &i2cdev_fops);
     /*创建一个设备类*/
     i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
     /*注册一个i2c驱动*/
     i2c_add_driver(&i2cdev_driver);
      i2c_register_driver(THIS_MODULE, driver);
       /*指定总线类型*/
       driver->driver.bus = &i2c_bus_type;
       /*驱动注册
        *1.将i2c驱动加入i2c总线的驱动链表
        *2.搜索设备链表,实现匹配,根据i2c总线的匹配原理:必须要求i2c驱动结构体中实现id_table
        *  但是,i2c驱动结构体中并没有实现id_table,所以永远都匹配失败
        */

       driver_register(&driver->driver);
        
       /*搜索适配器链表,每搜索一个适配器,都会调用__process_new_driver函数
        *在此函数中,又会调用i2c驱动中的,attach_adapter函数
        */

       bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
       __process_new_driver  //此函数可能会被调用多次
        i2c_do_add_adapter(data, to_i2c_adapter(dev));
         if (driver->attach_adapter) {
          /* We ignore the return code; if it fails, too bad */
          driver->attach_adapter(adap);    //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 struct i2c_driver i2cdev_driver = {
     .driver = {
      .name = "dev_driver",
     },
     .attach_adapter = i2cdev_attach_adapter,
     .detach_adapter = i2cdev_detach_adapter,
    };

     

    2.i2c-core.c(i2c核心层组件)

        功能:1)注册一条i2c总线
             2)提供基本的接口函数,用来建立上层与下层的连接

    i2c_init  //入口函数
     /*注册I2C总线*/
     bus_register(&i2c_bus_type);
       
    struct bus_type i2c_bus_type = {  //实际的物理总线,I2C总线
     .name  = "i2c",
     .match  = i2c_device_match,  //匹配函数
     .probe  = i2c_device_probe,
     .remove  = i2c_device_remove,
     .shutdown = i2c_device_shutdown,
     .pm  = &i2c_device_pm_ops,
    };
    static int i2c_device_match(struct device *dev, struct device_driver *drv)
    {
     struct i2c_client *client = i2c_verify_client(dev);
     struct i2c_driver *driver;
     if (!client)
      return 0;
     driver = to_i2c_driver(drv);
     /* match on an id table if there is one */
     if (driver->id_table)
      return i2c_match_id(driver->id_table, client) != NULL;
        while (id->name[0]) {
         if (strcmp(client->name, id->name) == 0)
          return id;
         id++;
        }
     return 0;
    }

    涉及的重要结构体:

    struct i2c_client {     //表示一个i2c设备
     unsigned short flags;   /* div., see below  */
     unsigned short addr;   /*器件地址*/
     char name[I2C_NAME_SIZE];  /*名字*/
     struct i2c_adapter *adapter; /*所属适配器,所属控制器*/
     struct i2c_driver *driver;  /*设备驱动*/
     struct device dev;    /* the device structure  */
     int irq;      /* irq issued by device  */
     struct list_head detected;
    };
    struct i2c_driver {     //用来表示i2c驱动
     unsigned int class;
     /* Notifies the driver that a new bus has appeared or is about to be
      * removed. You should avoid using this if you can, it will probably
      * be removed in a near future.
      */

     int (*attach_adapter)(struct i2c_adapter *);
     int (*detach_adapter)(struct i2c_adapter *);
     /*probe函数:初始化工作,设备检测,*/
     int (*probe)(struct i2c_client *, const struct i2c_device_id *);
     int (*remove)(struct i2c_client *);
     struct device_driver driver;    //设备驱动
     const struct i2c_device_id *id_table;  //指定此驱动能为哪些设备服务
     ...
     ...
    };
    struct i2c_adapter {    //表示一个i2c适配器/i2c控制器
     const struct i2c_algorithm *algo; /* the algorithm to access the bus */
      /*操作方法*/
      int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);
     int nr;     /*适配器的号码*/
     ...
     ...
    };
    struct i2c_msg {     //表示一个i2c数据包
     __u16 addr;      /*设备地址*/
     __u16 flags;     /*表示:1-表示读包 0-表示写包*/
     __u16 len;      /*数据包的长度*/
     __u8 *buf;      /*真正的数据*/
     ...
     ...
    };

    涉及的重要函数接口:

    /*注册一个i2c控制器*/
    int i2c_add_adapter(struct i2c_adapter *adapter)
    int i2c_del_adapter(struct i2c_adapter *adap)
    /*注册i2c驱动*/
    int i2c_add_driver(struct i2c_driver *driver)
    int i2c_add_numbered_adapter(struct i2c_adapter *adap)
    int i2c_del_numbered_adapter(struct i2c_adapter *adap)
    extern int i2c_del_driver(struct i2c_driver *driver);
    /*接收i2c数据包*/
    int i2c_master_recv(struct i2c_client *client, char *buf, int count)
    /*发送i2c数据包*/
    int i2c_master_send(struct i2c_client *client, const char *buf, int count)
    /*提交i2c数据包到总线驱动层*/
    int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

     

    3.busses目录:i2c总线驱动/i2c控制器驱动/i2c适配器驱动

        i2c-s3c2410.c

        功能:1)实现对i2c控制器的初始化
             2)实现操作方法(实现i2c协议,完成数据的发送)

    如何用通用接口驱动来操作i2c设备

    open

    app:  open("/dev/i2c-0", O_RDWR);
    =====================================
    sys:  sys_open
       ...
       ...
    i2c-dev.c struct file_operations i2cdev_fops
        .open  = i2cdev_open,
         /*构建一个i2c_client*/
         struct i2c_client *client; 
         struct i2c_adapter *adap;  
         /*获取适配器*/
         adap = i2c_get_adapter(i2c_dev->adap->nr);
         client = kzalloc(sizeof(*client), GFP_KERNEL);
         client->driver = &i2cdev_driver;  //指定i2c设备驱动
         client->adapter = adap;     //指定适配器
         file->private_data = client;

    ioctl

    app:  ioctl(fd, I2C_SLAVE, 0x48)
    ==============================================
    sys:  sys_ioctl
       ...
       ...
    i2c-dev.c struct file_operations i2cdev_fops
        .unlocked_ioctl = i2cdev_ioctl,
         /*获取i2c_client*/
         struct i2c_client *client = file->private_data;
         switch (cmd) {
          case I2C_SLAVE:    I2C_M_TEN:是否为10位寻址的设备
           if ((arg > 0x3ff) ||(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
            return -EINVAL;
           client->addr = arg;  //0x48
         }

    write

    app:  write(fd, wbuf, 1)
    ===============================================
    sys:  sys_write
       ...
       ...
    i2c-dev.c struct file_operations i2cdev_fops
        .write  = i2cdev_write,
         /*获取i2c_client*/
         struct i2c_client *client = file->private_data;
         char *tmp;
         tmp = kmalloc(count, GFP_KERNEL);
         copy_from_user(tmp, buf, count)
         
         /*发送数据到核心层*/
    i2c-core.c   i2c_master_send(client, tmp, count);
          struct i2c_msg msg;   //表示i2c数据包
          /*填充数据包*/
          msg.addr = client->addr;    //0x48
          msg.flags = client->flags & I2C_M_TEN; //写
          msg.len = count;      //1
          msg.buf = (char *)buf;     //wbuf 0x0
          /*提交数据给总线驱动层*/
          i2c_transfer(adap, &msg, 1);
           if (adap->algo->master_xfer) 
    i2c_s3c2410.c      adap->algo->master_xfer(adap, msgs, num);   //s3c24xx_i2c_xfer
             s3c24xx_i2c_xfer
              

    @成鹏致远

    (blogs:http://lcw.cnblogs.com

    (emailwwwlllll@126.com)

    (qq552158509





  • 相关阅读:
    爱生气的书店老板
    数组的度
    最大连续 1 的个数
    最大连续1的个数 III
    尽可能使字符串相等
    Java数据类型转换
    CSS卡片制作
    关于eclipse关联源码问题
    tomcat服务器对于http协议的处理
    shiro源码分析-认证过程
  • 原文地址:https://www.cnblogs.com/lcw/p/3802629.html
Copyright © 2011-2022 走看看