summaryrefslogtreecommitdiff
path: root/drivers/media/common/cx2341x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/common/cx2341x.c')
-rw-r--r--drivers/media/common/cx2341x.c218
1 files changed, 135 insertions, 83 deletions
diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c
index 103ef6bad2e2..1ee159ef7f38 100644
--- a/drivers/media/common/cx2341x.c
+++ b/drivers/media/common/cx2341x.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* cx2341x - generic code for cx23415/6/8 based devices
*
- * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Copyright (C) 2006 Hans Verkuil <hverkuil@kernel.org>
*/
@@ -27,7 +14,7 @@
#include <linux/videodev2.h>
#include <media/tuner.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
#include <media/v4l2-common.h>
MODULE_DESCRIPTION("cx23415/6/8 driver");
@@ -179,7 +166,7 @@ static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *ty
/* Must be sorted from low to high control ID! */
const u32 cx2341x_mpeg_ctrls[] = {
- V4L2_CID_MPEG_CLASS,
+ V4L2_CID_CODEC_CLASS,
V4L2_CID_MPEG_STREAM_TYPE,
V4L2_CID_MPEG_STREAM_VBI_FMT,
V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
@@ -573,7 +560,7 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
qctrl->step = step;
qctrl->default_value = def;
qctrl->reserved[0] = qctrl->reserved[1] = 0;
- strlcpy(qctrl->name, name, sizeof(qctrl->name));
+ strscpy(qctrl->name, name, sizeof(qctrl->name));
return 0;
default:
@@ -587,7 +574,7 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
int err;
switch (qctrl->id) {
- case V4L2_CID_MPEG_CLASS:
+ case V4L2_CID_CODEC_CLASS:
return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
case V4L2_CID_MPEG_STREAM_TYPE:
return v4l2_ctrl_query_fill(qctrl,
@@ -931,6 +918,35 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
}
}
+/* Check for correctness of the ctrl's value based on the data from
+ struct v4l2_queryctrl and the available menu items. Note that
+ menu_items may be NULL, in that case it is ignored. */
+static int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char * const *menu_items)
+{
+ if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ return -EINVAL;
+ if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+ return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_STRING)
+ return 0;
+ if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
+ qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return 0;
+ if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
+ return -ERANGE;
+ if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
+ if (menu_items[ctrl->value] == NULL ||
+ menu_items[ctrl->value][0] == '\0')
+ return -EINVAL;
+ }
+ if (qctrl->type == V4L2_CTRL_TYPE_BITMASK &&
+ (ctrl->value & ~qctrl->maximum))
+ return -ERANGE;
+ return 0;
+}
+
int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
struct v4l2_ext_controls *ctrls, unsigned int cmd)
{
@@ -1003,7 +1019,7 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func,
return func(priv, cmd, args, 0, data);
}
-#define NEQ(field) (old->field != new->field)
+#define CMP_FIELD(__old, __new, __field) (__old->__field != __new->__field)
int cx2341x_update(void *priv, cx2341x_mbox_func func,
const struct cx2341x_mpeg_params *old,
@@ -1017,20 +1033,22 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
11, /* VCD */
12, /* SVCD */
};
-
- int err = 0;
- int force = (old == NULL);
- u16 temporal = new->video_temporal_filter;
+ int err;
cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
- if (force || NEQ(is_50hz)) {
+ if (!old ||
+ CMP_FIELD(old, new, is_50hz)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
new->is_50hz);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
+ if (!old ||
+ CMP_FIELD(old, new, width) ||
+ CMP_FIELD(old, new, height) ||
+ CMP_FIELD(old, new, video_encoding)) {
u16 w = new->width;
u16 h = new->height;
@@ -1040,94 +1058,127 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
}
err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
h, w);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(stream_type)) {
+ if (!old ||
+ CMP_FIELD(old, new, stream_type)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
mpeg_stream_type[new->stream_type]);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(video_aspect)) {
+ if (!old ||
+ CMP_FIELD(old, new, video_aspect)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
1 + new->video_aspect);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
+ if (!old ||
+ CMP_FIELD(old, new, video_b_frames) ||
+ CMP_FIELD(old, new, video_gop_size)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
- new->video_gop_size, new->video_b_frames + 1);
- if (err) return err;
+ new->video_gop_size, new->video_b_frames + 1);
+ if (err)
+ return err;
}
- if (force || NEQ(video_gop_closure)) {
+ if (!old ||
+ CMP_FIELD(old, new, video_gop_closure)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
new->video_gop_closure);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(audio_properties)) {
+ if (!old ||
+ CMP_FIELD(old, new, audio_properties)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
1, new->audio_properties);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(audio_mute)) {
+ if (!old ||
+ CMP_FIELD(old, new, audio_mute)) {
err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
new->audio_mute);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
- NEQ(video_bitrate_peak)) {
+ if (!old ||
+ CMP_FIELD(old, new, video_bitrate_mode) ||
+ CMP_FIELD(old, new, video_bitrate) ||
+ CMP_FIELD(old, new, video_bitrate_peak)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
- new->video_bitrate_mode, new->video_bitrate,
- new->video_bitrate_peak / 400, 0, 0);
- if (err) return err;
+ new->video_bitrate_mode, new->video_bitrate,
+ new->video_bitrate_peak / 400, 0, 0);
+ if (err)
+ return err;
}
- if (force || NEQ(video_spatial_filter_mode) ||
- NEQ(video_temporal_filter_mode) ||
- NEQ(video_median_filter_type)) {
+ if (!old ||
+ CMP_FIELD(old, new, video_spatial_filter_mode) ||
+ CMP_FIELD(old, new, video_temporal_filter_mode) ||
+ CMP_FIELD(old, new, video_median_filter_type)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
- 2, new->video_spatial_filter_mode |
+ 2,
+ new->video_spatial_filter_mode |
(new->video_temporal_filter_mode << 1),
- new->video_median_filter_type);
- if (err) return err;
+ new->video_median_filter_type);
+ if (err)
+ return err;
}
- if (force || NEQ(video_luma_median_filter_bottom) ||
- NEQ(video_luma_median_filter_top) ||
- NEQ(video_chroma_median_filter_bottom) ||
- NEQ(video_chroma_median_filter_top)) {
+ if (!old ||
+ CMP_FIELD(old, new, video_luma_median_filter_bottom) ||
+ CMP_FIELD(old, new, video_luma_median_filter_top) ||
+ CMP_FIELD(old, new, video_chroma_median_filter_bottom) ||
+ CMP_FIELD(old, new, video_chroma_median_filter_top)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
- new->video_luma_median_filter_bottom,
- new->video_luma_median_filter_top,
- new->video_chroma_median_filter_bottom,
- new->video_chroma_median_filter_top);
- if (err) return err;
+ new->video_luma_median_filter_bottom,
+ new->video_luma_median_filter_top,
+ new->video_chroma_median_filter_bottom,
+ new->video_chroma_median_filter_top);
+ if (err)
+ return err;
}
- if (force || NEQ(video_luma_spatial_filter_type) ||
- NEQ(video_chroma_spatial_filter_type)) {
+ if (!old ||
+ CMP_FIELD(old, new, video_luma_spatial_filter_type) ||
+ CMP_FIELD(old, new, video_chroma_spatial_filter_type)) {
err = cx2341x_api(priv, func,
CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
2, new->video_luma_spatial_filter_type,
new->video_chroma_spatial_filter_type);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(video_spatial_filter) ||
- old->video_temporal_filter != temporal) {
+ if (!old ||
+ CMP_FIELD(old, new, video_spatial_filter) ||
+ CMP_FIELD(old, new, video_temporal_filter)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
- 2, new->video_spatial_filter, temporal);
- if (err) return err;
+ 2, new->video_spatial_filter,
+ new->video_temporal_filter);
+ if (err)
+ return err;
}
- if (force || NEQ(video_temporal_decimation)) {
+ if (!old ||
+ CMP_FIELD(old, new, video_temporal_decimation)) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
1, new->video_temporal_decimation);
- if (err) return err;
+ if (err)
+ return err;
}
- if (force || NEQ(video_mute) ||
- (new->video_mute && NEQ(video_mute_yuv))) {
+ if (!old ||
+ CMP_FIELD(old, new, video_mute) ||
+ (new->video_mute && CMP_FIELD(old, new, video_mute_yuv))) {
err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
- new->video_mute | (new->video_mute_yuv << 8));
- if (err) return err;
+ new->video_mute | (new->video_mute_yuv << 8));
+ if (err)
+ return err;
}
- if (force || NEQ(stream_insert_nav_packets)) {
+ if (!old ||
+ CMP_FIELD(old, new, stream_insert_nav_packets)) {
err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
- 7, new->stream_insert_nav_packets);
- if (err) return err;
+ 7, new->stream_insert_nav_packets);
+ if (err)
+ return err;
}
return 0;
}
@@ -1161,8 +1212,8 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
if (p->stream_insert_nav_packets)
- printk(" (with navigation packets)");
- printk("\n");
+ printk(KERN_CONT " (with navigation packets)");
+ printk(KERN_CONT "\n");
printk(KERN_INFO "%s: VBI Format: %s\n",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
@@ -1180,8 +1231,8 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
p->video_bitrate);
if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
- printk(", Peak %d", p->video_bitrate_peak);
- printk("\n");
+ printk(KERN_CONT ", Peak %d", p->video_bitrate_peak);
+ printk(KERN_CONT "\n");
printk(KERN_INFO
"%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
prefix,
@@ -1203,9 +1254,9 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
p->audio_mute ? " (muted)" : "");
if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
- printk(", %s", cx2341x_menu_item(p,
+ printk(KERN_CONT ", %s", cx2341x_menu_item(p,
V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
- printk(", %s, %s\n",
+ printk(KERN_CONT ", %s, %s\n",
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
@@ -1490,6 +1541,7 @@ static struct v4l2_ctrl *cx2341x_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
{
struct v4l2_ctrl_config cfg;
+ memset(&cfg, 0, sizeof(cfg));
cx2341x_ctrl_fill(id, &cfg.name, &cfg.type, &min, &max, &step, &def, &cfg.flags);
cfg.ops = &cx2341x_ops;
cfg.id = id;