注册一个v4l2设备实例,主要建立dev和v4l2_dev的关系(下边黄低红字)。初始化v4l2_dev,使dev_driver_data指向v4l2_dev,dev在少数情况下(ISA devices)可能为NULL。在这种情况下必须在调用该函数之前给v4l2_dev->name赋值。
1. v4l2_device_register
- int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
- {
- if (v4l2_dev == NULL)
- return -EINVAL;
- INIT_LIST_HEAD(&v4l2_dev->subdevs);//初始化子设备链表
- spin_lock_init(&v4l2_dev->lock);
- v4l2_dev->dev = dev;//将基本设备dev包含到v4l2_dev中
- if (dev == NULL) {
- /* If dev == NULL, then name must be filled in by the caller */
- WARN_ON(!v4l2_dev->name[0]);
- return 0;
- }
- /* Set name to driver name + device name if it is empty. */
- if (!v4l2_dev->name[0])
- snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
- dev->driver->name, dev_name(dev));
- if (dev_get_drvdata(dev))
- v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");
- dev_set_drvdata(dev, v4l2_dev);//dev->p->deriver_data = v4l2_dev
- return 0;
- }
设置v4l2设备的名称,用驱动的名称和驱动全局原子实例(deriver-global atomic)初始化结构体v4l2_device中的名称,这个函数将增加实例的引用计数和实例的名称。
2.v4l2_device_set_name
- int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
- atomic_t *instance)
- {
- int num = atomic_inc_return(instance) - 1;//实例的序号
- int len = strlen(basename);//设备实例原始名称
- //如果原始名称后边就有数字,那么在实例原始名称以实例序号中加入横线
- if (basename[len - 1] >= '0' && basename[len - 1] <= '9')
- snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
- "%s-%d", basename, num);
- //否则直接将它俩组合到一起
- else
- snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s%d", basename, num);
- return num;
- }
- EXPORT_SYMBOL_GPL(v4l2_device_set_name);
设置v4l2_dev->dev->p->driver_data和v4l2_dev->dev,在USB设备断开的时候调用,因此父设备消失时这个就能确保v4l2_dev就不会有一个无效的父设备指针。
3.v4l2_device_disconnect
- void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
- {
- if (v4l2_dev->dev) {
- dev_set_drvdata(v4l2_dev->dev, NULL);
- v4l2_dev->dev = NULL;
- }
- }
- EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
注销掉v4l2_dev的所有子设备和v4l2_dev其他相关的资源,比如i2c。
4 . v4l2_device_unregister
- void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
- {
- struct v4l2_subdev *sd, *next;
- if (v4l2_dev == NULL)
- return;
- v4l2_device_disconnect(v4l2_dev);//断开dev->p->drvdata和v4l2_dev
- /* Unregister subdevs 遍历注消子设备*/
- list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
- v4l2_device_unregister_subdev(sd);
- #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
- if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {//如果用到了i2c接口,则也注销掉它
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- /* 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. */
- if (client)
- i2c_unregister_device(client);
- }
- #endif
- }
- }
- EXPORT_SYMBOL_GPL(v4l2_device_unregister);
5、v4l2_device_register_subdev
为v4l2 device注册一个子设备,主要是建立起来v4l2_device和v4l2_subdev两个设备之前的关系,以便以后处理调用。
- int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd)
- {
- /* Check for valid input */
- if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
- return -EINVAL;
- /* Warn if we apparently re-register a subdev */
- WARN_ON(sd->v4l2_dev != NULL);
- if (!try_module_get(sd->owner))
- return -ENODEV;
- sd->v4l2_dev = v4l2_dev;//让v4l2_device指向v4l2_subdev的相应成员
- spin_lock(&v4l2_dev->lock);
- list_add_tail(&sd->list, &v4l2_dev->subdevs);//添加子设备到v4l2_device子设备链表
- spin_unlock(&v4l2_dev->lock);
- 3.3.1种还执行了一下操作:
- /* This just returns 0 if either of the two args is NULL */
- //添加控制处理:
- err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
- if (err) {
- if (sd->internal_ops && sd->internal_ops->unregistered)
- sd->internal_ops->unregistered(sd);
- module_put(sd->owner);
- return err;
- }
- #if defined(CONFIG_MEDIA_CONTROLLER)
- /* Register the entity. */
- //注册多媒体
- if (v4l2_dev->mdev) {
- err = media_device_register_entity(v4l2_dev->mdev, entity);
- if (err < 0) {
- if (sd->internal_ops && sd->internal_ops->unregistered)
- sd->internal_ops->unregistered(sd);
- module_put(sd->owner);
- return err;
- }
- }
- #endif
- return 0;
- }
- EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
6、v4l2_device_unregister_subdev
- void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
- {
- /* return if it isn't registered */
- if (sd == NULL || sd->v4l2_dev == NULL)
- return;
- spin_lock(&sd->v4l2_dev->lock);
- list_del(&sd->list);//从链表中删除要注消的子设备
- spin_unlock(&sd->v4l2_dev->lock);
- sd->v4l2_dev = NULL;//
- module_put(sd->owner);
- 3.3.1中还有一下操作:
- v4l2_dev = sd->v4l2_dev;
- //注消控制处理
- if (sd->internal_ops && sd->internal_ops->unregistered)
- sd->internal_ops->unregistered(sd);
- sd->v4l2_dev = NULL;
- //注消media实体
- #if defined(CONFIG_MEDIA_CONTROLLER)
- if (v4l2_dev->mdev)
- media_device_unregister_entity(&sd->entity);
- #endif
- //注消video设备节点
- video_unregister_device(sd->devnode);
- module_put(sd->owner);
- }
- EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
3.3.1种还有下边一些函数:
7、v4l2_device_put
- int v4l2_device_put(struct v4l2_device *v4l2_dev)
- {
- return kref_put(&v4l2_dev->ref, v4l2_device_release);
- }
- static void v4l2_device_release(struct kref *ref)
- {
- struct v4l2_device *v4l2_dev =
- container_of(ref, struct v4l2_device, ref);
- if (v4l2_dev->release)
- v4l2_dev->release(v4l2_dev);
- }
注册v4l2设备中所有子设备的设备节点,它们被标记为V4L2_SUBDEV_FL_HAS_DEVNODE
8、v4l2_device_register_subdev_nodes
- int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
- {
- struct video_device *vdev;
- struct v4l2_subdev *sd;
- int err;
- //Register a device node for every subdev marked with the V4L2_SUBDEV_FL_HAS_DEVNODE flag.
- 初始化并注册子设备节点
- list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
- if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
- continue;
- vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
- if (!vdev) {
- err = -ENOMEM;
- goto clean_up;
- }
- video_set_drvdata(vdev, sd);
- strlcpy(vdev->name, sd->name, sizeof(vdev->name));
- vdev->v4l2_dev = v4l2_dev;
- vdev->fops = &v4l2_subdev_fops;
- vdev->release = v4l2_device_release_subdev_node;
- vdev->ctrl_handler = sd->ctrl_handler;
- err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
- sd->owner);
- if (err < 0) {
- kfree(vdev);
- goto clean_up;
- }
- //media 实体设备号处理
- #if defined(CONFIG_MEDIA_CONTROLLER)
- sd->entity.info.v4l.major = VIDEO_MAJOR;
- sd->entity.info.v4l.minor = vdev->minor;
- #endif
- sd->devnode = vdev;
- }
- return 0;
- //发生错误时注消掉所有节点
- clean_up:
- list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
- if (!sd->devnode)
- break;
- video_unregister_device(sd->devnode);
- }
- return err;
- }
- EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
- //清除子设备节点操作函数
- static void v4l2_device_release_subdev_node(struct video_device *vdev)
- {
- struct v4l2_subdev *sd = video_get_drvdata(vdev);
- sd->devnode = NULL;
- kfree(vdev);
- }
还有一个内联函数(和v4l2_device_put对应):
9、v4l2_device_get
- static inline void v4l2_device_get(struct v4l2_device *v4l2_dev)
- {
- kref_get(&v4l2_dev->ref);
- }