videobuf-core.c

来自「linux 内核源代码」· C语言 代码 · 共 1,088 行 · 第 1/2 页

C
1,088
字号
		goto done;	}	list_add_tail(&buf->stream,&q->stream);	if (q->streaming) {		if (q->irqlock)			spin_lock_irqsave(q->irqlock,flags);		q->ops->buf_queue(q,buf);		if (q->irqlock)			spin_unlock_irqrestore(q->irqlock,flags);	}	dprintk(1,"qbuf: succeded\n");	retval = 0; done:	mutex_unlock(&q->lock);	if (b->memory == V4L2_MEMORY_MMAP)		up_read(&current->mm->mmap_sem);	return retval;}int videobuf_dqbuf(struct videobuf_queue *q,	       struct v4l2_buffer *b, int nonblocking){	struct videobuf_buffer *buf;	int retval;	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);	mutex_lock(&q->lock);	retval = -EBUSY;	if (q->reading) {		dprintk(1,"dqbuf: Reading running...\n");		goto done;	}	retval = -EINVAL;	if (b->type != q->type) {		dprintk(1,"dqbuf: Wrong type.\n");		goto done;	}	if (list_empty(&q->stream)) {		dprintk(1,"dqbuf: stream running\n");		goto done;	}	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);	retval = videobuf_waiton(buf, nonblocking, 1);	if (retval < 0) {		dprintk(1,"dqbuf: waiton returned %d\n",retval);		goto done;	}	switch (buf->state) {	case STATE_ERROR:		dprintk(1,"dqbuf: state is error\n");		retval = -EIO;		CALL(q,sync,q, buf);		buf->state = STATE_IDLE;		break;	case STATE_DONE:		dprintk(1,"dqbuf: state is done\n");		CALL(q,sync,q, buf);		buf->state = STATE_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->lock);	return retval;}int videobuf_streamon(struct videobuf_queue *q){	struct videobuf_buffer *buf;	unsigned long flags=0;	int retval;	mutex_lock(&q->lock);	retval = -EBUSY;	if (q->reading)		goto done;	retval = 0;	if (q->streaming)		goto done;	q->streaming = 1;	if (q->irqlock)		spin_lock_irqsave(q->irqlock,flags);	list_for_each_entry(buf, &q->stream, stream)		if (buf->state == STATE_PREPARED)			q->ops->buf_queue(q,buf);	if (q->irqlock)		spin_unlock_irqrestore(q->irqlock,flags); done:	mutex_unlock(&q->lock);	return retval;}/* Locking: Caller holds q->lock */static int __videobuf_streamoff(struct videobuf_queue *q){	if (!q->streaming)		return -EINVAL;	videobuf_queue_cancel(q);	q->streaming = 0;	return 0;}int videobuf_streamoff(struct videobuf_queue *q){	int retval;	mutex_lock(&q->lock);	retval = __videobuf_streamoff(q);	mutex_unlock(&q->lock);	return retval;}/* Locking: Caller holds q->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 */	if (q->irqlock)		spin_lock_irqsave(q->irqlock,flags);	q->ops->buf_queue(q,q->read_buf);	if (q->irqlock)		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 (STATE_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, nbufs;	int retval;	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);	mutex_lock(&q->lock);	nbufs = 1; size = 0;	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;		}		if (q->irqlock)			spin_lock_irqsave(q->irqlock,flags);		q->ops->buf_queue(q,q->read_buf);		if (q->irqlock)			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 (STATE_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->lock);	return retval;}/* Locking: Caller holds q->lock */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);	}	if (q->irqlock)		spin_lock_irqsave(q->irqlock,flags);	for (i = 0; i < count; i++)		q->ops->buf_queue(q,q->bufs[i]);	if (q->irqlock)		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;	q->reading  = 0;	}int videobuf_read_start(struct videobuf_queue *q){	int rc;	mutex_lock(&q->lock);	rc = __videobuf_read_start(q);	mutex_unlock(&q->lock);	return rc;}void videobuf_read_stop(struct videobuf_queue *q){	mutex_lock(&q->lock);	__videobuf_read_stop(q);	mutex_unlock(&q->lock);}void videobuf_stop(struct videobuf_queue *q){	mutex_lock(&q->lock);	if (q->streaming)		__videobuf_streamoff(q);	if (q->reading)		__videobuf_read_stop(q);	mutex_unlock(&q->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",__FUNCTION__);	mutex_lock(&q->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 == STATE_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);			if (q->irqlock)				spin_lock_irqsave(q->irqlock,flags);			q->ops->buf_queue(q,q->read_buf);			if (q->irqlock)				spin_unlock_irqrestore(q->irqlock,flags);			q->read_buf = NULL;		}		if (retval < 0)			break;	} done:	mutex_unlock(&q->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->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 == STATE_DONE ||		    buf->state == STATE_ERROR)			rc = POLLIN|POLLRDNORM;	}	mutex_unlock(&q->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->lock);	retval=CALL(q,mmap_mapper,q,vma);	mutex_unlock(&q->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_free);EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);/* * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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