soc camera子系统之注册video device设备

该函数是用于soc camera 子系统向v4l2子系统注册video_device设备,这个设备是v4l2子系统的核心设备。先展开代码.


首先展开video_dev_create函数,代码如下:

static int video_dev_create(struct soc_camera_device *icd)
{
	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
	struct video_device *vdev = video_device_alloc(); //为video device申请内存。

	if (!vdev)
		return -ENOMEM;

	strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));

	vdev->parent		= &icd->dev; //通过这个pointer,可以由vdev来获取到icd
	vdev->current_norm	= V4L2_STD_UNKNOWN;
	vdev->fops		= &soc_camera_fops;//该函数集类似于file_opration,其实就是用来作为v4l2 子系统的默认的file_opration函数集中的回调函数,下面会有对应的分析。
static struct v4l2_file_operations soc_camera_fops = {
	.owner		= THIS_MODULE,
	.open		= soc_camera_open, //作为v4l2_open函数的回调函数
	.release	= soc_camera_close, //作为v4l2_release函数的回调函数
	.unlocked_ioctl	= video_ioctl2,//作为v4l2_ioctl函数的回调函数。
	.read		= soc_camera_read,//作为v4l2_read函数的回调函数
	.mmap		= soc_camera_mmap,//作为v4l2_mmcp函数的回调函数。
	.poll		= soc_camera_poll,//作为v4l2_poll函数的回调函数
};
	vdev->ioctl_ops		= &soc_camera_ioctl_ops; //该函数集是soc camera.c中实现的核心函数集,作为videp_ioctl2函数的回调函数集,根据用户空间传入的不同的ioctl命令。
	vdev->release		= video_device_release;
	vdev->tvnorms		= V4L2_STD_UNKNOWN;

	icd->vdev = vdev; //让icd的成员指针指向已经初始化的video device设备。

	return 0;
}

好了,我们现在着重分析soc_camera_video_start函数

static int soc_camera_video_start(struct soc_camera_device *icd)
{
	const struct device_type *type = icd->vdev->dev.type;
	int ret;

	if (!icd->dev.parent)
		return -ENODEV;

	if (!icd->ops ||
	    !icd->ops->query_bus_param ||
	    !icd->ops->set_bus_param)
		return -EINVAL;

	ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);核心行为,向v4l2子系统注册video device设备,其实v4l2子系统向上实质是抽象成了一个字符设备。下面就会看到。type指定为VFL_TYPE_GRABBRER类型,对应video设备。
	if (ret < 0) {
		dev_err(&icd->dev, "video_register_device failed: %d\n", ret);
		return ret;
	}

	/* Restore device type, possibly set by the subdevice driver */
	icd->vdev->dev.type = type;

	return 0;
}

我们来着重分析一下video_register_device函数。该函数体内就是直接调用函数__video_register_device,所以我们真正要着重分析的函数是__video_register_device。这是一个很长的函数,我们需要慢慢分析,展开代码如下:

int __video_register_device(struct video_device *vdev, int type, int nr,
		int warn_if_nr_in_use, struct module *owner)
{
	int i = 0;
	int ret;
	int minor_offset = 0;
	int minor_cnt = VIDEO_NUM_DEVICES; //做多可以注册的设备数目256
	const char *name_base;

	/* A minor value of -1 marks this video device as never
	   having been registered */
	vdev->minor = -1;
......

	/* Part 1: check device type */
	switch (type) {
	case VFL_TYPE_GRABBER: 
		name_base = "video";
		break;
	case VFL_TYPE_VBI:
		name_base = "vbi";
		break;
	case VFL_TYPE_RADIO:
		name_base = "radio";
		break;
	case VFL_TYPE_SUBDEV:
		name_base = "v4l-subdev";
		break;
	default:
		printk(KERN_ERR "%s called with unknown type: %d\n",
		       __func__, type);
		return -EINVAL;
	}

	vdev->vfl_type = type; //type类型为VFL_TYPE_GRABBER
	vdev->cdev = NULL;/
	......

	/* Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
	/* Keep the ranges for the first four types for historical
	 * reasons.
	 * Newer devices (not yet in place) should use the range
	 * of 128-191 and just pick the first free minor there
	 * (new style). */
	switch (type) {
	case VFL_TYPE_GRABBER:
		minor_offset = 0;
		minor_cnt = 64;
		break;
	case VFL_TYPE_RADIO:
		minor_offset = 64;
		minor_cnt = 64;
		break;
	case VFL_TYPE_VBI:
		minor_offset = 224;
		minor_cnt = 32;
		break;
	default:
		minor_offset = 128;
		minor_cnt = 64;
		break;
	}
#endif

	/* Pick a device node number */
	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; //如果定义了改宏,那么video device的次设备号由nr和minor_offset共同决定。
#else
	/* The device node number and minor numbers are independent, so
	   we just find the first free minor number. */
为新注册的video device在数组video_device中寻找一个位置。
	for (i = 0; i < VIDEO_NUM_DEVICES; i++)
		if (video_device[i] == NULL)
			break;
......
#endif
	vdev->minor = i + minor_offset; //计算出设备的次设备号
    如果定义CONFIG_VIDEO_FIXED_MINOR_RANGES
	vdev->minor = i + minor_offset.
     否则
    vdev->minor = vdeio_device数组中第一个空闲的位置(从低地址开始。)


	vdev->num = nr;
	devnode_set(vdev);

	/* Should not happen since we thought this minor was free */
	WARN_ON(video_device[vdev->minor] != NULL);
	vdev->index = get_index(vdev);
	mutex_unlock(&videodev_lock);

	/* Part 3: Initialize the character device */、
//以下是初始化一个char dev结构,然后注册字符设备。
	vdev->cdev = cdev_alloc();
	if (vdev->cdev == NULL) {
		ret = -ENOMEM;
		goto cleanup;
	}
	vdev->cdev->ops = &v4l2_fops; //v4l2子系统实现的默认的file opration操作函数集,每个成员函数内会调用对应的v4l2_file_oprations操作函数集。
	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;
	}
.......
	return ret;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值