根据上一节课的分析,我们来解读这段代码:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; /* 地址值是7位 */
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr, /* 要发出S信号和设备地址并得到ACK信号,才能确定存在这个设备 */
.probe = ignore,
.ignore = ignore,
};
static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind)
{
printk("at24cxx_detect\n");
return 0;
}
/* i2c_add_driver之后会调用到这个函数 */
static int at24cxx_attach(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, at24cxx_detect);//这个函数最终会调用适配器的发送函数来发送设备地址
}
/* i2c_del_driver时会调用这个函数,但前提是调用在at24cxx_detect函数中调用了i2c_attach_client函数将 设备、驱动、适配器三者联系起来了*/
static int at24cxx_detach(struct i2c_client *client)
{
printk("at24cxx_detach\n");
return 0;
}
/* 1. 分配一个i2c_driver结构体 */
/* 2. 设置i2c_driver结构体 */
static struct i2c_driver at24cxx_driver = {
.driver = {
.name = "at24cxx",
},
.attach_adapter = at24cxx_attach,
.detach_client = at24cxx_detach,
};
static int at24cxx_init(void)
{
i2c_add_driver(&at24cxx_driver);
return 0;
}
static void at24cxx_exit(void)
{
i2c_del_driver(&at24cxx_driver);
}
module_init(at24cxx_init);
module_exit(at24cxx_exit);
MODULE_LICENSE("GPL");
我们来分析一下这个程序的流程:
首先分配一个i2c_driver结构体,然后设置并注册这个结构体。设置的时候有来个函数比较重要:attach_adapter 和.detach_client ,前一个在注册的时候调用,后一个在卸载的时候调用。注册之后,这个结构体就被加入到总线驱动列表里面,然后它会调用at24cxx_attach函数,at24cxx_attach函数又会调用i2c_probe(adapter, &addr_data, at24cxx_detect);函数,其中addr_data,代表设备地址,at24cxx_detect是
当调用 i2c_del_driver卸载i2c_driver这个结构体的时候,就会调用对应的驱动程序的 .detach_client = at24cxx_detach,函数来解除连接,但是前提是已经通过i2c_attach_client函数建立了联系。由于这里并没有建立联系,所以。。。。。。
我们可以总结出编写IIC总线驱动的大致流程:
1. 分配一个i2c_driver结构体
2. 设置
attach_adapter // 它直接调用 i2c_probe(adap, 设备地址, 发现这个设备后要调用的函数);
detach_client // 卸载这个驱动后,如果之前发现能够支持的设备,则调用它来清理
3. 注册:i2c_add_driver