说时迟,那时快,马上进入I2C驱动的最后一个小节了,在这个小节里,我们主要探讨i2c_algorithm 数据结构和i2c-core.c 的一些主要函数及其作用。有鉴于i2c-core.c 代码达2000行,所以本文仅对导出的函数(EXPORT_SYMBOL)进行简单注释,其它函数想必也是为前者服务的啦。好,马上进入正题:
i2c_algorithm 结构体
一个 i2c 适配器上的i2c 总线通信方法由其驱动程序提供的i2c_algorithm 数据结构描述,由algo 指针指向。i2c_algorithm 数据结构即为i2c_adapter 数据结构与具体i2c 适配器的总线通信方法的中间层,正是这个中间层使得上层的i2c 框架代码与与具体i2c 适配器的总线通信方法无关,从而实现了i2c 框架的
可移植性和重用性。当安装具体i2c 适配器的驱动程序时由相应驱动程序实现具体的i2c_algorithm 数据结构,其中的函数指针指向操作具体i2c 适配器的代码。
master_xfer/smbus_xfer 指针指向i2c 适配器驱动程序模块实现的i2c 通信协议或者smbus 通信协议。在用户进程通过i2c-dev 提供的/dev/i2c/%d 设备节点访问i2c 设备时,最终是通过调用
master_xfer 或者smbus_xfer 指向的方法完成的。
i2c-core.c
i2c.h 和i2c-core.c 为i2c 框架的主体,提供了核心数据结构的定义、i2c 适配器驱动和设备驱
动的注册、注销管理,i2c 通信方法上层的、与具体适配器无关的代码、检测设备地址的上层代码等;
i2c-dev.c 用于创建i2c 适配器的/dev/i2c/%d 设备节点,提供i2c 设备访问方法等。
下面介绍其主要的函数
函数i2c_init
主要做了以下几件事情:
1.i2c_add_driver(&dummy_driver);
注册i2c总线
2.class_compat_register("i2c-adapter");
注册一个可兼容的类
3.i2c_add_driver(&dummy_driver);
加载驱动
函数i2c_exit
这个就不解释了呀~~
结构体i2c_bus_type
本结构体被导出,其里面包含了6个函数,其作用看名字就能猜到个大概。下面贴出以上6个函数的代码。
函数i2c_add_adapter
函数主要作用是添加一个适配器
1.idr_get_new_above(&i2c_adapter_idr, adapter,
__i2c_first_dynamic_bus_num, &id);
确认是否还能分配得到适配器id,该操作不能被打断。
2.i2c_register_adapter(adapter);
注册一个适配器
函数i2c_del_adapter
对应于i2c_add_adapter,此函数删除一个适配器。
函数 i2c_register_driver
注册一个设备
1.driver_register(&driver->driver);
开始先注册一个设备
2.bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
调用相对应的__attach_adapter 函数,并传递参数driver 给它。完成设备绑定适配器的动作。至于__attach_adapter 的代码粘贴如下
函数i2c_del_driver
相对应i2c_register_driver,本函数执行卸载设备的动作。
1.bus_for_each_dev(&i2c_bus_type, NULL, driver, __detach_adapter);
调用__detach_adapter 函数,并传递函数driver 给它,完成分离设备和适配器的功能。
2.driver_unregister(&driver->driver);
卸载设备。
__detach_adapter 代码如下
最后来看3个重要的i2c总线操作函数
函数 i2c_transfer
该函数几乎与 i2c_master_recv 和i2c_master_send (接下来马上叙述)函数一模一样,都是在持有i2c_adapter 的lock 信号量的情况下利用i2c 适配器的algo 所指的i2c_algorithm 数据结构的master_xfer 方法执行实际的i2c 操作。
整个函数最重要的,当数for 循环里面的内容,而for 循环里面的内容,最最重要的,肯定就是
ret = adap->algo->master_xfer(adap, msgs, num); 经过前文提及的内容,master_xfer用于产生I2C访问周期需要的信号,以I2C消息为单位。
函数 i2c_master_send
把需要发送的数据以及其信息保存到msg 结构体,通过i2c_transfer 函数发送。
函数 i2c_master_recv
跟发送函数i2c_master_send 对应的一个接收函数,具体不作解释啦。
由于篇幅问题,故不能肆意展开全部代码,但我还是在这里罗列一下关于smbus协议需要注意的函数:
s32 i2c_smbus_read_byte(struct i2c_client *client);
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value);
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value);
s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command);
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value);
s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,
u8 *values);
s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
u8 length, const u8 *values);
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
unsigned short flags,
char read_write, u8 command, int size,
union i2c_smbus_data * data);
以上一系列的函数,都是在i2c_smbus_xfer 函数的基础上建立起来的,只要理解了基石,其上的函数就不足为惧了。最后的最后,看一下这个藏在代码最后的基石吧!
函数 i2c_smbus_xfer
该函数通过适配器驱动提供的总线访问方法(i2c_algorithm 的smbus_xfer 方法)尝试访问处于addr 地址上的设备。其实函数里面最核心的一句是:
res = adapter->algo->smbus_xfer(adapter, addr, flags,
read_write, command,
protocol, data);
哈哈,这岂不妙哉,到最后我们还是回到结构体i2c_algorithm 的smbus_xfef 成员函数(见本文起始部分)。真是众里寻他千百度,蓦然回首,此函数却在灯火阑珊处。
经过这一个i2c系列4个小节的学习,自己对代码的分析,特别是驱动代码的分析有了一定的提高,起码在心理上不会感到畏惧。希望各位初学的朋友能够跟我一起坚持下去,踏踏实实地走好每一步!
本系列博文链接:
I2C驱动(1)http://blog.csdn.net/jarvis_xian/archive/2011/05/27/6449939.aspx
I2C驱动(2)http://blog.csdn.net/jarvis_xian/archive/2011/05/27/6451168.aspx
I2C驱动(3)http://blog.csdn.net/jarvis_xian/archive/2011/05/28/6452431.aspx
I2C驱动(4)http://blog.csdn.net/jarvis_xian/archive/2011/05/30/6455697.aspx