Linux2.6.37 I2C驱动框架分析(二)

来源:互联网 发布:广告铃声制作软件 编辑:程序博客网 时间:2024/05/18 02:45

  接着上一篇继续深入分析,要想彻底搞清楚整个框架唯一的方法就是分析代码,从代码中构建出系统框图。

  首先还是分析一下i2c框架的入口吧!!!

  postcore_initcall(i2c_init);

 i2c_init

    retval = bus_register(&i2c_bus_type);  注册一条总线

    i2c_adapter_compat_class = class_compat_register("i2c-adapter");  注册设备类

    retval = i2c_add_driver(&dummy_driver);  注册一个哑设备驱动

 

  出口的代码如下:

 i2c_exit

  i2c_del_driver(&dummy_driver);   注销i2c设备哑驱动

  class_compat_unregister(i2c_adapter_compat_class); 注销设备类

  bus_unregister(&i2c_bus_type); 注销总线

 

接着继续分析i2c核心提供的核心接口:

 1.注册i2c适配器驱动(也叫i2c总线驱动,注意这里的总线驱动不是上面的i2c_bus_type哦,上面的总线是Linux内核提供的总线、设备、驱动模型中的总线,而适配器驱动的总线指的是实际存在的i2c总线)。

 int i2c_add_adapter(struct i2c_adapter *adapter)

 int i2c_add_numbered_adapter(struct i2c_adapter *adap)

上面两个函数都是注册适配器驱动,唯一的区别在于,这一个函数注册的适配器的总线号是系统动态分配的,而第二个函数的总线号是确定的。这两个函数最终都要调用:

i2c_register_adapter(struct i2c_adapter *adapter)

   rt_mutex_init(&adap->bus_lock);            i2c_adapter的成员初始化
   mutex_init(&adap->userspace_clients_lock);
   INIT_LIST_HEAD(&adap->userspace_clients);

   dev_set_name(&adap->dev, "i2c-%d", adap->nr); 设置适配器的名字:如i2c-0
   adap->dev.bus = &i2c_bus_type;                设置该适配器所属的总线
   adap->dev.type = &i2c_adapter_type;           设置适配器的设备类型

  

   res = device_register(&adap->dev);  注册设备,该设备节点对链接到其所属的总线的

   class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
           adap->dev.parent);          在sysfs中的一些设置

   if (adap->nr < __i2c_first_dynamic_bus_num) 如果适配器的总线号小

                                               于  __i2c_first_dynamic_bus_num
   i2c_scan_static_board_info(adap); 会扫描静态定义的i2c_board_info的信息

   bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); 最终会取出i2c_bus_type中的每个i2c_driver与adapter作为参数调用__process_new_adapter(后面详细分析),看到这个函数最少我们有两点疑惑:一是i2c_scan_static_board_info什么时候才会被调用;二是bus_for_each_drv最终会干啥事。

  现在我们专注第一个疑惑:__i2c_first_dynamic_bus_num会在哪里设置呢?__i2c_first_dynamic_bus_num是定义在i2c-boardinfo.c中定义的全局变量,在新版的Linux中可以使用i2c_board_info这个模版来创建i2c设备,如:

  static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
     {
        I2C_BOARD_INFO("twl4030", 0x48),
        .flags = I2C_CLIENT_WAKE,
        .irq = INT_24XX_SYS_NIRQ,
        .platform_data = &sdp2430_twldata,
     },
};

使用这个模版后,需要使用i2c_register_board_info将这个结构连入内核的全局链表__i2c_board_list中。先进去分析一下i2c_register_board_info函数:

 

busnum: 这个设备链接到i2c总线的总线号

info: 如上面所示的定义的结构指针

len: 个数,注册的个数

i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len)

  if (busnum >= __i2c_first_dynamic_bus_num)  静态变量的初始值为0
     __i2c_first_dynamic_bus_num = busnum + 1; 该值会在此处加1,这样在i2c_register_adapter中i2c_scan_static_board_info会被调用。

     devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); 分配一个i2c_devinfo结构

     devinfo->busnum = busnum;   利用静态信息进行填充
     devinfo->board_info = *info;

     list_add_tail(&devinfo->list, &__i2c_board_list); 最终会以i2_devinfo结构链接到__i2c_board_list链表中去。

  现在在回到i2c_scan_static_board_info(adap)函数去分析。

i2c_scan_static_board_info(adap)

  list_for_each_entry(devinfo,&__i2c_board_list, list) {
    if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter,

                                                 &devinfo->board_info))

因此,只要扫描到一个i2c_devinfo,最终会调用i2c_new_device创建一个i2c_client的。我相信此时你会想看下i2c_new_device都干了些啥?就顺便进去看下吧!

i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

  struct i2c_client *client = kzalloc(sizeof *client, GFP_KERNEL); 动态申请i2c_client

  client->adapter = adap;  将i2_client.adapter指向此时这个注册的i2c_adapter

  client->flags = info->flags;  这些信息都是从i2c_board_info中拷贝来的

  client->addr = info->addr;

  client->irq = info->irq;

  strlcpy(client->name, info->type, sizeof(client->name));

  client->dev.parent = &client->adapter->dev;  设置父设备为i2c_adapter.dev
  client->dev.bus = &i2c_bus_type;       设置设备所属的总线为i2c_bus_type
  client->dev.type = &i2c_client_type;

  status = device_register(&client->dev); 注册这个设备这个设备也会注册到i2c_bus_type总线去了。接下来留下一个疑惑继续分析注册i2c设备驱动,后面在来解决留下的那个问题。

 

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)

  driver->driver.owner = owner;
  driver->driver.bus = &i2c_bus_type;   驱动也属于i2c_bus_type总线

  res = driver_register(&driver->driver); 注册这个i2c设备驱动

  bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver); 

遍历i2c_bus_type总线,取出每个adapter和driver作为参数调用__process_new_driver。这里也有两点疑惑:一是drver_register到底做了什么;而是__process_new_driver跟前面的__process_new_adapter是不是很像呢? 

同样的,我们先分析第一个疑惑:driver_register(&driver->driver);

driver_register(&driver->driver)

  bus_add_driver(drv);

    driver_attach(drv);

      bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

        driver_match_device(drv, dev)

            drv->bus->match(dev, drv)

               i2c_match_id(driver->id_table, client)  将i2c_driver.id_talbe与i2c_client.name名字是否匹配

        driver_probe_device(drv, dev);

          really_probe(dev, drv);

            dev->bus->probe(dev); 最终调用i2c_bus_type的probe函数

               driver->probe(client, i2c_match_id(driver->id_table, client)); 最终会调用i2c_driver.probe函数,前提是i2c_driver.id_table的名字与i2c_client.name相同哦。

  夜已深,还留下了两个疑惑,实际是一个疑惑就明天在分析吧。。。。未完待续

 

 

0 0
原创粉丝点击