应用层:
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
errno_exit("VIDIOC_STREAMON");
break;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
内核:
(1)
drivers/media/v4l2-core/v4l2-ioctl.c
IOCTL_INFO_FNC(VIDIOC_STREAMON, v4l_streamon, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE)
static int v4l_streamon(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
return ops->vidioc_streamon(file, fh, *(unsigned int *)arg);
}
(2)
drivers/media/platform/soc_camera/soc_camera.c
static int soc_camera_streamon(struct file *file, void *priv,
enum v4l2_buf_type i)
{
struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
WARN_ON(priv != file->private_data);
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (icd->streamer != file)
return -EBUSY;
/* This calls buf_queue from host driver's videobuf_queue_ops */
if (ici->ops->init_videobuf)
ret = videobuf_streamon(&icd->vb_vidq);
else
ret = vb2_streamon(&icd->vb2_vidq, i);
if (!ret)
v4l2_subdev_call(sd, video, s_stream, 1);
//调用我们的sensor 驱动,开始视频采集
drivers/media/i2c/soc_camera/gc2155.c
static struct v4l2_subdev_ops gc2155_subdev_ops = {
.core = &gc2155_subdev_core_ops,
.video = &gc2155_subdev_video_ops,
};
static struct v4l2_subdev_video_ops gc2155_subdev_video_ops = {
.s_stream = gc2155_s_stream
}
return ret;
}
(3)
int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
{
/*
* If any buffers were queued before streamon,
* we can now pass them to driver for processing.
*/
list_for_each_entry(vb, &q->queued_list, queued_entry)
__enqueue_in_driver(vb); //将queued_list里面的buffer添加到我们驱动维护的链表video_buffer_list
ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
}
/**
* __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing //把buffer传给驱动处理
*/
static void __enqueue_in_driver(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
unsigned int plane;
vb->state = VB2_BUF_STATE_ACTIVE;
atomic_inc(&q->queued_count);
/* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane)
call_memop(q, prepare, vb->planes[plane].mem_priv);
q->ops->buf_queue(vb); //调进我们的控制器驱动
}
drivers/media/platform/soc_camera/jz_camera_v13.c
static void jz_buffer_queue(struct vb2_buffer *vb2)
{
list_add_tail(&buf->list, &pcdev->video_buffer_list); //将queued_list里面的buffer添加到我们驱动维护的链表video_buffer_list
if (pcdev->active == NULL) {
pcdev->active = buf; //给active赋值
}
}
(4)
drivers/media/platform/soc_camera/jz_camera_v13.c
static int jz_start_streaming(struct vb2_queue *q, unsigned int count)
{
list_for_each_entry_safe(buf, node, &pcdev->video_buffer_list, list) {
ret = jz_init_dma(&buf->vb2); //告诉dma buffer[0]和buffer[1]的地址,既是告诉他去哪里搬数据
if(ret) {
dev_err(icd->parent,"%s:DMA initialization for Y/RGB failed\n", __func__);
return ret;
}
}
//遍历video_buffer_list链表,把每个dma描述符加入链表,dma描述符结构体里面的一个buf地址成员赋值为我们申请的buffer[0] buffer[1]的开始地址 维护dma链表
enable_irq(pcdev->irq);
jz_dma_start(pcdev); //操作控制器cim的寄存器,开始dma
pcdev->dma_stopped = 0;
pcdev->start_streaming_called = 1;
}