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

        上节我们讲叙在struct i2c_adapter 注册到内核中后,内核时怎样把已经注册进系统中的i2c设备设备与刚注册进内核的适配器进行绑定的。分两种情况一是在板级用i2c_register_board_info注册的,其二是通过各种struct i2c_driver注册的。其中驱动注册又有两种方法,一种是新的总线式驱动一种是老式的,这里我们对老式的方法不做介绍,老式的方法在内核中也慢慢的消亡。下面我们看看新式的方法中的绑定函数i2c_detect。

在分析i2c_detect之前先看看一个数据结构struct i2c_client_address_data,内核总有很多的适配器,而且适配器上可以接有很多指定地址的设备,一个驱动对设备的在何地址上是有指导性的,因此在探测设备时(i2c_detect)我们要参考驱动的提示去做。

struct i2c_client_address_data {   
 const unsigned short *normal_i2c;                //该数组指定对每个适配器上的指定地址都进行探测
 const unsigned short *probe;                          //该数组是匹对出现的只对指定适配器的指定地址进行探测,前一个数是适配器后面是指该适配器的上的一个地址
 const unsigned short *ignore;                        //在进行normal_i2c探测是看看此中是否忽略,若忽略则放弃探测,其也是成对出现的,前者指适配器后者指地址
 const unsigned short * const *forces;         
//强制使用的地址,确定某个地址代  表 的设备已经连接在总线上了。这个指针指向一个指针数组,每一个成员所

//指的内容也是每个适配器号后紧跟一个地址。
};

下面可以看i2c_detect的源码:

static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
{
 const struct i2c_client_address_data *address_data;
 struct i2c_client *temp_client;
 int i, err = 0;
 int adap_id = i2c_adapter_id(adapter);
//得到适配器的编号

 address_data = driver->address_data;
 if (!driver->detect || !address_data)    //新式驱动这两个成员必须存在
  return 0;

 /* Set up a temporary client to help detect callback */
 temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); //分配一个设备结构体
 if (!temp_client)
  return -ENOMEM;
 temp_client->adapter = adapter;
//让设备与适配器绑定

 /* Force entries are done first, and are not affected by ignore
    entries */
 if (address_data->forces) {
  const unsigned short * const *forces = address_data->forces;
  int kind;

  for (kind = 0; forces[kind]; kind++) {

//下面代码首先在forces存在的情况下对其中适配器编号与现在加入的适配器编号相对应的或者指定任何适配器编号ANY_I2C_BUS项相对应的地址调用i2c_detect_address进行探测
   for (i = 0; forces[kind][i] != I2C_CLIENT_END;
        i += 2) {
    if (forces[kind][i] == adap_id
     || forces[kind][i] == ANY_I2C_BUS) {
     dev_dbg(&adapter->dev, "found force "
      "parameter for adapter %d, "
      "addr 0x%02x, kind %d\n",
      adap_id, forces[kind][i + 1],
      kind);
     temp_client->addr = forces[kind][i + 1];
     err = i2c_detect_address(temp_client,
      kind, driver);
     if (err)
      goto exit_free;
    }
   }
  }
 }

 

 /* Stop here if the classes do not match */
 if (!(adapter->class & driver->class))  //类型不匹配
  goto exit_free;

 /* Stop here if we can't use SMBUS_QUICK */

//如果adapter不支持I2C_FUNC_SMBUS_QUICK不能够遍历这个adapter上面的设备
 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
  if (address_data->probe[0] == I2C_CLIENT_END
   && address_data->normal_i2c[0] == I2C_CLIENT_END) //无需探测
   goto exit_free;

  dev_warn(&adapter->dev, "SMBus Quick command not supported, "
    "can't probe for chips\n");
  err = -EOPNOTSUPP;
  goto exit_free;
 }

 

 /* Probe entries are done second, and are not affected by ignore
    entries either */

//probe情况下对匹配的适配器的响应地址进行探测(i2c_detect_address)
 for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
  if (address_data->probe[i] == adap_id
   || address_data->probe[i] == ANY_I2C_BUS) {
   dev_dbg(&adapter->dev, "found probe parameter for "
    "adapter %d, addr 0x%02x\n", adap_id,
    address_data->probe[i + 1]);
   temp_client->addr = address_data->probe[i + 1];
   err = i2c_detect_address(temp_client, -1, driver);
   if (err)
    goto exit_free;
  }
 }

 /* Normal entries are done last, unless shadowed by an ignore entry */

//对normal_i2c指定的所以地址对每个适配器进行探测,但在ingore中指定的适配器对应的地址不做探测
 for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
  int j, ignore;

  ignore = 0;
  for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
       j += 2) {
   if ((address_data->ignore[j] == adap_id ||
        address_data->ignore[j] == ANY_I2C_BUS)
    && address_data->ignore[j + 1]
       == address_data->normal_i2c[i]) {
    dev_dbg(&adapter->dev, "found ignore "
     "parameter for adapter %d, "
     "addr 0x%02x\n", adap_id,
     address_data->ignore[j + 1]);
    ignore = 1;
    break;
   }
  }
  if (ignore)
   continue;

  dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
   "addr 0x%02x\n", adap_id,
   address_data->normal_i2c[i]);
  temp_client->addr = address_data->normal_i2c[i];
  err = i2c_detect_address(temp_client, -1, driver);
  if (err)
   goto exit_free;
 }

 exit_free:
 kfree(temp_client);
 return err;
}

i2c_detect就是对驱动传递下的设备地址列表类别做相应的处理,具体的探测工作由i2c_detect_address来完成,下面我们看具体的代码

 

static int i2c_detect_address(struct i2c_client *temp_client, int kind,
         struct i2c_driver *driver)
{
 struct i2c_board_info info;
 struct i2c_adapter *adapter = temp_client->adapter;
 int addr = temp_client->addr;
 int err;

 /* Make sure the address is valid */
 if (addr < 0x03 || addr > 0x77) {
  dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
    addr);
  return -EINVAL;
 }

 /* Skip if already in use */
 //对适配器中的所有设备进行检验,看该地址是否被使用过
 if (i2c_check_addr(adapter, addr))
  return 0;

 /* Make sure there is something at this address, unless forced */
 //当kind <0 时检查设备上是否有这个设备,而对forces而言并不做物理探测
 //在上个函数的探测中probe 和 normal_i2c都是把该值指定为 -1
 if (kind < 0) {
  if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
       I2C_SMBUS_QUICK, NULL) < 0)
   return 0;

  /* prevent 24RF08 corruption */
  if ((addr & ~0x0f) == 0x50)
   i2c_smbus_xfer(adapter, addr, 0, 0, 0,
           I2C_SMBUS_QUICK, NULL);
 }

 /* Finally call the custom detection function */
 //构建i2c_board_info结构
 memset(&info, 0, sizeof(struct i2c_board_info));
 info.addr = addr;
 err = driver->detect(temp_client, kind, &info);
 if (err) {
  /* -ENODEV is returned if the detection fails. We catch it
     here as this isn't an error. */
  return err == -ENODEV ? 0 : err;
 }

 /* Consistency check */
 //用i2c_board_info结构,调用i2c_new_device进行设备和适配器的绑定。
 if (info.type[0] == '\0') {
  dev_err(&adapter->dev, "%s detection function provided "
   "no name for 0x%x\n", driver->driver.name,
   addr);
 } else {
  struct i2c_client *client;

  /* Detection succeeded, instantiate the device */
  dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
   info.type, info.addr);
  client = i2c_new_device(adapter, &info);
  if (client)
   list_add_tail(&client->detected, &driver->clients);
  else
   dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
    info.type, info.addr);
 }
 return 0;
}

 首先,对传入的参数进行一系列的合法性检查.另外,如果该adapter上已经有了这个地址的设备了.也会返回失败.所有adapter下面的设备都是以adapter->dev为父结点的.因此只需要遍历adapter->dev下面的子设备就可以得到当前地址是不是被占用了.如果kind < 0.还得要adapter检查该总线是否有这个地址的设备.方法是向这个地址发送一个Read的Quick请求.如果该地址有应答,则说明这个地址上有这个设备.另外还有一种情况是在24RF08设备的特例。i2c_smbus_xfer是与具体的协议相关的,在后面的章节中再分析。最后我们看看设备也适配器的绑定函数i2c_new_device。

struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
 struct i2c_client *client;
 int   status;

 client = kzalloc(sizeof *client, GFP_KERNEL);
 if (!client)
  return NULL;

 client->adapter = adap;

 client->dev.platform_data = info->platform_data;

 client->flags = info->flags;
 client->addr = info->addr;
 client->irq = info->irq;

 strlcpy(client->name, info->type, sizeof(client->name));

 /* a new style driver may be bound to this device when we
  * return from this function, or any later moment (e.g. maybe
  * hotplugging will load the driver module).  and the device
  * refcount model is the standard driver model one.
  */
 status = i2c_attach_client(client);
 if (status < 0) {
  kfree(client);
  client = NULL;
 }
 return client;
}

分配一个struct i2c_client,并用i2c_board_info中的信息初始化它,然后调用i2c_attach_client,这个函数对其成员dev做一些初始化加入内核,然把client加入到adapter的设备列表中。再然后i2c的总线机制就发挥作用了(device_register调用)。这里留下一个疑问,当设备驱动先注册,而适配器后注册是两者又是如何绑定的呢?

 

你可能感兴趣的:(数据结构,c,struct,function,null,callback)