162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cx18 ioctl control functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Derived from ivtv-controls.c 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "cx18-driver.h" 1362306a36Sopenharmony_ci#include "cx18-cards.h" 1462306a36Sopenharmony_ci#include "cx18-ioctl.h" 1562306a36Sopenharmony_ci#include "cx18-audio.h" 1662306a36Sopenharmony_ci#include "cx18-mailbox.h" 1762306a36Sopenharmony_ci#include "cx18-controls.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); 2262306a36Sopenharmony_ci int type = cxhdl->stream_type->val; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (atomic_read(&cx->ana_capturing) > 0) 2562306a36Sopenharmony_ci return -EBUSY; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV || 2862306a36Sopenharmony_ci !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS || 2962306a36Sopenharmony_ci type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD || 3062306a36Sopenharmony_ci type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) { 3162306a36Sopenharmony_ci /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */ 3262306a36Sopenharmony_ci cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE; 3362306a36Sopenharmony_ci CX18_DEBUG_INFO("disabled insertion of sliced VBI data into the MPEG stream\n"); 3462306a36Sopenharmony_ci return 0; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* Allocate sliced VBI buffers if needed. */ 3862306a36Sopenharmony_ci if (cx->vbi.sliced_mpeg_data[0] == NULL) { 3962306a36Sopenharmony_ci int i; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci for (i = 0; i < CX18_VBI_FRAMES; i++) { 4262306a36Sopenharmony_ci cx->vbi.sliced_mpeg_data[i] = 4362306a36Sopenharmony_ci kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL); 4462306a36Sopenharmony_ci if (cx->vbi.sliced_mpeg_data[i] == NULL) { 4562306a36Sopenharmony_ci while (--i >= 0) { 4662306a36Sopenharmony_ci kfree(cx->vbi.sliced_mpeg_data[i]); 4762306a36Sopenharmony_ci cx->vbi.sliced_mpeg_data[i] = NULL; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci cx->vbi.insert_mpeg = 5062306a36Sopenharmony_ci V4L2_MPEG_STREAM_VBI_FMT_NONE; 5162306a36Sopenharmony_ci CX18_WARN("Unable to allocate buffers for sliced VBI data insertion\n"); 5262306a36Sopenharmony_ci return -ENOMEM; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci cx->vbi.insert_mpeg = fmt; 5862306a36Sopenharmony_ci CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,when sliced VBI is enabled\n"); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* 6162306a36Sopenharmony_ci * If our current settings have no lines set for capture, store a valid, 6262306a36Sopenharmony_ci * default set of service lines to capture, in our current settings. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci if (cx18_get_service_set(cx->vbi.sliced_in) == 0) { 6562306a36Sopenharmony_ci if (cx->is_60hz) 6662306a36Sopenharmony_ci cx->vbi.sliced_in->service_set = 6762306a36Sopenharmony_ci V4L2_SLICED_CAPTION_525; 6862306a36Sopenharmony_ci else 6962306a36Sopenharmony_ci cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; 7062306a36Sopenharmony_ci cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz); 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); 7862306a36Sopenharmony_ci int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; 7962306a36Sopenharmony_ci struct v4l2_subdev_format format = { 8062306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 8162306a36Sopenharmony_ci }; 8262306a36Sopenharmony_ci struct v4l2_mbus_framefmt *fmt = &format.format; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* fix videodecoder resolution */ 8562306a36Sopenharmony_ci fmt->width = cxhdl->width / (is_mpeg1 ? 2 : 1); 8662306a36Sopenharmony_ci fmt->height = cxhdl->height; 8762306a36Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_FIXED; 8862306a36Sopenharmony_ci v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci static const u32 freqs[3] = { 44100, 48000, 32000 }; 9562306a36Sopenharmony_ci struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* The audio clock of the digitizer must match the codec sample 9862306a36Sopenharmony_ci rate otherwise you get some very strange effects. */ 9962306a36Sopenharmony_ci if (idx < ARRAY_SIZE(freqs)) 10062306a36Sopenharmony_ci cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci cx->dualwatch_stereo_mode = val; 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciconst struct cx2341x_handler_ops cx18_cxhdl_ops = { 11362306a36Sopenharmony_ci .s_audio_mode = cx18_s_audio_mode, 11462306a36Sopenharmony_ci .s_audio_sampling_freq = cx18_s_audio_sampling_freq, 11562306a36Sopenharmony_ci .s_video_encoding = cx18_s_video_encoding, 11662306a36Sopenharmony_ci .s_stream_vbi_fmt = cx18_s_stream_vbi_fmt, 11762306a36Sopenharmony_ci}; 118