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(&current->mm->mmap_sem);
119ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart	spin_lock(&current->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(&current->mm->page_table_lock);
143ad614acb7eca429891313f57bafbe5b3924a5aaeLaurent Pinchart	up_write(&current->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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->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