jz2440 的Linux内核vivi.c框架分析

本文详细探讨了jz2440平台上的Linux内核vivi.c驱动框架,通过分析fill_buffer.c源码,展示了摄像头驱动程序的编写步骤:包括使用video_device_alloc分配设备,设置如.fops和.ioctl_ops的结构,以及注册video_device。如果使用内核缓冲区操作,还需定义videobuf_queue_ops。
摘要由CSDN通过智能技术生成
内核文档: V4L2-framework.txt


一、测试虚拟驱动vivi

准备工作:安装xawtv
sudo apt-get install xawtv

源码xawtv-3.95.tar.gz
http://www.kraxel.org/releases/xawtv/

在这个网站创建新的sources.list
http://repogen.simplylinux.ch/
1. 选择国家
2.选择相邻的ubuntu版本
3. 选择"Ubuntu Branches"
4. 生成sources.list
5. 把得到内容替换到/etc/apt/sources.list
deb http://cn.archive.ubuntu.com/ubuntu/ trusty main restricted universe multiverse
6. sudo apt-get update
   sudo apt-get install xawtv

测试USB摄像头:
1.让VMWAER处于前台,接上USB摄像头,可以看到生成了/dev/video0
2.执行 xawtv 即可看到图像

测试虚拟摄像头vivi:
1. 确实ubuntu的内核版本
uname -a
Linux book-desktop 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:04:26 UTC 2009 i686 GNU/Linux
2. 去www.kernel.org下载同版本的内核
   解压后把drivers/media/video目录取出
   修改它的Makefile为:

KERN_DIR = /usr/src/linux-headers-2.6.31-14-generic

all:
        make -C $(KERN_DIR) M=`pwd` modules 

clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order

obj-m   += vivi.o
obj-m   += videobuf-core.o
obj-m   += videobuf-vmalloc.o
obj-m   += v4l2-common.o
   
3. make
4. sudo modprobe vivi  
   sudo rmmod vivi
   sudo insmod ./vivi.ko

5. ls /dev/video*
6. xawtv -c /dev/videoX

如何才能知道vivi涉及到哪些系统调用
strace -o xawtv.log xawtv


二:UVC驱动框架:
UVC:usb video controll

system call: open   read   write

-------------------------------------------------

核心层:
        source: v4l2_dev.c
        struct: v4l2_device 
        operation:  1.分配  file_operations (v4l2_file_operations)
                    2.设置  file_operations (v4l2_file_operations)
                    2.注册  1.cdev_alloc
                            2.cdev->ops = v4l2_file_operations
                            3.cdev_add
----------------------------------------------------

硬件层:
        source: uvc_driver.c
        struct: video_device
        operation:  1.初始化 v4l2_driver_register
                    2.分配      video_device_alloc
                    3.设置   video_device
                    4.注册   video_register_device
----------------------------------------------------

如何写一个v4l2驱动:
    1.分配,设置,注册 v4l2_device
    2.分配 video_device
    3.设置 
            1. 将自己的video_device与v4l2核心层连接起来
                video_device->v4l2_dev = v4l2_device 
            2. 设置自己的video_device的fops操作函数
                video_device->fops       = xxx_fops
                video_device->ioctl_ops = xxx_ioctl 
            3. 设置自己的video_device的v4l2_ctrl_handler,并提交给核心层
                1.v4l2_ctrl_handler_init
                2.v4l2_ctrl_new_std 
                  v4l2_ctrl_new_custom
                3.v4l2_device->ctr_handler = v4l2_ctrl_handler

                
                
vivi.c 驱动框架分析:

---------------------------------------------------------------
核心层:
        source: v4l2_dev.c
        struct: v4l2_device
                        v4l2_ops(file_operations)
----------------------------------------------------------------
设备层:
        source: uvc_driver.c
        struct: video_device
-----------------------------------------------------------------
虚拟设备层: 
        source: vivi.c
        struct: vivi_dev
                        vivi_ops(v4l2_file_operations)
                        vivi_ioctl_ops(v4l2_ioctl_ops)
----------------------------------------------------------------


应用程序开启摄像头,驱动ioctl被调用流程:

//可以省略的ioctl
3.  ioctl(VIDIOC_G_FMT)
4.  for() ioctl(VIDIOC_ENUM_FMT)
5.  ioctl(VIDIOC_QUERYCAP)    // 列举性能
6.  ioctl(VIDIOC_G_INPUT)     // 获得当前使用输入源
7.  ioctl(VIDIOC_ENUMINPUT)   // 列举输入源
8.  ioctl(VIDIOC_QUERYCTRL)   // 查询属性,比如亮度、对比度
9.  ioctl(VIDIOC_QUERYCAP)
10. ioctl(VIDIOC_ENUMINPUT)


// 打开设备节点
1. fd = open
2. ioctl(fd,VIDIOC_QUERYCAP) 
  
// 获得设备容量
3. for() ioctl(VIDIOC_ENUMINPUT)     // 列举输入源,VIDIOC_ENUMINPUT/VIDIOC_G_INPUT/VIDIOC_S_INPUT不是必需的
4. for() ioctl(VIDIOC_ENUMSTD)       // 列举标准(制式), 不是必需的
5. for() ioctl(VIDIOC_ENUM_FMT)      // 列举格式
6. ioctl(VIDIOC_G_PARM)
7. for() ioctl(VIDIOC_QUERYCTRL)     // 查询属性(比如说亮度值最小值、最大值、默认值)

// 读取属性   
8.  ioctl(VIDIOC_G_STD)             // 获得当前使用的标准(制式), 不是必需的
9.  ioctl(VIDIOC_G_INPUT) 
10. ioctl(VIDIOC_G_CTRL )           // 获得当前属性, 比如亮度是多少
11. ioctl(VIDIOC_TRY_FMT)           // 试试能否支持某种格式
12. ioctl(VIDIOC_S_FMT)             // 设置摄像头使用某种格式

// 启动摄像头 streamon
13. ioctl(VIDIOC_REQBUFS )          // 请求系统分配缓冲区
14. for() ioctl(VIDIOC_QUERYBUF)    // 查询所分配的缓冲区   
          mmap()       
15. for() ioctl(VIDIOC_QBUF)        // 把缓冲区放入队列        
16. ioctl(VIDIOC_STREAMON)         // 启动摄像头

// 设置属性
17. for ()  ioctl(VIDIOC_S_CTRL)           // 设置属性
            ioctl(VIDIOC_S_INPUT )         // 设置输入源
            ioctl(VIDIOC_S_STD)            // 设置标准(制式), 不是必需的

// 不断地读取缓冲区数据 v4l2_nextframe > v4l2_waiton    
18. v4l2_queue_all
    v4l2_waiton    
        for ()
        {
            select(5, [4], NULL, NULL, {5, 0})      = 1 (in [4], left {4, 985979})
            ioctl(4, VIDIOC_DQBUF           // de-queue, 把缓冲区从队列中取出
                                            // 处理, 之以已经通过mmap获得了缓冲区的地址, 就可以直接访问数据        
            ioctl(4, VIDIOC_QBUF            // 把缓冲区放入队列
        }


xawtv的几大函数:
1. v4l2_open				//xawtv/libng/plugins/drv0-v4l2.c
2. v4l2_read_attr/v4l2_write_attr
3. v4l2_start_streaming
4. v4l2_nextframe/v4l2_waiton

摄像头驱动程序必需的11个ioctl:
    // 表示它是一个摄像头设备
	.vidioc_querycap      = vidioc_querycap,

    /* 用于列举、获得、测试、设置摄像头的数据的格式 */
	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap     = v
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值