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

📄 video-buf.c

📁 dvb数字电视实现参考 dvb数字电视实现参考
💻 C
📖 第 1 页 / 共 2 页
字号:
		q->ops->buf_queue(file,buf);		spin_unlock_irqrestore(q->irqlock,flags);	}	retval = 0;	 done:	up(&q->lock);	return retval;}intvideobuf_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_tvideobuf_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;	} done:	up(&q->lock);	return retval;}int videobuf_read_start(struct file *file, struct videobuf_queue *q){	enum v4l2_field field;	unsigned long flags;	int count = 0, size = 0;	int err, i;	q->ops->buf_setup(file,&count,&size);	if (count < 2)		count = 2;	if (count > VIDEO_MAX_FRAME)		count = VIDEO_MAX_FRAME;	size = PAGE_ALIGN(size);	err = videobuf_mmap_setup(file, q, count, size, V4L2_MEMORY_USERPTR);	if (err)		return err;	for (i = 0; i < count; i++) {		field = videobuf_next_field(q);		err = q->ops->buf_prepare(file,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(file,q->bufs[i]);	spin_unlock_irqrestore(q->irqlock,flags);	q->reading = 1;	return 0;}void videobuf_read_stop(struct file *file, struct videobuf_queue *q){	int i;		videobuf_queue_cancel(file,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;}ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q,			     char *data, size_t count, loff_t *ppos,			     int vbihack){	unsigned int *fc, bytes;	int err, retval;	unsigned long flags;		down(&q->lock);	retval = -EBUSY;	if (q->streaming)		goto done;	if (!q->reading) {		retval = videobuf_read_start(file,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;		}		err = videobuf_waiton(q->read_buf,				      file->f_flags & O_NONBLOCK,1);		if (err < 0) {			if (0 == retval)				retval = err;			break;		}		if (q->read_buf->state == STATE_DONE) {			if (vbihack) {				/* dirty, undocumented hack -- pass the frame counter				 * within the last four bytes of each vbi data block.				 * We need that one to maintain backward compatibility				 * to all vbi decoding software out there ... */				fc  = (unsigned int*)q->read_buf->dma.vmalloc;				fc += (q->read_buf->size>>2) -1;				*fc = q->read_buf->field_count >> 1;				dprintk(1,"vbihack: %d\n",*fc);			}						/* copy stuff */			bytes = count;			if (bytes > q->read_buf->size - q->read_off)				bytes = q->read_buf->size - q->read_off;			if (copy_to_user(data + retval,					 q->read_buf->dma.vmalloc + q->read_off,					 bytes)) {				if (0 == retval)					retval = -EFAULT;				break;			}			count       -= bytes;			retval      += bytes;			q->read_off += bytes;		} 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(file,q->read_buf);			spin_unlock_irqrestore(q->irqlock,flags);			q->read_buf = NULL;		}		if (retval < 0)			break;	} done:	up(&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;	down(&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(file,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;	}	up(&q->lock);	return rc;}/* --------------------------------------------------------------------- */static voidvideobuf_vm_open(struct vm_area_struct *vma){	struct videobuf_mapping *map = vma->vm_private_data;	dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,		map->count,vma->vm_start,vma->vm_end);	map->count++;}static voidvideobuf_vm_close(struct vm_area_struct *vma){	struct videobuf_mapping *map = vma->vm_private_data;	int i;	dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,		map->count,vma->vm_start,vma->vm_end);	/* down(&fh->lock); FIXME */	map->count--;	if (0 == map->count) {		dprintk(1,"munmap %p\n",map);		for (i = 0; i < VIDEO_MAX_FRAME; i++) {			if (NULL == map->q->bufs[i])				continue;			if (map->q->bufs[i])				;			if (map->q->bufs[i]->map != map)				continue;			map->q->bufs[i]->map   = NULL;			map->q->bufs[i]->baddr = 0;			map->q->ops->buf_release(vma->vm_file,map->q->bufs[i]);		}		kfree(map);	}	/* up(&fh->lock); FIXME */	return;}/* * Get a anonymous page for the mapping.  Make sure we can DMA to that * memory location with 32bit PCI devices (i.e. don't use highmem for * now ...).  Bounce buffers don't work very well for the data rates * video capture has. */static struct page*#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,1)videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,		   int write_access)#elsevideobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,		   int *type)#endif{	struct page *page;	dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",		vaddr,vma->vm_start,vma->vm_end);        if (vaddr > vma->vm_end)		return NOPAGE_SIGBUS;	page = alloc_page(GFP_USER);	if (!page)		return NOPAGE_OOM;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,20)	clear_user_page(page_address(page), vaddr);#else	clear_user_page(page_address(page), vaddr, page);#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,1)	if (type)		*type = VM_FAULT_MINOR;#endif	return page;}static struct vm_operations_struct videobuf_vm_ops ={	.open     = videobuf_vm_open,	.close    = videobuf_vm_close,	.nopage   = videobuf_vm_nopage,};int videobuf_mmap_setup(struct file *file, struct videobuf_queue *q,			unsigned int bcount, unsigned int bsize,			enum v4l2_memory memory){	unsigned int i;	int err;	err = videobuf_mmap_free(file,q);	if (0 != err)		return err;	for (i = 0; i < bcount; i++) {		q->bufs[i] = videobuf_alloc(q->msize);		q->bufs[i]->i      = i;		q->bufs[i]->input  = UNSET;		q->bufs[i]->memory = memory;		q->bufs[i]->bsize  = bsize;		switch (memory) {		case V4L2_MEMORY_MMAP:			q->bufs[i]->boff  = bsize * i;			break;		case V4L2_MEMORY_USERPTR:		case V4L2_MEMORY_OVERLAY:			/* nothing */			break;		}	}	dprintk(1,"mmap setup: %d buffers, %d bytes each\n",		bcount,bsize);	return 0;}int videobuf_mmap_free(struct file *file, struct videobuf_queue *q){	int i;	for (i = 0; i < VIDEO_MAX_FRAME; i++)		if (q->bufs[i] && q->bufs[i]->map)			return -EBUSY;	for (i = 0; i < VIDEO_MAX_FRAME; i++) {		if (NULL == q->bufs[i])			continue;		q->ops->buf_release(file,q->bufs[i]);		kfree(q->bufs[i]);		q->bufs[i] = NULL;	}	return 0;}int videobuf_mmap_mapper(struct vm_area_struct *vma,			 struct videobuf_queue *q){	struct videobuf_mapping *map;	unsigned int first,last,size,i;	int retval;	down(&q->lock);	retval = -EINVAL;	if (!(vma->vm_flags & VM_WRITE)) {		dprintk(1,"mmap app bug: PROT_WRITE please\n");		goto done;	}	if (!(vma->vm_flags & VM_SHARED)) {		dprintk(1,"mmap app bug: MAP_SHARED please\n");		goto done;	}	/* look for first buffer to map */	for (first = 0; first < VIDEO_MAX_FRAME; first++) {		if (NULL == q->bufs[first])			continue;		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)			continue;		if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))			break;	}	if (VIDEO_MAX_FRAME == first) {		dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",			(vma->vm_pgoff << PAGE_SHIFT));		goto done;	}	/* look for last buffer to map */	for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {		if (NULL == q->bufs[last])			continue;		if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)			continue;		if (q->bufs[last]->map) {			retval = -EBUSY;			goto done;		}		size += q->bufs[last]->bsize;		if (size == (vma->vm_end - vma->vm_start))			break;	}	if (VIDEO_MAX_FRAME == last) {		dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",			(vma->vm_end - vma->vm_start));		goto done;	}	/* create mapping + update buffer list */	retval = -ENOMEM;	map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);	if (NULL == map)		goto done;	for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {		q->bufs[i]->map   = map;		q->bufs[i]->baddr = vma->vm_start + size;	}	map->count    = 1;	map->start    = vma->vm_start;	map->end      = vma->vm_end;	map->q        = q;	vma->vm_ops   = &videobuf_vm_ops;	vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */	vma->vm_private_data = map;	dprintk(1,"mmap %p: %08lx-%08lx pgoff %08lx bufs %d-%d\n",		map,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);	retval = 0; done:	up(&q->lock);	return retval;}/* --------------------------------------------------------------------- */EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);EXPORT_SYMBOL_GPL(videobuf_dma_init);EXPORT_SYMBOL_GPL(videobuf_dma_init_user);EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);EXPORT_SYMBOL_GPL(videobuf_dma_pci_map);EXPORT_SYMBOL_GPL(videobuf_dma_pci_sync);EXPORT_SYMBOL_GPL(videobuf_dma_pci_unmap);EXPORT_SYMBOL_GPL(videobuf_dma_free);EXPORT_SYMBOL_GPL(videobuf_alloc);EXPORT_SYMBOL_GPL(videobuf_waiton);EXPORT_SYMBOL_GPL(videobuf_iolock);EXPORT_SYMBOL_GPL(videobuf_queue_init);EXPORT_SYMBOL_GPL(videobuf_queue_cancel);EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);EXPORT_SYMBOL_GPL(videobuf_next_field);EXPORT_SYMBOL_GPL(videobuf_status);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_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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -