linux-2.6.22源码分析\linux-2.6.22\drivers\i2c\chips\eeprom.c为例,分析i2c设备驱动程序的原理
1.从驱动的入口函数开始分析
eeprom_init
>i2c_add_driver(&eeprom_driver)
>i2c_register_driver(THIS_MODULE, driver)
>is_newstyle_driver(driver) //这是一处宏定义:#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
/*用于判断是否是新风格的驱动,新风格的驱动i2c_driver成员的probe与remove函数指针都为空*/
接下来填充i2c_driver的owner与bus成员
>driver_register(&driver->driver)
>bus_add_driver(&driver->driver)也就是(struct device_driver * drv)//添加成功返回0
>list_add_tail(&driver->list,&drivers)//把该i2c_driver添加到链表drivers全局变量中
>list_for_each_entry(adapter, &adapters, list) //遍历adapters适配器链表的所有成员
{driver->attach_adapter(adapter);} //调用i2c_driver->attach_adapter
在eeprom.c中定义了一个全局变量:
static struct i2c_driver eeprom_driver = {
.driver = {
.name = "eeprom",
},
.id = I2C_DRIVERID_EEPROM,
.attach_adapter = eeprom_attach_adapter,
.detach_client = eeprom_detach_client,
};
2.i2c设备的探测过程分析
在1中遍历调用了适配器链表中的每一个成员的attach_adapter成员函数,来完成i2c设备的探测
driver->attach_adapter(adapter)
等效于
eeprom_attach_adapter
>i2c_probe(adapter, &addr_data, eeprom_detect)
//当探测到i2c设备后会调用第三个参数所指的函数:也就是函数eeprom_detect。
/*在i2c.h头文件中定义了addr_data全局变量
*static struct i2c_client_address_data addr_data = { \
* .normal_i2c = normal_i2c, \
* .probe = probe, \
* .ignore = ignore, \
* .forces = forces, \
*}
*/
函数原型为:
i2c_probe(struct i2c_adapter *adapter,
struct i2c_client_address_data *address_data,
int (*found_proc) (struct i2c_adapter *, int, int))
>判断是否强制识别 if(address_data->forces),如果设置了i2c_client_address_data的
成员.forces则强制识别,采取相应的措施。
>i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)//检查是否支持SMBUS_QUICK方式
>for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2){
判断if(address_data->probe[i] || address_data->probe[i] == ANY_I2C_BUS)成立则:
>i2c_probe_address(adapter,address_data->probe[i + 1],-1, found_proc);
>i2c_check_addr(adapter, addr)
>__i2c_check_addr(adapter, addr)//检查地址是否可用
>i2c_smbus_xfer(adapter, addr, 0, 0, 0,I2C_SMBUS_QUICK, NULL)
>如果定义了adapter->algo->smbus_xfer则调用:
adapter->algo->smbus_xfer(adapter,addr,flags,read_write,command,size,data)
>found_proc(adapter, addr, kind)//也就是调用i2c_probe函数的第三个参数
(该参数为一个函数)
>否则调用:
i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,command,size,da