感觉写完了其实也没怎么理解这个函数,但是还是这里保存一下,希望大家予以拍砖指导:
下面分析一下video_register_device这个函数:位于include/media/v4l2-dev.h头文件中:
参考文献:http://blog.sina.com.cn/s/blog_602f87700101a52s.html
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函数:
其中:第一个参数struct video_device *vdev是想注册的video device的结构体;
第二个参数是视频设备类型,在此头文件(v4l2-dev.h中),定义了几种视频设备类型:
#defineVFL_TYPE_GRABBER 0 //图像采集设备
#defineVFL_TYPE_VBI 1 //从视频消隐的时间段获得信息的设备
#defineVFL_TYPE_RADIO 2 //无线电设备
#defineVFL_TYPE_SUBDEV 3 //视频设备(不确定)
#defineVFL_TYPE_MAX 4 //最大值
第三个参数是注册的设备节点号;
video_register_device函数主要是注册一个V4L2device,指定类型,然后指定device node number。函数只是简单的调用了__video_register_device函数。
按照参考文档的说明:这个__video_register_device函数主要做的工作有:1、初始化一些值;2、创建字符模式驱动;3、注册字符设备等。
下面我来分析这个函数,这个函数的定义在v4l2-dev.c中,声明在v4l2-dev.h中:
int__video_register_device(struct video_device *vdev, int type, int nr,
int warn_if_nr_in_use, struct module *owner)
前三个参数与video_register_device中相同,第四个参数不知道,第五个参数表面指向当前的模块;
int i =0;
intret;
intminor_offset = 0;
intminor_cnt = VIDEO_NUM_DEVICES;
constchar *name_base;
声明了一些变量;其中minor_cnt的赋值VIDEO_NUM_DEVICES仍定义在v4l2-dev.c中:
#defineVIDEO_NUM_DEVICES 256
声明最大的设备数量为256个?
/* A minor value of -1marks this video device as never
having beenregistered */
vdev->minor = -1;
-1表明这个video device从未被注册过(其实是指之前注册失败)。
/* the release callbackMUST be present */
if (WARN_ON(!vdev->release))
return -EINVAL;
声明release回调函数。
/* v4l2_fh support */
spin_lock_init(&vdev->fh_lock);
INIT_LIST_HEAD(&vdev->fh_list);
调用自旋锁和初始化链表。
下面开始进入各个部分的工作:
第一部分:
/* Part 1: check devicetype */
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;
vdev->cdev= NULL;
if(vdev->v4l2_dev) {
if (vdev->v4l2_dev->dev)
vdev->parent = vdev->v4l2_dev->dev;
if (vdev->ctrl_handler == NULL)
vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
/* If the prio state pointer is NULL, then use the v4l2_device prio state. */
if (vdev->prio == NULL)
vdev->prio = &vdev->v4l2_dev->prio;
}
这里是填充struct video_device的一些字段。
第二部分:
注册device node number等。
/* Part 2: find a freeminor, device node number and device index. */
#ifdefCONFIG_VIDEO_FIXED_MINOR_RANGES
/* Keep the ranges for the first four types for historical
* reasons.
* Newer devices (notyet in place) should use the range
* of 128-191 and justpick 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
定义minor_offset和minor_cnt。
/* 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 nodenumber\n");
mutex_unlock(&videodev_lock);
return -ENFILE;
}
注册device node number。
函数devnode_find:发现节点号。
#ifdefCONFIG_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 thefirst 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 freeminor\n");
return -ENFILE;
}
#endif
vdev->minor = i + minor_offset;
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);
/* if no lock was passed, then make sure the LOCK_ALL_FOPS bit is
clear and warn if itwasn't. */
if (vdev->lock == NULL)
WARN_ON(test_and_clear_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags));
if(vdev->ioctl_ops)
determine_valid_ioctls(vdev);
我都搞晕了,不知道第二部分在搞什么。
第三部分:初始化字符设备
/* Part 3: Initialize thecharacter device */
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;
}
调用cdev_add注册字符设备。这个看的比较简单。
第四部分:
注册device
/* Part 4: register thedevice with sysfs */
vdev->dev.class = &video_class;
vdev->dev.devt= MKDEV(VIDEO_MAJOR, vdev->minor);
if (vdev->parent)
vdev->dev.parent =vdev->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_registerfailed\n", __func__);
goto cleanup;
}
在sysfs中注册device。
/* Register the release callback that will be called when thelast
reference to thedevice goes away. */
vdev->dev.release = v4l2_device_release;
注册回调函数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_devicerefcount */
if(vdev->v4l2_dev)
v4l2_device_get(vdev->v4l2_dev);
第五部分:
在定义了CONFIG_MEDIA_CONTROLLER后才有第五部分,注册entity(实体?)
#ifdefined(CONFIG_MEDIA_CONTROLLER)
/* Part 5: Register the entity. */
if (vdev->v4l2_dev&& vdev->v4l2_dev->mdev&&
vdev->vfl_type !=VFL_TYPE_SUBDEV) {
vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
vdev->entity.name = vdev->name;
vdev->entity.info.v4l.major = VIDEO_MAJOR;
vdev->entity.info.v4l.minor = vdev->minor;
ret = media_device_register_entity(vdev->v4l2_dev->mdev,
&vdev->entity);
if (ret < 0)
printk(KERN_WARNING
"%s: media_device_register_entity failed\n",
__func__);
}
#endif
第六部分:
/* Part 6: Activate thisminor. The char device can now be used. */
set_bit(V4L2_FL_REGISTERED, &vdev->flags);
mutex_lock(&videodev_lock);
video_device[vdev->minor] = vdev;
mutex_unlock(&videodev_lock);
解锁,激活这一字符设备。
最后:
cleanup:
mutex_lock(&videodev_lock);
if (vdev->cdev)
cdev_del(vdev->cdev);
devnode_clear(vdev);
mutex_unlock(&videodev_lock);
/* Mark this video device as never having been registered. */
vdev->minor = -1;
return ret;
相关的一些清理操作。
总之呢,video_register_device的作用就是注册一个video device,并完成相关设备初始化的一些工作。