Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * Video for Linux Two
4 : : *
5 : : * A generic video device interface for the LINUX operating system
6 : : * using a set of device structures/vectors for low level operations.
7 : : *
8 : : * This file replaces the videodev.c file that comes with the
9 : : * regular kernel distribution.
10 : : *
11 : : * Author: Bill Dirks <bill@thedirks.org>
12 : : * based on code by Alan Cox, <alan@cymru.net>
13 : : */
14 : :
15 : : /*
16 : : * Video capture interface for Linux
17 : : *
18 : : * A generic video device interface for the LINUX operating system
19 : : * using a set of device structures/vectors for low level operations.
20 : : *
21 : : * Author: Alan Cox, <alan@lxorguk.ukuu.org.uk>
22 : : *
23 : : * Fixes:
24 : : */
25 : :
26 : : /*
27 : : * Video4linux 1/2 integration by Justin Schoeman
28 : : * <justin@suntiger.ee.up.ac.za>
29 : : * 2.4 PROCFS support ported from 2.4 kernels by
30 : : * Iñaki García Etxebarria <garetxe@euskalnet.net>
31 : : * Makefile fix by "W. Michael Petullo" <mike@flyn.org>
32 : : * 2.4 devfs support ported from 2.4 kernels by
33 : : * Dan Merillat <dan@merillat.org>
34 : : * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman)
35 : : */
36 : :
37 : : #include <linux/module.h>
38 : : #include <linux/types.h>
39 : : #include <linux/kernel.h>
40 : : #include <linux/mm.h>
41 : : #include <linux/string.h>
42 : : #include <linux/errno.h>
43 : : #include <linux/uaccess.h>
44 : : #include <asm/pgtable.h>
45 : : #include <asm/io.h>
46 : : #include <asm/div64.h>
47 : : #include <media/v4l2-common.h>
48 : : #include <media/v4l2-device.h>
49 : : #include <media/v4l2-ctrls.h>
50 : :
51 : : #include <linux/videodev2.h>
52 : :
53 : : /*
54 : : *
55 : : * V 4 L 2 D R I V E R H E L P E R A P I
56 : : *
57 : : */
58 : :
59 : : /*
60 : : * Video Standard Operations (contributed by Michael Schimek)
61 : : */
62 : :
63 : : /* Helper functions for control handling */
64 : :
65 : : /* Fill in a struct v4l2_queryctrl */
66 : 0 : int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _step, s32 _def)
67 : : {
68 : : const char *name;
69 : 0 : s64 min = _min;
70 : 0 : s64 max = _max;
71 : 0 : u64 step = _step;
72 : 0 : s64 def = _def;
73 : :
74 : 0 : v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
75 : 0 : &min, &max, &step, &def, &qctrl->flags);
76 : :
77 : 0 : if (name == NULL)
78 : : return -EINVAL;
79 : :
80 : 0 : qctrl->minimum = min;
81 : 0 : qctrl->maximum = max;
82 : 0 : qctrl->step = step;
83 : 0 : qctrl->default_value = def;
84 : 0 : qctrl->reserved[0] = qctrl->reserved[1] = 0;
85 : 0 : strscpy(qctrl->name, name, sizeof(qctrl->name));
86 : 0 : return 0;
87 : : }
88 : : EXPORT_SYMBOL(v4l2_ctrl_query_fill);
89 : :
90 : : /* Clamp x to be between min and max, aligned to a multiple of 2^align. min
91 : : * and max don't have to be aligned, but there must be at least one valid
92 : : * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples
93 : : * of 16 between 17 and 31. */
94 : : static unsigned int clamp_align(unsigned int x, unsigned int min,
95 : : unsigned int max, unsigned int align)
96 : : {
97 : : /* Bits that must be zero to be aligned */
98 : 0 : unsigned int mask = ~((1 << align) - 1);
99 : :
100 : : /* Clamp to aligned min and max */
101 : 0 : x = clamp(x, (min + ~mask) & mask, max & mask);
102 : :
103 : : /* Round to nearest aligned value */
104 : 0 : if (align)
105 : 0 : x = (x + (1 << (align - 1))) & mask;
106 : :
107 : : return x;
108 : : }
109 : :
110 : : static unsigned int clamp_roundup(unsigned int x, unsigned int min,
111 : : unsigned int max, unsigned int alignment)
112 : : {
113 : 0 : x = clamp(x, min, max);
114 : 0 : if (alignment)
115 : 0 : x = round_up(x, alignment);
116 : :
117 : : return x;
118 : : }
119 : :
120 : 0 : void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
121 : : unsigned int walign,
122 : : u32 *h, unsigned int hmin, unsigned int hmax,
123 : : unsigned int halign, unsigned int salign)
124 : : {
125 : 0 : *w = clamp_align(*w, wmin, wmax, walign);
126 : 0 : *h = clamp_align(*h, hmin, hmax, halign);
127 : :
128 : : /* Usually we don't need to align the size and are done now. */
129 : 0 : if (!salign)
130 : 0 : return;
131 : :
132 : : /* How much alignment do we have? */
133 : 0 : walign = __ffs(*w);
134 : : halign = __ffs(*h);
135 : : /* Enough to satisfy the image alignment? */
136 : 0 : if (walign + halign < salign) {
137 : : /* Max walign where there is still a valid width */
138 : 0 : unsigned int wmaxa = __fls(wmax ^ (wmin - 1));
139 : : /* Max halign where there is still a valid height */
140 : 0 : unsigned int hmaxa = __fls(hmax ^ (hmin - 1));
141 : :
142 : : /* up the smaller alignment until we have enough */
143 : : do {
144 : 0 : if (halign >= hmaxa ||
145 : 0 : (walign <= halign && walign < wmaxa)) {
146 : 0 : *w = clamp_align(*w, wmin, wmax, walign + 1);
147 : 0 : walign = __ffs(*w);
148 : : } else {
149 : 0 : *h = clamp_align(*h, hmin, hmax, halign + 1);
150 : : halign = __ffs(*h);
151 : : }
152 : 0 : } while (halign + walign < salign);
153 : : }
154 : : }
155 : : EXPORT_SYMBOL_GPL(v4l_bound_align_image);
156 : :
157 : : const void *
158 : 0 : __v4l2_find_nearest_size(const void *array, size_t array_size,
159 : : size_t entry_size, size_t width_offset,
160 : : size_t height_offset, s32 width, s32 height)
161 : : {
162 : : u32 error, min_error = U32_MAX;
163 : : const void *best = NULL;
164 : : unsigned int i;
165 : :
166 : 0 : if (!array)
167 : : return NULL;
168 : :
169 : 0 : for (i = 0; i < array_size; i++, array += entry_size) {
170 : 0 : const u32 *entry_width = array + width_offset;
171 : 0 : const u32 *entry_height = array + height_offset;
172 : :
173 : 0 : error = abs(*entry_width - width) + abs(*entry_height - height);
174 : 0 : if (error > min_error)
175 : 0 : continue;
176 : :
177 : : min_error = error;
178 : : best = array;
179 : 0 : if (!error)
180 : : break;
181 : : }
182 : :
183 : 0 : return best;
184 : : }
185 : : EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size);
186 : :
187 : 0 : int v4l2_g_parm_cap(struct video_device *vdev,
188 : : struct v4l2_subdev *sd, struct v4l2_streamparm *a)
189 : : {
190 : 0 : struct v4l2_subdev_frame_interval ival = { 0 };
191 : : int ret;
192 : :
193 : 0 : if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
194 : : a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
195 : : return -EINVAL;
196 : :
197 : 0 : if (vdev->device_caps & V4L2_CAP_READWRITE)
198 : 0 : a->parm.capture.readbuffers = 2;
199 : 0 : if (v4l2_subdev_has_op(sd, video, g_frame_interval))
200 : 0 : a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
201 : 0 : ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival);
202 : 0 : if (!ret)
203 : 0 : a->parm.capture.timeperframe = ival.interval;
204 : 0 : return ret;
205 : : }
206 : : EXPORT_SYMBOL_GPL(v4l2_g_parm_cap);
207 : :
208 : 0 : int v4l2_s_parm_cap(struct video_device *vdev,
209 : : struct v4l2_subdev *sd, struct v4l2_streamparm *a)
210 : : {
211 : 0 : struct v4l2_subdev_frame_interval ival = {
212 : : .interval = a->parm.capture.timeperframe
213 : : };
214 : : int ret;
215 : :
216 : 0 : if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
217 : : a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
218 : : return -EINVAL;
219 : :
220 : 0 : memset(&a->parm, 0, sizeof(a->parm));
221 : 0 : if (vdev->device_caps & V4L2_CAP_READWRITE)
222 : 0 : a->parm.capture.readbuffers = 2;
223 : : else
224 : 0 : a->parm.capture.readbuffers = 0;
225 : :
226 : 0 : if (v4l2_subdev_has_op(sd, video, g_frame_interval))
227 : 0 : a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
228 : 0 : ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival);
229 : 0 : if (!ret)
230 : 0 : a->parm.capture.timeperframe = ival.interval;
231 : 0 : return ret;
232 : : }
233 : : EXPORT_SYMBOL_GPL(v4l2_s_parm_cap);
234 : :
235 : 0 : const struct v4l2_format_info *v4l2_format_info(u32 format)
236 : : {
237 : : static const struct v4l2_format_info formats[] = {
238 : : /* RGB formats */
239 : : { .format = V4L2_PIX_FMT_BGR24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
240 : : { .format = V4L2_PIX_FMT_RGB24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
241 : : { .format = V4L2_PIX_FMT_HSV24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
242 : : { .format = V4L2_PIX_FMT_BGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
243 : : { .format = V4L2_PIX_FMT_XBGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
244 : : { .format = V4L2_PIX_FMT_BGRX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
245 : : { .format = V4L2_PIX_FMT_RGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
246 : : { .format = V4L2_PIX_FMT_XRGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
247 : : { .format = V4L2_PIX_FMT_RGBX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
248 : : { .format = V4L2_PIX_FMT_HSV32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
249 : : { .format = V4L2_PIX_FMT_ARGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
250 : : { .format = V4L2_PIX_FMT_RGBA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
251 : : { .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
252 : : { .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
253 : : { .format = V4L2_PIX_FMT_GREY, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
254 : : { .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
255 : : { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
256 : :
257 : : /* YUV packed formats */
258 : : { .format = V4L2_PIX_FMT_YUYV, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
259 : : { .format = V4L2_PIX_FMT_YVYU, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
260 : : { .format = V4L2_PIX_FMT_UYVY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
261 : : { .format = V4L2_PIX_FMT_VYUY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
262 : :
263 : : /* YUV planar formats */
264 : : { .format = V4L2_PIX_FMT_NV12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
265 : : { .format = V4L2_PIX_FMT_NV21, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
266 : : { .format = V4L2_PIX_FMT_NV16, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
267 : : { .format = V4L2_PIX_FMT_NV61, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
268 : : { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
269 : : { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
270 : :
271 : : { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
272 : : { .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
273 : : { .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 },
274 : : { .format = V4L2_PIX_FMT_YUV420, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
275 : : { .format = V4L2_PIX_FMT_YVU420, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
276 : : { .format = V4L2_PIX_FMT_YUV422P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 },
277 : :
278 : : /* YUV planar formats, non contiguous variant */
279 : : { .format = V4L2_PIX_FMT_YUV420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
280 : : { .format = V4L2_PIX_FMT_YVU420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
281 : : { .format = V4L2_PIX_FMT_YUV422M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 },
282 : : { .format = V4L2_PIX_FMT_YVU422M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 },
283 : : { .format = V4L2_PIX_FMT_YUV444M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 },
284 : : { .format = V4L2_PIX_FMT_YVU444M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 },
285 : :
286 : : { .format = V4L2_PIX_FMT_NV12M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
287 : : { .format = V4L2_PIX_FMT_NV21M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
288 : : { .format = V4L2_PIX_FMT_NV16M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
289 : : { .format = V4L2_PIX_FMT_NV61M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
290 : :
291 : : /* Bayer RGB formats */
292 : : { .format = V4L2_PIX_FMT_SBGGR8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
293 : : { .format = V4L2_PIX_FMT_SGBRG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
294 : : { .format = V4L2_PIX_FMT_SGRBG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
295 : : { .format = V4L2_PIX_FMT_SRGGB8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
296 : : { .format = V4L2_PIX_FMT_SBGGR10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
297 : : { .format = V4L2_PIX_FMT_SGBRG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
298 : : { .format = V4L2_PIX_FMT_SGRBG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
299 : : { .format = V4L2_PIX_FMT_SRGGB10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
300 : : { .format = V4L2_PIX_FMT_SBGGR10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
301 : : { .format = V4L2_PIX_FMT_SGBRG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
302 : : { .format = V4L2_PIX_FMT_SGRBG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
303 : : { .format = V4L2_PIX_FMT_SRGGB10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
304 : : { .format = V4L2_PIX_FMT_SBGGR10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
305 : : { .format = V4L2_PIX_FMT_SGBRG10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
306 : : { .format = V4L2_PIX_FMT_SGRBG10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
307 : : { .format = V4L2_PIX_FMT_SRGGB10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
308 : : { .format = V4L2_PIX_FMT_SBGGR12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
309 : : { .format = V4L2_PIX_FMT_SGBRG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
310 : : { .format = V4L2_PIX_FMT_SGRBG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
311 : : { .format = V4L2_PIX_FMT_SRGGB12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
312 : : };
313 : : unsigned int i;
314 : :
315 : 0 : for (i = 0; i < ARRAY_SIZE(formats); ++i)
316 : 0 : if (formats[i].format == format)
317 : 0 : return &formats[i];
318 : : return NULL;
319 : : }
320 : : EXPORT_SYMBOL(v4l2_format_info);
321 : :
322 : : static inline unsigned int v4l2_format_block_width(const struct v4l2_format_info *info, int plane)
323 : : {
324 : 0 : if (!info->block_w[plane])
325 : : return 1;
326 : 0 : return info->block_w[plane];
327 : : }
328 : :
329 : : static inline unsigned int v4l2_format_block_height(const struct v4l2_format_info *info, int plane)
330 : : {
331 : 0 : if (!info->block_h[plane])
332 : : return 1;
333 : 0 : return info->block_h[plane];
334 : : }
335 : :
336 : 0 : void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
337 : : const struct v4l2_frmsize_stepwise *frmsize)
338 : : {
339 : 0 : if (!frmsize)
340 : 0 : return;
341 : :
342 : : /*
343 : : * Clamp width/height to meet min/max constraints and round it up to
344 : : * macroblock alignment.
345 : : */
346 : 0 : *width = clamp_roundup(*width, frmsize->min_width, frmsize->max_width,
347 : : frmsize->step_width);
348 : 0 : *height = clamp_roundup(*height, frmsize->min_height, frmsize->max_height,
349 : : frmsize->step_height);
350 : : }
351 : : EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
352 : :
353 : 0 : int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
354 : : u32 pixelformat, u32 width, u32 height)
355 : : {
356 : : const struct v4l2_format_info *info;
357 : : struct v4l2_plane_pix_format *plane;
358 : : int i;
359 : :
360 : : info = v4l2_format_info(pixelformat);
361 : 0 : if (!info)
362 : : return -EINVAL;
363 : :
364 : 0 : pixfmt->width = width;
365 : 0 : pixfmt->height = height;
366 : 0 : pixfmt->pixelformat = pixelformat;
367 : 0 : pixfmt->num_planes = info->mem_planes;
368 : :
369 : 0 : if (info->mem_planes == 1) {
370 : : plane = &pixfmt->plane_fmt[0];
371 : 0 : plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
372 : 0 : plane->sizeimage = 0;
373 : :
374 : 0 : for (i = 0; i < info->comp_planes; i++) {
375 : 0 : unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
376 : 0 : unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
377 : : unsigned int aligned_width;
378 : : unsigned int aligned_height;
379 : :
380 : 0 : aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
381 : 0 : aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
382 : :
383 : 0 : plane->sizeimage += info->bpp[i] *
384 : 0 : DIV_ROUND_UP(aligned_width, hdiv) *
385 : 0 : DIV_ROUND_UP(aligned_height, vdiv);
386 : : }
387 : : } else {
388 : 0 : for (i = 0; i < info->comp_planes; i++) {
389 : 0 : unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
390 : 0 : unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
391 : : unsigned int aligned_width;
392 : : unsigned int aligned_height;
393 : :
394 : 0 : aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
395 : 0 : aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
396 : :
397 : : plane = &pixfmt->plane_fmt[i];
398 : 0 : plane->bytesperline =
399 : 0 : info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv);
400 : 0 : plane->sizeimage =
401 : 0 : plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv);
402 : : }
403 : : }
404 : : return 0;
405 : : }
406 : : EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
407 : :
408 : 0 : int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
409 : : u32 width, u32 height)
410 : : {
411 : : const struct v4l2_format_info *info;
412 : : int i;
413 : :
414 : : info = v4l2_format_info(pixelformat);
415 : 0 : if (!info)
416 : : return -EINVAL;
417 : :
418 : : /* Single planar API cannot be used for multi plane formats. */
419 : 0 : if (info->mem_planes > 1)
420 : : return -EINVAL;
421 : :
422 : 0 : pixfmt->width = width;
423 : 0 : pixfmt->height = height;
424 : 0 : pixfmt->pixelformat = pixelformat;
425 : 0 : pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
426 : 0 : pixfmt->sizeimage = 0;
427 : :
428 : 0 : for (i = 0; i < info->comp_planes; i++) {
429 : 0 : unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
430 : 0 : unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
431 : : unsigned int aligned_width;
432 : : unsigned int aligned_height;
433 : :
434 : 0 : aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
435 : 0 : aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
436 : :
437 : 0 : pixfmt->sizeimage += info->bpp[i] *
438 : 0 : DIV_ROUND_UP(aligned_width, hdiv) *
439 : 0 : DIV_ROUND_UP(aligned_height, vdiv);
440 : : }
441 : : return 0;
442 : : }
443 : : EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
|