Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 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 | */ |
Andy Walls | 225aeb1 | 2009-07-23 21:51:29 -0300 | [diff] [blame] | 23 | #include <linux/kernel.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 24 | #include <linux/slab.h> |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 25 | |
| 26 | #include "cx18-driver.h" |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 27 | #include "cx18-cards.h" |
| 28 | #include "cx18-ioctl.h" |
| 29 | #include "cx18-audio.h" |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 30 | #include "cx18-mailbox.h" |
| 31 | #include "cx18-controls.h" |
| 32 | |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 33 | static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 34 | { |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 35 | struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); |
| 36 | int type = cxhdl->stream_type->val; |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 37 | |
Hans Verkuil | 31554ae | 2008-05-25 11:21:27 -0300 | [diff] [blame] | 38 | if (atomic_read(&cx->ana_capturing) > 0) |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 39 | return -EBUSY; |
| 40 | |
Andy Walls | 49a5375 | 2009-03-01 23:10:07 -0300 | [diff] [blame] | 41 | if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV || |
Andy Walls | 0c62925 | 2009-04-26 16:34:36 -0300 | [diff] [blame] | 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 */ |
Andy Walls | 49a5375 | 2009-03-01 23:10:07 -0300 | [diff] [blame] | 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) { |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 54 | int i; |
| 55 | |
| 56 | for (i = 0; i < CX18_VBI_FRAMES; i++) { |
Andy Walls | 302df97 | 2009-01-31 00:33:02 -0300 | [diff] [blame] | 57 | cx->vbi.sliced_mpeg_data[i] = |
| 58 | kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL); |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 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 | } |
Andy Walls | 49a5375 | 2009-03-01 23:10:07 -0300 | [diff] [blame] | 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"); |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 68 | return -ENOMEM; |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | cx->vbi.insert_mpeg = fmt; |
Andy Walls | 49a5375 | 2009-03-01 23:10:07 -0300 | [diff] [blame] | 74 | CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS," |
| 75 | "when sliced VBI is enabled\n"); |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 76 | |
Andy Walls | 49a5375 | 2009-03-01 23:10:07 -0300 | [diff] [blame] | 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 | */ |
Mauro Carvalho Chehab | aed6abd | 2008-04-29 21:38:51 -0300 | [diff] [blame] | 81 | if (cx18_get_service_set(cx->vbi.sliced_in) == 0) { |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 82 | if (cx->is_60hz) |
Andy Walls | 49a5375 | 2009-03-01 23:10:07 -0300 | [diff] [blame] | 83 | cx->vbi.sliced_in->service_set = |
| 84 | V4L2_SLICED_CAPTION_525; |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 85 | else |
| 86 | cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; |
Mauro Carvalho Chehab | aed6abd | 2008-04-29 21:38:51 -0300 | [diff] [blame] | 87 | cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz); |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 88 | } |
| 89 | return 0; |
| 90 | } |
| 91 | |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 92 | static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 93 | { |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 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; |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 97 | |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 98 | /* fix videodecoder resolution */ |
| 99 | fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); |
| 100 | fmt.height = cxhdl->height; |
| 101 | fmt.code = V4L2_MBUS_FMT_FIXED; |
| 102 | v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); |
| 103 | return 0; |
Andy Walls | 3b6fe58 | 2008-06-21 08:36:31 -0300 | [diff] [blame] | 104 | } |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 105 | |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 106 | static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) |
Andy Walls | 3b6fe58 | 2008-06-21 08:36:31 -0300 | [diff] [blame] | 107 | { |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 108 | static const u32 freqs[3] = { 44100, 48000, 32000 }; |
| 109 | struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 110 | |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 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; |
Andy Walls | 3b6fe58 | 2008-06-21 08:36:31 -0300 | [diff] [blame] | 116 | } |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 117 | |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 118 | static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) |
Andy Walls | 3b6fe58 | 2008-06-21 08:36:31 -0300 | [diff] [blame] | 119 | { |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 120 | struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 121 | |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 122 | cx->dualwatch_stereo_mode = val; |
| 123 | return 0; |
Hans Verkuil | 1c1e45d | 2008-04-28 20:24:33 -0300 | [diff] [blame] | 124 | } |
Hans Verkuil | a75b9be | 2010-12-31 10:22:52 -0300 | [diff] [blame] | 125 | |
| 126 | struct 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 | }; |