linux/drivers/media/video/cx18/cx18-controls.c
<<
>>
Prefs
   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
  24#include "cx18-driver.h"
  25#include "cx18-av-core.h"
  26#include "cx18-cards.h"
  27#include "cx18-ioctl.h"
  28#include "cx18-audio.h"
  29#include "cx18-i2c.h"
  30#include "cx18-mailbox.h"
  31#include "cx18-controls.h"
  32
  33static const u32 user_ctrls[] = {
  34        V4L2_CID_USER_CLASS,
  35        V4L2_CID_BRIGHTNESS,
  36        V4L2_CID_CONTRAST,
  37        V4L2_CID_SATURATION,
  38        V4L2_CID_HUE,
  39        V4L2_CID_AUDIO_VOLUME,
  40        V4L2_CID_AUDIO_BALANCE,
  41        V4L2_CID_AUDIO_BASS,
  42        V4L2_CID_AUDIO_TREBLE,
  43        V4L2_CID_AUDIO_MUTE,
  44        V4L2_CID_AUDIO_LOUDNESS,
  45        0
  46};
  47
  48static const u32 *ctrl_classes[] = {
  49        user_ctrls,
  50        cx2341x_mpeg_ctrls,
  51        NULL
  52};
  53
  54int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
  55{
  56        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
  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_BRIGHTNESS:
  66        case V4L2_CID_HUE:
  67        case V4L2_CID_SATURATION:
  68        case V4L2_CID_CONTRAST:
  69                if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl))
  70                        qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
  71                return 0;
  72
  73        case V4L2_CID_AUDIO_VOLUME:
  74        case V4L2_CID_AUDIO_MUTE:
  75        case V4L2_CID_AUDIO_BALANCE:
  76        case V4L2_CID_AUDIO_BASS:
  77        case V4L2_CID_AUDIO_TREBLE:
  78        case V4L2_CID_AUDIO_LOUDNESS:
  79                if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
  80                        qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
  81                return 0;
  82
  83        default:
  84                if (cx2341x_ctrl_query(&cx->params, qctrl))
  85                        qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
  86                return 0;
  87        }
  88        strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
  89        qctrl->name[sizeof(qctrl->name) - 1] = 0;
  90        return 0;
  91}
  92
  93int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
  94{
  95        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
  96        struct v4l2_queryctrl qctrl;
  97
  98        qctrl.id = qmenu->id;
  99        cx18_queryctrl(file, fh, &qctrl);
 100        return v4l2_ctrl_query_menu(qmenu, &qctrl,
 101                        cx2341x_ctrl_get_menu(&cx->params, qmenu->id));
 102}
 103
 104static int cx18_try_ctrl(struct file *file, void *fh,
 105                                        struct v4l2_ext_control *vctrl)
 106{
 107        struct v4l2_queryctrl qctrl;
 108        const char **menu_items = NULL;
 109        int err;
 110
 111        qctrl.id = vctrl->id;
 112        err = cx18_queryctrl(file, fh, &qctrl);
 113        if (err)
 114                return err;
 115        if (qctrl.type == V4L2_CTRL_TYPE_MENU)
 116                menu_items = v4l2_ctrl_get_menu(qctrl.id);
 117        return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
 118}
 119
 120static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 121{
 122        switch (vctrl->id) {
 123                /* Standard V4L2 controls */
 124        case V4L2_CID_BRIGHTNESS:
 125        case V4L2_CID_HUE:
 126        case V4L2_CID_SATURATION:
 127        case V4L2_CID_CONTRAST:
 128                return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl);
 129
 130        case V4L2_CID_AUDIO_VOLUME:
 131        case V4L2_CID_AUDIO_MUTE:
 132        case V4L2_CID_AUDIO_BALANCE:
 133        case V4L2_CID_AUDIO_BASS:
 134        case V4L2_CID_AUDIO_TREBLE:
 135        case V4L2_CID_AUDIO_LOUDNESS:
 136                return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
 137
 138        default:
 139                CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 140                return -EINVAL;
 141        }
 142        return 0;
 143}
 144
 145static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 146{
 147        switch (vctrl->id) {
 148                /* Standard V4L2 controls */
 149        case V4L2_CID_BRIGHTNESS:
 150        case V4L2_CID_HUE:
 151        case V4L2_CID_SATURATION:
 152        case V4L2_CID_CONTRAST:
 153                return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl);
 154
 155        case V4L2_CID_AUDIO_VOLUME:
 156        case V4L2_CID_AUDIO_MUTE:
 157        case V4L2_CID_AUDIO_BALANCE:
 158        case V4L2_CID_AUDIO_BASS:
 159        case V4L2_CID_AUDIO_TREBLE:
 160        case V4L2_CID_AUDIO_LOUDNESS:
 161                return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
 162        default:
 163                CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 164                return -EINVAL;
 165        }
 166        return 0;
 167}
 168
 169static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
 170{
 171        if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
 172                return -EINVAL;
 173        if (atomic_read(&cx->ana_capturing) > 0)
 174                return -EBUSY;
 175
 176        /* First try to allocate sliced VBI buffers if needed. */
 177        if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
 178                int i;
 179
 180                for (i = 0; i < CX18_VBI_FRAMES; i++) {
 181                        /* Yuck, hardcoded. Needs to be a define */
 182                        cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
 183                        if (cx->vbi.sliced_mpeg_data[i] == NULL) {
 184                                while (--i >= 0) {
 185                                        kfree(cx->vbi.sliced_mpeg_data[i]);
 186                                        cx->vbi.sliced_mpeg_data[i] = NULL;
 187                                }
 188                                return -ENOMEM;
 189                        }
 190                }
 191        }
 192
 193        cx->vbi.insert_mpeg = fmt;
 194
 195        if (cx->vbi.insert_mpeg == 0)
 196                return 0;
 197        /* Need sliced data for mpeg insertion */
 198        if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
 199                if (cx->is_60hz)
 200                        cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
 201                else
 202                        cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
 203                cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
 204        }
 205        return 0;
 206}
 207
 208int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 209{
 210        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 211        struct v4l2_control ctrl;
 212
 213        if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
 214                int i;
 215                int err = 0;
 216
 217                for (i = 0; i < c->count; i++) {
 218                        ctrl.id = c->controls[i].id;
 219                        ctrl.value = c->controls[i].value;
 220                        err = cx18_g_ctrl(cx, &ctrl);
 221                        c->controls[i].value = ctrl.value;
 222                        if (err) {
 223                                c->error_idx = i;
 224                                break;
 225                        }
 226                }
 227                return err;
 228        }
 229        if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
 230                return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
 231        return -EINVAL;
 232}
 233
 234int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 235{
 236        struct cx18_open_id *id = fh;
 237        struct cx18 *cx = id->cx;
 238        int ret;
 239        struct v4l2_control ctrl;
 240
 241        ret = v4l2_prio_check(&cx->prio, &id->prio);
 242        if (ret)
 243                return ret;
 244
 245        if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
 246                int i;
 247                int err = 0;
 248
 249                for (i = 0; i < c->count; i++) {
 250                        ctrl.id = c->controls[i].id;
 251                        ctrl.value = c->controls[i].value;
 252                        err = cx18_s_ctrl(cx, &ctrl);
 253                        c->controls[i].value = ctrl.value;
 254                        if (err) {
 255                                c->error_idx = i;
 256                                break;
 257                        }
 258                }
 259                return err;
 260        }
 261        if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
 262                struct cx2341x_mpeg_params p = cx->params;
 263                int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
 264                                                c, VIDIOC_S_EXT_CTRLS);
 265
 266                if (err)
 267                        return err;
 268
 269                if (p.video_encoding != cx->params.video_encoding) {
 270                        int is_mpeg1 = p.video_encoding ==
 271                                                V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
 272                        struct v4l2_format fmt;
 273
 274                        /* fix videodecoder resolution */
 275                        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 276                        fmt.fmt.pix.width = cx->params.width
 277                                                / (is_mpeg1 ? 2 : 1);
 278                        fmt.fmt.pix.height = cx->params.height;
 279                        cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
 280                }
 281                err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
 282                if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
 283                        err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
 284                cx->params = p;
 285                cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
 286                cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
 287                return err;
 288        }
 289        return -EINVAL;
 290}
 291
 292int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 293{
 294        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 295
 296        if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
 297                int i;
 298                int err = 0;
 299
 300                for (i = 0; i < c->count; i++) {
 301                        err = cx18_try_ctrl(file, fh, &c->controls[i]);
 302                        if (err) {
 303                                c->error_idx = i;
 304                                break;
 305                        }
 306                }
 307                return err;
 308        }
 309        if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
 310                return cx2341x_ext_ctrls(&cx->params,
 311                                                atomic_read(&cx->ana_capturing),
 312                                                c, VIDIOC_TRY_EXT_CTRLS);
 313        return -EINVAL;
 314}
 315
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.