zoukankan      html  css  js  c++  java
  • USB摄像头驱动框架分析(五)


    一、USB摄像头驱动框架如下所示:
    1.构造一个usb_driver
    2.设置
       probe:
            2.1. 分配video_device:video_device_alloc
            2.2. 设置
               .fops
               .ioctl_ops (里面需要设置11项)
               如果要用内核提供的缓冲区操作函数,还需要构造一个videobuf_queue_ops
            2.3. 注册: video_register_device     
      id_table: 表示支持哪些USB设备     
    3.注册: usb_register

    二、分析UVC驱动

    UVC: USB Video Class
    UVC驱动:driversmediavideouvc

    uvc_driver.c分析:
      1. usb_register(&uvc_driver.driver);
      2. uvc_probe
            uvc_register_video
                vdev = video_device_alloc();
                vdev->fops = &uvc_fops;
                video_register_device

    分析一个驱动程序最好的方法就是跟踪应用程序对它的调用过程
     
    在www.usb.org下载 uvc specification, UVC规格书
    UVC 1.5 Class specification.pdf : 有详细描述

    USB_Video_Example 1.5.pdf    : 有示例
    由拓扑图可看出:
              USB摄像头内部分成两部分

        VideoControl Interface:视频控制接口 ——> 用于控制

        VideoSteaming Interface:视频流接口——>用于读取视频数据


     在USB Camera内部抽象出了个概念:

      Units :单元,内部连接,提供具有大部分功能的模块,如Selector Unit 、Process Unit

         SU: Select orUnit     多路选择器,选择两路输入IT和OT其中之一;选择哪一路信号
              PU: Process Unit    处理单元: 应该是亮度、白平衡,饱和度等的设置

      Terminals :端点,用于“内”“外”的连接

         CT:Camear Terminal  功能有:选择扫描模式、曝光模式、时间,缩放,焦点等
        IT / OT:Input / Output Terminal  视频数据流的输入输出端点
    VC里含有多个Unit/Terminal等功能模块,可以通过访问这些模块进行控制,比如调亮度
     
    三、分析UVC驱动调用过程:
     
    1. open:
            uvc_v4l2_open //主要是一些状态的设置
            
    应用程序调用ioctl时,就会进入uvc_v4l2_ioctl
     .ioctl = uvc_v4l2_ioctl,
        //把应用程序提供的参数拷贝到内核态,然后调用uvc_v4l2_do_ioctl
        video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl)
            uvc_v4l2_do_ioctl
                case VIDIOC_QUERYCAP:
                    ... //一系列ioctl
                case VIDIOC_G_INPUT:
    
    2. VIDIOC_QUERYCAP    // video->streaming->type 在设备被枚举时分析描述符时初始化
            if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
                          | V4L2_CAP_STREAMING;
            else
                cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
                          | V4L2_CAP_STREAMING;
                          
    3. VIDIOC_ENUM_FMT // format数组应是在设备被枚举时设置的
            format = &video->streaming->format[fmt->index];
            
    4. VIDIOC_G_FMT
            uvc_v4l2_get_format  // USB摄像头支持多种格式fromat, 每种格式下有多种frame(比如分辨率)
                    struct uvc_format *format = video->streaming->cur_format;
                    struct uvc_frame *frame = video->streaming->cur_frame;
    5. VIDIOC_TRY_FMT
            uvc_v4l2_try_format
                /* Check if the hardware supports the requested format. */
    
                /* Find the closest image size. The distance between image sizes is
                 * the size in pixels of the non-overlapping regions between the
                 * requested size and the frame-specified size.
                 */
    6. VIDIOC_S_FMT  // 只是把参数保存起来,还没有发给USB摄像头
            uvc_v4l2_set_format
                uvc_v4l2_try_format
                video->streaming->cur_format = format;
                video->streaming->cur_frame = frame;
    7. VIDIOC_REQBUFS
            uvc_alloc_buffers
                   for (; nbuffers > 0; --nbuffers) {
                    mem = vmalloc_32(nbuffers * bufsize);
                    if (mem != NULL)
                        break;
                }
    8. VIDIOC_QUERYBUF
            uvc_query_buffer
                __uvc_query_buffer
                    memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);  // 复制参数
    9. mmap
            uvc_v4l2_mmap
                
    10. VIDIOC_QBUF
            uvc_queue_buffer
                list_add_tail(&buf->stream, &queue->mainqueue);
                list_add_tail(&buf->queue, &queue->irqqueue);
                
    /*应用程序把buf放入队列后,会调用STREAMON做一些初始化,启动传输,*/
    11. VIDIOC_STREAMON
            uvc_video_enable(video, 1)  // 把所设置的参数发给硬件,然后启动摄像头
                /* Commit the streaming parameters. */
                uvc_commit_video
                    uvc_set_video_ctrl  /* 设置格式fromat, frame */
                            ret = __uvc_query_ctrl(video->dev /* 哪一个USB设备 */, SET_CUR, 0,
                                video->streaming->intfnum  /* 哪一个接口: VS */,
                                probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
                                uvc_timeout_param);
                        
                /* 启动:初始化实时的USB请求块,并分配传输buf. */
                uvc_init_video(video, GFP_KERNEL);
                        uvc_init_video_isoc / uvc_init_video_bulk
                            urb->complete = uvc_video_complete; 
                            /*收到数据后此函数被调用,它又调用video->decode(urb, video, buf); 
                             *最终会调用到=> wake_up(&buf->wait);终止休眠等待*/
                        usb_submit_urb  //初始完后提交urb结构体(USB Request Block) 
                        
    /* 调用poll查询数据是否准备就绪,没有的话进入休眠等待 */                     
    12. poll
            uvc_v4l2_poll            
                uvc_queue_poll
                    poll_wait(file, &buf->wait, wait);  // 休眠等待有数据
    
    /* poll返回之后就表明有可用数据,就从队列中取出buf */
    13. VIDIOC_DQBUF
            uvc_dequeue_buffer
                list_del(&buf->stream);
    
    14. VIDIOC_STREAMOFF            
            uvc_video_enable(video, 0);
                usb_kill_urb(urb);
                usb_free_urb(urb);
            
    分析设置亮度过程:
    ioctl: VIDIOC_S_CTRL
                uvc_ctrl_set
                uvc_ctrl_commit
                    __uvc_ctrl_commit(video, 0);
                        uvc_ctrl_commit_entity(video->dev, entity, rollback);
                                ret = uvc_query_ctrl(dev  /* 哪一个USB设备 */, SET_CUR, 
                                        ctrl->entity->id  /* 哪一个unit/terminal */,
                                         dev->intfnum  /* 哪一个接口: VC interface */, 
                                         ctrl->info->selector,
                                         uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                                         ctrl->info->size)

    总结:

    1. UVC设备有2个interface: VideoControl Interface, VideoStreaming Interface
    2. VideoControl Interface用于控制,比如设置亮度。它内部有多个Unit/Terminal(在程序里Unit/Terminal都称为entity:实体)
       可以通过类似的函数来访问:
            ret = uvc_query_ctrl(dev  /* 哪一个USB设备 */, SET_CUR, ctrl->entity->id  /* 哪一个unit/terminal */,
                dev->intfnum /* 哪一个接口: VC interface */, ctrl->info->selector,
                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                ctrl->info->size);
    3. VideoStreaming Interface用于获得视频数据,也可以用来选择fromat/frame(VS可能有多种format, 一个format支持多种frame, frame用来表示分辨率等信息)
       可以通过类似的函数来访问:
            ret = __uvc_query_ctrl(video->dev /* 哪一个USB设备 */, SET_CUR, 0,
                video->streaming->intfnum  /* 哪一个接口: VS */,
                probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
                uvc_timeout_param);
    4. 我们在设置FORMAT时只是简单的使用video->streaming->format[fmt->index]等数据,
       这些数据哪来的?
       应是设备被枚举时设置的,也就是分析它的描述符时设置的。
    
    5. UVC驱动的重点在于:
       描述符的分析
       属性的控制: 通过VideoControl Interface来设置
       格式的选择:通过VideoStreaming Interface来设置
       数据的获得:通过VideoStreaming Interface的URB来获得
  • 相关阅读:
    tomcat加载项目原理解惑
    英语口语大全
    ubuntu中wubi正在下载ubuntu11.04desktopi386.iso
    Strust2获得session和request
    字符串转成对象
    DevExpress控件使用
    DevExpress控件之GridControl控件(控件篇)
    ASP.NET AJAX + JSON 实现对象调用
    WinForm窗体之间交互的一些方法[转]
    barmanager设置
  • 原文地址:https://www.cnblogs.com/y4247464/p/10629885.html
Copyright © 2011-2022 走看看