1、目录1声明你可以自由地随意修改本文档的任何文字内容及图表,但是如果你在自己的文档中以任何形式直接引用了本文档的任何原有文字或图表并希望发布你的文档,那么你也得保证让所有得到你的文档的人同时享有你曾经享有过的权利。i2c 源代码情景分析(Beta2)作者在 上的 ID 为 shrek2欢迎补充,欢迎批评指正!第 1 章 i2c 核心数据结构之间的关系 .4第 2 章 i2c-core.c 的初始化 .10i2c_init 函数 .10i2cproc_init 函数 .11第 3 章 安装、卸载 pxa255 的 i2c 适配器驱动程序 .13pxa_i2c 数据结构 .13i2c_adap_p
2、xa_init 函数 .15i2c_add_adapter 函数 .16i2c_del_adapter 函数 .18i2c_adap_pxa_exit 函数 .20第 4 章 安装、卸载 ltc3445 驱动程序 .21ltc3445_init 函数 .21i2c_add_driver 函数 .22i2c_probe 函数 .23i2c_check_functionality 函数 .26i2c_smbus_xfer 函数 .27i2c_transfer 函数 .29ltc3445_detect_client 函数 .30i2c_attach_client 函数 .31ltc3445_clea
3、nup 函数 .32i2c_del_driver 函数 .33ltc3445_detach_client 函数 .35i2c_detach_client 函数 .35第 5 章 与 pxa255 的 i2c 适配器相关的代码 .37i2c_pxa_reset 函数 .37i2c_pxa_abort 函数 .38目录2i2c_pxa_xfer 函数 .38i2c_pxa_do_xfer 函数 .39i2c_pxa_start_message 函数 .41i2c_pxa_handler 函数 .42i2c_pxa_irq_txempty 函数 .42i2c_pxa_irq_rxfull 函数 .4
4、7第 6 章 i2c-dev 的初始化 .49i2c_dev_init 函数 .49i2cdev_attach_adapter 函数 .50第 7 章 i2c 框架提供的设备访问方法 .52i2cdev_open 函数 .52i2cdev_ioctl 函数 .53i2cdev_read 函数 .54i2c_master_recv 函数 .55对 i2cdev_read 和 i2c_master_recv 的修改 .56i2cdev_release 函数 .59第 8 章 编写 i2c 设备驱动程序模块的方法 .61第 9 章 用户进程访问 i2c 设备的步骤 .64讨论和总结 .65i2c 操
5、作中的同步问题 .65总结各个模块初始化函数的作用 .65对 i2c 框架代码的修改 .66有关 i2c 设备私有数据结构的讨论 .68遗留的问题 .68(注意:本文档中的源代码以 i2c-2.9.1 包及 www.arm.linux.org.uk 上下载的 pxa 的 i2c 适配器的补丁2360-2 为准!)第 1 章 i2c 核心数据结构之间的关系3第 1 章 i2c 核心数据结构之间的关系i2c 总线适配器(adapter )就是一条 i2c 总线的控制器,在物理连接上若干 i2c 设备并联于该 i2c 总线的SCL 和 SDA 线上,如下图所示:那么相应软件数据结构的设计、数据结构之
6、间的关系就至少应该描述硬件物理连接的这种组织关系。Linux 的 i2c 框架中各个部分的关系如下图所示:SDApxa255 I2CLTC3445 other deviceSCL第 1 章 i2c 核心数据结构之间的关系4内核中 i2c 相关代码可以分为三个层次:1. i2c 框架:i2c.h 和 i2c-core.c 为 i2c 框架的主体,提供了核心数据结构的定义、i2c 适配器驱动和设备驱动的注册、注销管理,i2c 通信方法上层的、与具体适配器无关的代码、检测设备地址的上层代码等;i2c-dev.c 用于创建 i2c 适配器的 /dev/i2c/%d 设备节点,提供 i2c 设备访问方法
7、等。2. i2c 总线适配器驱动:定义描述具体 i2c 总线适配器的 i2c_adapter 数据结构、实现在具体 i2c 适配器上的 i2c 总线通信方法,并由 i2c_algorithm 数据结构进行描述。3. i2c 设备驱动:定义描述具体设备的 i2c_client 和可能的私有数据结构、借助 i2c 框架的 i2c_probe 函数实现注册设备的 attach_adapter 方法、提供设备可能使用的地址范围、以及设备地址检测成功后创建 i2c_client 数据结构的回调函数。下面介绍 i2c 各核心数据结构的定义和它们之间的连接关系。1. 一个 i2c 设备的驱动程序由 i2c_
8、driver 数据结构描述,定义于 include/linux/i2c.h:struct i2c_driver char name32;int id;unsigned int flags;int (*attach_adapter)(struct i2c_adapter *);int (*detach_client)(struct i2c_client *);int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);void (*inc_use)(struct i2c_client *client);void (*
9、dec_use)(struct i2c_client *client);其中 name 为最大长度为 32 字节的字符串,id 可选 0xf000 到 0xffff 中的任一数值,flags 域可以直接设置为 I2C_DF_NOTIFY。attach_adapter 回调函数在安装 i2c 设备驱动程序模块时、或者在安装 i2c 适配器驱动程序模块时被调用,用于检测、认领设备并为设备分配 i2c_client 数据结构。detach_client 方法在卸载适配器或设备驱动程序模块时被调用,用于从总线上注销设备、并释放 i2c_client 及相应的私有数据结构。inc_use 和 dec_u
10、se 所指向的函数用于改变 i2c 设备驱动程序模块的引用计数。注意不要直接调用i2c_driver 数据结构中的这两个方法,而要通过如下函数调用路径:i2c_use_client i2c_inc_use_client inc_usei2c_release_client i2c_dec_use_client dec_use通过最顶层的 i2c_use/release_client 函数来同时改变 i2c 设备和 i2c 适配器驱动程序模块的引用计数。另外,不能在 attach_adapter 函数检测到一个 i2c 设备时就增加驱动程序模块的引用计数,而应该在用户进程访问一个/dev/i2c/
11、%d 设备节点时增加模块的引用计数,则关闭设备节点时减少引用计数(但在当前的应用中,适配器和设备的驱动程序都是静态地链接入内核映像的,所以在 pxa255 的 i2c 补丁中并没有使用控制引用计数的函数) 。第 1 章 i2c 核心数据结构之间的关系52. 一个 i2c 设备由 i2c_client 数据结构进行描述:struct i2c_client char name32;int id;unsigned int flags; /* div., see below */unsigned int addr; /* chip address - NOTE: 7bit addresses are
12、stored in the */* _LOWER_ 7 bits of this char */struct i2c_adapter *adapter; /* the adapter we sit on */struct i2c_driver *driver; /* and our access routines */void *data; /* for the clients */int usage_count; /* How many accesses currently to the client*/;在安装适配器或者设备的驱动程序时通过设备驱动程序 i2c_driver 中的 atta
13、ch_adapter 函数检测设备地址。如果检测成功则调用设备驱动程序提供的回调函数创建描述设备的 i2c_client 数据结构,并将其中的driver 指针指向设备驱动程序的 i2c_driver 数据结构。这样将来就可以使用 i2c_driver 中的注销设备和控制引用计数的方法了。由下文可见在描述 i2c 适配器的 i2c_adapter 数据结构中设计了指向该总线上所有 i2c 设备的 i2c_client 数据结构的指针数组 clients,而每个 i2c_client 又通过 adapter 指针回指 i2c_adapter。数据结构之间类似的组织关系在 Linux 内核中屡见不
14、鲜,比如父子进程的 PCB 之间、父目录及子目录和子文件的 dentry 之间,等等。每个 i2c 设备都有唯一的 7 位地址 addr。由于设备可能支持多个地址,所以在设备驱动程序模块中要指出需要检测的地址范围(由 i2c_client_address_data 二维数组指定) ,而设备实际使用的地址在检测成功并为之分配 i2c_client 数据结构时填入。以 i2c 设备 ltc3445 为例,硬件支持的地址为 1001011 或者 0101011,即 7 位地址的高 2 位由具体的布线方法决定(可以分别接到 VCC 或者 GND) 。如果 ltc3445 驱动程序的开发者知道具体的布线
15、方法,那么在驱动程序中就可以直接指定。否则可以指定地址检测范围为这两个地址,而在加载驱动程序模块时由软件进行地址检测。需要说明的是,i2c 设备的 7 位地址是就当前 i2c 总线而言的,是“相对地址” 。不同的 i2c 总线上的设备可以使用相同的 7 位地址,但是它们所在的 i2c 总线不同。所以在系统中一个 i2c 设备的“绝对地址”由二元组(i2c 适配器的 ID 和设备在该总线上的 7 位地址)表示。i2c_client 数据结构为描述 i2c 设备的“模板” ,而具体的 i2c 设备可能需要描述个性的私有数据。私有数据结构由 i2c_client 数据结构中的 data 域指向。设备
16、驱动程序开发者可以设计合适的私有数据结构来描述硬件的特性。值得一提的是,目前在 Linux 内核中常用的表示与具体设备、对象等相关的私有数据结构的方法有两种,一种就是采用 void 类型的指针 data 来指向具体的私有数据结构,又比如 file 结构中的private_data 域在设备驱动程序中往往被设置为指向具体的设备数据结构;第二种方法就是采用 union 域,比如 VFS 的 super_block、inode 数据结构。super_block 和 inode 数据结构本身集中描述了各种文件系统的共性,而具体文件系统的个性则放到 union 中进行描述,在挂载具体的文件系统时实例化为
17、具体的 union对象,比如 ext2_inode_union 或者 jffs2_inode_info。第 1 章 i2c 核心数据结构之间的关系6有关设计私有数据的的讨论可参见本文末尾的讨论 部分。当不同进程访问同一 i2c 总线时,对 i2c 总线的互斥访问由 i2c_adapter 的 lock 信号量实现,系统调用执行流只有在获得该信号量期间才能调用 master_xfer,并且在阻塞期间不释放信号量(类似在读写正规文件期间必须持有 inode.i_sem,参见本文末尾的讨 论部分) 。而 usage_count 域为设备的使用引用计数,在i2c_use_client 和 i2c_re
18、lease_client 函数中控制 usage_count 域的值(但是当前 pxa255 的 i2c 补丁中并没有使用这两个函数,usage_count 的值自初始化后就一直为 0) 。3. 一个 i2c 适配器由 i2c_adapter 数据结构描述:struct i2c_adapter char name32;unsigned int id; /* = is algo-id | hwdep.struct-id, for registered values see below */struct i2c_algorithm *algo; /* the algorithm to access
19、 the bus */void *algo_data;void (*inc_use)(struct i2c_adapter *);void (*dec_use)(struct i2c_adapter *);int (*client_register)(struct i2c_client *);int (*client_unregister)(struct i2c_client *);void *data; /* private data for the adapter */struct semaphore lock; unsigned int flags; /* flags specifyin
20、g div. data */struct i2c_client *clientsI2C_CLIENT_MAX;int client_count;int timeout;int retries;#ifdef CONFIG_PROC_FS /* No need to set this when you initialize the adapter */int inode;#if LINUX_VERSION_CODE KERNEL_VERSION(2,1,29)struct proc_dir_entry *proc_entry;#endif#endif /* def CONFIG_PROC_FS *
21、/;在 i2c_adapter 数据结构中设计了 clients 指针数组,指向该总线上每个设备的 i2c_client 数据结构。由于一条 i2c 总线上最多只有 I2C_CLENT_MAX 个设备,所以可以使用静态数组(题外话,如果相关数据结构的个数是未知的,链表显然是更好的选择) 。lock 信号量用于实现对 i2c 总线的互斥访问:在访问 i2c 总线上的任一设备期间当前进程必须首先获得该信号量,并且在阻塞等待 i2c 操作完成期间不释放。一个 i2c 适配器上的 i2c 总线通信方法由其驱动程序提供的 i2c_algorithm 数据结构描述,由 algo 指针指向。i2c_algo
22、rithm 数据结构即为 i2c_adapter 数据结构与具体 i2c 适配器的总线通信方法的中间层,由下文可见正是这个中间层使得上层的 i2c 框架代码与与具体 i2c 适配器的总线通信方法无关,从而实现了 i2c 框架第 1 章 i2c 核心数据结构之间的关系7的可移植性和重用性。当安装具体 i2c 适配器的驱动程序时由相应驱动程序实现具体的 i2c_algorithm 数据结构,其中的函数指针指向操作具体 i2c 适配器的代码(换用面向对象的语言,就是当创建子类对象时将基类中定义的函数调用接口实例化为与具体子类相关的代码。值得说明的是,在 Linux 内核层次中数据结构的设计大量地采用
23、了面向对象的概念来实现框架的可移植性和重用性) 。inc_use 和 dec_use 方法可以用来控制适配器驱动程序的引用计数;client_register 和 client_unregister 函数可以用来完成适配器端的、额外的设备注册和注销工作。这些函数在当前 pxa255 的 i2c 补丁中都没有实现。最后 timeout 和 retries 用于超时重传机制。4. 具体 i2c 适配器的通信方法由 i2c_algorithm 数据结构进行描述:struct i2c_algorithm char name32; /* textual description */unsigned in
24、t id;int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg msgs, int num);int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write,u8 command, int size, union i2c_smbus_data * data);int (*slave_send)(struct i2c_adapter *,char*,int);int (*slave_recv)(struct i
25、2c_adapter *,char*,int);int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);u32 (*functionality) (struct i2c_adapter *);master_xfer/smbus_xfer 指针指向 i2c 适配器驱动程序模块实现的 i2c 通信协议或者 smbus 通信协议。由下文分析可见在用户进程通过 i2c-dev 提供的/dev/i2c/%d 设备节点访问 i2c 设备时,最终是通过调用master_xfer 或者 smbus_xfer 指向的方法完成的
26、。slave_send/recv 函数用于实现当 i2c 适配器扮演 slave 角色时的传输方法。由于在 pxa255 的现有应用中其i2c 适配器始终为主导 i2c 通信的 master,故补丁中这两个函数都没有实现。i2c_algorithm 提供了 i2c 适配器的驱动,而 i2c 设备的驱动为 i2c_driver。内核中静态指针数组 adapters 和drivers 分别记录所有已经注册的 i2c 总线设备和 i2c 设备驱动。从下文源代码分析可以看到,安装 i2c 总线驱动和 i2c 设备驱动的顺序不确定,因此在安装 i2c 设备驱动时必须遍历所有已注册的适配器上的 i2c设备
27、,以“认领”相应的设备;同理,在安装 i2c 适配器驱动时必须遍历所有已注册的 i2c 设备的驱动程序,让已有驱动程序“认领”新注册的适配器上的所有设备。5. 假设一条 i2c 总线上有两个使用相同驱动程序的 i2c 设备,在打开该 i2c 总线的设备结点后相关数据结构之间的逻辑组织关系如下图所示。在阅读下文时请经常参照下图。上层的 i2c 框架实现了控制策略,具体 i2c 适配器和设备的驱动实现了使具体设备可用的机制,上层策略和底层机制通过中间的函数调用接口联系。正是中间的函数调用接口使得上层策略与底层机制无关,从而使得上层策略具有良好的可移植性和重用性。阅读完全文后可以回过头来总结一下各数据结构的作用、创建时机、由谁创建等,品味这一点是如何通过这些数据结构实现的,进一步在自己的研发过程中积极第 1 章 i2c 核心数据结构之间的关系8实践这种思想并享受学以致用的乐趣:)第 1 章 i2c 核心数据结构之间的关系9i2c_msgi2c_algorithmnameidmaster_xfersmbus_xferalgo_controlfunctionalitynameidflagsattach_adapterdetach_clientcommandinc_usedec_usei2c_drivernameidflagsaddradapterdriverdatausage_
Copyright © 2018-2021 Wenke99.com All rights reserved
工信部备案号:浙ICP备20026746号-2
公安局备案号:浙公网安备33038302330469号
本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。