1. 总览
如下图是vivi Capture Device的主要组件:

- v4l2_device是描述整个设备的结构,而vivi_dev是v4l2_device扩展而来的结构体。
- video_device是描述设备节点的结构,如“/dev/video0”。
- vb2_queue是vivi_device使用的buffer队列,其成员为vb2_buffer。
- cdev是video_device对外的接口设备,这是一个字符设备。
2. vivi_init()
vivi_init()初始化设备vivi_device,同时初始化设备节点video_device。

- 首先创建vivi_device实例,然后调用v4l2_device_register()注册该实例为v4l2设备。
- 调用vb2_queue_init()初始化vivi_device的成员vb2_queue vb_vidq。
- video_set_drvdata()将video_device与vivi_dev关联起来:video_device -> device -> device_private -> vivi_dev。
- 这里指定video_device.fops = vivi_fops, video_device.ioctl_ops = vivi_ioctl_ops。

- __video_register_device()注册video_device()。它首先调用devnode_find()找到合适的设备号,接着调用cdev_alloc()给video_device分配cdev实例,并调用cdev_add()对外暴露,这样应用层就能发现/dev/video0了。
- 这里给指定cdev.ops = v4l2_ops;

- 最后device_regiser()注册video_device。
3. open()
应用层调用open(“/dev/video0”)时,cdev.ops.open()(也就是v4l2_open())被调用。它将请求转交给video_device.fops(也就是v4l2_fh_open())处理。cdev就是video_device对外的接口层,实际上其他的请求也是类似转发处理的。

v4l2_fh_open()创建v4l2_fh管理与file有关的事务。

4. Ioctl (QUERYCAP)
与open()类似,应用层调用ioctl()时,v4l2_ioctl()和video_ioctl2()依次被调用。在__video_do_ioctl()中根据请求类型,将请求派发给vivi_ioctl_ops中相应的处理函数。对于QUERYCAP,就是vidioc_querycap()。
其他的请求,如REQBUFS派发给vb2_ioctl_reqbufs,EXPBUF派发给vb2_ioctl_expbuf等。这些与vb2_queue有关的函数操作video_device.queue,也就是vivi_dev.vb_vidq。

5. Ioctl(STREAMON)和vivi_thread()
应用层调用ioctl(STREAMON)时,start_streaming()被调用,这将启动一个新的线程vivi_thread。

vivi_thread在一个循环中调用vivi_sleep()。在vivi_thread_tick()中,vivi_fillbuff()填充buffer,然后将buffer加入video_deivce的vb_queue。

相关链接
sunxi 源代码分析(一) - vivi Camera Device Driver
sunxi 源代码分析(二) - DMABUF Driver
sunxi 源代码分析(三) - VDecoder
网友评论