v4l2_common.c浅析

V4l2的子设备一般是摄像头和摄像头控制器,它们和主机的控制操作是通过i2c总线完成的。V4l2驱动框架中跟i2c相关的代码在deriver/media/video/v4l2_common.c中,下边就相关函数作一简单分析:

下边宏的作用是如果v4l2的子设备通过i2c总线和主机通信时,才能用到下边的函数,因为有可能通过其他总线通信,比如SPI等。
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
这个函数的功能是判断i2c client和v4l2是否匹配,主要通过匹配类型来分类判断,如果过匹配类型是V4L2_CHIP_MATCH_I2C_DRIVER,那么就比较i2c client deriver->name和match-〉name是否相同;如果匹配类型是V4L2_CHIP_MATCH_I2C_ADDR,那么判断它们的地址是否相同。相同则返回1,否则返回0。
1、v4l2_chip_match_i2c_client

  1. int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match)  
  2. {  
  3.  int len;  
  4.   
  5.  if (c == NULL || match == NULL)  
  6.   return 0;  
  7. //通过switch case来判断匹配类型  
  8.  switch (match->type) {  
  9.  case V4L2_CHIP_MATCH_I2C_DRIVER:  
  10.   if (c->driver == NULL || c->driver->driver.name == NULL)  
  11.    return 0;  
  12.   len = strlen(c->driver->driver.name);  
  13.   /* legacy drivers have a ' suffix, don't try to match that */  
  14.   if (len && c->driver->driver.name[len - 1] == '\'')  
  15.    len--;  
  16.  //比较name  
  17.   return len && !strncmp(c->driver->driver.name, match->name, len);  
  18.  case V4L2_CHIP_MATCH_I2C_ADDR:  
  19.  //比较addr  
  20.   return c->addr == match->addr;  
  21.  default:  
  22.   return 0;  
  23.  }  
  24. }  


2、v4l2_chip_ident_i2c_client
//设置v4l2 chip的标示符

  1. int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip,  
  2.   u32 ident, u32 revision)  
  3. {  
  4. //如果v4l2和i2c不匹配,则退出  
  5.  if (!v4l2_chip_match_i2c_client(c, &chip->match))  
  6.   return 0;  
  7.  if (chip->ident == V4L2_IDENT_NONE) {  
  8.   chip->ident = ident;  
  9.   chip->revision = revision;  
  10.  }  
  11.  else {  
  12.   chip->ident = V4L2_IDENT_AMBIGUOUS;  
  13.   chip->revision = 0;  
  14.  }  
  15.  return 0;  
  16. }  
  17. EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);  


以上两个函数时debug模式时用的,下边是i2c的辅助函数:
/* ----------------------------------------------------------------- */
3、v4l2_i2c_subdev_init
/* I2C Helper functions */

  1. 该函数初始化v4l2_subdev数据结构,部分数据是从i2c_client结构中得到。建立i2c_client和v4l2_subdev之间的指向关系。  
  2. void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,  
  3.   const struct v4l2_subdev_ops *ops)  
  4. {  
  5.  v4l2_subdev_init(sd, ops);//简单的初始化v4l2_subdev结构体(v4l2_subdev.c)  
  6.  sd->flags |= V4L2_SUBDEV_FL_IS_I2C;//设置v4l2 subdev的控制状态  
  7.  /* the owner is the same as the i2c_client's driver owner */  
  8.  sd->owner = client->driver->driver.owner;  
  9.  /* i2c_client and v4l2_subdev point to one another */  
  10.  v4l2_set_subdevdata(sd, client);  
  11.  i2c_set_clientdata(client, sd);  
  12.  /* initialize name */  
  13.  snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",  
  14.   client->driver->driver.name, i2c_adapter_id(client->adapter),  
  15.   client->addr);  
  16. }  


4、v4l2_i2c_new_subdev_board

  1. /* Load an i2c sub-device. */  
  2. V4l2中增加i2c设备,返回创建新的v4l2 子设备  
  3. struct v4l2_subdev  *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,  
  4.   struct i2c_adapter *adapter, const char *module_name,  
  5.   struct i2c_board_info *info, const unsigned short *probe_addrs)  
  6. {  
  7.  struct v4l2_subdev *sd = NULL;  
  8.  struct i2c_client *client;  
  9.   
  10.  BUG_ON(!v4l2_dev);  
  11.   
  12.  if (module_name)  
  13.   request_module(module_name);//加载i2c驱动模块  
  14.   
  15.  /* Create the i2c client */  
  16.  创建i2c设备时从设备地址是明确的还是要通过探测。  
  17. 在这两个调用中会向系统中增加sysfs,会把驱动和设备关联起来,并会调用i2c驱动中的probe接口。  
  18.  if (info->addr == 0 && probe_addrs)  
  19.   client = i2c_new_probed_device(adapter, info, probe_addrs);  
  20.  else  
  21.   client = i2c_new_device(adapter, info);  
  22.   
  23. /* Note: by loading the module first we are certain that c->driver will be set if the driver was found. If the module was not loaded first, then the i2c core tries to delay-load the module for us, and then c->driver is still NULL until the module is finally loaded. This delay-load mechanism doesn't work if other drivers want to use the i2c device, so explicitly loading the module is the best alternative. */  
  24.  if (client == NULL || client->driver == NULL)  
  25.   goto error;  
  26.   
  27.  /* Lock the module so we can safely get the v4l2_subdev pointer */  
  28.  if (!try_module_get(client->driver->driver.owner))  
  29.   goto error;  
  30.  sd = i2c_get_clientdata(client);//获取v4l2子设备  
  31.   
  32.  /* Register with the v4l2_device which increases the module's use count as well. */  
  33. //注册v4l2子设备(driver/media/video/v4l2_device.c)  
  34.  if (v4l2_device_register_subdev(v4l2_dev, sd))  
  35.   sd = NULL;  
  36.  /* Decrease the module use count to match the first try_module_get. */  
  37.  module_put(client->driver->driver.owner);  
  38. 3.3.1版本中没有下边的if语句  
  39.  if (sd) {  
  40.   /* We return errors from v4l2_subdev_call only if we have the 
  41.      callback as the .s_config is not mandatory */  
  42.   int err = v4l2_subdev_call(sd, core, s_config, info->irq, info->platform_data);  
  43.   
  44.   if (err && err != -ENOIOCTLCMD) {  
  45.    v4l2_device_unregister_subdev(sd);  
  46.    sd = NULL;  
  47.   }  
  48.  }  
  49.   
  50. error:  
  51.  /* If we have a client but no subdev, then something went wrong and 
  52.     we must unregister the client. */  
  53.  if (client && sd == NULL)  
  54.   i2c_unregister_device(client);  
  55.  return sd;  
  56. }  
  57. EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);  


加载i2c 模块到系统,并返回初始化好的v4l2_subdev结构体,在加载模块时,当module->name不为空时,才掉用request_module() 创建i2c 模块。Client_type参数是适配器的名称。
5、v4l2_i2c_new_subdev_cfg

  1. struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,  
  2.   struct i2c_adapter *adapter,  
  3.   const char *module_name, const char *client_type,  
  4.   int irq, void *platform_data,  
  5.   u8 addr, const unsigned short *probe_addrs)  
  6. {  
  7.  struct i2c_board_info info;  
  8.   
  9.  /* Setup the i2c board info with the device type and the device address. */  
  10.  memset(&info, 0, sizeof(info));  
  11.  strlcpy(info.type, client_type, sizeof(info.type));  
  12.  info.addr = addr;  
  13.  info.irq = irq;  
  14.  info.platform_data = platform_data;  
  15. //调用创建和注册v4l2_subdev、i2c_client的函数  
  16.  return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,  
  17.    &info, probe_addrs);  
  18. }  


在3.3.1版本中,上边的函数用下边的函数替代:

  1. struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,  
  2.   struct i2c_adapter *adapter, const char *client_type,  
  3.   u8 addr, const unsigned short *probe_addrs)  
  4. {  
  5.  struct i2c_board_info info;  
  6.   
  7.  /* Setup the i2c board info with the device type and the device address. */  
  8.  memset(&info, 0, sizeof(info));  
  9.  strlcpy(info.type, client_type, sizeof(info.type));  
  10.  info.addr = addr;  
  11.   
  12.  return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);  
  13. }  


基本功能一样就是接口不一样,少了几个参数

6、v4l2_i2c_subdev_addr

  1. /* Return i2c client address of v4l2_subdev. */  
  2. unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)  
  3. {  
  4.  struct i2c_client *client = v4l2_get_subdevdata(sd);  
  5.   
  6.  return client ? client->addr : I2C_CLIENT_END;  
  7. }  
  8. EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);  



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值