cx18-ioctl.c 23.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
/*
 *  cx18 ioctl system call
 *
 *  Derived from ivtv-ioctl.c
 *
 *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 *  02111-1307  USA
 */

#include "cx18-driver.h"
#include "cx18-version.h"
#include "cx18-mailbox.h"
#include "cx18-i2c.h"
#include "cx18-queue.h"
#include "cx18-fileops.h"
#include "cx18-vbi.h"
#include "cx18-audio.h"
#include "cx18-video.h"
#include "cx18-streams.h"
#include "cx18-ioctl.h"
#include "cx18-gpio.h"
#include "cx18-controls.h"
#include "cx18-cards.h"
#include "cx18-av-core.h"
#include <media/tveeprom.h>
#include <media/v4l2-chip-ident.h>
#include <linux/i2c-id.h>

43
u16 cx18_service2vbi(int type)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
{
	switch (type) {
	case V4L2_SLICED_TELETEXT_B:
		return CX18_SLICED_TYPE_TELETEXT_B;
	case V4L2_SLICED_CAPTION_525:
		return CX18_SLICED_TYPE_CAPTION_525;
	case V4L2_SLICED_WSS_625:
		return CX18_SLICED_TYPE_WSS_625;
	case V4L2_SLICED_VPS:
		return CX18_SLICED_TYPE_VPS;
	default:
		return 0;
	}
}

static int valid_service_line(int field, int line, int is_pal)
{
	return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
	       (!is_pal && line >= 10 && line < 22);
}

static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
{
	u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
	int i;

	set = set & valid_set;
	if (set == 0 || !valid_service_line(field, line, is_pal))
		return 0;
	if (!is_pal) {
		if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
			return V4L2_SLICED_CAPTION_525;
	} else {
		if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
			return V4L2_SLICED_VPS;
		if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
			return V4L2_SLICED_WSS_625;
		if (line == 23)
			return 0;
	}
	for (i = 0; i < 32; i++) {
		if ((1 << i) & set)
			return 1 << i;
	}
	return 0;
}

91
void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
92 93 94 95 96 97 98 99 100 101 102 103
{
	u16 set = fmt->service_set;
	int f, l;

	fmt->service_set = 0;
	for (f = 0; f < 2; f++) {
		for (l = 0; l < 24; l++)
			fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
	}
}


104
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
{
	int f, l;
	u16 set = 0;

	for (f = 0; f < 2; f++) {
		for (l = 0; l < 24; l++)
			set |= fmt->service_lines[f][l];
	}
	return set;
}

static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
{
	struct v4l2_register *regs = arg;
	unsigned long flags;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
	if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
		return -EINVAL;

	spin_lock_irqsave(&cx18_cards_lock, flags);
	if (cmd == VIDIOC_DBG_G_REGISTER)
		regs->val = read_enc(regs->reg);
	else
		write_enc(regs->val, regs->reg);
	spin_unlock_irqrestore(&cx18_cards_lock, flags);
	return 0;
}

135 136 137 138 139
static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
				struct v4l2_format *fmt)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
140
	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
141

142 143 144 145 146
	pixfmt->width = cx->params.width;
	pixfmt->height = cx->params.height;
	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
	pixfmt->field = V4L2_FIELD_INTERLACED;
	pixfmt->priv = 0;
147
	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
148
		pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
149
		/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
150 151 152 153
		pixfmt->sizeimage =
			pixfmt->height * pixfmt->width +
			pixfmt->height * (pixfmt->width / 2);
		pixfmt->bytesperline = 720;
154
	} else {
155 156 157
		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
		pixfmt->sizeimage = 128 * 1024;
		pixfmt->bytesperline = 0;
158 159 160
	}
	return 0;
}
161

162 163 164 165
static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
				struct v4l2_format *fmt)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
166
	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
167

168
	CX18_DEBUG_IOCTL("VIDIOC_G_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n");
169

170 171 172 173 174 175 176 177 178 179
	vbifmt->sampling_rate = 27000000;
	vbifmt->offset = 248;
	vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
	vbifmt->sample_format = V4L2_PIX_FMT_GREY;
	vbifmt->start[0] = cx->vbi.start[0];
	vbifmt->start[1] = cx->vbi.start[1];
	vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
	vbifmt->flags = 0;
	vbifmt->reserved[0] = 0;
	vbifmt->reserved[1] = 0;
180 181 182
	return 0;
}

183 184
static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
					struct v4l2_format *fmt)
185
{
186 187
	return -EINVAL;
}
188

189 190 191 192 193
static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
				struct v4l2_format *fmt)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
194

195 196
	int w = fmt->fmt.pix.width;
	int h = fmt->fmt.pix.height;
197

198
	CX18_DEBUG_IOCTL("VIDIOC_TRY_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
199

200 201 202 203 204 205 206 207 208
	w = min(w, 720);
	w = max(w, 1);
	h = min(h, cx->is_50hz ? 576 : 480);
	h = max(h, 2);
	cx18_g_fmt_vid_cap(file, fh, fmt);
	fmt->fmt.pix.width = w;
	fmt->fmt.pix.height = h;
	return 0;
}
209

210 211 212 213
static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
				struct v4l2_format *fmt)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
214

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
	CX18_DEBUG_IOCTL("VIDIOC_TRY_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n");

	return cx18_g_fmt_vbi_cap(file, fh, fmt);
}

static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
					struct v4l2_format *fmt)
{
	return -EINVAL;
}

static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
				struct v4l2_format *fmt)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
	int ret;
	int w = fmt->fmt.pix.width;
	int h = fmt->fmt.pix.height;

	ret = v4l2_prio_check(&cx->prio, &id->prio);
	if (ret)
		return ret;
238

239
	CX18_DEBUG_IOCTL("VIDIOC_S_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
240

241 242 243
	ret = cx18_try_fmt_vid_cap(file, fh, fmt);
	if (ret)
		return ret;
244

245
	if (cx->params.width == w && cx->params.height == h)
246
		return 0;
247 248

	if (atomic_read(&cx->ana_capturing) > 0)
249
		return -EBUSY;
250 251 252

	cx->params.width = w;
	cx->params.height = h;
253
	cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
254
	return cx18_g_fmt_vid_cap(file, fh, fmt);
255 256
}

257 258
static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
				struct v4l2_format *fmt)
259
{
260
	struct cx18_open_id *id = fh;
261
	struct cx18 *cx = id->cx;
262
	int ret;
263

264 265 266
	ret = v4l2_prio_check(&cx->prio, &id->prio);
	if (ret)
		return ret;
267

268
	CX18_DEBUG_IOCTL("VIDIOC_S_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n");
269

270 271 272 273
	if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
			cx->vbi.sliced_in->service_set &&
			atomic_read(&cx->ana_capturing) > 0)
		return -EBUSY;
274

275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
	cx->vbi.sliced_in->service_set = 0;
	cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
	return cx18_g_fmt_vbi_cap(file, fh, fmt);
}

static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
					struct v4l2_format *fmt)
{
	return -EINVAL;
}

static int cx18_g_chip_ident(struct file *file, void *fh,
				struct v4l2_chip_ident *chip)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;

	CX18_DEBUG_IOCTL("VIDIOC_G_CHIP_IDENT\n");

	chip->ident = V4L2_IDENT_NONE;
	chip->revision = 0;
	if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
		if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
			chip->ident = V4L2_IDENT_CX23418;
		return 0;
299
	}
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
	if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
		return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT,
					chip);
	if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
		return cx18_call_i2c_client(cx, chip->match_chip,
						VIDIOC_G_CHIP_IDENT, chip);
	return -EINVAL;
}

static int cx18_g_register(struct file *file, void *fh,
				struct v4l2_register *reg)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;

	CX18_DEBUG_IOCTL("VIDIOC_DBG_G_REGISTER\n");

	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
		return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
		return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
					reg);
	return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
					reg);
}

static int cx18_s_register(struct file *file, void *fh,
				struct v4l2_register *reg)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;

	CX18_DEBUG_IOCTL("VIDIOC_DBG_S_REGISTER\n");

	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
		return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
		return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
					reg);
	return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
					reg);
}

static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;

	CX18_DEBUG_IOCTL("VIDIOC_G_PRIORITY\n");

	*p = v4l2_prio_max(&cx->prio);
348 349 350
	return 0;
}

351
static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
352
{
353 354
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
355

356
	CX18_DEBUG_IOCTL("VIDIOC_S_PRIORITY\n");
357

358 359
	return v4l2_prio_change(&cx->prio, &id->prio, prio);
}
360

361 362 363 364
static int cx18_querycap(struct file *file, void *fh,
				struct v4l2_capability *vcap)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
365

366
	CX18_DEBUG_IOCTL("VIDIOC_QUERYCAP\n");
367

368 369 370 371 372 373 374
	strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
	strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
	strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
	vcap->version = CX18_DRIVER_VERSION; 	    /* version */
	vcap->capabilities = cx->v4l2_cap; 	    /* capabilities */
	return 0;
}
375

376 377 378
static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
379

380
	CX18_DEBUG_IOCTL("VIDIOC_ENUMAUDIO\n");
381

382 383
	return cx18_get_audio_input(cx, vin->index, vin);
}
384

385 386 387
static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
388

389
	CX18_DEBUG_IOCTL("VIDIOC_G_AUDIO\n");
390

391 392 393
	vin->index = cx->audio_input;
	return cx18_get_audio_input(cx, vin->index, vin);
}
394

395 396 397
static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
398

399
	CX18_DEBUG_IOCTL("VIDIOC_S_AUDIO\n");
400

401 402 403 404 405 406
	if (vout->index >= cx->nof_audio_inputs)
		return -EINVAL;
	cx->audio_input = vout->index;
	cx18_audio_set_io(cx);
	return 0;
}
407

408 409 410
static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
411

412
	CX18_DEBUG_IOCTL("VIDIOC_ENUMINPUT\n");
413

414 415 416
	/* set it to defaults from our table */
	return cx18_get_input(cx, vin->index, vin);
}
417

418 419 420 421
static int cx18_cropcap(struct file *file, void *fh,
			struct v4l2_cropcap *cropcap)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
422

423
	CX18_DEBUG_IOCTL("VIDIOC_CROPCAP\n");
424

425 426 427 428 429 430 431 432 433 434
	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
	cropcap->bounds.top = cropcap->bounds.left = 0;
	cropcap->bounds.width = 720;
	cropcap->bounds.height = cx->is_50hz ? 576 : 480;
	cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
	cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
	cropcap->defrect = cropcap->bounds;
	return 0;
}
435

436 437 438 439 440
static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
	int ret;
441

442 443 444
	ret = v4l2_prio_check(&cx->prio, &id->prio);
	if (ret)
		return ret;
445

446
	CX18_DEBUG_IOCTL("VIDIOC_S_CROP\n");
447

448 449 450 451
	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
	return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
}
452

453 454 455
static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
456

457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
	CX18_DEBUG_IOCTL("VIDIOC_G_CROP\n");

	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
	return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
}

static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
					struct v4l2_fmtdesc *fmt)
{
	static struct v4l2_fmtdesc formats[] = {
		{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
		  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
		},
		{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
		  "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
473
		}
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
	};

	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;

	CX18_DEBUG_IOCTL("VIDIOC_ENUM_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n");

	if (fmt->index > 1)
		return -EINVAL;
	*fmt = formats[fmt->index];
	return 0;
}

static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;

	CX18_DEBUG_IOCTL("VIDIOC_G_INPUT\n");

	*i = cx->active_input;
	return 0;
}

int cx18_s_input(struct file *file, void *fh, unsigned int inp)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
	int ret;

	ret = v4l2_prio_check(&cx->prio, &id->prio);
	if (ret)
		return ret;

	CX18_DEBUG_IOCTL("VIDIOC_S_INPUT\n");

	if (inp < 0 || inp >= cx->nof_inputs)
		return -EINVAL;

	if (inp == cx->active_input) {
		CX18_DEBUG_INFO("Input unchanged\n");
513 514 515
		return 0;
	}

516 517
	CX18_DEBUG_INFO("Changing input from %d to %d\n",
			cx->active_input, inp);
518

519 520 521
	cx->active_input = inp;
	/* Set the audio input to whatever is appropriate for the input type. */
	cx->audio_input = cx->card->video_inputs[inp].audio_index;
522

523 524 525 526 527 528 529 530
	/* prevent others from messing with the streams until
	   we're finished changing inputs. */
	cx18_mute(cx);
	cx18_video_set_io(cx);
	cx18_audio_set_io(cx);
	cx18_unmute(cx);
	return 0;
}
531

532 533 534 535
static int cx18_g_frequency(struct file *file, void *fh,
				struct v4l2_frequency *vf)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
536

537
	CX18_DEBUG_IOCTL("VIDIOC_G_FREQUENCY\n");
538

539 540
	if (vf->tuner != 0)
		return -EINVAL;
541

542 543 544
	cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
	return 0;
}
545

546 547 548 549 550
int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
	int ret;
551

552 553 554
	ret = v4l2_prio_check(&cx->prio, &id->prio);
	if (ret)
		return ret;
555

556
	CX18_DEBUG_IOCTL("VIDIOC_S_FREQUENCY\n");
557

558 559
	if (vf->tuner != 0)
		return -EINVAL;
560

561 562 563 564 565 566
	cx18_mute(cx);
	CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
	cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
	cx18_unmute(cx);
	return 0;
}
567

568 569 570
static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
571

572
	CX18_DEBUG_IOCTL("VIDIOC_G_STD\n");
573

574 575 576
	*std = cx->std;
	return 0;
}
577

578 579 580 581 582
int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
	int ret;
583

584 585 586
	ret = v4l2_prio_check(&cx->prio, &id->prio);
	if (ret)
		return ret;
587

588
	CX18_DEBUG_IOCTL("VIDIOC_S_STD\n");
589

590 591
	if ((*std & V4L2_STD_ALL) == 0)
		return -EINVAL;
592

593 594 595 596 597 598 599 600 601
	if (*std == cx->std)
		return 0;

	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
	    atomic_read(&cx->ana_capturing) > 0) {
		/* Switching standard would turn off the radio or mess
		   with already running streams, prevent that by
		   returning EBUSY. */
		return -EBUSY;
602 603
	}

604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
	cx->std = *std;
	cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
	cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
	cx->params.width = 720;
	cx->params.height = cx->is_50hz ? 576 : 480;
	cx->vbi.count = cx->is_50hz ? 18 : 12;
	cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
	cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
	cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
	CX18_DEBUG_INFO("Switching standard to %llx.\n",
			(unsigned long long) cx->std);

	/* Tuner */
	cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
	return 0;
}
620

621 622 623 624 625
static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
	int ret;
626

627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
	ret = v4l2_prio_check(&cx->prio, &id->prio);
	if (ret)
		return ret;

	CX18_DEBUG_IOCTL("VIDIOC_S_TUNER\n");

	if (vt->index != 0)
		return -EINVAL;

	/* Setting tuner can only set audio mode */
	cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);

	return 0;
}

static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;

	CX18_DEBUG_IOCTL("VIDIOC_G_TUNER\n");

	if (vt->index != 0)
		return -EINVAL;

	cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);

	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
		strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
		vt->type = V4L2_TUNER_RADIO;
	} else {
		strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
		vt->type = V4L2_TUNER_ANALOG_TV;
659 660
	}

661 662 663 664 665 666 667 668
	return 0;
}

static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
					struct v4l2_sliced_vbi_cap *cap)
{
	return -EINVAL;
}
669

670 671 672 673 674
static int cx18_g_enc_index(struct file *file, void *fh,
				struct v4l2_enc_idx *idx)
{
	return -EINVAL;
}
675

676 677 678 679 680
static int cx18_encoder_cmd(struct file *file, void *fh,
				struct v4l2_encoder_cmd *enc)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
681

682 683 684 685 686 687 688 689 690 691 692 693 694
	CX18_DEBUG_IOCTL("VIDIOC_ENCODER_CMD:\n");

	switch (enc->cmd) {
	case V4L2_ENC_CMD_START:
		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
		enc->flags = 0;
		return cx18_start_capture(id);

	case V4L2_ENC_CMD_STOP:
		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
		cx18_stop_capture(id,
				  enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
695 696
		break;

697 698 699 700 701 702
	case V4L2_ENC_CMD_PAUSE:
		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
		enc->flags = 0;
		if (!atomic_read(&cx->ana_capturing))
			return -EPERM;
		if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
703
			return 0;
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
		cx18_mute(cx);
		cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
		break;

	case V4L2_ENC_CMD_RESUME:
		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
		enc->flags = 0;
		if (!atomic_read(&cx->ana_capturing))
			return -EPERM;
		if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
			return 0;
		cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
		cx18_unmute(cx);
		break;

	default:
		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
721 722
		return -EINVAL;
	}
723 724
	return 0;
}
725

726 727 728 729
static int cx18_try_encoder_cmd(struct file *file, void *fh,
				struct v4l2_encoder_cmd *enc)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
730

731 732 733 734 735 736
	CX18_DEBUG_IOCTL("VIDIOC_TRY_ENCDOER_CMD:\n");

	switch (enc->cmd) {
	case V4L2_ENC_CMD_START:
		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
		enc->flags = 0;
737 738
		break;

739 740 741 742
	case V4L2_ENC_CMD_STOP:
		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
		break;
743

744 745 746 747
	case V4L2_ENC_CMD_PAUSE:
		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
		enc->flags = 0;
		break;
748

749 750 751
	case V4L2_ENC_CMD_RESUME:
		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
		enc->flags = 0;
752 753 754
		break;

	default:
755
		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
756 757 758 759 760
		return -EINVAL;
	}
	return 0;
}

761
static int cx18_log_status(struct file *file, void *fh)
762
{
763 764 765 766
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
	struct v4l2_input vidin;
	struct v4l2_audio audin;
	int i;
767

768 769 770 771 772 773 774 775 776 777 778 779
	CX18_DEBUG_IOCTL("VIDIOC_LOG_STATUS\n");
	CX18_INFO("=================  START STATUS CARD #%d  =================\n", cx->num);
	if (cx->hw_flags & CX18_HW_TVEEPROM) {
		struct tveeprom tv;

		cx18_read_eeprom(cx, &tv);
	}
	cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
	cx18_get_input(cx, cx->active_input, &vidin);
	cx18_get_audio_input(cx, cx->audio_input, &audin);
	CX18_INFO("Video Input: %s\n", vidin.name);
	CX18_INFO("Audio Input: %s\n", audin.name);
780 781
	CX18_INFO("GPIO:  direction 0x%08x, value 0x%08x\n",
		cx->gpio_dir, cx->gpio_val);
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
	CX18_INFO("Tuner: %s\n",
		test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
	cx2341x_log_status(&cx->params, cx->name);
	CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
	for (i = 0; i < CX18_MAX_STREAMS; i++) {
		struct cx18_stream *s = &cx->streams[i];

		if (s->v4l2dev == NULL || s->buffers == 0)
			continue;
		CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
			  s->name, s->s_flags,
			  (s->buffers - s->q_free.buffers) * 100 / s->buffers,
			  (s->buffers * s->buf_size) / 1024, s->buffers);
	}
	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
			(long long)cx->mpg_data_received,
			(long long)cx->vbi_data_inserted);
	CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
	return 0;
}

static int cx18_default(struct file *file, void *fh, int cmd, void *arg)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
806 807

	switch (cmd) {
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
	case VIDIOC_INT_S_AUDIO_ROUTING: {
		struct v4l2_routing *route = arg;
		CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING (%d, %d)\n",
					route->input, route->output);
		cx18_audio_set_route(cx, route);
		break;
	}
	case VIDIOC_INT_RESET: {
		u32 val = *(u32 *)arg;
		CX18_DEBUG_IOCTL("VIDIOC_INT_RESET (%#10x)\n", val);
		/* No op right now */
		/* cx18_av_cmd(cx, cmd, arg) */
		/* cx18_call_i2c_clients(cx, cmd, arg) */
		break;
	}
	default:
824
		if (cx18_debug & CX18_DBGFLG_IOCTL) {
825 826
			printk(KERN_INFO "cx18%d ioctl: unsupported cmd: ",
				 cx->num);
827
			v4l_printk_ioctl(cmd);
828
			printk("\n");
829 830 831 832 833 834 835 836 837 838 839 840 841 842
		}
		return -EINVAL;
	}
	return 0;
}

int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
		    unsigned long arg)
{
	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
	struct cx18 *cx = id->cx;
	int res;

	mutex_lock(&cx->serialize_lock);
843
	res = video_ioctl2(inode, filp, cmd, arg);
844 845 846
	mutex_unlock(&cx->serialize_lock);
	return res;
}
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894

void cx18_set_funcs(struct video_device *vdev)
{
	vdev->vidioc_querycap                = cx18_querycap;
	vdev->vidioc_g_priority              = cx18_g_priority;
	vdev->vidioc_s_priority              = cx18_s_priority;
	vdev->vidioc_s_audio                 = cx18_s_audio;
	vdev->vidioc_g_audio                 = cx18_g_audio;
	vdev->vidioc_enumaudio               = cx18_enumaudio;
	vdev->vidioc_enum_input              = cx18_enum_input;
	vdev->vidioc_cropcap                 = cx18_cropcap;
	vdev->vidioc_s_crop                  = cx18_s_crop;
	vdev->vidioc_g_crop                  = cx18_g_crop;
	vdev->vidioc_g_input                 = cx18_g_input;
	vdev->vidioc_s_input                 = cx18_s_input;
	vdev->vidioc_g_frequency             = cx18_g_frequency;
	vdev->vidioc_s_frequency             = cx18_s_frequency;
	vdev->vidioc_s_tuner                 = cx18_s_tuner;
	vdev->vidioc_g_tuner                 = cx18_g_tuner;
	vdev->vidioc_g_enc_index             = cx18_g_enc_index;
	vdev->vidioc_g_std                   = cx18_g_std;
	vdev->vidioc_s_std                   = cx18_s_std;
	vdev->vidioc_log_status              = cx18_log_status;
	vdev->vidioc_enum_fmt_vid_cap        = cx18_enum_fmt_vid_cap;
	vdev->vidioc_encoder_cmd             = cx18_encoder_cmd;
	vdev->vidioc_try_encoder_cmd         = cx18_try_encoder_cmd;
	vdev->vidioc_g_fmt_vid_cap           = cx18_g_fmt_vid_cap;
	vdev->vidioc_g_fmt_vbi_cap           = cx18_g_fmt_vbi_cap;
	vdev->vidioc_g_fmt_sliced_vbi_cap    = cx18_g_fmt_sliced_vbi_cap;
	vdev->vidioc_s_fmt_vid_cap           = cx18_s_fmt_vid_cap;
	vdev->vidioc_s_fmt_vbi_cap           = cx18_s_fmt_vbi_cap;
	vdev->vidioc_s_fmt_sliced_vbi_cap    = cx18_s_fmt_sliced_vbi_cap;
	vdev->vidioc_try_fmt_vid_cap         = cx18_try_fmt_vid_cap;
	vdev->vidioc_try_fmt_vbi_cap         = cx18_try_fmt_vbi_cap;
	vdev->vidioc_try_fmt_sliced_vbi_cap  = cx18_try_fmt_sliced_vbi_cap;
	vdev->vidioc_g_sliced_vbi_cap        = cx18_g_sliced_vbi_cap;
	vdev->vidioc_g_chip_ident            = cx18_g_chip_ident;
	vdev->vidioc_g_register              = cx18_g_register;
	vdev->vidioc_s_register              = cx18_s_register;
	vdev->vidioc_default                 = cx18_default;
	vdev->vidioc_queryctrl               = cx18_queryctrl;
	vdev->vidioc_querymenu               = cx18_querymenu;
	vdev->vidioc_g_ctrl                  = cx18_g_ctrl;
	vdev->vidioc_s_ctrl                  = cx18_s_ctrl;
	vdev->vidioc_g_ext_ctrls             = cx18_g_ext_ctrls;
	vdev->vidioc_s_ext_ctrls             = cx18_s_ext_ctrls;
	vdev->vidioc_try_ext_ctrls           = cx18_try_ext_ctrls;
}