162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  cx18 ioctl system call
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Derived from ivtv-ioctl.c
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
862306a36Sopenharmony_ci *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.net>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "cx18-driver.h"
1262306a36Sopenharmony_ci#include "cx18-io.h"
1362306a36Sopenharmony_ci#include "cx18-version.h"
1462306a36Sopenharmony_ci#include "cx18-mailbox.h"
1562306a36Sopenharmony_ci#include "cx18-i2c.h"
1662306a36Sopenharmony_ci#include "cx18-queue.h"
1762306a36Sopenharmony_ci#include "cx18-fileops.h"
1862306a36Sopenharmony_ci#include "cx18-vbi.h"
1962306a36Sopenharmony_ci#include "cx18-audio.h"
2062306a36Sopenharmony_ci#include "cx18-video.h"
2162306a36Sopenharmony_ci#include "cx18-streams.h"
2262306a36Sopenharmony_ci#include "cx18-ioctl.h"
2362306a36Sopenharmony_ci#include "cx18-gpio.h"
2462306a36Sopenharmony_ci#include "cx18-controls.h"
2562306a36Sopenharmony_ci#include "cx18-cards.h"
2662306a36Sopenharmony_ci#include "cx18-av-core.h"
2762306a36Sopenharmony_ci#include <media/tveeprom.h>
2862306a36Sopenharmony_ci#include <media/v4l2-event.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic const struct v4l2_fmtdesc cx18_formats_yuv[] = {
3162306a36Sopenharmony_ci	{
3262306a36Sopenharmony_ci		.index = 0,
3362306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
3462306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_NV12_16L16,
3562306a36Sopenharmony_ci	},
3662306a36Sopenharmony_ci	{
3762306a36Sopenharmony_ci		.index = 1,
3862306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
3962306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_UYVY,
4062306a36Sopenharmony_ci	},
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic const struct v4l2_fmtdesc cx18_formats_mpeg[] = {
4462306a36Sopenharmony_ci	{
4562306a36Sopenharmony_ci		.index = 0,
4662306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
4762306a36Sopenharmony_ci		.flags = V4L2_FMT_FLAG_COMPRESSED,
4862306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_MPEG,
4962306a36Sopenharmony_ci	},
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int cx18_g_fmt_vid_cap(struct file *file, void *fh,
5362306a36Sopenharmony_ci			      struct v4l2_format *fmt)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
5662306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
5762306a36Sopenharmony_ci	struct cx18_stream *s = &cx->streams[id->type];
5862306a36Sopenharmony_ci	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	pixfmt->width = cx->cxhdl.width;
6162306a36Sopenharmony_ci	pixfmt->height = cx->cxhdl.height;
6262306a36Sopenharmony_ci	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
6362306a36Sopenharmony_ci	pixfmt->field = V4L2_FIELD_INTERLACED;
6462306a36Sopenharmony_ci	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
6562306a36Sopenharmony_ci		pixfmt->pixelformat = s->pixelformat;
6662306a36Sopenharmony_ci		pixfmt->sizeimage = s->vb_bytes_per_frame;
6762306a36Sopenharmony_ci		pixfmt->bytesperline = s->vb_bytes_per_line;
6862306a36Sopenharmony_ci	} else {
6962306a36Sopenharmony_ci		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
7062306a36Sopenharmony_ci		pixfmt->sizeimage = 128 * 1024;
7162306a36Sopenharmony_ci		pixfmt->bytesperline = 0;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci	return 0;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic int cx18_try_fmt_vid_cap(struct file *file, void *fh,
7762306a36Sopenharmony_ci				struct v4l2_format *fmt)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
8062306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
8162306a36Sopenharmony_ci	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
8262306a36Sopenharmony_ci	int w = pixfmt->width;
8362306a36Sopenharmony_ci	int h = pixfmt->height;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	w = min(w, 720);
8662306a36Sopenharmony_ci	w = max(w, 720 / 16);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	h = min(h, cx->is_50hz ? 576 : 480);
8962306a36Sopenharmony_ci	h = max(h, (cx->is_50hz ? 576 : 480) / 8);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
9262306a36Sopenharmony_ci		if (pixfmt->pixelformat != V4L2_PIX_FMT_NV12_16L16 &&
9362306a36Sopenharmony_ci		    pixfmt->pixelformat != V4L2_PIX_FMT_UYVY)
9462306a36Sopenharmony_ci			pixfmt->pixelformat = V4L2_PIX_FMT_UYVY;
9562306a36Sopenharmony_ci		/* YUV height must be a multiple of 32 */
9662306a36Sopenharmony_ci		h = round_up(h, 32);
9762306a36Sopenharmony_ci		/*
9862306a36Sopenharmony_ci		 * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
9962306a36Sopenharmony_ci		 * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
10062306a36Sopenharmony_ci		 */
10162306a36Sopenharmony_ci		if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12_16L16) {
10262306a36Sopenharmony_ci			pixfmt->sizeimage = h * 720 * 3 / 2;
10362306a36Sopenharmony_ci			pixfmt->bytesperline = 720; /* First plane */
10462306a36Sopenharmony_ci		} else {
10562306a36Sopenharmony_ci			pixfmt->sizeimage = h * 720 * 2;
10662306a36Sopenharmony_ci			pixfmt->bytesperline = 1440; /* Packed */
10762306a36Sopenharmony_ci		}
10862306a36Sopenharmony_ci	} else {
10962306a36Sopenharmony_ci		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
11062306a36Sopenharmony_ci		pixfmt->sizeimage = 128 * 1024;
11162306a36Sopenharmony_ci		pixfmt->bytesperline = 0;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	pixfmt->width = w;
11562306a36Sopenharmony_ci	pixfmt->height = h;
11662306a36Sopenharmony_ci	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
11762306a36Sopenharmony_ci	pixfmt->field = V4L2_FIELD_INTERLACED;
11862306a36Sopenharmony_ci	return 0;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int cx18_s_fmt_vid_cap(struct file *file, void *fh,
12262306a36Sopenharmony_ci			      struct v4l2_format *fmt)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
12562306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
12662306a36Sopenharmony_ci	struct v4l2_subdev_format format = {
12762306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
12862306a36Sopenharmony_ci	};
12962306a36Sopenharmony_ci	struct cx18_stream *s = &cx->streams[id->type];
13062306a36Sopenharmony_ci	int ret;
13162306a36Sopenharmony_ci	int w, h;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	ret = cx18_try_fmt_vid_cap(file, fh, fmt);
13462306a36Sopenharmony_ci	if (ret)
13562306a36Sopenharmony_ci		return ret;
13662306a36Sopenharmony_ci	w = fmt->fmt.pix.width;
13762306a36Sopenharmony_ci	h = fmt->fmt.pix.height;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
14062306a36Sopenharmony_ci	    s->pixelformat == fmt->fmt.pix.pixelformat)
14162306a36Sopenharmony_ci		return 0;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (atomic_read(&cx->ana_capturing) > 0)
14462306a36Sopenharmony_ci		return -EBUSY;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	s->pixelformat = fmt->fmt.pix.pixelformat;
14762306a36Sopenharmony_ci	s->vb_bytes_per_frame = fmt->fmt.pix.sizeimage;
14862306a36Sopenharmony_ci	s->vb_bytes_per_line = fmt->fmt.pix.bytesperline;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	format.format.width = cx->cxhdl.width = w;
15162306a36Sopenharmony_ci	format.format.height = cx->cxhdl.height = h;
15262306a36Sopenharmony_ci	format.format.code = MEDIA_BUS_FMT_FIXED;
15362306a36Sopenharmony_ci	v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format);
15462306a36Sopenharmony_ci	return cx18_g_fmt_vid_cap(file, fh, fmt);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciu16 cx18_service2vbi(int type)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	switch (type) {
16062306a36Sopenharmony_ci	case V4L2_SLICED_TELETEXT_B:
16162306a36Sopenharmony_ci		return CX18_SLICED_TYPE_TELETEXT_B;
16262306a36Sopenharmony_ci	case V4L2_SLICED_CAPTION_525:
16362306a36Sopenharmony_ci		return CX18_SLICED_TYPE_CAPTION_525;
16462306a36Sopenharmony_ci	case V4L2_SLICED_WSS_625:
16562306a36Sopenharmony_ci		return CX18_SLICED_TYPE_WSS_625;
16662306a36Sopenharmony_ci	case V4L2_SLICED_VPS:
16762306a36Sopenharmony_ci		return CX18_SLICED_TYPE_VPS;
16862306a36Sopenharmony_ci	default:
16962306a36Sopenharmony_ci		return 0;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* Check if VBI services are allowed on the (field, line) for the video std */
17462306a36Sopenharmony_cistatic int valid_service_line(int field, int line, int is_pal)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	return (is_pal && line >= 6 &&
17762306a36Sopenharmony_ci		((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
17862306a36Sopenharmony_ci	       (!is_pal && line >= 10 && line < 22);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/*
18262306a36Sopenharmony_ci * For a (field, line, std) and inbound potential set of services for that line,
18362306a36Sopenharmony_ci * return the first valid service of those passed in the incoming set for that
18462306a36Sopenharmony_ci * line in priority order:
18562306a36Sopenharmony_ci * CC, VPS, or WSS over TELETEXT for well known lines
18662306a36Sopenharmony_ci * TELETEXT, before VPS, before CC, before WSS, for other lines
18762306a36Sopenharmony_ci */
18862306a36Sopenharmony_cistatic u16 select_service_from_set(int field, int line, u16 set, int is_pal)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
19162306a36Sopenharmony_ci	int i;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	set = set & valid_set;
19462306a36Sopenharmony_ci	if (set == 0 || !valid_service_line(field, line, is_pal))
19562306a36Sopenharmony_ci		return 0;
19662306a36Sopenharmony_ci	if (!is_pal) {
19762306a36Sopenharmony_ci		if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
19862306a36Sopenharmony_ci			return V4L2_SLICED_CAPTION_525;
19962306a36Sopenharmony_ci	} else {
20062306a36Sopenharmony_ci		if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
20162306a36Sopenharmony_ci			return V4L2_SLICED_VPS;
20262306a36Sopenharmony_ci		if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
20362306a36Sopenharmony_ci			return V4L2_SLICED_WSS_625;
20462306a36Sopenharmony_ci		if (line == 23)
20562306a36Sopenharmony_ci			return 0;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci	for (i = 0; i < 32; i++) {
20862306a36Sopenharmony_ci		if (BIT(i) & set)
20962306a36Sopenharmony_ci			return 1 << i;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/*
21562306a36Sopenharmony_ci * Expand the service_set of *fmt into valid service_lines for the std,
21662306a36Sopenharmony_ci * and clear the passed in fmt->service_set
21762306a36Sopenharmony_ci */
21862306a36Sopenharmony_civoid cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	u16 set = fmt->service_set;
22162306a36Sopenharmony_ci	int f, l;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	fmt->service_set = 0;
22462306a36Sopenharmony_ci	for (f = 0; f < 2; f++) {
22562306a36Sopenharmony_ci		for (l = 0; l < 24; l++)
22662306a36Sopenharmony_ci			fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci/*
23162306a36Sopenharmony_ci * Sanitize the service_lines in *fmt per the video std, and return 1
23262306a36Sopenharmony_ci * if any service_line is left as valid after santization
23362306a36Sopenharmony_ci */
23462306a36Sopenharmony_cistatic int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	int f, l;
23762306a36Sopenharmony_ci	u16 set = 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	for (f = 0; f < 2; f++) {
24062306a36Sopenharmony_ci		for (l = 0; l < 24; l++) {
24162306a36Sopenharmony_ci			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
24262306a36Sopenharmony_ci			set |= fmt->service_lines[f][l];
24362306a36Sopenharmony_ci		}
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci	return set != 0;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/* Compute the service_set from the assumed valid service_lines of *fmt */
24962306a36Sopenharmony_ciu16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	int f, l;
25262306a36Sopenharmony_ci	u16 set = 0;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	for (f = 0; f < 2; f++) {
25562306a36Sopenharmony_ci		for (l = 0; l < 24; l++)
25662306a36Sopenharmony_ci			set |= fmt->service_lines[f][l];
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci	return set;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
26262306a36Sopenharmony_ci				struct v4l2_format *fmt)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
26562306a36Sopenharmony_ci	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	vbifmt->sampling_rate = 27000000;
26862306a36Sopenharmony_ci	vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
26962306a36Sopenharmony_ci	vbifmt->samples_per_line = VBI_ACTIVE_SAMPLES - 4;
27062306a36Sopenharmony_ci	vbifmt->sample_format = V4L2_PIX_FMT_GREY;
27162306a36Sopenharmony_ci	vbifmt->start[0] = cx->vbi.start[0];
27262306a36Sopenharmony_ci	vbifmt->start[1] = cx->vbi.start[1];
27362306a36Sopenharmony_ci	vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
27462306a36Sopenharmony_ci	vbifmt->flags = 0;
27562306a36Sopenharmony_ci	vbifmt->reserved[0] = 0;
27662306a36Sopenharmony_ci	vbifmt->reserved[1] = 0;
27762306a36Sopenharmony_ci	return 0;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
28162306a36Sopenharmony_ci					struct v4l2_format *fmt)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
28462306a36Sopenharmony_ci	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* sane, V4L2 spec compliant, defaults */
28762306a36Sopenharmony_ci	vbifmt->reserved[0] = 0;
28862306a36Sopenharmony_ci	vbifmt->reserved[1] = 0;
28962306a36Sopenharmony_ci	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
29062306a36Sopenharmony_ci	memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
29162306a36Sopenharmony_ci	vbifmt->service_set = 0;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/*
29462306a36Sopenharmony_ci	 * Fetch the configured service_lines and total service_set from the
29562306a36Sopenharmony_ci	 * digitizer/slicer.  Note, cx18_av_vbi() wipes the passed in
29662306a36Sopenharmony_ci	 * fmt->fmt.sliced under valid calling conditions
29762306a36Sopenharmony_ci	 */
29862306a36Sopenharmony_ci	if (v4l2_subdev_call(cx->sd_av, vbi, g_sliced_fmt, &fmt->fmt.sliced))
29962306a36Sopenharmony_ci		return -EINVAL;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	vbifmt->service_set = cx18_get_service_set(vbifmt);
30262306a36Sopenharmony_ci	return 0;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
30662306a36Sopenharmony_ci				struct v4l2_format *fmt)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	return cx18_g_fmt_vbi_cap(file, fh, fmt);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
31262306a36Sopenharmony_ci					struct v4l2_format *fmt)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
31562306a36Sopenharmony_ci	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
31862306a36Sopenharmony_ci	vbifmt->reserved[0] = 0;
31962306a36Sopenharmony_ci	vbifmt->reserved[1] = 0;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/* If given a service set, expand it validly & clear passed in set */
32262306a36Sopenharmony_ci	if (vbifmt->service_set)
32362306a36Sopenharmony_ci		cx18_expand_service_set(vbifmt, cx->is_50hz);
32462306a36Sopenharmony_ci	/* Sanitize the service_lines, and compute the new set if any valid */
32562306a36Sopenharmony_ci	if (check_service_set(vbifmt, cx->is_50hz))
32662306a36Sopenharmony_ci		vbifmt->service_set = cx18_get_service_set(vbifmt);
32762306a36Sopenharmony_ci	return 0;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
33162306a36Sopenharmony_ci				struct v4l2_format *fmt)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
33462306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
33562306a36Sopenharmony_ci	int ret;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/*
33862306a36Sopenharmony_ci	 * Changing the Encoder's Raw VBI parameters won't have any effect
33962306a36Sopenharmony_ci	 * if any analog capture is ongoing
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci	if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
34262306a36Sopenharmony_ci		return -EBUSY;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/*
34562306a36Sopenharmony_ci	 * Set the digitizer registers for raw active VBI.
34662306a36Sopenharmony_ci	 * Note cx18_av_vbi_wipes out a lot of the passed in fmt under valid
34762306a36Sopenharmony_ci	 * calling conditions
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi);
35062306a36Sopenharmony_ci	if (ret)
35162306a36Sopenharmony_ci		return ret;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* Store our new v4l2 (non-)sliced VBI state */
35462306a36Sopenharmony_ci	cx->vbi.sliced_in->service_set = 0;
35562306a36Sopenharmony_ci	cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return cx18_g_fmt_vbi_cap(file, fh, fmt);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
36162306a36Sopenharmony_ci					struct v4l2_format *fmt)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
36462306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
36562306a36Sopenharmony_ci	int ret;
36662306a36Sopenharmony_ci	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/*
37162306a36Sopenharmony_ci	 * Changing the Encoder's Raw VBI parameters won't have any effect
37262306a36Sopenharmony_ci	 * if any analog capture is ongoing
37362306a36Sopenharmony_ci	 */
37462306a36Sopenharmony_ci	if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
37562306a36Sopenharmony_ci		return -EBUSY;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/*
37862306a36Sopenharmony_ci	 * Set the service_lines requested in the digitizer/slicer registers.
37962306a36Sopenharmony_ci	 * Note, cx18_av_vbi() wipes some "impossible" service lines in the
38062306a36Sopenharmony_ci	 * passed in fmt->fmt.sliced under valid calling conditions
38162306a36Sopenharmony_ci	 */
38262306a36Sopenharmony_ci	ret = v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &fmt->fmt.sliced);
38362306a36Sopenharmony_ci	if (ret)
38462306a36Sopenharmony_ci		return ret;
38562306a36Sopenharmony_ci	/* Store our current v4l2 sliced VBI settings */
38662306a36Sopenharmony_ci	cx->vbi.in.type =  V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
38762306a36Sopenharmony_ci	memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
38862306a36Sopenharmony_ci	return 0;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
39262306a36Sopenharmony_cistatic int cx18_g_register(struct file *file, void *fh,
39362306a36Sopenharmony_ci				struct v4l2_dbg_register *reg)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (reg->reg & 0x3)
39862306a36Sopenharmony_ci		return -EINVAL;
39962306a36Sopenharmony_ci	if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
40062306a36Sopenharmony_ci		return -EINVAL;
40162306a36Sopenharmony_ci	reg->size = 4;
40262306a36Sopenharmony_ci	reg->val = cx18_read_enc(cx, reg->reg);
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic int cx18_s_register(struct file *file, void *fh,
40762306a36Sopenharmony_ci				const struct v4l2_dbg_register *reg)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (reg->reg & 0x3)
41262306a36Sopenharmony_ci		return -EINVAL;
41362306a36Sopenharmony_ci	if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
41462306a36Sopenharmony_ci		return -EINVAL;
41562306a36Sopenharmony_ci	cx18_write_enc(cx, reg->val, reg->reg);
41662306a36Sopenharmony_ci	return 0;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci#endif
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int cx18_querycap(struct file *file, void *fh,
42162306a36Sopenharmony_ci				struct v4l2_capability *vcap)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
42462306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
42762306a36Sopenharmony_ci	strscpy(vcap->card, cx->card_name, sizeof(vcap->card));
42862306a36Sopenharmony_ci	vcap->capabilities = cx->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return cx18_get_audio_input(cx, vin->index, vin);
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	vin->index = cx->audio_input;
44462306a36Sopenharmony_ci	return cx18_get_audio_input(cx, vin->index, vin);
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int cx18_s_audio(struct file *file, void *fh, const struct v4l2_audio *vout)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (vout->index >= cx->nof_audio_inputs)
45262306a36Sopenharmony_ci		return -EINVAL;
45362306a36Sopenharmony_ci	cx->audio_input = vout->index;
45462306a36Sopenharmony_ci	cx18_audio_set_io(cx);
45562306a36Sopenharmony_ci	return 0;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* set it to defaults from our table */
46362306a36Sopenharmony_ci	return cx18_get_input(cx, vin->index, vin);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic int cx18_g_pixelaspect(struct file *file, void *fh,
46762306a36Sopenharmony_ci			      int type, struct v4l2_fract *f)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
47262306a36Sopenharmony_ci		return -EINVAL;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	f->numerator = cx->is_50hz ? 54 : 11;
47562306a36Sopenharmony_ci	f->denominator = cx->is_50hz ? 59 : 10;
47662306a36Sopenharmony_ci	return 0;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic int cx18_g_selection(struct file *file, void *fh,
48062306a36Sopenharmony_ci			    struct v4l2_selection *sel)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
48562306a36Sopenharmony_ci		return -EINVAL;
48662306a36Sopenharmony_ci	switch (sel->target) {
48762306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
48862306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_DEFAULT:
48962306a36Sopenharmony_ci		sel->r.top = sel->r.left = 0;
49062306a36Sopenharmony_ci		sel->r.width = 720;
49162306a36Sopenharmony_ci		sel->r.height = cx->is_50hz ? 576 : 480;
49262306a36Sopenharmony_ci		break;
49362306a36Sopenharmony_ci	default:
49462306a36Sopenharmony_ci		return -EINVAL;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci	return 0;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
50062306a36Sopenharmony_ci					struct v4l2_fmtdesc *fmt)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
50562306a36Sopenharmony_ci		if (fmt->index >= ARRAY_SIZE(cx18_formats_yuv))
50662306a36Sopenharmony_ci			return -EINVAL;
50762306a36Sopenharmony_ci		*fmt = cx18_formats_yuv[fmt->index];
50862306a36Sopenharmony_ci		return 0;
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci	if (fmt->index)
51162306a36Sopenharmony_ci		return -EINVAL;
51262306a36Sopenharmony_ci	*fmt = cx18_formats_mpeg[0];
51362306a36Sopenharmony_ci	return 0;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic int cx18_g_input(struct file *file, void *fh, unsigned int *i)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	*i = cx->active_input;
52162306a36Sopenharmony_ci	return 0;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ciint cx18_s_input(struct file *file, void *fh, unsigned int inp)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
52762306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
52862306a36Sopenharmony_ci	v4l2_std_id std = V4L2_STD_ALL;
52962306a36Sopenharmony_ci	const struct cx18_card_video_input *card_input =
53062306a36Sopenharmony_ci				cx->card->video_inputs + inp;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (inp >= cx->nof_inputs)
53362306a36Sopenharmony_ci		return -EINVAL;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (inp == cx->active_input) {
53662306a36Sopenharmony_ci		CX18_DEBUG_INFO("Input unchanged\n");
53762306a36Sopenharmony_ci		return 0;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	CX18_DEBUG_INFO("Changing input from %d to %d\n",
54162306a36Sopenharmony_ci			cx->active_input, inp);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	cx->active_input = inp;
54462306a36Sopenharmony_ci	/* Set the audio input to whatever is appropriate for the input type. */
54562306a36Sopenharmony_ci	cx->audio_input = cx->card->video_inputs[inp].audio_index;
54662306a36Sopenharmony_ci	if (card_input->video_type == V4L2_INPUT_TYPE_TUNER)
54762306a36Sopenharmony_ci		std = cx->tuner_std;
54862306a36Sopenharmony_ci	cx->streams[CX18_ENC_STREAM_TYPE_MPG].video_dev.tvnorms = std;
54962306a36Sopenharmony_ci	cx->streams[CX18_ENC_STREAM_TYPE_YUV].video_dev.tvnorms = std;
55062306a36Sopenharmony_ci	cx->streams[CX18_ENC_STREAM_TYPE_VBI].video_dev.tvnorms = std;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/* prevent others from messing with the streams until
55362306a36Sopenharmony_ci	   we're finished changing inputs. */
55462306a36Sopenharmony_ci	cx18_mute(cx);
55562306a36Sopenharmony_ci	cx18_video_set_io(cx);
55662306a36Sopenharmony_ci	cx18_audio_set_io(cx);
55762306a36Sopenharmony_ci	cx18_unmute(cx);
55862306a36Sopenharmony_ci	return 0;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic int cx18_g_frequency(struct file *file, void *fh,
56262306a36Sopenharmony_ci				struct v4l2_frequency *vf)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (vf->tuner != 0)
56762306a36Sopenharmony_ci		return -EINVAL;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	cx18_call_all(cx, tuner, g_frequency, vf);
57062306a36Sopenharmony_ci	return 0;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ciint cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
57662306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	if (vf->tuner != 0)
57962306a36Sopenharmony_ci		return -EINVAL;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	cx18_mute(cx);
58262306a36Sopenharmony_ci	CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
58362306a36Sopenharmony_ci	cx18_call_all(cx, tuner, s_frequency, vf);
58462306a36Sopenharmony_ci	cx18_unmute(cx);
58562306a36Sopenharmony_ci	return 0;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	*std = cx->std;
59362306a36Sopenharmony_ci	return 0;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ciint cx18_s_std(struct file *file, void *fh, v4l2_std_id std)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
59962306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if ((std & V4L2_STD_ALL) == 0)
60262306a36Sopenharmony_ci		return -EINVAL;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (std == cx->std)
60562306a36Sopenharmony_ci		return 0;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
60862306a36Sopenharmony_ci	    atomic_read(&cx->ana_capturing) > 0) {
60962306a36Sopenharmony_ci		/* Switching standard would turn off the radio or mess
61062306a36Sopenharmony_ci		   with already running streams, prevent that by
61162306a36Sopenharmony_ci		   returning EBUSY. */
61262306a36Sopenharmony_ci		return -EBUSY;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	cx->std = std;
61662306a36Sopenharmony_ci	cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
61762306a36Sopenharmony_ci	cx->is_50hz = !cx->is_60hz;
61862306a36Sopenharmony_ci	cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
61962306a36Sopenharmony_ci	cx->cxhdl.width = 720;
62062306a36Sopenharmony_ci	cx->cxhdl.height = cx->is_50hz ? 576 : 480;
62162306a36Sopenharmony_ci	/*
62262306a36Sopenharmony_ci	 * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
62362306a36Sopenharmony_ci	 * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
62462306a36Sopenharmony_ci	 */
62562306a36Sopenharmony_ci	if (cx->streams[CX18_ENC_STREAM_TYPE_YUV].pixelformat == V4L2_PIX_FMT_NV12_16L16) {
62662306a36Sopenharmony_ci		cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_frame =
62762306a36Sopenharmony_ci			cx->cxhdl.height * 720 * 3 / 2;
62862306a36Sopenharmony_ci		cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_line = 720;
62962306a36Sopenharmony_ci	} else {
63062306a36Sopenharmony_ci		cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_frame =
63162306a36Sopenharmony_ci			cx->cxhdl.height * 720 * 2;
63262306a36Sopenharmony_ci		cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_line = 1440;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci	cx->vbi.count = cx->is_50hz ? 18 : 12;
63562306a36Sopenharmony_ci	cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
63662306a36Sopenharmony_ci	cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
63762306a36Sopenharmony_ci	CX18_DEBUG_INFO("Switching standard to %llx.\n",
63862306a36Sopenharmony_ci			(unsigned long long) cx->std);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* Tuner */
64162306a36Sopenharmony_ci	cx18_call_all(cx, video, s_std, cx->std);
64262306a36Sopenharmony_ci	return 0;
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
64862306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (vt->index != 0)
65162306a36Sopenharmony_ci		return -EINVAL;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	cx18_call_all(cx, tuner, s_tuner, vt);
65462306a36Sopenharmony_ci	return 0;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (vt->index != 0)
66262306a36Sopenharmony_ci		return -EINVAL;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	cx18_call_all(cx, tuner, g_tuner, vt);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (vt->type == V4L2_TUNER_RADIO)
66762306a36Sopenharmony_ci		strscpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
66862306a36Sopenharmony_ci	else
66962306a36Sopenharmony_ci		strscpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
67062306a36Sopenharmony_ci	return 0;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
67462306a36Sopenharmony_ci					struct v4l2_sliced_vbi_cap *cap)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
67762306a36Sopenharmony_ci	int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
67862306a36Sopenharmony_ci	int f, l;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
68162306a36Sopenharmony_ci		return -EINVAL;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	cap->service_set = 0;
68462306a36Sopenharmony_ci	for (f = 0; f < 2; f++) {
68562306a36Sopenharmony_ci		for (l = 0; l < 24; l++) {
68662306a36Sopenharmony_ci			if (valid_service_line(f, l, cx->is_50hz)) {
68762306a36Sopenharmony_ci				/*
68862306a36Sopenharmony_ci				 * We can find all v4l2 supported vbi services
68962306a36Sopenharmony_ci				 * for the standard, on a valid line for the std
69062306a36Sopenharmony_ci				 */
69162306a36Sopenharmony_ci				cap->service_lines[f][l] = set;
69262306a36Sopenharmony_ci				cap->service_set |= set;
69362306a36Sopenharmony_ci			} else
69462306a36Sopenharmony_ci				cap->service_lines[f][l] = 0;
69562306a36Sopenharmony_ci		}
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci	for (f = 0; f < 3; f++)
69862306a36Sopenharmony_ci		cap->reserved[f] = 0;
69962306a36Sopenharmony_ci	return 0;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic int _cx18_process_idx_data(struct cx18_buffer *buf,
70362306a36Sopenharmony_ci				  struct v4l2_enc_idx *idx)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	int consumed, remaining;
70662306a36Sopenharmony_ci	struct v4l2_enc_idx_entry *e_idx;
70762306a36Sopenharmony_ci	struct cx18_enc_idx_entry *e_buf;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* Frame type lookup: 1=I, 2=P, 4=B */
71062306a36Sopenharmony_ci	static const int mapping[8] = {
71162306a36Sopenharmony_ci		-1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P,
71262306a36Sopenharmony_ci		-1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1
71362306a36Sopenharmony_ci	};
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/*
71662306a36Sopenharmony_ci	 * Assumption here is that a buf holds an integral number of
71762306a36Sopenharmony_ci	 * struct cx18_enc_idx_entry objects and is properly aligned.
71862306a36Sopenharmony_ci	 * This is enforced by the module options on IDX buffer sizes.
71962306a36Sopenharmony_ci	 */
72062306a36Sopenharmony_ci	remaining = buf->bytesused - buf->readpos;
72162306a36Sopenharmony_ci	consumed = 0;
72262306a36Sopenharmony_ci	e_idx = &idx->entry[idx->entries];
72362306a36Sopenharmony_ci	e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos];
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	while (remaining >= sizeof(struct cx18_enc_idx_entry) &&
72662306a36Sopenharmony_ci	       idx->entries < V4L2_ENC_IDX_ENTRIES) {
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32)
72962306a36Sopenharmony_ci				| le32_to_cpu(e_buf->offset_low);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32)
73262306a36Sopenharmony_ci			     | le32_to_cpu(e_buf->pts_low);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci		e_idx->length = le32_to_cpu(e_buf->length);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7];
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci		e_idx->reserved[0] = 0;
73962306a36Sopenharmony_ci		e_idx->reserved[1] = 0;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci		idx->entries++;
74262306a36Sopenharmony_ci		e_idx = &idx->entry[idx->entries];
74362306a36Sopenharmony_ci		e_buf++;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		remaining -= sizeof(struct cx18_enc_idx_entry);
74662306a36Sopenharmony_ci		consumed += sizeof(struct cx18_enc_idx_entry);
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	/* Swallow any partial entries at the end, if there are any */
75062306a36Sopenharmony_ci	if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry))
75162306a36Sopenharmony_ci		consumed += remaining;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	buf->readpos += consumed;
75462306a36Sopenharmony_ci	return consumed;
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl,
75862306a36Sopenharmony_ci				 struct v4l2_enc_idx *idx)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	if (s->type != CX18_ENC_STREAM_TYPE_IDX)
76162306a36Sopenharmony_ci		return -EINVAL;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (mdl->curr_buf == NULL)
76462306a36Sopenharmony_ci		mdl->curr_buf = list_first_entry(&mdl->buf_list,
76562306a36Sopenharmony_ci						 struct cx18_buffer, list);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
76862306a36Sopenharmony_ci		/*
76962306a36Sopenharmony_ci		 * For some reason we've exhausted the buffers, but the MDL
77062306a36Sopenharmony_ci		 * object still said some data was unread.
77162306a36Sopenharmony_ci		 * Fix that and bail out.
77262306a36Sopenharmony_ci		 */
77362306a36Sopenharmony_ci		mdl->readpos = mdl->bytesused;
77462306a36Sopenharmony_ci		return 0;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) {
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		/* Skip any empty buffers in the MDL */
78062306a36Sopenharmony_ci		if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused)
78162306a36Sopenharmony_ci			continue;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci		mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci		/* exit when MDL drained or request satisfied */
78662306a36Sopenharmony_ci		if (idx->entries >= V4L2_ENC_IDX_ENTRIES ||
78762306a36Sopenharmony_ci		    mdl->curr_buf->readpos < mdl->curr_buf->bytesused ||
78862306a36Sopenharmony_ci		    mdl->readpos >= mdl->bytesused)
78962306a36Sopenharmony_ci			break;
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci	return 0;
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cistatic int cx18_g_enc_index(struct file *file, void *fh,
79562306a36Sopenharmony_ci				struct v4l2_enc_idx *idx)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
79862306a36Sopenharmony_ci	struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
79962306a36Sopenharmony_ci	s32 tmp;
80062306a36Sopenharmony_ci	struct cx18_mdl *mdl;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */
80362306a36Sopenharmony_ci		return -EINVAL;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* Compute the best case number of entries we can buffer */
80662306a36Sopenharmony_ci	tmp = s->buffers -
80762306a36Sopenharmony_ci			  s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN;
80862306a36Sopenharmony_ci	if (tmp <= 0)
80962306a36Sopenharmony_ci		tmp = 1;
81062306a36Sopenharmony_ci	tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* Fill out the header of the return structure */
81362306a36Sopenharmony_ci	idx->entries = 0;
81462306a36Sopenharmony_ci	idx->entries_cap = tmp;
81562306a36Sopenharmony_ci	memset(idx->reserved, 0, sizeof(idx->reserved));
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* Pull IDX MDLs and buffers from q_full and populate the entries */
81862306a36Sopenharmony_ci	do {
81962306a36Sopenharmony_ci		mdl = cx18_dequeue(s, &s->q_full);
82062306a36Sopenharmony_ci		if (mdl == NULL) /* No more IDX data right now */
82162306a36Sopenharmony_ci			break;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		/* Extract the Index entry data from the MDL and buffers */
82462306a36Sopenharmony_ci		cx18_process_idx_data(s, mdl, idx);
82562306a36Sopenharmony_ci		if (mdl->readpos < mdl->bytesused) {
82662306a36Sopenharmony_ci			/* We finished with data remaining, push the MDL back */
82762306a36Sopenharmony_ci			cx18_push(s, mdl, &s->q_full);
82862306a36Sopenharmony_ci			break;
82962306a36Sopenharmony_ci		}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		/* We drained this MDL, schedule it to go to the firmware */
83262306a36Sopenharmony_ci		cx18_enqueue(s, mdl, &s->q_free);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	} while (idx->entries < V4L2_ENC_IDX_ENTRIES);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* Tell the work handler to send free IDX MDLs to the firmware */
83762306a36Sopenharmony_ci	cx18_stream_load_fw_queue(s);
83862306a36Sopenharmony_ci	return 0;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic int cx18_encoder_cmd(struct file *file, void *fh,
84262306a36Sopenharmony_ci				struct v4l2_encoder_cmd *enc)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	struct cx18_open_id *id = fh2id(fh);
84562306a36Sopenharmony_ci	struct cx18 *cx = id->cx;
84662306a36Sopenharmony_ci	u32 h;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	switch (enc->cmd) {
84962306a36Sopenharmony_ci	case V4L2_ENC_CMD_START:
85062306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
85162306a36Sopenharmony_ci		enc->flags = 0;
85262306a36Sopenharmony_ci		return cx18_start_capture(id);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	case V4L2_ENC_CMD_STOP:
85562306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
85662306a36Sopenharmony_ci		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
85762306a36Sopenharmony_ci		cx18_stop_capture(&cx->streams[id->type],
85862306a36Sopenharmony_ci				  enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
85962306a36Sopenharmony_ci		break;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	case V4L2_ENC_CMD_PAUSE:
86262306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
86362306a36Sopenharmony_ci		enc->flags = 0;
86462306a36Sopenharmony_ci		if (!atomic_read(&cx->ana_capturing))
86562306a36Sopenharmony_ci			return -EPERM;
86662306a36Sopenharmony_ci		if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
86762306a36Sopenharmony_ci			return 0;
86862306a36Sopenharmony_ci		h = cx18_find_handle(cx);
86962306a36Sopenharmony_ci		if (h == CX18_INVALID_TASK_HANDLE) {
87062306a36Sopenharmony_ci			CX18_ERR("Can't find valid task handle for V4L2_ENC_CMD_PAUSE\n");
87162306a36Sopenharmony_ci			return -EBADFD;
87262306a36Sopenharmony_ci		}
87362306a36Sopenharmony_ci		cx18_mute(cx);
87462306a36Sopenharmony_ci		cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);
87562306a36Sopenharmony_ci		break;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	case V4L2_ENC_CMD_RESUME:
87862306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
87962306a36Sopenharmony_ci		enc->flags = 0;
88062306a36Sopenharmony_ci		if (!atomic_read(&cx->ana_capturing))
88162306a36Sopenharmony_ci			return -EPERM;
88262306a36Sopenharmony_ci		if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
88362306a36Sopenharmony_ci			return 0;
88462306a36Sopenharmony_ci		h = cx18_find_handle(cx);
88562306a36Sopenharmony_ci		if (h == CX18_INVALID_TASK_HANDLE) {
88662306a36Sopenharmony_ci			CX18_ERR("Can't find valid task handle for V4L2_ENC_CMD_RESUME\n");
88762306a36Sopenharmony_ci			return -EBADFD;
88862306a36Sopenharmony_ci		}
88962306a36Sopenharmony_ci		cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);
89062306a36Sopenharmony_ci		cx18_unmute(cx);
89162306a36Sopenharmony_ci		break;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	default:
89462306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
89562306a36Sopenharmony_ci		return -EINVAL;
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci	return 0;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int cx18_try_encoder_cmd(struct file *file, void *fh,
90162306a36Sopenharmony_ci				struct v4l2_encoder_cmd *enc)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	switch (enc->cmd) {
90662306a36Sopenharmony_ci	case V4L2_ENC_CMD_START:
90762306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
90862306a36Sopenharmony_ci		enc->flags = 0;
90962306a36Sopenharmony_ci		break;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	case V4L2_ENC_CMD_STOP:
91262306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
91362306a36Sopenharmony_ci		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
91462306a36Sopenharmony_ci		break;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	case V4L2_ENC_CMD_PAUSE:
91762306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
91862306a36Sopenharmony_ci		enc->flags = 0;
91962306a36Sopenharmony_ci		break;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	case V4L2_ENC_CMD_RESUME:
92262306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
92362306a36Sopenharmony_ci		enc->flags = 0;
92462306a36Sopenharmony_ci		break;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	default:
92762306a36Sopenharmony_ci		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
92862306a36Sopenharmony_ci		return -EINVAL;
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci	return 0;
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_cistatic int cx18_log_status(struct file *file, void *fh)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
93662306a36Sopenharmony_ci	struct v4l2_input vidin;
93762306a36Sopenharmony_ci	struct v4l2_audio audin;
93862306a36Sopenharmony_ci	int i;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	CX18_INFO("Version: %s  Card: %s\n", CX18_VERSION, cx->card_name);
94162306a36Sopenharmony_ci	if (cx->hw_flags & CX18_HW_TVEEPROM) {
94262306a36Sopenharmony_ci		struct tveeprom tv;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		cx18_read_eeprom(cx, &tv);
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci	cx18_call_all(cx, core, log_status);
94762306a36Sopenharmony_ci	cx18_get_input(cx, cx->active_input, &vidin);
94862306a36Sopenharmony_ci	cx18_get_audio_input(cx, cx->audio_input, &audin);
94962306a36Sopenharmony_ci	CX18_INFO("Video Input: %s\n", vidin.name);
95062306a36Sopenharmony_ci	CX18_INFO("Audio Input: %s\n", audin.name);
95162306a36Sopenharmony_ci	mutex_lock(&cx->gpio_lock);
95262306a36Sopenharmony_ci	CX18_INFO("GPIO:  direction 0x%08x, value 0x%08x\n",
95362306a36Sopenharmony_ci		cx->gpio_dir, cx->gpio_val);
95462306a36Sopenharmony_ci	mutex_unlock(&cx->gpio_lock);
95562306a36Sopenharmony_ci	CX18_INFO("Tuner: %s\n",
95662306a36Sopenharmony_ci		test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
95762306a36Sopenharmony_ci	v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name);
95862306a36Sopenharmony_ci	CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
95962306a36Sopenharmony_ci	for (i = 0; i < CX18_MAX_STREAMS; i++) {
96062306a36Sopenharmony_ci		struct cx18_stream *s = &cx->streams[i];
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci		if (s->video_dev.v4l2_dev == NULL || s->buffers == 0)
96362306a36Sopenharmony_ci			continue;
96462306a36Sopenharmony_ci		CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
96562306a36Sopenharmony_ci			  s->name, s->s_flags,
96662306a36Sopenharmony_ci			  atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100
96762306a36Sopenharmony_ci			   / s->buffers,
96862306a36Sopenharmony_ci			  (s->buffers * s->buf_size) / 1024, s->buffers);
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
97162306a36Sopenharmony_ci			(long long)cx->mpg_data_received,
97262306a36Sopenharmony_ci			(long long)cx->vbi_data_inserted);
97362306a36Sopenharmony_ci	return 0;
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_cistatic long cx18_default(struct file *file, void *fh, bool valid_prio,
97762306a36Sopenharmony_ci			 unsigned int cmd, void *arg)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	struct cx18 *cx = fh2id(fh)->cx;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	switch (cmd) {
98262306a36Sopenharmony_ci	case VIDIOC_INT_RESET: {
98362306a36Sopenharmony_ci		u32 val = *(u32 *)arg;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci		if ((val == 0) || (val & 0x01))
98662306a36Sopenharmony_ci			cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset,
98762306a36Sopenharmony_ci				     (u32) CX18_GPIO_RESET_Z8F0811);
98862306a36Sopenharmony_ci		break;
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	default:
99262306a36Sopenharmony_ci		return -ENOTTY;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci	return 0;
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops cx18_ioctl_ops = {
99862306a36Sopenharmony_ci	.vidioc_querycap                = cx18_querycap,
99962306a36Sopenharmony_ci	.vidioc_s_audio                 = cx18_s_audio,
100062306a36Sopenharmony_ci	.vidioc_g_audio                 = cx18_g_audio,
100162306a36Sopenharmony_ci	.vidioc_enumaudio               = cx18_enumaudio,
100262306a36Sopenharmony_ci	.vidioc_enum_input              = cx18_enum_input,
100362306a36Sopenharmony_ci	.vidioc_g_pixelaspect           = cx18_g_pixelaspect,
100462306a36Sopenharmony_ci	.vidioc_g_selection             = cx18_g_selection,
100562306a36Sopenharmony_ci	.vidioc_g_input                 = cx18_g_input,
100662306a36Sopenharmony_ci	.vidioc_s_input                 = cx18_s_input,
100762306a36Sopenharmony_ci	.vidioc_g_frequency             = cx18_g_frequency,
100862306a36Sopenharmony_ci	.vidioc_s_frequency             = cx18_s_frequency,
100962306a36Sopenharmony_ci	.vidioc_s_tuner                 = cx18_s_tuner,
101062306a36Sopenharmony_ci	.vidioc_g_tuner                 = cx18_g_tuner,
101162306a36Sopenharmony_ci	.vidioc_g_enc_index             = cx18_g_enc_index,
101262306a36Sopenharmony_ci	.vidioc_g_std                   = cx18_g_std,
101362306a36Sopenharmony_ci	.vidioc_s_std                   = cx18_s_std,
101462306a36Sopenharmony_ci	.vidioc_log_status              = cx18_log_status,
101562306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_cap        = cx18_enum_fmt_vid_cap,
101662306a36Sopenharmony_ci	.vidioc_encoder_cmd             = cx18_encoder_cmd,
101762306a36Sopenharmony_ci	.vidioc_try_encoder_cmd         = cx18_try_encoder_cmd,
101862306a36Sopenharmony_ci	.vidioc_g_fmt_vid_cap           = cx18_g_fmt_vid_cap,
101962306a36Sopenharmony_ci	.vidioc_g_fmt_vbi_cap           = cx18_g_fmt_vbi_cap,
102062306a36Sopenharmony_ci	.vidioc_g_fmt_sliced_vbi_cap    = cx18_g_fmt_sliced_vbi_cap,
102162306a36Sopenharmony_ci	.vidioc_s_fmt_vid_cap           = cx18_s_fmt_vid_cap,
102262306a36Sopenharmony_ci	.vidioc_s_fmt_vbi_cap           = cx18_s_fmt_vbi_cap,
102362306a36Sopenharmony_ci	.vidioc_s_fmt_sliced_vbi_cap    = cx18_s_fmt_sliced_vbi_cap,
102462306a36Sopenharmony_ci	.vidioc_try_fmt_vid_cap         = cx18_try_fmt_vid_cap,
102562306a36Sopenharmony_ci	.vidioc_try_fmt_vbi_cap         = cx18_try_fmt_vbi_cap,
102662306a36Sopenharmony_ci	.vidioc_try_fmt_sliced_vbi_cap  = cx18_try_fmt_sliced_vbi_cap,
102762306a36Sopenharmony_ci	.vidioc_g_sliced_vbi_cap        = cx18_g_sliced_vbi_cap,
102862306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
102962306a36Sopenharmony_ci	.vidioc_g_register              = cx18_g_register,
103062306a36Sopenharmony_ci	.vidioc_s_register              = cx18_s_register,
103162306a36Sopenharmony_ci#endif
103262306a36Sopenharmony_ci	.vidioc_default                 = cx18_default,
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
103562306a36Sopenharmony_ci	.vidioc_querybuf		= vb2_ioctl_querybuf,
103662306a36Sopenharmony_ci	.vidioc_qbuf			= vb2_ioctl_qbuf,
103762306a36Sopenharmony_ci	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
103862306a36Sopenharmony_ci	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
103962306a36Sopenharmony_ci	.vidioc_streamon		= vb2_ioctl_streamon,
104062306a36Sopenharmony_ci	.vidioc_streamoff		= vb2_ioctl_streamoff,
104162306a36Sopenharmony_ci	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
104262306a36Sopenharmony_ci	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
104362306a36Sopenharmony_ci	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
104462306a36Sopenharmony_ci};
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_civoid cx18_set_funcs(struct video_device *vdev)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci	vdev->ioctl_ops = &cx18_ioctl_ops;
104962306a36Sopenharmony_ci}
1050