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