V4l2大体介绍

在这里插入图片描述

1.video_device的初始化

static struct video_device viu_template = {
	.name		= "FSL viu",
	.fops		= &viu_fops,
	.minor		= -1,
	.ioctl_ops	= &viu_ioctl_ops,
	.release	= video_device_release,

	.tvnorms        = V4L2_STD_NTSC_M | V4L2_STD_PAL,
};

一般我们使用上述方式,定义一个video_device实现,里面核心是fops和ioctl_ops 这两个接口的实现。
使用video_device_alloc()函数分配一个video_device内存空间,然后指向上述的结构体实现,如下所示:

	struct video_device *vdev;
	vdev = video_device_alloc();
	*vdev = viu_template;

2.注册video_device

注册video_device的函数接口为video_register_device

static inline int __must_check video_register_device(struct video_device *vdev,
		int type, int nr)
{
	return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
}

接下来看看__video_register_device函数说明

/**
 *	__video_register_device - register video4linux devices
 *	@vdev: video device structure we want to register
 *	@type: type of device to register
 *	@nr:   which device node number (0 == /dev/video0, 1 == /dev/video1, ...
 *             -1 == first free)
 *	@warn_if_nr_in_use: warn if the desired device node number
 *	       was already in use and another number was chosen instead.
 *	@owner: module that owns the video device node
 *
 *	The registration code assigns minor numbers and device node numbers
 *	based on the requested type and registers the new device node with
 *	the kernel.
 *
 *	This function assumes that struct video_device was zeroed when it
 *	was allocated and does not contain any stale date.
 *
 *	An error is returned if no free minor or device node number could be
 *	found, or if the registration of the device node failed.
 *
 *	Zero is returned on success.
 *
 *	Valid types are
 *
 *	%VFL_TYPE_GRABBER - A frame grabber
 *
 *	%VFL_TYPE_VBI - Vertical blank data (undecoded)
 *
 *	%VFL_TYPE_RADIO - A radio card
 *
 *	%VFL_TYPE_SUBDEV - A subdevice
 *
 *	%VFL_TYPE_SDR - Software Defined Radio
 */
int __video_register_device(struct video_device *vdev, int type, int nr,
		int warn_if_nr_in_use, struct module *owner)

函数说明如下:
/**

  • __video_register_device - register video4linux devices
    vdev: 这个参数是我们想注册的video device结构体

type: 注册的社备类型

nr: 选择的设备节点号0代表选择 /dev/video0,1代码选择 /dev/video 1,-1代表第一个 (0 == /dev/video0, 1 == /dev/video1, … -1 == first free)

warn_if_nr_in_use: 警告如果我们期望的设备号已经被占用,将会选择另 外一个设备号

owner: 模块的拥有者

0返回成功
*合法的类型有如下几种:
*

  • %VFL_TYPE_GRABBER - A frame grabber
  • %VFL_TYPE_VBI - Vertical blank data (undecoded)
  • %VFL_TYPE_RADIO - A radio card
  • %VFL_TYPE_SUBDEV - A subdevice
  • %VFL_TYPE_SDR - Software Defined Radio
    */
    接下来看看其函数代码实现
int __video_register_device(struct video_device *vdev, int type, int nr,
		int warn_if_nr_in_use, struct module *owner)
{
	...
	//如果release和v4l2_dev这两个成员是null将返回失败,也就是说这两个成员都必须赋值
	if (WARN_ON(!vdev->release))
		return -EINVAL;
	/* the v4l2_dev pointer MUST be present */
	if (WARN_ON(!vdev->v4l2_dev))
		return -EINVAL;

	//下面就是选择一个最小的没有使用的下标,作为次设备号
	mutex_lock(&videodev_lock);
	nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
	if (nr == minor_cnt)
		nr = devnode_find(vdev, 0, minor_cnt);
	if (nr == minor_cnt) {
		printk(KERN_ERR "could not get a free device node number\n");
		mutex_unlock(&videodev_lock);
		return -ENFILE;
	}
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
	/* 1-on-1 mapping of device node number to minor number */
	i = nr;
#else
	/* The device node number and minor numbers are independent, so
	   we just find the first free minor number. */
	for (i = 0; i < VIDEO_NUM_DEVICES; i++)
		if (video_device[i] == NULL)
			break;
	if (i == VIDEO_NUM_DEVICES) {
		mutex_unlock(&videodev_lock);
		printk(KERN_ERR "could not get a free minor\n");
		return -ENFILE;
	}
#endif
//赋值次设备号,为下标+偏移,不同的设备类型在数据的不同范围时硕
下标0-63		为VFL_TYPE_GRABBER
下标64-127	为VFL_TYPE_RADIO
下标128-223	为其它类型
下标224-255	为VFL_TYPE_VBI
video_device数组大小为256
	vdev->minor = i + minor_offset;
	vdev->num = nr;
	devnode_set(vdev);

	//由于次设备号是没有使用的下标+偏移,由于有偏移所以这个下标可以已经被使用
	WARN_ON(video_device[vdev->minor] != NULL);
	vdev->index = get_index(vdev);
	//使用数组存储这个video_device结构体
	video_device[vdev->minor] = vdev;
	mutex_unlock(&videodev_lock);

	if (vdev->ioctl_ops)
		determine_valid_ioctls(vdev);

	//初始化字符设备
	vdev->cdev = cdev_alloc();
	if (vdev->cdev == NULL) {
		ret = -ENOMEM;
		goto cleanup;
	}
	vdev->cdev->ops = &v4l2_fops;
	vdev->cdev->owner = owner;
	//注册字符设备
	ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
	if (ret < 0) {
		printk(KERN_ERR "%s: cdev_add failed\n", __func__);
		kfree(vdev->cdev);
		vdev->cdev = NULL;
		goto cleanup;
	}

	/* Part 4: register the device with sysfs */
	vdev->dev.class = &video_class;
	vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
	vdev->dev.parent = vdev->dev_parent;
	dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
	ret = device_register(&vdev->dev);
	if (ret < 0) {
		printk(KERN_ERR "%s: device_register failed\n", __func__);
		goto cleanup;
	}
	/* Register the release callback that will be called when the last
	   reference to the device goes away. */
	vdev->dev.release = v4l2_device_release;

	if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
		printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
			name_base, nr, video_device_node_name(vdev));

	/* Increase v4l2_device refcount */
	v4l2_device_get(vdev->v4l2_dev);

	/* Part 5: Register the entity. */
	ret = video_register_media_controller(vdev, type);

	/* Part 6: Activate this minor. The char device can now be used. */
	set_bit(V4L2_FL_REGISTERED, &vdev->flags);

	return 0;

cleanup:
	mutex_lock(&videodev_lock);
	if (vdev->cdev)
		cdev_del(vdev->cdev);
	video_device[vdev->minor] = NULL;
	devnode_clear(vdev);
	mutex_unlock(&videodev_lock);
	/* Mark this video device as never having been registered. */
	vdev->minor = -1;
	return ret;
}

这个注册函数为v4l2的核心函数大体有以下作用:
1.进行合法性检查
2.分配一个未使用的最小下标来保存video_device
3.注册字符设备,以产生节点被上层访问
4.设备注册

大体的调用过程如下:
在这里插入图片描述
v4l2_fops结构体里面的实现基本都是中转,把调用从节点转动自己定义的video_device的v4l2_file_operations结构体中。也就相当对上层提供了统一接口,所有的video_device都是通过这个中转到具体实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bruk_spp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值