1ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 2ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * ispqueue.c 3ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 4ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * TI OMAP3 ISP - Video buffers queue handling 5ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 6ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Copyright (C) 2010 Nokia Corporation 7ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 8ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 9ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Sakari Ailus <sakari.ailus@iki.fi> 10ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 11ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This program is free software; you can redistribute it and/or modify 12ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * it under the terms of the GNU General Public License version 2 as 13ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * published by the Free Software Foundation. 14ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 15ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This program is distributed in the hope that it will be useful, but 16ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * WITHOUT ANY WARRANTY; without even the implied warranty of 17ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * General Public License for more details. 19ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 20ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * You should have received a copy of the GNU General Public License 21ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * along with this program; if not, write to the Free Software 22ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 23ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 02110-1301 USA 24ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 25ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 26ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <asm/cacheflush.h> 27ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <linux/dma-mapping.h> 28ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <linux/mm.h> 29ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <linux/pagemap.h> 30ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <linux/poll.h> 31ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <linux/scatterlist.h> 32ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <linux/sched.h> 33ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <linux/slab.h> 34ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include <linux/vmalloc.h> 35ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 36ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#include "ispqueue.h" 37ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 38ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* ----------------------------------------------------------------------------- 39ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Video buffers management 40ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 41ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 42ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 43ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP 44ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 45ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * The typical operation required here is Cache Invalidation across 46ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * the (user space) buffer address range. And this _must_ be done 47ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * at QBUF stage (and *only* at QBUF). 48ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 49ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * We try to use optimal cache invalidation function: 50ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - dmac_map_area: 51ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - used when the number of pages are _low_. 52ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - it becomes quite slow as the number of pages increase. 53ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - for 648x492 viewfinder (150 pages) it takes 1.3 ms. 54ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms. 55ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 56ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - flush_cache_all: 57ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - used when the number of pages are _high_. 58ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - time taken in the range of 500-900 us. 59ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - has a higher penalty but, as whole dcache + icache is invalidated 60ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 61ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 62ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * FIXME: dmac_inv_range crashes randomly on the user space buffer 63ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * address. Fall back to flush_cache_all for now. 64ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 65ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart#define ISP_CACHE_FLUSH_PAGES_MAX 0 66ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 67ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic void isp_video_buffer_cache_sync(struct isp_video_buffer *buf) 68ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 69ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->skip_cache) 70ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return; 71ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 72ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->vbuf.m.userptr == 0 || buf->npages == 0 || 73ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->npages > ISP_CACHE_FLUSH_PAGES_MAX) 74ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart flush_cache_all(); 75ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart else { 76ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length, 77ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart DMA_FROM_DEVICE); 78ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart outer_inv_range(buf->vbuf.m.userptr, 79ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.m.userptr + buf->vbuf.length); 80ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 81ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 82ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 83ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 84ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped 85ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 86ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Lock the VMAs underlying the given buffer into memory. This avoids the 87ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * userspace buffer mapping from being swapped out, making VIPT cache handling 88ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * easier. 89ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 90ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Note that the pages will not be freed as the buffers have been locked to 91ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * memory using by a call to get_user_pages(), but the userspace mapping could 92ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * still disappear if the VMAs are not locked. This is caused by the memory 93ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * management code trying to be as lock-less as possible, which results in the 94ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * userspace mapping manager not finding out that the pages are locked under 95ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * some conditions. 96ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 97ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock) 98ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 99ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct vm_area_struct *vma; 100ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long start; 101ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long end; 102ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret = 0; 103ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 104ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->vbuf.memory == V4L2_MEMORY_MMAP) 105ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return 0; 106ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 107ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart /* We can be called from workqueue context if the current task dies to 108ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * unlock the VMAs. In that case there's no current memory management 109ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * context so unlocking can't be performed, but the VMAs have been or 110ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * are getting destroyed anyway so it doesn't really matter. 111ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 112ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (!current || !current->mm) 113ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return lock ? -EINVAL : 0; 114ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 115ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart start = buf->vbuf.m.userptr; 116ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart end = buf->vbuf.m.userptr + buf->vbuf.length - 1; 117ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 118ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart down_write(¤t->mm->mmap_sem); 119ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_lock(¤t->mm->page_table_lock); 120ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 121ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart do { 122ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vma = find_vma(current->mm, start); 123ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vma == NULL) { 124ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = -EFAULT; 125ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto out; 126ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 127ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 128ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (lock) 129ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vma->vm_flags |= VM_LOCKED; 130ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart else 131ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vma->vm_flags &= ~VM_LOCKED; 132ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 133ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart start = vma->vm_end + 1; 134ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } while (vma->vm_end < end); 135ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 136ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (lock) 137ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vm_flags |= VM_LOCKED; 138ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart else 139ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vm_flags &= ~VM_LOCKED; 140ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 141ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartout: 142ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_unlock(¤t->mm->page_table_lock); 143ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart up_write(¤t->mm->mmap_sem); 144ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 145ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 146ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 147ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 148ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer 149ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 150ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Iterate over the vmalloc'ed area and create a scatter list entry for every 151ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * page. 152ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 153ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf) 154ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 155ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct scatterlist *sglist; 156ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int npages; 157ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 158ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart void *addr; 159ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 160ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart addr = buf->vaddr; 161ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT; 162ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 163ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sglist = vmalloc(npages * sizeof(*sglist)); 164ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (sglist == NULL) 165ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -ENOMEM; 166ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 167ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sg_init_table(sglist, npages); 168ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 169ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < npages; ++i, addr += PAGE_SIZE) { 170ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct page *page = vmalloc_to_page(addr); 171ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 172ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (page == NULL || PageHighMem(page)) { 173ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vfree(sglist); 174ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EINVAL; 175ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 176ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 177ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sg_set_page(&sglist[i], page, PAGE_SIZE, 0); 178ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 179ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 180ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->sglen = npages; 181ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->sglist = sglist; 182ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 183ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return 0; 184ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 185ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 186ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 187ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer 188ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 189ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Walk the buffer pages list and create a 1:1 mapping to a scatter list. 190ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 191ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_sglist_user(struct isp_video_buffer *buf) 192ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 193ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct scatterlist *sglist; 194ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int offset = buf->offset; 195ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 196ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 197ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sglist = vmalloc(buf->npages * sizeof(*sglist)); 198ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (sglist == NULL) 199ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -ENOMEM; 200ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 201ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sg_init_table(sglist, buf->npages); 202ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 203ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < buf->npages; ++i) { 204ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (PageHighMem(buf->pages[i])) { 205ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vfree(sglist); 206ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EINVAL; 207ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 208ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 209ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset, 210ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart offset); 211ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart offset = 0; 212ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 213ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 214ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->sglen = buf->npages; 215ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->sglist = sglist; 216ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 217ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return 0; 218ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 219ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 220ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 221ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer 222ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 223ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Create a scatter list of physically contiguous pages starting at the buffer 224ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * memory physical address. 225ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 226ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf) 227ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 228ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct scatterlist *sglist; 229ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int offset = buf->offset; 230ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long pfn = buf->paddr >> PAGE_SHIFT; 231ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 232ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 233ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sglist = vmalloc(buf->npages * sizeof(*sglist)); 234ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (sglist == NULL) 235ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -ENOMEM; 236ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 237ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sg_init_table(sglist, buf->npages); 238ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 239ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < buf->npages; ++i, ++pfn) { 240ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset, 241ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart offset); 242ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart /* PFNMAP buffers will not get DMA-mapped, set the DMA address 243ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * manually. 244ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 245ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset; 246ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart offset = 0; 247ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 248ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 249ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->sglen = buf->npages; 250ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->sglist = sglist; 251ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 252ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return 0; 253ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 254ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 255ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 256ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_cleanup - Release pages for a userspace VMA. 257ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 258ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Release pages locked by a call isp_video_buffer_prepare_user and free the 259ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * pages table. 260ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 261ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic void isp_video_buffer_cleanup(struct isp_video_buffer *buf) 262ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 263ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart enum dma_data_direction direction; 264ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 265ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 266ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->queue->ops->buffer_cleanup) 267ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->queue->ops->buffer_cleanup(buf); 268ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 269ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (!(buf->vm_flags & VM_PFNMAP)) { 270ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE 271ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ? DMA_FROM_DEVICE : DMA_TO_DEVICE; 272ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen, 273ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart direction); 274ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 275ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 276ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vfree(buf->sglist); 277ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->sglist = NULL; 278ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->sglen = 0; 279ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 280ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->pages != NULL) { 281ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_lock_vma(buf, 0); 282ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 283ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < buf->npages; ++i) 284ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart page_cache_release(buf->pages[i]); 285ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 286ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vfree(buf->pages); 287ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->pages = NULL; 288ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 289ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 290ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->npages = 0; 291ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->skip_cache = false; 292ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 293ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 294ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 295ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory. 296ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 297ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function creates a list of pages for a userspace VMA. The number of 298ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * pages is first computed based on the buffer size, and pages are then 299ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * retrieved by a call to get_user_pages. 300ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 301ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Pages are pinned to memory by get_user_pages, making them available for DMA 302ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * transfers. However, due to memory management optimization, it seems the 303ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * get_user_pages doesn't guarantee that the pinned pages will not be written 304ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * to swap and removed from the userspace mapping(s). When this happens, a page 305ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * fault can be generated when accessing those unmapped pages. 306ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 307ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * If the fault is triggered by a page table walk caused by VIPT cache 308ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * management operations, the page fault handler might oops if the MM semaphore 309ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * is held, as it can't handle kernel page faults in that case. To fix that, a 310ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * fixup entry needs to be added to the cache management code, or the userspace 311ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * VMA must be locked to avoid removing pages from the userspace mapping in the 312ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * first place. 313ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 314ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * If the number of pages retrieved is smaller than the number required by the 315ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * buffer size, the function returns -EFAULT. 316ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 317ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) 318ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 319ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long data; 320ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int first; 321ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int last; 322ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret; 323ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 324ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart data = buf->vbuf.m.userptr; 325ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart first = (data & PAGE_MASK) >> PAGE_SHIFT; 326ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT; 327ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 328ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->offset = data & ~PAGE_MASK; 329ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->npages = last - first + 1; 330ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0])); 331ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->pages == NULL) 332ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -ENOMEM; 333ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 334ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart down_read(¤t->mm->mmap_sem); 335ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = get_user_pages(current, current->mm, data & PAGE_MASK, 336ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->npages, 337ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, 338ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->pages, NULL); 339ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart up_read(¤t->mm->mmap_sem); 340ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 341ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret != buf->npages) { 3422578dfb7f767076baf04eaf5fbf35a75afb9a1a7Laurent Pinchart buf->npages = ret < 0 ? 0 : ret; 343ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_cleanup(buf); 344ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EFAULT; 345ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 346ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 347ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_lock_vma(buf, 1); 348ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 349ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_cleanup(buf); 350ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 351ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 352ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 353ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 354ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 355ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer 356ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 357ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Userspace VM_PFNMAP buffers are supported only if they are contiguous in 358ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * memory and if they span a single VMA. 359ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 360ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Return 0 if the buffer is valid, or -EFAULT otherwise. 361ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 362ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf) 363ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 364ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct vm_area_struct *vma; 365ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long prev_pfn; 366ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long this_pfn; 367ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long start; 368ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long end; 369ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart dma_addr_t pa; 370ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret = -EFAULT; 371ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 372ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart start = buf->vbuf.m.userptr; 373ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart end = buf->vbuf.m.userptr + buf->vbuf.length - 1; 374ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 375ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->offset = start & ~PAGE_MASK; 376ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; 377ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->pages = NULL; 378ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 379ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart down_read(¤t->mm->mmap_sem); 380ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vma = find_vma(current->mm, start); 381ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vma == NULL || vma->vm_end < end) 382ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 383ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 384ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (prev_pfn = 0; start <= end; start += PAGE_SIZE) { 385ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = follow_pfn(vma, start, &this_pfn); 386ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret) 387ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 388ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 389ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (prev_pfn == 0) 390ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart pa = this_pfn << PAGE_SHIFT; 391ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart else if (this_pfn != prev_pfn + 1) { 392ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = -EFAULT; 393ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 394ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 395ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 396ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart prev_pfn = this_pfn; 397ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 398ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 399ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->paddr = pa + buf->offset; 400ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = 0; 401ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 402ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 403ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart up_read(¤t->mm->mmap_sem); 404ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 405ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 406ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 407ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 408ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address 409ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 410ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function locates the VMAs for the buffer's userspace address and checks 4112d4e9d1db22117ebcd4f3353cb45292a8704d511Michael Jones * that their flags match. The only flag that we need to care for at the moment 4122d4e9d1db22117ebcd4f3353cb45292a8704d511Michael Jones * is VM_PFNMAP. 413ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 414ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * The buffer vm_flags field is set to the first VMA flags. 415ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 416ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs 417ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * have incompatible flags. 418ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 419ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf) 420ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 421ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct vm_area_struct *vma; 422ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart pgprot_t vm_page_prot; 423ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long start; 424ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long end; 425ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret = -EFAULT; 426ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 427ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart start = buf->vbuf.m.userptr; 428ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart end = buf->vbuf.m.userptr + buf->vbuf.length - 1; 429ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 430ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart down_read(¤t->mm->mmap_sem); 431ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 432ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart do { 433ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vma = find_vma(current->mm, start); 434ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vma == NULL) 435ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 436ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 437ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (start == buf->vbuf.m.userptr) { 438ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vm_flags = vma->vm_flags; 439ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vm_page_prot = vma->vm_page_prot; 440ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 441ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 442ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP) 443ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 444ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 445ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vm_page_prot != vma->vm_page_prot) 446ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 447ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 448ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart start = vma->vm_end + 1; 449ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } while (vma->vm_end < end); 450ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 451ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart /* Skip cache management to enhance performances for non-cached or 452ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * write-combining buffers. 453ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 454ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vm_page_prot == pgprot_noncached(vm_page_prot) || 455ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vm_page_prot == pgprot_writecombine(vm_page_prot)) 456ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->skip_cache = true; 457ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 458ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = 0; 459ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 460ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 461ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart up_read(¤t->mm->mmap_sem); 462ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 463ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 464ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 465ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 466ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_prepare - Make a buffer ready for operation 467ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 468ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Preparing a buffer involves: 469ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 470ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - validating VMAs (userspace buffers only) 471ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - locking pages and VMAs into memory (userspace buffers only) 472ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - building page and scatter-gather lists 473ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - mapping buffers for DMA operation 474ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * - performing driver-specific preparation 475ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 476ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * The function must be called in userspace context with a valid mm context 477ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * (this excludes cleanup paths such as sys_close when the userspace process 478ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * segfaults). 479ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 480ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_prepare(struct isp_video_buffer *buf) 481ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 482ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart enum dma_data_direction direction; 483ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret; 484ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 485ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart switch (buf->vbuf.memory) { 486ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart case V4L2_MEMORY_MMAP: 487ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_sglist_kernel(buf); 488ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart break; 489ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 490ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart case V4L2_MEMORY_USERPTR: 491ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_prepare_vm_flags(buf); 492ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 493ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 494ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 495ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->vm_flags & VM_PFNMAP) { 496ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_prepare_pfnmap(buf); 497ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 498ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 499ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 500ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_sglist_pfnmap(buf); 501ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } else { 502ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_prepare_user(buf); 503ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 504ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 505ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 506ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_sglist_user(buf); 507ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 508ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart break; 509ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 510ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart default: 511ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EINVAL; 512ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 513ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 514ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 515ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 516ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 517ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (!(buf->vm_flags & VM_PFNMAP)) { 518ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE 519ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ? DMA_FROM_DEVICE : DMA_TO_DEVICE; 520ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen, 521ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart direction); 522ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret != buf->sglen) { 523ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = -EFAULT; 524ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 525ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 526ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 527ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 528ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->queue->ops->buffer_prepare) 529ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = buf->queue->ops->buffer_prepare(buf); 530ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 531ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 532ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) { 533ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_cleanup(buf); 534ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 535ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 536ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 537ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 538ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 539ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 540ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 541ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_queue_query - Query the status of a given buffer 542ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 543ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Locking: must be called with the queue lock held. 544ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 545ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic void isp_video_buffer_query(struct isp_video_buffer *buf, 546ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct v4l2_buffer *vbuf) 547ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 548ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart memcpy(vbuf, &buf->vbuf, sizeof(*vbuf)); 549ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 550ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->vma_use_count) 551ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vbuf->flags |= V4L2_BUF_FLAG_MAPPED; 552ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 553ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart switch (buf->state) { 554ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart case ISP_BUF_STATE_ERROR: 555ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vbuf->flags |= V4L2_BUF_FLAG_ERROR; 556ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart case ISP_BUF_STATE_DONE: 557ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vbuf->flags |= V4L2_BUF_FLAG_DONE; 558ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart case ISP_BUF_STATE_QUEUED: 559ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart case ISP_BUF_STATE_ACTIVE: 560ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vbuf->flags |= V4L2_BUF_FLAG_QUEUED; 561ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart break; 562ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart case ISP_BUF_STATE_IDLE: 563ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart default: 564ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart break; 565ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 566ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 567ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 568ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 569ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_buffer_wait - Wait for a buffer to be ready 570ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 571ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * In non-blocking mode, return immediately with 0 if the buffer is ready or 572ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * -EAGAIN if the buffer is in the QUEUED or ACTIVE state. 573ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 574ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait 575ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * queue using the same condition. 576ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 577ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking) 578ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 579ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (nonblocking) { 580ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return (buf->state != ISP_BUF_STATE_QUEUED && 581ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->state != ISP_BUF_STATE_ACTIVE) 582ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ? 0 : -EAGAIN; 583ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 584ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 585ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return wait_event_interruptible(buf->wait, 586ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->state != ISP_BUF_STATE_QUEUED && 587ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->state != ISP_BUF_STATE_ACTIVE); 588ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 589ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 590ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* ----------------------------------------------------------------------------- 591ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Queue management 592ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 593ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 594ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 595ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_queue_free - Free video buffers memory 596ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 597ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Buffers can only be freed if the queue isn't streaming and if no buffer is 598ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * mapped to userspace. Return -EBUSY if those conditions aren't statisfied. 599ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 600ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function must be called with the queue lock held. 601ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 602ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_queue_free(struct isp_video_queue *queue) 603ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 604ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 605ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 606ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (queue->streaming) 607ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EBUSY; 608ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 609ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < queue->count; ++i) { 610ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (queue->buffers[i]->vma_use_count != 0) 611ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EBUSY; 612ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 613ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 614ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < queue->count; ++i) { 615ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf = queue->buffers[i]; 616ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 617ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_cleanup(buf); 618ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 619ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vfree(buf->vaddr); 620ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vaddr = NULL; 621ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 622ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart kfree(buf); 623ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->buffers[i] = NULL; 624ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 625ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 626ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart INIT_LIST_HEAD(&queue->queue); 627ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->count = 0; 628ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return 0; 629ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 630ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 631ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* 632ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * isp_video_queue_alloc - Allocate video buffers memory 633ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 634ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function must be called with the queue lock held. 635ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 636ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic int isp_video_queue_alloc(struct isp_video_queue *queue, 637ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int nbuffers, 638ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int size, enum v4l2_memory memory) 639ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 640ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf; 641ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 642ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart void *mem; 643ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret; 644ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 645ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart /* Start by freeing the buffers. */ 646ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_queue_free(queue); 647ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 648ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 649ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 650ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart /* Bail out of no buffers should be allocated. */ 651ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (nbuffers == 0) 652ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return 0; 653ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 654ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart /* Initialize the allocated buffers. */ 655ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < nbuffers; ++i) { 656ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf = kzalloc(queue->bufsize, GFP_KERNEL); 657ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf == NULL) 658ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart break; 659ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 660ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (memory == V4L2_MEMORY_MMAP) { 661ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart /* Allocate video buffers memory for mmap mode. Align 662ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * the size to the page size. 663ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 664ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mem = vmalloc_32_user(PAGE_ALIGN(size)); 665ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (mem == NULL) { 666ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart kfree(buf); 667ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart break; 668ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 669ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 670ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.m.offset = i * PAGE_ALIGN(size); 671ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vaddr = mem; 672ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 673ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 674ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.index = i; 675ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.length = size; 676ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.type = queue->type; 677ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.field = V4L2_FIELD_NONE; 678ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.memory = memory; 679ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 680ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->queue = queue; 681ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart init_waitqueue_head(&buf->wait); 682ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 683ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->buffers[i] = buf; 684ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 685ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 686ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (i == 0) 687ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -ENOMEM; 688ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 689ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->count = i; 690ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return nbuffers; 691ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 692ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 693ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 694ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_cleanup - Clean up the video buffers queue 695ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * @queue: Video buffers queue 696ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 697ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Free all allocated resources and clean up the video buffers queue. The queue 698ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * must not be busy (no ongoing video stream) and buffers must have been 699ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * unmapped. 700ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 701ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been 702ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * unmapped. 703ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 704ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartint omap3isp_video_queue_cleanup(struct isp_video_queue *queue) 705ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 706ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return isp_video_queue_free(queue); 707ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 708ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 709ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 710ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_init - Initialize the video buffers queue 711ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * @queue: Video buffers queue 712ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * @type: V4L2 buffer type (capture or output) 713ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * @ops: Driver-specific queue operations 714ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * @dev: Device used for DMA operations 715ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * @bufsize: Size of the driver-specific buffer structure 716ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 717ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Initialize the video buffers queue with the supplied parameters. 718ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 719ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or 720ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet. 721ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 722ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Buffer objects will be allocated using the given buffer size to allow room 723ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * for driver-specific fields. Driver-specific buffer structures must start 724ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * with a struct isp_video_buffer field. Drivers with no driver-specific buffer 725ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * structure must pass the size of the isp_video_buffer structure in the bufsize 726ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * parameter. 727ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 728ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Return 0 on success. 729ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 730ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartint omap3isp_video_queue_init(struct isp_video_queue *queue, 731ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart enum v4l2_buf_type type, 732ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart const struct isp_video_queue_operations *ops, 733ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct device *dev, unsigned int bufsize) 734ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 735ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart INIT_LIST_HEAD(&queue->queue); 736ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_init(&queue->lock); 737ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_lock_init(&queue->irqlock); 738ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 739ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->type = type; 740ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->ops = ops; 741ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->dev = dev; 742ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->bufsize = bufsize; 743ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 744ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return 0; 745ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 746ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 747ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/* ----------------------------------------------------------------------------- 748ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * V4L2 operations 749ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 750ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 751ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 752ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_reqbufs - Allocate video buffers memory 753ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 754ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It 755ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * allocated video buffer objects and, for MMAP buffers, buffer memory. 756ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 757ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * If the number of buffers is 0, all buffers are freed and the function returns 758ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * without performing any allocation. 759ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 760ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * If the number of buffers is not 0, currently allocated buffers (if any) are 761ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * freed and the requested number of buffers are allocated. Depending on 762ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * driver-specific requirements and on memory availability, a number of buffer 763ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * smaller or bigger than requested can be allocated. This isn't considered as 764ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * an error. 765ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 766ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Return 0 on success or one of the following error codes: 767ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 768ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * -EINVAL if the buffer type or index are invalid 769ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * -EBUSY if the queue is busy (streaming or buffers mapped) 770ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition 771ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 772ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartint omap3isp_video_queue_reqbufs(struct isp_video_queue *queue, 773ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct v4l2_requestbuffers *rb) 774ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 775ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int nbuffers = rb->count; 776ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int size; 777ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret; 778ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 779ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (rb->type != queue->type) 780ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EINVAL; 781ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 782ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->ops->queue_prepare(queue, &nbuffers, &size); 783ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (size == 0) 784ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EINVAL; 785ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 786ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS); 787ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 788ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 789ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 790ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory); 791ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 792ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 793ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 794ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart rb->count = ret; 795ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = 0; 796ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 797ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 798ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 799ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 800ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 801ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 802ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 803ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue 804ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 805ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It 806ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * returns the status of a given video buffer. 807ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 808ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Return 0 on success or -EINVAL if the buffer type or index are invalid. 809ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 810ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartint omap3isp_video_queue_querybuf(struct isp_video_queue *queue, 811ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct v4l2_buffer *vbuf) 812ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 813ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf; 814ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret = 0; 815ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 816ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vbuf->type != queue->type) 817ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EINVAL; 818ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 819ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 820ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 821ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vbuf->index >= queue->count) { 822ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = -EINVAL; 823ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 824ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 825ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 826ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf = queue->buffers[vbuf->index]; 827ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_query(buf, vbuf); 828ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 829ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 830ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 831ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 832ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 833ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 834ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 835ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_qbuf - Queue a buffer 836ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 837ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used as a VIDIOC_QBUF ioctl handler. 838ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 839ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * The v4l2_buffer structure passed from userspace is first sanity tested. If 840ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * sane, the buffer is then processed and added to the main queue and, if the 841ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * queue is streaming, to the IRQ queue. 842ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 843ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Before being enqueued, USERPTR buffers are checked for address changes. If 844ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * the buffer has a different userspace address, the old memory area is unlocked 845ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * and the new memory area is locked. 846ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 847ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartint omap3isp_video_queue_qbuf(struct isp_video_queue *queue, 848ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct v4l2_buffer *vbuf) 849ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 850ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf; 851ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long flags; 852ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret = -EINVAL; 853ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 854ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vbuf->type != queue->type) 855ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 856ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 857ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 858ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 859ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vbuf->index >= queue->count) 860ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 861ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 862ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf = queue->buffers[vbuf->index]; 863ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 864ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vbuf->memory != buf->vbuf.memory) 865ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 866ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 867ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->state != ISP_BUF_STATE_IDLE) 868ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 869ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 870ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vbuf->memory == V4L2_MEMORY_USERPTR && 87161e6561fae573c3c618118a71ff966ddb14299daMichael Jones vbuf->length < buf->vbuf.length) 87261e6561fae573c3c618118a71ff966ddb14299daMichael Jones goto done; 87361e6561fae573c3c618118a71ff966ddb14299daMichael Jones 87461e6561fae573c3c618118a71ff966ddb14299daMichael Jones if (vbuf->memory == V4L2_MEMORY_USERPTR && 875ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vbuf->m.userptr != buf->vbuf.m.userptr) { 876ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_cleanup(buf); 877ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vbuf.m.userptr = vbuf->m.userptr; 878ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->prepared = 0; 879ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 880ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 881ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (!buf->prepared) { 882ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_prepare(buf); 883ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 884ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 885ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->prepared = 1; 886ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 887ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 888ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_cache_sync(buf); 889ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 890ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->state = ISP_BUF_STATE_QUEUED; 891ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart list_add_tail(&buf->stream, &queue->queue); 892ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 893ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (queue->streaming) { 894ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_lock_irqsave(&queue->irqlock, flags); 895ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->ops->buffer_queue(buf); 896ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_unlock_irqrestore(&queue->irqlock, flags); 897ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 898ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 899ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = 0; 900ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 901ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 902ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 903ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 904ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 905ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 906ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 907ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_dqbuf - Dequeue a buffer 908ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 909ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used as a VIDIOC_DQBUF ioctl handler. 910ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 911ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * The v4l2_buffer structure passed from userspace is first sanity tested. If 912ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * sane, the buffer is then processed and added to the main queue and, if the 913ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * queue is streaming, to the IRQ queue. 914ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 915ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Before being enqueued, USERPTR buffers are checked for address changes. If 916ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * the buffer has a different userspace address, the old memory area is unlocked 917ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * and the new memory area is locked. 918ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 919ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartint omap3isp_video_queue_dqbuf(struct isp_video_queue *queue, 920ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct v4l2_buffer *vbuf, int nonblocking) 921ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 922ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf; 923ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret; 924ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 925ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (vbuf->type != queue->type) 926ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return -EINVAL; 927ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 928ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 929ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 930ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (list_empty(&queue->queue)) { 931ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = -EINVAL; 932ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 933ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 934ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 935ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream); 936ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = isp_video_buffer_wait(buf, nonblocking); 937ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 938ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 939ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 940ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart list_del(&buf->stream); 941ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 942ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_buffer_query(buf, vbuf); 943ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->state = ISP_BUF_STATE_IDLE; 944ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED; 945ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 946ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 947ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 948ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 949ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 950ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 951ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 952ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_streamon - Start streaming 953ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 954ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It 955ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * starts streaming on the queue and calls the buffer_queue operation for all 956ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * queued buffers. 957ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 958ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Return 0 on success. 959ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 960ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartint omap3isp_video_queue_streamon(struct isp_video_queue *queue) 961ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 962ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf; 963ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long flags; 964ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 965ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 966ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 967ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (queue->streaming) 968ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 969ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 970ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->streaming = 1; 971ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 972ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_lock_irqsave(&queue->irqlock, flags); 973ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart list_for_each_entry(buf, &queue->queue, stream) 974ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->ops->buffer_queue(buf); 975ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_unlock_irqrestore(&queue->irqlock, flags); 976ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 977ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 978ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 979ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return 0; 980ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 981ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 982ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 983ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_streamoff - Stop streaming 984ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 985ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It 986ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * stops streaming on the queue and wakes up all the buffers. 987ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 988ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Drivers must stop the hardware and synchronize with interrupt handlers and/or 989ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * delayed works before calling this function to make sure no buffer will be 990ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * touched by the driver and/or hardware. 991ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 992ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartvoid omap3isp_video_queue_streamoff(struct isp_video_queue *queue) 993ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 994ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf; 995ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long flags; 996ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 997ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 998ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 999ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1000ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (!queue->streaming) 1001ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 1002ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1003ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart queue->streaming = 0; 1004ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1005ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_lock_irqsave(&queue->irqlock, flags); 1006ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < queue->count; ++i) { 1007ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf = queue->buffers[i]; 1008ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1009ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->state == ISP_BUF_STATE_ACTIVE) 1010ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart wake_up(&buf->wait); 1011ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1012ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->state = ISP_BUF_STATE_IDLE; 1013ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 1014ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart spin_unlock_irqrestore(&queue->irqlock, flags); 1015ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1016ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart INIT_LIST_HEAD(&queue->queue); 1017ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1018ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 1019ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 1020ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 1021ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1022ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 1023ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE 1024ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 1025ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used with suspend/resume operations. It 1026ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * discards all 'done' buffers as they would be too old to be requested after 1027ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * resume. 1028ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 1029ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Drivers must stop the hardware and synchronize with interrupt handlers and/or 1030ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * delayed works before calling this function to make sure no buffer will be 1031ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * touched by the driver and/or hardware. 1032ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 1033ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartvoid omap3isp_video_queue_discard_done(struct isp_video_queue *queue) 1034ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 1035ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf; 1036ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 1037ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1038ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 1039ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1040ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (!queue->streaming) 1041ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 1042ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1043ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < queue->count; ++i) { 1044ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf = queue->buffers[i]; 1045ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1046ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->state == ISP_BUF_STATE_DONE) 1047ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->state = ISP_BUF_STATE_ERROR; 1048ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 1049ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1050ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 1051ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 1052ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 1053ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1054ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic void isp_video_queue_vm_open(struct vm_area_struct *vma) 1055ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 1056ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf = vma->vm_private_data; 1057ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1058ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vma_use_count++; 1059ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 1060ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1061ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic void isp_video_queue_vm_close(struct vm_area_struct *vma) 1062ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 1063ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf = vma->vm_private_data; 1064ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1065ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->vma_use_count--; 1066ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 1067ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1068ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartstatic const struct vm_operations_struct isp_video_queue_vm_ops = { 1069ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart .open = isp_video_queue_vm_open, 1070ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart .close = isp_video_queue_vm_close, 1071ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart}; 1072ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1073ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 1074ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_mmap - Map buffers to userspace 1075ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 1076ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used as an mmap() file operation handler. It 1077ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * maps a buffer to userspace based on the VMA offset. 1078ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 1079ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * Only buffers of memory type MMAP are supported. 1080ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 1081ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartint omap3isp_video_queue_mmap(struct isp_video_queue *queue, 1082ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct vm_area_struct *vma) 1083ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 1084ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *uninitialized_var(buf); 1085ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned long size; 1086ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int i; 1087ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart int ret = 0; 1088ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1089ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 1090ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1091ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart for (i = 0; i < queue->count; ++i) { 1092ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf = queue->buffers[i]; 1093ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) 1094ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart break; 1095ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 1096ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1097ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (i == queue->count) { 1098ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = -EINVAL; 1099ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 1100ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 1101ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1102ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart size = vma->vm_end - vma->vm_start; 1103ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1104ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->vbuf.memory != V4L2_MEMORY_MMAP || 1105ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart size != PAGE_ALIGN(buf->vbuf.length)) { 1106ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = -EINVAL; 1107ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 1108ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 1109ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1110ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart ret = remap_vmalloc_range(vma, buf->vaddr, 0); 1111ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (ret < 0) 1112ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 1113ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1114ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vma->vm_ops = &isp_video_queue_vm_ops; 1115ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart vma->vm_private_data = buf; 1116ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart isp_video_queue_vm_open(vma); 1117ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1118ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 1119ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 1120ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return ret; 1121ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 1122ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1123ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart/** 1124ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * omap3isp_video_queue_poll - Poll video queue state 1125ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 1126ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * This function is intended to be used as a poll() file operation handler. It 1127ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * polls the state of the video buffer at the front of the queue and returns an 1128ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * events mask. 1129ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * 1130ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart * If no buffer is present at the front of the queue, POLLERR is returned. 1131ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart */ 1132ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartunsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue, 1133ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct file *file, poll_table *wait) 1134ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart{ 1135ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart struct isp_video_buffer *buf; 1136ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart unsigned int mask = 0; 1137ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1138ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_lock(&queue->lock); 1139ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (list_empty(&queue->queue)) { 1140ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mask |= POLLERR; 1141ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart goto done; 1142ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 1143ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream); 1144ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1145ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart poll_wait(file, &buf->wait, wait); 1146ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (buf->state == ISP_BUF_STATE_DONE || 1147ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart buf->state == ISP_BUF_STATE_ERROR) { 1148ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1149ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mask |= POLLIN | POLLRDNORM; 1150ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart else 1151ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mask |= POLLOUT | POLLWRNORM; 1152ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart } 1153ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart 1154ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchartdone: 1155ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart mutex_unlock(&queue->lock); 1156ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart return mask; 1157ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart} 1158