二.i2c子系统操作函数,i2c-core.c
1.
kernel/driver/linux/i2c/i2c-core.c
/**
* i2c_add_adapter - declare i2c adapter, use dynamic bus number
* @adapter: the adapter to add
* Context: can sleep
*
* This routine is used to declare an I2C adapter when its bus number
* doesn't matter. Examples: for I2C adapters dynamically added by
* USB links or PCI plugin cards.
*
* When this returns zero, a new bus number was allocated and stored
* in adap->nr, and the specified adapter became available for clients.
* Otherwise, a negative errno value is returned.
*/
int i2c_add_adapter(struct i2c_adapter *adapter)
{
int id, res = 0;
retry:
if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
return -ENOMEM;
mutex_lock(&core_lock);
/* "above" here means "above or equal to", sigh */
res = idr_get_new_above(&i2c_adapter_idr, adapter,
__i2c_first_dynamic_bus_num, &id);
mutex_unlock(&core_lock);
if (res < 0) {
if (res == -EAGAIN)
goto retry;
return res;
}
adapter->nr = id;
return i2c_register_adapter(adapter);
}
i2c_add_adapter 注册i2c适配器到系统,主要功能是首先通过ird机制给i2c适配器分配指针,然后注册该i2c适配器
idr_pre_get 预分配i2c适配器指针
idr_get_new_above 给i2c适配器分配指针并和id关联
i2c_register_adapter i2c注册适配器
kernel/driver/linux/i2c/i2c-core.c
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p))) {
res = -EAGAIN;
goto out_list;
}
/* Sanity checks */
if (unlikely(adap->name[0] == '\0')) {
pr_err("i2c-core: Attempt to register an adapter with "
"no name!\n");
return -EINVAL;
}
if (unlikely(!adap->algo)) {
pr_err("i2c-core: Attempt to register adapter '%s' with "
"no algo!\n", adap->name);
return -EINVAL;
}
rt_mutex_init(&adap->bus_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
adap->timeout = HZ;
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev);
if (res)
goto out_list;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
#ifdef CONFIG_I2C_COMPAT
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
adap->dev.parent);
if (res)
dev_warn(&adap->dev,
"Failed to create compatibility class link\n");
#endif
/* create pre-declared device nodes */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/* Notify drivers */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
mutex_unlock(&core_lock);
return 0;
out_list:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
return res;
}
i2c_register_adapter 注册适配器
unlikely(WARN_ON(!i2c_bus_type.p 检查总线是否初始化完成
unlikely(adap->name[0] == '\0') 检查适配器名称是否为空
unlikely(!adap->algo) 检查适配器算法是否为空
rt_mutex_init(&adap->bus_lock); 初始化实时互斥锁
mutex_init(&adap->userspace_clients_lock); 初始化用户设备锁
INIT_LIST_HEAD(&adap->userspace_clients); 初始化i2c设备链表
dev_set_name(&adap->dev, "i2c-%d", adap->nr); 设置适配器设备驱动模型设备名称
adap->dev.bus = &i2c_bus_type; 初始化适配器设备驱动模型设备的总线类型
adap->dev.type = &i2c_adapter_type; 初始化适配器设备驱动模型设备类型
device_register(&adap->dev); 注册适配器设备到设备驱动模型
i2c_scan_static_board_info(adap); 扫描静态声明的i2c设备信息,该方法也对应i2c设备静态声明注册
kernel/driver/linux/i2c/i2c-core.c
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
struct i2c_devinfo*devinfo;
down_read(&__i2c_board_lock);
list_for_each_entry(devinfo, &__i2c_board_list, list) {
if (devinfo->busnum == adapter->nr
&& !i2c_new_device(adapter,
&devinfo->board_info))
dev_err(&