原文再续,书接上回。本篇主要介绍i2c client与i2cdriver的框架实现,主要内容如下:
- I2c driver模块的注册与注销接口
- I2c client模块的注册与注销接口
- I2c client添加方式说明
I2c driver模块的注册与注销
本小节主要介绍i2c driver模块的注册与注销流程,i2c driver相关的结构体定义如下,可以理
解为设备驱动模型中struct device_driver的子类,并完成对基类方法(probe、remove、shutdown等接口)重载,并定义一些i2c 模块相关的变量(包括用于i2c client与i2c driver匹配判断的变量id_table)。
针对i2c_driver结构体而言,也就是重载了基类device_driver的方法,i2c_driver特有变量的
意义如下:
- 变量class、detect、address_list、clients,用于i2c模块自动探测i2c client(不通过设备驱动模型的方式实现i2c client与i2c driver的绑定),因此定义了链表头clients,实现i2c client、i2c_driver的绑定操作,这一类i2c设备的添加与探测,未通过linux设备驱动模型中的接口,因此i2c_driver来进行client与driver的绑定以及解绑的操作。这一类型的i2c client的探测,主要针对spd 、hwmon类型的硬件设备,且需要i2c adapter支持此种探测方式(通过class成员判断adapter、driver之间是否支持自动探测等)。
- 而command函数指针,如注释所述类似于ioctl,目前linux系统中很少有实现该函数指针的驱动。
- 而attach_adapter与上述a中的功能类似,内核不推荐使用。
struct i2c_driver {
/*该变量主要指示该driver支持的类型,包括hwmon、内存相关的spd等,主要用于detect某一个adapter下的
已挂载的硬件设备(且该硬件设备对应的逻辑设备未注册到i2c总线上)。*/
unsigned int class;
/* Notifies the driver that a new bus has appeared. You should avoid
* using this, it will be removed in a near future.
*/
/*该接口主要用于新注册adapter时,通过遍历i2c总线上所有已注册的驱动程序,针对每一个驱动均调用
attach_adapter接口,识别该adapter上挂载的i2c设备,并未识别到的设备创建其对应的i2c_client*/
int (*attach_adapter)(struct i2c_adapter *) __deprecated;
/* Standard driver model interfaces */
/*设备驱动模型的probe接口,在driver_register/device_register时,对于已注册的device和driver,
若匹配则调用driver_probe_device进行探测操作,最终即调用该驱动的probe接口*/
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
/*设备驱动模型的probe接口,在driver_unregister/device_unregister时,对于已绑定的device-driver,
调用__device_release_driver进行移除操作,最终会调用该去的的remove接口*/
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration */
/*电源管理相关的接口*/
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag").
*/
void (*alert)(struct i2c_client *, unsigned int data);
/* a ioctl like command that can be used to perform specific functions
* with the device.
*/
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
/*设备驱动模型中的device-driver类型变量,为了继承设备驱动模型,包含该变量,即可
使用设备驱动模型中的相应接口,实现驱动注册、驱动与设备的探测与移除等等内容*/
struct device_driver driver;
/*该驱动支持的设备列表,该变量主要用于设备与驱动的匹配*/
const struct i2c_device_id *id_table;
/* Device detection callback for automatic device creation */
/*该接口的作用是若已注册到i2c总线上的adapter上挂载的物理设备,并没有创建对应的逻辑对象,则调用
该接口,并根据该驱动的address_list上支持的地址类型,进行搜索该adapter上挂载的物理设
备(且没有创建对应的逻辑对象)*/
int (*detect)(struct i2c_client *, struct i2c_board_info *);
/*表明该驱动所支持的i2c设备的地址列表*/
const unsigned short *address_list;
struct list_head clients;
};
通过对i2c_driver的分析,我们可以发现,i2c_driver的注册与注销应该不复杂,也就是在调用设备驱动模型的driver_register的基础上,增加对自动探测i2c client的功能支持。
I2c driver 注册
I2c driver的注册接口定义为i2c_register_driver,我们首先来看下该接口的流程图。
和我们对i2c_driver结构体的分析结果一致(再一次说明了linux内核的结构体定义会提供很多有用的信息)。
- 调用driver_register,完成将该驱动注册到i2c总线上,同时针对所有已注册到i2c总线上的i2c client进行匹配检测与绑定操作(具体流程请看图“device_register/driver_register”);
- 针对需要自动探测的i2c client,遍历每一个注册到i2c总线上的adpater,根据该driver的address_list上支持的地址,进行探测与匹配,若匹配上则为该设备增加对应的i2c_client,同时调用i2c_new_device注册到i2c总线上,同时完成i2c_client与i2c_driver的绑定操作。(需要自动探测的设备类型为spd、hwmon等类型的设备)。
(针对驱动注册接口driver_register,属于LINUX设备-总线-驱动模型部分的内容,这部分内容在之前的文章中已经分析过,此处不再赘述,感兴趣的朋友可翻看我之前分析的文档,针对i2c、spi、pci这类驱动模块,强烈建议先熟悉LINUX设备-总线-驱动模型,把这个模型搞熟悉了,就会有一览众山小的感觉了)
I2c driver注销
I2c driver的注销接口为i2c_del_driver,该接口实现的内容刚好与上述注册部分相反,流程图如下:
- 针对i2c driver自动探测的i2c client,调用__process_removed_driver完成解除绑定及移除操作;
- 针对通过LINUX设备驱动模型完成的绑定的i2c client,通过调用driver_unregister完成i2c client的解绑以及i2c driver从i2c总线上注销(调用流程图如下device_unregister/driver_unregister)。
I2c client模块的注册与注销
I2c client相关的结构体的定义如下,也可以将i2c_client理解为device类型的子类。针对i2c模块的自定义变量有:
- flag用于说明i2c client的通信地址类型(7bit还是10bit)
- addr表示该i2c client的地址;
- 该i2c client所依附的adapter(因为一个i2c client需要借助i2c adapter的通信方法才能与cpu进行通信,因此增加该指针指向所依附的adapter);
- 该i2c_clietn所绑定的i2c_driver(这个操作所具体想表达的意思,我还不明晰,我认为使用设备驱动模型中的device、device_driver已经能实现i2c client与i2c driver的绑定类,此处为何还要增加一个指向i2c_driver的变量呢??)
- detected变量作用在上面的i2c_driver中就已经说明了(当该i2c client是由i2c_driver的detect接口探测且进行创建的,则通过该变量链接至对应的i2c_driver上)。
struct i2c_client {
/*主要用于设置i2c client的地址类型(10bit还是7bit)等信息*/
unsigned short flags; /* div., see below */
/*标注该i2c设备的地址,7bit或9bit()*/
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
char name[I2C_NAME_SIZE];
/*该i2c client所依附的i2c适配器*/
struct i2c_adapter *adapter; /* the adapter we sit on */
/*该i2c设备所绑定的驱动*/
struct i2c_driver *driver; /* and our access routines */
/*对应的device类型的变量,用于使用linux设备驱动模型*/
struct device dev; /* the device structure */
/*中断号*/
int irq; /* irq issued by device */
/*用于将该设备链接至其绑定的驱动对应的clients链表上*/
struct list_head detected;
};
而针对i2c client的注册与注销而言,应该也就是调用设备驱动模型中的注册与注销接口,不像i2c_driver那样还有自动探测与移除的功能,i2c client的注册与注销应该还是很简单的,我们来分析下
i2c_client的注册
I2c client创建与注册接口为i2c_new_device,该接口完成i2c_client的创建,并调用device_register将其注册到i2c总线上(若i2c总线上已注册了该设备对应的驱动,则会触发该client与对应driver的绑定操作,而device_register的调用流程,请参考上面图“device_regiser/driver_register”)。和我们分析i2c_client结构体中的说明一致,主要就是调用device_register完成注册及绑定操作。
I2c client的注销
I2c client的注销接口为i2c_unregister_device,该接口就是直接调用device_unregister,完成从i2c总线上注销该client,同时完成与绑定驱动的解除绑定操作,而关于device_unregister的调用流程,请参看上面图“device_unregister/driver_unregister”。
I2c client创建方式
针对i2c client而言,大致有两种创建方式,下面我们分别说明:
- 通过调用i2c_new_device,在LINUX系统初始化时,完成i2c client的创建与注册操作,而针对这一类设备,其与驱动的绑定与探测操作,由LINUX设备-总线-驱动模型中的流程机制来完成;(针对支持设备树的LINUX内核,在系统初始化时,通过读取dtb中定义的i2c client,调用该接口完成i2c设备注册到i2c总线上)。
- 由I2C driver通过其detect函数指针接口进行探测的client,这一类client与driver的绑定与解绑由i2c模块自己完成(通过__process_new_adapter/__process_new_driver实现绑定,通过__process_removed_adapter/__process_removed_driver),这种机制主要针对spd、hwmon类型的i2c设备。而这种机制的探测也是有条件的,即:
- I2c driver需要支持detect函数;
- I2c adapter与i2c driver均需要标注其支持自动探测i2c设备的类,且它们支持的类型存在交集时方可支持探测(如均标注支持hwmon、spd的探测等)。
以上即为本次分析的内容,主要涉及i2c client的注册与注销、i2c driver的注册与注销。而针对诸如i2c_new_probed_device、i2c_scan_static_board_info、i2c_sysfs_new_device等接口,也是调用i2c_new_device完成具体功能,此处不再介绍。下一章介绍i2c 通用设备以及i2c相关的通信接口的分析以及i2c模块的总结。