从应用调用vivi驱动分析v4l2 -- 运行设备(VIDIOC_STREAMON)_v4l2 vb

vidioc_streamon

-> vb2_streamon

-> vb2_core_streamon


static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
	struct vivi_dev *dev = video_drvdata(file);
	return vb2_streamon(&dev->vb_vidq, i);
}

int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
{
	return vb2_core_streamon(q, type);
}

int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
{
	int ret;

	if (type != q->type) {
		dprintk(1, "invalid stream type\n");
		return -EINVAL;
	}


        /* 
         * 如果已经启动了,则这里不再继续执行 
         * start_streaming_called 不用考虑???
         * 在qbuf的时候有2种情况
         * 1. q->start_streaming_called = 1
         * 2. q->start_streaming_called = 0, q->streaming = 1
         * 情况1,说明其他应用已经正常抓图了,也就是底层驱动start_streaming执行没问题
         * 情况2,说明底层驱动start_streaming执行失败了,这时候会继续执行stream_on
         *       只有stream_on没有问题,qbuf才会返回正常值给应用
         *       所以需要应用把关,如果返回值错了,就不要向下走了
         * 所以这里也可以知道 如果q->streaming = 1
         * 那么q->start_streaming_called = 1
         * 这里就可以直接返回了
         */


	if (q->streaming) {
		dprintk(3, "already streaming\n");
		return 0;
	}

	if (!q->num_buffers) {
		dprintk(1, "no buffers have been allocated\n");
		return -EINVAL;
	}

	if (q->num_buffers < q->min_buffers_needed) {
		dprintk(1, "need at least %u allocated buffers\n",
				q->min_buffers_needed);
		return -EINVAL;
	}

        

	/*
	 * Tell driver to start streaming provided sufficient buffers
	 * are available.
	 */


        /*
         * 这个if语句上一篇文章提了一句
         * 就是缓冲区不够,无法启动
         * 导致 q->streaming = 1 
         * start_streaming_called = 0
         * 
         */

	if (q->queued_count >= q->min_buffers_needed) {

            
                /*
                 * 这里牵扯到使用media
                 * 因为vivi没有使用,所以这里暂时跳过
                 * 后面再分析
                 */


		ret = v4l_vb2q_enable_media_source(q);
		if (ret)
			return ret;
		ret = vb2_start_streaming(q);
		if (ret)
			return ret;
	}


        /*
         * 执行了stream_on的标志
         */

	q->streaming = 1;
	return 0;
}

vidioc_streamon

-> vb2_streamon

-> vb2_core_streamon

-> vb2_start_streaming


static int vb2_start_streaming(struct vb2_queue *q)
{
	struct vb2_buffer *vb;
	int ret;

	/*
	 * If any buffers were queued before streamon,
	 * we can now pass them to driver for processing.
	 */


        /*
         * 之前分析过__enqueue_in_driver
         * 当时的情况是在本次应用QBUF的时候,发现操作的video节点被其他的应用打开
         * 且正在抓图
         * 这种情况下__enqueue_in_driver会被调用
         * 现在看来在stream_on的时候,还会被再次调用
         * 主意这里不仅仅是当前应用的buffer,还有其他操作该video节点应用的buffer
         * 底层驱动是不是要判断一下,防止被多次添加
         * 另外q->owned_by_drv_count的值一直在增加
         * 对于owned_by_drv_count最后是怎么判断?
         *       下面失败的时候,会dec,所以不用担心
         * 如果是ioctl(STREAM_ON)能走到这里,说明只有当前这一个应用在操作节点
         */


	list_for_each_entry(vb, &q->queued_list, queued_entry)
		__enqueue_in_driver(vb);

	/* Tell the driver to start streaming */



        /*
         * start_streaming_called
         * 记录的是底层驱动start_streaming被调用
         */


	q->start_streaming_called = 1;
	ret = call_qop(q, start_streaming, q,
		       atomic_read(&q->owned_by_drv_count));
	if (!ret)
		return 0;


        /*
         * 调用失败置0
         */


	q->start_streaming_called = 0;

	dprintk(1, "driver refused to start streaming\n");
	/*
	 * If you see this warning, then the driver isn't cleaning up properly
	 * after a failed start_streaming(). See the start_streaming()
	 * documentation in videobuf2-core.h for more information how buffers
	 * should be returned to vb2 in start_streaming().
	 */
	if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
		unsigned i;

		/*
		 * Forcefully reclaim buffers if the driver did not
		 * correctly return them to vb2.
		 */
		for (i = 0; i < q->num_buffers; ++i) {
			vb = q->bufs[i];
			if (vb->state == VB2_BUF_STATE_ACTIVE)
                                

                                /*
                                 * 这里面会把owned_by_drv_count进行减操作
                                 */
				vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
		}
		/* Must be zero now */
		WARN_ON(atomic_read(&q->owned_by_drv_count));
	}
	/*
	 * If done_list is not empty, then start_streaming() didn't call
	 * vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED) but STATE_ERROR or
	 * STATE_DONE.
	 */
	WARN_ON(!list_empty(&q->done_list));
	return ret;
}

vidioc_streamon

-> vb2_streamon

-> vb2_core_streamon

-> vb2_start_streaming

-> call_qop(start_streaming    —  start_streaming


static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
	struct vivi_dev *dev = vb2_get_drv_priv(vq);
	dprintk(dev, 1, "%s\n", __func__);
	return vivi_start_generating(dev);
}

static int vivi_start_generating(struct vivi_dev *dev)
{
	struct vivi_dmaqueue *dma_q = &dev->vidq;

	dprintk(dev, 1, "%s\n", __func__);

	/* Resets frame counters */
	dev->ms = 0;
	dev->mv_count = 0;
	dev->jiffies = jiffies;

	dma_q->frame = 0;
	dma_q->ini_jiffies = jiffies;
	dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);

	if (IS_ERR(dma_q->kthread)) {
		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
		return PTR_ERR(dma_q->kthread);
	}
	/* Wakes thread */
	wake_up_interruptible(&dma_q->wq);

	dprintk(dev, 1, "returning from %s\n", __func__);
	return 0;
}

static void vivi_thread_tick(struct vivi_dev *dev)
{
	struct vivi_dmaqueue *dma_q = &dev->vidq;
	struct vivi_buffer *buf;
	unsigned long flags = 0;

	dprintk(dev, 1, "Thread tick\n");

	spin_lock_irqsave(&dev->slock, flags);
	if (list_empty(&dma_q->active)) {
		dprintk(dev, 1, "No active queue to serve\n");
		goto unlock;
	}


        /*
         * 取出active上的每一个buffer
         */


	buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
	list_del(&buf->list);

	buf->vb.timestamp = ktime_get_ns();

	/* Fill buffer */



        /*
         * 这里相当于填充帧数据
         */


	vivi_fillbuff(dev, buf);
	dprintk(dev, 1, "filled buffer %p\n", buf);

        
        /*
         * 这里最重要
         */

	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
	dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.index);
unlock:
	spin_unlock_irqrestore(&dev->slock, flags);
}


vidioc_streamon

-> vb2_streamon

-> vb2_core_streamon

-> vb2_start_streaming

-> call_qop(start_streaming    —  start_streaming

-> vb2_buffer_done

void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
{
	struct vb2_queue *q = vb->vb2_queue;
	unsigned long flags;
	unsigned int plane;

	if (WARN_ON(vb->state != VB2_BUF_STATE_ACTIVE))
		return;

	if (WARN_ON(state != VB2_BUF_STATE_DONE &&
		    state != VB2_BUF_STATE_ERROR &&
		    state != VB2_BUF_STATE_QUEUED &&
		    state != VB2_BUF_STATE_REQUEUEING))
		state = VB2_BUF_STATE_ERROR;

#ifdef CONFIG_VIDEO_ADV_DEBUG
	/*
	 * Although this is not a callback, it still does have to balance
	 * with the buf_queue op. So update this counter manually.
	 */
	vb->cnt_buf_done++;
#endif
	dprintk(4, "done processing on buffer %d, state: %d\n",
			vb->index, state);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值