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