参照元

説明

引数

返り値

参考

実装

/**
 *      __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)
{
        int i = 0;
        int ret;
        int minor_offset = 0;
        int minor_cnt = VIDEO_NUM_DEVICES;
        const char *name_base;
        /* A minor value of -1 marks this video device as never
           having been registered */
        vdev->minor = -1;

        /* the release callback MUST be present */
        if (WARN_ON(!vdev->release))
                return -EINVAL;
        /* the v4l2_dev pointer MUST be present */
        if (WARN_ON(!vdev->v4l2_dev))
                return -EINVAL;
        /* v4l2_fh support */
        spin_lock_init(&vdev->fh_lock);
        INIT_LIST_HEAD(&vdev->fh_list);
        /* 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;
        case VFL_TYPE_SDR:
                /* Use device name 'swradio' because 'sdr' was already taken. */
                name_base = "swradio";
                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->dev_parent == NULL)
                vdev->dev_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;
        /* 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;
#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
        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);
        video_device[vdev->minor] = vdev;
        mutex_unlock(&videodev_lock);

        if (vdev->ioctl_ops)
                determine_valid_ioctls(vdev);
        /* Part 3: Initialize the character 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;
        }
        /* 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);
#if defined(CONFIG_MEDIA_CONTROLLER)
        /* Part 5: Register the entity. */
        if (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.dev.major = VIDEO_MAJOR;
                vdev->entity.info.dev.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 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;
}
EXPORT_SYMBOL(__video_register_device);

コメント


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-02-08 (月) 17:56:13