linux/drivers/media/video/ivtv/ivtv-controls.c
<<
>>
Prefs
   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#include <linux/kernel.h>
  21#include <linux/slab.h>
  22
  23#include "ivtv-driver.h"
  24#include "ivtv-cards.h"
  25#include "ivtv-ioctl.h"
  26#include "ivtv-routing.h"
  27#include "ivtv-i2c.h"
  28#include "ivtv-mailbox.h"
  29#include "ivtv-controls.h"
  30
  31/* Must be sorted from low to high control ID! */
  32static 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
  47static const u32 *ctrl_classes[] = {
  48        user_ctrls,
  49        cx2341x_mpeg_ctrls,
  50        NULL
  51};
  52
  53
  54int 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
  95int 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
 106static 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
 122static 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
 147static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
 148{
 149        switch (vctrl->id) {
 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
 171static 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
 178        /* First try to allocate sliced VBI buffers if needed. */
 179        if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) {
 180                int i;
 181
 182                for (i = 0; i < IVTV_VBI_FRAMES; i++) {
 183                        /* Yuck, hardcoded. Needs to be a define */
 184                        itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
 185                        if (itv->vbi.sliced_mpeg_data[i] == NULL) {
 186                                while (--i >= 0) {
 187                                        kfree(itv->vbi.sliced_mpeg_data[i]);
 188                                        itv->vbi.sliced_mpeg_data[i] = NULL;
 189                                }
 190                                return -ENOMEM;
 191                        }
 192                }
 193        }
 194
 195        itv->vbi.insert_mpeg = fmt;
 196
 197        if (itv->vbi.insert_mpeg == 0) {
 198                return 0;
 199        }
 200        /* Need sliced data for mpeg insertion */
 201        if (ivtv_get_service_set(itv->vbi.sliced_in) == 0) {
 202                if (itv->is_60hz)
 203                        itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
 204                else
 205                        itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
 206                ivtv_expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
 207        }
 208        return 0;
 209}
 210
 211int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 212{
 213        struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 214        struct v4l2_control ctrl;
 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_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}
 236
 237int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 238{
 239        struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 240        struct v4l2_control ctrl;
 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
 267                if (p.video_encoding != itv->params.video_encoding) {
 268                        int is_mpeg1 = p.video_encoding ==
 269                                V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
 270                        struct v4l2_mbus_framefmt fmt;
 271
 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}
 292
 293int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 294{
 295        struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 296
 297        if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
 298                int i;
 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}
 314