Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Video for Linux Two
0004  *
0005  *  A generic video device interface for the LINUX operating system
0006  *  using a set of device structures/vectors for low level operations.
0007  *
0008  *  This file replaces the videodev.c file that comes with the
0009  *  regular kernel distribution.
0010  *
0011  * Author:  Bill Dirks <bill@thedirks.org>
0012  *      based on code by Alan Cox, <alan@cymru.net>
0013  */
0014 
0015 /*
0016  * Video capture interface for Linux
0017  *
0018  *  A generic video device interface for the LINUX operating system
0019  *  using a set of device structures/vectors for low level operations.
0020  *
0021  * Author:  Alan Cox, <alan@lxorguk.ukuu.org.uk>
0022  *
0023  * Fixes:
0024  */
0025 
0026 /*
0027  * Video4linux 1/2 integration by Justin Schoeman
0028  * <justin@suntiger.ee.up.ac.za>
0029  * 2.4 PROCFS support ported from 2.4 kernels by
0030  *  Iñaki García Etxebarria <garetxe@euskalnet.net>
0031  * Makefile fix by "W. Michael Petullo" <mike@flyn.org>
0032  * 2.4 devfs support ported from 2.4 kernels by
0033  *  Dan Merillat <dan@merillat.org>
0034  * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman)
0035  */
0036 
0037 #include <linux/module.h>
0038 #include <linux/types.h>
0039 #include <linux/kernel.h>
0040 #include <linux/mm.h>
0041 #include <linux/string.h>
0042 #include <linux/errno.h>
0043 #include <linux/uaccess.h>
0044 #include <asm/io.h>
0045 #include <asm/div64.h>
0046 #include <media/v4l2-common.h>
0047 #include <media/v4l2-device.h>
0048 #include <media/v4l2-ctrls.h>
0049 
0050 #include <linux/videodev2.h>
0051 
0052 /*
0053  *
0054  *  V 4 L 2   D R I V E R   H E L P E R   A P I
0055  *
0056  */
0057 
0058 /*
0059  *  Video Standard Operations (contributed by Michael Schimek)
0060  */
0061 
0062 /* Helper functions for control handling                 */
0063 
0064 /* Fill in a struct v4l2_queryctrl */
0065 int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _step, s32 _def)
0066 {
0067     const char *name;
0068     s64 min = _min;
0069     s64 max = _max;
0070     u64 step = _step;
0071     s64 def = _def;
0072 
0073     v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
0074                &min, &max, &step, &def, &qctrl->flags);
0075 
0076     if (name == NULL)
0077         return -EINVAL;
0078 
0079     qctrl->minimum = min;
0080     qctrl->maximum = max;
0081     qctrl->step = step;
0082     qctrl->default_value = def;
0083     qctrl->reserved[0] = qctrl->reserved[1] = 0;
0084     strscpy(qctrl->name, name, sizeof(qctrl->name));
0085     return 0;
0086 }
0087 EXPORT_SYMBOL(v4l2_ctrl_query_fill);
0088 
0089 /* Clamp x to be between min and max, aligned to a multiple of 2^align.  min
0090  * and max don't have to be aligned, but there must be at least one valid
0091  * value.  E.g., min=17,max=31,align=4 is not allowed as there are no multiples
0092  * of 16 between 17 and 31.  */
0093 static unsigned int clamp_align(unsigned int x, unsigned int min,
0094                 unsigned int max, unsigned int align)
0095 {
0096     /* Bits that must be zero to be aligned */
0097     unsigned int mask = ~((1 << align) - 1);
0098 
0099     /* Clamp to aligned min and max */
0100     x = clamp(x, (min + ~mask) & mask, max & mask);
0101 
0102     /* Round to nearest aligned value */
0103     if (align)
0104         x = (x + (1 << (align - 1))) & mask;
0105 
0106     return x;
0107 }
0108 
0109 static unsigned int clamp_roundup(unsigned int x, unsigned int min,
0110                    unsigned int max, unsigned int alignment)
0111 {
0112     x = clamp(x, min, max);
0113     if (alignment)
0114         x = round_up(x, alignment);
0115 
0116     return x;
0117 }
0118 
0119 void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
0120                unsigned int walign,
0121                u32 *h, unsigned int hmin, unsigned int hmax,
0122                unsigned int halign, unsigned int salign)
0123 {
0124     *w = clamp_align(*w, wmin, wmax, walign);
0125     *h = clamp_align(*h, hmin, hmax, halign);
0126 
0127     /* Usually we don't need to align the size and are done now. */
0128     if (!salign)
0129         return;
0130 
0131     /* How much alignment do we have? */
0132     walign = __ffs(*w);
0133     halign = __ffs(*h);
0134     /* Enough to satisfy the image alignment? */
0135     if (walign + halign < salign) {
0136         /* Max walign where there is still a valid width */
0137         unsigned int wmaxa = __fls(wmax ^ (wmin - 1));
0138         /* Max halign where there is still a valid height */
0139         unsigned int hmaxa = __fls(hmax ^ (hmin - 1));
0140 
0141         /* up the smaller alignment until we have enough */
0142         do {
0143             if (halign >= hmaxa ||
0144                 (walign <= halign && walign < wmaxa)) {
0145                 *w = clamp_align(*w, wmin, wmax, walign + 1);
0146                 walign = __ffs(*w);
0147             } else {
0148                 *h = clamp_align(*h, hmin, hmax, halign + 1);
0149                 halign = __ffs(*h);
0150             }
0151         } while (halign + walign < salign);
0152     }
0153 }
0154 EXPORT_SYMBOL_GPL(v4l_bound_align_image);
0155 
0156 const void *
0157 __v4l2_find_nearest_size(const void *array, size_t array_size,
0158              size_t entry_size, size_t width_offset,
0159              size_t height_offset, s32 width, s32 height)
0160 {
0161     u32 error, min_error = U32_MAX;
0162     const void *best = NULL;
0163     unsigned int i;
0164 
0165     if (!array)
0166         return NULL;
0167 
0168     for (i = 0; i < array_size; i++, array += entry_size) {
0169         const u32 *entry_width = array + width_offset;
0170         const u32 *entry_height = array + height_offset;
0171 
0172         error = abs(*entry_width - width) + abs(*entry_height - height);
0173         if (error > min_error)
0174             continue;
0175 
0176         min_error = error;
0177         best = array;
0178         if (!error)
0179             break;
0180     }
0181 
0182     return best;
0183 }
0184 EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size);
0185 
0186 int v4l2_g_parm_cap(struct video_device *vdev,
0187             struct v4l2_subdev *sd, struct v4l2_streamparm *a)
0188 {
0189     struct v4l2_subdev_frame_interval ival = { 0 };
0190     int ret;
0191 
0192     if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
0193         a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
0194         return -EINVAL;
0195 
0196     if (vdev->device_caps & V4L2_CAP_READWRITE)
0197         a->parm.capture.readbuffers = 2;
0198     if (v4l2_subdev_has_op(sd, video, g_frame_interval))
0199         a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
0200     ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival);
0201     if (!ret)
0202         a->parm.capture.timeperframe = ival.interval;
0203     return ret;
0204 }
0205 EXPORT_SYMBOL_GPL(v4l2_g_parm_cap);
0206 
0207 int v4l2_s_parm_cap(struct video_device *vdev,
0208             struct v4l2_subdev *sd, struct v4l2_streamparm *a)
0209 {
0210     struct v4l2_subdev_frame_interval ival = {
0211         .interval = a->parm.capture.timeperframe
0212     };
0213     int ret;
0214 
0215     if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
0216         a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
0217         return -EINVAL;
0218 
0219     memset(&a->parm, 0, sizeof(a->parm));
0220     if (vdev->device_caps & V4L2_CAP_READWRITE)
0221         a->parm.capture.readbuffers = 2;
0222     else
0223         a->parm.capture.readbuffers = 0;
0224 
0225     if (v4l2_subdev_has_op(sd, video, g_frame_interval))
0226         a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
0227     ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival);
0228     if (!ret)
0229         a->parm.capture.timeperframe = ival.interval;
0230     return ret;
0231 }
0232 EXPORT_SYMBOL_GPL(v4l2_s_parm_cap);
0233 
0234 const struct v4l2_format_info *v4l2_format_info(u32 format)
0235 {
0236     static const struct v4l2_format_info formats[] = {
0237         /* RGB formats */
0238         { .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 },
0239         { .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 },
0240         { .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 },
0241         { .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 },
0242         { .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 },
0243         { .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 },
0244         { .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 },
0245         { .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 },
0246         { .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 },
0247         { .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 },
0248         { .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 },
0249         { .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 },
0250         { .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 },
0251         { .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 },
0252         { .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 },
0253         { .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 },
0254         { .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 },
0255 
0256         /* YUV packed formats */
0257         { .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 },
0258         { .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 },
0259         { .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 },
0260         { .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 },
0261 
0262         /* YUV planar formats */
0263         { .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 },
0264         { .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 },
0265         { .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 },
0266         { .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 },
0267         { .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 },
0268         { .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 },
0269         { .format = V4L2_PIX_FMT_P010,    .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
0270 
0271         { .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 },
0272         { .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 },
0273         { .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 },
0274         { .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 },
0275         { .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 },
0276         { .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 },
0277         { .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 },
0278 
0279         /* Tiled YUV formats */
0280         { .format = V4L2_PIX_FMT_NV12_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
0281         { .format = V4L2_PIX_FMT_P010_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .hdiv = 2, .vdiv = 2 },
0282 
0283         /* YUV planar formats, non contiguous variant */
0284         { .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 },
0285         { .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 },
0286         { .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 },
0287         { .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 },
0288         { .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 },
0289         { .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 },
0290 
0291         { .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 },
0292         { .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 },
0293         { .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 },
0294         { .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 },
0295 
0296         /* Bayer RGB formats */
0297         { .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 },
0298         { .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 },
0299         { .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 },
0300         { .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 },
0301         { .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 },
0302         { .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 },
0303         { .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 },
0304         { .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 },
0305         { .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 },
0306         { .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 },
0307         { .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 },
0308         { .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 },
0309         { .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 },
0310         { .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 },
0311         { .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 },
0312         { .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 },
0313         { .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 },
0314         { .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 },
0315         { .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 },
0316         { .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 },
0317     };
0318     unsigned int i;
0319 
0320     for (i = 0; i < ARRAY_SIZE(formats); ++i)
0321         if (formats[i].format == format)
0322             return &formats[i];
0323     return NULL;
0324 }
0325 EXPORT_SYMBOL(v4l2_format_info);
0326 
0327 static inline unsigned int v4l2_format_block_width(const struct v4l2_format_info *info, int plane)
0328 {
0329     if (!info->block_w[plane])
0330         return 1;
0331     return info->block_w[plane];
0332 }
0333 
0334 static inline unsigned int v4l2_format_block_height(const struct v4l2_format_info *info, int plane)
0335 {
0336     if (!info->block_h[plane])
0337         return 1;
0338     return info->block_h[plane];
0339 }
0340 
0341 void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
0342                     const struct v4l2_frmsize_stepwise *frmsize)
0343 {
0344     if (!frmsize)
0345         return;
0346 
0347     /*
0348      * Clamp width/height to meet min/max constraints and round it up to
0349      * macroblock alignment.
0350      */
0351     *width = clamp_roundup(*width, frmsize->min_width, frmsize->max_width,
0352                    frmsize->step_width);
0353     *height = clamp_roundup(*height, frmsize->min_height, frmsize->max_height,
0354                 frmsize->step_height);
0355 }
0356 EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
0357 
0358 int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
0359             u32 pixelformat, u32 width, u32 height)
0360 {
0361     const struct v4l2_format_info *info;
0362     struct v4l2_plane_pix_format *plane;
0363     int i;
0364 
0365     info = v4l2_format_info(pixelformat);
0366     if (!info)
0367         return -EINVAL;
0368 
0369     pixfmt->width = width;
0370     pixfmt->height = height;
0371     pixfmt->pixelformat = pixelformat;
0372     pixfmt->num_planes = info->mem_planes;
0373 
0374     if (info->mem_planes == 1) {
0375         plane = &pixfmt->plane_fmt[0];
0376         plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
0377         plane->sizeimage = 0;
0378 
0379         for (i = 0; i < info->comp_planes; i++) {
0380             unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
0381             unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
0382             unsigned int aligned_width;
0383             unsigned int aligned_height;
0384 
0385             aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
0386             aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
0387 
0388             plane->sizeimage += info->bpp[i] *
0389                 DIV_ROUND_UP(aligned_width, hdiv) *
0390                 DIV_ROUND_UP(aligned_height, vdiv);
0391         }
0392     } else {
0393         for (i = 0; i < info->comp_planes; i++) {
0394             unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
0395             unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
0396             unsigned int aligned_width;
0397             unsigned int aligned_height;
0398 
0399             aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
0400             aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
0401 
0402             plane = &pixfmt->plane_fmt[i];
0403             plane->bytesperline =
0404                 info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv);
0405             plane->sizeimage =
0406                 plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv);
0407         }
0408     }
0409     return 0;
0410 }
0411 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
0412 
0413 int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
0414              u32 width, u32 height)
0415 {
0416     const struct v4l2_format_info *info;
0417     int i;
0418 
0419     info = v4l2_format_info(pixelformat);
0420     if (!info)
0421         return -EINVAL;
0422 
0423     /* Single planar API cannot be used for multi plane formats. */
0424     if (info->mem_planes > 1)
0425         return -EINVAL;
0426 
0427     pixfmt->width = width;
0428     pixfmt->height = height;
0429     pixfmt->pixelformat = pixelformat;
0430     pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
0431     pixfmt->sizeimage = 0;
0432 
0433     for (i = 0; i < info->comp_planes; i++) {
0434         unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
0435         unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
0436         unsigned int aligned_width;
0437         unsigned int aligned_height;
0438 
0439         aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
0440         aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
0441 
0442         pixfmt->sizeimage += info->bpp[i] *
0443             DIV_ROUND_UP(aligned_width, hdiv) *
0444             DIV_ROUND_UP(aligned_height, vdiv);
0445     }
0446     return 0;
0447 }
0448 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
0449 
0450 s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
0451                unsigned int div)
0452 {
0453     struct v4l2_ctrl *ctrl;
0454     s64 freq;
0455 
0456     ctrl = v4l2_ctrl_find(handler, V4L2_CID_LINK_FREQ);
0457     if (ctrl) {
0458         struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ };
0459         int ret;
0460 
0461         qm.index = v4l2_ctrl_g_ctrl(ctrl);
0462 
0463         ret = v4l2_querymenu(handler, &qm);
0464         if (ret)
0465             return -ENOENT;
0466 
0467         freq = qm.value;
0468     } else {
0469         if (!mul || !div)
0470             return -ENOENT;
0471 
0472         ctrl = v4l2_ctrl_find(handler, V4L2_CID_PIXEL_RATE);
0473         if (!ctrl)
0474             return -ENOENT;
0475 
0476         freq = div_u64(v4l2_ctrl_g_ctrl_int64(ctrl) * mul, div);
0477 
0478         pr_warn("%s: Link frequency estimated using pixel rate: result might be inaccurate\n",
0479             __func__);
0480         pr_warn("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n",
0481             __func__);
0482     }
0483 
0484     return freq > 0 ? freq : -EINVAL;
0485 }
0486 EXPORT_SYMBOL_GPL(v4l2_get_link_freq);