1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /*
3b285192aSMauro Carvalho Chehab * cx18 ioctl system call
4b285192aSMauro Carvalho Chehab *
5b285192aSMauro Carvalho Chehab * Derived from ivtv-ioctl.c
6b285192aSMauro Carvalho Chehab *
7b285192aSMauro Carvalho Chehab * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
8b285192aSMauro Carvalho Chehab * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
9b285192aSMauro Carvalho Chehab */
10b285192aSMauro Carvalho Chehab
11b285192aSMauro Carvalho Chehab #include "cx18-driver.h"
12b285192aSMauro Carvalho Chehab #include "cx18-io.h"
13b285192aSMauro Carvalho Chehab #include "cx18-version.h"
14b285192aSMauro Carvalho Chehab #include "cx18-mailbox.h"
15b285192aSMauro Carvalho Chehab #include "cx18-i2c.h"
16b285192aSMauro Carvalho Chehab #include "cx18-queue.h"
17b285192aSMauro Carvalho Chehab #include "cx18-fileops.h"
18b285192aSMauro Carvalho Chehab #include "cx18-vbi.h"
19b285192aSMauro Carvalho Chehab #include "cx18-audio.h"
20b285192aSMauro Carvalho Chehab #include "cx18-video.h"
21b285192aSMauro Carvalho Chehab #include "cx18-streams.h"
22b285192aSMauro Carvalho Chehab #include "cx18-ioctl.h"
23b285192aSMauro Carvalho Chehab #include "cx18-gpio.h"
24b285192aSMauro Carvalho Chehab #include "cx18-controls.h"
25b285192aSMauro Carvalho Chehab #include "cx18-cards.h"
26b285192aSMauro Carvalho Chehab #include "cx18-av-core.h"
27b285192aSMauro Carvalho Chehab #include <media/tveeprom.h>
28eaa80c44SHans Verkuil #include <media/v4l2-event.h>
29b285192aSMauro Carvalho Chehab
30651640f6SHans Verkuil static const struct v4l2_fmtdesc cx18_formats_yuv[] = {
31651640f6SHans Verkuil {
32651640f6SHans Verkuil .index = 0,
33651640f6SHans Verkuil .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
34651640f6SHans Verkuil .pixelformat = V4L2_PIX_FMT_NV12_16L16,
35651640f6SHans Verkuil },
36651640f6SHans Verkuil {
37651640f6SHans Verkuil .index = 1,
38651640f6SHans Verkuil .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
39651640f6SHans Verkuil .pixelformat = V4L2_PIX_FMT_UYVY,
40651640f6SHans Verkuil },
41651640f6SHans Verkuil };
42651640f6SHans Verkuil
43651640f6SHans Verkuil static const struct v4l2_fmtdesc cx18_formats_mpeg[] = {
44651640f6SHans Verkuil {
45651640f6SHans Verkuil .index = 0,
46651640f6SHans Verkuil .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
47651640f6SHans Verkuil .flags = V4L2_FMT_FLAG_COMPRESSED,
48651640f6SHans Verkuil .pixelformat = V4L2_PIX_FMT_MPEG,
49651640f6SHans Verkuil },
50651640f6SHans Verkuil };
51651640f6SHans Verkuil
cx18_g_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * fmt)5200d08584SHans Verkuil static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
5300d08584SHans Verkuil struct v4l2_format *fmt)
5400d08584SHans Verkuil {
5500d08584SHans Verkuil struct cx18_open_id *id = fh2id(fh);
5600d08584SHans Verkuil struct cx18 *cx = id->cx;
5700d08584SHans Verkuil struct cx18_stream *s = &cx->streams[id->type];
5800d08584SHans Verkuil struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
5900d08584SHans Verkuil
6000d08584SHans Verkuil pixfmt->width = cx->cxhdl.width;
6100d08584SHans Verkuil pixfmt->height = cx->cxhdl.height;
6200d08584SHans Verkuil pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
6300d08584SHans Verkuil pixfmt->field = V4L2_FIELD_INTERLACED;
6400d08584SHans Verkuil if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
6500d08584SHans Verkuil pixfmt->pixelformat = s->pixelformat;
6600d08584SHans Verkuil pixfmt->sizeimage = s->vb_bytes_per_frame;
6700d08584SHans Verkuil pixfmt->bytesperline = s->vb_bytes_per_line;
6800d08584SHans Verkuil } else {
6900d08584SHans Verkuil pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
7000d08584SHans Verkuil pixfmt->sizeimage = 128 * 1024;
7100d08584SHans Verkuil pixfmt->bytesperline = 0;
7200d08584SHans Verkuil }
7300d08584SHans Verkuil return 0;
7400d08584SHans Verkuil }
7500d08584SHans Verkuil
cx18_try_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * fmt)7600d08584SHans Verkuil static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
7700d08584SHans Verkuil struct v4l2_format *fmt)
7800d08584SHans Verkuil {
7900d08584SHans Verkuil struct cx18_open_id *id = fh2id(fh);
8000d08584SHans Verkuil struct cx18 *cx = id->cx;
81*13de5a51SHans Verkuil struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
82*13de5a51SHans Verkuil int w = pixfmt->width;
83*13de5a51SHans Verkuil int h = pixfmt->height;
8400d08584SHans Verkuil
8500d08584SHans Verkuil w = min(w, 720);
86*13de5a51SHans Verkuil w = max(w, 720 / 16);
8700d08584SHans Verkuil
8800d08584SHans Verkuil h = min(h, cx->is_50hz ? 576 : 480);
89*13de5a51SHans Verkuil h = max(h, (cx->is_50hz ? 576 : 480) / 8);
9000d08584SHans Verkuil
91*13de5a51SHans Verkuil if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
92*13de5a51SHans Verkuil if (pixfmt->pixelformat != V4L2_PIX_FMT_NV12_16L16 &&
93*13de5a51SHans Verkuil pixfmt->pixelformat != V4L2_PIX_FMT_UYVY)
94*13de5a51SHans Verkuil pixfmt->pixelformat = V4L2_PIX_FMT_UYVY;
95*13de5a51SHans Verkuil /* YUV height must be a multiple of 32 */
96*13de5a51SHans Verkuil h = round_up(h, 32);
97*13de5a51SHans Verkuil /*
98*13de5a51SHans Verkuil * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
99*13de5a51SHans Verkuil * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
100*13de5a51SHans Verkuil */
101*13de5a51SHans Verkuil if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12_16L16) {
102*13de5a51SHans Verkuil pixfmt->sizeimage = h * 720 * 3 / 2;
103*13de5a51SHans Verkuil pixfmt->bytesperline = 720; /* First plane */
104*13de5a51SHans Verkuil } else {
105*13de5a51SHans Verkuil pixfmt->sizeimage = h * 720 * 2;
106*13de5a51SHans Verkuil pixfmt->bytesperline = 1440; /* Packed */
107*13de5a51SHans Verkuil }
108*13de5a51SHans Verkuil } else {
109*13de5a51SHans Verkuil pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
110*13de5a51SHans Verkuil pixfmt->sizeimage = 128 * 1024;
111*13de5a51SHans Verkuil pixfmt->bytesperline = 0;
112*13de5a51SHans Verkuil }
113*13de5a51SHans Verkuil
114*13de5a51SHans Verkuil pixfmt->width = w;
115*13de5a51SHans Verkuil pixfmt->height = h;
116*13de5a51SHans Verkuil pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
117*13de5a51SHans Verkuil pixfmt->field = V4L2_FIELD_INTERLACED;
11800d08584SHans Verkuil return 0;
11900d08584SHans Verkuil }
12000d08584SHans Verkuil
cx18_s_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * fmt)12100d08584SHans Verkuil static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
12200d08584SHans Verkuil struct v4l2_format *fmt)
12300d08584SHans Verkuil {
12400d08584SHans Verkuil struct cx18_open_id *id = fh2id(fh);
12500d08584SHans Verkuil struct cx18 *cx = id->cx;
12600d08584SHans Verkuil struct v4l2_subdev_format format = {
12700d08584SHans Verkuil .which = V4L2_SUBDEV_FORMAT_ACTIVE,
12800d08584SHans Verkuil };
12900d08584SHans Verkuil struct cx18_stream *s = &cx->streams[id->type];
13000d08584SHans Verkuil int ret;
13100d08584SHans Verkuil int w, h;
13200d08584SHans Verkuil
13300d08584SHans Verkuil ret = cx18_try_fmt_vid_cap(file, fh, fmt);
13400d08584SHans Verkuil if (ret)
13500d08584SHans Verkuil return ret;
13600d08584SHans Verkuil w = fmt->fmt.pix.width;
13700d08584SHans Verkuil h = fmt->fmt.pix.height;
13800d08584SHans Verkuil
13900d08584SHans Verkuil if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
14000d08584SHans Verkuil s->pixelformat == fmt->fmt.pix.pixelformat)
14100d08584SHans Verkuil return 0;
14200d08584SHans Verkuil
14300d08584SHans Verkuil if (atomic_read(&cx->ana_capturing) > 0)
14400d08584SHans Verkuil return -EBUSY;
14500d08584SHans Verkuil
14600d08584SHans Verkuil s->pixelformat = fmt->fmt.pix.pixelformat;
147*13de5a51SHans Verkuil s->vb_bytes_per_frame = fmt->fmt.pix.sizeimage;
148*13de5a51SHans Verkuil s->vb_bytes_per_line = fmt->fmt.pix.bytesperline;
14900d08584SHans Verkuil
15000d08584SHans Verkuil format.format.width = cx->cxhdl.width = w;
15100d08584SHans Verkuil format.format.height = cx->cxhdl.height = h;
15200d08584SHans Verkuil format.format.code = MEDIA_BUS_FMT_FIXED;
15300d08584SHans Verkuil v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format);
15400d08584SHans Verkuil return cx18_g_fmt_vid_cap(file, fh, fmt);
15500d08584SHans Verkuil }
15600d08584SHans Verkuil
cx18_service2vbi(int type)157b285192aSMauro Carvalho Chehab u16 cx18_service2vbi(int type)
158b285192aSMauro Carvalho Chehab {
159b285192aSMauro Carvalho Chehab switch (type) {
160b285192aSMauro Carvalho Chehab case V4L2_SLICED_TELETEXT_B:
161b285192aSMauro Carvalho Chehab return CX18_SLICED_TYPE_TELETEXT_B;
162b285192aSMauro Carvalho Chehab case V4L2_SLICED_CAPTION_525:
163b285192aSMauro Carvalho Chehab return CX18_SLICED_TYPE_CAPTION_525;
164b285192aSMauro Carvalho Chehab case V4L2_SLICED_WSS_625:
165b285192aSMauro Carvalho Chehab return CX18_SLICED_TYPE_WSS_625;
166b285192aSMauro Carvalho Chehab case V4L2_SLICED_VPS:
167b285192aSMauro Carvalho Chehab return CX18_SLICED_TYPE_VPS;
168b285192aSMauro Carvalho Chehab default:
169b285192aSMauro Carvalho Chehab return 0;
170b285192aSMauro Carvalho Chehab }
171b285192aSMauro Carvalho Chehab }
172b285192aSMauro Carvalho Chehab
173b285192aSMauro Carvalho Chehab /* Check if VBI services are allowed on the (field, line) for the video std */
valid_service_line(int field,int line,int is_pal)174b285192aSMauro Carvalho Chehab static int valid_service_line(int field, int line, int is_pal)
175b285192aSMauro Carvalho Chehab {
176b285192aSMauro Carvalho Chehab return (is_pal && line >= 6 &&
177b285192aSMauro Carvalho Chehab ((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
178b285192aSMauro Carvalho Chehab (!is_pal && line >= 10 && line < 22);
179b285192aSMauro Carvalho Chehab }
180b285192aSMauro Carvalho Chehab
181b285192aSMauro Carvalho Chehab /*
182b285192aSMauro Carvalho Chehab * For a (field, line, std) and inbound potential set of services for that line,
183b285192aSMauro Carvalho Chehab * return the first valid service of those passed in the incoming set for that
184b285192aSMauro Carvalho Chehab * line in priority order:
185b285192aSMauro Carvalho Chehab * CC, VPS, or WSS over TELETEXT for well known lines
186b285192aSMauro Carvalho Chehab * TELETEXT, before VPS, before CC, before WSS, for other lines
187b285192aSMauro Carvalho Chehab */
select_service_from_set(int field,int line,u16 set,int is_pal)188b285192aSMauro Carvalho Chehab static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
189b285192aSMauro Carvalho Chehab {
190b285192aSMauro Carvalho Chehab u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
191b285192aSMauro Carvalho Chehab int i;
192b285192aSMauro Carvalho Chehab
193b285192aSMauro Carvalho Chehab set = set & valid_set;
194b285192aSMauro Carvalho Chehab if (set == 0 || !valid_service_line(field, line, is_pal))
195b285192aSMauro Carvalho Chehab return 0;
196b285192aSMauro Carvalho Chehab if (!is_pal) {
197b285192aSMauro Carvalho Chehab if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
198b285192aSMauro Carvalho Chehab return V4L2_SLICED_CAPTION_525;
199b285192aSMauro Carvalho Chehab } else {
200b285192aSMauro Carvalho Chehab if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
201b285192aSMauro Carvalho Chehab return V4L2_SLICED_VPS;
202b285192aSMauro Carvalho Chehab if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
203b285192aSMauro Carvalho Chehab return V4L2_SLICED_WSS_625;
204b285192aSMauro Carvalho Chehab if (line == 23)
205b285192aSMauro Carvalho Chehab return 0;
206b285192aSMauro Carvalho Chehab }
207b285192aSMauro Carvalho Chehab for (i = 0; i < 32; i++) {
20895c52069SMauro Carvalho Chehab if (BIT(i) & set)
209b285192aSMauro Carvalho Chehab return 1 << i;
210b285192aSMauro Carvalho Chehab }
211b285192aSMauro Carvalho Chehab return 0;
212b285192aSMauro Carvalho Chehab }
213b285192aSMauro Carvalho Chehab
214b285192aSMauro Carvalho Chehab /*
215b285192aSMauro Carvalho Chehab * Expand the service_set of *fmt into valid service_lines for the std,
216b285192aSMauro Carvalho Chehab * and clear the passed in fmt->service_set
217b285192aSMauro Carvalho Chehab */
cx18_expand_service_set(struct v4l2_sliced_vbi_format * fmt,int is_pal)218b285192aSMauro Carvalho Chehab void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
219b285192aSMauro Carvalho Chehab {
220b285192aSMauro Carvalho Chehab u16 set = fmt->service_set;
221b285192aSMauro Carvalho Chehab int f, l;
222b285192aSMauro Carvalho Chehab
223b285192aSMauro Carvalho Chehab fmt->service_set = 0;
224b285192aSMauro Carvalho Chehab for (f = 0; f < 2; f++) {
225b285192aSMauro Carvalho Chehab for (l = 0; l < 24; l++)
226b285192aSMauro Carvalho Chehab fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
227b285192aSMauro Carvalho Chehab }
228b285192aSMauro Carvalho Chehab }
229b285192aSMauro Carvalho Chehab
230b285192aSMauro Carvalho Chehab /*
231b285192aSMauro Carvalho Chehab * Sanitize the service_lines in *fmt per the video std, and return 1
232b285192aSMauro Carvalho Chehab * if any service_line is left as valid after santization
233b285192aSMauro Carvalho Chehab */
check_service_set(struct v4l2_sliced_vbi_format * fmt,int is_pal)234b285192aSMauro Carvalho Chehab static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
235b285192aSMauro Carvalho Chehab {
236b285192aSMauro Carvalho Chehab int f, l;
237b285192aSMauro Carvalho Chehab u16 set = 0;
238b285192aSMauro Carvalho Chehab
239b285192aSMauro Carvalho Chehab for (f = 0; f < 2; f++) {
240b285192aSMauro Carvalho Chehab for (l = 0; l < 24; l++) {
241b285192aSMauro Carvalho Chehab fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
242b285192aSMauro Carvalho Chehab set |= fmt->service_lines[f][l];
243b285192aSMauro Carvalho Chehab }
244b285192aSMauro Carvalho Chehab }
245b285192aSMauro Carvalho Chehab return set != 0;
246b285192aSMauro Carvalho Chehab }
247b285192aSMauro Carvalho Chehab
248b285192aSMauro Carvalho Chehab /* Compute the service_set from the assumed valid service_lines of *fmt */
cx18_get_service_set(struct v4l2_sliced_vbi_format * fmt)249b285192aSMauro Carvalho Chehab u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
250b285192aSMauro Carvalho Chehab {
251b285192aSMauro Carvalho Chehab int f, l;
252b285192aSMauro Carvalho Chehab u16 set = 0;
253b285192aSMauro Carvalho Chehab
254b285192aSMauro Carvalho Chehab for (f = 0; f < 2; f++) {
255b285192aSMauro Carvalho Chehab for (l = 0; l < 24; l++)
256b285192aSMauro Carvalho Chehab set |= fmt->service_lines[f][l];
257b285192aSMauro Carvalho Chehab }
258b285192aSMauro Carvalho Chehab return set;
259b285192aSMauro Carvalho Chehab }
260b285192aSMauro Carvalho Chehab
cx18_g_fmt_vbi_cap(struct file * file,void * fh,struct v4l2_format * fmt)261b285192aSMauro Carvalho Chehab static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
262b285192aSMauro Carvalho Chehab struct v4l2_format *fmt)
263b285192aSMauro Carvalho Chehab {
264b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
265b285192aSMauro Carvalho Chehab struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
266b285192aSMauro Carvalho Chehab
267b285192aSMauro Carvalho Chehab vbifmt->sampling_rate = 27000000;
268b285192aSMauro Carvalho Chehab vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
269318de791SMauro Carvalho Chehab vbifmt->samples_per_line = VBI_ACTIVE_SAMPLES - 4;
270b285192aSMauro Carvalho Chehab vbifmt->sample_format = V4L2_PIX_FMT_GREY;
271b285192aSMauro Carvalho Chehab vbifmt->start[0] = cx->vbi.start[0];
272b285192aSMauro Carvalho Chehab vbifmt->start[1] = cx->vbi.start[1];
273b285192aSMauro Carvalho Chehab vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
274b285192aSMauro Carvalho Chehab vbifmt->flags = 0;
275b285192aSMauro Carvalho Chehab vbifmt->reserved[0] = 0;
276b285192aSMauro Carvalho Chehab vbifmt->reserved[1] = 0;
277b285192aSMauro Carvalho Chehab return 0;
278b285192aSMauro Carvalho Chehab }
279b285192aSMauro Carvalho Chehab
cx18_g_fmt_sliced_vbi_cap(struct file * file,void * fh,struct v4l2_format * fmt)280b285192aSMauro Carvalho Chehab static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
281b285192aSMauro Carvalho Chehab struct v4l2_format *fmt)
282b285192aSMauro Carvalho Chehab {
283b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
284b285192aSMauro Carvalho Chehab struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
285b285192aSMauro Carvalho Chehab
286b285192aSMauro Carvalho Chehab /* sane, V4L2 spec compliant, defaults */
287b285192aSMauro Carvalho Chehab vbifmt->reserved[0] = 0;
288b285192aSMauro Carvalho Chehab vbifmt->reserved[1] = 0;
289b285192aSMauro Carvalho Chehab vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
290b285192aSMauro Carvalho Chehab memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
291b285192aSMauro Carvalho Chehab vbifmt->service_set = 0;
292b285192aSMauro Carvalho Chehab
293b285192aSMauro Carvalho Chehab /*
294b285192aSMauro Carvalho Chehab * Fetch the configured service_lines and total service_set from the
295b285192aSMauro Carvalho Chehab * digitizer/slicer. Note, cx18_av_vbi() wipes the passed in
296b285192aSMauro Carvalho Chehab * fmt->fmt.sliced under valid calling conditions
297b285192aSMauro Carvalho Chehab */
298b285192aSMauro Carvalho Chehab if (v4l2_subdev_call(cx->sd_av, vbi, g_sliced_fmt, &fmt->fmt.sliced))
299b285192aSMauro Carvalho Chehab return -EINVAL;
300b285192aSMauro Carvalho Chehab
301b285192aSMauro Carvalho Chehab vbifmt->service_set = cx18_get_service_set(vbifmt);
302b285192aSMauro Carvalho Chehab return 0;
303b285192aSMauro Carvalho Chehab }
304b285192aSMauro Carvalho Chehab
cx18_try_fmt_vbi_cap(struct file * file,void * fh,struct v4l2_format * fmt)305b285192aSMauro Carvalho Chehab static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
306b285192aSMauro Carvalho Chehab struct v4l2_format *fmt)
307b285192aSMauro Carvalho Chehab {
308b285192aSMauro Carvalho Chehab return cx18_g_fmt_vbi_cap(file, fh, fmt);
309b285192aSMauro Carvalho Chehab }
310b285192aSMauro Carvalho Chehab
cx18_try_fmt_sliced_vbi_cap(struct file * file,void * fh,struct v4l2_format * fmt)311b285192aSMauro Carvalho Chehab static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
312b285192aSMauro Carvalho Chehab struct v4l2_format *fmt)
313b285192aSMauro Carvalho Chehab {
314b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
315b285192aSMauro Carvalho Chehab struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
316b285192aSMauro Carvalho Chehab
317b285192aSMauro Carvalho Chehab vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
318b285192aSMauro Carvalho Chehab vbifmt->reserved[0] = 0;
319b285192aSMauro Carvalho Chehab vbifmt->reserved[1] = 0;
320b285192aSMauro Carvalho Chehab
321b285192aSMauro Carvalho Chehab /* If given a service set, expand it validly & clear passed in set */
322b285192aSMauro Carvalho Chehab if (vbifmt->service_set)
323b285192aSMauro Carvalho Chehab cx18_expand_service_set(vbifmt, cx->is_50hz);
324b285192aSMauro Carvalho Chehab /* Sanitize the service_lines, and compute the new set if any valid */
325b285192aSMauro Carvalho Chehab if (check_service_set(vbifmt, cx->is_50hz))
326b285192aSMauro Carvalho Chehab vbifmt->service_set = cx18_get_service_set(vbifmt);
327b285192aSMauro Carvalho Chehab return 0;
328b285192aSMauro Carvalho Chehab }
329b285192aSMauro Carvalho Chehab
cx18_s_fmt_vbi_cap(struct file * file,void * fh,struct v4l2_format * fmt)330b285192aSMauro Carvalho Chehab static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
331b285192aSMauro Carvalho Chehab struct v4l2_format *fmt)
332b285192aSMauro Carvalho Chehab {
333b285192aSMauro Carvalho Chehab struct cx18_open_id *id = fh2id(fh);
334b285192aSMauro Carvalho Chehab struct cx18 *cx = id->cx;
335b285192aSMauro Carvalho Chehab int ret;
336b285192aSMauro Carvalho Chehab
337b285192aSMauro Carvalho Chehab /*
338b285192aSMauro Carvalho Chehab * Changing the Encoder's Raw VBI parameters won't have any effect
339b285192aSMauro Carvalho Chehab * if any analog capture is ongoing
340b285192aSMauro Carvalho Chehab */
341b285192aSMauro Carvalho Chehab if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
342b285192aSMauro Carvalho Chehab return -EBUSY;
343b285192aSMauro Carvalho Chehab
344b285192aSMauro Carvalho Chehab /*
345b285192aSMauro Carvalho Chehab * Set the digitizer registers for raw active VBI.
346b285192aSMauro Carvalho Chehab * Note cx18_av_vbi_wipes out a lot of the passed in fmt under valid
347b285192aSMauro Carvalho Chehab * calling conditions
348b285192aSMauro Carvalho Chehab */
349b285192aSMauro Carvalho Chehab ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi);
350b285192aSMauro Carvalho Chehab if (ret)
351b285192aSMauro Carvalho Chehab return ret;
352b285192aSMauro Carvalho Chehab
353b285192aSMauro Carvalho Chehab /* Store our new v4l2 (non-)sliced VBI state */
354b285192aSMauro Carvalho Chehab cx->vbi.sliced_in->service_set = 0;
355b285192aSMauro Carvalho Chehab cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
356b285192aSMauro Carvalho Chehab
357b285192aSMauro Carvalho Chehab return cx18_g_fmt_vbi_cap(file, fh, fmt);
358b285192aSMauro Carvalho Chehab }
359b285192aSMauro Carvalho Chehab
cx18_s_fmt_sliced_vbi_cap(struct file * file,void * fh,struct v4l2_format * fmt)360b285192aSMauro Carvalho Chehab static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
361b285192aSMauro Carvalho Chehab struct v4l2_format *fmt)
362b285192aSMauro Carvalho Chehab {
363b285192aSMauro Carvalho Chehab struct cx18_open_id *id = fh2id(fh);
364b285192aSMauro Carvalho Chehab struct cx18 *cx = id->cx;
365b285192aSMauro Carvalho Chehab int ret;
366b285192aSMauro Carvalho Chehab struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
367b285192aSMauro Carvalho Chehab
368b285192aSMauro Carvalho Chehab cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
369b285192aSMauro Carvalho Chehab
370b285192aSMauro Carvalho Chehab /*
371b285192aSMauro Carvalho Chehab * Changing the Encoder's Raw VBI parameters won't have any effect
372b285192aSMauro Carvalho Chehab * if any analog capture is ongoing
373b285192aSMauro Carvalho Chehab */
374b285192aSMauro Carvalho Chehab if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
375b285192aSMauro Carvalho Chehab return -EBUSY;
376b285192aSMauro Carvalho Chehab
377b285192aSMauro Carvalho Chehab /*
378b285192aSMauro Carvalho Chehab * Set the service_lines requested in the digitizer/slicer registers.
379b285192aSMauro Carvalho Chehab * Note, cx18_av_vbi() wipes some "impossible" service lines in the
380b285192aSMauro Carvalho Chehab * passed in fmt->fmt.sliced under valid calling conditions
381b285192aSMauro Carvalho Chehab */
382b285192aSMauro Carvalho Chehab ret = v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &fmt->fmt.sliced);
383b285192aSMauro Carvalho Chehab if (ret)
384b285192aSMauro Carvalho Chehab return ret;
385b285192aSMauro Carvalho Chehab /* Store our current v4l2 sliced VBI settings */
386b285192aSMauro Carvalho Chehab cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
387b285192aSMauro Carvalho Chehab memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
388b285192aSMauro Carvalho Chehab return 0;
389b285192aSMauro Carvalho Chehab }
390b285192aSMauro Carvalho Chehab
391b285192aSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
cx18_g_register(struct file * file,void * fh,struct v4l2_dbg_register * reg)392b285192aSMauro Carvalho Chehab static int cx18_g_register(struct file *file, void *fh,
393b285192aSMauro Carvalho Chehab struct v4l2_dbg_register *reg)
394b285192aSMauro Carvalho Chehab {
395b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
396b285192aSMauro Carvalho Chehab
397771d7733SHans Verkuil if (reg->reg & 0x3)
398771d7733SHans Verkuil return -EINVAL;
399977ba3b1SHans Verkuil if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
400977ba3b1SHans Verkuil return -EINVAL;
401977ba3b1SHans Verkuil reg->size = 4;
402977ba3b1SHans Verkuil reg->val = cx18_read_enc(cx, reg->reg);
403977ba3b1SHans Verkuil return 0;
404977ba3b1SHans Verkuil }
405b285192aSMauro Carvalho Chehab
cx18_s_register(struct file * file,void * fh,const struct v4l2_dbg_register * reg)406b285192aSMauro Carvalho Chehab static int cx18_s_register(struct file *file, void *fh,
407977ba3b1SHans Verkuil const struct v4l2_dbg_register *reg)
408b285192aSMauro Carvalho Chehab {
409b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
410b285192aSMauro Carvalho Chehab
411771d7733SHans Verkuil if (reg->reg & 0x3)
412771d7733SHans Verkuil return -EINVAL;
413977ba3b1SHans Verkuil if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
414977ba3b1SHans Verkuil return -EINVAL;
415977ba3b1SHans Verkuil cx18_write_enc(cx, reg->val, reg->reg);
416977ba3b1SHans Verkuil return 0;
417977ba3b1SHans Verkuil }
418b285192aSMauro Carvalho Chehab #endif
419b285192aSMauro Carvalho Chehab
cx18_querycap(struct file * file,void * fh,struct v4l2_capability * vcap)420b285192aSMauro Carvalho Chehab static int cx18_querycap(struct file *file, void *fh,
421b285192aSMauro Carvalho Chehab struct v4l2_capability *vcap)
422b285192aSMauro Carvalho Chehab {
423b285192aSMauro Carvalho Chehab struct cx18_open_id *id = fh2id(fh);
424b285192aSMauro Carvalho Chehab struct cx18 *cx = id->cx;
425b285192aSMauro Carvalho Chehab
426c0decac1SMauro Carvalho Chehab strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
427c0decac1SMauro Carvalho Chehab strscpy(vcap->card, cx->card_name, sizeof(vcap->card));
42821615365SHans Verkuil vcap->capabilities = cx->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
429b285192aSMauro Carvalho Chehab return 0;
430b285192aSMauro Carvalho Chehab }
431b285192aSMauro Carvalho Chehab
cx18_enumaudio(struct file * file,void * fh,struct v4l2_audio * vin)432b285192aSMauro Carvalho Chehab static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
433b285192aSMauro Carvalho Chehab {
434b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
435b285192aSMauro Carvalho Chehab
436b285192aSMauro Carvalho Chehab return cx18_get_audio_input(cx, vin->index, vin);
437b285192aSMauro Carvalho Chehab }
438b285192aSMauro Carvalho Chehab
cx18_g_audio(struct file * file,void * fh,struct v4l2_audio * vin)439b285192aSMauro Carvalho Chehab static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
440b285192aSMauro Carvalho Chehab {
441b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
442b285192aSMauro Carvalho Chehab
443b285192aSMauro Carvalho Chehab vin->index = cx->audio_input;
444b285192aSMauro Carvalho Chehab return cx18_get_audio_input(cx, vin->index, vin);
445b285192aSMauro Carvalho Chehab }
446b285192aSMauro Carvalho Chehab
cx18_s_audio(struct file * file,void * fh,const struct v4l2_audio * vout)4470e8025b9SHans Verkuil static int cx18_s_audio(struct file *file, void *fh, const struct v4l2_audio *vout)
448b285192aSMauro Carvalho Chehab {
449b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
450b285192aSMauro Carvalho Chehab
451b285192aSMauro Carvalho Chehab if (vout->index >= cx->nof_audio_inputs)
452b285192aSMauro Carvalho Chehab return -EINVAL;
453b285192aSMauro Carvalho Chehab cx->audio_input = vout->index;
454b285192aSMauro Carvalho Chehab cx18_audio_set_io(cx);
455b285192aSMauro Carvalho Chehab return 0;
456b285192aSMauro Carvalho Chehab }
457b285192aSMauro Carvalho Chehab
cx18_enum_input(struct file * file,void * fh,struct v4l2_input * vin)458b285192aSMauro Carvalho Chehab static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
459b285192aSMauro Carvalho Chehab {
460b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
461b285192aSMauro Carvalho Chehab
462b285192aSMauro Carvalho Chehab /* set it to defaults from our table */
463b285192aSMauro Carvalho Chehab return cx18_get_input(cx, vin->index, vin);
464b285192aSMauro Carvalho Chehab }
465b285192aSMauro Carvalho Chehab
cx18_g_pixelaspect(struct file * file,void * fh,int type,struct v4l2_fract * f)4665200ab6aSHans Verkuil static int cx18_g_pixelaspect(struct file *file, void *fh,
4675200ab6aSHans Verkuil int type, struct v4l2_fract *f)
468b285192aSMauro Carvalho Chehab {
469b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
470b285192aSMauro Carvalho Chehab
4715200ab6aSHans Verkuil if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
472b285192aSMauro Carvalho Chehab return -EINVAL;
4735200ab6aSHans Verkuil
4745200ab6aSHans Verkuil f->numerator = cx->is_50hz ? 54 : 11;
4755200ab6aSHans Verkuil f->denominator = cx->is_50hz ? 59 : 10;
476b285192aSMauro Carvalho Chehab return 0;
477b285192aSMauro Carvalho Chehab }
478b285192aSMauro Carvalho Chehab
cx18_g_selection(struct file * file,void * fh,struct v4l2_selection * sel)47955cda4abSHans Verkuil static int cx18_g_selection(struct file *file, void *fh,
48055cda4abSHans Verkuil struct v4l2_selection *sel)
481b285192aSMauro Carvalho Chehab {
482b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
483b285192aSMauro Carvalho Chehab
48455cda4abSHans Verkuil if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
485b285192aSMauro Carvalho Chehab return -EINVAL;
48655cda4abSHans Verkuil switch (sel->target) {
48755cda4abSHans Verkuil case V4L2_SEL_TGT_CROP_BOUNDS:
48855cda4abSHans Verkuil case V4L2_SEL_TGT_CROP_DEFAULT:
48955cda4abSHans Verkuil sel->r.top = sel->r.left = 0;
49055cda4abSHans Verkuil sel->r.width = 720;
49155cda4abSHans Verkuil sel->r.height = cx->is_50hz ? 576 : 480;
49255cda4abSHans Verkuil break;
49355cda4abSHans Verkuil default:
494b285192aSMauro Carvalho Chehab return -EINVAL;
495b285192aSMauro Carvalho Chehab }
49655cda4abSHans Verkuil return 0;
49755cda4abSHans Verkuil }
498b285192aSMauro Carvalho Chehab
cx18_enum_fmt_vid_cap(struct file * file,void * fh,struct v4l2_fmtdesc * fmt)499b285192aSMauro Carvalho Chehab static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
500b285192aSMauro Carvalho Chehab struct v4l2_fmtdesc *fmt)
501b285192aSMauro Carvalho Chehab {
502651640f6SHans Verkuil struct cx18_open_id *id = fh2id(fh);
503b285192aSMauro Carvalho Chehab
504651640f6SHans Verkuil if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
505651640f6SHans Verkuil if (fmt->index >= ARRAY_SIZE(cx18_formats_yuv))
506b285192aSMauro Carvalho Chehab return -EINVAL;
507651640f6SHans Verkuil *fmt = cx18_formats_yuv[fmt->index];
508651640f6SHans Verkuil return 0;
509651640f6SHans Verkuil }
510651640f6SHans Verkuil if (fmt->index)
511651640f6SHans Verkuil return -EINVAL;
512651640f6SHans Verkuil *fmt = cx18_formats_mpeg[0];
513b285192aSMauro Carvalho Chehab return 0;
514b285192aSMauro Carvalho Chehab }
515b285192aSMauro Carvalho Chehab
cx18_g_input(struct file * file,void * fh,unsigned int * i)516b285192aSMauro Carvalho Chehab static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
517b285192aSMauro Carvalho Chehab {
518b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
519b285192aSMauro Carvalho Chehab
520b285192aSMauro Carvalho Chehab *i = cx->active_input;
521b285192aSMauro Carvalho Chehab return 0;
522b285192aSMauro Carvalho Chehab }
523b285192aSMauro Carvalho Chehab
cx18_s_input(struct file * file,void * fh,unsigned int inp)524b285192aSMauro Carvalho Chehab int cx18_s_input(struct file *file, void *fh, unsigned int inp)
525b285192aSMauro Carvalho Chehab {
526b285192aSMauro Carvalho Chehab struct cx18_open_id *id = fh2id(fh);
527b285192aSMauro Carvalho Chehab struct cx18 *cx = id->cx;
5283a29a4f1SHans Verkuil v4l2_std_id std = V4L2_STD_ALL;
5293a29a4f1SHans Verkuil const struct cx18_card_video_input *card_input =
5303a29a4f1SHans Verkuil cx->card->video_inputs + inp;
531b285192aSMauro Carvalho Chehab
532b285192aSMauro Carvalho Chehab if (inp >= cx->nof_inputs)
533b285192aSMauro Carvalho Chehab return -EINVAL;
534b285192aSMauro Carvalho Chehab
535b285192aSMauro Carvalho Chehab if (inp == cx->active_input) {
536b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Input unchanged\n");
537b285192aSMauro Carvalho Chehab return 0;
538b285192aSMauro Carvalho Chehab }
539b285192aSMauro Carvalho Chehab
540b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Changing input from %d to %d\n",
541b285192aSMauro Carvalho Chehab cx->active_input, inp);
542b285192aSMauro Carvalho Chehab
543b285192aSMauro Carvalho Chehab cx->active_input = inp;
544b285192aSMauro Carvalho Chehab /* Set the audio input to whatever is appropriate for the input type. */
545b285192aSMauro Carvalho Chehab cx->audio_input = cx->card->video_inputs[inp].audio_index;
5463a29a4f1SHans Verkuil if (card_input->video_type == V4L2_INPUT_TYPE_TUNER)
5473a29a4f1SHans Verkuil std = cx->tuner_std;
5483a29a4f1SHans Verkuil cx->streams[CX18_ENC_STREAM_TYPE_MPG].video_dev.tvnorms = std;
5493a29a4f1SHans Verkuil cx->streams[CX18_ENC_STREAM_TYPE_YUV].video_dev.tvnorms = std;
5503a29a4f1SHans Verkuil cx->streams[CX18_ENC_STREAM_TYPE_VBI].video_dev.tvnorms = std;
551b285192aSMauro Carvalho Chehab
552b285192aSMauro Carvalho Chehab /* prevent others from messing with the streams until
553b285192aSMauro Carvalho Chehab we're finished changing inputs. */
554b285192aSMauro Carvalho Chehab cx18_mute(cx);
555b285192aSMauro Carvalho Chehab cx18_video_set_io(cx);
556b285192aSMauro Carvalho Chehab cx18_audio_set_io(cx);
557b285192aSMauro Carvalho Chehab cx18_unmute(cx);
558b285192aSMauro Carvalho Chehab return 0;
559b285192aSMauro Carvalho Chehab }
560b285192aSMauro Carvalho Chehab
cx18_g_frequency(struct file * file,void * fh,struct v4l2_frequency * vf)561b285192aSMauro Carvalho Chehab static int cx18_g_frequency(struct file *file, void *fh,
562b285192aSMauro Carvalho Chehab struct v4l2_frequency *vf)
563b285192aSMauro Carvalho Chehab {
564b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
565b285192aSMauro Carvalho Chehab
566b285192aSMauro Carvalho Chehab if (vf->tuner != 0)
567b285192aSMauro Carvalho Chehab return -EINVAL;
568b285192aSMauro Carvalho Chehab
569b285192aSMauro Carvalho Chehab cx18_call_all(cx, tuner, g_frequency, vf);
570b285192aSMauro Carvalho Chehab return 0;
571b285192aSMauro Carvalho Chehab }
572b285192aSMauro Carvalho Chehab
cx18_s_frequency(struct file * file,void * fh,const struct v4l2_frequency * vf)573b530a447SHans Verkuil int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
574b285192aSMauro Carvalho Chehab {
575b285192aSMauro Carvalho Chehab struct cx18_open_id *id = fh2id(fh);
576b285192aSMauro Carvalho Chehab struct cx18 *cx = id->cx;
577b285192aSMauro Carvalho Chehab
578b285192aSMauro Carvalho Chehab if (vf->tuner != 0)
579b285192aSMauro Carvalho Chehab return -EINVAL;
580b285192aSMauro Carvalho Chehab
581b285192aSMauro Carvalho Chehab cx18_mute(cx);
582b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
583b285192aSMauro Carvalho Chehab cx18_call_all(cx, tuner, s_frequency, vf);
584b285192aSMauro Carvalho Chehab cx18_unmute(cx);
585b285192aSMauro Carvalho Chehab return 0;
586b285192aSMauro Carvalho Chehab }
587b285192aSMauro Carvalho Chehab
cx18_g_std(struct file * file,void * fh,v4l2_std_id * std)588b285192aSMauro Carvalho Chehab static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
589b285192aSMauro Carvalho Chehab {
590b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
591b285192aSMauro Carvalho Chehab
592b285192aSMauro Carvalho Chehab *std = cx->std;
593b285192aSMauro Carvalho Chehab return 0;
594b285192aSMauro Carvalho Chehab }
595b285192aSMauro Carvalho Chehab
cx18_s_std(struct file * file,void * fh,v4l2_std_id std)596314527acSHans Verkuil int cx18_s_std(struct file *file, void *fh, v4l2_std_id std)
597b285192aSMauro Carvalho Chehab {
598b285192aSMauro Carvalho Chehab struct cx18_open_id *id = fh2id(fh);
599b285192aSMauro Carvalho Chehab struct cx18 *cx = id->cx;
600b285192aSMauro Carvalho Chehab
601314527acSHans Verkuil if ((std & V4L2_STD_ALL) == 0)
602b285192aSMauro Carvalho Chehab return -EINVAL;
603b285192aSMauro Carvalho Chehab
604314527acSHans Verkuil if (std == cx->std)
605b285192aSMauro Carvalho Chehab return 0;
606b285192aSMauro Carvalho Chehab
607b285192aSMauro Carvalho Chehab if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
608b285192aSMauro Carvalho Chehab atomic_read(&cx->ana_capturing) > 0) {
609b285192aSMauro Carvalho Chehab /* Switching standard would turn off the radio or mess
610b285192aSMauro Carvalho Chehab with already running streams, prevent that by
611b285192aSMauro Carvalho Chehab returning EBUSY. */
612b285192aSMauro Carvalho Chehab return -EBUSY;
613b285192aSMauro Carvalho Chehab }
614b285192aSMauro Carvalho Chehab
615314527acSHans Verkuil cx->std = std;
616314527acSHans Verkuil cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
617b285192aSMauro Carvalho Chehab cx->is_50hz = !cx->is_60hz;
618b285192aSMauro Carvalho Chehab cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
619b285192aSMauro Carvalho Chehab cx->cxhdl.width = 720;
620b285192aSMauro Carvalho Chehab cx->cxhdl.height = cx->is_50hz ? 576 : 480;
621*13de5a51SHans Verkuil /*
622*13de5a51SHans Verkuil * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
623*13de5a51SHans Verkuil * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
624*13de5a51SHans Verkuil */
625*13de5a51SHans Verkuil if (cx->streams[CX18_ENC_STREAM_TYPE_YUV].pixelformat == V4L2_PIX_FMT_NV12_16L16) {
626*13de5a51SHans Verkuil cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_frame =
627*13de5a51SHans Verkuil cx->cxhdl.height * 720 * 3 / 2;
628*13de5a51SHans Verkuil cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_line = 720;
629*13de5a51SHans Verkuil } else {
630*13de5a51SHans Verkuil cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_frame =
631*13de5a51SHans Verkuil cx->cxhdl.height * 720 * 2;
632*13de5a51SHans Verkuil cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_line = 1440;
633*13de5a51SHans Verkuil }
634b285192aSMauro Carvalho Chehab cx->vbi.count = cx->is_50hz ? 18 : 12;
635b285192aSMauro Carvalho Chehab cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
636b285192aSMauro Carvalho Chehab cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
637b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Switching standard to %llx.\n",
638b285192aSMauro Carvalho Chehab (unsigned long long) cx->std);
639b285192aSMauro Carvalho Chehab
640b285192aSMauro Carvalho Chehab /* Tuner */
6418774bed9SLaurent Pinchart cx18_call_all(cx, video, s_std, cx->std);
642b285192aSMauro Carvalho Chehab return 0;
643b285192aSMauro Carvalho Chehab }
644b285192aSMauro Carvalho Chehab
cx18_s_tuner(struct file * file,void * fh,const struct v4l2_tuner * vt)6452f73c7c5SHans Verkuil static int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
646b285192aSMauro Carvalho Chehab {
647b285192aSMauro Carvalho Chehab struct cx18_open_id *id = fh2id(fh);
648b285192aSMauro Carvalho Chehab struct cx18 *cx = id->cx;
649b285192aSMauro Carvalho Chehab
650b285192aSMauro Carvalho Chehab if (vt->index != 0)
651b285192aSMauro Carvalho Chehab return -EINVAL;
652b285192aSMauro Carvalho Chehab
653b285192aSMauro Carvalho Chehab cx18_call_all(cx, tuner, s_tuner, vt);
654b285192aSMauro Carvalho Chehab return 0;
655b285192aSMauro Carvalho Chehab }
656b285192aSMauro Carvalho Chehab
cx18_g_tuner(struct file * file,void * fh,struct v4l2_tuner * vt)657b285192aSMauro Carvalho Chehab static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
658b285192aSMauro Carvalho Chehab {
659b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
660b285192aSMauro Carvalho Chehab
661b285192aSMauro Carvalho Chehab if (vt->index != 0)
662b285192aSMauro Carvalho Chehab return -EINVAL;
663b285192aSMauro Carvalho Chehab
664b285192aSMauro Carvalho Chehab cx18_call_all(cx, tuner, g_tuner, vt);
665b285192aSMauro Carvalho Chehab
666b285192aSMauro Carvalho Chehab if (vt->type == V4L2_TUNER_RADIO)
667c0decac1SMauro Carvalho Chehab strscpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
668b285192aSMauro Carvalho Chehab else
669c0decac1SMauro Carvalho Chehab strscpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
670b285192aSMauro Carvalho Chehab return 0;
671b285192aSMauro Carvalho Chehab }
672b285192aSMauro Carvalho Chehab
cx18_g_sliced_vbi_cap(struct file * file,void * fh,struct v4l2_sliced_vbi_cap * cap)673b285192aSMauro Carvalho Chehab static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
674b285192aSMauro Carvalho Chehab struct v4l2_sliced_vbi_cap *cap)
675b285192aSMauro Carvalho Chehab {
676b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
677b285192aSMauro Carvalho Chehab int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
678b285192aSMauro Carvalho Chehab int f, l;
679b285192aSMauro Carvalho Chehab
680b285192aSMauro Carvalho Chehab if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
681b285192aSMauro Carvalho Chehab return -EINVAL;
682b285192aSMauro Carvalho Chehab
683b285192aSMauro Carvalho Chehab cap->service_set = 0;
684b285192aSMauro Carvalho Chehab for (f = 0; f < 2; f++) {
685b285192aSMauro Carvalho Chehab for (l = 0; l < 24; l++) {
686b285192aSMauro Carvalho Chehab if (valid_service_line(f, l, cx->is_50hz)) {
687b285192aSMauro Carvalho Chehab /*
688b285192aSMauro Carvalho Chehab * We can find all v4l2 supported vbi services
689b285192aSMauro Carvalho Chehab * for the standard, on a valid line for the std
690b285192aSMauro Carvalho Chehab */
691b285192aSMauro Carvalho Chehab cap->service_lines[f][l] = set;
692b285192aSMauro Carvalho Chehab cap->service_set |= set;
693b285192aSMauro Carvalho Chehab } else
694b285192aSMauro Carvalho Chehab cap->service_lines[f][l] = 0;
695b285192aSMauro Carvalho Chehab }
696b285192aSMauro Carvalho Chehab }
697b285192aSMauro Carvalho Chehab for (f = 0; f < 3; f++)
698b285192aSMauro Carvalho Chehab cap->reserved[f] = 0;
699b285192aSMauro Carvalho Chehab return 0;
700b285192aSMauro Carvalho Chehab }
701b285192aSMauro Carvalho Chehab
_cx18_process_idx_data(struct cx18_buffer * buf,struct v4l2_enc_idx * idx)702b285192aSMauro Carvalho Chehab static int _cx18_process_idx_data(struct cx18_buffer *buf,
703b285192aSMauro Carvalho Chehab struct v4l2_enc_idx *idx)
704b285192aSMauro Carvalho Chehab {
705b285192aSMauro Carvalho Chehab int consumed, remaining;
706b285192aSMauro Carvalho Chehab struct v4l2_enc_idx_entry *e_idx;
707b285192aSMauro Carvalho Chehab struct cx18_enc_idx_entry *e_buf;
708b285192aSMauro Carvalho Chehab
709b285192aSMauro Carvalho Chehab /* Frame type lookup: 1=I, 2=P, 4=B */
71027dbc2e6SColin Ian King static const int mapping[8] = {
711b285192aSMauro Carvalho Chehab -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P,
712b285192aSMauro Carvalho Chehab -1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1
713b285192aSMauro Carvalho Chehab };
714b285192aSMauro Carvalho Chehab
715b285192aSMauro Carvalho Chehab /*
716b285192aSMauro Carvalho Chehab * Assumption here is that a buf holds an integral number of
717b285192aSMauro Carvalho Chehab * struct cx18_enc_idx_entry objects and is properly aligned.
718b285192aSMauro Carvalho Chehab * This is enforced by the module options on IDX buffer sizes.
719b285192aSMauro Carvalho Chehab */
720b285192aSMauro Carvalho Chehab remaining = buf->bytesused - buf->readpos;
721b285192aSMauro Carvalho Chehab consumed = 0;
722b285192aSMauro Carvalho Chehab e_idx = &idx->entry[idx->entries];
723b285192aSMauro Carvalho Chehab e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos];
724b285192aSMauro Carvalho Chehab
725b285192aSMauro Carvalho Chehab while (remaining >= sizeof(struct cx18_enc_idx_entry) &&
726b285192aSMauro Carvalho Chehab idx->entries < V4L2_ENC_IDX_ENTRIES) {
727b285192aSMauro Carvalho Chehab
728b285192aSMauro Carvalho Chehab e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32)
729b285192aSMauro Carvalho Chehab | le32_to_cpu(e_buf->offset_low);
730b285192aSMauro Carvalho Chehab
731b285192aSMauro Carvalho Chehab e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32)
732b285192aSMauro Carvalho Chehab | le32_to_cpu(e_buf->pts_low);
733b285192aSMauro Carvalho Chehab
734b285192aSMauro Carvalho Chehab e_idx->length = le32_to_cpu(e_buf->length);
735b285192aSMauro Carvalho Chehab
736b285192aSMauro Carvalho Chehab e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7];
737b285192aSMauro Carvalho Chehab
738b285192aSMauro Carvalho Chehab e_idx->reserved[0] = 0;
739b285192aSMauro Carvalho Chehab e_idx->reserved[1] = 0;
740b285192aSMauro Carvalho Chehab
741b285192aSMauro Carvalho Chehab idx->entries++;
742b285192aSMauro Carvalho Chehab e_idx = &idx->entry[idx->entries];
743b285192aSMauro Carvalho Chehab e_buf++;
744b285192aSMauro Carvalho Chehab
745b285192aSMauro Carvalho Chehab remaining -= sizeof(struct cx18_enc_idx_entry);
746b285192aSMauro Carvalho Chehab consumed += sizeof(struct cx18_enc_idx_entry);
747b285192aSMauro Carvalho Chehab }
748b285192aSMauro Carvalho Chehab
749b285192aSMauro Carvalho Chehab /* Swallow any partial entries at the end, if there are any */
750b285192aSMauro Carvalho Chehab if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry))
751b285192aSMauro Carvalho Chehab consumed += remaining;
752b285192aSMauro Carvalho Chehab
753b285192aSMauro Carvalho Chehab buf->readpos += consumed;
754b285192aSMauro Carvalho Chehab return consumed;
755b285192aSMauro Carvalho Chehab }
756b285192aSMauro Carvalho Chehab
cx18_process_idx_data(struct cx18_stream * s,struct cx18_mdl * mdl,struct v4l2_enc_idx * idx)757b285192aSMauro Carvalho Chehab static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl,
758b285192aSMauro Carvalho Chehab struct v4l2_enc_idx *idx)
759b285192aSMauro Carvalho Chehab {
760b285192aSMauro Carvalho Chehab if (s->type != CX18_ENC_STREAM_TYPE_IDX)
761b285192aSMauro Carvalho Chehab return -EINVAL;
762b285192aSMauro Carvalho Chehab
763b285192aSMauro Carvalho Chehab if (mdl->curr_buf == NULL)
764b285192aSMauro Carvalho Chehab mdl->curr_buf = list_first_entry(&mdl->buf_list,
765b285192aSMauro Carvalho Chehab struct cx18_buffer, list);
766b285192aSMauro Carvalho Chehab
767b285192aSMauro Carvalho Chehab if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
768b285192aSMauro Carvalho Chehab /*
769b285192aSMauro Carvalho Chehab * For some reason we've exhausted the buffers, but the MDL
770b285192aSMauro Carvalho Chehab * object still said some data was unread.
771b285192aSMauro Carvalho Chehab * Fix that and bail out.
772b285192aSMauro Carvalho Chehab */
773b285192aSMauro Carvalho Chehab mdl->readpos = mdl->bytesused;
774b285192aSMauro Carvalho Chehab return 0;
775b285192aSMauro Carvalho Chehab }
776b285192aSMauro Carvalho Chehab
777b285192aSMauro Carvalho Chehab list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) {
778b285192aSMauro Carvalho Chehab
779b285192aSMauro Carvalho Chehab /* Skip any empty buffers in the MDL */
780b285192aSMauro Carvalho Chehab if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused)
781b285192aSMauro Carvalho Chehab continue;
782b285192aSMauro Carvalho Chehab
783b285192aSMauro Carvalho Chehab mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx);
784b285192aSMauro Carvalho Chehab
785b285192aSMauro Carvalho Chehab /* exit when MDL drained or request satisfied */
786b285192aSMauro Carvalho Chehab if (idx->entries >= V4L2_ENC_IDX_ENTRIES ||
787b285192aSMauro Carvalho Chehab mdl->curr_buf->readpos < mdl->curr_buf->bytesused ||
788b285192aSMauro Carvalho Chehab mdl->readpos >= mdl->bytesused)
789b285192aSMauro Carvalho Chehab break;
790b285192aSMauro Carvalho Chehab }
791b285192aSMauro Carvalho Chehab return 0;
792b285192aSMauro Carvalho Chehab }
793b285192aSMauro Carvalho Chehab
cx18_g_enc_index(struct file * file,void * fh,struct v4l2_enc_idx * idx)794b285192aSMauro Carvalho Chehab static int cx18_g_enc_index(struct file *file, void *fh,
795b285192aSMauro Carvalho Chehab struct v4l2_enc_idx *idx)
796b285192aSMauro Carvalho Chehab {
797b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
798b285192aSMauro Carvalho Chehab struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
799b285192aSMauro Carvalho Chehab s32 tmp;
800b285192aSMauro Carvalho Chehab struct cx18_mdl *mdl;
801b285192aSMauro Carvalho Chehab
802b285192aSMauro Carvalho Chehab if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */
803b285192aSMauro Carvalho Chehab return -EINVAL;
804b285192aSMauro Carvalho Chehab
805b285192aSMauro Carvalho Chehab /* Compute the best case number of entries we can buffer */
806b285192aSMauro Carvalho Chehab tmp = s->buffers -
807b285192aSMauro Carvalho Chehab s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN;
808b285192aSMauro Carvalho Chehab if (tmp <= 0)
809b285192aSMauro Carvalho Chehab tmp = 1;
810b285192aSMauro Carvalho Chehab tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry);
811b285192aSMauro Carvalho Chehab
812b285192aSMauro Carvalho Chehab /* Fill out the header of the return structure */
813b285192aSMauro Carvalho Chehab idx->entries = 0;
814b285192aSMauro Carvalho Chehab idx->entries_cap = tmp;
815b285192aSMauro Carvalho Chehab memset(idx->reserved, 0, sizeof(idx->reserved));
816b285192aSMauro Carvalho Chehab
817b285192aSMauro Carvalho Chehab /* Pull IDX MDLs and buffers from q_full and populate the entries */
818b285192aSMauro Carvalho Chehab do {
819b285192aSMauro Carvalho Chehab mdl = cx18_dequeue(s, &s->q_full);
820b285192aSMauro Carvalho Chehab if (mdl == NULL) /* No more IDX data right now */
821b285192aSMauro Carvalho Chehab break;
822b285192aSMauro Carvalho Chehab
823b285192aSMauro Carvalho Chehab /* Extract the Index entry data from the MDL and buffers */
824b285192aSMauro Carvalho Chehab cx18_process_idx_data(s, mdl, idx);
825b285192aSMauro Carvalho Chehab if (mdl->readpos < mdl->bytesused) {
826b285192aSMauro Carvalho Chehab /* We finished with data remaining, push the MDL back */
827b285192aSMauro Carvalho Chehab cx18_push(s, mdl, &s->q_full);
828b285192aSMauro Carvalho Chehab break;
829b285192aSMauro Carvalho Chehab }
830b285192aSMauro Carvalho Chehab
831b285192aSMauro Carvalho Chehab /* We drained this MDL, schedule it to go to the firmware */
832b285192aSMauro Carvalho Chehab cx18_enqueue(s, mdl, &s->q_free);
833b285192aSMauro Carvalho Chehab
834b285192aSMauro Carvalho Chehab } while (idx->entries < V4L2_ENC_IDX_ENTRIES);
835b285192aSMauro Carvalho Chehab
836b285192aSMauro Carvalho Chehab /* Tell the work handler to send free IDX MDLs to the firmware */
837b285192aSMauro Carvalho Chehab cx18_stream_load_fw_queue(s);
838b285192aSMauro Carvalho Chehab return 0;
839b285192aSMauro Carvalho Chehab }
840b285192aSMauro Carvalho Chehab
cx18_encoder_cmd(struct file * file,void * fh,struct v4l2_encoder_cmd * enc)841b285192aSMauro Carvalho Chehab static int cx18_encoder_cmd(struct file *file, void *fh,
842b285192aSMauro Carvalho Chehab struct v4l2_encoder_cmd *enc)
843b285192aSMauro Carvalho Chehab {
844b285192aSMauro Carvalho Chehab struct cx18_open_id *id = fh2id(fh);
845b285192aSMauro Carvalho Chehab struct cx18 *cx = id->cx;
846b285192aSMauro Carvalho Chehab u32 h;
847b285192aSMauro Carvalho Chehab
848b285192aSMauro Carvalho Chehab switch (enc->cmd) {
849b285192aSMauro Carvalho Chehab case V4L2_ENC_CMD_START:
850b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
851b285192aSMauro Carvalho Chehab enc->flags = 0;
852b285192aSMauro Carvalho Chehab return cx18_start_capture(id);
853b285192aSMauro Carvalho Chehab
854b285192aSMauro Carvalho Chehab case V4L2_ENC_CMD_STOP:
855b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
856b285192aSMauro Carvalho Chehab enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
857643e8350SHans Verkuil cx18_stop_capture(&cx->streams[id->type],
858b285192aSMauro Carvalho Chehab enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
859b285192aSMauro Carvalho Chehab break;
860b285192aSMauro Carvalho Chehab
861b285192aSMauro Carvalho Chehab case V4L2_ENC_CMD_PAUSE:
862b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
863b285192aSMauro Carvalho Chehab enc->flags = 0;
864b285192aSMauro Carvalho Chehab if (!atomic_read(&cx->ana_capturing))
865b285192aSMauro Carvalho Chehab return -EPERM;
866b285192aSMauro Carvalho Chehab if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
867b285192aSMauro Carvalho Chehab return 0;
868b285192aSMauro Carvalho Chehab h = cx18_find_handle(cx);
869b285192aSMauro Carvalho Chehab if (h == CX18_INVALID_TASK_HANDLE) {
8706beb1388SMauro Carvalho Chehab CX18_ERR("Can't find valid task handle for V4L2_ENC_CMD_PAUSE\n");
871b285192aSMauro Carvalho Chehab return -EBADFD;
872b285192aSMauro Carvalho Chehab }
873b285192aSMauro Carvalho Chehab cx18_mute(cx);
874b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);
875b285192aSMauro Carvalho Chehab break;
876b285192aSMauro Carvalho Chehab
877b285192aSMauro Carvalho Chehab case V4L2_ENC_CMD_RESUME:
878b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
879b285192aSMauro Carvalho Chehab enc->flags = 0;
880b285192aSMauro Carvalho Chehab if (!atomic_read(&cx->ana_capturing))
881b285192aSMauro Carvalho Chehab return -EPERM;
882b285192aSMauro Carvalho Chehab if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
883b285192aSMauro Carvalho Chehab return 0;
884b285192aSMauro Carvalho Chehab h = cx18_find_handle(cx);
885b285192aSMauro Carvalho Chehab if (h == CX18_INVALID_TASK_HANDLE) {
8866beb1388SMauro Carvalho Chehab CX18_ERR("Can't find valid task handle for V4L2_ENC_CMD_RESUME\n");
887b285192aSMauro Carvalho Chehab return -EBADFD;
888b285192aSMauro Carvalho Chehab }
889b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);
890b285192aSMauro Carvalho Chehab cx18_unmute(cx);
891b285192aSMauro Carvalho Chehab break;
892b285192aSMauro Carvalho Chehab
893b285192aSMauro Carvalho Chehab default:
894b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
895b285192aSMauro Carvalho Chehab return -EINVAL;
896b285192aSMauro Carvalho Chehab }
897b285192aSMauro Carvalho Chehab return 0;
898b285192aSMauro Carvalho Chehab }
899b285192aSMauro Carvalho Chehab
cx18_try_encoder_cmd(struct file * file,void * fh,struct v4l2_encoder_cmd * enc)900b285192aSMauro Carvalho Chehab static int cx18_try_encoder_cmd(struct file *file, void *fh,
901b285192aSMauro Carvalho Chehab struct v4l2_encoder_cmd *enc)
902b285192aSMauro Carvalho Chehab {
903b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
904b285192aSMauro Carvalho Chehab
905b285192aSMauro Carvalho Chehab switch (enc->cmd) {
906b285192aSMauro Carvalho Chehab case V4L2_ENC_CMD_START:
907b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
908b285192aSMauro Carvalho Chehab enc->flags = 0;
909b285192aSMauro Carvalho Chehab break;
910b285192aSMauro Carvalho Chehab
911b285192aSMauro Carvalho Chehab case V4L2_ENC_CMD_STOP:
912b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
913b285192aSMauro Carvalho Chehab enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
914b285192aSMauro Carvalho Chehab break;
915b285192aSMauro Carvalho Chehab
916b285192aSMauro Carvalho Chehab case V4L2_ENC_CMD_PAUSE:
917b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
918b285192aSMauro Carvalho Chehab enc->flags = 0;
919b285192aSMauro Carvalho Chehab break;
920b285192aSMauro Carvalho Chehab
921b285192aSMauro Carvalho Chehab case V4L2_ENC_CMD_RESUME:
922b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
923b285192aSMauro Carvalho Chehab enc->flags = 0;
924b285192aSMauro Carvalho Chehab break;
925b285192aSMauro Carvalho Chehab
926b285192aSMauro Carvalho Chehab default:
927b285192aSMauro Carvalho Chehab CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
928b285192aSMauro Carvalho Chehab return -EINVAL;
929b285192aSMauro Carvalho Chehab }
930b285192aSMauro Carvalho Chehab return 0;
931b285192aSMauro Carvalho Chehab }
932b285192aSMauro Carvalho Chehab
cx18_log_status(struct file * file,void * fh)933b285192aSMauro Carvalho Chehab static int cx18_log_status(struct file *file, void *fh)
934b285192aSMauro Carvalho Chehab {
935b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
936b285192aSMauro Carvalho Chehab struct v4l2_input vidin;
937b285192aSMauro Carvalho Chehab struct v4l2_audio audin;
938b285192aSMauro Carvalho Chehab int i;
939b285192aSMauro Carvalho Chehab
940b285192aSMauro Carvalho Chehab CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name);
941b285192aSMauro Carvalho Chehab if (cx->hw_flags & CX18_HW_TVEEPROM) {
942b285192aSMauro Carvalho Chehab struct tveeprom tv;
943b285192aSMauro Carvalho Chehab
944b285192aSMauro Carvalho Chehab cx18_read_eeprom(cx, &tv);
945b285192aSMauro Carvalho Chehab }
946b285192aSMauro Carvalho Chehab cx18_call_all(cx, core, log_status);
947b285192aSMauro Carvalho Chehab cx18_get_input(cx, cx->active_input, &vidin);
948b285192aSMauro Carvalho Chehab cx18_get_audio_input(cx, cx->audio_input, &audin);
949b285192aSMauro Carvalho Chehab CX18_INFO("Video Input: %s\n", vidin.name);
950b285192aSMauro Carvalho Chehab CX18_INFO("Audio Input: %s\n", audin.name);
951b285192aSMauro Carvalho Chehab mutex_lock(&cx->gpio_lock);
952b285192aSMauro Carvalho Chehab CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n",
953b285192aSMauro Carvalho Chehab cx->gpio_dir, cx->gpio_val);
954b285192aSMauro Carvalho Chehab mutex_unlock(&cx->gpio_lock);
955b285192aSMauro Carvalho Chehab CX18_INFO("Tuner: %s\n",
956b285192aSMauro Carvalho Chehab test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV");
957b285192aSMauro Carvalho Chehab v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name);
958b285192aSMauro Carvalho Chehab CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
959b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_MAX_STREAMS; i++) {
960b285192aSMauro Carvalho Chehab struct cx18_stream *s = &cx->streams[i];
961b285192aSMauro Carvalho Chehab
96208569d64SHans Verkuil if (s->video_dev.v4l2_dev == NULL || s->buffers == 0)
963b285192aSMauro Carvalho Chehab continue;
964b285192aSMauro Carvalho Chehab CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
965b285192aSMauro Carvalho Chehab s->name, s->s_flags,
966b285192aSMauro Carvalho Chehab atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100
967b285192aSMauro Carvalho Chehab / s->buffers,
968b285192aSMauro Carvalho Chehab (s->buffers * s->buf_size) / 1024, s->buffers);
969b285192aSMauro Carvalho Chehab }
970b285192aSMauro Carvalho Chehab CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
971b285192aSMauro Carvalho Chehab (long long)cx->mpg_data_received,
972b285192aSMauro Carvalho Chehab (long long)cx->vbi_data_inserted);
973b285192aSMauro Carvalho Chehab return 0;
974b285192aSMauro Carvalho Chehab }
975b285192aSMauro Carvalho Chehab
cx18_default(struct file * file,void * fh,bool valid_prio,unsigned int cmd,void * arg)976b285192aSMauro Carvalho Chehab static long cx18_default(struct file *file, void *fh, bool valid_prio,
9776d43be77SMauro Carvalho Chehab unsigned int cmd, void *arg)
978b285192aSMauro Carvalho Chehab {
979b285192aSMauro Carvalho Chehab struct cx18 *cx = fh2id(fh)->cx;
980b285192aSMauro Carvalho Chehab
981b285192aSMauro Carvalho Chehab switch (cmd) {
982b285192aSMauro Carvalho Chehab case VIDIOC_INT_RESET: {
983b285192aSMauro Carvalho Chehab u32 val = *(u32 *)arg;
984b285192aSMauro Carvalho Chehab
985b285192aSMauro Carvalho Chehab if ((val == 0) || (val & 0x01))
986b285192aSMauro Carvalho Chehab cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset,
987b285192aSMauro Carvalho Chehab (u32) CX18_GPIO_RESET_Z8F0811);
988b285192aSMauro Carvalho Chehab break;
989b285192aSMauro Carvalho Chehab }
990b285192aSMauro Carvalho Chehab
991b285192aSMauro Carvalho Chehab default:
992b285192aSMauro Carvalho Chehab return -ENOTTY;
993b285192aSMauro Carvalho Chehab }
994b285192aSMauro Carvalho Chehab return 0;
995b285192aSMauro Carvalho Chehab }
996b285192aSMauro Carvalho Chehab
997b285192aSMauro Carvalho Chehab static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
998b285192aSMauro Carvalho Chehab .vidioc_querycap = cx18_querycap,
999b285192aSMauro Carvalho Chehab .vidioc_s_audio = cx18_s_audio,
1000b285192aSMauro Carvalho Chehab .vidioc_g_audio = cx18_g_audio,
1001b285192aSMauro Carvalho Chehab .vidioc_enumaudio = cx18_enumaudio,
1002b285192aSMauro Carvalho Chehab .vidioc_enum_input = cx18_enum_input,
10035200ab6aSHans Verkuil .vidioc_g_pixelaspect = cx18_g_pixelaspect,
100455cda4abSHans Verkuil .vidioc_g_selection = cx18_g_selection,
1005b285192aSMauro Carvalho Chehab .vidioc_g_input = cx18_g_input,
1006b285192aSMauro Carvalho Chehab .vidioc_s_input = cx18_s_input,
1007b285192aSMauro Carvalho Chehab .vidioc_g_frequency = cx18_g_frequency,
1008b285192aSMauro Carvalho Chehab .vidioc_s_frequency = cx18_s_frequency,
1009b285192aSMauro Carvalho Chehab .vidioc_s_tuner = cx18_s_tuner,
1010b285192aSMauro Carvalho Chehab .vidioc_g_tuner = cx18_g_tuner,
1011b285192aSMauro Carvalho Chehab .vidioc_g_enc_index = cx18_g_enc_index,
1012b285192aSMauro Carvalho Chehab .vidioc_g_std = cx18_g_std,
1013b285192aSMauro Carvalho Chehab .vidioc_s_std = cx18_s_std,
1014b285192aSMauro Carvalho Chehab .vidioc_log_status = cx18_log_status,
1015b285192aSMauro Carvalho Chehab .vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap,
1016b285192aSMauro Carvalho Chehab .vidioc_encoder_cmd = cx18_encoder_cmd,
1017b285192aSMauro Carvalho Chehab .vidioc_try_encoder_cmd = cx18_try_encoder_cmd,
1018b285192aSMauro Carvalho Chehab .vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap,
1019b285192aSMauro Carvalho Chehab .vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap,
1020b285192aSMauro Carvalho Chehab .vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap,
1021b285192aSMauro Carvalho Chehab .vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap,
1022b285192aSMauro Carvalho Chehab .vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap,
1023b285192aSMauro Carvalho Chehab .vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap,
1024b285192aSMauro Carvalho Chehab .vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap,
1025b285192aSMauro Carvalho Chehab .vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap,
1026b285192aSMauro Carvalho Chehab .vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap,
1027b285192aSMauro Carvalho Chehab .vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap,
1028b285192aSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
1029b285192aSMauro Carvalho Chehab .vidioc_g_register = cx18_g_register,
1030b285192aSMauro Carvalho Chehab .vidioc_s_register = cx18_s_register,
1031b285192aSMauro Carvalho Chehab #endif
1032b285192aSMauro Carvalho Chehab .vidioc_default = cx18_default,
1033643e8350SHans Verkuil
1034643e8350SHans Verkuil .vidioc_reqbufs = vb2_ioctl_reqbufs,
1035643e8350SHans Verkuil .vidioc_querybuf = vb2_ioctl_querybuf,
1036643e8350SHans Verkuil .vidioc_qbuf = vb2_ioctl_qbuf,
1037643e8350SHans Verkuil .vidioc_dqbuf = vb2_ioctl_dqbuf,
1038643e8350SHans Verkuil .vidioc_create_bufs = vb2_ioctl_create_bufs,
1039643e8350SHans Verkuil .vidioc_streamon = vb2_ioctl_streamon,
1040643e8350SHans Verkuil .vidioc_streamoff = vb2_ioctl_streamoff,
1041643e8350SHans Verkuil .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1042eaa80c44SHans Verkuil .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1043eaa80c44SHans Verkuil .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1044b285192aSMauro Carvalho Chehab };
1045b285192aSMauro Carvalho Chehab
cx18_set_funcs(struct video_device * vdev)1046b285192aSMauro Carvalho Chehab void cx18_set_funcs(struct video_device *vdev)
1047b285192aSMauro Carvalho Chehab {
1048b285192aSMauro Carvalho Chehab vdev->ioctl_ops = &cx18_ioctl_ops;
1049b285192aSMauro Carvalho Chehab }
1050