videobuf-core.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,138 行 · 第 1/2 页

C
1,138
字号
	wake_up_interruptible_sync(&q->wait); done:	mutex_unlock(&q->vb_lock);	if (b->memory == V4L2_MEMORY_MMAP)		up_read(&current->mm->mmap_sem);	return retval;}/* Locking: Caller holds q->vb_lock */static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock){	int retval;checks:	if (!q->streaming) {		dprintk(1, "next_buffer: Not streaming\n");		retval = -EINVAL;		goto done;	}	if (list_empty(&q->stream)) {		if (noblock) {			retval = -EAGAIN;			dprintk(2, "next_buffer: no buffers to dequeue\n");			goto done;		} else {			dprintk(2, "next_buffer: waiting on buffer\n");			/* Drop lock to avoid deadlock with qbuf */			mutex_unlock(&q->vb_lock);			/* Checking list_empty and streaming is safe without			 * locks because we goto checks to validate while			 * holding locks before proceeding */			retval = wait_event_interruptible(q->wait,				!list_empty(&q->stream) || !q->streaming);			mutex_lock(&q->vb_lock);			if (retval)				goto done;			goto checks;		}	}	retval = 0;done:	return retval;}/* Locking: Caller holds q->vb_lock */static int stream_next_buffer(struct videobuf_queue *q,			struct videobuf_buffer **vb, int nonblocking){	int retval;	struct videobuf_buffer *buf = NULL;	retval = stream_next_buffer_check_queue(q, nonblocking);	if (retval)		goto done;	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);	retval = videobuf_waiton(buf, nonblocking, 1);	if (retval < 0)		goto done;	*vb = buf;done:	return retval;}int videobuf_dqbuf(struct videobuf_queue *q,	       struct v4l2_buffer *b, int nonblocking){	struct videobuf_buffer *buf = NULL;	int retval;	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);	mutex_lock(&q->vb_lock);	retval = stream_next_buffer(q, &buf, nonblocking);	if (retval < 0) {		dprintk(1, "dqbuf: next_buffer error: %i\n", retval);		goto done;	}	switch (buf->state) {	case VIDEOBUF_ERROR:		dprintk(1, "dqbuf: state is error\n");		retval = -EIO;		CALL(q, sync, q, buf);		buf->state = VIDEOBUF_IDLE;		break;	case VIDEOBUF_DONE:		dprintk(1, "dqbuf: state is done\n");		CALL(q, sync, q, buf);		buf->state = VIDEOBUF_IDLE;		break;	default:		dprintk(1, "dqbuf: state invalid\n");		retval = -EINVAL;		goto done;	}	list_del(&buf->stream);	memset(b, 0, sizeof(*b));	videobuf_status(q, b, buf, q->type); done:	mutex_unlock(&q->vb_lock);	return retval;}int videobuf_streamon(struct videobuf_queue *q){	struct videobuf_buffer *buf;	unsigned long flags = 0;	int retval;	mutex_lock(&q->vb_lock);	retval = -EBUSY;	if (q->reading)		goto done;	retval = 0;	if (q->streaming)		goto done;	q->streaming = 1;	spin_lock_irqsave(q->irqlock, flags);	list_for_each_entry(buf, &q->stream, stream)		if (buf->state == VIDEOBUF_PREPARED)			q->ops->buf_queue(q, buf);	spin_unlock_irqrestore(q->irqlock, flags);	wake_up_interruptible_sync(&q->wait); done:	mutex_unlock(&q->vb_lock);	return retval;}/* Locking: Caller holds q->vb_lock */static int __videobuf_streamoff(struct videobuf_queue *q){	if (!q->streaming)		return -EINVAL;	videobuf_queue_cancel(q);	return 0;}int videobuf_streamoff(struct videobuf_queue *q){	int retval;	mutex_lock(&q->vb_lock);	retval = __videobuf_streamoff(q);	mutex_unlock(&q->vb_lock);	return retval;}/* Locking: Caller holds q->vb_lock */static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,				      char __user *data,				      size_t count, loff_t *ppos){	enum v4l2_field field;	unsigned long flags = 0;	int retval;	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);	/* setup stuff */	q->read_buf = videobuf_alloc(q);	if (NULL == q->read_buf)		return -ENOMEM;	q->read_buf->memory = V4L2_MEMORY_USERPTR;	q->read_buf->baddr  = (unsigned long)data;	q->read_buf->bsize  = count;	field = videobuf_next_field(q);	retval = q->ops->buf_prepare(q, q->read_buf, field);	if (0 != retval)		goto done;	/* start capture & wait */	spin_lock_irqsave(q->irqlock, flags);	q->ops->buf_queue(q, q->read_buf);	spin_unlock_irqrestore(q->irqlock, flags);	retval = videobuf_waiton(q->read_buf, 0, 0);	if (0 == retval) {		CALL(q, sync, q, q->read_buf);		if (VIDEOBUF_ERROR == q->read_buf->state)			retval = -EIO;		else			retval = q->read_buf->size;	} done:	/* cleanup */	q->ops->buf_release(q, q->read_buf);	kfree(q->read_buf);	q->read_buf = NULL;	return retval;}ssize_t videobuf_read_one(struct videobuf_queue *q,			  char __user *data, size_t count, loff_t *ppos,			  int nonblocking){	enum v4l2_field field;	unsigned long flags = 0;	unsigned size = 0, nbufs = 1;	int retval;	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);	mutex_lock(&q->vb_lock);	q->ops->buf_setup(q, &nbufs, &size);	if (NULL == q->read_buf  &&	    count >= size        &&	    !nonblocking) {		retval = videobuf_read_zerocopy(q, data, count, ppos);		if (retval >= 0  ||  retval == -EIO)			/* ok, all done */			goto done;		/* fallback to kernel bounce buffer on failures */	}	if (NULL == q->read_buf) {		/* need to capture a new frame */		retval = -ENOMEM;		q->read_buf = videobuf_alloc(q);		dprintk(1, "video alloc=0x%p\n", q->read_buf);		if (NULL == q->read_buf)			goto done;		q->read_buf->memory = V4L2_MEMORY_USERPTR;		q->read_buf->bsize = count; /* preferred size */		field = videobuf_next_field(q);		retval = q->ops->buf_prepare(q, q->read_buf, field);		if (0 != retval) {			kfree(q->read_buf);			q->read_buf = NULL;			goto done;		}		spin_lock_irqsave(q->irqlock, flags);		q->ops->buf_queue(q, q->read_buf);		spin_unlock_irqrestore(q->irqlock, flags);		q->read_off = 0;	}	/* wait until capture is done */	retval = videobuf_waiton(q->read_buf, nonblocking, 1);	if (0 != retval)		goto done;	CALL(q, sync, q, q->read_buf);	if (VIDEOBUF_ERROR == q->read_buf->state) {		/* catch I/O errors */		q->ops->buf_release(q, q->read_buf);		kfree(q->read_buf);		q->read_buf = NULL;		retval = -EIO;		goto done;	}	/* Copy to userspace */	retval = CALL(q, video_copy_to_user, q, data, count, nonblocking);	if (retval < 0)		goto done;	q->read_off += retval;	if (q->read_off == q->read_buf->size) {		/* all data copied, cleanup */		q->ops->buf_release(q, q->read_buf);		kfree(q->read_buf);		q->read_buf = NULL;	} done:	mutex_unlock(&q->vb_lock);	return retval;}/* Locking: Caller holds q->vb_lock */static int __videobuf_read_start(struct videobuf_queue *q){	enum v4l2_field field;	unsigned long flags = 0;	unsigned int count = 0, size = 0;	int err, i;	q->ops->buf_setup(q, &count, &size);	if (count < 2)		count = 2;	if (count > VIDEO_MAX_FRAME)		count = VIDEO_MAX_FRAME;	size = PAGE_ALIGN(size);	err = __videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR);	if (err < 0)		return err;	count = err;	for (i = 0; i < count; i++) {		field = videobuf_next_field(q);		err = q->ops->buf_prepare(q, q->bufs[i], field);		if (err)			return err;		list_add_tail(&q->bufs[i]->stream, &q->stream);	}	spin_lock_irqsave(q->irqlock, flags);	for (i = 0; i < count; i++)		q->ops->buf_queue(q, q->bufs[i]);	spin_unlock_irqrestore(q->irqlock, flags);	q->reading = 1;	return 0;}static void __videobuf_read_stop(struct videobuf_queue *q){	int i;	videobuf_queue_cancel(q);	__videobuf_mmap_free(q);	INIT_LIST_HEAD(&q->stream);	for (i = 0; i < VIDEO_MAX_FRAME; i++) {		if (NULL == q->bufs[i])			continue;		kfree(q->bufs[i]);		q->bufs[i] = NULL;	}	q->read_buf = NULL;}int videobuf_read_start(struct videobuf_queue *q){	int rc;	mutex_lock(&q->vb_lock);	rc = __videobuf_read_start(q);	mutex_unlock(&q->vb_lock);	return rc;}void videobuf_read_stop(struct videobuf_queue *q){	mutex_lock(&q->vb_lock);	__videobuf_read_stop(q);	mutex_unlock(&q->vb_lock);}void videobuf_stop(struct videobuf_queue *q){	mutex_lock(&q->vb_lock);	if (q->streaming)		__videobuf_streamoff(q);	if (q->reading)		__videobuf_read_stop(q);	mutex_unlock(&q->vb_lock);}ssize_t videobuf_read_stream(struct videobuf_queue *q,			     char __user *data, size_t count, loff_t *ppos,			     int vbihack, int nonblocking){	int rc, retval;	unsigned long flags = 0;	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);	dprintk(2, "%s\n", __func__);	mutex_lock(&q->vb_lock);	retval = -EBUSY;	if (q->streaming)		goto done;	if (!q->reading) {		retval = __videobuf_read_start(q);		if (retval < 0)			goto done;	}	retval = 0;	while (count > 0) {		/* get / wait for data */		if (NULL == q->read_buf) {			q->read_buf = list_entry(q->stream.next,						 struct videobuf_buffer,						 stream);			list_del(&q->read_buf->stream);			q->read_off = 0;		}		rc = videobuf_waiton(q->read_buf, nonblocking, 1);		if (rc < 0) {			if (0 == retval)				retval = rc;			break;		}		if (q->read_buf->state == VIDEOBUF_DONE) {			rc = CALL(q, copy_stream, q, data + retval, count,					retval, vbihack, nonblocking);			if (rc < 0) {				retval = rc;				break;			}			retval      += rc;			count       -= rc;			q->read_off += rc;		} else {			/* some error */			q->read_off = q->read_buf->size;			if (0 == retval)				retval = -EIO;		}		/* requeue buffer when done with copying */		if (q->read_off == q->read_buf->size) {			list_add_tail(&q->read_buf->stream,				      &q->stream);			spin_lock_irqsave(q->irqlock, flags);			q->ops->buf_queue(q, q->read_buf);			spin_unlock_irqrestore(q->irqlock, flags);			q->read_buf = NULL;		}		if (retval < 0)			break;	} done:	mutex_unlock(&q->vb_lock);	return retval;}unsigned int videobuf_poll_stream(struct file *file,				  struct videobuf_queue *q,				  poll_table *wait){	struct videobuf_buffer *buf = NULL;	unsigned int rc = 0;	mutex_lock(&q->vb_lock);	if (q->streaming) {		if (!list_empty(&q->stream))			buf = list_entry(q->stream.next,					 struct videobuf_buffer, stream);	} else {		if (!q->reading)			__videobuf_read_start(q);		if (!q->reading) {			rc = POLLERR;		} else if (NULL == q->read_buf) {			q->read_buf = list_entry(q->stream.next,						 struct videobuf_buffer,						 stream);			list_del(&q->read_buf->stream);			q->read_off = 0;		}		buf = q->read_buf;	}	if (!buf)		rc = POLLERR;	if (0 == rc) {		poll_wait(file, &buf->done, wait);		if (buf->state == VIDEOBUF_DONE ||		    buf->state == VIDEOBUF_ERROR)			rc = POLLIN|POLLRDNORM;	}	mutex_unlock(&q->vb_lock);	return rc;}int videobuf_mmap_mapper(struct videobuf_queue *q,			 struct vm_area_struct *vma){	int retval;	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);	mutex_lock(&q->vb_lock);	retval = CALL(q, mmap_mapper, q, vma);	q->is_mmapped = 1;	mutex_unlock(&q->vb_lock);	return retval;}#ifdef CONFIG_VIDEO_V4L1_COMPATint videobuf_cgmbuf(struct videobuf_queue *q,		    struct video_mbuf *mbuf, int count){	struct v4l2_requestbuffers req;	int rc, i;	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);	memset(&req, 0, sizeof(req));	req.type   = q->type;	req.count  = count;	req.memory = V4L2_MEMORY_MMAP;	rc = videobuf_reqbufs(q, &req);	if (rc < 0)		return rc;	mbuf->frames = req.count;	mbuf->size   = 0;	for (i = 0; i < mbuf->frames; i++) {		mbuf->offsets[i]  = q->bufs[i]->boff;		mbuf->size       += q->bufs[i]->bsize;	}	return 0;}EXPORT_SYMBOL_GPL(videobuf_cgmbuf);#endif/* --------------------------------------------------------------------- */EXPORT_SYMBOL_GPL(videobuf_waiton);EXPORT_SYMBOL_GPL(videobuf_iolock);EXPORT_SYMBOL_GPL(videobuf_alloc);EXPORT_SYMBOL_GPL(videobuf_queue_core_init);EXPORT_SYMBOL_GPL(videobuf_queue_cancel);EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);EXPORT_SYMBOL_GPL(videobuf_next_field);EXPORT_SYMBOL_GPL(videobuf_reqbufs);EXPORT_SYMBOL_GPL(videobuf_querybuf);EXPORT_SYMBOL_GPL(videobuf_qbuf);EXPORT_SYMBOL_GPL(videobuf_dqbuf);EXPORT_SYMBOL_GPL(videobuf_streamon);EXPORT_SYMBOL_GPL(videobuf_streamoff);EXPORT_SYMBOL_GPL(videobuf_read_start);EXPORT_SYMBOL_GPL(videobuf_read_stop);EXPORT_SYMBOL_GPL(videobuf_stop);EXPORT_SYMBOL_GPL(videobuf_read_stream);EXPORT_SYMBOL_GPL(videobuf_read_one);EXPORT_SYMBOL_GPL(videobuf_poll_stream);EXPORT_SYMBOL_GPL(__videobuf_mmap_setup);EXPORT_SYMBOL_GPL(videobuf_mmap_setup);EXPORT_SYMBOL_GPL(videobuf_mmap_free);EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?