From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:50 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux driver --- kernel/drivers/media/v4l2-core/v4l2-ioctl.c | 719 +++++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 499 insertions(+), 220 deletions(-) diff --git a/kernel/drivers/media/v4l2-core/v4l2-ioctl.c b/kernel/drivers/media/v4l2-core/v4l2-ioctl.c index 47ddb8c..2b94f62 100644 --- a/kernel/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/kernel/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Video capture interface for Linux version 2 * * A generic framework to process V4L2 ioctl commands. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. * * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1) * Mauro Carvalho Chehab <mchehab@kernel.org> (version 2) @@ -32,6 +28,8 @@ #include <media/v4l2-mem2mem.h> #include <trace/events/v4l2.h> +#include <trace/hooks/v4l2core.h> + /* Zero out the end of the struct pointed to by p. Everything after, but * not including, the specified field is cleared. */ @@ -80,6 +78,15 @@ { 0, "Unknown" } }; +static void clear_reserved(struct v4l2_format *p) +{ + int ret = 0; + + trace_android_vh_clear_reserved_fmt_fields(p, &ret); + if (!ret) + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); +} + /* video4linux standard ID conversion to standard name */ const char *v4l2_norm_to_name(v4l2_std_id id) @@ -88,7 +95,7 @@ int i; /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle - 64 bit comparations. So, on that architecture, with some gcc + 64 bit comparisons. So, on that architecture, with some gcc variants, compilation fails. Currently, the max value is 30bit wide. */ BUG_ON(myid != id); @@ -121,7 +128,7 @@ vs->id = id; v4l2_video_std_frame_period(id, &vs->frameperiod); vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625; - strlcpy(vs->name, name, sizeof(vs->name)); + strscpy(vs->name, name, sizeof(vs->name)); return 0; } EXPORT_SYMBOL(v4l2_video_std_construct); @@ -268,12 +275,13 @@ { const struct v4l2_fmtdesc *p = arg; - pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%.*s'\n", + pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, mbus_code=0x%04x, description='%.*s'\n", p->index, prt_names(p->type, v4l2_type_names), p->flags, (p->pixelformat & 0xff), (p->pixelformat >> 8) & 0xff, (p->pixelformat >> 16) & 0xff, (p->pixelformat >> 24) & 0xff, + p->mbus_code, (int)sizeof(p->description), p->description); } @@ -478,13 +486,13 @@ const struct v4l2_plane *plane; int i; - pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, flags=0x%08x, field=%s, sequence=%d, memory=%s", - p->timestamp.tv_sec / 3600, - (int)(p->timestamp.tv_sec / 60) % 60, - (int)(p->timestamp.tv_sec % 60), + pr_cont("%02d:%02d:%02d.%09ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s", + (int)p->timestamp.tv_sec / 3600, + ((int)p->timestamp.tv_sec / 60) % 60, + ((int)p->timestamp.tv_sec % 60), (long)p->timestamp.tv_usec, p->index, - prt_names(p->type, v4l2_type_names), + prt_names(p->type, v4l2_type_names), p->request_fd, p->flags, prt_names(p->field, v4l2_field_names), p->sequence, prt_names(p->memory, v4l2_memory_names)); @@ -585,7 +593,10 @@ static void v4l_print_control(const void *arg, bool write_only) { const struct v4l2_control *p = arg; + const char *name = v4l2_ctrl_get_name(p->id); + if (name) + pr_cont("name=%s, ", name); pr_cont("id=0x%x, value=%d\n", p->id, p->value); } @@ -594,15 +605,18 @@ const struct v4l2_ext_controls *p = arg; int i; - pr_cont("which=0x%x, count=%d, error_idx=%d", - p->which, p->count, p->error_idx); + pr_cont("which=0x%x, count=%d, error_idx=%d, request_fd=%d", + p->which, p->count, p->error_idx, p->request_fd); for (i = 0; i < p->count; i++) { + unsigned int id = p->controls[i].id; + const char *name = v4l2_ctrl_get_name(id); + + if (name) + pr_cont(", name=%s", name); if (!p->controls[i].size) - pr_cont(", id/val=0x%x/0x%x", - p->controls[i].id, p->controls[i].value); + pr_cont(", id/val=0x%x/0x%x", id, p->controls[i].value); else - pr_cont(", id/size=0x%x/%u", - p->controls[i].id, p->controls[i].size); + pr_cont(", id/size=0x%x/%u", id, p->controls[i].size); } pr_cont("\n"); } @@ -779,7 +793,6 @@ p->stepwise.step_height); break; case V4L2_FRMSIZE_TYPE_CONTINUOUS: - /* fall through */ default: pr_cont("\n"); break; @@ -813,7 +826,6 @@ p->stepwise.step.denominator); break; case V4L2_FRMIVAL_TYPE_CONTINUOUS: - /* fall through */ default: pr_cont("\n"); break; @@ -825,7 +837,7 @@ const struct v4l2_event *p = arg; const struct v4l2_event_ctrl *c; - pr_cont("type=0x%x, pending=%u, sequence=%u, id=%u, timestamp=%lu.%9.9lu\n", + pr_cont("type=0x%x, pending=%u, sequence=%u, id=%u, timestamp=%llu.%9.9llu\n", p->type, p->pending, p->sequence, p->id, p->timestamp.tv_sec, p->timestamp.tv_nsec); switch (p->type) { @@ -906,42 +918,70 @@ pr_cont("driver-specific ioctl\n"); } -static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) +static bool check_ext_ctrls(struct v4l2_ext_controls *c, unsigned long ioctl) { __u32 i; /* zero the reserved fields */ - c->reserved[0] = c->reserved[1] = 0; + c->reserved[0] = 0; for (i = 0; i < c->count; i++) c->controls[i].reserved2[0] = 0; - /* V4L2_CID_PRIVATE_BASE cannot be used as control class - when using extended controls. - Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL - is it allowed for backwards compatibility. - */ - if (!allow_priv && c->which == V4L2_CID_PRIVATE_BASE) - return 0; - if (!c->which) - return 1; + switch (c->which) { + case V4L2_CID_PRIVATE_BASE: + /* + * V4L2_CID_PRIVATE_BASE cannot be used as control class + * when using extended controls. + * Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL + * is it allowed for backwards compatibility. + */ + if (ioctl == VIDIOC_G_CTRL || ioctl == VIDIOC_S_CTRL) + return false; + break; + case V4L2_CTRL_WHICH_DEF_VAL: + /* Default value cannot be changed */ + if (ioctl == VIDIOC_S_EXT_CTRLS || + ioctl == VIDIOC_TRY_EXT_CTRLS) { + c->error_idx = c->count; + return false; + } + return true; + case V4L2_CTRL_WHICH_CUR_VAL: + return true; + case V4L2_CTRL_WHICH_REQUEST_VAL: + c->error_idx = c->count; + return false; + } + /* Check that all controls are from the same control class. */ for (i = 0; i < c->count; i++) { if (V4L2_CTRL_ID2WHICH(c->controls[i].id) != c->which) { - c->error_idx = i; - return 0; + c->error_idx = ioctl == VIDIOC_TRY_EXT_CTRLS ? i : + c->count; + return false; } } - return 1; + return true; } static int check_fmt(struct file *file, enum v4l2_buf_type type) { + const u32 vid_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE; + const u32 meta_caps = V4L2_CAP_META_CAPTURE | + V4L2_CAP_META_OUTPUT; struct video_device *vfd = video_devdata(file); const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; - bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; + bool is_vid = vfd->vfl_type == VFL_TYPE_VIDEO && + (vfd->device_caps & vid_caps); bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI; bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; + bool is_meta = vfd->vfl_type == VFL_TYPE_VIDEO && + (vfd->device_caps & meta_caps); bool is_rx = vfd->vfl_dir != VFL_DIR_TX; bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -955,7 +995,7 @@ return 0; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (is_vid && is_rx && ops->vidioc_g_fmt_vid_cap_mplane) + if ((is_vid || is_tch) && is_rx && ops->vidioc_g_fmt_vid_cap_mplane) return 0; break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: @@ -1000,11 +1040,11 @@ return 0; break; case V4L2_BUF_TYPE_META_CAPTURE: - if (is_vid && is_rx && ops->vidioc_g_fmt_meta_cap) + if (is_meta && is_rx && ops->vidioc_g_fmt_meta_cap) return 0; break; case V4L2_BUF_TYPE_META_OUTPUT: - if (is_vid && is_tx && ops->vidioc_g_fmt_meta_out) + if (is_meta && is_tx && ops->vidioc_g_fmt_meta_out) return 0; break; default: @@ -1016,6 +1056,12 @@ static void v4l_sanitize_format(struct v4l2_format *fmt) { unsigned int offset; + + /* Make sure num_planes is not bogus */ + if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || + fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + fmt->fmt.pix_mp.num_planes = min_t(u32, fmt->fmt.pix_mp.num_planes, + VIDEO_MAX_PLANES); /* * The v4l2_pix_format structure has been extended with fields that were @@ -1055,17 +1101,48 @@ ret = ops->vidioc_querycap(file, fh, cap); - cap->capabilities |= V4L2_CAP_EXT_PIX_FORMAT; /* - * Drivers MUST fill in device_caps, so check for this and - * warn if it was forgotten. + * Drivers must not change device_caps, so check for this and + * warn if this happened. */ - WARN(!(cap->capabilities & V4L2_CAP_DEVICE_CAPS) || - !cap->device_caps, "Bad caps for driver %s, %x %x", - cap->driver, cap->capabilities, cap->device_caps); + WARN_ON(cap->device_caps != vfd->device_caps); + /* + * Check that capabilities is a superset of + * vfd->device_caps | V4L2_CAP_DEVICE_CAPS + */ + WARN_ON((cap->capabilities & + (vfd->device_caps | V4L2_CAP_DEVICE_CAPS)) != + (vfd->device_caps | V4L2_CAP_DEVICE_CAPS)); + cap->capabilities |= V4L2_CAP_EXT_PIX_FORMAT; cap->device_caps |= V4L2_CAP_EXT_PIX_FORMAT; return ret; +} + +static int v4l_g_input(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + + if (vfd->device_caps & V4L2_CAP_IO_MC) { + *(int *)arg = 0; + return 0; + } + + return ops->vidioc_g_input(file, fh, arg); +} + +static int v4l_g_output(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + + if (vfd->device_caps & V4L2_CAP_IO_MC) { + *(int *)arg = 0; + return 0; + } + + return ops->vidioc_g_output(file, fh, arg); } static int v4l_s_input(const struct v4l2_ioctl_ops *ops, @@ -1077,12 +1154,21 @@ ret = v4l_enable_media_source(vfd); if (ret) return ret; + + if (vfd->device_caps & V4L2_CAP_IO_MC) + return *(int *)arg ? -EINVAL : 0; + return ops->vidioc_s_input(file, fh, *(unsigned int *)arg); } static int v4l_s_output(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); + + if (vfd->device_caps & V4L2_CAP_IO_MC) + return *(int *)arg ? -EINVAL : 0; + return ops->vidioc_s_output(file, fh, *(unsigned int *)arg); } @@ -1126,6 +1212,14 @@ if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_IN_CAP_STD; + if (vfd->device_caps & V4L2_CAP_IO_MC) { + if (p->index) + return -EINVAL; + strscpy(p->name, vfd->name, sizeof(p->name)); + p->type = V4L2_INPUT_TYPE_CAMERA; + return 0; + } + return ops->vidioc_enum_input(file, fh, p); } @@ -1143,6 +1237,14 @@ */ if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_OUT_CAP_STD; + + if (vfd->device_caps & V4L2_CAP_IO_MC) { + if (p->index) + return -EINVAL; + strscpy(p->name, vfd->name, sizeof(p->name)); + p->type = V4L2_OUTPUT_TYPE_ANALOG; + return 0; + } return ops->vidioc_enum_output(file, fh, p); } @@ -1167,9 +1269,21 @@ case V4L2_PIX_FMT_RGB444: descr = "16-bit A/XRGB 4-4-4-4"; break; case V4L2_PIX_FMT_ARGB444: descr = "16-bit ARGB 4-4-4-4"; break; case V4L2_PIX_FMT_XRGB444: descr = "16-bit XRGB 4-4-4-4"; break; + case V4L2_PIX_FMT_RGBA444: descr = "16-bit RGBA 4-4-4-4"; break; + case V4L2_PIX_FMT_RGBX444: descr = "16-bit RGBX 4-4-4-4"; break; + case V4L2_PIX_FMT_ABGR444: descr = "16-bit ABGR 4-4-4-4"; break; + case V4L2_PIX_FMT_XBGR444: descr = "16-bit XBGR 4-4-4-4"; break; + case V4L2_PIX_FMT_BGRA444: descr = "16-bit BGRA 4-4-4-4"; break; + case V4L2_PIX_FMT_BGRX444: descr = "16-bit BGRX 4-4-4-4"; break; case V4L2_PIX_FMT_RGB555: descr = "16-bit A/XRGB 1-5-5-5"; break; case V4L2_PIX_FMT_ARGB555: descr = "16-bit ARGB 1-5-5-5"; break; case V4L2_PIX_FMT_XRGB555: descr = "16-bit XRGB 1-5-5-5"; break; + case V4L2_PIX_FMT_ABGR555: descr = "16-bit ABGR 1-5-5-5"; break; + case V4L2_PIX_FMT_XBGR555: descr = "16-bit XBGR 1-5-5-5"; break; + case V4L2_PIX_FMT_RGBA555: descr = "16-bit RGBA 5-5-5-1"; break; + case V4L2_PIX_FMT_RGBX555: descr = "16-bit RGBX 5-5-5-1"; break; + case V4L2_PIX_FMT_BGRA555: descr = "16-bit BGRA 5-5-5-1"; break; + case V4L2_PIX_FMT_BGRX555: descr = "16-bit BGRX 5-5-5-1"; break; case V4L2_PIX_FMT_RGB565: descr = "16-bit RGB 5-6-5"; break; case V4L2_PIX_FMT_RGB555X: descr = "16-bit A/XRGB 1-5-5-5 BE"; break; case V4L2_PIX_FMT_ARGB555X: descr = "16-bit ARGB 1-5-5-5 BE"; break; @@ -1184,11 +1298,16 @@ case V4L2_PIX_FMT_RGB32: descr = "32-bit A/XRGB 8-8-8-8"; break; case V4L2_PIX_FMT_ARGB32: descr = "32-bit ARGB 8-8-8-8"; break; case V4L2_PIX_FMT_XRGB32: descr = "32-bit XRGB 8-8-8-8"; break; + case V4L2_PIX_FMT_BGRA32: descr = "32-bit ABGR 8-8-8-8"; break; + case V4L2_PIX_FMT_BGRX32: descr = "32-bit XBGR 8-8-8-8"; break; + case V4L2_PIX_FMT_RGBA32: descr = "32-bit RGBA 8-8-8-8"; break; + case V4L2_PIX_FMT_RGBX32: descr = "32-bit RGBX 8-8-8-8"; break; case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break; case V4L2_PIX_FMT_Y4: descr = "4-bit Greyscale"; break; case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break; case V4L2_PIX_FMT_Y10: descr = "10-bit Greyscale"; break; case V4L2_PIX_FMT_Y12: descr = "12-bit Greyscale"; break; + case V4L2_PIX_FMT_Y14: descr = "14-bit Greyscale"; break; case V4L2_PIX_FMT_Y16: descr = "16-bit Greyscale"; break; case V4L2_PIX_FMT_Y16_BE: descr = "16-bit Greyscale BE"; break; case V4L2_PIX_FMT_Y10BPACK: descr = "10-bit Greyscale (Packed)"; break; @@ -1197,6 +1316,7 @@ case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break; case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break; case V4L2_PIX_FMT_INZI: descr = "Planar 10:16 Greyscale Depth"; break; + case V4L2_PIX_FMT_CNF4: descr = "4-bit Depth Confidence (Packed)"; break; case V4L2_PIX_FMT_PAL8: descr = "8-bit Palette"; break; case V4L2_PIX_FMT_UV8: descr = "8-bit Chrominance UV 4-4"; break; case V4L2_PIX_FMT_YVU410: descr = "Planar YVU 4:1:0"; break; @@ -1213,6 +1333,10 @@ case V4L2_PIX_FMT_YUV555: descr = "16-bit A/XYUV 1-5-5-5"; break; case V4L2_PIX_FMT_YUV565: descr = "16-bit YUV 5-6-5"; break; case V4L2_PIX_FMT_YUV32: descr = "32-bit A/XYUV 8-8-8-8"; break; + case V4L2_PIX_FMT_AYUV32: descr = "32-bit AYUV 8-8-8-8"; break; + case V4L2_PIX_FMT_XYUV32: descr = "32-bit XYUV 8-8-8-8"; break; + case V4L2_PIX_FMT_VUYA32: descr = "32-bit VUYA 8-8-8-8"; break; + case V4L2_PIX_FMT_VUYX32: descr = "32-bit VUYX 8-8-8-8"; break; case V4L2_PIX_FMT_YUV410: descr = "Planar YUV 4:1:0"; break; case V4L2_PIX_FMT_YUV420: descr = "Planar YUV 4:2:0"; break; case V4L2_PIX_FMT_HI240: descr = "8-bit Dithered RGB (BTTV)"; break; @@ -1268,6 +1392,10 @@ case V4L2_PIX_FMT_SGBRG12P: descr = "12-bit Bayer GBGB/RGRG Packed"; break; case V4L2_PIX_FMT_SGRBG12P: descr = "12-bit Bayer GRGR/BGBG Packed"; break; case V4L2_PIX_FMT_SRGGB12P: descr = "12-bit Bayer RGRG/GBGB Packed"; break; + case V4L2_PIX_FMT_SBGGR14: descr = "14-bit Bayer BGBG/GRGR"; break; + case V4L2_PIX_FMT_SGBRG14: descr = "14-bit Bayer GBGB/RGRG"; break; + case V4L2_PIX_FMT_SGRBG14: descr = "14-bit Bayer GRGR/BGBG"; break; + case V4L2_PIX_FMT_SRGGB14: descr = "14-bit Bayer RGRG/GBGB"; break; case V4L2_PIX_FMT_SBGGR14P: descr = "14-bit Bayer BGBG/GRGR Packed"; break; case V4L2_PIX_FMT_SGBRG14P: descr = "14-bit Bayer GBGB/RGRG Packed"; break; case V4L2_PIX_FMT_SGRBG14P: descr = "14-bit Bayer GRGR/BGBG Packed"; break; @@ -1294,27 +1422,15 @@ case V4L2_SDR_FMT_PCU16BE: descr = "Planar Complex U16BE"; break; case V4L2_SDR_FMT_PCU18BE: descr = "Planar Complex U18BE"; break; case V4L2_SDR_FMT_PCU20BE: descr = "Planar Complex U20BE"; break; - case V4L2_TCH_FMT_DELTA_TD16: descr = "16-bit signed deltas"; break; - case V4L2_TCH_FMT_DELTA_TD08: descr = "8-bit signed deltas"; break; - case V4L2_TCH_FMT_TU16: descr = "16-bit unsigned touch data"; break; - case V4L2_TCH_FMT_TU08: descr = "8-bit unsigned touch data"; break; + case V4L2_TCH_FMT_DELTA_TD16: descr = "16-bit Signed Deltas"; break; + case V4L2_TCH_FMT_DELTA_TD08: descr = "8-bit Signed Deltas"; break; + case V4L2_TCH_FMT_TU16: descr = "16-bit Unsigned Touch Data"; break; + case V4L2_TCH_FMT_TU08: descr = "8-bit Unsigned Touch Data"; break; case V4L2_META_FMT_VSP1_HGO: descr = "R-Car VSP1 1-D Histogram"; break; case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break; - case V4L2_META_FMT_UVC: descr = "UVC payload header metadata"; break; - case V4L2_PIX_FMT_NV12_UBWC: - descr = "NV12 UBWC"; break; - case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS: - descr = "Y/CbCr 4:2:0 P10 Venus"; break; - case V4L2_PIX_FMT_NV12_TP10_UBWC: - descr = "Y/CbCr 4:2:0 TP10 UBWC"; break; - case V4L2_PIX_FMT_NV12_512: - descr = "Y/CbCr 4:2:0 (512 align)"; break; - case V4L2_META_FMT_RK_ISP1_PARAMS: - descr = "Rockchip ISP1 3A params"; - break; - case V4L2_META_FMT_RK_ISP1_STAT_3A: - descr = "Rockchip ISP1 3A statistics"; - break; + case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; + case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; + case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break; default: /* Compressed formats */ @@ -1328,17 +1444,22 @@ case V4L2_PIX_FMT_H264: descr = "H.264"; break; case V4L2_PIX_FMT_H264_NO_SC: descr = "H.264 (No Start Codes)"; break; case V4L2_PIX_FMT_H264_MVC: descr = "H.264 MVC"; break; + case V4L2_PIX_FMT_H264_SLICE: descr = "H.264 Parsed Slice Data"; break; case V4L2_PIX_FMT_H263: descr = "H.263"; break; case V4L2_PIX_FMT_MPEG1: descr = "MPEG-1 ES"; break; case V4L2_PIX_FMT_MPEG2: descr = "MPEG-2 ES"; break; - case V4L2_PIX_FMT_MPEG4: descr = "MPEG-4 part 2 ES"; break; + case V4L2_PIX_FMT_MPEG2_SLICE: descr = "MPEG-2 Parsed Slice Data"; break; + case V4L2_PIX_FMT_MPEG4: descr = "MPEG-4 Part 2 ES"; break; case V4L2_PIX_FMT_XVID: descr = "Xvid"; break; case V4L2_PIX_FMT_VC1_ANNEX_G: descr = "VC-1 (SMPTE 412M Annex G)"; break; case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break; case V4L2_PIX_FMT_VP8: descr = "VP8"; break; + case V4L2_PIX_FMT_VP8_FRAME: descr = "VP8 Frame"; break; case V4L2_PIX_FMT_VP9: descr = "VP9"; break; case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ + case V4L2_PIX_FMT_HEVC_SLICE: descr = "HEVC Parsed Slice Data"; break; case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */ + case V4L2_PIX_FMT_FWHT_STATELESS: descr = "FWHT Stateless"; break; /* used in vicodec */ case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break; case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break; case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break; @@ -1358,51 +1479,62 @@ case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break; case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; - case V4L2_PIX_FMT_FBC2: descr = "Rockchip yuv422sp fbc encoder"; break; - case V4L2_PIX_FMT_FBC0: descr = "Rockchip yuv420sp fbc encoder"; break; - case V4L2_PIX_FMT_FBCG: descr = "Rockchip fbc gain"; break; - case V4l2_PIX_FMT_EBD8: descr = "Embedded data 8-bit"; break; - case V4l2_PIX_FMT_SPD16: descr = "Shield pix data 16-bit"; break; + case V4L2_PIX_FMT_SUNXI_TILED_NV12: descr = "Sunxi Tiled NV12 Format"; break; default: - WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat); + trace_android_vh_fill_ext_fmtdesc(fmt, &descr); + if (descr) + break; if (fmt->description[0]) return; + WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat); flags = 0; snprintf(fmt->description, sz, "%c%c%c%c%s", (char)(fmt->pixelformat & 0x7f), (char)((fmt->pixelformat >> 8) & 0x7f), (char)((fmt->pixelformat >> 16) & 0x7f), (char)((fmt->pixelformat >> 24) & 0x7f), - (fmt->pixelformat & (1 << 31)) ? "-BE" : ""); + (fmt->pixelformat & (1UL << 31)) ? "-BE" : ""); break; } } if (descr) - WARN_ON(strlcpy(fmt->description, descr, sz) >= sz); - fmt->flags = flags; + WARN_ON(strscpy(fmt->description, descr, sz) < 0); + fmt->flags |= flags; } static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vdev = video_devdata(file); struct v4l2_fmtdesc *p = arg; int ret = check_fmt(file, p->type); + u32 mbus_code; + u32 cap_mask; if (ret) return ret; ret = -EINVAL; + if (!(vdev->device_caps & V4L2_CAP_IO_MC)) + p->mbus_code = 0; + + mbus_code = p->mbus_code; + CLEAR_AFTER_FIELD(p, type); + p->mbus_code = mbus_code; + switch (p->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + cap_mask = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE; + if (!!(vdev->device_caps & cap_mask) != + (p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) + break; + if (unlikely(!ops->vidioc_enum_fmt_vid_cap)) break; ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane)) - break; - ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_enum_fmt_vid_overlay)) @@ -1410,14 +1542,16 @@ ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + cap_mask = V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE; + if (!!(vdev->device_caps & cap_mask) != + (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) + break; + if (unlikely(!ops->vidioc_enum_fmt_vid_out)) break; ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane)) - break; - ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); break; case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_enum_fmt_sdr_cap)) @@ -1547,6 +1681,7 @@ struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); int ret = check_fmt(file, p->type); + unsigned int i; if (ret) return ret; @@ -1570,7 +1705,10 @@ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane)) break; - CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + clear_reserved(p); + for (i = 0; i < p->fmt.pix_mp.num_planes; i++) + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_overlay)) @@ -1598,7 +1736,10 @@ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane)) break; - CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + clear_reserved(p); + for (i = 0; i < p->fmt.pix_mp.num_planes; i++) + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay)) @@ -1643,7 +1784,9 @@ struct file *file, void *fh, void *arg) { struct v4l2_format *p = arg; + struct video_device *vfd = video_devdata(file); int ret = check_fmt(file, p->type); + unsigned int i; if (ret) return ret; @@ -1658,11 +1801,16 @@ ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + if (vfd->vfl_type == VFL_TYPE_TOUCH) + v4l_pix_format_touch(&p->fmt.pix); return ret; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane)) break; - CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + clear_reserved(p); + for (i = 0; i < p->fmt.pix_mp.num_planes; i++) + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_overlay)) @@ -1690,7 +1838,10 @@ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane)) break; - CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + clear_reserved(p); + for (i = 0; i < p->fmt.pix_mp.num_planes; i++) + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay)) @@ -1924,7 +2075,7 @@ if (ret) return ret; - CLEAR_AFTER_FIELD(p, memory); + CLEAR_AFTER_FIELD(p, capabilities); return ops->vidioc_reqbufs(file, fh, p); } @@ -1965,7 +2116,7 @@ if (ret) return ret; - CLEAR_AFTER_FIELD(create, format); + CLEAR_AFTER_FIELD(create, capabilities); v4l_sanitize_format(&create->format); @@ -1990,6 +2141,7 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_streamparm *p = arg; v4l2_std_id std; int ret = check_fmt(file, p->type); @@ -2001,7 +2153,8 @@ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - p->parm.capture.readbuffers = 2; + if (vfd->device_caps & V4L2_CAP_READWRITE) + p->parm.capture.readbuffers = 2; ret = ops->vidioc_g_std(file, fh, &std); if (ret == 0) v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe); @@ -2107,7 +2260,7 @@ ctrls.controls = &ctrl; ctrl.id = p->id; ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) { + if (check_ext_ctrls(&ctrls, VIDIOC_G_CTRL)) { int ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); if (ret == 0) @@ -2126,6 +2279,7 @@ test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; + int ret; if (vfh && vfh->ctrl_handler) return v4l2_s_ctrl(vfh, vfh->ctrl_handler, p); @@ -2141,9 +2295,11 @@ ctrls.controls = &ctrl; ctrl.id = p->id; ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) - return ops->vidioc_s_ext_ctrls(file, fh, &ctrls); - return -EINVAL; + if (!check_ext_ctrls(&ctrls, VIDIOC_S_CTRL)) + return -EINVAL; + ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); + p->value = ctrl.value; + return ret; } static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, @@ -2156,13 +2312,15 @@ p->error_idx = p->count; if (vfh && vfh->ctrl_handler) - return v4l2_g_ext_ctrls(vfh->ctrl_handler, p); + return v4l2_g_ext_ctrls(vfh->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (vfd->ctrl_handler) - return v4l2_g_ext_ctrls(vfd->ctrl_handler, p); + return v4l2_g_ext_ctrls(vfd->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_g_ext_ctrls == NULL) return -ENOTTY; - return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) : - -EINVAL; + return check_ext_ctrls(p, VIDIOC_G_EXT_CTRLS) ? + ops->vidioc_g_ext_ctrls(file, fh, p) : -EINVAL; } static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, @@ -2175,13 +2333,15 @@ p->error_idx = p->count; if (vfh && vfh->ctrl_handler) - return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p); + return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (vfd->ctrl_handler) - return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p); + return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_s_ext_ctrls == NULL) return -ENOTTY; - return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) : - -EINVAL; + return check_ext_ctrls(p, VIDIOC_S_EXT_CTRLS) ? + ops->vidioc_s_ext_ctrls(file, fh, p) : -EINVAL; } static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, @@ -2194,13 +2354,15 @@ p->error_idx = p->count; if (vfh && vfh->ctrl_handler) - return v4l2_try_ext_ctrls(vfh->ctrl_handler, p); + return v4l2_try_ext_ctrls(vfh->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (vfd->ctrl_handler) - return v4l2_try_ext_ctrls(vfd->ctrl_handler, p); + return v4l2_try_ext_ctrls(vfd->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_try_ext_ctrls == NULL) return -ENOTTY; - return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) : - -EINVAL; + return check_ext_ctrls(p, VIDIOC_TRY_EXT_CTRLS) ? + ops->vidioc_try_ext_ctrls(file, fh, p) : -EINVAL; } /* @@ -2247,21 +2409,24 @@ static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_crop *p = arg; struct v4l2_selection s = { .type = p->type, }; int ret; - if (ops->vidioc_g_crop) - return ops->vidioc_g_crop(file, fh, p); /* simulate capture crop using selection api */ /* crop means compose for output devices */ if (V4L2_TYPE_IS_OUTPUT(p->type)) - s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + s.target = V4L2_SEL_TGT_COMPOSE; else - s.target = V4L2_SEL_TGT_CROP_ACTIVE; + s.target = V4L2_SEL_TGT_CROP; + + if (test_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags)) + s.target = s.target == V4L2_SEL_TGT_COMPOSE ? + V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE; ret = v4l_g_selection(ops, file, fh, &s); @@ -2274,21 +2439,24 @@ static int v4l_s_crop(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_crop *p = arg; struct v4l2_selection s = { .type = p->type, .r = p->c, }; - if (ops->vidioc_s_crop) - return ops->vidioc_s_crop(file, fh, p); /* simulate capture crop using selection api */ /* crop means compose for output devices */ if (V4L2_TYPE_IS_OUTPUT(p->type)) - s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + s.target = V4L2_SEL_TGT_COMPOSE; else - s.target = V4L2_SEL_TGT_CROP_ACTIVE; + s.target = V4L2_SEL_TGT_CROP; + + if (test_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags)) + s.target = s.target == V4L2_SEL_TGT_COMPOSE ? + V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE; return v4l_s_selection(ops, file, fh, &s); } @@ -2296,6 +2464,7 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_cropcap *p = arg; struct v4l2_selection s = { .type = p->type }; int ret = 0; @@ -2304,18 +2473,21 @@ p->pixelaspect.numerator = 1; p->pixelaspect.denominator = 1; + if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + s.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else if (s.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + s.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + /* * The determine_valid_ioctls() call already should ensure * that this can never happen, but just in case... */ - if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_g_selection)) + if (WARN_ON(!ops->vidioc_g_selection)) return -ENOTTY; - if (ops->vidioc_cropcap) - ret = ops->vidioc_cropcap(file, fh, p); - - if (!ops->vidioc_g_selection) - return ret; + if (ops->vidioc_g_pixelaspect) + ret = ops->vidioc_g_pixelaspect(file, fh, s.type, + &p->pixelaspect); /* * Ignore ENOTTY or ENOIOCTLCMD error returns, just use the @@ -2332,13 +2504,17 @@ else s.target = V4L2_SEL_TGT_CROP_BOUNDS; + if (test_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags)) + s.target = s.target == V4L2_SEL_TGT_COMPOSE_BOUNDS ? + V4L2_SEL_TGT_CROP_BOUNDS : V4L2_SEL_TGT_COMPOSE_BOUNDS; + ret = v4l_g_selection(ops, file, fh, &s); if (ret) return ret; p->bounds = s.r; /* obtaining defrect */ - if (V4L2_TYPE_IS_OUTPUT(p->type)) + if (s.target == V4L2_SEL_TGT_COMPOSE_BOUNDS) s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; else s.target = V4L2_SEL_TGT_CROP_DEFAULT; @@ -2438,7 +2614,7 @@ p->flags |= V4L2_CHIP_FL_WRITABLE; if (ops->vidioc_g_register) p->flags |= V4L2_CHIP_FL_READABLE; - strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); + strscpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); if (ops->vidioc_g_chip_info) return ops->vidioc_g_chip_info(file, fh, arg); if (p->match.addr) @@ -2455,7 +2631,7 @@ p->flags |= V4L2_CHIP_FL_WRITABLE; if (sd->ops->core && sd->ops->core->g_register) p->flags |= V4L2_CHIP_FL_READABLE; - strlcpy(p->name, sd->name, sizeof(p->name)); + strscpy(p->name, sd->name, sizeof(p->name)); return 0; } break; @@ -2582,7 +2758,7 @@ /* Zero struct from after the field to the end */ #define INFO_FL_CLEAR(v4l2_struct, field) \ ((offsetof(struct v4l2_struct, field) + \ - sizeof(((struct v4l2_struct *)0)->field)) << 16) + sizeof_field(struct v4l2_struct, field)) << 16) #define INFO_FL_CLEAR_MASK (_IOC_SIZEMASK << 16) #define DEFINE_V4L_STUB_FUNC(_vidioc) \ @@ -2608,10 +2784,8 @@ DEFINE_V4L_STUB_FUNC(g_std) DEFINE_V4L_STUB_FUNC(g_audio) DEFINE_V4L_STUB_FUNC(s_audio) -DEFINE_V4L_STUB_FUNC(g_input) DEFINE_V4L_STUB_FUNC(g_edid) DEFINE_V4L_STUB_FUNC(s_edid) -DEFINE_V4L_STUB_FUNC(g_output) DEFINE_V4L_STUB_FUNC(g_audout) DEFINE_V4L_STUB_FUNC(s_audout) DEFINE_V4L_STUB_FUNC(g_jpegcomp) @@ -2631,9 +2805,9 @@ DEFINE_V4L_STUB_FUNC(query_dv_timings) DEFINE_V4L_STUB_FUNC(dv_timings_cap) -static struct v4l2_ioctl_info v4l2_ioctls[] = { +static const struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0), - IOCTL_INFO(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, INFO_FL_CLEAR(v4l2_fmtdesc, type)), + IOCTL_INFO(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, 0), IOCTL_INFO(VIDIOC_G_FMT, v4l_g_fmt, v4l_print_format, 0), IOCTL_INFO(VIDIOC_S_FMT, v4l_s_fmt, v4l_print_format, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE), @@ -2660,11 +2834,11 @@ IOCTL_INFO(VIDIOC_S_AUDIO, v4l_stub_s_audio, v4l_print_audio, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_QUERYCTRL, v4l_queryctrl, v4l_print_queryctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_queryctrl, id)), IOCTL_INFO(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)), - IOCTL_INFO(VIDIOC_G_INPUT, v4l_stub_g_input, v4l_print_u32, 0), + IOCTL_INFO(VIDIOC_G_INPUT, v4l_g_input, v4l_print_u32, 0), IOCTL_INFO(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_G_EDID, v4l_stub_g_edid, v4l_print_edid, INFO_FL_ALWAYS_COPY), IOCTL_INFO(VIDIOC_S_EDID, v4l_stub_s_edid, v4l_print_edid, INFO_FL_PRIO | INFO_FL_ALWAYS_COPY), - IOCTL_INFO(VIDIOC_G_OUTPUT, v4l_stub_g_output, v4l_print_u32, 0), + IOCTL_INFO(VIDIOC_G_OUTPUT, v4l_g_output, v4l_print_u32, 0), IOCTL_INFO(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)), IOCTL_INFO(VIDIOC_G_AUDOUT, v4l_stub_g_audout, v4l_print_audioout, 0), @@ -2724,62 +2898,17 @@ return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd; } -#if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV) -static bool v4l2_ioctl_m2m_queue_is_output(unsigned int cmd, void *arg) -{ - switch (cmd) { - case VIDIOC_CREATE_BUFS: { - struct v4l2_create_buffers *cbufs = arg; - - return V4L2_TYPE_IS_OUTPUT(cbufs->format.type); - } - case VIDIOC_REQBUFS: { - struct v4l2_requestbuffers *rbufs = arg; - - return V4L2_TYPE_IS_OUTPUT(rbufs->type); - } - case VIDIOC_QBUF: - case VIDIOC_DQBUF: - case VIDIOC_QUERYBUF: - case VIDIOC_PREPARE_BUF: { - struct v4l2_buffer *buf = arg; - - return V4L2_TYPE_IS_OUTPUT(buf->type); - } - case VIDIOC_EXPBUF: { - struct v4l2_exportbuffer *expbuf = arg; - - return V4L2_TYPE_IS_OUTPUT(expbuf->type); - } - case VIDIOC_STREAMON: - case VIDIOC_STREAMOFF: { - int *type = arg; - - return V4L2_TYPE_IS_OUTPUT(*type); - } - default: - return false; - } -} -#endif - static struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, struct v4l2_fh *vfh, unsigned int cmd, void *arg) { if (_IOC_NR(cmd) >= V4L2_IOCTLS) return vdev->lock; -#if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV) if (vfh && vfh->m2m_ctx && (v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE)) { - bool is_output = v4l2_ioctl_m2m_queue_is_output(cmd, arg); - struct v4l2_m2m_queue_ctx *ctx = is_output ? - &vfh->m2m_ctx->out_q_ctx : &vfh->m2m_ctx->cap_q_ctx; - - if (ctx->q.lock) - return ctx->q.lock; + if (vfh->m2m_ctx->q_lock) + return vfh->m2m_ctx->q_lock; } -#endif if (vdev->queue && vdev->queue->lock && (v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE)) return vdev->queue->lock; @@ -2827,6 +2956,7 @@ unsigned int cmd, void *arg) { struct video_device *vfd = video_devdata(file); + struct mutex *req_queue_lock = NULL; struct mutex *lock; /* ioctl serialization mutex */ const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; bool write_only = false; @@ -2846,10 +2976,27 @@ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) vfh = file->private_data; + /* + * We need to serialize streamon/off with queueing new requests. + * These ioctls may trigger the cancellation of a streaming + * operation, and that should not be mixed with queueing a new + * request at the same time. + */ + if (v4l2_device_supports_requests(vfd->v4l2_dev) && + (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF)) { + req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex; + + if (mutex_lock_interruptible(req_queue_lock)) + return -ERESTARTSYS; + } + lock = v4l2_ioctl_get_lock(vfd, vfh, cmd, arg); - if (lock && mutex_lock_interruptible(lock)) + if (lock && mutex_lock_interruptible(lock)) { + if (req_queue_lock) + mutex_unlock(req_queue_lock); return -ERESTARTSYS; + } if (!video_is_registered(vfd)) { ret = -ENODEV; @@ -2908,6 +3055,8 @@ unlock: if (lock) mutex_unlock(lock); + if (req_queue_lock) + mutex_unlock(req_queue_lock); return ret; } @@ -2976,8 +3125,170 @@ return ret; } +static unsigned int video_translate_cmd(unsigned int cmd) +{ + switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_DQEVENT_TIME32: + return VIDIOC_DQEVENT; + case VIDIOC_QUERYBUF_TIME32: + return VIDIOC_QUERYBUF; + case VIDIOC_QBUF_TIME32: + return VIDIOC_QBUF; + case VIDIOC_DQBUF_TIME32: + return VIDIOC_DQBUF; + case VIDIOC_PREPARE_BUF_TIME32: + return VIDIOC_PREPARE_BUF; +#endif + } + + return cmd; +} + +static int video_get_user(void __user *arg, void *parg, unsigned int cmd, + bool *always_copy) +{ + unsigned int n = _IOC_SIZE(cmd); + + if (!(_IOC_DIR(cmd) & _IOC_WRITE)) { + /* read-only ioctl */ + memset(parg, 0, n); + return 0; + } + + switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_QUERYBUF_TIME32: + case VIDIOC_QBUF_TIME32: + case VIDIOC_DQBUF_TIME32: + case VIDIOC_PREPARE_BUF_TIME32: { + struct v4l2_buffer_time32 vb32; + struct v4l2_buffer *vb = parg; + + if (copy_from_user(&vb32, arg, sizeof(vb32))) + return -EFAULT; + + *vb = (struct v4l2_buffer) { + .index = vb32.index, + .type = vb32.type, + .bytesused = vb32.bytesused, + .flags = vb32.flags, + .field = vb32.field, + .timestamp.tv_sec = vb32.timestamp.tv_sec, + .timestamp.tv_usec = vb32.timestamp.tv_usec, + .timecode = vb32.timecode, + .sequence = vb32.sequence, + .memory = vb32.memory, + .m.userptr = vb32.m.userptr, + .length = vb32.length, + .request_fd = vb32.request_fd, +#if defined(CONFIG_ARCH_ROCKCHIP) && IS_ENABLED(CONFIG_USB_F_UVC) + .reserved2 = vb32.reserved2, +#endif + }; + + if (cmd == VIDIOC_QUERYBUF_TIME32) + vb->request_fd = 0; + + break; + } +#endif + default: + /* + * In some cases, only a few fields are used as input, + * i.e. when the app sets "index" and then the driver + * fills in the rest of the structure for the thing + * with that index. We only need to copy up the first + * non-input field. + */ + if (v4l2_is_known_ioctl(cmd)) { + u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags; + + if (flags & INFO_FL_CLEAR_MASK) + n = (flags & INFO_FL_CLEAR_MASK) >> 16; + *always_copy = flags & INFO_FL_ALWAYS_COPY; + trace_android_vh_clear_mask_adjust(v4l2_ioctls[_IOC_NR(cmd)].ioctl, &n); + } + + if (copy_from_user(parg, (void __user *)arg, n)) + return -EFAULT; + + /* zero out anything we don't copy from userspace */ + if (n < _IOC_SIZE(cmd)) + memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); + break; + } + + return 0; +} + +static int video_put_user(void __user *arg, void *parg, unsigned int cmd) +{ + if (!(_IOC_DIR(cmd) & _IOC_READ)) + return 0; + + switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_DQEVENT_TIME32: { + struct v4l2_event *ev = parg; + struct v4l2_event_time32 ev32; + + memset(&ev32, 0, sizeof(ev32)); + + ev32.type = ev->type; + ev32.pending = ev->pending; + ev32.sequence = ev->sequence; + ev32.timestamp.tv_sec = ev->timestamp.tv_sec; + ev32.timestamp.tv_nsec = ev->timestamp.tv_nsec; + ev32.id = ev->id; + + memcpy(&ev32.u, &ev->u, sizeof(ev->u)); + memcpy(&ev32.reserved, &ev->reserved, sizeof(ev->reserved)); + + if (copy_to_user(arg, &ev32, sizeof(ev32))) + return -EFAULT; + break; + } + case VIDIOC_QUERYBUF_TIME32: + case VIDIOC_QBUF_TIME32: + case VIDIOC_DQBUF_TIME32: + case VIDIOC_PREPARE_BUF_TIME32: { + struct v4l2_buffer *vb = parg; + struct v4l2_buffer_time32 vb32; + + memset(&vb32, 0, sizeof(vb32)); + + vb32.index = vb->index; + vb32.type = vb->type; + vb32.bytesused = vb->bytesused; + vb32.flags = vb->flags; + vb32.field = vb->field; + vb32.timestamp.tv_sec = vb->timestamp.tv_sec; + vb32.timestamp.tv_usec = vb->timestamp.tv_usec; + vb32.timecode = vb->timecode; + vb32.sequence = vb->sequence; + vb32.memory = vb->memory; + vb32.m.userptr = vb->m.userptr; + vb32.length = vb->length; + vb32.request_fd = vb->request_fd; + + if (copy_to_user(arg, &vb32, sizeof(vb32))) + return -EFAULT; + break; + } +#endif + default: + /* Copy results into user buffer */ + if (copy_to_user(arg, parg, _IOC_SIZE(cmd))) + return -EFAULT; + break; + } + + return 0; +} + long -video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, +video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, v4l2_kioctl func) { char sbuf[128]; @@ -2989,6 +3300,7 @@ size_t array_size = 0; void __user *user_ptr = NULL; void **kernel_ptr = NULL; + unsigned int cmd = video_translate_cmd(orig_cmd); const size_t ioc_size = _IOC_SIZE(cmd); /* Copy arguments into temp kernel buffer */ @@ -3003,35 +3315,10 @@ parg = mbuf; } - err = -EFAULT; - if (_IOC_DIR(cmd) & _IOC_WRITE) { - unsigned int n = ioc_size; - - /* - * In some cases, only a few fields are used as input, - * i.e. when the app sets "index" and then the driver - * fills in the rest of the structure for the thing - * with that index. We only need to copy up the first - * non-input field. - */ - if (v4l2_is_known_ioctl(cmd)) { - u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags; - - if (flags & INFO_FL_CLEAR_MASK) - n = (flags & INFO_FL_CLEAR_MASK) >> 16; - always_copy = flags & INFO_FL_ALWAYS_COPY; - } - - if (copy_from_user(parg, (void __user *)arg, n)) - goto out; - - /* zero out anything we don't copy from userspace */ - if (n < ioc_size) - memset((u8 *)parg + n, 0, ioc_size - n); - } else { - /* read-only ioctl */ - memset(parg, 0, ioc_size); - } + err = video_get_user((void __user *)arg, parg, orig_cmd, + &always_copy); + if (err) + goto out; } err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr); @@ -3078,21 +3365,13 @@ goto out; out_array_args: - /* Copy results into user buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_READ: - case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, ioc_size)) - err = -EFAULT; - break; - } - + if (video_put_user((void __user *)arg, parg, orig_cmd)) + err = -EFAULT; out: kvfree(array_buf); kvfree(mbuf); return err; } -EXPORT_SYMBOL_GPL(video_usercopy); long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg) -- Gitblit v1.6.2