UVC(1)-v4l2框架分析

此节是韦东山第三期学习资料
 
当插入一个网上买的UVC时,内核UVC驱动会打印出下面的Log信息出来
0
对应的UVC驱动位于:/drivers/media/usb/uvc
0
 
当插入的UVC与uvc_ids匹配了,就会调用uvc_probe函数枚举设备
 struct uvc_driver uvc_driver = {
         .driver = {
                 .name           = "uvcvideo",
                 .probe          = uvc_probe,
                 .disconnect     = uvc_disconnect,
                 .suspend        = uvc_suspend,
                 .resume         = uvc_resume,
                 .reset_resume   = uvc_reset_resume,
                 .id_table       = uvc_ids,
                 .supports_autosuspend = 1,
         },
 };
 
在uvc_probe函数中,
uvc_probe
    ->v4l2_device_register
    ->uvc_register_chains
        ->uvc_register_terms
            ->uuv_register_video
                ->video_register_device    // 注册video_device,video_device使用cdev方式注册,cdev_ops = v4l2_fops
 
虚拟视频驱动vivid.c分析:
1、分配video_device
2、设置video_device结构体
3、注册video_device结构体
 
代码位置:linux/drivers/platform/vivid
vivid-core.c
 static const struct v4l2_file_operations vivid_fops = {
         .owner          = THIS_MODULE,
         .open           = v4l2_fh_open,
         .release        = vivid_fop_release,
         .read           = vb2_fop_read,
         .write          = vb2_fop_write,
         .poll           = vb2_fop_poll,
         .unlocked_ioctl = video_ioctl2,
         .mmap           = vb2_fop_mmap,
 };
 
  static const struct v4l2_file_operations vivid_radio_fops = {
         .owner          = THIS_MODULE,
         .open           = v4l2_fh_open,
         .release        = vivid_fop_release,
         .read           = vivid_radio_read,
         .write          = vivid_radio_write,
         .poll           = vivid_radio_poll,
         .unlocked_ioctl = video_ioctl2,
 };

 static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
         .vidioc_querycap                = vidioc_querycap,

         .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid,
         .vidioc_g_fmt_vid_cap           = vidioc_g_fmt_vid_cap,
         .vidioc_try_fmt_vid_cap         = vidioc_try_fmt_vid_cap,
         .vidioc_s_fmt_vid_cap           = vidioc_s_fmt_vid_cap,
         .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_mplane,
         .vidioc_g_fmt_vid_cap_mplane    = vidioc_g_fmt_vid_cap_mplane,
         .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap_mplane,
         .vidioc_s_fmt_vid_cap_mplane    = vidioc_s_fmt_vid_cap_mplane,

         .vidioc_enum_fmt_vid_out        = vidioc_enum_fmt_vid,
         .vidioc_g_fmt_vid_out           = vidioc_g_fmt_vid_out,
         .vidioc_try_fmt_vid_out         = vidioc_try_fmt_vid_out,
         .vidioc_s_fmt_vid_out           = vidioc_s_fmt_vid_out,
         .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_mplane,
         .vidioc_g_fmt_vid_out_mplane    = vidioc_g_fmt_vid_out_mplane,
         .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out_mplane,
         .vidioc_s_fmt_vid_out_mplane    = vidioc_s_fmt_vid_out_mplane,

         .vidioc_g_selection             = vidioc_g_selection,
         .vidioc_s_selection             = vidioc_s_selection,
         .vidioc_cropcap                 = vidioc_cropcap,

         .vidioc_g_fmt_vbi_cap           = vidioc_g_fmt_vbi_cap,
         .vidioc_try_fmt_vbi_cap         = vidioc_g_fmt_vbi_cap,
         .vidioc_s_fmt_vbi_cap           = vidioc_s_fmt_vbi_cap,

         .vidioc_g_fmt_sliced_vbi_cap    = vidioc_g_fmt_sliced_vbi_cap,
         .vidioc_try_fmt_sliced_vbi_cap  = vidioc_try_fmt_sliced_vbi_cap,
         .vidioc_s_fmt_sliced_vbi_cap    = vidioc_s_fmt_sliced_vbi_cap,
         .vidioc_g_sliced_vbi_cap        = vidioc_g_sliced_vbi_cap,

         .vidioc_g_fmt_vbi_out           = vidioc_g_fmt_vbi_out,
         .vidioc_try_fmt_vbi_out         = vidioc_g_fmt_vbi_out,
         .vidioc_s_fmt_vbi_out           = vidioc_s_fmt_vbi_out,
         .vidioc_g_fmt_sliced_vbi_out    = vidioc_g_fmt_sliced_vbi_out,
         .vidioc_try_fmt_sliced_vbi_out  = vidioc_try_fmt_sliced_vbi_out,
         .vidioc_s_fmt_sliced_vbi_out    = vidioc_s_fmt_sliced_vbi_out,

         .vidioc_enum_fmt_sdr_cap        = vidioc_enum_fmt_sdr_cap,
         .vidioc_g_fmt_sdr_cap           = vidioc_g_fmt_sdr_cap,
         .vidioc_try_fmt_sdr_cap         = vidioc_g_fmt_sdr_cap,
         .vidioc_s_fmt_sdr_cap           = vidioc_g_fmt_sdr_cap,

         .vidioc_overlay                 = vidioc_overlay,
         .vidioc_enum_framesizes         = vidioc_enum_framesizes,
         .vidioc_enum_frameintervals     = vidioc_enum_frameintervals,
         .vidioc_g_parm                  = vidioc_g_parm,
         .vidioc_s_parm                  = vidioc_s_parm,

         .vidioc_enum_fmt_vid_overlay    = vidioc_enum_fmt_vid_overlay,
         .vidioc_g_fmt_vid_overlay       = vidioc_g_fmt_vid_overlay,
         .vidioc_try_fmt_vid_overlay     = vidioc_try_fmt_vid_overlay,
         .vidioc_s_fmt_vid_overlay       = vidioc_s_fmt_vid_overlay,
         .vidioc_g_fmt_vid_out_overlay   = vidioc_g_fmt_vid_out_overlay,
         .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_out_overlay,
         .vidioc_s_fmt_vid_out_overlay   = vidioc_s_fmt_vid_out_overlay,
         .vidioc_g_fbuf                  = vidioc_g_fbuf,
         .vidioc_s_fbuf                  = vidioc_s_fbuf,

         .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
         .vidioc_create_bufs             = vb2_ioctl_create_bufs,
         .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
         .vidioc_querybuf                = vb2_ioctl_querybuf,
         .vidioc_qbuf                    = vb2_ioctl_qbuf,
         .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
         .vidioc_expbuf                  = vb2_ioctl_expbuf,
         .vidioc_streamon                = vb2_ioctl_streamon,
         .vidioc_streamoff               = vb2_ioctl_streamoff,

         .vidioc_enum_input              = vidioc_enum_input,
         .vidioc_g_input                 = vidioc_g_input,
         .vidioc_s_input                 = vidioc_s_input,
         .vidioc_s_audio                 = vidioc_s_audio,
         .vidioc_g_audio                 = vidioc_g_audio,
         .vidioc_enumaudio               = vidioc_enumaudio,
         .vidioc_s_frequency             = vidioc_s_frequency,
         .vidioc_g_frequency             = vidioc_g_frequency,
         .vidioc_s_tuner                 = vidioc_s_tuner,
         .vidioc_g_tuner                 = vidioc_g_tuner,
         .vidioc_s_modulator             = vidioc_s_modulator,
         .vidioc_g_modulator             = vidioc_g_modulator,
         .vidioc_s_hw_freq_seek          = vidioc_s_hw_freq_seek,
         .vidioc_enum_freq_bands         = vidioc_enum_freq_bands,

         .vidioc_enum_output             = vidioc_enum_output,
         .vidioc_g_output                = vidioc_g_output,
         .vidioc_s_output                = vidioc_s_output,
         .vidioc_s_audout                = vidioc_s_audout,
         .vidioc_g_audout                = vidioc_g_audout,
         .vidioc_enumaudout              = vidioc_enumaudout,

         .vidioc_querystd                = vidioc_querystd,
         .vidioc_g_std                   = vidioc_g_std,
         .vidioc_s_std                   = vidioc_s_std,
         .vidioc_s_dv_timings            = vidioc_s_dv_timings,
         .vidioc_g_dv_timings            = vidioc_g_dv_timings,
         .vidioc_query_dv_timings        = vidioc_query_dv_timings,
         .vidioc_enum_dv_timings         = vidioc_enum_dv_timings,
         .vidioc_dv_timings_cap          = vidioc_dv_timings_cap,
         .vidioc_g_edid                  = vidioc_g_edid,
         .vidioc_s_edid                  = vidioc_s_edid,

         .vidioc_log_status              = v4l2_ctrl_log_status,
         .vidioc_subscribe_event         = vidioc_subscribe_event,
         .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 };    
 
vivid_init
    ->vivid_probe
        ->vivid_create_instance
            ->设置ctrl(用于app的ioctl):事先添加属性
                例如dev->brightness = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
                    V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
            ->v4l2_device_register    // 不是主要,主要初始化一些东西,比如自旋锁,引用计数
            ->video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]);    // 根据不同的功能,实现不同的节点注册
                ->__video_register_device
                    vdev->cdev = cdev_alloc();
                    vdev->cdev->ops = &v4l2_fops;
                    cdev_add



分析vivid的open、read、write、ioctl过程:
app: open("/dev/video0",...)
--------------------------------------------------------------------------------
drv: v4l2_open
        vdev = video_devdata(filp);    // 根据次设备号从数组中得到video_device
        ret = vdev->fops->open(filp);    // 也就是vivid_fops->v4l2_fh_open函数

app: ioctl
--------------------------------------------------------------------------------
drv: v4l2_fops.unlocked_ioctl
        v4l2-ioctl
            struct video_device vdev = video_devdata(filp);
            ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
                    video_ioctl2
                        video_usercopy(file, cmd, arg, __video_do_ioctl);
                            __video_do_ioctl
                                struct video_device *vfd = video_devdata(file);
                                根据app传入的cmn来获取设置某些属性

 

如何填写v4l2驱动:
1、分配设置注册v4l2_device:v4l2_device_register,得到v4l2_device(辅助作用,提供自旋锁引用计数)
2、分配设置注册一个video_device结构体,video_register_device,video_device.v4l2_device指向第一步分配的v4l2_device
3、video_device.v4l2_file_operations会被上层应用调用到的open/read/ioctl所调用
4、video_device.v4l2_ioctl_ops会被上层应用调用到的ioctl所间接调用
5、app可以通过ioctl来设置亮度等等信息,驱动程序使用v4l2_ctrl属性来表示接收存储设置到硬件
属性:v4l2_ctrl
管理:v4l2_ctrl_handler
初始化一个v4l2_ctrl_hander:v4l2_ctrl_handler_init
添加v4l2_ctrl属性项:v4l2_ctrl_new_std和v4l2_ctrl_new_custom,创建个个v4l2_ctrl,放入v4l2_ctrl_handler管理的链表
6、v4l2_dev.ctrl_handler和video_dev->v4l2_dev相关联
 
v4l2_vtrl_handler的使用过程:
    IOCTL_INFO_FNC(VIDIOC_QUERYCTRL, v4l_queryctrl, v4l_print_queryctrl, INFO_FL_CTRL | INFO_FL _CLEAR(v4l2_queryctrl, id)),
->
    static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops,
                                 struct file *file, void *fh, void *arg)
 {
         struct video_device *vfd = video_devdata(file);
         struct v4l2_queryctrl *p = arg;
         struct v4l2_fh *vfh =
                 test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL;

         if (vfh && vfh->ctrl_handler)
                 return v4l2_queryctrl(vfh->ctrl_handler, p);
         if (vfd->ctrl_handler)
                 return v4l2_queryctrl(vfd->ctrl_handler, p);
         if (ops->vidioc_queryctrl)
                 return ops->vidioc_queryctrl(file, fh, p);
         return -ENOTTY;
 }

 

 

 

posted @ 2024-04-02 19:25  lethe1203  阅读(7)  评论(0编辑  收藏  举报