V4L2系列之video_register_device函數分析

來源:互聯網
上載者:User

感覺寫完了其實也沒怎麼理解這個函數,但是還是這裡儲存一下,希望大家予以拍磚指導:

下面分析一下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,並完成相關裝置初始化的一些工作。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.