162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci    ioctl system call
462306a36Sopenharmony_ci    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
562306a36Sopenharmony_ci    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "ivtv-driver.h"
1062306a36Sopenharmony_ci#include "ivtv-version.h"
1162306a36Sopenharmony_ci#include "ivtv-mailbox.h"
1262306a36Sopenharmony_ci#include "ivtv-i2c.h"
1362306a36Sopenharmony_ci#include "ivtv-queue.h"
1462306a36Sopenharmony_ci#include "ivtv-fileops.h"
1562306a36Sopenharmony_ci#include "ivtv-vbi.h"
1662306a36Sopenharmony_ci#include "ivtv-routing.h"
1762306a36Sopenharmony_ci#include "ivtv-streams.h"
1862306a36Sopenharmony_ci#include "ivtv-yuv.h"
1962306a36Sopenharmony_ci#include "ivtv-ioctl.h"
2062306a36Sopenharmony_ci#include "ivtv-gpio.h"
2162306a36Sopenharmony_ci#include "ivtv-controls.h"
2262306a36Sopenharmony_ci#include "ivtv-cards.h"
2362306a36Sopenharmony_ci#include <media/i2c/saa7127.h>
2462306a36Sopenharmony_ci#include <media/tveeprom.h>
2562306a36Sopenharmony_ci#include <media/v4l2-event.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciu16 ivtv_service2vbi(int type)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	switch (type) {
3062306a36Sopenharmony_ci		case V4L2_SLICED_TELETEXT_B:
3162306a36Sopenharmony_ci			return IVTV_SLICED_TYPE_TELETEXT_B;
3262306a36Sopenharmony_ci		case V4L2_SLICED_CAPTION_525:
3362306a36Sopenharmony_ci			return IVTV_SLICED_TYPE_CAPTION_525;
3462306a36Sopenharmony_ci		case V4L2_SLICED_WSS_625:
3562306a36Sopenharmony_ci			return IVTV_SLICED_TYPE_WSS_625;
3662306a36Sopenharmony_ci		case V4L2_SLICED_VPS:
3762306a36Sopenharmony_ci			return IVTV_SLICED_TYPE_VPS;
3862306a36Sopenharmony_ci		default:
3962306a36Sopenharmony_ci			return 0;
4062306a36Sopenharmony_ci	}
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic int valid_service_line(int field, int line, int is_pal)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
4662306a36Sopenharmony_ci	       (!is_pal && line >= 10 && line < 22);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic u16 select_service_from_set(int field, int line, u16 set, int is_pal)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
5262306a36Sopenharmony_ci	int i;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	set = set & valid_set;
5562306a36Sopenharmony_ci	if (set == 0 || !valid_service_line(field, line, is_pal)) {
5662306a36Sopenharmony_ci		return 0;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci	if (!is_pal) {
5962306a36Sopenharmony_ci		if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
6062306a36Sopenharmony_ci			return V4L2_SLICED_CAPTION_525;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	else {
6362306a36Sopenharmony_ci		if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
6462306a36Sopenharmony_ci			return V4L2_SLICED_VPS;
6562306a36Sopenharmony_ci		if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
6662306a36Sopenharmony_ci			return V4L2_SLICED_WSS_625;
6762306a36Sopenharmony_ci		if (line == 23)
6862306a36Sopenharmony_ci			return 0;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci	for (i = 0; i < 32; i++) {
7162306a36Sopenharmony_ci		if (BIT(i) & set)
7262306a36Sopenharmony_ci			return BIT(i);
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci	return 0;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_civoid ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	u16 set = fmt->service_set;
8062306a36Sopenharmony_ci	int f, l;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	fmt->service_set = 0;
8362306a36Sopenharmony_ci	for (f = 0; f < 2; f++) {
8462306a36Sopenharmony_ci		for (l = 0; l < 24; l++) {
8562306a36Sopenharmony_ci			fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
8662306a36Sopenharmony_ci		}
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	int f, l;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	for (f = 0; f < 2; f++) {
9562306a36Sopenharmony_ci		for (l = 0; l < 24; l++) {
9662306a36Sopenharmony_ci			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
9762306a36Sopenharmony_ci		}
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciu16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	int f, l;
10462306a36Sopenharmony_ci	u16 set = 0;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	for (f = 0; f < 2; f++) {
10762306a36Sopenharmony_ci		for (l = 0; l < 24; l++) {
10862306a36Sopenharmony_ci			set |= fmt->service_lines[f][l];
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci	return set;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_civoid ivtv_set_osd_alpha(struct ivtv *itv)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
11762306a36Sopenharmony_ci		itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state);
11862306a36Sopenharmony_ci	ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciint ivtv_set_speed(struct ivtv *itv, int speed)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
12462306a36Sopenharmony_ci	int single_step = (speed == 1 || speed == -1);
12562306a36Sopenharmony_ci	DEFINE_WAIT(wait);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (speed == 0) speed = 1000;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* No change? */
13062306a36Sopenharmony_ci	if (speed == itv->speed && !single_step)
13162306a36Sopenharmony_ci		return 0;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (single_step && (speed < 0) == (itv->speed < 0)) {
13462306a36Sopenharmony_ci		/* Single step video and no need to change direction */
13562306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);
13662306a36Sopenharmony_ci		itv->speed = speed;
13762306a36Sopenharmony_ci		return 0;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci	if (single_step)
14062306a36Sopenharmony_ci		/* Need to change direction */
14162306a36Sopenharmony_ci		speed = speed < 0 ? -1000 : 1000;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0;
14462306a36Sopenharmony_ci	data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0;
14562306a36Sopenharmony_ci	data[1] = (speed < 0);
14662306a36Sopenharmony_ci	data[2] = speed < 0 ? 3 : 7;
14762306a36Sopenharmony_ci	data[3] = v4l2_ctrl_g_ctrl(itv->cxhdl.video_b_frames);
14862306a36Sopenharmony_ci	data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0;
14962306a36Sopenharmony_ci	data[5] = 0;
15062306a36Sopenharmony_ci	data[6] = 0;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (speed == 1500 || speed == -1500) data[0] |= 1;
15362306a36Sopenharmony_ci	else if (speed == 2000 || speed == -2000) data[0] |= 2;
15462306a36Sopenharmony_ci	else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed);
15562306a36Sopenharmony_ci	else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/* If not decoding, just change speed setting */
15862306a36Sopenharmony_ci	if (atomic_read(&itv->decoding) > 0) {
15962306a36Sopenharmony_ci		int got_sig = 0;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		/* Stop all DMA and decoding activity */
16262306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		/* Wait for any DMA to finish */
16562306a36Sopenharmony_ci		mutex_unlock(&itv->serialize_lock);
16662306a36Sopenharmony_ci		prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
16762306a36Sopenharmony_ci		while (test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
16862306a36Sopenharmony_ci			got_sig = signal_pending(current);
16962306a36Sopenharmony_ci			if (got_sig)
17062306a36Sopenharmony_ci				break;
17162306a36Sopenharmony_ci			got_sig = 0;
17262306a36Sopenharmony_ci			schedule();
17362306a36Sopenharmony_ci		}
17462306a36Sopenharmony_ci		finish_wait(&itv->dma_waitq, &wait);
17562306a36Sopenharmony_ci		mutex_lock(&itv->serialize_lock);
17662306a36Sopenharmony_ci		if (got_sig)
17762306a36Sopenharmony_ci			return -EINTR;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		/* Change Speed safely */
18062306a36Sopenharmony_ci		ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data);
18162306a36Sopenharmony_ci		IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
18262306a36Sopenharmony_ci				data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	if (single_step) {
18562306a36Sopenharmony_ci		speed = (speed < 0) ? -1 : 1;
18662306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci	itv->speed = speed;
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int ivtv_validate_speed(int cur_speed, int new_speed)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	int fact = new_speed < 0 ? -1 : 1;
19562306a36Sopenharmony_ci	int s;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (cur_speed == 0)
19862306a36Sopenharmony_ci		cur_speed = 1000;
19962306a36Sopenharmony_ci	if (new_speed < 0)
20062306a36Sopenharmony_ci		new_speed = -new_speed;
20162306a36Sopenharmony_ci	if (cur_speed < 0)
20262306a36Sopenharmony_ci		cur_speed = -cur_speed;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (cur_speed <= new_speed) {
20562306a36Sopenharmony_ci		if (new_speed > 1500)
20662306a36Sopenharmony_ci			return fact * 2000;
20762306a36Sopenharmony_ci		if (new_speed > 1000)
20862306a36Sopenharmony_ci			return fact * 1500;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci	else {
21162306a36Sopenharmony_ci		if (new_speed >= 2000)
21262306a36Sopenharmony_ci			return fact * 2000;
21362306a36Sopenharmony_ci		if (new_speed >= 1500)
21462306a36Sopenharmony_ci			return fact * 1500;
21562306a36Sopenharmony_ci		if (new_speed >= 1000)
21662306a36Sopenharmony_ci			return fact * 1000;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci	if (new_speed == 0)
21962306a36Sopenharmony_ci		return 1000;
22062306a36Sopenharmony_ci	if (new_speed == 1 || new_speed == 1000)
22162306a36Sopenharmony_ci		return fact * new_speed;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	s = new_speed;
22462306a36Sopenharmony_ci	new_speed = 1000 / new_speed;
22562306a36Sopenharmony_ci	if (1000 / cur_speed == new_speed)
22662306a36Sopenharmony_ci		new_speed += (cur_speed < s) ? -1 : 1;
22762306a36Sopenharmony_ci	if (new_speed > 60) return 1000 / (fact * 60);
22862306a36Sopenharmony_ci	return 1000 / (fact * new_speed);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
23262306a36Sopenharmony_ci		struct v4l2_decoder_cmd *dc, int try)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
23762306a36Sopenharmony_ci		return -EINVAL;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	switch (dc->cmd) {
24062306a36Sopenharmony_ci	case V4L2_DEC_CMD_START: {
24162306a36Sopenharmony_ci		dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO;
24262306a36Sopenharmony_ci		dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed);
24362306a36Sopenharmony_ci		if (dc->start.speed < 0)
24462306a36Sopenharmony_ci			dc->start.format = V4L2_DEC_START_FMT_GOP;
24562306a36Sopenharmony_ci		else
24662306a36Sopenharmony_ci			dc->start.format = V4L2_DEC_START_FMT_NONE;
24762306a36Sopenharmony_ci		if (dc->start.speed != 500 && dc->start.speed != 1500)
24862306a36Sopenharmony_ci			dc->flags = dc->start.speed == 1000 ? 0 :
24962306a36Sopenharmony_ci					V4L2_DEC_CMD_START_MUTE_AUDIO;
25062306a36Sopenharmony_ci		if (try) break;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO;
25362306a36Sopenharmony_ci		if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
25462306a36Sopenharmony_ci			return -EBUSY;
25562306a36Sopenharmony_ci		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
25662306a36Sopenharmony_ci			/* forces ivtv_set_speed to be called */
25762306a36Sopenharmony_ci			itv->speed = 0;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci		return ivtv_start_decoding(id, dc->start.speed);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	case V4L2_DEC_CMD_STOP:
26362306a36Sopenharmony_ci		dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK;
26462306a36Sopenharmony_ci		if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY)
26562306a36Sopenharmony_ci			dc->stop.pts = 0;
26662306a36Sopenharmony_ci		if (try) break;
26762306a36Sopenharmony_ci		if (atomic_read(&itv->decoding) == 0)
26862306a36Sopenharmony_ci			return 0;
26962306a36Sopenharmony_ci		if (itv->output_mode != OUT_MPG)
27062306a36Sopenharmony_ci			return -EBUSY;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		itv->output_mode = OUT_NONE;
27362306a36Sopenharmony_ci		return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	case V4L2_DEC_CMD_PAUSE:
27662306a36Sopenharmony_ci		dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK;
27762306a36Sopenharmony_ci		if (try) break;
27862306a36Sopenharmony_ci		if (!atomic_read(&itv->decoding))
27962306a36Sopenharmony_ci			return -EPERM;
28062306a36Sopenharmony_ci		if (itv->output_mode != OUT_MPG)
28162306a36Sopenharmony_ci			return -EBUSY;
28262306a36Sopenharmony_ci		if (atomic_read(&itv->decoding) > 0) {
28362306a36Sopenharmony_ci			ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
28462306a36Sopenharmony_ci				(dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0);
28562306a36Sopenharmony_ci			set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
28662306a36Sopenharmony_ci		}
28762306a36Sopenharmony_ci		break;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	case V4L2_DEC_CMD_RESUME:
29062306a36Sopenharmony_ci		dc->flags = 0;
29162306a36Sopenharmony_ci		if (try) break;
29262306a36Sopenharmony_ci		if (!atomic_read(&itv->decoding))
29362306a36Sopenharmony_ci			return -EPERM;
29462306a36Sopenharmony_ci		if (itv->output_mode != OUT_MPG)
29562306a36Sopenharmony_ci			return -EBUSY;
29662306a36Sopenharmony_ci		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
29762306a36Sopenharmony_ci			int speed = itv->speed;
29862306a36Sopenharmony_ci			itv->speed = 0;
29962306a36Sopenharmony_ci			return ivtv_start_decoding(id, speed);
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci		break;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	default:
30462306a36Sopenharmony_ci		return -EINVAL;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci	return 0;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
31262306a36Sopenharmony_ci	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	vbifmt->reserved[0] = 0;
31562306a36Sopenharmony_ci	vbifmt->reserved[1] = 0;
31662306a36Sopenharmony_ci	if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
31762306a36Sopenharmony_ci		return -EINVAL;
31862306a36Sopenharmony_ci	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
31962306a36Sopenharmony_ci	memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
32062306a36Sopenharmony_ci	if (itv->is_60hz) {
32162306a36Sopenharmony_ci		vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
32262306a36Sopenharmony_ci		vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
32362306a36Sopenharmony_ci	} else {
32462306a36Sopenharmony_ci		vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
32562306a36Sopenharmony_ci		vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci	vbifmt->service_set = ivtv_get_service_set(vbifmt);
32862306a36Sopenharmony_ci	return 0;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
33462306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
33562306a36Sopenharmony_ci	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	pixfmt->width = itv->cxhdl.width;
33862306a36Sopenharmony_ci	pixfmt->height = itv->cxhdl.height;
33962306a36Sopenharmony_ci	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
34062306a36Sopenharmony_ci	pixfmt->field = V4L2_FIELD_INTERLACED;
34162306a36Sopenharmony_ci	if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
34262306a36Sopenharmony_ci		pixfmt->pixelformat = V4L2_PIX_FMT_NV12_16L16;
34362306a36Sopenharmony_ci		/* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
34462306a36Sopenharmony_ci		pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
34562306a36Sopenharmony_ci		pixfmt->bytesperline = 720;
34662306a36Sopenharmony_ci	} else {
34762306a36Sopenharmony_ci		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
34862306a36Sopenharmony_ci		pixfmt->sizeimage = 128 * 1024;
34962306a36Sopenharmony_ci		pixfmt->bytesperline = 0;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	return 0;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
35762306a36Sopenharmony_ci	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	vbifmt->sampling_rate = 27000000;
36062306a36Sopenharmony_ci	vbifmt->offset = 248;
36162306a36Sopenharmony_ci	vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4;
36262306a36Sopenharmony_ci	vbifmt->sample_format = V4L2_PIX_FMT_GREY;
36362306a36Sopenharmony_ci	vbifmt->start[0] = itv->vbi.start[0];
36462306a36Sopenharmony_ci	vbifmt->start[1] = itv->vbi.start[1];
36562306a36Sopenharmony_ci	vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count;
36662306a36Sopenharmony_ci	vbifmt->flags = 0;
36762306a36Sopenharmony_ci	vbifmt->reserved[0] = 0;
36862306a36Sopenharmony_ci	vbifmt->reserved[1] = 0;
36962306a36Sopenharmony_ci	return 0;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
37562306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
37662306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	vbifmt->reserved[0] = 0;
37962306a36Sopenharmony_ci	vbifmt->reserved[1] = 0;
38062306a36Sopenharmony_ci	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (id->type == IVTV_DEC_STREAM_TYPE_VBI) {
38362306a36Sopenharmony_ci		vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
38462306a36Sopenharmony_ci			V4L2_SLICED_VBI_525;
38562306a36Sopenharmony_ci		ivtv_expand_service_set(vbifmt, itv->is_50hz);
38662306a36Sopenharmony_ci		vbifmt->service_set = ivtv_get_service_set(vbifmt);
38762306a36Sopenharmony_ci		return 0;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	v4l2_subdev_call(itv->sd_video, vbi, g_sliced_fmt, vbifmt);
39162306a36Sopenharmony_ci	vbifmt->service_set = ivtv_get_service_set(vbifmt);
39262306a36Sopenharmony_ci	return 0;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
39862306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
39962306a36Sopenharmony_ci	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
40262306a36Sopenharmony_ci		return -EINVAL;
40362306a36Sopenharmony_ci	pixfmt->width = itv->main_rect.width;
40462306a36Sopenharmony_ci	pixfmt->height = itv->main_rect.height;
40562306a36Sopenharmony_ci	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
40662306a36Sopenharmony_ci	pixfmt->field = V4L2_FIELD_INTERLACED;
40762306a36Sopenharmony_ci	if (id->type == IVTV_DEC_STREAM_TYPE_YUV) {
40862306a36Sopenharmony_ci		switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
40962306a36Sopenharmony_ci		case IVTV_YUV_MODE_INTERLACED:
41062306a36Sopenharmony_ci			pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
41162306a36Sopenharmony_ci				V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
41262306a36Sopenharmony_ci			break;
41362306a36Sopenharmony_ci		case IVTV_YUV_MODE_PROGRESSIVE:
41462306a36Sopenharmony_ci			pixfmt->field = V4L2_FIELD_NONE;
41562306a36Sopenharmony_ci			break;
41662306a36Sopenharmony_ci		default:
41762306a36Sopenharmony_ci			pixfmt->field = V4L2_FIELD_ANY;
41862306a36Sopenharmony_ci			break;
41962306a36Sopenharmony_ci		}
42062306a36Sopenharmony_ci		pixfmt->pixelformat = V4L2_PIX_FMT_NV12_16L16;
42162306a36Sopenharmony_ci		pixfmt->bytesperline = 720;
42262306a36Sopenharmony_ci		pixfmt->width = itv->yuv_info.v4l2_src_w;
42362306a36Sopenharmony_ci		pixfmt->height = itv->yuv_info.v4l2_src_h;
42462306a36Sopenharmony_ci		/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
42562306a36Sopenharmony_ci		pixfmt->sizeimage =
42662306a36Sopenharmony_ci			1080 * ((pixfmt->height + 31) & ~31);
42762306a36Sopenharmony_ci	} else {
42862306a36Sopenharmony_ci		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
42962306a36Sopenharmony_ci		pixfmt->sizeimage = 128 * 1024;
43062306a36Sopenharmony_ci		pixfmt->bytesperline = 0;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci	return 0;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
43862306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
43962306a36Sopenharmony_ci	struct v4l2_window *winfmt = &fmt->fmt.win;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
44262306a36Sopenharmony_ci		return -EINVAL;
44362306a36Sopenharmony_ci	if (!itv->osd_video_pbase)
44462306a36Sopenharmony_ci		return -EINVAL;
44562306a36Sopenharmony_ci	winfmt->chromakey = itv->osd_chroma_key;
44662306a36Sopenharmony_ci	winfmt->global_alpha = itv->osd_global_alpha;
44762306a36Sopenharmony_ci	winfmt->field = V4L2_FIELD_INTERLACED;
44862306a36Sopenharmony_ci	winfmt->clips = NULL;
44962306a36Sopenharmony_ci	winfmt->clipcount = 0;
45062306a36Sopenharmony_ci	winfmt->bitmap = NULL;
45162306a36Sopenharmony_ci	winfmt->w.top = winfmt->w.left = 0;
45262306a36Sopenharmony_ci	winfmt->w.width = itv->osd_rect.width;
45362306a36Sopenharmony_ci	winfmt->w.height = itv->osd_rect.height;
45462306a36Sopenharmony_ci	return 0;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
46562306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
46662306a36Sopenharmony_ci	int w = fmt->fmt.pix.width;
46762306a36Sopenharmony_ci	int h = fmt->fmt.pix.height;
46862306a36Sopenharmony_ci	int min_h = 2;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	w = min(w, 720);
47162306a36Sopenharmony_ci	w = max(w, 2);
47262306a36Sopenharmony_ci	if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
47362306a36Sopenharmony_ci		/* YUV height must be a multiple of 32 */
47462306a36Sopenharmony_ci		h &= ~0x1f;
47562306a36Sopenharmony_ci		min_h = 32;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci	h = min(h, itv->is_50hz ? 576 : 480);
47862306a36Sopenharmony_ci	h = max(h, min_h);
47962306a36Sopenharmony_ci	ivtv_g_fmt_vid_cap(file, fh, fmt);
48062306a36Sopenharmony_ci	fmt->fmt.pix.width = w;
48162306a36Sopenharmony_ci	fmt->fmt.pix.height = h;
48262306a36Sopenharmony_ci	return 0;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
49362306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
49462306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (id->type == IVTV_DEC_STREAM_TYPE_VBI)
49762306a36Sopenharmony_ci		return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* set sliced VBI capture format */
50062306a36Sopenharmony_ci	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
50162306a36Sopenharmony_ci	vbifmt->reserved[0] = 0;
50262306a36Sopenharmony_ci	vbifmt->reserved[1] = 0;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (vbifmt->service_set)
50562306a36Sopenharmony_ci		ivtv_expand_service_set(vbifmt, itv->is_50hz);
50662306a36Sopenharmony_ci	check_service_set(vbifmt, itv->is_50hz);
50762306a36Sopenharmony_ci	vbifmt->service_set = ivtv_get_service_set(vbifmt);
50862306a36Sopenharmony_ci	return 0;
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
51462306a36Sopenharmony_ci	s32 w = fmt->fmt.pix.width;
51562306a36Sopenharmony_ci	s32 h = fmt->fmt.pix.height;
51662306a36Sopenharmony_ci	int field = fmt->fmt.pix.field;
51762306a36Sopenharmony_ci	int ret = ivtv_g_fmt_vid_out(file, fh, fmt);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	w = min(w, 720);
52062306a36Sopenharmony_ci	w = max(w, 2);
52162306a36Sopenharmony_ci	/* Why can the height be 576 even when the output is NTSC?
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	   Internally the buffers of the PVR350 are always set to 720x576. The
52462306a36Sopenharmony_ci	   decoded video frame will always be placed in the top left corner of
52562306a36Sopenharmony_ci	   this buffer. For any video which is not 720x576, the buffer will
52662306a36Sopenharmony_ci	   then be cropped to remove the unused right and lower areas, with
52762306a36Sopenharmony_ci	   the remaining image being scaled by the hardware to fit the display
52862306a36Sopenharmony_ci	   area. The video can be scaled both up and down, so a 720x480 video
52962306a36Sopenharmony_ci	   can be displayed full-screen on PAL and a 720x576 video can be
53062306a36Sopenharmony_ci	   displayed without cropping on NTSC.
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	   Note that the scaling only occurs on the video stream, the osd
53362306a36Sopenharmony_ci	   resolution is locked to the broadcast standard and not scaled.
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	   Thanks to Ian Armstrong for this explanation. */
53662306a36Sopenharmony_ci	h = min(h, 576);
53762306a36Sopenharmony_ci	h = max(h, 2);
53862306a36Sopenharmony_ci	if (id->type == IVTV_DEC_STREAM_TYPE_YUV)
53962306a36Sopenharmony_ci		fmt->fmt.pix.field = field;
54062306a36Sopenharmony_ci	fmt->fmt.pix.width = w;
54162306a36Sopenharmony_ci	fmt->fmt.pix.height = h;
54262306a36Sopenharmony_ci	return ret;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
54862306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
54962306a36Sopenharmony_ci	u32 chromakey = fmt->fmt.win.chromakey;
55062306a36Sopenharmony_ci	u8 global_alpha = fmt->fmt.win.global_alpha;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
55362306a36Sopenharmony_ci		return -EINVAL;
55462306a36Sopenharmony_ci	if (!itv->osd_video_pbase)
55562306a36Sopenharmony_ci		return -EINVAL;
55662306a36Sopenharmony_ci	ivtv_g_fmt_vid_out_overlay(file, fh, fmt);
55762306a36Sopenharmony_ci	fmt->fmt.win.chromakey = chromakey;
55862306a36Sopenharmony_ci	fmt->fmt.win.global_alpha = global_alpha;
55962306a36Sopenharmony_ci	return 0;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
57062306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
57162306a36Sopenharmony_ci	struct v4l2_subdev_format format = {
57262306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
57362306a36Sopenharmony_ci	};
57462306a36Sopenharmony_ci	int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
57562306a36Sopenharmony_ci	int w = fmt->fmt.pix.width;
57662306a36Sopenharmony_ci	int h = fmt->fmt.pix.height;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	if (ret)
57962306a36Sopenharmony_ci		return ret;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (itv->cxhdl.width == w && itv->cxhdl.height == h)
58262306a36Sopenharmony_ci		return 0;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (atomic_read(&itv->capturing) > 0)
58562306a36Sopenharmony_ci		return -EBUSY;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	itv->cxhdl.width = w;
58862306a36Sopenharmony_ci	itv->cxhdl.height = h;
58962306a36Sopenharmony_ci	if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
59062306a36Sopenharmony_ci		fmt->fmt.pix.width /= 2;
59162306a36Sopenharmony_ci	format.format.width = fmt->fmt.pix.width;
59262306a36Sopenharmony_ci	format.format.height = h;
59362306a36Sopenharmony_ci	format.format.code = MEDIA_BUS_FMT_FIXED;
59462306a36Sopenharmony_ci	v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format);
59562306a36Sopenharmony_ci	return ivtv_g_fmt_vid_cap(file, fh, fmt);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
60362306a36Sopenharmony_ci		return -EBUSY;
60462306a36Sopenharmony_ci	itv->vbi.sliced_in->service_set = 0;
60562306a36Sopenharmony_ci	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
60662306a36Sopenharmony_ci	v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &fmt->fmt.vbi);
60762306a36Sopenharmony_ci	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
61362306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
61462306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
61562306a36Sopenharmony_ci	int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI)
61862306a36Sopenharmony_ci		return ret;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	check_service_set(vbifmt, itv->is_50hz);
62162306a36Sopenharmony_ci	if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
62262306a36Sopenharmony_ci		return -EBUSY;
62362306a36Sopenharmony_ci	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
62462306a36Sopenharmony_ci	v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, vbifmt);
62562306a36Sopenharmony_ci	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
62662306a36Sopenharmony_ci	return 0;
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
63262306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
63362306a36Sopenharmony_ci	struct yuv_playback_info *yi = &itv->yuv_info;
63462306a36Sopenharmony_ci	int ret = ivtv_try_fmt_vid_out(file, fh, fmt);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if (ret)
63762306a36Sopenharmony_ci		return ret;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	if (id->type != IVTV_DEC_STREAM_TYPE_YUV)
64062306a36Sopenharmony_ci		return 0;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	/* Return now if we already have some frame data */
64362306a36Sopenharmony_ci	if (yi->stream_size)
64462306a36Sopenharmony_ci		return -EBUSY;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	yi->v4l2_src_w = fmt->fmt.pix.width;
64762306a36Sopenharmony_ci	yi->v4l2_src_h = fmt->fmt.pix.height;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	switch (fmt->fmt.pix.field) {
65062306a36Sopenharmony_ci	case V4L2_FIELD_NONE:
65162306a36Sopenharmony_ci		yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
65262306a36Sopenharmony_ci		break;
65362306a36Sopenharmony_ci	case V4L2_FIELD_ANY:
65462306a36Sopenharmony_ci		yi->lace_mode = IVTV_YUV_MODE_AUTO;
65562306a36Sopenharmony_ci		break;
65662306a36Sopenharmony_ci	case V4L2_FIELD_INTERLACED_BT:
65762306a36Sopenharmony_ci		yi->lace_mode =
65862306a36Sopenharmony_ci			IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
65962306a36Sopenharmony_ci		break;
66062306a36Sopenharmony_ci	case V4L2_FIELD_INTERLACED_TB:
66162306a36Sopenharmony_ci	default:
66262306a36Sopenharmony_ci		yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
66362306a36Sopenharmony_ci		break;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci	yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
66862306a36Sopenharmony_ci		itv->dma_data_req_size =
66962306a36Sopenharmony_ci			1080 * ((yi->v4l2_src_h + 31) & ~31);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return 0;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
67762306a36Sopenharmony_ci	int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (ret == 0) {
68062306a36Sopenharmony_ci		itv->osd_chroma_key = fmt->fmt.win.chromakey;
68162306a36Sopenharmony_ci		itv->osd_global_alpha = fmt->fmt.win.global_alpha;
68262306a36Sopenharmony_ci		ivtv_set_osd_alpha(itv);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci	return ret;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
68862306a36Sopenharmony_cistatic int ivtv_itvc(struct ivtv *itv, bool get, u64 reg, u64 *val)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	volatile u8 __iomem *reg_start;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (reg & 0x3)
69362306a36Sopenharmony_ci		return -EINVAL;
69462306a36Sopenharmony_ci	if (reg >= IVTV_REG_OFFSET && reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
69562306a36Sopenharmony_ci		reg_start = itv->reg_mem - IVTV_REG_OFFSET;
69662306a36Sopenharmony_ci	else if (itv->has_cx23415 && reg >= IVTV_DECODER_OFFSET &&
69762306a36Sopenharmony_ci			reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
69862306a36Sopenharmony_ci		reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;
69962306a36Sopenharmony_ci	else if (reg < IVTV_ENCODER_SIZE)
70062306a36Sopenharmony_ci		reg_start = itv->enc_mem;
70162306a36Sopenharmony_ci	else
70262306a36Sopenharmony_ci		return -EINVAL;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (get)
70562306a36Sopenharmony_ci		*val = readl(reg + reg_start);
70662306a36Sopenharmony_ci	else
70762306a36Sopenharmony_ci		writel(*val, reg + reg_start);
70862306a36Sopenharmony_ci	return 0;
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	reg->size = 4;
71662306a36Sopenharmony_ci	return ivtv_itvc(itv, true, reg->reg, &reg->val);
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
72262306a36Sopenharmony_ci	u64 val = reg->val;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	return ivtv_itvc(itv, false, reg->reg, &val);
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci#endif
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cistatic int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(file->private_data);
73162306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
73462306a36Sopenharmony_ci	strscpy(vcap->card, itv->card_name, sizeof(vcap->card));
73562306a36Sopenharmony_ci	vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
73662306a36Sopenharmony_ci	return 0;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	return ivtv_get_audio_input(itv, vin->index, vin);
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	vin->index = itv->audio_input;
75162306a36Sopenharmony_ci	return ivtv_get_audio_input(itv, vin->index, vin);
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_cistatic int ivtv_s_audio(struct file *file, void *fh, const struct v4l2_audio *vout)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (vout->index >= itv->nof_audio_inputs)
75962306a36Sopenharmony_ci		return -EINVAL;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	itv->audio_input = vout->index;
76262306a36Sopenharmony_ci	ivtv_audio_set_io(itv);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	return 0;
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	/* set it to defaults from our table */
77262306a36Sopenharmony_ci	return ivtv_get_audio_output(itv, vin->index, vin);
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	vin->index = 0;
78062306a36Sopenharmony_ci	return ivtv_get_audio_output(itv, vin->index, vin);
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic int ivtv_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (itv->card->video_outputs == NULL || vout->index != 0)
78862306a36Sopenharmony_ci		return -EINVAL;
78962306a36Sopenharmony_ci	return 0;
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* set it to defaults from our table */
79762306a36Sopenharmony_ci	return ivtv_get_input(itv, vin->index, vin);
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return ivtv_get_output(itv, vout->index, vout);
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic int ivtv_g_pixelaspect(struct file *file, void *fh,
80862306a36Sopenharmony_ci			      int type, struct v4l2_fract *f)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
81162306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
81462306a36Sopenharmony_ci		f->numerator = itv->is_50hz ? 54 : 11;
81562306a36Sopenharmony_ci		f->denominator = itv->is_50hz ? 59 : 10;
81662306a36Sopenharmony_ci	} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
81762306a36Sopenharmony_ci		f->numerator = itv->is_out_50hz ? 54 : 11;
81862306a36Sopenharmony_ci		f->denominator = itv->is_out_50hz ? 59 : 10;
81962306a36Sopenharmony_ci	} else {
82062306a36Sopenharmony_ci		return -EINVAL;
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci	return 0;
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic int ivtv_s_selection(struct file *file, void *fh,
82662306a36Sopenharmony_ci			    struct v4l2_selection *sel)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
82962306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
83062306a36Sopenharmony_ci	struct yuv_playback_info *yi = &itv->yuv_info;
83162306a36Sopenharmony_ci	struct v4l2_rect r = { 0, 0, 720, 0 };
83262306a36Sopenharmony_ci	int streamtype = id->type;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
83562306a36Sopenharmony_ci	    !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
83662306a36Sopenharmony_ci		return -EINVAL;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (sel->target != V4L2_SEL_TGT_COMPOSE)
83962306a36Sopenharmony_ci		return -EINVAL;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
84362306a36Sopenharmony_ci	    !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
84462306a36Sopenharmony_ci		return -EINVAL;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	r.height = itv->is_out_50hz ? 576 : 480;
84762306a36Sopenharmony_ci	if (streamtype == IVTV_DEC_STREAM_TYPE_YUV && yi->track_osd) {
84862306a36Sopenharmony_ci		r.width = yi->osd_full_w;
84962306a36Sopenharmony_ci		r.height = yi->osd_full_h;
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci	sel->r.width = clamp(sel->r.width, 16U, r.width);
85262306a36Sopenharmony_ci	sel->r.height = clamp(sel->r.height, 16U, r.height);
85362306a36Sopenharmony_ci	sel->r.left = clamp_t(unsigned, sel->r.left, 0, r.width - sel->r.width);
85462306a36Sopenharmony_ci	sel->r.top = clamp_t(unsigned, sel->r.top, 0, r.height - sel->r.height);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
85762306a36Sopenharmony_ci		yi->main_rect = sel->r;
85862306a36Sopenharmony_ci		return 0;
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci	if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
86162306a36Sopenharmony_ci			sel->r.width, sel->r.height, sel->r.left, sel->r.top)) {
86262306a36Sopenharmony_ci		itv->main_rect = sel->r;
86362306a36Sopenharmony_ci		return 0;
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci	return -EINVAL;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic int ivtv_g_selection(struct file *file, void *fh,
86962306a36Sopenharmony_ci			    struct v4l2_selection *sel)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
87262306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
87362306a36Sopenharmony_ci	struct yuv_playback_info *yi = &itv->yuv_info;
87462306a36Sopenharmony_ci	struct v4l2_rect r = { 0, 0, 720, 0 };
87562306a36Sopenharmony_ci	int streamtype = id->type;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	if (sel->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
87862306a36Sopenharmony_ci		switch (sel->target) {
87962306a36Sopenharmony_ci		case V4L2_SEL_TGT_CROP_DEFAULT:
88062306a36Sopenharmony_ci		case V4L2_SEL_TGT_CROP_BOUNDS:
88162306a36Sopenharmony_ci			sel->r.top = sel->r.left = 0;
88262306a36Sopenharmony_ci			sel->r.width = 720;
88362306a36Sopenharmony_ci			sel->r.height = itv->is_50hz ? 576 : 480;
88462306a36Sopenharmony_ci			return 0;
88562306a36Sopenharmony_ci		default:
88662306a36Sopenharmony_ci			return -EINVAL;
88762306a36Sopenharmony_ci		}
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
89162306a36Sopenharmony_ci	    !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
89262306a36Sopenharmony_ci		return -EINVAL;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	switch (sel->target) {
89562306a36Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE:
89662306a36Sopenharmony_ci		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
89762306a36Sopenharmony_ci			sel->r = yi->main_rect;
89862306a36Sopenharmony_ci		else
89962306a36Sopenharmony_ci			sel->r = itv->main_rect;
90062306a36Sopenharmony_ci		return 0;
90162306a36Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
90262306a36Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
90362306a36Sopenharmony_ci		r.height = itv->is_out_50hz ? 576 : 480;
90462306a36Sopenharmony_ci		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV && yi->track_osd) {
90562306a36Sopenharmony_ci			r.width = yi->osd_full_w;
90662306a36Sopenharmony_ci			r.height = yi->osd_full_h;
90762306a36Sopenharmony_ci		}
90862306a36Sopenharmony_ci		sel->r = r;
90962306a36Sopenharmony_ci		return 0;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci	return -EINVAL;
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	static const struct v4l2_fmtdesc hm12 = {
91762306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
91862306a36Sopenharmony_ci		.description = "HM12 (YUV 4:2:0)",
91962306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_NV12_16L16,
92062306a36Sopenharmony_ci	};
92162306a36Sopenharmony_ci	static const struct v4l2_fmtdesc mpeg = {
92262306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
92362306a36Sopenharmony_ci		.flags = V4L2_FMT_FLAG_COMPRESSED,
92462306a36Sopenharmony_ci		.description = "MPEG",
92562306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_MPEG,
92662306a36Sopenharmony_ci	};
92762306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
92862306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	if (fmt->index)
93162306a36Sopenharmony_ci		return -EINVAL;
93262306a36Sopenharmony_ci	if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
93362306a36Sopenharmony_ci		*fmt = mpeg;
93462306a36Sopenharmony_ci	else if (s->type == IVTV_ENC_STREAM_TYPE_YUV)
93562306a36Sopenharmony_ci		*fmt = hm12;
93662306a36Sopenharmony_ci	else
93762306a36Sopenharmony_ci		return -EINVAL;
93862306a36Sopenharmony_ci	return 0;
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_cistatic int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	static const struct v4l2_fmtdesc hm12 = {
94462306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
94562306a36Sopenharmony_ci		.description = "HM12 (YUV 4:2:0)",
94662306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_NV12_16L16,
94762306a36Sopenharmony_ci	};
94862306a36Sopenharmony_ci	static const struct v4l2_fmtdesc mpeg = {
94962306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
95062306a36Sopenharmony_ci		.flags = V4L2_FMT_FLAG_COMPRESSED,
95162306a36Sopenharmony_ci		.description = "MPEG",
95262306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_MPEG,
95362306a36Sopenharmony_ci	};
95462306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
95562306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	if (fmt->index)
95862306a36Sopenharmony_ci		return -EINVAL;
95962306a36Sopenharmony_ci	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
96062306a36Sopenharmony_ci		*fmt = mpeg;
96162306a36Sopenharmony_ci	else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
96262306a36Sopenharmony_ci		*fmt = hm12;
96362306a36Sopenharmony_ci	else
96462306a36Sopenharmony_ci		return -EINVAL;
96562306a36Sopenharmony_ci	return 0;
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistatic int ivtv_g_input(struct file *file, void *fh, unsigned int *i)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	*i = itv->active_input;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	return 0;
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ciint ivtv_s_input(struct file *file, void *fh, unsigned int inp)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
98062306a36Sopenharmony_ci	v4l2_std_id std;
98162306a36Sopenharmony_ci	int i;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	if (inp >= itv->nof_inputs)
98462306a36Sopenharmony_ci		return -EINVAL;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (inp == itv->active_input) {
98762306a36Sopenharmony_ci		IVTV_DEBUG_INFO("Input unchanged\n");
98862306a36Sopenharmony_ci		return 0;
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	if (atomic_read(&itv->capturing) > 0) {
99262306a36Sopenharmony_ci		return -EBUSY;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	IVTV_DEBUG_INFO("Changing input from %d to %d\n",
99662306a36Sopenharmony_ci			itv->active_input, inp);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	itv->active_input = inp;
99962306a36Sopenharmony_ci	/* Set the audio input to whatever is appropriate for the
100062306a36Sopenharmony_ci	   input type. */
100162306a36Sopenharmony_ci	itv->audio_input = itv->card->video_inputs[inp].audio_index;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	if (itv->card->video_inputs[inp].video_type == IVTV_CARD_INPUT_VID_TUNER)
100462306a36Sopenharmony_ci		std = itv->tuner_std;
100562306a36Sopenharmony_ci	else
100662306a36Sopenharmony_ci		std = V4L2_STD_ALL;
100762306a36Sopenharmony_ci	for (i = 0; i <= IVTV_ENC_STREAM_TYPE_VBI; i++)
100862306a36Sopenharmony_ci		itv->streams[i].vdev.tvnorms = std;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	/* prevent others from messing with the streams until
101162306a36Sopenharmony_ci	   we're finished changing inputs. */
101262306a36Sopenharmony_ci	ivtv_mute(itv);
101362306a36Sopenharmony_ci	ivtv_video_set_io(itv);
101462306a36Sopenharmony_ci	ivtv_audio_set_io(itv);
101562306a36Sopenharmony_ci	ivtv_unmute(itv);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	return 0;
101862306a36Sopenharmony_ci}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_cistatic int ivtv_g_output(struct file *file, void *fh, unsigned int *i)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
102562306a36Sopenharmony_ci		return -EINVAL;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	*i = itv->active_output;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	return 0;
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_cistatic int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	if (outp >= itv->card->nof_outputs)
103762306a36Sopenharmony_ci		return -EINVAL;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (outp == itv->active_output) {
104062306a36Sopenharmony_ci		IVTV_DEBUG_INFO("Output unchanged\n");
104162306a36Sopenharmony_ci		return 0;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci	IVTV_DEBUG_INFO("Changing output from %d to %d\n",
104462306a36Sopenharmony_ci		   itv->active_output, outp);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	itv->active_output = outp;
104762306a36Sopenharmony_ci	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
104862306a36Sopenharmony_ci			SAA7127_INPUT_TYPE_NORMAL,
104962306a36Sopenharmony_ci			itv->card->video_outputs[outp].video_output, 0);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	return 0;
105262306a36Sopenharmony_ci}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cistatic int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
105562306a36Sopenharmony_ci{
105662306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
105762306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	if (s->vdev.vfl_dir)
106062306a36Sopenharmony_ci		return -ENOTTY;
106162306a36Sopenharmony_ci	if (vf->tuner != 0)
106262306a36Sopenharmony_ci		return -EINVAL;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	ivtv_call_all(itv, tuner, g_frequency, vf);
106562306a36Sopenharmony_ci	return 0;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ciint ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
107162306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (s->vdev.vfl_dir)
107462306a36Sopenharmony_ci		return -ENOTTY;
107562306a36Sopenharmony_ci	if (vf->tuner != 0)
107662306a36Sopenharmony_ci		return -EINVAL;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	ivtv_mute(itv);
107962306a36Sopenharmony_ci	IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
108062306a36Sopenharmony_ci	ivtv_call_all(itv, tuner, s_frequency, vf);
108162306a36Sopenharmony_ci	ivtv_unmute(itv);
108262306a36Sopenharmony_ci	return 0;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	*std = itv->std;
109062306a36Sopenharmony_ci	return 0;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_civoid ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	itv->std = std;
109662306a36Sopenharmony_ci	itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
109762306a36Sopenharmony_ci	itv->is_50hz = !itv->is_60hz;
109862306a36Sopenharmony_ci	cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz);
109962306a36Sopenharmony_ci	itv->cxhdl.width = 720;
110062306a36Sopenharmony_ci	itv->cxhdl.height = itv->is_50hz ? 576 : 480;
110162306a36Sopenharmony_ci	itv->vbi.count = itv->is_50hz ? 18 : 12;
110262306a36Sopenharmony_ci	itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
110362306a36Sopenharmony_ci	itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	if (itv->hw_flags & IVTV_HW_CX25840)
110662306a36Sopenharmony_ci		itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/* Tuner */
110962306a36Sopenharmony_ci	ivtv_call_all(itv, video, s_std, itv->std);
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_civoid ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	struct yuv_playback_info *yi = &itv->yuv_info;
111562306a36Sopenharmony_ci	DEFINE_WAIT(wait);
111662306a36Sopenharmony_ci	int f;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/* set display standard */
111962306a36Sopenharmony_ci	itv->std_out = std;
112062306a36Sopenharmony_ci	itv->is_out_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
112162306a36Sopenharmony_ci	itv->is_out_50hz = !itv->is_out_60hz;
112262306a36Sopenharmony_ci	ivtv_call_all(itv, video, s_std_output, itv->std_out);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	/*
112562306a36Sopenharmony_ci	 * The next firmware call is time sensitive. Time it to
112662306a36Sopenharmony_ci	 * avoid risk of a hard lock, by trying to ensure the call
112762306a36Sopenharmony_ci	 * happens within the first 100 lines of the top field.
112862306a36Sopenharmony_ci	 * Make 4 attempts to sync to the decoder before giving up.
112962306a36Sopenharmony_ci	 */
113062306a36Sopenharmony_ci	mutex_unlock(&itv->serialize_lock);
113162306a36Sopenharmony_ci	for (f = 0; f < 4; f++) {
113262306a36Sopenharmony_ci		prepare_to_wait(&itv->vsync_waitq, &wait,
113362306a36Sopenharmony_ci				TASK_UNINTERRUPTIBLE);
113462306a36Sopenharmony_ci		if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100)
113562306a36Sopenharmony_ci			break;
113662306a36Sopenharmony_ci		schedule_timeout(msecs_to_jiffies(25));
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci	finish_wait(&itv->vsync_waitq, &wait);
113962306a36Sopenharmony_ci	mutex_lock(&itv->serialize_lock);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (f == 4)
114262306a36Sopenharmony_ci		IVTV_WARN("Mode change failed to sync to decoder\n");
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
114562306a36Sopenharmony_ci	itv->main_rect.left = 0;
114662306a36Sopenharmony_ci	itv->main_rect.top = 0;
114762306a36Sopenharmony_ci	itv->main_rect.width = 720;
114862306a36Sopenharmony_ci	itv->main_rect.height = itv->is_out_50hz ? 576 : 480;
114962306a36Sopenharmony_ci	ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
115062306a36Sopenharmony_ci		720, itv->main_rect.height, 0, 0);
115162306a36Sopenharmony_ci	yi->main_rect = itv->main_rect;
115262306a36Sopenharmony_ci	if (!itv->osd_info) {
115362306a36Sopenharmony_ci		yi->osd_full_w = 720;
115462306a36Sopenharmony_ci		yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if ((std & V4L2_STD_ALL) == 0)
116362306a36Sopenharmony_ci		return -EINVAL;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	if (std == itv->std)
116662306a36Sopenharmony_ci		return 0;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
116962306a36Sopenharmony_ci	    atomic_read(&itv->capturing) > 0 ||
117062306a36Sopenharmony_ci	    atomic_read(&itv->decoding) > 0) {
117162306a36Sopenharmony_ci		/* Switching standard would mess with already running
117262306a36Sopenharmony_ci		   streams, prevent that by returning EBUSY. */
117362306a36Sopenharmony_ci		return -EBUSY;
117462306a36Sopenharmony_ci	}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	IVTV_DEBUG_INFO("Switching standard to %llx.\n",
117762306a36Sopenharmony_ci		(unsigned long long)itv->std);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	ivtv_s_std_enc(itv, std);
118062306a36Sopenharmony_ci	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
118162306a36Sopenharmony_ci		ivtv_s_std_dec(itv, std);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	return 0;
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
118962306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	if (vt->index != 0)
119262306a36Sopenharmony_ci		return -EINVAL;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	ivtv_call_all(itv, tuner, s_tuner, vt);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return 0;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	if (vt->index != 0)
120462306a36Sopenharmony_ci		return -EINVAL;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	ivtv_call_all(itv, tuner, g_tuner, vt);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	if (vt->type == V4L2_TUNER_RADIO)
120962306a36Sopenharmony_ci		strscpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
121062306a36Sopenharmony_ci	else
121162306a36Sopenharmony_ci		strscpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
121262306a36Sopenharmony_ci	return 0;
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
121862306a36Sopenharmony_ci	int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
121962306a36Sopenharmony_ci	int f, l;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
122262306a36Sopenharmony_ci		for (f = 0; f < 2; f++) {
122362306a36Sopenharmony_ci			for (l = 0; l < 24; l++) {
122462306a36Sopenharmony_ci				if (valid_service_line(f, l, itv->is_50hz))
122562306a36Sopenharmony_ci					cap->service_lines[f][l] = set;
122662306a36Sopenharmony_ci			}
122762306a36Sopenharmony_ci		}
122862306a36Sopenharmony_ci	} else if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
122962306a36Sopenharmony_ci		if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
123062306a36Sopenharmony_ci			return -EINVAL;
123162306a36Sopenharmony_ci		if (itv->is_60hz) {
123262306a36Sopenharmony_ci			cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
123362306a36Sopenharmony_ci			cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
123462306a36Sopenharmony_ci		} else {
123562306a36Sopenharmony_ci			cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
123662306a36Sopenharmony_ci			cap->service_lines[0][16] = V4L2_SLICED_VPS;
123762306a36Sopenharmony_ci		}
123862306a36Sopenharmony_ci	} else {
123962306a36Sopenharmony_ci		return -EINVAL;
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	set = 0;
124362306a36Sopenharmony_ci	for (f = 0; f < 2; f++)
124462306a36Sopenharmony_ci		for (l = 0; l < 24; l++)
124562306a36Sopenharmony_ci			set |= cap->service_lines[f][l];
124662306a36Sopenharmony_ci	cap->service_set = set;
124762306a36Sopenharmony_ci	return 0;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
125362306a36Sopenharmony_ci	struct v4l2_enc_idx_entry *e = idx->entry;
125462306a36Sopenharmony_ci	int entries;
125562306a36Sopenharmony_ci	int i;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
125862306a36Sopenharmony_ci				IVTV_MAX_PGM_INDEX;
125962306a36Sopenharmony_ci	if (entries > V4L2_ENC_IDX_ENTRIES)
126062306a36Sopenharmony_ci		entries = V4L2_ENC_IDX_ENTRIES;
126162306a36Sopenharmony_ci	idx->entries = 0;
126262306a36Sopenharmony_ci	idx->entries_cap = IVTV_MAX_PGM_INDEX;
126362306a36Sopenharmony_ci	if (!atomic_read(&itv->capturing))
126462306a36Sopenharmony_ci		return 0;
126562306a36Sopenharmony_ci	for (i = 0; i < entries; i++) {
126662306a36Sopenharmony_ci		*e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
126762306a36Sopenharmony_ci		if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
126862306a36Sopenharmony_ci			idx->entries++;
126962306a36Sopenharmony_ci			e++;
127062306a36Sopenharmony_ci		}
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci	itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
127362306a36Sopenharmony_ci	return 0;
127462306a36Sopenharmony_ci}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_cistatic int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
127962306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	switch (enc->cmd) {
128362306a36Sopenharmony_ci	case V4L2_ENC_CMD_START:
128462306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
128562306a36Sopenharmony_ci		enc->flags = 0;
128662306a36Sopenharmony_ci		return ivtv_start_capture(id);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	case V4L2_ENC_CMD_STOP:
128962306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
129062306a36Sopenharmony_ci		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
129162306a36Sopenharmony_ci		ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
129262306a36Sopenharmony_ci		return 0;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	case V4L2_ENC_CMD_PAUSE:
129562306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
129662306a36Sopenharmony_ci		enc->flags = 0;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci		if (!atomic_read(&itv->capturing))
129962306a36Sopenharmony_ci			return -EPERM;
130062306a36Sopenharmony_ci		if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
130162306a36Sopenharmony_ci			return 0;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci		ivtv_mute(itv);
130462306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
130562306a36Sopenharmony_ci		break;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	case V4L2_ENC_CMD_RESUME:
130862306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
130962306a36Sopenharmony_ci		enc->flags = 0;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci		if (!atomic_read(&itv->capturing))
131262306a36Sopenharmony_ci			return -EPERM;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci		if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
131562306a36Sopenharmony_ci			return 0;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
131862306a36Sopenharmony_ci		ivtv_unmute(itv);
131962306a36Sopenharmony_ci		break;
132062306a36Sopenharmony_ci	default:
132162306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
132262306a36Sopenharmony_ci		return -EINVAL;
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	return 0;
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_cistatic int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
132962306a36Sopenharmony_ci{
133062306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	switch (enc->cmd) {
133362306a36Sopenharmony_ci	case V4L2_ENC_CMD_START:
133462306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
133562306a36Sopenharmony_ci		enc->flags = 0;
133662306a36Sopenharmony_ci		return 0;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	case V4L2_ENC_CMD_STOP:
133962306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
134062306a36Sopenharmony_ci		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
134162306a36Sopenharmony_ci		return 0;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	case V4L2_ENC_CMD_PAUSE:
134462306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
134562306a36Sopenharmony_ci		enc->flags = 0;
134662306a36Sopenharmony_ci		return 0;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	case V4L2_ENC_CMD_RESUME:
134962306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
135062306a36Sopenharmony_ci		enc->flags = 0;
135162306a36Sopenharmony_ci		return 0;
135262306a36Sopenharmony_ci	default:
135362306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
135462306a36Sopenharmony_ci		return -EINVAL;
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_cistatic int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
136162306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
136262306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
136362306a36Sopenharmony_ci	struct yuv_playback_info *yi = &itv->yuv_info;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	int pixfmt;
136662306a36Sopenharmony_ci	static u32 pixel_format[16] = {
136762306a36Sopenharmony_ci		V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
136862306a36Sopenharmony_ci		V4L2_PIX_FMT_RGB565,
136962306a36Sopenharmony_ci		V4L2_PIX_FMT_RGB555,
137062306a36Sopenharmony_ci		V4L2_PIX_FMT_RGB444,
137162306a36Sopenharmony_ci		V4L2_PIX_FMT_RGB32,
137262306a36Sopenharmony_ci		0,
137362306a36Sopenharmony_ci		0,
137462306a36Sopenharmony_ci		0,
137562306a36Sopenharmony_ci		V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
137662306a36Sopenharmony_ci		V4L2_PIX_FMT_YUV565,
137762306a36Sopenharmony_ci		V4L2_PIX_FMT_YUV555,
137862306a36Sopenharmony_ci		V4L2_PIX_FMT_YUV444,
137962306a36Sopenharmony_ci		V4L2_PIX_FMT_YUV32,
138062306a36Sopenharmony_ci		0,
138162306a36Sopenharmony_ci		0,
138262306a36Sopenharmony_ci		0,
138362306a36Sopenharmony_ci	};
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
138662306a36Sopenharmony_ci		return -ENOTTY;
138762306a36Sopenharmony_ci	if (!itv->osd_video_pbase)
138862306a36Sopenharmony_ci		return -ENOTTY;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
139162306a36Sopenharmony_ci		V4L2_FBUF_CAP_GLOBAL_ALPHA;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
139462306a36Sopenharmony_ci	data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
139562306a36Sopenharmony_ci	pixfmt = (data[0] >> 3) & 0xf;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	fb->fmt.pixelformat = pixel_format[pixfmt];
139862306a36Sopenharmony_ci	fb->fmt.width = itv->osd_rect.width;
139962306a36Sopenharmony_ci	fb->fmt.height = itv->osd_rect.height;
140062306a36Sopenharmony_ci	fb->fmt.field = V4L2_FIELD_INTERLACED;
140162306a36Sopenharmony_ci	fb->fmt.bytesperline = fb->fmt.width;
140262306a36Sopenharmony_ci	fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
140362306a36Sopenharmony_ci	fb->fmt.field = V4L2_FIELD_INTERLACED;
140462306a36Sopenharmony_ci	if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8)
140562306a36Sopenharmony_ci		fb->fmt.bytesperline *= 2;
140662306a36Sopenharmony_ci	if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 ||
140762306a36Sopenharmony_ci	    fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32)
140862306a36Sopenharmony_ci		fb->fmt.bytesperline *= 2;
140962306a36Sopenharmony_ci	fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height;
141062306a36Sopenharmony_ci	fb->base = (void *)itv->osd_video_pbase;
141162306a36Sopenharmony_ci	fb->flags = 0;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (itv->osd_chroma_key_state)
141462306a36Sopenharmony_ci		fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (itv->osd_global_alpha_state)
141762306a36Sopenharmony_ci		fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if (yi->track_osd)
142062306a36Sopenharmony_ci		fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	pixfmt &= 7;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	/* no local alpha for RGB565 or unknown formats */
142562306a36Sopenharmony_ci	if (pixfmt == 1 || pixfmt > 4)
142662306a36Sopenharmony_ci		return 0;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	/* 16-bit formats have inverted local alpha */
142962306a36Sopenharmony_ci	if (pixfmt == 2 || pixfmt == 3)
143062306a36Sopenharmony_ci		fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
143162306a36Sopenharmony_ci	else
143262306a36Sopenharmony_ci		fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	if (itv->osd_local_alpha_state) {
143562306a36Sopenharmony_ci		/* 16-bit formats have inverted local alpha */
143662306a36Sopenharmony_ci		if (pixfmt == 2 || pixfmt == 3)
143762306a36Sopenharmony_ci			fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
143862306a36Sopenharmony_ci		else
143962306a36Sopenharmony_ci			fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	return 0;
144362306a36Sopenharmony_ci}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_cistatic int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb)
144662306a36Sopenharmony_ci{
144762306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
144862306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
144962306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
145062306a36Sopenharmony_ci	struct yuv_playback_info *yi = &itv->yuv_info;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
145362306a36Sopenharmony_ci		return -ENOTTY;
145462306a36Sopenharmony_ci	if (!itv->osd_video_pbase)
145562306a36Sopenharmony_ci		return -ENOTTY;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
145862306a36Sopenharmony_ci	itv->osd_local_alpha_state =
145962306a36Sopenharmony_ci		(fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
146062306a36Sopenharmony_ci	itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
146162306a36Sopenharmony_ci	ivtv_set_osd_alpha(itv);
146262306a36Sopenharmony_ci	yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
146362306a36Sopenharmony_ci	return 0;
146462306a36Sopenharmony_ci}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_cistatic int ivtv_overlay(struct file *file, void *fh, unsigned int on)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(fh);
146962306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
147062306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
147362306a36Sopenharmony_ci		return -ENOTTY;
147462306a36Sopenharmony_ci	if (!itv->osd_video_pbase)
147562306a36Sopenharmony_ci		return -ENOTTY;
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	return 0;
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cistatic int ivtv_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)
148362306a36Sopenharmony_ci{
148462306a36Sopenharmony_ci	switch (sub->type) {
148562306a36Sopenharmony_ci	case V4L2_EVENT_VSYNC:
148662306a36Sopenharmony_ci	case V4L2_EVENT_EOS:
148762306a36Sopenharmony_ci		return v4l2_event_subscribe(fh, sub, 0, NULL);
148862306a36Sopenharmony_ci	default:
148962306a36Sopenharmony_ci		return v4l2_ctrl_subscribe_event(fh, sub);
149062306a36Sopenharmony_ci	}
149162306a36Sopenharmony_ci}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_cistatic int ivtv_log_status(struct file *file, void *fh)
149462306a36Sopenharmony_ci{
149562306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
149662306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
149962306a36Sopenharmony_ci	struct v4l2_input vidin;
150062306a36Sopenharmony_ci	struct v4l2_audio audin;
150162306a36Sopenharmony_ci	int i;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
150462306a36Sopenharmony_ci	if (itv->hw_flags & IVTV_HW_TVEEPROM) {
150562306a36Sopenharmony_ci		struct tveeprom tv;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci		ivtv_read_eeprom(itv, &tv);
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci	ivtv_call_all(itv, core, log_status);
151062306a36Sopenharmony_ci	ivtv_get_input(itv, itv->active_input, &vidin);
151162306a36Sopenharmony_ci	ivtv_get_audio_input(itv, itv->audio_input, &audin);
151262306a36Sopenharmony_ci	IVTV_INFO("Video Input:  %s\n", vidin.name);
151362306a36Sopenharmony_ci	IVTV_INFO("Audio Input:  %s%s\n", audin.name,
151462306a36Sopenharmony_ci		itv->dualwatch_stereo_mode == V4L2_MPEG_AUDIO_MODE_DUAL ?
151562306a36Sopenharmony_ci			" (Bilingual)" : "");
151662306a36Sopenharmony_ci	if (has_output) {
151762306a36Sopenharmony_ci		struct v4l2_output vidout;
151862306a36Sopenharmony_ci		struct v4l2_audioout audout;
151962306a36Sopenharmony_ci		int mode = itv->output_mode;
152062306a36Sopenharmony_ci		static const char * const output_modes[5] = {
152162306a36Sopenharmony_ci			"None",
152262306a36Sopenharmony_ci			"MPEG Streaming",
152362306a36Sopenharmony_ci			"YUV Streaming",
152462306a36Sopenharmony_ci			"YUV Frames",
152562306a36Sopenharmony_ci			"Passthrough",
152662306a36Sopenharmony_ci		};
152762306a36Sopenharmony_ci		static const char * const alpha_mode[4] = {
152862306a36Sopenharmony_ci			"None",
152962306a36Sopenharmony_ci			"Global",
153062306a36Sopenharmony_ci			"Local",
153162306a36Sopenharmony_ci			"Global and Local"
153262306a36Sopenharmony_ci		};
153362306a36Sopenharmony_ci		static const char * const pixel_format[16] = {
153462306a36Sopenharmony_ci			"ARGB Indexed",
153562306a36Sopenharmony_ci			"RGB 5:6:5",
153662306a36Sopenharmony_ci			"ARGB 1:5:5:5",
153762306a36Sopenharmony_ci			"ARGB 1:4:4:4",
153862306a36Sopenharmony_ci			"ARGB 8:8:8:8",
153962306a36Sopenharmony_ci			"5",
154062306a36Sopenharmony_ci			"6",
154162306a36Sopenharmony_ci			"7",
154262306a36Sopenharmony_ci			"AYUV Indexed",
154362306a36Sopenharmony_ci			"YUV 5:6:5",
154462306a36Sopenharmony_ci			"AYUV 1:5:5:5",
154562306a36Sopenharmony_ci			"AYUV 1:4:4:4",
154662306a36Sopenharmony_ci			"AYUV 8:8:8:8",
154762306a36Sopenharmony_ci			"13",
154862306a36Sopenharmony_ci			"14",
154962306a36Sopenharmony_ci			"15",
155062306a36Sopenharmony_ci		};
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci		ivtv_get_output(itv, itv->active_output, &vidout);
155362306a36Sopenharmony_ci		ivtv_get_audio_output(itv, 0, &audout);
155462306a36Sopenharmony_ci		IVTV_INFO("Video Output: %s\n", vidout.name);
155562306a36Sopenharmony_ci		if (mode < 0 || mode > OUT_PASSTHROUGH)
155662306a36Sopenharmony_ci			mode = OUT_NONE;
155762306a36Sopenharmony_ci		IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
155862306a36Sopenharmony_ci		ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
155962306a36Sopenharmony_ci		data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
156062306a36Sopenharmony_ci		IVTV_INFO("Overlay:      %s, Alpha: %s, Pixel Format: %s\n",
156162306a36Sopenharmony_ci			data[0] & 1 ? "On" : "Off",
156262306a36Sopenharmony_ci			alpha_mode[(data[0] >> 1) & 0x3],
156362306a36Sopenharmony_ci			pixel_format[(data[0] >> 3) & 0xf]);
156462306a36Sopenharmony_ci	}
156562306a36Sopenharmony_ci	IVTV_INFO("Tuner:  %s\n",
156662306a36Sopenharmony_ci		test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
156762306a36Sopenharmony_ci	v4l2_ctrl_handler_log_status(&itv->cxhdl.hdl, itv->v4l2_dev.name);
156862306a36Sopenharmony_ci	IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
156962306a36Sopenharmony_ci	for (i = 0; i < IVTV_MAX_STREAMS; i++) {
157062306a36Sopenharmony_ci		struct ivtv_stream *s = &itv->streams[i];
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci		if (s->vdev.v4l2_dev == NULL || s->buffers == 0)
157362306a36Sopenharmony_ci			continue;
157462306a36Sopenharmony_ci		IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
157562306a36Sopenharmony_ci				(s->buffers - s->q_free.buffers) * 100 / s->buffers,
157662306a36Sopenharmony_ci				(s->buffers * s->buf_size) / 1024, s->buffers);
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
158062306a36Sopenharmony_ci			(long long)itv->mpg_data_received,
158162306a36Sopenharmony_ci			(long long)itv->vbi_data_inserted);
158262306a36Sopenharmony_ci	return 0;
158362306a36Sopenharmony_ci}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_cistatic int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
158662306a36Sopenharmony_ci{
158762306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(file->private_data);
158862306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd);
159162306a36Sopenharmony_ci	return ivtv_video_command(itv, id, dec, false);
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(file->private_data);
159762306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd);
160062306a36Sopenharmony_ci	return ivtv_video_command(itv, id, dec, true);
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	struct ivtv_open_id *id = fh2id(filp->private_data);
160662306a36Sopenharmony_ci	struct ivtv *itv = id->itv;
160762306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[id->type];
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	switch (cmd) {
161062306a36Sopenharmony_ci	case IVTV_IOC_DMA_FRAME: {
161162306a36Sopenharmony_ci		struct ivtv_dma_frame *args = arg;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n");
161462306a36Sopenharmony_ci		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
161562306a36Sopenharmony_ci			return -EINVAL;
161662306a36Sopenharmony_ci		if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
161762306a36Sopenharmony_ci			return -EINVAL;
161862306a36Sopenharmony_ci		if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL)
161962306a36Sopenharmony_ci			return 0;
162062306a36Sopenharmony_ci		if (ivtv_start_decoding(id, id->type)) {
162162306a36Sopenharmony_ci			return -EBUSY;
162262306a36Sopenharmony_ci		}
162362306a36Sopenharmony_ci		if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) {
162462306a36Sopenharmony_ci			ivtv_release_stream(s);
162562306a36Sopenharmony_ci			return -EBUSY;
162662306a36Sopenharmony_ci		}
162762306a36Sopenharmony_ci		/* Mark that this file handle started the UDMA_YUV mode */
162862306a36Sopenharmony_ci		id->yuv_frames = 1;
162962306a36Sopenharmony_ci		if (args->y_source == NULL)
163062306a36Sopenharmony_ci			return 0;
163162306a36Sopenharmony_ci		return ivtv_yuv_prep_frame(itv, args);
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	case IVTV_IOC_PASSTHROUGH_MODE:
163562306a36Sopenharmony_ci		IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n");
163662306a36Sopenharmony_ci		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
163762306a36Sopenharmony_ci			return -EINVAL;
163862306a36Sopenharmony_ci		return ivtv_passthrough_mode(itv, *(int *)arg != 0);
163962306a36Sopenharmony_ci	default:
164062306a36Sopenharmony_ci		return -EINVAL;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci	return 0;
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_cistatic long ivtv_default(struct file *file, void *fh, bool valid_prio,
164662306a36Sopenharmony_ci			 unsigned int cmd, void *arg)
164762306a36Sopenharmony_ci{
164862306a36Sopenharmony_ci	struct ivtv *itv = fh2id(fh)->itv;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if (!valid_prio) {
165162306a36Sopenharmony_ci		switch (cmd) {
165262306a36Sopenharmony_ci		case IVTV_IOC_PASSTHROUGH_MODE:
165362306a36Sopenharmony_ci			return -EBUSY;
165462306a36Sopenharmony_ci		}
165562306a36Sopenharmony_ci	}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	switch (cmd) {
165862306a36Sopenharmony_ci	case VIDIOC_INT_RESET: {
165962306a36Sopenharmony_ci		u32 val = *(u32 *)arg;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci		if ((val == 0 && itv->options.newi2c) || (val & 0x01))
166262306a36Sopenharmony_ci			ivtv_reset_ir_gpio(itv);
166362306a36Sopenharmony_ci		if (val & 0x02)
166462306a36Sopenharmony_ci			v4l2_subdev_call(itv->sd_video, core, reset, 0);
166562306a36Sopenharmony_ci		break;
166662306a36Sopenharmony_ci	}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	case IVTV_IOC_DMA_FRAME:
166962306a36Sopenharmony_ci	case IVTV_IOC_PASSTHROUGH_MODE:
167062306a36Sopenharmony_ci		return ivtv_decoder_ioctls(file, cmd, (void *)arg);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	default:
167362306a36Sopenharmony_ci		return -ENOTTY;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci	return 0;
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
167962306a36Sopenharmony_ci	.vidioc_querycap		    = ivtv_querycap,
168062306a36Sopenharmony_ci	.vidioc_s_audio			    = ivtv_s_audio,
168162306a36Sopenharmony_ci	.vidioc_g_audio			    = ivtv_g_audio,
168262306a36Sopenharmony_ci	.vidioc_enumaudio		    = ivtv_enumaudio,
168362306a36Sopenharmony_ci	.vidioc_s_audout		    = ivtv_s_audout,
168462306a36Sopenharmony_ci	.vidioc_g_audout		    = ivtv_g_audout,
168562306a36Sopenharmony_ci	.vidioc_enum_input		    = ivtv_enum_input,
168662306a36Sopenharmony_ci	.vidioc_enum_output		    = ivtv_enum_output,
168762306a36Sopenharmony_ci	.vidioc_enumaudout		    = ivtv_enumaudout,
168862306a36Sopenharmony_ci	.vidioc_g_pixelaspect		    = ivtv_g_pixelaspect,
168962306a36Sopenharmony_ci	.vidioc_s_selection		    = ivtv_s_selection,
169062306a36Sopenharmony_ci	.vidioc_g_selection		    = ivtv_g_selection,
169162306a36Sopenharmony_ci	.vidioc_g_input			    = ivtv_g_input,
169262306a36Sopenharmony_ci	.vidioc_s_input			    = ivtv_s_input,
169362306a36Sopenharmony_ci	.vidioc_g_output		    = ivtv_g_output,
169462306a36Sopenharmony_ci	.vidioc_s_output		    = ivtv_s_output,
169562306a36Sopenharmony_ci	.vidioc_g_frequency		    = ivtv_g_frequency,
169662306a36Sopenharmony_ci	.vidioc_s_frequency		    = ivtv_s_frequency,
169762306a36Sopenharmony_ci	.vidioc_s_tuner			    = ivtv_s_tuner,
169862306a36Sopenharmony_ci	.vidioc_g_tuner			    = ivtv_g_tuner,
169962306a36Sopenharmony_ci	.vidioc_g_enc_index		    = ivtv_g_enc_index,
170062306a36Sopenharmony_ci	.vidioc_g_fbuf			    = ivtv_g_fbuf,
170162306a36Sopenharmony_ci	.vidioc_s_fbuf			    = ivtv_s_fbuf,
170262306a36Sopenharmony_ci	.vidioc_g_std			    = ivtv_g_std,
170362306a36Sopenharmony_ci	.vidioc_s_std			    = ivtv_s_std,
170462306a36Sopenharmony_ci	.vidioc_overlay			    = ivtv_overlay,
170562306a36Sopenharmony_ci	.vidioc_log_status		    = ivtv_log_status,
170662306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_cap	    = ivtv_enum_fmt_vid_cap,
170762306a36Sopenharmony_ci	.vidioc_encoder_cmd		    = ivtv_encoder_cmd,
170862306a36Sopenharmony_ci	.vidioc_try_encoder_cmd		    = ivtv_try_encoder_cmd,
170962306a36Sopenharmony_ci	.vidioc_decoder_cmd		    = ivtv_decoder_cmd,
171062306a36Sopenharmony_ci	.vidioc_try_decoder_cmd		    = ivtv_try_decoder_cmd,
171162306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_out	    = ivtv_enum_fmt_vid_out,
171262306a36Sopenharmony_ci	.vidioc_g_fmt_vid_cap		    = ivtv_g_fmt_vid_cap,
171362306a36Sopenharmony_ci	.vidioc_g_fmt_vbi_cap		    = ivtv_g_fmt_vbi_cap,
171462306a36Sopenharmony_ci	.vidioc_g_fmt_sliced_vbi_cap        = ivtv_g_fmt_sliced_vbi_cap,
171562306a36Sopenharmony_ci	.vidioc_g_fmt_vid_out               = ivtv_g_fmt_vid_out,
171662306a36Sopenharmony_ci	.vidioc_g_fmt_vid_out_overlay       = ivtv_g_fmt_vid_out_overlay,
171762306a36Sopenharmony_ci	.vidioc_g_fmt_sliced_vbi_out        = ivtv_g_fmt_sliced_vbi_out,
171862306a36Sopenharmony_ci	.vidioc_s_fmt_vid_cap		    = ivtv_s_fmt_vid_cap,
171962306a36Sopenharmony_ci	.vidioc_s_fmt_vbi_cap		    = ivtv_s_fmt_vbi_cap,
172062306a36Sopenharmony_ci	.vidioc_s_fmt_sliced_vbi_cap        = ivtv_s_fmt_sliced_vbi_cap,
172162306a36Sopenharmony_ci	.vidioc_s_fmt_vid_out               = ivtv_s_fmt_vid_out,
172262306a36Sopenharmony_ci	.vidioc_s_fmt_vid_out_overlay       = ivtv_s_fmt_vid_out_overlay,
172362306a36Sopenharmony_ci	.vidioc_s_fmt_sliced_vbi_out        = ivtv_s_fmt_sliced_vbi_out,
172462306a36Sopenharmony_ci	.vidioc_try_fmt_vid_cap		    = ivtv_try_fmt_vid_cap,
172562306a36Sopenharmony_ci	.vidioc_try_fmt_vbi_cap		    = ivtv_try_fmt_vbi_cap,
172662306a36Sopenharmony_ci	.vidioc_try_fmt_sliced_vbi_cap      = ivtv_try_fmt_sliced_vbi_cap,
172762306a36Sopenharmony_ci	.vidioc_try_fmt_vid_out		    = ivtv_try_fmt_vid_out,
172862306a36Sopenharmony_ci	.vidioc_try_fmt_vid_out_overlay     = ivtv_try_fmt_vid_out_overlay,
172962306a36Sopenharmony_ci	.vidioc_try_fmt_sliced_vbi_out	    = ivtv_try_fmt_sliced_vbi_out,
173062306a36Sopenharmony_ci	.vidioc_g_sliced_vbi_cap	    = ivtv_g_sliced_vbi_cap,
173162306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
173262306a36Sopenharmony_ci	.vidioc_g_register		    = ivtv_g_register,
173362306a36Sopenharmony_ci	.vidioc_s_register		    = ivtv_s_register,
173462306a36Sopenharmony_ci#endif
173562306a36Sopenharmony_ci	.vidioc_default			    = ivtv_default,
173662306a36Sopenharmony_ci	.vidioc_subscribe_event		    = ivtv_subscribe_event,
173762306a36Sopenharmony_ci	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
173862306a36Sopenharmony_ci};
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_civoid ivtv_set_funcs(struct video_device *vdev)
174162306a36Sopenharmony_ci{
174262306a36Sopenharmony_ci	vdev->ioctl_ops = &ivtv_ioctl_ops;
174362306a36Sopenharmony_ci}
1744