七、V4L2 ioctl 标准接口 调用流程

一、V4L2应用层调用流程
二、V4L2设备注册
三、video设备初始化
四、V4L2 control结构框架图
五、v4l2 ctrl 函数初始化—增加标准接口v4l2_ctrl_new_std
六、v4l2 ctrl 函数初始化—增加自定义接口v4l2_ctrl_new_custom
七、V4L2 ioctl 标准接口 调用流程
八、V4L2 ioctl 控制接口 调用流程

V4L2 ioctl调用流程

当video节点注册完成之后,用户层就会通过 该节点的字符设备接口接入到内核中去
三、video设备初始化中就讲解了video的初始化,vdev->cdev->ops = &v4l2_fops; 代表着用户层的ioctl会调用到v4l2_fops的unlocked_ioctl = v4l2_ioctl;

结构体 file_operations

static const struct file_operations v4l2_fops = {
        .owner = THIS_MODULE,
        .read = v4l2_read,
        .write = v4l2_write,
        .open = v4l2_open,
        .get_unmapped_area = v4l2_get_unmapped_area,
        .mmap = v4l2_mmap,
        .unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
        .compat_ioctl = v4l2_compat_ioctl32,
#endif
        .release = v4l2_release,
        .poll = v4l2_poll,
        .llseek = no_llseek,
};

v4l2_ioctl

static long v4l2_ioctl(struct file filp, unsigned int cmd, unsigned long arg)
{
	struct video_device *vdev = video_devdata(flip);
	int ret = -ENODEV;

	if (vdev->fops->unlocked_ioctl) {
			if (video_is_registered(vdev))
				//这里从kernel的ioctl 就调用到具体video设备的ioctl上去了
				ret = vdev->fops->unlocked_ioctl(flip, cmd, arg)
			else
				ret = -ENOTTY;	
	}
	return ret;
}

接下来看下具体设备的fops的结构体

static const struct v4l2_file_operations xxx_v4l2_fops = {
    .owner = THIS_MODULE,
    .open = xxx_v4l2_fop_open,
    .release = xxx_v4l2_fop_close,
    .read = xxx_v4l2_fop_read,
    .poll = xxx_v4l2_fop_poll,
    .unlocked_ioctl = video_ioctl2,
    .mmap = xxx_v4l2_fop_mmap,
};

从用户层的ioctl的调用直接调用到了 具体设备的unlocked_ioctl
unlocked_ioctl 又调用到了kernel的video_ioctl2

video_ioctl2

long video_ioctl2(struct file *file,
               unsigned int cmd, unsigned long arg)
{
        return video_usercopy(file, cmd, arg, __video_do_ioctl);
}

__video_do_ioctl

static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
	struct video_device *vfd = video_devdata(file);
	struct mutex *req_queue_lock = NULL;
	struct mutex *lock;
	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
	struct write_only = false;
	struct v4l2_ioctl_info default_info;
	const struct v4l2_ioctl_info *info;
	void *fh = file->private_data;
	struct v4l2_fh *vfh = NULL;
	int dev_debug = vfd->dev_debug;
	long ret = -ENOTTY;
	
        if (ops == NULL) {
                pr_warn("%s: has no ioctl_ops.\n",
                                video_device_node_name(vfd));
                return ret;
        }

        if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags))
                vfh = file->private_data;

		....
		/*
		假如执行的是
		ioctl(fd, VIDIOC_QUERYCAP, &cap)
		info = v4l2_ioctls[0]组的地址
		*/
	if (v4l2_is_know_ioctl(cmd)) {
		info = &v4l2_ioctls[_IOC_NR(cmd)];
	}

	ret = info->func(ops, file, fh, arg);
}

v4l2_is_known_ioctl

static bool v4l2_is_known_ioctl(unsigned int cmd)
{
        if (_IOC_NR(cmd) >= V4L2_IOCTLS)
                return false;
        return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd;
}

v4l2_ioctl_info 结构体

struct v4l2_ioctl_info {
        unsigned int ioctl;
        u32 flags;
        const char * const name;
        int (*func)(const struct v4l2_ioctl_ops *ops, struct file *file,
                    void *fh, void *p);
        void (*debug)(const void *arg, bool write_only);
};
static const struct v4l2_ioctl_info v4l2_ioctls[] = {
	IOCTL_INFO(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0),
}
#define IOCTL_INFO(_ioctl, _func, _debug, _flags)               \
        [_IOC_NR(_ioctl)] = {                                   \
                .ioctl = _ioctl,                                \
                .flags = _flags,                                \
                .name = #_ioctl,                                \
                .func = _func,                                  \
                .debug = _debug,                                \
        }

info->func最后就指向了v4l_querycap
在前面的初始化中 const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;

static int v4l_querycap(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
{
    	struct v4l2_capability *cap = (struct v4l2_capability *)arg;
    	struct video_device *vfd = video_devdata(file);
    	cap->version = LINUX_VERSION_CODE;
        cap->device_caps = vfd->device_caps;
        cap->capabilities = vfd->device_caps | V4L2_CAP_DEVICE_CAPS;

        ret = ops->vidioc_querycap(file, fh, cap); //从这里调用到了 平台自定义的驱动中
        cap->capabilities |= V4L2_CAP_EXT_PIX_FORMAT;
}

在这里插入图片描述

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值