⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 video-buf.c

📁 这是一个市场上常见电视卡的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (q->read_buf) {
		dprintk(1,"busy: pending read #2\n");
		return 1;
	}
	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
		if (NULL == q->bufs[i])
			continue;
		if (q->bufs[i]->map) {
			dprintk(1,"busy: buffer #%d mapped\n",i);
			return 1;
		}
		if (q->bufs[i]->state == STATE_QUEUED) {
			dprintk(1,"busy: buffer #%d queued\n",i);
			return 1;
		}
		if (q->bufs[i]->state == STATE_ACTIVE) {
			dprintk(1,"busy: buffer #%d avtive\n",i);
			return 1;
		}
	}
	return 0;
}

void
videobuf_queue_cancel(struct file *file, struct videobuf_queue *q)
{
	unsigned long flags;
	int i;

	/* remove queued buffers from list */
	spin_lock_irqsave(q->irqlock,flags);
	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
		if (NULL == q->bufs[i])
			continue;
		if (q->bufs[i]->state == STATE_QUEUED) {
			list_del(&q->bufs[i]->queue);
			q->bufs[i]->state = STATE_ERROR;
		}
	}
	spin_unlock_irqrestore(q->irqlock,flags);

	/* free all buffers + clear queue */
	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
		if (NULL == q->bufs[i])
			continue;
		q->ops->buf_release(file,q->bufs[i]);
	}
	INIT_LIST_HEAD(&q->stream);
}

/* --------------------------------------------------------------------- */

enum v4l2_field
videobuf_next_field(struct videobuf_queue *q)
{
	enum v4l2_field field = q->field;

	BUG_ON(V4L2_FIELD_ANY == field);

	if (V4L2_FIELD_ALTERNATE == field) {
		if (V4L2_FIELD_TOP == q->last) {
			field   = V4L2_FIELD_BOTTOM;
			q->last = V4L2_FIELD_BOTTOM;
		} else {
			field   = V4L2_FIELD_TOP;
			q->last = V4L2_FIELD_TOP;
		}
	}
	return field;
}

void
videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
		enum v4l2_buf_type type)
{
	b->index    = vb->i;
	b->type     = type;

	b->memory   = vb->memory;
	switch (b->memory) {
	case V4L2_MEMORY_MMAP:
		b->m.offset  = vb->boff;
		b->length    = vb->bsize;
		break;
	case V4L2_MEMORY_USERPTR:
		b->m.userptr = vb->baddr;
		b->length    = vb->bsize;
		break;
	case V4L2_MEMORY_OVERLAY:
		b->m.offset  = vb->boff;
		break;
	}

	b->flags    = 0;
	if (vb->map)
		b->flags |= V4L2_BUF_FLAG_MAPPED;

	switch (vb->state) {
	case STATE_PREPARED:
	case STATE_QUEUED:
	case STATE_ACTIVE:
		b->flags |= V4L2_BUF_FLAG_QUEUED;
		break;
	case STATE_DONE:
	case STATE_ERROR:
		b->flags |= V4L2_BUF_FLAG_DONE;
		break;
	case STATE_NEEDS_INIT:
	case STATE_IDLE:
		/* nothing */
		break;
	}

	b->field     = vb->field;
	b->timestamp = vb->ts;
	b->bytesused = vb->size;
	b->sequence  = vb->field_count >> 1;
}

int
videobuf_reqbufs(struct file *file, struct videobuf_queue *q,
		 struct v4l2_requestbuffers *req)
{
	unsigned int size,count;
	int retval;

	if (req->type != q->type)
		return -EINVAL;
	if (req->count < 1)
		return -EINVAL;
	if (req->memory != V4L2_MEMORY_MMAP     &&
	    req->memory != V4L2_MEMORY_USERPTR  &&
	    req->memory != V4L2_MEMORY_OVERLAY)
		return -EINVAL;

	down(&q->lock);
	count = req->count;
	if (count > VIDEO_MAX_FRAME)
		count = VIDEO_MAX_FRAME;
	size = 0;
	q->ops->buf_setup(file,&count,&size);
	size = PAGE_ALIGN(size);
	dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
		count, size, (count*size)>>PAGE_SHIFT);

	retval = videobuf_mmap_setup(file,q,count,size,req->memory);
	if (retval < 0)
		goto done;

	req->count = count;

 done:
	up(&q->lock);
	return retval;
}

int
videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
{
	if (unlikely(b->type != q->type))
		return -EINVAL;
	if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME))
		return -EINVAL;
	if (unlikely(NULL == q->bufs[b->index]))
		return -EINVAL;
	videobuf_status(b,q->bufs[b->index],q->type);
	return 0;
}

int
videobuf_qbuf(struct file *file, struct videobuf_queue *q,
	      struct v4l2_buffer *b)
{
	struct videobuf_buffer *buf;
	enum v4l2_field field;
	unsigned long flags;
	int retval;

	down(&q->lock);
	retval = -EBUSY;
	if (q->reading)
		goto done;
	retval = -EINVAL;
	if (b->type != q->type)
		goto done;
	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME)
		goto done;
	buf = q->bufs[b->index];
	if (NULL == buf)
		goto done;
	if (buf->memory != b->memory)
		goto done;
	if (buf->state == STATE_QUEUED ||
	    buf->state == STATE_ACTIVE)
		goto done;

	switch (b->memory) {
	case V4L2_MEMORY_MMAP:
		if (0 == buf->baddr)
			goto done;
		break;
	case V4L2_MEMORY_USERPTR:
		if (b->length < buf->bsize)
			goto done;
		buf->baddr = b->m.userptr;
		break;
	case V4L2_MEMORY_OVERLAY:
		buf->boff = b->m.offset;
		break;
	default:
		goto done;
	}

	field = videobuf_next_field(q);
	retval = q->ops->buf_prepare(file,buf,field);
	if (0 != retval)
		goto done;
	
	list_add_tail(&buf->stream,&q->stream);
	if (q->streaming) {
		spin_lock_irqsave(q->irqlock,flags);
		q->ops->buf_queue(file,buf);
		spin_unlock_irqrestore(q->irqlock,flags);
	}
	retval = 0;
	
 done:
	up(&q->lock);
	return retval;
}

int
videobuf_dqbuf(struct file *file, struct videobuf_queue *q,
	       struct v4l2_buffer *b)
{
	struct videobuf_buffer *buf;
	int retval;
	
	down(&q->lock);
	retval = -EBUSY;
	if (q->reading)
		goto done;
	retval = -EINVAL;
	if (b->type != q->type)
		goto done;
	if (list_empty(&q->stream))
		goto done;
	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
	retval = videobuf_waiton(buf, file->f_flags & O_NONBLOCK, 1);
	if (retval < 0)
		goto done;
	switch (buf->state) {
	case STATE_ERROR:
		retval = -EIO;
		/* fall through */
	case STATE_DONE:
		videobuf_dma_pci_sync(q->pci,&buf->dma);
		buf->state = STATE_IDLE;
		break;
	default:
		retval = -EINVAL;
		goto done;
	}
	list_del(&buf->stream);
	memset(b,0,sizeof(*b));
	videobuf_status(b,buf,q->type);

 done:
	up(&q->lock);
	return retval;
}

int videobuf_streamon(struct file *file, struct videobuf_queue *q)
{
	struct videobuf_buffer *buf;
	struct list_head *list;
	unsigned long flags;
	int retval;
	
	down(&q->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(list,&q->stream) {
		buf = list_entry(list, struct videobuf_buffer, stream);
		if (buf->state == STATE_PREPARED)
			q->ops->buf_queue(file,buf);
	}
	spin_unlock_irqrestore(q->irqlock,flags);

 done:
	up(&q->lock);
	return retval;
}

int videobuf_streamoff(struct file *file, struct videobuf_queue *q)
{
	int retval = -EINVAL;

	down(&q->lock);
	if (!q->streaming)
		goto done;
	videobuf_queue_cancel(file,q);
	q->streaming = 0;
	retval = 0;

 done:
	up(&q->lock);
	return retval;
}

static ssize_t
videobuf_read_zerocopy(struct file *file, struct videobuf_queue *q,
		       char *data, size_t count, loff_t *ppos)
{
	enum v4l2_field field;
	unsigned long flags;
        int retval;

        /* setup stuff */
	retval = -ENOMEM;
	q->read_buf = videobuf_alloc(q->msize);
	if (NULL == q->read_buf)
		goto done;

	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(file,q->read_buf,field);
	if (0 != retval)
		goto done;
	
        /* start capture & wait */
	spin_lock_irqsave(q->irqlock,flags);
	q->ops->buf_queue(file,q->read_buf);
	spin_unlock_irqrestore(q->irqlock,flags);
        retval = videobuf_waiton(q->read_buf,0,0);
        if (0 == retval) {
		videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
		if (STATE_ERROR == q->read_buf->state)
			retval = -EIO;
		else
			retval = q->read_buf->size;
	}

 done:
	/* cleanup */
	q->ops->buf_release(file,q->read_buf);
	kfree(q->read_buf);
	q->read_buf = NULL;
	return retval;
}

ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q,
			  char *data, size_t count, loff_t *ppos)
{
	enum v4l2_field field;
	unsigned long flags;
	unsigned size, nbufs, bytes;
	int retval;

	down(&q->lock);

	nbufs = 1; size = 0;
	q->ops->buf_setup(file,&nbufs,&size);
	if (NULL == q->read_buf  &&
	    count >= size        &&
	    !(file->f_flags & O_NONBLOCK)) {
		retval = videobuf_read_zerocopy(file,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->msize);
		if (NULL == q->read_buf)
			goto done;
		q->read_buf->memory = V4L2_MEMORY_USERPTR;
		field = videobuf_next_field(q);
		retval = q->ops->buf_prepare(file,q->read_buf,field);
		if (0 != retval)
			goto done;
		spin_lock_irqsave(q->irqlock,flags);
		q->ops->buf_queue(file,q->read_buf);
		spin_unlock_irqrestore(q->irqlock,flags);
		q->read_off = 0;
	}

	/* wait until capture is done */
        retval = videobuf_waiton(q->read_buf, file->f_flags & O_NONBLOCK, 1);
	if (0 != retval)
		goto done;
	videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);

	if (STATE_ERROR == q->read_buf->state) {
		/* catch I/O errors */
		q->ops->buf_release(file,q->read_buf);
		kfree(q->read_buf);
		q->read_buf = NULL;
		retval = -EIO;
		goto done;
	}

	/* copy to userspace */
	bytes = count;
	if (bytes > q->read_buf->size - q->read_off)
		bytes = q->read_buf->size - q->read_off;
	retval = -EFAULT;
	if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes))
		goto done;

	retval = bytes;
	q->read_off += bytes;
	if (q->read_off == q->read_buf->size) {
		/* all data copied, cleanup */
		q->ops->buf_release(file,q->read_buf);
		kfree(q->read_buf);
		q->read_buf = NULL;
	}

⌨️ 快捷键说明

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