| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  |  * helper functions for SG DMA video4linux capture buffers | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2008-07-16 21:27:49 -03:00
										 |  |  |  * The functions expect the hardware being able to scatter gather | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  |  * (i.e. the buffers are not linear in physical memory, but fragmented | 
					
						
							|  |  |  |  * into PAGE_SIZE chunks).  They also assume the driver does not need | 
					
						
							|  |  |  |  * to touch the video data. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Highly based on video-buf written originally by: | 
					
						
							|  |  |  |  * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> | 
					
						
							|  |  |  |  * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org> | 
					
						
							|  |  |  |  * (c) 2006 Ted Walther and John Sokol | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/moduleparam.h>
 | 
					
						
							| 
									
										
										
										
											2009-10-07 17:09:06 +04:00
										 |  |  | #include <linux/sched.h>
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | #include <linux/interrupt.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | #include <linux/dma-mapping.h>
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | #include <linux/vmalloc.h>
 | 
					
						
							|  |  |  | #include <linux/pagemap.h>
 | 
					
						
							| 
									
										
										
										
											2007-10-23 20:42:11 +02:00
										 |  |  | #include <linux/scatterlist.h>
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | #include <asm/page.h>
 | 
					
						
							|  |  |  | #include <asm/pgtable.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <media/videobuf-dma-sg.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MAGIC_DMABUF 0x19721112
 | 
					
						
							|  |  |  | #define MAGIC_SG_MEM 0x17890714
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | #define MAGIC_CHECK(is, should)						\
 | 
					
						
							|  |  |  | 	if (unlikely((is) != (should))) {				\ | 
					
						
							|  |  |  | 		printk(KERN_ERR "magic mismatch: %x (expected %x)\n",	\ | 
					
						
							|  |  |  | 				is, should);				\ | 
					
						
							|  |  |  | 		BUG();							\ | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:41:48 -03:00
										 |  |  | static int debug; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | module_param(debug, int, 0644); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | MODULE_DESCRIPTION("helper module to manage video4linux dma sg buffers"); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | 
					
						
							|  |  |  | MODULE_LICENSE("GPL"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | #define dprintk(level, fmt, arg...)					\
 | 
					
						
							|  |  |  | 	if (debug >= level)						\ | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:32 -03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Return a scatterlist for some page-aligned vmalloc()'ed memory | 
					
						
							|  |  |  |  * block (NULL on errors).  Memory for the scatterlist is allocated | 
					
						
							|  |  |  |  * using kmalloc.  The caller must free the memory. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, | 
					
						
							|  |  |  | 						  int nr_pages) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct scatterlist *sglist; | 
					
						
							|  |  |  | 	struct page *pg; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-05 00:07:39 -03:00
										 |  |  | 	sglist = vzalloc(nr_pages * sizeof(*sglist)); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	if (NULL == sglist) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2007-10-22 21:19:53 +02:00
										 |  |  | 	sg_init_table(sglist, nr_pages); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { | 
					
						
							|  |  |  | 		pg = vmalloc_to_page(virt); | 
					
						
							|  |  |  | 		if (NULL == pg) | 
					
						
							|  |  |  | 			goto err; | 
					
						
							|  |  |  | 		BUG_ON(PageHighMem(pg)); | 
					
						
							| 
									
										
										
										
											2007-10-24 11:20:47 +02:00
										 |  |  | 		sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return sglist; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | err: | 
					
						
							| 
									
										
										
										
											2009-05-11 11:00:20 -03:00
										 |  |  | 	vfree(sglist); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:32 -03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Return a scatterlist for a an array of userpages (NULL on errors). | 
					
						
							|  |  |  |  * Memory for the scatterlist is allocated using kmalloc.  The caller | 
					
						
							|  |  |  |  * must free the memory. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct scatterlist *videobuf_pages_to_sg(struct page **pages, | 
					
						
							| 
									
										
										
										
											2010-09-07 06:10:45 -03:00
										 |  |  | 					int nr_pages, int offset, size_t size) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct scatterlist *sglist; | 
					
						
							| 
									
										
										
										
											2008-07-04 06:33:22 -03:00
										 |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (NULL == pages[0]) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2009-05-11 11:00:20 -03:00
										 |  |  | 	sglist = vmalloc(nr_pages * sizeof(*sglist)); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	if (NULL == sglist) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2007-10-22 21:19:53 +02:00
										 |  |  | 	sg_init_table(sglist, nr_pages); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (PageHighMem(pages[0])) | 
					
						
							|  |  |  | 		/* DMA to highmem pages might not work */ | 
					
						
							|  |  |  | 		goto highmem; | 
					
						
							| 
									
										
										
										
											2011-04-19 11:54:54 -03:00
										 |  |  | 	sg_set_page(&sglist[0], pages[0], | 
					
						
							|  |  |  | 			min_t(size_t, PAGE_SIZE - offset, size), offset); | 
					
						
							|  |  |  | 	size -= min_t(size_t, PAGE_SIZE - offset, size); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	for (i = 1; i < nr_pages; i++) { | 
					
						
							|  |  |  | 		if (NULL == pages[i]) | 
					
						
							|  |  |  | 			goto nopage; | 
					
						
							|  |  |  | 		if (PageHighMem(pages[i])) | 
					
						
							|  |  |  | 			goto highmem; | 
					
						
							| 
									
										
										
										
											2010-10-07 09:31:33 -03:00
										 |  |  | 		sg_set_page(&sglist[i], pages[i], min_t(size_t, PAGE_SIZE, size), 0); | 
					
						
							|  |  |  | 		size -= min_t(size_t, PAGE_SIZE, size); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return sglist; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | nopage: | 
					
						
							|  |  |  | 	dprintk(2, "sgl: oops - no page\n"); | 
					
						
							| 
									
										
										
										
											2009-05-11 11:00:20 -03:00
										 |  |  | 	vfree(sglist); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | highmem: | 
					
						
							|  |  |  | 	dprintk(2, "sgl: oops - highmem page\n"); | 
					
						
							| 
									
										
										
										
											2009-05-11 11:00:20 -03:00
										 |  |  | 	vfree(sglist); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	struct videobuf_dma_sg_memory *mem = buf->priv; | 
					
						
							|  |  |  | 	BUG_ON(!mem); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return &mem->dma; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_to_dma); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | void videobuf_dma_init(struct videobuf_dmabuf *dma) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	memset(dma, 0, sizeof(*dma)); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	dma->magic = MAGIC_DMABUF; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_dma_init); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-27 20:34:09 -03:00
										 |  |  | static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, | 
					
						
							|  |  |  | 			int direction, unsigned long data, unsigned long size) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	unsigned long first, last; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	int err, rw = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dma->direction = direction; | 
					
						
							|  |  |  | 	switch (dma->direction) { | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	case DMA_FROM_DEVICE: | 
					
						
							|  |  |  | 		rw = READ; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DMA_TO_DEVICE: | 
					
						
							|  |  |  | 		rw = WRITE; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		BUG(); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	first = (data          & PAGE_MASK) >> PAGE_SHIFT; | 
					
						
							|  |  |  | 	last  = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; | 
					
						
							| 
									
										
										
										
											2010-09-07 06:10:45 -03:00
										 |  |  | 	dma->offset = data & ~PAGE_MASK; | 
					
						
							|  |  |  | 	dma->size = size; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	dma->nr_pages = last-first+1; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	dma->pages = kmalloc(dma->nr_pages * sizeof(struct page *), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	if (NULL == dma->pages) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n", | 
					
						
							|  |  |  | 		data, size, dma->nr_pages); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = get_user_pages(current, current->mm, | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			     data & PAGE_MASK, dma->nr_pages, | 
					
						
							|  |  |  | 			     rw == READ, 1, /* force */ | 
					
						
							|  |  |  | 			     dma->pages, NULL); | 
					
						
							| 
									
										
										
										
											2007-09-27 20:34:09 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	if (err != dma->nr_pages) { | 
					
						
							|  |  |  | 		dma->nr_pages = (err >= 0) ? err : 0; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 		dprintk(1, "get_user_pages: err=%d [%d]\n", err, dma->nr_pages); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		return err < 0 ? err : -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-27 20:34:09 -03:00
										 |  |  | int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, | 
					
						
							|  |  |  | 			   unsigned long data, unsigned long size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-27 20:34:09 -03:00
										 |  |  | 	down_read(¤t->mm->mmap_sem); | 
					
						
							|  |  |  | 	ret = videobuf_dma_init_user_locked(dma, direction, data, size); | 
					
						
							|  |  |  | 	up_read(¤t->mm->mmap_sem); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_dma_init_user); | 
					
						
							| 
									
										
										
										
											2007-09-27 20:34:09 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, | 
					
						
							|  |  |  | 			     int nr_pages) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	dprintk(1, "init kernel [%d pages]\n", nr_pages); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	dma->direction = direction; | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:34 -03:00
										 |  |  | 	dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); | 
					
						
							|  |  |  | 	if (NULL == dma->vaddr) { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 		dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:34 -03:00
										 |  |  | 				(unsigned long)dma->vaddr, | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 				nr_pages << PAGE_SHIFT); | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:34 -03:00
										 |  |  | 	memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	dma->nr_pages = nr_pages; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, | 
					
						
							|  |  |  | 			      dma_addr_t addr, int nr_pages) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	dprintk(1, "init overlay [%d pages @ bus 0x%lx]\n", | 
					
						
							|  |  |  | 		nr_pages, (unsigned long)addr); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	dma->direction = direction; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	if (0 == addr) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dma->bus_addr = addr; | 
					
						
							|  |  |  | 	dma->nr_pages = nr_pages; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:30 -03:00
										 |  |  | int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	MAGIC_CHECK(dma->magic, MAGIC_DMABUF); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	BUG_ON(0 == dma->nr_pages); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dma->pages) { | 
					
						
							|  |  |  | 		dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, | 
					
						
							| 
									
										
										
										
											2010-09-07 06:10:45 -03:00
										 |  |  | 						   dma->offset, dma->size); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:34 -03:00
										 |  |  | 	if (dma->vaddr) { | 
					
						
							|  |  |  | 		dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr, | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 						     dma->nr_pages); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (dma->bus_addr) { | 
					
						
							| 
									
										
										
										
											2009-05-11 11:00:20 -03:00
										 |  |  | 		dma->sglist = vmalloc(sizeof(*dma->sglist)); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		if (NULL != dma->sglist) { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 			dma->sglen = 1; | 
					
						
							|  |  |  | 			sg_dma_address(&dma->sglist[0])	= dma->bus_addr | 
					
						
							|  |  |  | 							& PAGE_MASK; | 
					
						
							|  |  |  | 			dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; | 
					
						
							|  |  |  | 			sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (NULL == dma->sglist) { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 		dprintk(1, "scatterlist is NULL\n"); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!dma->bus_addr) { | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:30 -03:00
										 |  |  | 		dma->sglen = dma_map_sg(dev, dma->sglist, | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 					dma->nr_pages, dma->direction); | 
					
						
							|  |  |  | 		if (0 == dma->sglen) { | 
					
						
							|  |  |  | 			printk(KERN_WARNING | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 			       "%s: videobuf_map_sg failed\n", __func__); | 
					
						
							| 
									
										
										
										
											2009-05-11 11:00:20 -03:00
										 |  |  | 			vfree(dma->sglist); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			dma->sglist = NULL; | 
					
						
							|  |  |  | 			dma->sglen = 0; | 
					
						
							| 
									
										
										
										
											2009-06-10 23:17:27 -03:00
										 |  |  | 			return -ENOMEM; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_dma_map); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:30 -03:00
										 |  |  | int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	MAGIC_CHECK(dma->magic, MAGIC_DMABUF); | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	if (!dma->sglen) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:30 -03:00
										 |  |  | 	dma_unmap_sg(dev, dma->sglist, dma->sglen, dma->direction); | 
					
						
							| 
									
										
										
										
											2007-10-08 11:43:49 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-11 11:00:20 -03:00
										 |  |  | 	vfree(dma->sglist); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	dma->sglist = NULL; | 
					
						
							|  |  |  | 	dma->sglen = 0; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_dma_unmap); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | int videobuf_dma_free(struct videobuf_dmabuf *dma) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 	MAGIC_CHECK(dma->magic, MAGIC_DMABUF); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	BUG_ON(dma->sglen); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dma->pages) { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 		for (i = 0; i < dma->nr_pages; i++) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			page_cache_release(dma->pages[i]); | 
					
						
							|  |  |  | 		kfree(dma->pages); | 
					
						
							|  |  |  | 		dma->pages = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:34 -03:00
										 |  |  | 	vfree(dma->vaddr); | 
					
						
							|  |  |  | 	dma->vaddr = NULL; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	if (dma->bus_addr) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		dma->bus_addr = 0; | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	dma->direction = DMA_NONE; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_dma_free); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | static void videobuf_vm_open(struct vm_area_struct *vma) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct videobuf_mapping *map = vma->vm_private_data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, | 
					
						
							|  |  |  | 		map->count, vma->vm_start, vma->vm_end); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	map->count++; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | static void videobuf_vm_close(struct vm_area_struct *vma) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct videobuf_mapping *map = vma->vm_private_data; | 
					
						
							|  |  |  | 	struct videobuf_queue *q = map->q; | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	struct videobuf_dma_sg_memory *mem; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, | 
					
						
							|  |  |  | 		map->count, vma->vm_start, vma->vm_end); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-03 08:10:49 -03:00
										 |  |  | 	map->count--; | 
					
						
							|  |  |  | 	if (0 == map->count) { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 		dprintk(1, "munmap %p q=%p\n", map, q); | 
					
						
							| 
									
										
										
										
											2014-01-03 08:10:49 -03:00
										 |  |  | 		videobuf_queue_lock(q); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		for (i = 0; i < VIDEO_MAX_FRAME; i++) { | 
					
						
							|  |  |  | 			if (NULL == q->bufs[i]) | 
					
						
							|  |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 			mem = q->bufs[i]->priv; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			if (!mem) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 			MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-27 18:25:44 -03:00
										 |  |  | 			if (q->bufs[i]->map != map) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2007-09-27 18:25:44 -03:00
										 |  |  | 			q->bufs[i]->map   = NULL; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			q->bufs[i]->baddr = 0; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 			q->ops->buf_release(q, q->bufs[i]); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-01-03 08:10:49 -03:00
										 |  |  | 		videobuf_queue_unlock(q); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		kfree(map); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	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. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | static int videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct page *page; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	dprintk(3, "fault: fault @ %08lx [vma %08lx-%08lx]\n", | 
					
						
							|  |  |  | 		(unsigned long)vmf->virtual_address, | 
					
						
							|  |  |  | 		vma->vm_start, vma->vm_end); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	page = alloc_page(GFP_USER | __GFP_DMA32); | 
					
						
							|  |  |  | 	if (!page) | 
					
						
							| 
									
										
										
										
											2007-12-07 17:57:38 -03:00
										 |  |  | 		return VM_FAULT_OOM; | 
					
						
							| 
									
										
										
										
											2009-01-03 18:20:04 -03:00
										 |  |  | 	clear_user_highpage(page, (unsigned long)vmf->virtual_address); | 
					
						
							| 
									
										
										
										
											2007-12-07 17:57:38 -03:00
										 |  |  | 	vmf->page = page; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-07 17:57:38 -03:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | static const struct vm_operations_struct videobuf_vm_ops = { | 
					
						
							|  |  |  | 	.open	= videobuf_vm_open, | 
					
						
							|  |  |  | 	.close	= videobuf_vm_close, | 
					
						
							|  |  |  | 	.fault	= videobuf_vm_fault, | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  |  * SG handlers for the generic methods | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Allocated area consists on 3 parts:
 | 
					
						
							|  |  |  | 	struct video_buffer | 
					
						
							|  |  |  | 	struct <driver>_buffer (cx88_buffer, saa7134_buf, ...) | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	struct videobuf_dma_sg_memory | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:28 -03:00
										 |  |  | static struct videobuf_buffer *__videobuf_alloc_vb(size_t size) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	struct videobuf_dma_sg_memory *mem; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	struct videobuf_buffer *vb; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2010-02-22 13:10:06 -03:00
										 |  |  | 	if (!vb) | 
					
						
							|  |  |  | 		return vb; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	mem = vb->priv = ((char *)vb) + size; | 
					
						
							|  |  |  | 	mem->magic = MAGIC_SG_MEM; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	videobuf_dma_init(&mem->dma); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", | 
					
						
							|  |  |  | 		__func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), | 
					
						
							|  |  |  | 		mem, (long)sizeof(*mem)); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return vb; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-28 08:18:37 -03:00
										 |  |  | static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) | 
					
						
							| 
									
										
										
										
											2008-04-13 15:10:00 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct videobuf_dma_sg_memory *mem = buf->priv; | 
					
						
							|  |  |  | 	BUG_ON(!mem); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:34 -03:00
										 |  |  | 	return mem->dma.vaddr; | 
					
						
							| 
									
										
										
										
											2008-04-13 15:10:00 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | static int __videobuf_iolock(struct videobuf_queue *q, | 
					
						
							|  |  |  | 			     struct videobuf_buffer *vb, | 
					
						
							|  |  |  | 			     struct v4l2_framebuffer *fbuf) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	int err, pages; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	dma_addr_t bus; | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	struct videobuf_dma_sg_memory *mem = vb->priv; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	BUG_ON(!mem); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 			err = videobuf_dma_init_kernel(&mem->dma, | 
					
						
							|  |  |  | 						       DMA_FROM_DEVICE, | 
					
						
							|  |  |  | 						       pages); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			if (0 != err) | 
					
						
							|  |  |  | 				return err; | 
					
						
							| 
									
										
										
										
											2007-09-27 20:34:09 -03:00
										 |  |  | 		} else if (vb->memory == V4L2_MEMORY_USERPTR) { | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			/* dma directly to userspace */ | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 			err = videobuf_dma_init_user(&mem->dma, | 
					
						
							|  |  |  | 						     DMA_FROM_DEVICE, | 
					
						
							|  |  |  | 						     vb->baddr, vb->bsize); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			if (0 != err) | 
					
						
							|  |  |  | 				return err; | 
					
						
							| 
									
										
										
										
											2007-09-27 20:34:09 -03:00
										 |  |  | 		} 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, | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 						      DMA_FROM_DEVICE, | 
					
						
							| 
									
										
										
										
											2007-09-27 20:34:09 -03:00
										 |  |  | 						      vb->baddr, vb->bsize); | 
					
						
							|  |  |  | 			if (0 != err) | 
					
						
							|  |  |  | 				return err; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 		err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE, | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 						bus, pages); | 
					
						
							|  |  |  | 		if (0 != err) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		BUG(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:30 -03:00
										 |  |  | 	err = videobuf_dma_map(q->dev, &mem->dma); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	if (0 != err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __videobuf_sync(struct videobuf_queue *q, | 
					
						
							|  |  |  | 			   struct videobuf_buffer *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	struct videobuf_dma_sg_memory *mem = buf->priv; | 
					
						
							| 
									
										
										
										
											2010-05-05 16:23:09 -03:00
										 |  |  | 	BUG_ON(!mem || !mem->dma.sglen); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); | 
					
						
							| 
									
										
										
										
											2010-05-05 16:23:09 -03:00
										 |  |  | 	MAGIC_CHECK(mem->dma.magic, MAGIC_DMABUF); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-05 16:23:09 -03:00
										 |  |  | 	dma_sync_sg_for_cpu(q->dev, mem->dma.sglist, | 
					
						
							| 
									
										
										
										
											2010-03-17 19:53:04 -03:00
										 |  |  | 			    mem->dma.sglen, mem->dma.direction); | 
					
						
							| 
									
										
										
										
											2010-05-05 16:23:09 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __videobuf_mmap_mapper(struct videobuf_queue *q, | 
					
						
							| 
									
										
										
										
											2010-03-28 09:09:05 -03:00
										 |  |  | 				  struct videobuf_buffer *buf, | 
					
						
							|  |  |  | 				  struct vm_area_struct *vma) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-28 09:09:05 -03:00
										 |  |  | 	struct videobuf_dma_sg_memory *mem = buf->priv; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	struct videobuf_mapping *map; | 
					
						
							| 
									
										
										
										
											2010-04-25 11:23:52 -03:00
										 |  |  | 	unsigned int first, last, size = 0, i; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	int retval; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	retval = -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-28 09:09:05 -03:00
										 |  |  | 	BUG_ON(!mem); | 
					
						
							|  |  |  | 	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	/* look for first buffer to map */ | 
					
						
							|  |  |  | 	for (first = 0; first < VIDEO_MAX_FRAME; first++) { | 
					
						
							| 
									
										
										
										
											2010-03-28 09:09:05 -03:00
										 |  |  | 		if (buf == q->bufs[first]) { | 
					
						
							|  |  |  | 			size = PAGE_ALIGN(q->bufs[first]->bsize); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2010-03-28 09:09:05 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-03-28 09:09:05 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* paranoia, should never happen since buf is always valid. */ | 
					
						
							| 
									
										
										
										
											2010-04-25 11:23:52 -03:00
										 |  |  | 	if (!size) { | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 		dprintk(1, "mmap app bug: offset invalid [offset=0x%lx]\n", | 
					
						
							| 
									
										
										
										
											2010-03-28 09:09:05 -03:00
										 |  |  | 				(vma->vm_pgoff << PAGE_SHIFT)); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-28 09:09:05 -03:00
										 |  |  | 	last = first; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* create mapping + update buffer list */ | 
					
						
							|  |  |  | 	retval = -ENOMEM; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	map = kmalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	if (NULL == map) | 
					
						
							|  |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2008-04-02 18:10:59 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	size = 0; | 
					
						
							|  |  |  | 	for (i = first; i <= last; i++) { | 
					
						
							|  |  |  | 		if (NULL == q->bufs[i]) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2007-09-27 18:25:44 -03:00
										 |  |  | 		q->bufs[i]->map   = map; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 		q->bufs[i]->baddr = vma->vm_start + size; | 
					
						
							| 
									
										
										
										
											2009-07-23 10:56:25 -03:00
										 |  |  | 		size += PAGE_ALIGN(q->bufs[i]->bsize); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-04-02 18:10:59 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	map->count    = 1; | 
					
						
							|  |  |  | 	map->q        = q; | 
					
						
							|  |  |  | 	vma->vm_ops   = &videobuf_vm_ops; | 
					
						
							| 
									
										
											  
											
												mm: kill vma flag VM_RESERVED and mm->reserved_vm counter
A long time ago, in v2.4, VM_RESERVED kept swapout process off VMA,
currently it lost original meaning but still has some effects:
 | effect                 | alternative flags
-+------------------------+---------------------------------------------
1| account as reserved_vm | VM_IO
2| skip in core dump      | VM_IO, VM_DONTDUMP
3| do not merge or expand | VM_IO, VM_DONTEXPAND, VM_HUGETLB, VM_PFNMAP
4| do not mlock           | VM_IO, VM_DONTEXPAND, VM_HUGETLB, VM_PFNMAP
This patch removes reserved_vm counter from mm_struct.  Seems like nobody
cares about it, it does not exported into userspace directly, it only
reduces total_vm showed in proc.
Thus VM_RESERVED can be replaced with VM_IO or pair VM_DONTEXPAND | VM_DONTDUMP.
remap_pfn_range() and io_remap_pfn_range() set VM_IO|VM_DONTEXPAND|VM_DONTDUMP.
remap_vmalloc_range() set VM_DONTEXPAND | VM_DONTDUMP.
[akpm@linux-foundation.org: drivers/vfio/pci/vfio_pci.c fixup]
Signed-off-by: Konstantin Khlebnikov <khlebnikov@openvz.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Carsten Otte <cotte@de.ibm.com>
Cc: Chris Metcalf <cmetcalf@tilera.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Eric Paris <eparis@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Kentaro Takeda <takedakn@nttdata.co.jp>
Cc: Matt Helsley <matthltc@us.ibm.com>
Cc: Nick Piggin <npiggin@kernel.dk>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Robert Richter <robert.richter@amd.com>
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: Venkatesh Pallipadi <venki@google.com>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
											
										 
											2012-10-08 16:29:02 -07:00
										 |  |  | 	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ | 
					
						
							|  |  |  | 	vma->vm_private_data = map; | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	retval = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | done: | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	return retval; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | static struct videobuf_qtype_ops sg_ops = { | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	.magic        = MAGIC_QTYPE_OPS, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:28 -03:00
										 |  |  | 	.alloc_vb     = __videobuf_alloc_vb, | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 	.iolock       = __videobuf_iolock, | 
					
						
							|  |  |  | 	.sync         = __videobuf_sync, | 
					
						
							|  |  |  | 	.mmap_mapper  = __videobuf_mmap_mapper, | 
					
						
							| 
									
										
										
										
											2010-03-28 08:18:37 -03:00
										 |  |  | 	.vaddr        = __videobuf_to_vaddr, | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | void *videobuf_sg_alloc(size_t size) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct videobuf_queue q; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Required to make generic handler to call __videobuf_alloc */ | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	q.int_ops = &sg_ops; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 	q.msize = size; | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-11 10:36:28 -03:00
										 |  |  | 	return videobuf_alloc_vb(&q); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_sg_alloc); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 04:01:04 -03:00
										 |  |  | void videobuf_queue_sg_init(struct videobuf_queue *q, | 
					
						
							| 
									
										
										
										
											2009-11-17 19:43:41 -03:00
										 |  |  | 			 const struct videobuf_queue_ops *ops, | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | 			 struct device *dev, | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 			 spinlock_t *irqlock, | 
					
						
							|  |  |  | 			 enum v4l2_buf_type type, | 
					
						
							|  |  |  | 			 enum v4l2_field field, | 
					
						
							|  |  |  | 			 unsigned int msize, | 
					
						
							| 
									
										
										
										
											2010-09-20 17:39:46 -03:00
										 |  |  | 			 void *priv, | 
					
						
							|  |  |  | 			 struct mutex *ext_lock) | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-08 12:20:02 -03:00
										 |  |  | 	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, | 
					
						
							| 
									
										
										
										
											2010-09-20 17:39:46 -03:00
										 |  |  | 				 priv, &sg_ops, ext_lock); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-04-22 14:42:13 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(videobuf_queue_sg_init); | 
					
						
							| 
									
										
										
										
											2007-08-23 16:26:14 -03:00
										 |  |  | 
 |