i2c-core之适配器驱动注册(4)

           在i2c-core架构中struct i2c_adapter和struct i2c_algorithm是为适配器服务的,也就是i2c总线控制器驱动。注册一个适配器驱动就是要把一个struct i2c_adapter 加入到内核中,前面我们说过i2c-core中的i2c_adapter_idr是专门用来管理注册到i2c-core中的struct i2c_adapter结构的。struct i2c_adapter中有指向具体struct i2c_algorithm的指针。struct i2c_algorithm是i2c的具体操作方法函数。内核中提供了两个adapter注册接口,分别为i2c_add_adapter()和i2c_add_numbered_adapter().由于在系统中可能存在多个adapter,因为将每一条I2C总线对应一个编号,下文中称为I2C总线号.这个总线号的PCI中的总线号不同.它和硬件无关,只是软件上便于区分而已。当在实现的具体struct i2c_algorithm中一般也提供了相类似的接口i2c_xxx_add_numbered_adapter和i2c_xxx_add_adapter。  对于i2c_add_adapter()而言,它使用的是动态总线号,即由系统给其分析一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败.分别来看一下这两个函数的代码:

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);
}

int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
 int id;
 int status;

 if (adap->nr & ~MAX_ID_MASK)
  return -EINVAL;

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;
  * we need the "equal to" result to force the result
  */
 status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
 if (status == 0 && id != adap->nr) {
  status = -EBUSY;
  idr_remove(&i2c_adapter_idr, id);
 }
 mutex_unlock(&core_lock);
 if (status == -EAGAIN)
  goto retry;

 if (status == 0)
  status = i2c_register_adapter(adap);
 return status;
}

至于idr的使用方法,在前节中已经介绍。对比两个代码的区别在于前者没有指定adap->nr,而是从某一起始数字开始动态分配而后者直接指定了nr,如果分配的id不和指定的相等,便返回错误。接着我们继续追踪i2c_register_adapter。

static int i2c_register_adapter(struct i2c_adapter *adap)
{
 int res = 0, dummy;

 mutex_init(&adap->bus_lock);    //初始化保护i2c适配器的互斥锁
 mutex_init(&adap->clist_lock);    //初始化保护adap->clients的锁
 INIT_LIST_HEAD(&adap->clients);
//初始化i2c适配器上介入的设备(client)链表

 mutex_lock(&core_lock);

 /* Add the adapter to the driver core.
  * If the parent pointer is not set up,
  * we add this adapter to the host bus.
  */

//初始化adap->dev然后注册该设备
 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);

 /* Notify drivers */
 dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
     i2c_do_add_adapter);

out_unlock:
 mutex_unlock(&core_lock);
 return res;

out_list:
 idr_remove(&i2c_adapter_idr, adap->nr);
 goto out_unlock;
}

内核中I2C设备的加入有两种方式,一种是在soc上板级是利用i2c_register_board_info注册在__i2c_board_list链表上的i2c设备(由__i2c_board保护)。另外一种就是通过i2c_driver驱动加入的设备。下面我们分别看看两种情况

static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
 struct i2c_devinfo *devinfo;

 mutex_lock(&__i2c_board_lock);
 list_for_each_entry(devinfo, &__i2c_board_list, list) {
  if (devinfo->busnum == adapter->nr
    && !i2c_new_device(adapter,
      &devinfo->board_info))
   printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",
    i2c_adapter_id(adapter),
    devinfo->board_info.addr);
 }
 mutex_unlock(&__i2c_board_lock);
}

第一种是对&__i2c_board_list中的每个struct i2c_devinfo对比,若busnum与适配器编号相同则调用i2c_new_device把设备绑定到适配器。

对第二种通过设备驱动注册进的设备调用的函数为bus_for_each_drv(&i2c_bus_type, NULL, adap,i2c_do_add_adapter)对i2c总线上的每个驱动调用i2c_do_add_adapter(drv,adap)函数,下面我们看看i2c_do_add_adapter函数。

static int i2c_do_add_adapter(struct device_driver *d, void *data)
{
 struct i2c_driver *driver = to_i2c_driver(d);
 struct i2c_adapter *adap = data;

 /* Detect supported devices on that bus, and instantiate them */
 i2c_detect(adap, driver); 
//最终调用i2c_new_device把设备绑定到适配器

 /* Let legacy drivers scan this bus for matching devices */
 if (driver->attach_adapter) {
  /* We ignore the return code; if it fails, too bad */
  driver->attach_adapter(adap);
 }
 return 0;
}

第二方式应对的是以驱动方式注册进系统的i2c设备,因为i2c驱动由两种方式因此这里有有两种应对方式,而且新旧两种方式中实现的对应函数也有所不同,新中以probe函数为代表,而旧中以attach_adapter和detach_adapter为代表(旧方法我们在这里不再追踪)。

----------------------------未完待续

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值