1. 程式人生 > >從cimutils到核心-(4)VIDIOC_STREAMON(開始採集資料)

從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;

}