三、video设备初始化

一、V4L2应用层调用流程


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

video_device结构体

struct video_device
{
#if defined (CONFIG_MEDIA_CONTROLLER)
	struct media_entity entity;
    struct media_intf_devnode *intf_devnode;
    struct media_pipeline pipe;
#endif
    const struct v4l2_file_operations *fops;
    u32 device_caps;

/* sysfs /
struct device dev;
struct cdev cdev;
struct v4l2_device v4l2_dev;
struct device dev_parent;
struct v4l2_ctrl_handler ctrl_handler;
struct vb2_queue queue;
struct v4l2_prio_state prio;
/ device info /
char name[32];
int vfl_type;
int vfl_dir;
int minor;
u16 num;
unsigned long flags;
int index;
/ V4L2 file handles /
spinlock_t fh_lock;
struct list_head fh_list;
int dev_debug;
v4l2_std_id tvnorms;
/ callbacks /
void (release)(struct video_device vdev);
const struct v4l2_ioctl_ops ioctl_ops;
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);
struct mutex *lock;
};

video设备也是一个字符设备,具备字符设备的open、close、read、wirte、ioctl功能

v4l2_file_operations结构体初始化定义

struct v4l2_file_operations xxx_fops = {
    .owner = THIS_MODULE,
    .open = xxx_open,
    .release = xxx_close,
    .read = xxx_read,
    .poll = xxx_p_poll, 
    .unlocked_ioctl = video_ioctl2,
    .mmap = xxx_mmap,
};  

v4l2_ioctl_ops结构体初始化定义

struct v4l2_ioctl_ops xxx_v4l2_ioctl_ops = {
    .vidioc_querycap = xxx_v4l2_querycap,
<span class="token comment">/* Per-stream config operations */</span>
<span class="token punctuation">.</span>vidioc_g_fmt_vid_cap_mplane <span class="token operator">=</span> xxx_v4l2_g_fmt_vid_cap<span class="token punctuation">,</span>
<span class="token punctuation">.</span>vidioc_enum_fmt_vid_cap <span class="token operator">=</span> xxx_v4l2_enum_fmt_vid_cap<span class="token punctuation">,</span>
<span class="token punctuation">.</span>vidioc_try_fmt_vid_cap_mplane <span class="token operator">=</span> xxx_v4l2_try_fmt_vid_cap<span class="token punctuation">,</span>
<span class="token punctuation">.</span>vidioc_s_fmt_vid_cap_mplane <span class="token operator">=</span> xxx_v4l2_s_fmt_vid_cap<span class="token punctuation">,</span>

.vidioc_g_fmt_vid_cap = xxx_v4l2_g_fmt_vid_cap,
.vidioc_enum_fmt_vid_cap = xxx_v4l2_enum_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = xxx_v4l2_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = xxx_v4l2_s_fmt_vid_cap,
.vidioc_enum_framesizes = xxx_v4l2_enum_framesizes,
/* Per-stream control operations /
.vidioc_streamon = xxx_v4l2_streamon,
.vidioc_streamoff = xxx_v4l2_streamoff,
/ input control /
.vidioc_enum_input = xxx_v4l2_enum_input,
.vidioc_g_input = xxx_v4l2_g_input,
.vidioc_s_input = xxx_v4l2_s_input,
/ vb2 customization for multi-stream support /
.vidioc_reqbufs = xxx_v4l2_reqbufs,
.vidioc_querybuf = xxx_v4l2_querybuf,
.vidioc_qbuf = xxx_v4l2_qbuf,
.vidioc_dqbuf = xxx_v4l2_dqbuf,
/ v4l2 event ioctls /
.vidioc_log_status = xxx_ctrl_log_status,
.vidioc_subscribe_event = xxx_ctrl_subscribe_event,
.vidioc_unsubscribe_event = xxx_event_unsubscribe,
/ crop ioctls */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
.vidioc_g_selection = xxx_v4l2_g_selection,
.vidioc_s_selection = xxx_v4l2_s_selection,
.vidioc_g_pixelaspect = xxx_v4l2_g_pixelaspect,
#else
.vidioc_cropcap = xxx_v4l2_cropcap,
.vidioc_g_crop = xxx_v4l2_g_crop,
.vidioc_s_crop = xxx_v4l2_s_crop,
#endif
.vidioc_expbuf = xxx_v4l2_expbuf,
};

以上的xxx函数都是各个平台最终实现的函数功能,左边的由用户程序调用到kernel驱动最终调用到平台函数

video_register_device注册

struct video_device *vdev;
    vdev= &dev->video_dev;
    strlcpy( vfd->name, "xxx", sizeof( vfd->name ) );
    vdev->fops = &xxx_v4l2_fops;
    vdev->ioctl_ops = &xxx_v4l2_ioctl_ops;
    vdev->release = video_device_release_empty;
    vdev->v4l2_dev = dev->v4l2_dev;
    vdev->queue = NULL; // queue will be customized in file handle
    vdev->tvnorms = tvnorms_cap;
    vdev->vfl_type = VFL_TYPE_GRABBER;
    vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
    //VFL_TYPE_GRABBER代表注册的是video节点
    //0代表的是注册video0节点
    video_register_device( vdev, VFL_TYPE_GRABBER, 0);//代表创建注册video0节点
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);
}

int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_use, struct module *owner)
{
	...
	/* v4l2_fh support */
	spin_lock_init(&vdev->fh_lock);
	INIT_LIST_HEAD(&vdev->fh_list);
	switch(type)
	{
		case VFL_TYPE_GRABBER:
			name_base = "video";
			break;
	}
	...
	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->vdev_dev->ctrl_handler;
	if (vdev->prio == NULL)
		vdev->prio = &vdev->v4l2_dev->prio;
	
	switch (type) {
		case VFL_TYPE_GRABBER:
			minor_offset = 0;
			minor_cnt = 64;
			break;
	}
	...
	vdev->minor = i + minor_offset;
	vdev->num = nr;
	    devnode_set(vdev);
    video_device[vdev->minor] = vdev;//把vdev保存到了 video_device[x]
    ...
    vdev->cdev->ops = &v4l2_fops;
    ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
    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);
}

                
  
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值