v4l2_device.c浅析

关于v4l2及v4l2_subdev设备实例的注册注消等操作在deriver/media/video/v4l2_device.c文件中,下边将各个函数分析一下(分析的时候以2.6.32.40内核为主,并列出与3.3.1的区别):

注册一个v4l2设备实例,主要建立dev和v4l2_dev的关系(下边黄低红字)。初始化v4l2_dev,使dev_driver_data指向v4l2_dev,dev在少数情况下(ISA devices)可能为NULL。在这种情况下必须在调用该函数之前给v4l2_dev->name赋值。
1. v4l2_device_register

  1. int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)  
  2. {  
  3.  if (v4l2_dev == NULL)  
  4.   return -EINVAL;  
  5.   
  6.  INIT_LIST_HEAD(&v4l2_dev->subdevs);//初始化子设备链表  
  7.  spin_lock_init(&v4l2_dev->lock);  
  8.  v4l2_dev->dev = dev;//将基本设备dev包含到v4l2_dev中  
  9.  if (dev == NULL) {  
  10.   /* If dev == NULL, then name must be filled in by the caller */  
  11.   WARN_ON(!v4l2_dev->name[0]);  
  12.   return 0;  
  13.  }  
  14.   
  15.  /* Set name to driver name + device name if it is empty. */  
  16.  if (!v4l2_dev->name[0])  
  17.   snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",  
  18.    dev->driver->name, dev_name(dev));  
  19.  if (dev_get_drvdata(dev))  
  20.   v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");  
  21.  dev_set_drvdata(dev, v4l2_dev);//dev->p->deriver_data = v4l2_dev  
  22.  return 0;  
  23. }  


设置v4l2设备的名称,用驱动的名称和驱动全局原子实例(deriver-global atomic)初始化结构体v4l2_device中的名称,这个函数将增加实例的引用计数和实例的名称。
2.v4l2_device_set_name

  1. int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,  
  2. atomic_t *instance)  
  3. {  
  4.  int num = atomic_inc_return(instance) - 1;//实例的序号  
  5.  int len = strlen(basename);//设备实例原始名称  
  6. //如果原始名称后边就有数字,那么在实例原始名称以实例序号中加入横线  
  7.  if (basename[len - 1] >= '0' && basename[len - 1] <= '9')  
  8.   snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),  
  9.     "%s-%d", basename, num);  
  10. //否则直接将它俩组合到一起  
  11.  else  
  12.   snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s%d", basename, num);  
  13.  return num;  
  14. }  
  15. EXPORT_SYMBOL_GPL(v4l2_device_set_name);  


设置v4l2_dev->dev->p->driver_data和v4l2_dev->dev,在USB设备断开的时候调用,因此父设备消失时这个就能确保v4l2_dev就不会有一个无效的父设备指针。
3.v4l2_device_disconnect

  1. void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)  
  2. {  
  3.  if (v4l2_dev->dev) {  
  4.   dev_set_drvdata(v4l2_dev->dev, NULL);  
  5.   v4l2_dev->dev = NULL;  
  6.  }  
  7. }  
  8. EXPORT_SYMBOL_GPL(v4l2_device_disconnect);  


注销掉v4l2_dev的所有子设备和v4l2_dev其他相关的资源,比如i2c。
4 . v4l2_device_unregister

  1. void v4l2_device_unregister(struct v4l2_device *v4l2_dev)  
  2. {  
  3.  struct v4l2_subdev *sd, *next;  
  4.   
  5.  if (v4l2_dev == NULL)  
  6.   return;  
  7.  v4l2_device_disconnect(v4l2_dev);//断开dev->p->drvdata和v4l2_dev  
  8.   
  9.  /* Unregister subdevs  遍历注消子设备*/  
  10.  list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {  
  11.   v4l2_device_unregister_subdev(sd);  
  12. #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))  
  13.   if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {//如果用到了i2c接口,则也注销掉它  
  14.    struct i2c_client *client = v4l2_get_subdevdata(sd);  
  15. /* We need to unregister the i2c client explicitly.We cannot rely on i2c_del_adapter to always unregister clients for us, since if the i2c bus is a platform bus, then it is never deleted. */  
  16.    if (client)  
  17.     i2c_unregister_device(client);  
  18.   }  
  19. #endif  
  20.  }  
  21. }  
  22. EXPORT_SYMBOL_GPL(v4l2_device_unregister);  


5、v4l2_device_register_subdev
为v4l2 device注册一个子设备,主要是建立起来v4l2_device和v4l2_subdev两个设备之前的关系,以便以后处理调用。

  1. int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd)  
  2. {  
  3.  /* Check for valid input */  
  4.  if (v4l2_dev == NULL || sd == NULL || !sd->name[0])  
  5.   return -EINVAL;  
  6.  /* Warn if we apparently re-register a subdev */  
  7.  WARN_ON(sd->v4l2_dev != NULL);  
  8.  if (!try_module_get(sd->owner))  
  9.   return -ENODEV;  
  10.  sd->v4l2_dev = v4l2_dev;//让v4l2_device指向v4l2_subdev的相应成员  
  11.  spin_lock(&v4l2_dev->lock);  
  12.  list_add_tail(&sd->list, &v4l2_dev->subdevs);//添加子设备到v4l2_device子设备链表  
  13.  spin_unlock(&v4l2_dev->lock);  
  14. 3.3.1种还执行了一下操作:  
  15.   /* This just returns 0 if either of the two args is NULL */  
  16. //添加控制处理:  
  17.   err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);  
  18.   if (err) {  
  19.    if (sd->internal_ops && sd->internal_ops->unregistered)  
  20.     sd->internal_ops->unregistered(sd);  
  21.    module_put(sd->owner);  
  22.    return err;  
  23.   }  
  24.   
  25. #if defined(CONFIG_MEDIA_CONTROLLER)  
  26.   /* Register the entity. */  
  27. //注册多媒体  
  28.  if (v4l2_dev->mdev) {  
  29.    err = media_device_register_entity(v4l2_dev->mdev, entity);  
  30.    if (err < 0) {  
  31.     if (sd->internal_ops && sd->internal_ops->unregistered)  
  32.      sd->internal_ops->unregistered(sd);  
  33.     module_put(sd->owner);  
  34.     return err;  
  35.    }  
  36.   }  
  37. #endif  
  38.  return 0;  
  39. }  
  40. EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);  


6、v4l2_device_unregister_subdev

  1. void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)  
  2. {  
  3.  /* return if it isn't registered */  
  4.  if (sd == NULL || sd->v4l2_dev == NULL)  
  5.   return;  
  6.  spin_lock(&sd->v4l2_dev->lock);  
  7.  list_del(&sd->list);//从链表中删除要注消的子设备  
  8.  spin_unlock(&sd->v4l2_dev->lock);  
  9.  sd->v4l2_dev = NULL;//  
  10.  module_put(sd->owner);  
  11. 3.3.1中还有一下操作:  
  12.  v4l2_dev = sd->v4l2_dev;  
  13. //注消控制处理  
  14.  if (sd->internal_ops && sd->internal_ops->unregistered)  
  15.   sd->internal_ops->unregistered(sd);  
  16.  sd->v4l2_dev = NULL;  
  17. //注消media实体  
  18. #if defined(CONFIG_MEDIA_CONTROLLER)  
  19.  if (v4l2_dev->mdev)  
  20.   media_device_unregister_entity(&sd->entity);  
  21. #endif  
  22. //注消video设备节点  
  23.  video_unregister_device(sd->devnode);  
  24.  module_put(sd->owner);  
  25. }  
  26. EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);  


3.3.1种还有下边一些函数:
7、v4l2_device_put

  1. int v4l2_device_put(struct v4l2_device *v4l2_dev)  
  2. {  
  3.  return kref_put(&v4l2_dev->ref, v4l2_device_release);  
  4. }  
  5. static void v4l2_device_release(struct kref *ref)  
  6. {  
  7.  struct v4l2_device *v4l2_dev =  
  8.   container_of(ref, struct v4l2_device, ref);  
  9.   
  10.  if (v4l2_dev->release)  
  11.   v4l2_dev->release(v4l2_dev);  
  12. }  


注册v4l2设备中所有子设备的设备节点,它们被标记为V4L2_SUBDEV_FL_HAS_DEVNODE
8、v4l2_device_register_subdev_nodes

  1. int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)  
  2. {  
  3.  struct video_device *vdev;  
  4.  struct v4l2_subdev *sd;  
  5.  int err;  
  6.   
  7.  //Register a device node for every subdev marked with the V4L2_SUBDEV_FL_HAS_DEVNODE flag.  
  8. 初始化并注册子设备节点  
  9.  list_for_each_entry(sd, &v4l2_dev->subdevs, list) {  
  10.   if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))  
  11.    continue;  
  12.   
  13.   vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);  
  14.   if (!vdev) {  
  15.    err = -ENOMEM;  
  16.    goto clean_up;  
  17.   }  
  18.   
  19.   
  20.   
  21.   video_set_drvdata(vdev, sd);  
  22.   strlcpy(vdev->name, sd->name, sizeof(vdev->name));  
  23.   vdev->v4l2_dev = v4l2_dev;  
  24.   vdev->fops = &v4l2_subdev_fops;  
  25.   vdev->release = v4l2_device_release_subdev_node;  
  26.   vdev->ctrl_handler = sd->ctrl_handler;  
  27.   err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,  
  28.            sd->owner);  
  29.   if (err < 0) {  
  30.    kfree(vdev);  
  31.    goto clean_up;  
  32.   }  
  33. //media 实体设备号处理  
  34. #if defined(CONFIG_MEDIA_CONTROLLER)  
  35.   sd->entity.info.v4l.major = VIDEO_MAJOR;  
  36.   sd->entity.info.v4l.minor = vdev->minor;  
  37. #endif  
  38.   sd->devnode = vdev;  
  39.  }  
  40.  return 0;  
  41. //发生错误时注消掉所有节点  
  42. clean_up:  
  43.  list_for_each_entry(sd, &v4l2_dev->subdevs, list) {  
  44.   if (!sd->devnode)  
  45.    break;  
  46.   video_unregister_device(sd->devnode);  
  47.  }  
  48.   
  49.  return err;  
  50. }  
  51. EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);  
  52.   
  53. //清除子设备节点操作函数  
  54. static void v4l2_device_release_subdev_node(struct video_device *vdev)  
  55. {  
  56.  struct v4l2_subdev *sd = video_get_drvdata(vdev);  
  57.  sd->devnode = NULL;  
  58.  kfree(vdev);  
  59. }  


还有一个内联函数(和v4l2_device_put对应):
9、v4l2_device_get

  1. static inline void v4l2_device_get(struct v4l2_device *v4l2_dev)  
  2. {  
  3.  kref_get(&v4l2_dev->ref);  
  4. }  


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值