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

📄 videobuf-dma-sg.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)static struct page*videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,		   int *type){	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 | __GFP_DMA32);	if (!page)		return NOPAGE_OOM;	clear_user_page(page_address(page), vaddr, page);	if (type)		*type = VM_FAULT_MINOR;	return page;}#elsestatic intvideobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf){	struct page *page;	dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n",		(unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end);	page = alloc_page(GFP_USER | __GFP_DMA32);	if (!page)		return VM_FAULT_OOM;	clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,			page);	vmf->page = page;	return 0;}#endifstatic struct vm_operations_struct videobuf_vm_ops ={	.open     = videobuf_vm_open,	.close    = videobuf_vm_close,#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)	.nopage   = videobuf_vm_nopage,#else	.fault    = videobuf_vm_fault,#endif};/* --------------------------------------------------------------------- * SG handlers for the generic methods *//* Allocated area consists on 3 parts:	struct video_buffer	struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)	struct videobuf_dma_sg_memory */static void *__videobuf_alloc(size_t size){	struct videobuf_dma_sg_memory *mem;	struct videobuf_buffer *vb;	vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);	mem = vb->priv = ((char *)vb)+size;	mem->magic=MAGIC_SG_MEM;	videobuf_dma_init(&mem->dma);	dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",		__func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),		mem,(long)sizeof(*mem));	return vb;}static void *__videobuf_to_vmalloc (struct videobuf_buffer *buf){	struct videobuf_dma_sg_memory *mem = buf->priv;	BUG_ON(!mem);	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);	return mem->dma.vmalloc;}static int __videobuf_iolock (struct videobuf_queue* q,			      struct videobuf_buffer *vb,			      struct v4l2_framebuffer *fbuf){	int err,pages;	dma_addr_t bus;	struct videobuf_dma_sg_memory *mem = vb->priv;	BUG_ON(!mem);	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);	switch (vb->memory) {	case V4L2_MEMORY_MMAP:	case V4L2_MEMORY_USERPTR:		if (0 == vb->baddr) {			/* no userspace addr -- kernel bounce buffer */			pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;			err = videobuf_dma_init_kernel( &mem->dma,							DMA_FROM_DEVICE,							pages );			if (0 != err)				return err;		} else if (vb->memory == V4L2_MEMORY_USERPTR) {			/* dma directly to userspace */			err = videobuf_dma_init_user( &mem->dma,						      DMA_FROM_DEVICE,						      vb->baddr,vb->bsize );			if (0 != err)				return err;		} else {			/* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP			buffers can only be called from videobuf_qbuf			we take current->mm->mmap_sem there, to prevent			locking inversion, so don't take it here */			err = videobuf_dma_init_user_locked(&mem->dma,						      DMA_FROM_DEVICE,						      vb->baddr, vb->bsize);			if (0 != err)				return err;		}		break;	case V4L2_MEMORY_OVERLAY:		if (NULL == fbuf)			return -EINVAL;		/* FIXME: need sanity checks for vb->boff */		/*		 * Using a double cast to avoid compiler warnings when		 * building for PAE. Compiler doesn't like direct casting		 * of a 32 bit ptr to 64 bit integer.		 */		bus   = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;		pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;		err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE,						bus, pages);		if (0 != err)			return err;		break;	default:		BUG();	}	err = videobuf_dma_map(q, &mem->dma);	if (0 != err)		return err;	return 0;}static int __videobuf_sync(struct videobuf_queue *q,			   struct videobuf_buffer *buf){	struct videobuf_dma_sg_memory *mem = buf->priv;	BUG_ON(!mem);	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);	return	videobuf_dma_sync(q,&mem->dma);}static int __videobuf_mmap_free(struct videobuf_queue *q){	int i;	for (i = 0; i < VIDEO_MAX_FRAME; i++) {		if (q->bufs[i]) {			if (q->bufs[i]->map)				return -EBUSY;		}	}	return 0;}static int __videobuf_mmap_mapper(struct videobuf_queue *q,			 struct vm_area_struct *vma){	struct videobuf_dma_sg_memory *mem;	struct videobuf_mapping *map;	unsigned int first,last,size,i;	int retval;	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;	}	/* This function maintains backwards compatibility with V4L1 and will	 * map more than one buffer if the vma length is equal to the combined	 * size of multiple buffers than it will map them together.  See	 * VIDIOCGMBUF in the v4l spec	 *	 * TODO: Allow drivers to specify if they support this mode	 */	/* look for first buffer to map */	for (first = 0; first < VIDEO_MAX_FRAME; first++) {		if (NULL == q->bufs[first])			continue;		mem=q->bufs[first]->priv;		BUG_ON(!mem);		MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);		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;	size = 0;	for (i = first; i <= last; i++) {		if (NULL == q->bufs[i])			continue;		q->bufs[i]->map   = map;		q->bufs[i]->baddr = vma->vm_start + size;		size += q->bufs[i]->bsize;	}	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: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",		map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);	retval = 0; done:	return retval;}static int __videobuf_copy_to_user ( struct videobuf_queue *q,				char __user *data, size_t count,				int nonblocking ){	struct videobuf_dma_sg_memory *mem = q->read_buf->priv;	BUG_ON(!mem);	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);	/* copy to userspace */	if (count > q->read_buf->size - q->read_off)		count = q->read_buf->size - q->read_off;	if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count))		return -EFAULT;	return count;}static int __videobuf_copy_stream ( struct videobuf_queue *q,				char __user *data, size_t count, size_t pos,				int vbihack, int nonblocking ){	unsigned int  *fc;	struct videobuf_dma_sg_memory *mem = q->read_buf->priv;	BUG_ON(!mem);	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);	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*)mem->dma.vmalloc;		fc += (q->read_buf->size>>2) -1;		*fc = q->read_buf->field_count >> 1;		dprintk(1,"vbihack: %d\n",*fc);	}	/* copy stuff using the common method */	count = __videobuf_copy_to_user (q,data,count,nonblocking);	if ( (count==-EFAULT) && (0 == pos) )		return -EFAULT;	return count;}static struct videobuf_qtype_ops sg_ops = {	.magic        = MAGIC_QTYPE_OPS,	.alloc        = __videobuf_alloc,	.iolock       = __videobuf_iolock,	.sync         = __videobuf_sync,	.mmap_free    = __videobuf_mmap_free,	.mmap_mapper  = __videobuf_mmap_mapper,	.video_copy_to_user = __videobuf_copy_to_user,	.copy_stream  = __videobuf_copy_stream,	.vmalloc      = __videobuf_to_vmalloc,};void *videobuf_sg_alloc(size_t size){	struct videobuf_queue q;	/* Required to make generic handler to call __videobuf_alloc */	q.int_ops = &sg_ops;	q.msize = size;	return videobuf_alloc(&q);}void videobuf_queue_sg_init(struct videobuf_queue* q,			 struct videobuf_queue_ops *ops,			 struct device *dev,			 spinlock_t *irqlock,			 enum v4l2_buf_type type,			 enum v4l2_field field,			 unsigned int msize,			 void *priv){	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,				 priv, &sg_ops);}/* --------------------------------------------------------------------- */EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);EXPORT_SYMBOL_GPL(videobuf_to_dma);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_map);EXPORT_SYMBOL_GPL(videobuf_dma_sync);EXPORT_SYMBOL_GPL(videobuf_dma_unmap);EXPORT_SYMBOL_GPL(videobuf_dma_free);EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);EXPORT_SYMBOL_GPL(videobuf_sg_alloc);EXPORT_SYMBOL_GPL(videobuf_queue_sg_init);/* * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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