1、总线适配器注册:
1)drivers/i2c/i2c-core.c
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_lists);
/* "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_lists);
if (res < 0) {
if (res == -EAGAIN)
goto retry;
return res;
}
adapter->nr = id; //使用动态的总线号来标识总线适配器。
return i2c_register_adapter(adapter);
}
EXPORT_SYMBOL(i2c_add_adapter);
2)drivers/i2c/i2c-core.c
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0;
struct list_head *item;
struct i2c_driver *driver;
mutex_init(&adap->bus_lock); //初始化总线访问控制变量(总线上数据传输时使用)
mutex_init(&adap->clist_lock); //初始化客户端访问控制变量(操作客户端结构时使用)
INIT_LIST_HEAD(&adap->clients); //初始化客户端链表头
mutex_lock(&core_lists);
list_add_tail(&adap->list, &adapters); //添加到总线适配器链表中
/* Add the adapter to the driver core.
* If the parent pointer is not set up,
* we add this adapter to the host bus.
*/
if (adap->dev.parent == NULL) {
adap->dev.parent = &platform_bus;
pr_debug("I2C adapter driver [%s] forgot to specify "
"physical device\n", adap->name);
}
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
adap->dev.release = &i2c_adapter_dev_release;
adap->dev.class = &i2c_adapter_class;
res = device_register(&adap->dev); //注册设备
if (res)
goto out_list;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
/* create pre-declared device nodes for new-style drivers */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/* let legacy drivers scan this bus for matching devices */
list_for_each(item,&drivers) { //搜索总线上的所有设备驱动,通过调用其attach_adapter接口函数,查找匹配的设备。
driver = list_entry(item, struct i2c_driver, list);
if (driver->attach_adapter)
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
out_unlock:
mutex_unlock(&core_lists);
return res;
out_list:
list_del(&adap->list);
idr_remove(&i2c_adapter_idr, adap->nr);
goto out_unlock;
}
2、设备驱动注册(以i2c-dev.c为例):
1)include/linux/i2c.h
static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}
2)drivers/i2c/i2c-core.c
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* new style driver methods can't mix with legacy ones */
if (is_newstyle_driver(driver)) {
if (driver->attach_adapter || driver->detach_adapter
|| driver->detach_client) {
printk(KERN_WARNING
"i2c-core: driver [%s] is confused\n",
driver->driver.name);
return -EINVAL;
}
}
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
/* for new style drivers, when registration returns the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver); //注册驱动
if (res)
return res;
mutex_lock(&core_lists);
list_add_tail(&driver->list,&drivers); //添加到设备驱动链表中
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
/* legacy drivers scan i2c busses directly */
if (driver->attach_adapter) {
struct i2c_adapter *adapter;
list_for_each_entry(adapter, &adapters, list) { //让设备驱动搜索匹配的适配器(通过调用其attach_adapter接口)
driver->attach_adapter(adapter);
}
}
mutex_unlock(&core_lists);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
3)drivers/i2c/i2c-dev.c
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
int res;
i2c_dev = get_free_i2c_dev(adap); //创建并初始化i2c_dev结构
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
/* register this i2c device with the driver core */
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev, //注意,这里使用的次设备号为adap->nr,便于以后获取adap结构。
MKDEV(I2C_MAJOR, adap->nr),
"i2c-%d", adap->nr);
if (IS_ERR(i2c_dev->dev)) {
res = PTR_ERR(i2c_dev->dev);
goto error;
}
res = device_create_file(i2c_dev->dev, &dev_attr_name); //创建设备文件
if (res)
goto error_destroy;
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
adap->name, adap->nr);
return 0;
error_destroy:
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
return_i2c_dev(i2c_dev);
return res;
}
总结:
一个适配器对应一个i2c控制器。
1)drivers/i2c/i2c-core.c
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_lists);
/* "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_lists);
if (res < 0) {
if (res == -EAGAIN)
goto retry;
return res;
}
adapter->nr = id; //使用动态的总线号来标识总线适配器。
return i2c_register_adapter(adapter);
}
EXPORT_SYMBOL(i2c_add_adapter);
2)drivers/i2c/i2c-core.c
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0;
struct list_head *item;
struct i2c_driver *driver;
mutex_init(&adap->bus_lock); //初始化总线访问控制变量(总线上数据传输时使用)
mutex_init(&adap->clist_lock); //初始化客户端访问控制变量(操作客户端结构时使用)
INIT_LIST_HEAD(&adap->clients); //初始化客户端链表头
mutex_lock(&core_lists);
list_add_tail(&adap->list, &adapters); //添加到总线适配器链表中
/* Add the adapter to the driver core.
* If the parent pointer is not set up,
* we add this adapter to the host bus.
*/
if (adap->dev.parent == NULL) {
adap->dev.parent = &platform_bus;
pr_debug("I2C adapter driver [%s] forgot to specify "
"physical device\n", adap->name);
}
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
adap->dev.release = &i2c_adapter_dev_release;
adap->dev.class = &i2c_adapter_class;
res = device_register(&adap->dev); //注册设备
if (res)
goto out_list;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
/* create pre-declared device nodes for new-style drivers */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/* let legacy drivers scan this bus for matching devices */
list_for_each(item,&drivers) { //搜索总线上的所有设备驱动,通过调用其attach_adapter接口函数,查找匹配的设备。
driver = list_entry(item, struct i2c_driver, list);
if (driver->attach_adapter)
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
out_unlock:
mutex_unlock(&core_lists);
return res;
out_list:
list_del(&adap->list);
idr_remove(&i2c_adapter_idr, adap->nr);
goto out_unlock;
}
2、设备驱动注册(以i2c-dev.c为例):
1)include/linux/i2c.h
static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}
2)drivers/i2c/i2c-core.c
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* new style driver methods can't mix with legacy ones */
if (is_newstyle_driver(driver)) {
if (driver->attach_adapter || driver->detach_adapter
|| driver->detach_client) {
printk(KERN_WARNING
"i2c-core: driver [%s] is confused\n",
driver->driver.name);
return -EINVAL;
}
}
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
/* for new style drivers, when registration returns the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver); //注册驱动
if (res)
return res;
mutex_lock(&core_lists);
list_add_tail(&driver->list,&drivers); //添加到设备驱动链表中
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
/* legacy drivers scan i2c busses directly */
if (driver->attach_adapter) {
struct i2c_adapter *adapter;
list_for_each_entry(adapter, &adapters, list) { //让设备驱动搜索匹配的适配器(通过调用其attach_adapter接口)
driver->attach_adapter(adapter);
}
}
mutex_unlock(&core_lists);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
3)drivers/i2c/i2c-dev.c
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
int res;
i2c_dev = get_free_i2c_dev(adap); //创建并初始化i2c_dev结构
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
/* register this i2c device with the driver core */
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev, //注意,这里使用的次设备号为adap->nr,便于以后获取adap结构。
MKDEV(I2C_MAJOR, adap->nr),
"i2c-%d", adap->nr);
if (IS_ERR(i2c_dev->dev)) {
res = PTR_ERR(i2c_dev->dev);
goto error;
}
res = device_create_file(i2c_dev->dev, &dev_attr_name); //创建设备文件
if (res)
goto error_destroy;
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
adap->name, adap->nr);
return 0;
error_destroy:
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
return_i2c_dev(i2c_dev);
return res;
}
总结:
一个适配器对应一个i2c控制器。