V4L2系列之video_register_device函数分析

来源:互联网 发布:西部数码备案域名购买 编辑:程序博客网 时间:2024/05/18 02:23

感觉写完了其实也没怎么理解这个函数,但是还是这里保存一下,希望大家予以拍砖指导:


下面分析一下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,并完成相关设备初始化的一些工作。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 车辆被扣24分怎么办 现在深圳牌十年老车怎么办? 护士证过期4年了怎么办 护士资格证延续注册过期了怎么办 护士资格证过期没注册怎么办 护士资格证注册时间过期怎么办 辅警体检视力不行怎么办 护士延续注册体检怀孕怎么办 护士资格证没有延续注册怎么办 申请信用卡没有座机号码怎么办 网上申请信用卡没有座机号码怎么办 我叫上门服务被骗了怎么办 上门服务被骗了3000多怎么办 微信被骗9000元怎么办 奥迪a8气囊灯亮怎么办 驾考站岗迟到了怎么办 老板欠员工工资不给怎么办 如果有一天我没头发了怎么办 苏州公积金密码忘了怎么办 科二考试第二把怎么办 科一老是记不住怎么办 科目二考试没去怎么办 网约车驾龄不到怎么办 科四预约不上怎么办 教练不退钱怎么办找谁 驾考出入证丢了怎么办 科二成绩单丢了怎么办 考驾照的准考证丢了怎么办 驾考预约去不了怎么办 科目一预约没去怎么办 打狂犬疫苗期间感冒了怎么办 公司社保欠费不交怎么办 25号社保不交怎么办欠费 会计从业停考了怎么办 黑龙江龙育黄了档案怎么办 科目四档案丢了怎么办 从上海调档案到杭州怎么办 户口迁移身份证变更护照怎么办 有中国签证的孩子怎么办户口 大学生户口在学校怎么办签证 户口在南方人才市场怎么办签证