1/*
2 *  cx18 ioctl control functions
3 *
4 *  Derived from ivtv-controls.c
5 *
6 *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 *  02111-1307  USA
22 */
23#include <linux/kernel.h>
24#include <linux/slab.h>
25
26#include "cx18-driver.h"
27#include "cx18-cards.h"
28#include "cx18-ioctl.h"
29#include "cx18-audio.h"
30#include "cx18-mailbox.h"
31#include "cx18-controls.h"
32
33static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
34{
35	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
36	int type = cxhdl->stream_type->val;
37
38	if (atomic_read(&cx->ana_capturing) > 0)
39		return -EBUSY;
40
41	if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
42	    !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS ||
43	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD ||
44	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) {
45		/* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */
46		cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
47		CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
48				"the MPEG stream\n");
49		return 0;
50	}
51
52	/* Allocate sliced VBI buffers if needed. */
53	if (cx->vbi.sliced_mpeg_data[0] == NULL) {
54		int i;
55
56		for (i = 0; i < CX18_VBI_FRAMES; i++) {
57			cx->vbi.sliced_mpeg_data[i] =
58			       kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
59			if (cx->vbi.sliced_mpeg_data[i] == NULL) {
60				while (--i >= 0) {
61					kfree(cx->vbi.sliced_mpeg_data[i]);
62					cx->vbi.sliced_mpeg_data[i] = NULL;
63				}
64				cx->vbi.insert_mpeg =
65						  V4L2_MPEG_STREAM_VBI_FMT_NONE;
66				CX18_WARN("Unable to allocate buffers for "
67					  "sliced VBI data insertion\n");
68				return -ENOMEM;
69			}
70		}
71	}
72
73	cx->vbi.insert_mpeg = fmt;
74	CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,"
75			"when sliced VBI is enabled\n");
76
77	/*
78	 * If our current settings have no lines set for capture, store a valid,
79	 * default set of service lines to capture, in our current settings.
80	 */
81	if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
82		if (cx->is_60hz)
83			cx->vbi.sliced_in->service_set =
84							V4L2_SLICED_CAPTION_525;
85		else
86			cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
87		cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
88	}
89	return 0;
90}
91
92static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
93{
94	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
95	int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
96	struct v4l2_mbus_framefmt fmt;
97
98	/* fix videodecoder resolution */
99	fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
100	fmt.height = cxhdl->height;
101	fmt.code = MEDIA_BUS_FMT_FIXED;
102	v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
103	return 0;
104}
105
106static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
107{
108	static const u32 freqs[3] = { 44100, 48000, 32000 };
109	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
110
111	/* The audio clock of the digitizer must match the codec sample
112	   rate otherwise you get some very strange effects. */
113	if (idx < ARRAY_SIZE(freqs))
114		cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
115	return 0;
116}
117
118static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
119{
120	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
121
122	cx->dualwatch_stereo_mode = val;
123	return 0;
124}
125
126struct cx2341x_handler_ops cx18_cxhdl_ops = {
127	.s_audio_mode = cx18_s_audio_mode,
128	.s_audio_sampling_freq = cx18_s_audio_sampling_freq,
129	.s_video_encoding = cx18_s_video_encoding,
130	.s_stream_vbi_fmt = cx18_s_stream_vbi_fmt,
131};
132