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相同哦。
夜已深,还留下了两个疑惑,实际是一个疑惑就明天在分析吧。。。。未完待续
- Linux2.6.37 I2C驱动框架分析(二)
- Linux2.6.37 I2C驱动框架分析(一)
- Linux2.6.37 I2C驱动框架分析(三)
- Linux2.6.37 I2C驱动框架分析(五)
- Linux2.6.37 I2C驱动框架分析(六)
- Linux2.6.37 I2C驱动框架(四)
- Linux I2C驱动完全分析(二)
- Linux I2C驱动源码分析(二)
- Linux I2C驱动源码分析(二)
- Linux I2C驱动源码分析(二)
- Linux I2C驱动完全分析(二)
- Linux I2C驱动完全分析(二)
- Linux I2C驱动完全分析(二)
- Linux I2C驱动完全分析(二)
- linux I2C驱动分析(二)
- Linux下I2C驱动分析(二)
- Linux I2C驱动完全分析(二)
- i2c 驱动举例框架分析
- 25个增强iOS应用程序性能的提示和技巧
- Android开发进阶之NIO非阻塞包
- 十种贵人可遇不可求
- ServletContext例子
- 深入理解l内核v4l2框架之video for linux 2
- Linux2.6.37 I2C驱动框架分析(二)
- "阿爸的虱目鱼" - 萧煌奇
- Oracle nologging
- LeetCode Merge Two Sorted Lists
- 学习makefile语法(1)
- Oracle Database Compression 3 - Hybrid Columnar Compression
- UVa:10717 Mint
- flume ng配置拓扑图
- Oracle Database Compression 1 - Basic Compression