1/* 2 ioctl control functions 3 Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> 4 Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 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 19 */ 20 21#include "ivtv-driver.h" 22#include "ivtv-cards.h" 23#include "ivtv-ioctl.h" 24#include "ivtv-audio.h" 25#include "ivtv-i2c.h" 26#include "ivtv-mailbox.h" 27#include "ivtv-controls.h" 28 29static const u32 user_ctrls[] = { 30 V4L2_CID_USER_CLASS, 31 V4L2_CID_BRIGHTNESS, 32 V4L2_CID_CONTRAST, 33 V4L2_CID_SATURATION, 34 V4L2_CID_HUE, 35 V4L2_CID_AUDIO_VOLUME, 36 V4L2_CID_AUDIO_BALANCE, 37 V4L2_CID_AUDIO_BASS, 38 V4L2_CID_AUDIO_TREBLE, 39 V4L2_CID_AUDIO_MUTE, 40 V4L2_CID_AUDIO_LOUDNESS, 41 0 42}; 43 44static const u32 *ctrl_classes[] = { 45 user_ctrls, 46 cx2341x_mpeg_ctrls, 47 NULL 48}; 49 50static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) 51{ 52 const char *name; 53 54 IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); 55 56 qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); 57 if (qctrl->id == 0) 58 return -EINVAL; 59 60 switch (qctrl->id) { 61 /* Standard V4L2 controls */ 62 case V4L2_CID_BRIGHTNESS: 63 case V4L2_CID_HUE: 64 case V4L2_CID_SATURATION: 65 case V4L2_CID_CONTRAST: 66 if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl)) 67 qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; 68 return 0; 69 70 case V4L2_CID_AUDIO_VOLUME: 71 case V4L2_CID_AUDIO_MUTE: 72 case V4L2_CID_AUDIO_BALANCE: 73 case V4L2_CID_AUDIO_BASS: 74 case V4L2_CID_AUDIO_TREBLE: 75 case V4L2_CID_AUDIO_LOUDNESS: 76 if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) 77 qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; 78 return 0; 79 80 default: 81 if (cx2341x_ctrl_query(&itv->params, qctrl)) 82 qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; 83 return 0; 84 } 85 strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); 86 qctrl->name[sizeof(qctrl->name) - 1] = 0; 87 return 0; 88} 89 90static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu) 91{ 92 struct v4l2_queryctrl qctrl; 93 94 qctrl.id = qmenu->id; 95 ivtv_queryctrl(itv, &qctrl); 96 return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); 97} 98 99static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) 100{ 101 s32 v = vctrl->value; 102 103 IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); 104 105 switch (vctrl->id) { 106 /* Standard V4L2 controls */ 107 case V4L2_CID_BRIGHTNESS: 108 case V4L2_CID_HUE: 109 case V4L2_CID_SATURATION: 110 case V4L2_CID_CONTRAST: 111 return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl); 112 113 case V4L2_CID_AUDIO_VOLUME: 114 case V4L2_CID_AUDIO_MUTE: 115 case V4L2_CID_AUDIO_BALANCE: 116 case V4L2_CID_AUDIO_BASS: 117 case V4L2_CID_AUDIO_TREBLE: 118 case V4L2_CID_AUDIO_LOUDNESS: 119 return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); 120 121 default: 122 IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); 123 return -EINVAL; 124 } 125 return 0; 126} 127 128static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) 129{ 130 IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); 131 132 switch (vctrl->id) { 133 /* Standard V4L2 controls */ 134 case V4L2_CID_BRIGHTNESS: 135 case V4L2_CID_HUE: 136 case V4L2_CID_SATURATION: 137 case V4L2_CID_CONTRAST: 138 return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl); 139 140 case V4L2_CID_AUDIO_VOLUME: 141 case V4L2_CID_AUDIO_MUTE: 142 case V4L2_CID_AUDIO_BALANCE: 143 case V4L2_CID_AUDIO_BASS: 144 case V4L2_CID_AUDIO_TREBLE: 145 case V4L2_CID_AUDIO_LOUDNESS: 146 return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); 147 default: 148 IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); 149 return -EINVAL; 150 } 151 return 0; 152} 153 154static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt) 155{ 156 if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) 157 return -EINVAL; 158 if (atomic_read(&itv->capturing) > 0) 159 return -EBUSY; 160 161 /* First try to allocate sliced VBI buffers if needed. */ 162 if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { 163 int i; 164 165 for (i = 0; i < IVTV_VBI_FRAMES; i++) { 166 /* Yuck, hardcoded. Needs to be a define */ 167 itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); 168 if (itv->vbi.sliced_mpeg_data[i] == NULL) { 169 while (--i >= 0) { 170 kfree(itv->vbi.sliced_mpeg_data[i]); 171 itv->vbi.sliced_mpeg_data[i] = NULL; 172 } 173 return -ENOMEM; 174 } 175 } 176 } 177 178 itv->vbi.insert_mpeg = fmt; 179 180 if (itv->vbi.insert_mpeg == 0) { 181 return 0; 182 } 183 /* Need sliced data for mpeg insertion */ 184 if (get_service_set(itv->vbi.sliced_in) == 0) { 185 if (itv->is_60hz) 186 itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; 187 else 188 itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; 189 expand_service_set(itv->vbi.sliced_in, itv->is_50hz); 190 } 191 return 0; 192} 193 194int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) 195{ 196 struct v4l2_control ctrl; 197 198 switch (cmd) { 199 case VIDIOC_QUERYMENU: 200 IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); 201 return ivtv_querymenu(itv, arg); 202 203 case VIDIOC_QUERYCTRL: 204 return ivtv_queryctrl(itv, arg); 205 206 case VIDIOC_S_CTRL: 207 return ivtv_s_ctrl(itv, arg); 208 209 case VIDIOC_G_CTRL: 210 return ivtv_g_ctrl(itv, arg); 211 212 case VIDIOC_S_EXT_CTRLS: 213 { 214 struct v4l2_ext_controls *c = arg; 215 216 if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { 217 int i; 218 int err = 0; 219 220 for (i = 0; i < c->count; i++) { 221 ctrl.id = c->controls[i].id; 222 ctrl.value = c->controls[i].value; 223 err = ivtv_s_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 IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); 233 if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { 234 struct cx2341x_mpeg_params p = itv->params; 235 int err = cx2341x_ext_ctrls(&p, arg, cmd); 236 237 if (err) 238 return err; 239 240 if (p.video_encoding != itv->params.video_encoding) { 241 int is_mpeg1 = p.video_encoding == 242 V4L2_MPEG_VIDEO_ENCODING_MPEG_1; 243 struct v4l2_format fmt; 244 245 /* fix videodecoder resolution */ 246 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 247 fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); 248 fmt.fmt.pix.height = itv->params.height; 249 itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); 250 } 251 err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); 252 if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) { 253 err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); 254 } 255 itv->params = p; 256 itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; 257 ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03); 258 return err; 259 } 260 return -EINVAL; 261 } 262 263 case VIDIOC_G_EXT_CTRLS: 264 { 265 struct v4l2_ext_controls *c = arg; 266 267 if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { 268 int i; 269 int err = 0; 270 271 for (i = 0; i < c->count; i++) { 272 ctrl.id = c->controls[i].id; 273 ctrl.value = c->controls[i].value; 274 err = ivtv_g_ctrl(itv, &ctrl); 275 c->controls[i].value = ctrl.value; 276 if (err) { 277 c->error_idx = i; 278 break; 279 } 280 } 281 return err; 282 } 283 IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); 284 if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) 285 return cx2341x_ext_ctrls(&itv->params, arg, cmd); 286 return -EINVAL; 287 } 288 289 case VIDIOC_TRY_EXT_CTRLS: 290 { 291 struct v4l2_ext_controls *c = arg; 292 293 IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); 294 if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) 295 return cx2341x_ext_ctrls(&itv->params, arg, cmd); 296 return -EINVAL; 297 } 298 299 default: 300 return -EINVAL; 301 } 302 return 0; 303} 304