diff options
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-controls.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-controls.c | 276 |
1 files changed, 32 insertions, 244 deletions
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index b588e30cbcf0..b31ee1bceef8 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c | |||
@@ -17,163 +17,14 @@ | |||
17 | along with this program; if not, write to the Free Software | 17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | #include <linux/kernel.h> | ||
21 | #include <linux/slab.h> | ||
22 | 20 | ||
23 | #include "ivtv-driver.h" | 21 | #include "ivtv-driver.h" |
24 | #include "ivtv-cards.h" | ||
25 | #include "ivtv-ioctl.h" | 22 | #include "ivtv-ioctl.h" |
26 | #include "ivtv-routing.h" | ||
27 | #include "ivtv-i2c.h" | ||
28 | #include "ivtv-mailbox.h" | ||
29 | #include "ivtv-controls.h" | 23 | #include "ivtv-controls.h" |
30 | 24 | ||
31 | /* Must be sorted from low to high control ID! */ | 25 | static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) |
32 | static const u32 user_ctrls[] = { | ||
33 | V4L2_CID_USER_CLASS, | ||
34 | V4L2_CID_BRIGHTNESS, | ||
35 | V4L2_CID_CONTRAST, | ||
36 | V4L2_CID_SATURATION, | ||
37 | V4L2_CID_HUE, | ||
38 | V4L2_CID_AUDIO_VOLUME, | ||
39 | V4L2_CID_AUDIO_BALANCE, | ||
40 | V4L2_CID_AUDIO_BASS, | ||
41 | V4L2_CID_AUDIO_TREBLE, | ||
42 | V4L2_CID_AUDIO_MUTE, | ||
43 | V4L2_CID_AUDIO_LOUDNESS, | ||
44 | 0 | ||
45 | }; | ||
46 | |||
47 | static const u32 *ctrl_classes[] = { | ||
48 | user_ctrls, | ||
49 | cx2341x_mpeg_ctrls, | ||
50 | NULL | ||
51 | }; | ||
52 | |||
53 | |||
54 | int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) | ||
55 | { | ||
56 | struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; | ||
57 | const char *name; | ||
58 | |||
59 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
60 | if (qctrl->id == 0) | ||
61 | return -EINVAL; | ||
62 | |||
63 | switch (qctrl->id) { | ||
64 | /* Standard V4L2 controls */ | ||
65 | case V4L2_CID_USER_CLASS: | ||
66 | return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); | ||
67 | case V4L2_CID_BRIGHTNESS: | ||
68 | case V4L2_CID_HUE: | ||
69 | case V4L2_CID_SATURATION: | ||
70 | case V4L2_CID_CONTRAST: | ||
71 | if (v4l2_subdev_call(itv->sd_video, core, queryctrl, qctrl)) | ||
72 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
73 | return 0; | ||
74 | |||
75 | case V4L2_CID_AUDIO_VOLUME: | ||
76 | case V4L2_CID_AUDIO_MUTE: | ||
77 | case V4L2_CID_AUDIO_BALANCE: | ||
78 | case V4L2_CID_AUDIO_BASS: | ||
79 | case V4L2_CID_AUDIO_TREBLE: | ||
80 | case V4L2_CID_AUDIO_LOUDNESS: | ||
81 | if (v4l2_subdev_call(itv->sd_audio, core, queryctrl, qctrl)) | ||
82 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
83 | return 0; | ||
84 | |||
85 | default: | ||
86 | if (cx2341x_ctrl_query(&itv->params, qctrl)) | ||
87 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
88 | return 0; | ||
89 | } | ||
90 | strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); | ||
91 | qctrl->name[sizeof(qctrl->name) - 1] = 0; | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu) | ||
96 | { | ||
97 | struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; | ||
98 | struct v4l2_queryctrl qctrl; | ||
99 | |||
100 | qctrl.id = qmenu->id; | ||
101 | ivtv_queryctrl(file, fh, &qctrl); | ||
102 | return v4l2_ctrl_query_menu(qmenu, &qctrl, | ||
103 | cx2341x_ctrl_get_menu(&itv->params, qmenu->id)); | ||
104 | } | ||
105 | |||
106 | static int ivtv_try_ctrl(struct file *file, void *fh, | ||
107 | struct v4l2_ext_control *vctrl) | ||
108 | { | ||
109 | struct v4l2_queryctrl qctrl; | ||
110 | const char **menu_items = NULL; | ||
111 | int err; | ||
112 | |||
113 | qctrl.id = vctrl->id; | ||
114 | err = ivtv_queryctrl(file, fh, &qctrl); | ||
115 | if (err) | ||
116 | return err; | ||
117 | if (qctrl.type == V4L2_CTRL_TYPE_MENU) | ||
118 | menu_items = v4l2_ctrl_get_menu(qctrl.id); | ||
119 | return v4l2_ctrl_check(vctrl, &qctrl, menu_items); | ||
120 | } | ||
121 | |||
122 | static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) | ||
123 | { | ||
124 | switch (vctrl->id) { | ||
125 | /* Standard V4L2 controls */ | ||
126 | case V4L2_CID_BRIGHTNESS: | ||
127 | case V4L2_CID_HUE: | ||
128 | case V4L2_CID_SATURATION: | ||
129 | case V4L2_CID_CONTRAST: | ||
130 | return v4l2_subdev_call(itv->sd_video, core, s_ctrl, vctrl); | ||
131 | |||
132 | case V4L2_CID_AUDIO_VOLUME: | ||
133 | case V4L2_CID_AUDIO_MUTE: | ||
134 | case V4L2_CID_AUDIO_BALANCE: | ||
135 | case V4L2_CID_AUDIO_BASS: | ||
136 | case V4L2_CID_AUDIO_TREBLE: | ||
137 | case V4L2_CID_AUDIO_LOUDNESS: | ||
138 | return v4l2_subdev_call(itv->sd_audio, core, s_ctrl, vctrl); | ||
139 | |||
140 | default: | ||
141 | IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) | ||
148 | { | 26 | { |
149 | switch (vctrl->id) { | 27 | struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); |
150 | /* Standard V4L2 controls */ | ||
151 | case V4L2_CID_BRIGHTNESS: | ||
152 | case V4L2_CID_HUE: | ||
153 | case V4L2_CID_SATURATION: | ||
154 | case V4L2_CID_CONTRAST: | ||
155 | return v4l2_subdev_call(itv->sd_video, core, g_ctrl, vctrl); | ||
156 | |||
157 | case V4L2_CID_AUDIO_VOLUME: | ||
158 | case V4L2_CID_AUDIO_MUTE: | ||
159 | case V4L2_CID_AUDIO_BALANCE: | ||
160 | case V4L2_CID_AUDIO_BASS: | ||
161 | case V4L2_CID_AUDIO_TREBLE: | ||
162 | case V4L2_CID_AUDIO_LOUDNESS: | ||
163 | return v4l2_subdev_call(itv->sd_audio, core, g_ctrl, vctrl); | ||
164 | default: | ||
165 | IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt) | ||
172 | { | ||
173 | if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) | ||
174 | return -EINVAL; | ||
175 | if (atomic_read(&itv->capturing) > 0) | ||
176 | return -EBUSY; | ||
177 | 28 | ||
178 | /* First try to allocate sliced VBI buffers if needed. */ | 29 | /* First try to allocate sliced VBI buffers if needed. */ |
179 | if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { | 30 | if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { |
@@ -208,106 +59,43 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm | |||
208 | return 0; | 59 | return 0; |
209 | } | 60 | } |
210 | 61 | ||
211 | int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) | 62 | static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) |
212 | { | 63 | { |
213 | struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; | 64 | struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); |
214 | struct v4l2_control ctrl; | 65 | int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; |
215 | 66 | struct v4l2_mbus_framefmt fmt; | |
216 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | 67 | |
217 | int i; | 68 | /* fix videodecoder resolution */ |
218 | int err = 0; | 69 | fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); |
219 | 70 | fmt.height = cxhdl->height; | |
220 | for (i = 0; i < c->count; i++) { | 71 | fmt.code = V4L2_MBUS_FMT_FIXED; |
221 | ctrl.id = c->controls[i].id; | 72 | v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); |
222 | ctrl.value = c->controls[i].value; | 73 | return 0; |
223 | err = ivtv_g_ctrl(itv, &ctrl); | ||
224 | c->controls[i].value = ctrl.value; | ||
225 | if (err) { | ||
226 | c->error_idx = i; | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | return err; | ||
231 | } | ||
232 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
233 | return cx2341x_ext_ctrls(&itv->params, 0, c, VIDIOC_G_EXT_CTRLS); | ||
234 | return -EINVAL; | ||
235 | } | 74 | } |
236 | 75 | ||
237 | int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) | 76 | static int ivtv_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) |
238 | { | 77 | { |
239 | struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; | 78 | static const u32 freqs[3] = { 44100, 48000, 32000 }; |
240 | struct v4l2_control ctrl; | 79 | struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); |
241 | |||
242 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
243 | int i; | ||
244 | int err = 0; | ||
245 | |||
246 | for (i = 0; i < c->count; i++) { | ||
247 | ctrl.id = c->controls[i].id; | ||
248 | ctrl.value = c->controls[i].value; | ||
249 | err = ivtv_s_ctrl(itv, &ctrl); | ||
250 | c->controls[i].value = ctrl.value; | ||
251 | if (err) { | ||
252 | c->error_idx = i; | ||
253 | break; | ||
254 | } | ||
255 | } | ||
256 | return err; | ||
257 | } | ||
258 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
259 | static u32 freqs[3] = { 44100, 48000, 32000 }; | ||
260 | struct cx2341x_mpeg_params p = itv->params; | ||
261 | int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), c, VIDIOC_S_EXT_CTRLS); | ||
262 | unsigned idx; | ||
263 | |||
264 | if (err) | ||
265 | return err; | ||
266 | 80 | ||
267 | if (p.video_encoding != itv->params.video_encoding) { | 81 | /* The audio clock of the digitizer must match the codec sample |
268 | int is_mpeg1 = p.video_encoding == | 82 | rate otherwise you get some very strange effects. */ |
269 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | 83 | if (idx < ARRAY_SIZE(freqs)) |
270 | struct v4l2_mbus_framefmt fmt; | 84 | ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]); |
271 | 85 | return 0; | |
272 | /* fix videodecoder resolution */ | ||
273 | fmt.width = itv->params.width / (is_mpeg1 ? 2 : 1); | ||
274 | fmt.height = itv->params.height; | ||
275 | fmt.code = V4L2_MBUS_FMT_FIXED; | ||
276 | v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); | ||
277 | } | ||
278 | err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); | ||
279 | if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) | ||
280 | err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); | ||
281 | itv->params = p; | ||
282 | itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; | ||
283 | idx = p.audio_properties & 0x03; | ||
284 | /* The audio clock of the digitizer must match the codec sample | ||
285 | rate otherwise you get some very strange effects. */ | ||
286 | if (idx < ARRAY_SIZE(freqs)) | ||
287 | ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]); | ||
288 | return err; | ||
289 | } | ||
290 | return -EINVAL; | ||
291 | } | 86 | } |
292 | 87 | ||
293 | int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) | 88 | static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) |
294 | { | 89 | { |
295 | struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; | 90 | struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); |
296 | 91 | ||
297 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | 92 | itv->dualwatch_stereo_mode = val; |
298 | int i; | 93 | return 0; |
299 | int err = 0; | ||
300 | |||
301 | for (i = 0; i < c->count; i++) { | ||
302 | err = ivtv_try_ctrl(file, fh, &c->controls[i]); | ||
303 | if (err) { | ||
304 | c->error_idx = i; | ||
305 | break; | ||
306 | } | ||
307 | } | ||
308 | return err; | ||
309 | } | ||
310 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
311 | return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), c, VIDIOC_TRY_EXT_CTRLS); | ||
312 | return -EINVAL; | ||
313 | } | 94 | } |
95 | |||
96 | struct cx2341x_handler_ops ivtv_cxhdl_ops = { | ||
97 | .s_audio_mode = ivtv_s_audio_mode, | ||
98 | .s_audio_sampling_freq = ivtv_s_audio_sampling_freq, | ||
99 | .s_video_encoding = ivtv_s_video_encoding, | ||
100 | .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt, | ||
101 | }; | ||