从cimutils到内核-(4)VIDIOC_STREAMON(开始采集数据)

应用层:

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;

}

猜你喜欢

转载自blog.csdn.net/sinat_37817094/article/details/83815737