linux/drivers/media/video/cx18/cx18-ioctl.c
<<
>>
Prefs
   1/*
   2 *  cx18 ioctl system call
   3 *
   4 *  Derived from ivtv-ioctl.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-io.h"
  26#include "cx18-version.h"
  27#include "cx18-mailbox.h"
  28#include "cx18-i2c.h"
  29#include "cx18-queue.h"
  30#include "cx18-fileops.h"
  31#include "cx18-vbi.h"
  32#include "cx18-audio.h"
  33#include "cx18-video.h"
  34#include "cx18-streams.h"
  35#include "cx18-ioctl.h"
  36#include "cx18-gpio.h"
  37#include "cx18-controls.h"
  38#include "cx18-cards.h"
  39#include "cx18-av-core.h"
  40#include <media/tveeprom.h>
  41#include <media/v4l2-chip-ident.h>
  42#include <linux/i2c-id.h>
  43
  44u16 cx18_service2vbi(int type)
  45{
  46        switch (type) {
  47        case V4L2_SLICED_TELETEXT_B:
  48                return CX18_SLICED_TYPE_TELETEXT_B;
  49        case V4L2_SLICED_CAPTION_525:
  50                return CX18_SLICED_TYPE_CAPTION_525;
  51        case V4L2_SLICED_WSS_625:
  52                return CX18_SLICED_TYPE_WSS_625;
  53        case V4L2_SLICED_VPS:
  54                return CX18_SLICED_TYPE_VPS;
  55        default:
  56                return 0;
  57        }
  58}
  59
  60static int valid_service_line(int field, int line, int is_pal)
  61{
  62        return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
  63               (!is_pal && line >= 10 && line < 22);
  64}
  65
  66static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
  67{
  68        u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
  69        int i;
  70
  71        set = set & valid_set;
  72        if (set == 0 || !valid_service_line(field, line, is_pal))
  73                return 0;
  74        if (!is_pal) {
  75                if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
  76                        return V4L2_SLICED_CAPTION_525;
  77        } else {
  78                if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
  79                        return V4L2_SLICED_VPS;
  80                if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
  81                        return V4L2_SLICED_WSS_625;
  82                if (line == 23)
  83                        return 0;
  84        }
  85        for (i = 0; i < 32; i++) {
  86                if ((1 << i) & set)
  87                        return 1 << i;
  88        }
  89        return 0;
  90}
  91
  92void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
  93{
  94        u16 set = fmt->service_set;
  95        int f, l;
  96
  97        fmt->service_set = 0;
  98        for (f = 0; f < 2; f++) {
  99                for (l = 0; l < 24; l++)
 100                        fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
 101        }
 102}
 103
 104
 105u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 106{
 107        int f, l;
 108        u16 set = 0;
 109
 110        for (f = 0; f < 2; f++) {
 111                for (l = 0; l < 24; l++)
 112                        set |= fmt->service_lines[f][l];
 113        }
 114        return set;
 115}
 116
 117static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
 118                                struct v4l2_format *fmt)
 119{
 120        struct cx18_open_id *id = fh;
 121        struct cx18 *cx = id->cx;
 122        struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
 123
 124        pixfmt->width = cx->params.width;
 125        pixfmt->height = cx->params.height;
 126        pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
 127        pixfmt->field = V4L2_FIELD_INTERLACED;
 128        pixfmt->priv = 0;
 129        if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
 130                pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
 131                /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
 132                pixfmt->sizeimage =
 133                        pixfmt->height * pixfmt->width +
 134                        pixfmt->height * (pixfmt->width / 2);
 135                pixfmt->bytesperline = 720;
 136        } else {
 137                pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
 138                pixfmt->sizeimage = 128 * 1024;
 139                pixfmt->bytesperline = 0;
 140        }
 141        return 0;
 142}
 143
 144static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
 145                                struct v4l2_format *fmt)
 146{
 147        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 148        struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
 149
 150        vbifmt->sampling_rate = 27000000;
 151        vbifmt->offset = 248;
 152        vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
 153        vbifmt->sample_format = V4L2_PIX_FMT_GREY;
 154        vbifmt->start[0] = cx->vbi.start[0];
 155        vbifmt->start[1] = cx->vbi.start[1];
 156        vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
 157        vbifmt->flags = 0;
 158        vbifmt->reserved[0] = 0;
 159        vbifmt->reserved[1] = 0;
 160        return 0;
 161}
 162
 163static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
 164                                        struct v4l2_format *fmt)
 165{
 166        return -EINVAL;
 167}
 168
 169static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
 170                                struct v4l2_format *fmt)
 171{
 172        struct cx18_open_id *id = fh;
 173        struct cx18 *cx = id->cx;
 174        int w = fmt->fmt.pix.width;
 175        int h = fmt->fmt.pix.height;
 176
 177        w = min(w, 720);
 178        w = max(w, 1);
 179        h = min(h, cx->is_50hz ? 576 : 480);
 180        h = max(h, 2);
 181        cx18_g_fmt_vid_cap(file, fh, fmt);
 182        fmt->fmt.pix.width = w;
 183        fmt->fmt.pix.height = h;
 184        return 0;
 185}
 186
 187static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
 188                                struct v4l2_format *fmt)
 189{
 190        return cx18_g_fmt_vbi_cap(file, fh, fmt);
 191}
 192
 193static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
 194                                        struct v4l2_format *fmt)
 195{
 196        return -EINVAL;
 197}
 198
 199static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
 200                                struct v4l2_format *fmt)
 201{
 202        struct cx18_open_id *id = fh;
 203        struct cx18 *cx = id->cx;
 204        int ret;
 205        int w, h;
 206
 207        ret = v4l2_prio_check(&cx->prio, &id->prio);
 208        if (ret)
 209                return ret;
 210
 211        ret = cx18_try_fmt_vid_cap(file, fh, fmt);
 212        if (ret)
 213                return ret;
 214        w = fmt->fmt.pix.width;
 215        h = fmt->fmt.pix.height;
 216
 217        if (cx->params.width == w && cx->params.height == h)
 218                return 0;
 219
 220        if (atomic_read(&cx->ana_capturing) > 0)
 221                return -EBUSY;
 222
 223        cx->params.width = w;
 224        cx->params.height = h;
 225        cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
 226        return cx18_g_fmt_vid_cap(file, fh, fmt);
 227}
 228
 229static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
 230                                struct v4l2_format *fmt)
 231{
 232        struct cx18_open_id *id = fh;
 233        struct cx18 *cx = id->cx;
 234        int ret;
 235
 236        ret = v4l2_prio_check(&cx->prio, &id->prio);
 237        if (ret)
 238                return ret;
 239
 240        if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
 241                        cx->vbi.sliced_in->service_set &&
 242                        atomic_read(&cx->ana_capturing) > 0)
 243                return -EBUSY;
 244
 245        cx->vbi.sliced_in->service_set = 0;
 246        cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
 247        return cx18_g_fmt_vbi_cap(file, fh, fmt);
 248}
 249
 250static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
 251                                        struct v4l2_format *fmt)
 252{
 253        return -EINVAL;
 254}
 255
 256static int cx18_g_chip_ident(struct file *file, void *fh,
 257                                struct v4l2_chip_ident *chip)
 258{
 259        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 260
 261        chip->ident = V4L2_IDENT_NONE;
 262        chip->revision = 0;
 263        if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
 264                if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
 265                        chip->ident = V4L2_IDENT_CX23418;
 266                return 0;
 267        }
 268        if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
 269                return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT,
 270                                        chip);
 271        if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
 272                return cx18_call_i2c_client(cx, chip->match_chip,
 273                                                VIDIOC_G_CHIP_IDENT, chip);
 274        return -EINVAL;
 275}
 276
 277#ifdef CONFIG_VIDEO_ADV_DEBUG
 278static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 279{
 280        struct v4l2_register *regs = arg;
 281        unsigned long flags;
 282
 283        if (!capable(CAP_SYS_ADMIN))
 284                return -EPERM;
 285        if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
 286                return -EINVAL;
 287
 288        spin_lock_irqsave(&cx18_cards_lock, flags);
 289        if (cmd == VIDIOC_DBG_G_REGISTER)
 290                regs->val = cx18_read_enc(cx, regs->reg);
 291        else
 292                cx18_write_enc(cx, regs->val, regs->reg);
 293        spin_unlock_irqrestore(&cx18_cards_lock, flags);
 294        return 0;
 295}
 296
 297static int cx18_g_register(struct file *file, void *fh,
 298                                struct v4l2_register *reg)
 299{
 300        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 301
 302        if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
 303                return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
 304        if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
 305                return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
 306                                        reg);
 307        return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
 308                                        reg);
 309}
 310
 311static int cx18_s_register(struct file *file, void *fh,
 312                                struct v4l2_register *reg)
 313{
 314        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 315
 316        if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
 317                return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
 318        if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
 319                return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
 320                                        reg);
 321        return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
 322                                        reg);
 323}
 324#endif
 325
 326static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
 327{
 328        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 329
 330        *p = v4l2_prio_max(&cx->prio);
 331        return 0;
 332}
 333
 334static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
 335{
 336        struct cx18_open_id *id = fh;
 337        struct cx18 *cx = id->cx;
 338
 339        return v4l2_prio_change(&cx->prio, &id->prio, prio);
 340}
 341
 342static int cx18_querycap(struct file *file, void *fh,
 343                                struct v4l2_capability *vcap)
 344{
 345        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 346
 347        strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
 348        strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
 349        snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->dev));
 350        vcap->version = CX18_DRIVER_VERSION;        /* version */
 351        vcap->capabilities = cx->v4l2_cap;          /* capabilities */
 352        return 0;
 353}
 354
 355static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
 356{
 357        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 358
 359        return cx18_get_audio_input(cx, vin->index, vin);
 360}
 361
 362static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
 363{
 364        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 365
 366        vin->index = cx->audio_input;
 367        return cx18_get_audio_input(cx, vin->index, vin);
 368}
 369
 370static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
 371{
 372        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 373
 374        if (vout->index >= cx->nof_audio_inputs)
 375                return -EINVAL;
 376        cx->audio_input = vout->index;
 377        cx18_audio_set_io(cx);
 378        return 0;
 379}
 380
 381static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
 382{
 383        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 384
 385        /* set it to defaults from our table */
 386        return cx18_get_input(cx, vin->index, vin);
 387}
 388
 389static int cx18_cropcap(struct file *file, void *fh,
 390                        struct v4l2_cropcap *cropcap)
 391{
 392        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 393
 394        if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 395                return -EINVAL;
 396        cropcap->bounds.top = cropcap->bounds.left = 0;
 397        cropcap->bounds.width = 720;
 398        cropcap->bounds.height = cx->is_50hz ? 576 : 480;
 399        cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
 400        cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
 401        cropcap->defrect = cropcap->bounds;
 402        return 0;
 403}
 404
 405static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 406{
 407        struct cx18_open_id *id = fh;
 408        struct cx18 *cx = id->cx;
 409        int ret;
 410
 411        ret = v4l2_prio_check(&cx->prio, &id->prio);
 412        if (ret)
 413                return ret;
 414
 415        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 416                return -EINVAL;
 417        return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
 418}
 419
 420static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 421{
 422        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 423
 424        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 425                return -EINVAL;
 426        return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
 427}
 428
 429static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
 430                                        struct v4l2_fmtdesc *fmt)
 431{
 432        static struct v4l2_fmtdesc formats[] = {
 433                { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
 434                  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
 435                },
 436                { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
 437                  "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
 438                }
 439        };
 440
 441        if (fmt->index > 1)
 442                return -EINVAL;
 443        *fmt = formats[fmt->index];
 444        return 0;
 445}
 446
 447static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
 448{
 449        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 450
 451        *i = cx->active_input;
 452        return 0;
 453}
 454
 455int cx18_s_input(struct file *file, void *fh, unsigned int inp)
 456{
 457        struct cx18_open_id *id = fh;
 458        struct cx18 *cx = id->cx;
 459        int ret;
 460
 461        ret = v4l2_prio_check(&cx->prio, &id->prio);
 462        if (ret)
 463                return ret;
 464
 465        if (inp < 0 || inp >= cx->nof_inputs)
 466                return -EINVAL;
 467
 468        if (inp == cx->active_input) {
 469                CX18_DEBUG_INFO("Input unchanged\n");
 470                return 0;
 471        }
 472
 473        CX18_DEBUG_INFO("Changing input from %d to %d\n",
 474                        cx->active_input, inp);
 475
 476        cx->active_input = inp;
 477        /* Set the audio input to whatever is appropriate for the input type. */
 478        cx->audio_input = cx->card->video_inputs[inp].audio_index;
 479
 480        /* prevent others from messing with the streams until
 481           we're finished changing inputs. */
 482        cx18_mute(cx);
 483        cx18_video_set_io(cx);
 484        cx18_audio_set_io(cx);
 485        cx18_unmute(cx);
 486        return 0;
 487}
 488
 489static int cx18_g_frequency(struct file *file, void *fh,
 490                                struct v4l2_frequency *vf)
 491{
 492        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 493
 494        if (vf->tuner != 0)
 495                return -EINVAL;
 496
 497        cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
 498        return 0;
 499}
 500
 501int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 502{
 503        struct cx18_open_id *id = fh;
 504        struct cx18 *cx = id->cx;
 505        int ret;
 506
 507        ret = v4l2_prio_check(&cx->prio, &id->prio);
 508        if (ret)
 509                return ret;
 510
 511        if (vf->tuner != 0)
 512                return -EINVAL;
 513
 514        cx18_mute(cx);
 515        CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
 516        cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
 517        cx18_unmute(cx);
 518        return 0;
 519}
 520
 521static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
 522{
 523        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 524
 525        *std = cx->std;
 526        return 0;
 527}
 528
 529int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
 530{
 531        struct cx18_open_id *id = fh;
 532        struct cx18 *cx = id->cx;
 533        int ret;
 534
 535        ret = v4l2_prio_check(&cx->prio, &id->prio);
 536        if (ret)
 537                return ret;
 538
 539        if ((*std & V4L2_STD_ALL) == 0)
 540                return -EINVAL;
 541
 542        if (*std == cx->std)
 543                return 0;
 544
 545        if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
 546            atomic_read(&cx->ana_capturing) > 0) {
 547                /* Switching standard would turn off the radio or mess
 548                   with already running streams, prevent that by
 549                   returning EBUSY. */
 550                return -EBUSY;
 551        }
 552
 553        cx->std = *std;
 554        cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
 555        cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
 556        cx->params.width = 720;
 557        cx->params.height = cx->is_50hz ? 576 : 480;
 558        cx->vbi.count = cx->is_50hz ? 18 : 12;
 559        cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
 560        cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
 561        cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
 562        CX18_DEBUG_INFO("Switching standard to %llx.\n",
 563                        (unsigned long long) cx->std);
 564
 565        /* Tuner */
 566        cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
 567        return 0;
 568}
 569
 570static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 571{
 572        struct cx18_open_id *id = fh;
 573        struct cx18 *cx = id->cx;
 574        int ret;
 575
 576        ret = v4l2_prio_check(&cx->prio, &id->prio);
 577        if (ret)
 578                return ret;
 579
 580        if (vt->index != 0)
 581                return -EINVAL;
 582
 583        /* Setting tuner can only set audio mode */
 584        cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
 585
 586        return 0;
 587}
 588
 589static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 590{
 591        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 592
 593        if (vt->index != 0)
 594                return -EINVAL;
 595
 596        cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
 597
 598        if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
 599                strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
 600                vt->type = V4L2_TUNER_RADIO;
 601        } else {
 602                strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
 603                vt->type = V4L2_TUNER_ANALOG_TV;
 604        }
 605
 606        return 0;
 607}
 608
 609static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
 610                                        struct v4l2_sliced_vbi_cap *cap)
 611{
 612        return -EINVAL;
 613}
 614
 615static int cx18_g_enc_index(struct file *file, void *fh,
 616                                struct v4l2_enc_idx *idx)
 617{
 618        return -EINVAL;
 619}
 620
 621static int cx18_encoder_cmd(struct file *file, void *fh,
 622                                struct v4l2_encoder_cmd *enc)
 623{
 624        struct cx18_open_id *id = fh;
 625        struct cx18 *cx = id->cx;
 626        u32 h;
 627
 628        switch (enc->cmd) {
 629        case V4L2_ENC_CMD_START:
 630                CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
 631                enc->flags = 0;
 632                return cx18_start_capture(id);
 633
 634        case V4L2_ENC_CMD_STOP:
 635                CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
 636                enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
 637                cx18_stop_capture(id,
 638                                  enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
 639                break;
 640
 641        case V4L2_ENC_CMD_PAUSE:
 642                CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
 643                enc->flags = 0;
 644                if (!atomic_read(&cx->ana_capturing))
 645                        return -EPERM;
 646                if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
 647                        return 0;
 648                h = cx18_find_handle(cx);
 649                if (h == CX18_INVALID_TASK_HANDLE) {
 650                        CX18_ERR("Can't find valid task handle for "
 651                                 "V4L2_ENC_CMD_PAUSE\n");
 652                        return -EBADFD;
 653                }
 654                cx18_mute(cx);
 655                cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);
 656                break;
 657
 658        case V4L2_ENC_CMD_RESUME:
 659                CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
 660                enc->flags = 0;
 661                if (!atomic_read(&cx->ana_capturing))
 662                        return -EPERM;
 663                if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
 664                        return 0;
 665                h = cx18_find_handle(cx);
 666                if (h == CX18_INVALID_TASK_HANDLE) {
 667                        CX18_ERR("Can't find valid task handle for "
 668                                 "V4L2_ENC_CMD_RESUME\n");
 669                        return -EBADFD;
 670                }
 671                cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);
 672                cx18_unmute(cx);
 673                break;
 674
 675        default:
 676                CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
 677                return -EINVAL;
 678        }
 679        return 0;
 680}
 681
 682static int cx18_try_encoder_cmd(struct file *file, void *fh,
 683                                struct v4l2_encoder_cmd *enc)
 684{
 685        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 686
 687        switch (enc->cmd) {
 688        case V4L2_ENC_CMD_START:
 689                CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
 690                enc->flags = 0;
 691                break;
 692
 693        case V4L2_ENC_CMD_STOP:
 694                CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
 695                enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
 696                break;
 697
 698        case V4L2_ENC_CMD_PAUSE:
 699                CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
 700                enc->flags = 0;
 701                break;
 702
 703        case V4L2_ENC_CMD_RESUME:
 704                CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
 705                enc->flags = 0;
 706                break;
 707
 708        default:
 709                CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
 710                return -EINVAL;
 711        }
 712        return 0;
 713}
 714
 715static int cx18_log_status(struct file *file, void *fh)
 716{
 717        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 718        struct v4l2_input vidin;
 719        struct v4l2_audio audin;
 720        int i;
 721
 722        CX18_INFO("=================  START STATUS CARD #%d  =================\n", cx->num);
 723        if (cx->hw_flags & CX18_HW_TVEEPROM) {
 724                struct tveeprom tv;
 725
 726                cx18_read_eeprom(cx, &tv);
 727        }
 728        cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
 729        cx18_get_input(cx, cx->active_input, &vidin);
 730        cx18_get_audio_input(cx, cx->audio_input, &audin);
 731        CX18_INFO("Video Input: %s\n", vidin.name);
 732        CX18_INFO("Audio Input: %s\n", audin.name);
 733        mutex_lock(&cx->gpio_lock);
 734        CX18_INFO("GPIO:  direction 0x%08x, value 0x%08x\n",
 735                cx->gpio_dir, cx->gpio_val);
 736        mutex_unlock(&cx->gpio_lock);
 737        CX18_INFO("Tuner: %s\n",
 738                test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
 739        cx2341x_log_status(&cx->params, cx->name);
 740        CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
 741        for (i = 0; i < CX18_MAX_STREAMS; i++) {
 742                struct cx18_stream *s = &cx->streams[i];
 743
 744                if (s->v4l2dev == NULL || s->buffers == 0)
 745                        continue;
 746                CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
 747                          s->name, s->s_flags,
 748                          (s->buffers - atomic_read(&s->q_free.buffers))
 749                                * 100 / s->buffers,
 750                          (s->buffers * s->buf_size) / 1024, s->buffers);
 751        }
 752        CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
 753                        (long long)cx->mpg_data_received,
 754                        (long long)cx->vbi_data_inserted);
 755        cx18_log_statistics(cx);
 756        CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
 757        return 0;
 758}
 759
 760static int cx18_default(struct file *file, void *fh, int cmd, void *arg)
 761{
 762        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 763
 764        switch (cmd) {
 765        case VIDIOC_INT_S_AUDIO_ROUTING: {
 766                struct v4l2_routing *route = arg;
 767
 768                CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
 769                        route->input, route->output);
 770                cx18_audio_set_route(cx, route);
 771                break;
 772        }
 773
 774        case VIDIOC_INT_RESET: {
 775                u32 val = *(u32 *)arg;
 776
 777                if ((val == 0) || (val & 0x01))
 778                        cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]);
 779                break;
 780        }
 781
 782        default:
 783                return -EINVAL;
 784        }
 785        return 0;
 786}
 787
 788int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 789                    unsigned long arg)
 790{
 791        struct video_device *vfd = video_devdata(filp);
 792        struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
 793        struct cx18 *cx = id->cx;
 794        int res;
 795
 796        mutex_lock(&cx->serialize_lock);
 797
 798        if (cx18_debug & CX18_DBGFLG_IOCTL)
 799                vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
 800        res = video_ioctl2(inode, filp, cmd, arg);
 801        vfd->debug = 0;
 802        mutex_unlock(&cx->serialize_lock);
 803        return res;
 804}
 805
 806static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
 807        .vidioc_querycap                = cx18_querycap,
 808        .vidioc_g_priority              = cx18_g_priority,
 809        .vidioc_s_priority              = cx18_s_priority,
 810        .vidioc_s_audio                 = cx18_s_audio,
 811        .vidioc_g_audio                 = cx18_g_audio,
 812        .vidioc_enumaudio               = cx18_enumaudio,
 813        .vidioc_enum_input              = cx18_enum_input,
 814        .vidioc_cropcap                 = cx18_cropcap,
 815        .vidioc_s_crop                  = cx18_s_crop,
 816        .vidioc_g_crop                  = cx18_g_crop,
 817        .vidioc_g_input                 = cx18_g_input,
 818        .vidioc_s_input                 = cx18_s_input,
 819        .vidioc_g_frequency             = cx18_g_frequency,
 820        .vidioc_s_frequency             = cx18_s_frequency,
 821        .vidioc_s_tuner                 = cx18_s_tuner,
 822        .vidioc_g_tuner                 = cx18_g_tuner,
 823        .vidioc_g_enc_index             = cx18_g_enc_index,
 824        .vidioc_g_std                   = cx18_g_std,
 825        .vidioc_s_std                   = cx18_s_std,
 826        .vidioc_log_status              = cx18_log_status,
 827        .vidioc_enum_fmt_vid_cap        = cx18_enum_fmt_vid_cap,
 828        .vidioc_encoder_cmd             = cx18_encoder_cmd,
 829        .vidioc_try_encoder_cmd         = cx18_try_encoder_cmd,
 830        .vidioc_g_fmt_vid_cap           = cx18_g_fmt_vid_cap,
 831        .vidioc_g_fmt_vbi_cap           = cx18_g_fmt_vbi_cap,
 832        .vidioc_g_fmt_sliced_vbi_cap    = cx18_g_fmt_sliced_vbi_cap,
 833        .vidioc_s_fmt_vid_cap           = cx18_s_fmt_vid_cap,
 834        .vidioc_s_fmt_vbi_cap           = cx18_s_fmt_vbi_cap,
 835        .vidioc_s_fmt_sliced_vbi_cap    = cx18_s_fmt_sliced_vbi_cap,
 836        .vidioc_try_fmt_vid_cap         = cx18_try_fmt_vid_cap,
 837        .vidioc_try_fmt_vbi_cap         = cx18_try_fmt_vbi_cap,
 838        .vidioc_try_fmt_sliced_vbi_cap  = cx18_try_fmt_sliced_vbi_cap,
 839        .vidioc_g_sliced_vbi_cap        = cx18_g_sliced_vbi_cap,
 840        .vidioc_g_chip_ident            = cx18_g_chip_ident,
 841#ifdef CONFIG_VIDEO_ADV_DEBUG
 842        .vidioc_g_register              = cx18_g_register,
 843        .vidioc_s_register              = cx18_s_register,
 844#endif
 845        .vidioc_default                 = cx18_default,
 846        .vidioc_queryctrl               = cx18_queryctrl,
 847        .vidioc_querymenu               = cx18_querymenu,
 848        .vidioc_g_ext_ctrls             = cx18_g_ext_ctrls,
 849        .vidioc_s_ext_ctrls             = cx18_s_ext_ctrls,
 850        .vidioc_try_ext_ctrls           = cx18_try_ext_ctrls,
 851};
 852
 853void cx18_set_funcs(struct video_device *vdev)
 854{
 855        vdev->ioctl_ops = &cx18_ioctl_ops;
 856}
 857
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.