1*2a0c2806SHans Verkuil // SPDX-License-Identifier: GPL-2.0-or-later
2*2a0c2806SHans Verkuil /*
3*2a0c2806SHans Verkuil  * Zoran zr36057/zr36067 PCI controller driver, for the
4*2a0c2806SHans Verkuil  * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
5*2a0c2806SHans Verkuil  * Media Labs LML33/LML33R10.
6*2a0c2806SHans Verkuil  *
7*2a0c2806SHans Verkuil  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
8*2a0c2806SHans Verkuil  *
9*2a0c2806SHans Verkuil  * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net>
10*2a0c2806SHans Verkuil  *
11*2a0c2806SHans Verkuil  * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be>
12*2a0c2806SHans Verkuil  *
13*2a0c2806SHans Verkuil  * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com>
14*2a0c2806SHans Verkuil  *
15*2a0c2806SHans Verkuil  * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net>
16*2a0c2806SHans Verkuil  *
17*2a0c2806SHans Verkuil  * Based on
18*2a0c2806SHans Verkuil  *
19*2a0c2806SHans Verkuil  * Miro DC10 driver
20*2a0c2806SHans Verkuil  * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
21*2a0c2806SHans Verkuil  *
22*2a0c2806SHans Verkuil  * Iomega Buz driver version 1.0
23*2a0c2806SHans Verkuil  * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
24*2a0c2806SHans Verkuil  *
25*2a0c2806SHans Verkuil  * buz.0.0.3
26*2a0c2806SHans Verkuil  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
27*2a0c2806SHans Verkuil  *
28*2a0c2806SHans Verkuil  * bttv - Bt848 frame grabber driver
29*2a0c2806SHans Verkuil  * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
30*2a0c2806SHans Verkuil  *                        & Marcus Metzler (mocm@thp.uni-koeln.de)
31*2a0c2806SHans Verkuil  */
32*2a0c2806SHans Verkuil 
33*2a0c2806SHans Verkuil #include <linux/init.h>
34*2a0c2806SHans Verkuil #include <linux/module.h>
35*2a0c2806SHans Verkuil #include <linux/delay.h>
36*2a0c2806SHans Verkuil #include <linux/slab.h>
37*2a0c2806SHans Verkuil #include <linux/pci.h>
38*2a0c2806SHans Verkuil #include <linux/wait.h>
39*2a0c2806SHans Verkuil 
40*2a0c2806SHans Verkuil #include <linux/interrupt.h>
41*2a0c2806SHans Verkuil #include <linux/i2c.h>
42*2a0c2806SHans Verkuil #include <linux/i2c-algo-bit.h>
43*2a0c2806SHans Verkuil 
44*2a0c2806SHans Verkuil #include <linux/spinlock.h>
45*2a0c2806SHans Verkuil 
46*2a0c2806SHans Verkuil #include <linux/videodev2.h>
47*2a0c2806SHans Verkuil #include <media/v4l2-common.h>
48*2a0c2806SHans Verkuil #include <media/v4l2-ioctl.h>
49*2a0c2806SHans Verkuil #include <media/v4l2-event.h>
50*2a0c2806SHans Verkuil #include "videocodec.h"
51*2a0c2806SHans Verkuil 
52*2a0c2806SHans Verkuil #include <linux/io.h>
53*2a0c2806SHans Verkuil #include <linux/uaccess.h>
54*2a0c2806SHans Verkuil 
55*2a0c2806SHans Verkuil #include <linux/mutex.h>
56*2a0c2806SHans Verkuil #include "zoran.h"
57*2a0c2806SHans Verkuil #include "zoran_device.h"
58*2a0c2806SHans Verkuil #include "zoran_card.h"
59*2a0c2806SHans Verkuil 
60*2a0c2806SHans Verkuil const struct zoran_format zoran_formats[] = {
61*2a0c2806SHans Verkuil 	{
62*2a0c2806SHans Verkuil 		.name = "15-bit RGB LE",
63*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_RGB555,
64*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SRGB,
65*2a0c2806SHans Verkuil 		.depth = 15,
66*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
67*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ERR_DIF |
68*2a0c2806SHans Verkuil 			   ZR36057_VFESPFR_LITTLE_ENDIAN,
69*2a0c2806SHans Verkuil 	}, {
70*2a0c2806SHans Verkuil 		.name = "15-bit RGB BE",
71*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_RGB555X,
72*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SRGB,
73*2a0c2806SHans Verkuil 		.depth = 15,
74*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
75*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ERR_DIF,
76*2a0c2806SHans Verkuil 	}, {
77*2a0c2806SHans Verkuil 		.name = "16-bit RGB LE",
78*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_RGB565,
79*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SRGB,
80*2a0c2806SHans Verkuil 		.depth = 16,
81*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
82*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ERR_DIF |
83*2a0c2806SHans Verkuil 			   ZR36057_VFESPFR_LITTLE_ENDIAN,
84*2a0c2806SHans Verkuil 	}, {
85*2a0c2806SHans Verkuil 		.name = "16-bit RGB BE",
86*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_RGB565X,
87*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SRGB,
88*2a0c2806SHans Verkuil 		.depth = 16,
89*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
90*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ERR_DIF,
91*2a0c2806SHans Verkuil 	}, {
92*2a0c2806SHans Verkuil 		.name = "24-bit RGB",
93*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_BGR24,
94*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SRGB,
95*2a0c2806SHans Verkuil 		.depth = 24,
96*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
97*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_PACK24,
98*2a0c2806SHans Verkuil 	}, {
99*2a0c2806SHans Verkuil 		.name = "32-bit RGB LE",
100*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_BGR32,
101*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SRGB,
102*2a0c2806SHans Verkuil 		.depth = 32,
103*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
104*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_LITTLE_ENDIAN,
105*2a0c2806SHans Verkuil 	}, {
106*2a0c2806SHans Verkuil 		.name = "32-bit RGB BE",
107*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_RGB32,
108*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SRGB,
109*2a0c2806SHans Verkuil 		.depth = 32,
110*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
111*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_RGB888,
112*2a0c2806SHans Verkuil 	}, {
113*2a0c2806SHans Verkuil 		.name = "4:2:2, packed, YUYV",
114*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_YUYV,
115*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SMPTE170M,
116*2a0c2806SHans Verkuil 		.depth = 16,
117*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
118*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_YUV422,
119*2a0c2806SHans Verkuil 	}, {
120*2a0c2806SHans Verkuil 		.name = "4:2:2, packed, UYVY",
121*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_UYVY,
122*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SMPTE170M,
123*2a0c2806SHans Verkuil 		.depth = 16,
124*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE,
125*2a0c2806SHans Verkuil 		.vfespfr = ZR36057_VFESPFR_YUV422 | ZR36057_VFESPFR_LITTLE_ENDIAN,
126*2a0c2806SHans Verkuil 	}, {
127*2a0c2806SHans Verkuil 		.name = "Hardware-encoded Motion-JPEG",
128*2a0c2806SHans Verkuil 		.fourcc = V4L2_PIX_FMT_MJPEG,
129*2a0c2806SHans Verkuil 		.colorspace = V4L2_COLORSPACE_SMPTE170M,
130*2a0c2806SHans Verkuil 		.depth = 0,
131*2a0c2806SHans Verkuil 		.flags = ZORAN_FORMAT_CAPTURE |
132*2a0c2806SHans Verkuil 			 ZORAN_FORMAT_PLAYBACK |
133*2a0c2806SHans Verkuil 			 ZORAN_FORMAT_COMPRESSED,
134*2a0c2806SHans Verkuil 	}
135*2a0c2806SHans Verkuil };
136*2a0c2806SHans Verkuil 
137*2a0c2806SHans Verkuil #define NUM_FORMATS ARRAY_SIZE(zoran_formats)
138*2a0c2806SHans Verkuil 
139*2a0c2806SHans Verkuil 	/*
140*2a0c2806SHans Verkuil 	 * small helper function for calculating buffersizes for v4l2
141*2a0c2806SHans Verkuil 	 * we calculate the nearest higher power-of-two, which
142*2a0c2806SHans Verkuil 	 * will be the recommended buffersize
143*2a0c2806SHans Verkuil 	 */
zoran_v4l2_calc_bufsize(struct zoran_jpg_settings * settings)144*2a0c2806SHans Verkuil static __u32 zoran_v4l2_calc_bufsize(struct zoran_jpg_settings *settings)
145*2a0c2806SHans Verkuil {
146*2a0c2806SHans Verkuil 	__u8 div = settings->ver_dcm * settings->hor_dcm * settings->tmp_dcm;
147*2a0c2806SHans Verkuil 	__u32 num = (1024 * 512) / (div);
148*2a0c2806SHans Verkuil 	__u32 result = 2;
149*2a0c2806SHans Verkuil 
150*2a0c2806SHans Verkuil 	num--;
151*2a0c2806SHans Verkuil 	while (num) {
152*2a0c2806SHans Verkuil 		num >>= 1;
153*2a0c2806SHans Verkuil 		result <<= 1;
154*2a0c2806SHans Verkuil 	}
155*2a0c2806SHans Verkuil 
156*2a0c2806SHans Verkuil 	if (result < 8192)
157*2a0c2806SHans Verkuil 		return 8192;
158*2a0c2806SHans Verkuil 
159*2a0c2806SHans Verkuil 	return result;
160*2a0c2806SHans Verkuil }
161*2a0c2806SHans Verkuil 
162*2a0c2806SHans Verkuil /*
163*2a0c2806SHans Verkuil  *   V4L Buffer grabbing
164*2a0c2806SHans Verkuil  */
zoran_v4l_set_format(struct zoran * zr,int width,int height,const struct zoran_format * format)165*2a0c2806SHans Verkuil static int zoran_v4l_set_format(struct zoran *zr, int width, int height,
166*2a0c2806SHans Verkuil 				const struct zoran_format *format)
167*2a0c2806SHans Verkuil {
168*2a0c2806SHans Verkuil 	int bpp;
169*2a0c2806SHans Verkuil 
170*2a0c2806SHans Verkuil 	/* Check size and format of the grab wanted */
171*2a0c2806SHans Verkuil 
172*2a0c2806SHans Verkuil 	if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH ||
173*2a0c2806SHans Verkuil 	    height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) {
174*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "%s - wrong frame size (%dx%d)\n", __func__, width, height);
175*2a0c2806SHans Verkuil 		return -EINVAL;
176*2a0c2806SHans Verkuil 	}
177*2a0c2806SHans Verkuil 
178*2a0c2806SHans Verkuil 	bpp = (format->depth + 7) / 8;
179*2a0c2806SHans Verkuil 
180*2a0c2806SHans Verkuil 	zr->buffer_size = height * width * bpp;
181*2a0c2806SHans Verkuil 
182*2a0c2806SHans Verkuil 	/* Check against available buffer size */
183*2a0c2806SHans Verkuil 	if (height * width * bpp > zr->buffer_size) {
184*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "%s - video buffer size (%d kB) is too small\n",
185*2a0c2806SHans Verkuil 			__func__, zr->buffer_size >> 10);
186*2a0c2806SHans Verkuil 		return -EINVAL;
187*2a0c2806SHans Verkuil 	}
188*2a0c2806SHans Verkuil 
189*2a0c2806SHans Verkuil 	/* The video front end needs 4-byte alinged line sizes */
190*2a0c2806SHans Verkuil 
191*2a0c2806SHans Verkuil 	if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
192*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "%s - wrong frame alignment\n", __func__);
193*2a0c2806SHans Verkuil 		return -EINVAL;
194*2a0c2806SHans Verkuil 	}
195*2a0c2806SHans Verkuil 
196*2a0c2806SHans Verkuil 	zr->v4l_settings.width = width;
197*2a0c2806SHans Verkuil 	zr->v4l_settings.height = height;
198*2a0c2806SHans Verkuil 	zr->v4l_settings.format = format;
199*2a0c2806SHans Verkuil 	zr->v4l_settings.bytesperline = bpp * zr->v4l_settings.width;
200*2a0c2806SHans Verkuil 
201*2a0c2806SHans Verkuil 	return 0;
202*2a0c2806SHans Verkuil }
203*2a0c2806SHans Verkuil 
zoran_set_norm(struct zoran * zr,v4l2_std_id norm)204*2a0c2806SHans Verkuil static int zoran_set_norm(struct zoran *zr, v4l2_std_id norm)
205*2a0c2806SHans Verkuil {
206*2a0c2806SHans Verkuil 	if (!(norm & zr->card.norms)) {
207*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "%s - unsupported norm %llx\n", __func__, norm);
208*2a0c2806SHans Verkuil 		return -EINVAL;
209*2a0c2806SHans Verkuil 	}
210*2a0c2806SHans Verkuil 
211*2a0c2806SHans Verkuil 	if (norm & V4L2_STD_SECAM)
212*2a0c2806SHans Verkuil 		zr->timing = zr->card.tvn[ZR_NORM_SECAM];
213*2a0c2806SHans Verkuil 	else if (norm & V4L2_STD_NTSC)
214*2a0c2806SHans Verkuil 		zr->timing = zr->card.tvn[ZR_NORM_NTSC];
215*2a0c2806SHans Verkuil 	else
216*2a0c2806SHans Verkuil 		zr->timing = zr->card.tvn[ZR_NORM_PAL];
217*2a0c2806SHans Verkuil 
218*2a0c2806SHans Verkuil 	decoder_call(zr, video, s_std, norm);
219*2a0c2806SHans Verkuil 	encoder_call(zr, video, s_std_output, norm);
220*2a0c2806SHans Verkuil 
221*2a0c2806SHans Verkuil 	/* Make sure the changes come into effect */
222*2a0c2806SHans Verkuil 	zr->norm = norm;
223*2a0c2806SHans Verkuil 
224*2a0c2806SHans Verkuil 	return 0;
225*2a0c2806SHans Verkuil }
226*2a0c2806SHans Verkuil 
zoran_set_input(struct zoran * zr,int input)227*2a0c2806SHans Verkuil static int zoran_set_input(struct zoran *zr, int input)
228*2a0c2806SHans Verkuil {
229*2a0c2806SHans Verkuil 	if (input == zr->input)
230*2a0c2806SHans Verkuil 		return 0;
231*2a0c2806SHans Verkuil 
232*2a0c2806SHans Verkuil 	if (input < 0 || input >= zr->card.inputs) {
233*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "%s - unsupported input %d\n", __func__, input);
234*2a0c2806SHans Verkuil 		return -EINVAL;
235*2a0c2806SHans Verkuil 	}
236*2a0c2806SHans Verkuil 
237*2a0c2806SHans Verkuil 	zr->input = input;
238*2a0c2806SHans Verkuil 
239*2a0c2806SHans Verkuil 	decoder_call(zr, video, s_routing, zr->card.input[input].muxsel, 0, 0);
240*2a0c2806SHans Verkuil 
241*2a0c2806SHans Verkuil 	return 0;
242*2a0c2806SHans Verkuil }
243*2a0c2806SHans Verkuil 
244*2a0c2806SHans Verkuil /*
245*2a0c2806SHans Verkuil  *   ioctl routine
246*2a0c2806SHans Verkuil  */
247*2a0c2806SHans Verkuil 
zoran_querycap(struct file * file,void * __fh,struct v4l2_capability * cap)248*2a0c2806SHans Verkuil static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap)
249*2a0c2806SHans Verkuil {
250*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
251*2a0c2806SHans Verkuil 
252*2a0c2806SHans Verkuil 	strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
253*2a0c2806SHans Verkuil 	strscpy(cap->driver, "zoran", sizeof(cap->driver));
254*2a0c2806SHans Verkuil 	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(zr->pci_dev));
255*2a0c2806SHans Verkuil 	return 0;
256*2a0c2806SHans Verkuil }
257*2a0c2806SHans Verkuil 
zoran_enum_fmt(struct zoran * zr,struct v4l2_fmtdesc * fmt,int flag)258*2a0c2806SHans Verkuil static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag)
259*2a0c2806SHans Verkuil {
260*2a0c2806SHans Verkuil 	unsigned int num, i;
261*2a0c2806SHans Verkuil 
262*2a0c2806SHans Verkuil 	if (fmt->index >= ARRAY_SIZE(zoran_formats))
263*2a0c2806SHans Verkuil 		return -EINVAL;
264*2a0c2806SHans Verkuil 	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
265*2a0c2806SHans Verkuil 		return -EINVAL;
266*2a0c2806SHans Verkuil 
267*2a0c2806SHans Verkuil 	for (num = i = 0; i < NUM_FORMATS; i++) {
268*2a0c2806SHans Verkuil 		if (zoran_formats[i].flags & flag && num++ == fmt->index) {
269*2a0c2806SHans Verkuil 			strscpy(fmt->description, zoran_formats[i].name,
270*2a0c2806SHans Verkuil 				sizeof(fmt->description));
271*2a0c2806SHans Verkuil 			/* fmt struct pre-zeroed, so adding '\0' not needed */
272*2a0c2806SHans Verkuil 			fmt->pixelformat = zoran_formats[i].fourcc;
273*2a0c2806SHans Verkuil 			if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
274*2a0c2806SHans Verkuil 				fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
275*2a0c2806SHans Verkuil 			return 0;
276*2a0c2806SHans Verkuil 		}
277*2a0c2806SHans Verkuil 	}
278*2a0c2806SHans Verkuil 	return -EINVAL;
279*2a0c2806SHans Verkuil }
280*2a0c2806SHans Verkuil 
zoran_enum_fmt_vid_cap(struct file * file,void * __fh,struct v4l2_fmtdesc * f)281*2a0c2806SHans Verkuil static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh,
282*2a0c2806SHans Verkuil 				  struct v4l2_fmtdesc *f)
283*2a0c2806SHans Verkuil {
284*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
285*2a0c2806SHans Verkuil 
286*2a0c2806SHans Verkuil 	return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE);
287*2a0c2806SHans Verkuil }
288*2a0c2806SHans Verkuil 
zoran_g_fmt_vid_out(struct file * file,void * __fh,struct v4l2_format * fmt)289*2a0c2806SHans Verkuil static int zoran_g_fmt_vid_out(struct file *file, void *__fh,
290*2a0c2806SHans Verkuil 			       struct v4l2_format *fmt)
291*2a0c2806SHans Verkuil {
292*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
293*2a0c2806SHans Verkuil 
294*2a0c2806SHans Verkuil 	fmt->fmt.pix.width = zr->jpg_settings.img_width / zr->jpg_settings.hor_dcm;
295*2a0c2806SHans Verkuil 	fmt->fmt.pix.height = zr->jpg_settings.img_height * 2 /
296*2a0c2806SHans Verkuil 		(zr->jpg_settings.ver_dcm * zr->jpg_settings.tmp_dcm);
297*2a0c2806SHans Verkuil 	fmt->fmt.pix.sizeimage = zr->buffer_size;
298*2a0c2806SHans Verkuil 	fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
299*2a0c2806SHans Verkuil 	if (zr->jpg_settings.tmp_dcm == 1)
300*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = (zr->jpg_settings.odd_even ?
301*2a0c2806SHans Verkuil 				V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
302*2a0c2806SHans Verkuil 	else
303*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = (zr->jpg_settings.odd_even ?
304*2a0c2806SHans Verkuil 				V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
305*2a0c2806SHans Verkuil 	fmt->fmt.pix.bytesperline = 0;
306*2a0c2806SHans Verkuil 	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
307*2a0c2806SHans Verkuil 
308*2a0c2806SHans Verkuil 	return 0;
309*2a0c2806SHans Verkuil }
310*2a0c2806SHans Verkuil 
zoran_g_fmt_vid_cap(struct file * file,void * __fh,struct v4l2_format * fmt)311*2a0c2806SHans Verkuil static int zoran_g_fmt_vid_cap(struct file *file, void *__fh,
312*2a0c2806SHans Verkuil 			       struct v4l2_format *fmt)
313*2a0c2806SHans Verkuil {
314*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
315*2a0c2806SHans Verkuil 
316*2a0c2806SHans Verkuil 	if (zr->map_mode != ZORAN_MAP_MODE_RAW)
317*2a0c2806SHans Verkuil 		return zoran_g_fmt_vid_out(file, __fh, fmt);
318*2a0c2806SHans Verkuil 	fmt->fmt.pix.width = zr->v4l_settings.width;
319*2a0c2806SHans Verkuil 	fmt->fmt.pix.height = zr->v4l_settings.height;
320*2a0c2806SHans Verkuil 	fmt->fmt.pix.sizeimage = zr->buffer_size;
321*2a0c2806SHans Verkuil 	fmt->fmt.pix.pixelformat = zr->v4l_settings.format->fourcc;
322*2a0c2806SHans Verkuil 	fmt->fmt.pix.colorspace = zr->v4l_settings.format->colorspace;
323*2a0c2806SHans Verkuil 	fmt->fmt.pix.bytesperline = zr->v4l_settings.bytesperline;
324*2a0c2806SHans Verkuil 	if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2))
325*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
326*2a0c2806SHans Verkuil 	else
327*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = V4L2_FIELD_TOP;
328*2a0c2806SHans Verkuil 	return 0;
329*2a0c2806SHans Verkuil }
330*2a0c2806SHans Verkuil 
zoran_try_fmt_vid_out(struct file * file,void * __fh,struct v4l2_format * fmt)331*2a0c2806SHans Verkuil static int zoran_try_fmt_vid_out(struct file *file, void *__fh,
332*2a0c2806SHans Verkuil 				 struct v4l2_format *fmt)
333*2a0c2806SHans Verkuil {
334*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
335*2a0c2806SHans Verkuil 	struct zoran_jpg_settings settings;
336*2a0c2806SHans Verkuil 	int res = 0;
337*2a0c2806SHans Verkuil 
338*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
339*2a0c2806SHans Verkuil 		return -EINVAL;
340*2a0c2806SHans Verkuil 
341*2a0c2806SHans Verkuil 	settings = zr->jpg_settings;
342*2a0c2806SHans Verkuil 
343*2a0c2806SHans Verkuil 	/* we actually need to set 'real' parameters now */
344*2a0c2806SHans Verkuil 	if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT)
345*2a0c2806SHans Verkuil 		settings.tmp_dcm = 1;
346*2a0c2806SHans Verkuil 	else
347*2a0c2806SHans Verkuil 		settings.tmp_dcm = 2;
348*2a0c2806SHans Verkuil 	settings.decimation = 0;
349*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.height <= zr->jpg_settings.img_height / 2)
350*2a0c2806SHans Verkuil 		settings.ver_dcm = 2;
351*2a0c2806SHans Verkuil 	else
352*2a0c2806SHans Verkuil 		settings.ver_dcm = 1;
353*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 4)
354*2a0c2806SHans Verkuil 		settings.hor_dcm = 4;
355*2a0c2806SHans Verkuil 	else if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 2)
356*2a0c2806SHans Verkuil 		settings.hor_dcm = 2;
357*2a0c2806SHans Verkuil 	else
358*2a0c2806SHans Verkuil 		settings.hor_dcm = 1;
359*2a0c2806SHans Verkuil 	if (settings.tmp_dcm == 1)
360*2a0c2806SHans Verkuil 		settings.field_per_buff = 2;
361*2a0c2806SHans Verkuil 	else
362*2a0c2806SHans Verkuil 		settings.field_per_buff = 1;
363*2a0c2806SHans Verkuil 
364*2a0c2806SHans Verkuil 	if (settings.hor_dcm > 1) {
365*2a0c2806SHans Verkuil 		settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
366*2a0c2806SHans Verkuil 		settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
367*2a0c2806SHans Verkuil 	} else {
368*2a0c2806SHans Verkuil 		settings.img_x = 0;
369*2a0c2806SHans Verkuil 		settings.img_width = BUZ_MAX_WIDTH;
370*2a0c2806SHans Verkuil 	}
371*2a0c2806SHans Verkuil 
372*2a0c2806SHans Verkuil 	/* check */
373*2a0c2806SHans Verkuil 	res = zoran_check_jpg_settings(zr, &settings, 1);
374*2a0c2806SHans Verkuil 	if (res)
375*2a0c2806SHans Verkuil 		return res;
376*2a0c2806SHans Verkuil 
377*2a0c2806SHans Verkuil 	/* tell the user what we actually did */
378*2a0c2806SHans Verkuil 	fmt->fmt.pix.width = settings.img_width / settings.hor_dcm;
379*2a0c2806SHans Verkuil 	fmt->fmt.pix.height = settings.img_height * 2 /
380*2a0c2806SHans Verkuil 		(settings.tmp_dcm * settings.ver_dcm);
381*2a0c2806SHans Verkuil 	if (settings.tmp_dcm == 1)
382*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = (zr->jpg_settings.odd_even ?
383*2a0c2806SHans Verkuil 				V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
384*2a0c2806SHans Verkuil 	else
385*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = (zr->jpg_settings.odd_even ?
386*2a0c2806SHans Verkuil 				V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
387*2a0c2806SHans Verkuil 
388*2a0c2806SHans Verkuil 	fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings);
389*2a0c2806SHans Verkuil 	fmt->fmt.pix.bytesperline = 0;
390*2a0c2806SHans Verkuil 	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
391*2a0c2806SHans Verkuil 	return res;
392*2a0c2806SHans Verkuil }
393*2a0c2806SHans Verkuil 
zoran_try_fmt_vid_cap(struct file * file,void * __fh,struct v4l2_format * fmt)394*2a0c2806SHans Verkuil static int zoran_try_fmt_vid_cap(struct file *file, void *__fh,
395*2a0c2806SHans Verkuil 				 struct v4l2_format *fmt)
396*2a0c2806SHans Verkuil {
397*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
398*2a0c2806SHans Verkuil 	int bpp;
399*2a0c2806SHans Verkuil 	int i;
400*2a0c2806SHans Verkuil 
401*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
402*2a0c2806SHans Verkuil 		return zoran_try_fmt_vid_out(file, __fh, fmt);
403*2a0c2806SHans Verkuil 
404*2a0c2806SHans Verkuil 	for (i = 0; i < NUM_FORMATS; i++)
405*2a0c2806SHans Verkuil 		if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat)
406*2a0c2806SHans Verkuil 			break;
407*2a0c2806SHans Verkuil 
408*2a0c2806SHans Verkuil 	if (i == NUM_FORMATS) {
409*2a0c2806SHans Verkuil 		/* TODO do not return here to fix the TRY_FMT cannot handle an invalid pixelformat*/
410*2a0c2806SHans Verkuil 		return -EINVAL;
411*2a0c2806SHans Verkuil 	}
412*2a0c2806SHans Verkuil 
413*2a0c2806SHans Verkuil 	fmt->fmt.pix.pixelformat = zoran_formats[i].fourcc;
414*2a0c2806SHans Verkuil 	fmt->fmt.pix.colorspace = zoran_formats[i].colorspace;
415*2a0c2806SHans Verkuil 	if (BUZ_MAX_HEIGHT < (fmt->fmt.pix.height * 2))
416*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
417*2a0c2806SHans Verkuil 	else
418*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = V4L2_FIELD_TOP;
419*2a0c2806SHans Verkuil 
420*2a0c2806SHans Verkuil 	bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8);
421*2a0c2806SHans Verkuil 	v4l_bound_align_image(&fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH,
422*2a0c2806SHans Verkuil 			      bpp == 2 ? 1 : 2,
423*2a0c2806SHans Verkuil 			      &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT,
424*2a0c2806SHans Verkuil 			      0, 0);
425*2a0c2806SHans Verkuil 	fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * bpp;
426*2a0c2806SHans Verkuil 	fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline * fmt->fmt.pix.height;
427*2a0c2806SHans Verkuil 	return 0;
428*2a0c2806SHans Verkuil }
429*2a0c2806SHans Verkuil 
zoran_s_fmt_vid_out(struct file * file,void * __fh,struct v4l2_format * fmt)430*2a0c2806SHans Verkuil static int zoran_s_fmt_vid_out(struct file *file, void *__fh,
431*2a0c2806SHans Verkuil 			       struct v4l2_format *fmt)
432*2a0c2806SHans Verkuil {
433*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
434*2a0c2806SHans Verkuil 	__le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat);
435*2a0c2806SHans Verkuil 	struct zoran_jpg_settings settings;
436*2a0c2806SHans Verkuil 	int res = 0;
437*2a0c2806SHans Verkuil 
438*2a0c2806SHans Verkuil 	pci_dbg(zr->pci_dev, "size=%dx%d, fmt=0x%x (%4.4s)\n",
439*2a0c2806SHans Verkuil 		fmt->fmt.pix.width, fmt->fmt.pix.height,
440*2a0c2806SHans Verkuil 			fmt->fmt.pix.pixelformat,
441*2a0c2806SHans Verkuil 			(char *)&printformat);
442*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
443*2a0c2806SHans Verkuil 		return -EINVAL;
444*2a0c2806SHans Verkuil 
445*2a0c2806SHans Verkuil 	if (!fmt->fmt.pix.height || !fmt->fmt.pix.width)
446*2a0c2806SHans Verkuil 		return -EINVAL;
447*2a0c2806SHans Verkuil 
448*2a0c2806SHans Verkuil 	settings = zr->jpg_settings;
449*2a0c2806SHans Verkuil 
450*2a0c2806SHans Verkuil 	/* we actually need to set 'real' parameters now */
451*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT)
452*2a0c2806SHans Verkuil 		settings.tmp_dcm = 1;
453*2a0c2806SHans Verkuil 	else
454*2a0c2806SHans Verkuil 		settings.tmp_dcm = 2;
455*2a0c2806SHans Verkuil 	settings.decimation = 0;
456*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.height <= zr->jpg_settings.img_height / 2)
457*2a0c2806SHans Verkuil 		settings.ver_dcm = 2;
458*2a0c2806SHans Verkuil 	else
459*2a0c2806SHans Verkuil 		settings.ver_dcm = 1;
460*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 4)
461*2a0c2806SHans Verkuil 		settings.hor_dcm = 4;
462*2a0c2806SHans Verkuil 	else if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 2)
463*2a0c2806SHans Verkuil 		settings.hor_dcm = 2;
464*2a0c2806SHans Verkuil 	else
465*2a0c2806SHans Verkuil 		settings.hor_dcm = 1;
466*2a0c2806SHans Verkuil 	if (settings.tmp_dcm == 1)
467*2a0c2806SHans Verkuil 		settings.field_per_buff = 2;
468*2a0c2806SHans Verkuil 	else
469*2a0c2806SHans Verkuil 		settings.field_per_buff = 1;
470*2a0c2806SHans Verkuil 
471*2a0c2806SHans Verkuil 	if (settings.hor_dcm > 1) {
472*2a0c2806SHans Verkuil 		settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
473*2a0c2806SHans Verkuil 		settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
474*2a0c2806SHans Verkuil 	} else {
475*2a0c2806SHans Verkuil 		settings.img_x = 0;
476*2a0c2806SHans Verkuil 		settings.img_width = BUZ_MAX_WIDTH;
477*2a0c2806SHans Verkuil 	}
478*2a0c2806SHans Verkuil 
479*2a0c2806SHans Verkuil 	/* check */
480*2a0c2806SHans Verkuil 	res = zoran_check_jpg_settings(zr, &settings, 0);
481*2a0c2806SHans Verkuil 	if (res)
482*2a0c2806SHans Verkuil 		return res;
483*2a0c2806SHans Verkuil 
484*2a0c2806SHans Verkuil 	/* it's ok, so set them */
485*2a0c2806SHans Verkuil 	zr->jpg_settings = settings;
486*2a0c2806SHans Verkuil 
487*2a0c2806SHans Verkuil 	if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
488*2a0c2806SHans Verkuil 		zr->map_mode = ZORAN_MAP_MODE_JPG_REC;
489*2a0c2806SHans Verkuil 	else
490*2a0c2806SHans Verkuil 		zr->map_mode = ZORAN_MAP_MODE_JPG_PLAY;
491*2a0c2806SHans Verkuil 
492*2a0c2806SHans Verkuil 	zr->buffer_size = zoran_v4l2_calc_bufsize(&zr->jpg_settings);
493*2a0c2806SHans Verkuil 
494*2a0c2806SHans Verkuil 	/* tell the user what we actually did */
495*2a0c2806SHans Verkuil 	fmt->fmt.pix.width = settings.img_width / settings.hor_dcm;
496*2a0c2806SHans Verkuil 	fmt->fmt.pix.height = settings.img_height * 2 /
497*2a0c2806SHans Verkuil 		(settings.tmp_dcm * settings.ver_dcm);
498*2a0c2806SHans Verkuil 	if (settings.tmp_dcm == 1)
499*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = (zr->jpg_settings.odd_even ?
500*2a0c2806SHans Verkuil 				V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
501*2a0c2806SHans Verkuil 	else
502*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = (zr->jpg_settings.odd_even ?
503*2a0c2806SHans Verkuil 				V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
504*2a0c2806SHans Verkuil 	fmt->fmt.pix.bytesperline = 0;
505*2a0c2806SHans Verkuil 	fmt->fmt.pix.sizeimage = zr->buffer_size;
506*2a0c2806SHans Verkuil 	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
507*2a0c2806SHans Verkuil 	return res;
508*2a0c2806SHans Verkuil }
509*2a0c2806SHans Verkuil 
zoran_s_fmt_vid_cap(struct file * file,void * __fh,struct v4l2_format * fmt)510*2a0c2806SHans Verkuil static int zoran_s_fmt_vid_cap(struct file *file, void *__fh,
511*2a0c2806SHans Verkuil 			       struct v4l2_format *fmt)
512*2a0c2806SHans Verkuil {
513*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
514*2a0c2806SHans Verkuil 	struct zoran_fh *fh = __fh;
515*2a0c2806SHans Verkuil 	int i;
516*2a0c2806SHans Verkuil 	int res = 0;
517*2a0c2806SHans Verkuil 
518*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
519*2a0c2806SHans Verkuil 		return zoran_s_fmt_vid_out(file, fh, fmt);
520*2a0c2806SHans Verkuil 
521*2a0c2806SHans Verkuil 	for (i = 0; i < NUM_FORMATS; i++)
522*2a0c2806SHans Verkuil 		if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc)
523*2a0c2806SHans Verkuil 			break;
524*2a0c2806SHans Verkuil 	if (i == NUM_FORMATS) {
525*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "VIDIOC_S_FMT - unknown/unsupported format 0x%x\n",
526*2a0c2806SHans Verkuil 			fmt->fmt.pix.pixelformat);
527*2a0c2806SHans Verkuil 		/* TODO do not return here to fix the TRY_FMT cannot handle an invalid pixelformat*/
528*2a0c2806SHans Verkuil 		return -EINVAL;
529*2a0c2806SHans Verkuil 	}
530*2a0c2806SHans Verkuil 
531*2a0c2806SHans Verkuil 	fmt->fmt.pix.pixelformat = zoran_formats[i].fourcc;
532*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
533*2a0c2806SHans Verkuil 		fmt->fmt.pix.height = BUZ_MAX_HEIGHT;
534*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
535*2a0c2806SHans Verkuil 		fmt->fmt.pix.width = BUZ_MAX_WIDTH;
536*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
537*2a0c2806SHans Verkuil 		fmt->fmt.pix.height = BUZ_MIN_HEIGHT;
538*2a0c2806SHans Verkuil 	if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
539*2a0c2806SHans Verkuil 		fmt->fmt.pix.width = BUZ_MIN_WIDTH;
540*2a0c2806SHans Verkuil 
541*2a0c2806SHans Verkuil 	zr->map_mode = ZORAN_MAP_MODE_RAW;
542*2a0c2806SHans Verkuil 
543*2a0c2806SHans Verkuil 	res = zoran_v4l_set_format(zr, fmt->fmt.pix.width, fmt->fmt.pix.height,
544*2a0c2806SHans Verkuil 				   &zoran_formats[i]);
545*2a0c2806SHans Verkuil 	if (res)
546*2a0c2806SHans Verkuil 		return res;
547*2a0c2806SHans Verkuil 
548*2a0c2806SHans Verkuil 	/* tell the user the results/missing stuff */
549*2a0c2806SHans Verkuil 	fmt->fmt.pix.bytesperline = zr->v4l_settings.bytesperline;
550*2a0c2806SHans Verkuil 	fmt->fmt.pix.sizeimage = zr->buffer_size;
551*2a0c2806SHans Verkuil 	fmt->fmt.pix.colorspace = zr->v4l_settings.format->colorspace;
552*2a0c2806SHans Verkuil 	if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2))
553*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
554*2a0c2806SHans Verkuil 	else
555*2a0c2806SHans Verkuil 		fmt->fmt.pix.field = V4L2_FIELD_TOP;
556*2a0c2806SHans Verkuil 	return res;
557*2a0c2806SHans Verkuil }
558*2a0c2806SHans Verkuil 
zoran_g_std(struct file * file,void * __fh,v4l2_std_id * std)559*2a0c2806SHans Verkuil static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std)
560*2a0c2806SHans Verkuil {
561*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
562*2a0c2806SHans Verkuil 
563*2a0c2806SHans Verkuil 	*std = zr->norm;
564*2a0c2806SHans Verkuil 	return 0;
565*2a0c2806SHans Verkuil }
566*2a0c2806SHans Verkuil 
zoran_s_std(struct file * file,void * __fh,v4l2_std_id std)567*2a0c2806SHans Verkuil static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std)
568*2a0c2806SHans Verkuil {
569*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
570*2a0c2806SHans Verkuil 	int res = 0;
571*2a0c2806SHans Verkuil 
572*2a0c2806SHans Verkuil 	if (zr->norm == std)
573*2a0c2806SHans Verkuil 		return 0;
574*2a0c2806SHans Verkuil 
575*2a0c2806SHans Verkuil 	if (zr->running != ZORAN_MAP_MODE_NONE)
576*2a0c2806SHans Verkuil 		return -EBUSY;
577*2a0c2806SHans Verkuil 
578*2a0c2806SHans Verkuil 	res = zoran_set_norm(zr, std);
579*2a0c2806SHans Verkuil 	return res;
580*2a0c2806SHans Verkuil }
581*2a0c2806SHans Verkuil 
zoran_enum_input(struct file * file,void * __fh,struct v4l2_input * inp)582*2a0c2806SHans Verkuil static int zoran_enum_input(struct file *file, void *__fh,
583*2a0c2806SHans Verkuil 			    struct v4l2_input *inp)
584*2a0c2806SHans Verkuil {
585*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
586*2a0c2806SHans Verkuil 
587*2a0c2806SHans Verkuil 	if (inp->index >= zr->card.inputs)
588*2a0c2806SHans Verkuil 		return -EINVAL;
589*2a0c2806SHans Verkuil 
590*2a0c2806SHans Verkuil 	strscpy(inp->name, zr->card.input[inp->index].name, sizeof(inp->name));
591*2a0c2806SHans Verkuil 	inp->type = V4L2_INPUT_TYPE_CAMERA;
592*2a0c2806SHans Verkuil 	inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
593*2a0c2806SHans Verkuil 
594*2a0c2806SHans Verkuil 	/* Get status of video decoder */
595*2a0c2806SHans Verkuil 	decoder_call(zr, video, g_input_status, &inp->status);
596*2a0c2806SHans Verkuil 	return 0;
597*2a0c2806SHans Verkuil }
598*2a0c2806SHans Verkuil 
zoran_g_input(struct file * file,void * __fh,unsigned int * input)599*2a0c2806SHans Verkuil static int zoran_g_input(struct file *file, void *__fh, unsigned int *input)
600*2a0c2806SHans Verkuil {
601*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
602*2a0c2806SHans Verkuil 
603*2a0c2806SHans Verkuil 	*input = zr->input;
604*2a0c2806SHans Verkuil 
605*2a0c2806SHans Verkuil 	return 0;
606*2a0c2806SHans Verkuil }
607*2a0c2806SHans Verkuil 
zoran_s_input(struct file * file,void * __fh,unsigned int input)608*2a0c2806SHans Verkuil static int zoran_s_input(struct file *file, void *__fh, unsigned int input)
609*2a0c2806SHans Verkuil {
610*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
611*2a0c2806SHans Verkuil 	int res;
612*2a0c2806SHans Verkuil 
613*2a0c2806SHans Verkuil 	if (zr->running != ZORAN_MAP_MODE_NONE)
614*2a0c2806SHans Verkuil 		return -EBUSY;
615*2a0c2806SHans Verkuil 
616*2a0c2806SHans Verkuil 	res = zoran_set_input(zr, input);
617*2a0c2806SHans Verkuil 	return res;
618*2a0c2806SHans Verkuil }
619*2a0c2806SHans Verkuil 
620*2a0c2806SHans Verkuil /* cropping (sub-frame capture) */
zoran_g_selection(struct file * file,void * __fh,struct v4l2_selection * sel)621*2a0c2806SHans Verkuil static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel)
622*2a0c2806SHans Verkuil {
623*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
624*2a0c2806SHans Verkuil 
625*2a0c2806SHans Verkuil 	if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
626*2a0c2806SHans Verkuil 	    sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
627*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "%s invalid selection type combination\n", __func__);
628*2a0c2806SHans Verkuil 		return -EINVAL;
629*2a0c2806SHans Verkuil 	}
630*2a0c2806SHans Verkuil 
631*2a0c2806SHans Verkuil 	switch (sel->target) {
632*2a0c2806SHans Verkuil 	case V4L2_SEL_TGT_CROP:
633*2a0c2806SHans Verkuil 		sel->r.top = zr->jpg_settings.img_y;
634*2a0c2806SHans Verkuil 		sel->r.left = zr->jpg_settings.img_x;
635*2a0c2806SHans Verkuil 		sel->r.width = zr->jpg_settings.img_width;
636*2a0c2806SHans Verkuil 		sel->r.height = zr->jpg_settings.img_height;
637*2a0c2806SHans Verkuil 		break;
638*2a0c2806SHans Verkuil 	case V4L2_SEL_TGT_CROP_DEFAULT:
639*2a0c2806SHans Verkuil 		sel->r.top = 0;
640*2a0c2806SHans Verkuil 		sel->r.left = 0;
641*2a0c2806SHans Verkuil 		sel->r.width = BUZ_MIN_WIDTH;
642*2a0c2806SHans Verkuil 		sel->r.height = BUZ_MIN_HEIGHT;
643*2a0c2806SHans Verkuil 		break;
644*2a0c2806SHans Verkuil 	case V4L2_SEL_TGT_CROP_BOUNDS:
645*2a0c2806SHans Verkuil 		sel->r.top = 0;
646*2a0c2806SHans Verkuil 		sel->r.left = 0;
647*2a0c2806SHans Verkuil 		sel->r.width = BUZ_MAX_WIDTH;
648*2a0c2806SHans Verkuil 		sel->r.height = BUZ_MAX_HEIGHT;
649*2a0c2806SHans Verkuil 		break;
650*2a0c2806SHans Verkuil 	default:
651*2a0c2806SHans Verkuil 		return -EINVAL;
652*2a0c2806SHans Verkuil 	}
653*2a0c2806SHans Verkuil 	return 0;
654*2a0c2806SHans Verkuil }
655*2a0c2806SHans Verkuil 
zoran_s_selection(struct file * file,void * __fh,struct v4l2_selection * sel)656*2a0c2806SHans Verkuil static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selection *sel)
657*2a0c2806SHans Verkuil {
658*2a0c2806SHans Verkuil 	struct zoran *zr = video_drvdata(file);
659*2a0c2806SHans Verkuil 	struct zoran_jpg_settings settings;
660*2a0c2806SHans Verkuil 	int res;
661*2a0c2806SHans Verkuil 
662*2a0c2806SHans Verkuil 	if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
663*2a0c2806SHans Verkuil 	    sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
664*2a0c2806SHans Verkuil 		return -EINVAL;
665*2a0c2806SHans Verkuil 
666*2a0c2806SHans Verkuil 	if (!sel->r.width || !sel->r.height)
667*2a0c2806SHans Verkuil 		return -EINVAL;
668*2a0c2806SHans Verkuil 
669*2a0c2806SHans Verkuil 	if (sel->target != V4L2_SEL_TGT_CROP)
670*2a0c2806SHans Verkuil 		return -EINVAL;
671*2a0c2806SHans Verkuil 
672*2a0c2806SHans Verkuil 	if (zr->map_mode == ZORAN_MAP_MODE_RAW) {
673*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "VIDIOC_S_SELECTION - subcapture only supported for compressed capture\n");
674*2a0c2806SHans Verkuil 		return -EINVAL;
675*2a0c2806SHans Verkuil 	}
676*2a0c2806SHans Verkuil 
677*2a0c2806SHans Verkuil 	settings = zr->jpg_settings;
678*2a0c2806SHans Verkuil 
679*2a0c2806SHans Verkuil 	/* move into a form that we understand */
680*2a0c2806SHans Verkuil 	settings.img_x = sel->r.left;
681*2a0c2806SHans Verkuil 	settings.img_y = sel->r.top;
682*2a0c2806SHans Verkuil 	settings.img_width = sel->r.width;
683*2a0c2806SHans Verkuil 	settings.img_height = sel->r.height;
684*2a0c2806SHans Verkuil 
685*2a0c2806SHans Verkuil 	/* check validity */
686*2a0c2806SHans Verkuil 	res = zoran_check_jpg_settings(zr, &settings, 0);
687*2a0c2806SHans Verkuil 	if (res)
688*2a0c2806SHans Verkuil 		return res;
689*2a0c2806SHans Verkuil 
690*2a0c2806SHans Verkuil 	/* accept */
691*2a0c2806SHans Verkuil 	zr->jpg_settings = settings;
692*2a0c2806SHans Verkuil 	return res;
693*2a0c2806SHans Verkuil }
694*2a0c2806SHans Verkuil 
695*2a0c2806SHans Verkuil /*
696*2a0c2806SHans Verkuil  * Output is disabled temporarily
697*2a0c2806SHans Verkuil  * Zoran is picky about jpeg data it accepts. At least it seems to unsupport COM and APPn.
698*2a0c2806SHans Verkuil  * So until a way to filter data will be done, disable output.
699*2a0c2806SHans Verkuil  */
700*2a0c2806SHans Verkuil static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
701*2a0c2806SHans Verkuil 	.vidioc_querycap		    = zoran_querycap,
702*2a0c2806SHans Verkuil 	.vidioc_s_selection		    = zoran_s_selection,
703*2a0c2806SHans Verkuil 	.vidioc_g_selection		    = zoran_g_selection,
704*2a0c2806SHans Verkuil 	.vidioc_enum_input		    = zoran_enum_input,
705*2a0c2806SHans Verkuil 	.vidioc_g_input			    = zoran_g_input,
706*2a0c2806SHans Verkuil 	.vidioc_s_input			    = zoran_s_input,
707*2a0c2806SHans Verkuil 	.vidioc_g_std			    = zoran_g_std,
708*2a0c2806SHans Verkuil 	.vidioc_s_std			    = zoran_s_std,
709*2a0c2806SHans Verkuil 	.vidioc_create_bufs		    = vb2_ioctl_create_bufs,
710*2a0c2806SHans Verkuil 	.vidioc_reqbufs			    = vb2_ioctl_reqbufs,
711*2a0c2806SHans Verkuil 	.vidioc_querybuf		    = vb2_ioctl_querybuf,
712*2a0c2806SHans Verkuil 	.vidioc_qbuf			    = vb2_ioctl_qbuf,
713*2a0c2806SHans Verkuil 	.vidioc_dqbuf			    = vb2_ioctl_dqbuf,
714*2a0c2806SHans Verkuil 	.vidioc_expbuf                      = vb2_ioctl_expbuf,
715*2a0c2806SHans Verkuil 	.vidioc_streamon		    = vb2_ioctl_streamon,
716*2a0c2806SHans Verkuil 	.vidioc_streamoff		    = vb2_ioctl_streamoff,
717*2a0c2806SHans Verkuil 	.vidioc_enum_fmt_vid_cap	    = zoran_enum_fmt_vid_cap,
718*2a0c2806SHans Verkuil 	.vidioc_g_fmt_vid_cap		    = zoran_g_fmt_vid_cap,
719*2a0c2806SHans Verkuil 	.vidioc_s_fmt_vid_cap		    = zoran_s_fmt_vid_cap,
720*2a0c2806SHans Verkuil 	.vidioc_try_fmt_vid_cap		    = zoran_try_fmt_vid_cap,
721*2a0c2806SHans Verkuil 	.vidioc_subscribe_event             = v4l2_ctrl_subscribe_event,
722*2a0c2806SHans Verkuil 	.vidioc_unsubscribe_event           = v4l2_event_unsubscribe,
723*2a0c2806SHans Verkuil };
724*2a0c2806SHans Verkuil 
725*2a0c2806SHans Verkuil static const struct v4l2_file_operations zoran_fops = {
726*2a0c2806SHans Verkuil 	.owner = THIS_MODULE,
727*2a0c2806SHans Verkuil 	.unlocked_ioctl = video_ioctl2,
728*2a0c2806SHans Verkuil 	.open		= v4l2_fh_open,
729*2a0c2806SHans Verkuil 	.release	= vb2_fop_release,
730*2a0c2806SHans Verkuil 	.mmap		= vb2_fop_mmap,
731*2a0c2806SHans Verkuil 	.poll		= vb2_fop_poll,
732*2a0c2806SHans Verkuil };
733*2a0c2806SHans Verkuil 
734*2a0c2806SHans Verkuil const struct video_device zoran_template = {
735*2a0c2806SHans Verkuil 	.name = ZORAN_NAME,
736*2a0c2806SHans Verkuil 	.fops = &zoran_fops,
737*2a0c2806SHans Verkuil 	.ioctl_ops = &zoran_ioctl_ops,
738*2a0c2806SHans Verkuil 	.release = &zoran_vdev_release,
739*2a0c2806SHans Verkuil 	.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
740*2a0c2806SHans Verkuil };
741*2a0c2806SHans Verkuil 
zr_vb2_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])742*2a0c2806SHans Verkuil static int zr_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes,
743*2a0c2806SHans Verkuil 			      unsigned int sizes[], struct device *alloc_devs[])
744*2a0c2806SHans Verkuil {
745*2a0c2806SHans Verkuil 	struct zoran *zr = vb2_get_drv_priv(vq);
746*2a0c2806SHans Verkuil 	unsigned int size = zr->buffer_size;
747*2a0c2806SHans Verkuil 
748*2a0c2806SHans Verkuil 	pci_dbg(zr->pci_dev, "%s nbuf=%u nplanes=%u", __func__, *nbuffers, *nplanes);
749*2a0c2806SHans Verkuil 
750*2a0c2806SHans Verkuil 	zr->buf_in_reserve = 0;
751*2a0c2806SHans Verkuil 
752*2a0c2806SHans Verkuil 	if (*nbuffers < vq->min_buffers_needed)
753*2a0c2806SHans Verkuil 		*nbuffers = vq->min_buffers_needed;
754*2a0c2806SHans Verkuil 
755*2a0c2806SHans Verkuil 	if (*nplanes) {
756*2a0c2806SHans Verkuil 		if (sizes[0] < size)
757*2a0c2806SHans Verkuil 			return -EINVAL;
758*2a0c2806SHans Verkuil 		else
759*2a0c2806SHans Verkuil 			return 0;
760*2a0c2806SHans Verkuil 	}
761*2a0c2806SHans Verkuil 
762*2a0c2806SHans Verkuil 	*nplanes = 1;
763*2a0c2806SHans Verkuil 	sizes[0] = size;
764*2a0c2806SHans Verkuil 
765*2a0c2806SHans Verkuil 	return 0;
766*2a0c2806SHans Verkuil }
767*2a0c2806SHans Verkuil 
zr_vb2_queue(struct vb2_buffer * vb)768*2a0c2806SHans Verkuil static void zr_vb2_queue(struct vb2_buffer *vb)
769*2a0c2806SHans Verkuil {
770*2a0c2806SHans Verkuil 	struct zoran *zr = vb2_get_drv_priv(vb->vb2_queue);
771*2a0c2806SHans Verkuil 	struct zr_buffer *buf = vb2_to_zr_buffer(vb);
772*2a0c2806SHans Verkuil 	unsigned long flags;
773*2a0c2806SHans Verkuil 
774*2a0c2806SHans Verkuil 	spin_lock_irqsave(&zr->queued_bufs_lock, flags);
775*2a0c2806SHans Verkuil 	list_add_tail(&buf->queue, &zr->queued_bufs);
776*2a0c2806SHans Verkuil 	zr->buf_in_reserve++;
777*2a0c2806SHans Verkuil 	spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
778*2a0c2806SHans Verkuil 	if (zr->running == ZORAN_MAP_MODE_JPG_REC)
779*2a0c2806SHans Verkuil 		zoran_feed_stat_com(zr);
780*2a0c2806SHans Verkuil 	zr->queued++;
781*2a0c2806SHans Verkuil }
782*2a0c2806SHans Verkuil 
zr_vb2_prepare(struct vb2_buffer * vb)783*2a0c2806SHans Verkuil static int zr_vb2_prepare(struct vb2_buffer *vb)
784*2a0c2806SHans Verkuil {
785*2a0c2806SHans Verkuil 	struct zoran *zr = vb2_get_drv_priv(vb->vb2_queue);
786*2a0c2806SHans Verkuil 
787*2a0c2806SHans Verkuil 	if (vb2_plane_size(vb, 0) < zr->buffer_size)
788*2a0c2806SHans Verkuil 		return -EINVAL;
789*2a0c2806SHans Verkuil 	zr->prepared++;
790*2a0c2806SHans Verkuil 
791*2a0c2806SHans Verkuil 	return 0;
792*2a0c2806SHans Verkuil }
793*2a0c2806SHans Verkuil 
zr_set_buf(struct zoran * zr)794*2a0c2806SHans Verkuil int zr_set_buf(struct zoran *zr)
795*2a0c2806SHans Verkuil {
796*2a0c2806SHans Verkuil 	struct zr_buffer *buf;
797*2a0c2806SHans Verkuil 	struct vb2_v4l2_buffer *vbuf;
798*2a0c2806SHans Verkuil 	dma_addr_t phys_addr;
799*2a0c2806SHans Verkuil 	unsigned long flags;
800*2a0c2806SHans Verkuil 	u32 reg;
801*2a0c2806SHans Verkuil 
802*2a0c2806SHans Verkuil 	if (zr->running == ZORAN_MAP_MODE_NONE)
803*2a0c2806SHans Verkuil 		return 0;
804*2a0c2806SHans Verkuil 
805*2a0c2806SHans Verkuil 	if (zr->inuse[0]) {
806*2a0c2806SHans Verkuil 		buf = zr->inuse[0];
807*2a0c2806SHans Verkuil 		buf->vbuf.vb2_buf.timestamp = ktime_get_ns();
808*2a0c2806SHans Verkuil 		buf->vbuf.sequence = zr->vbseq++;
809*2a0c2806SHans Verkuil 		vbuf = &buf->vbuf;
810*2a0c2806SHans Verkuil 
811*2a0c2806SHans Verkuil 		buf->vbuf.field = V4L2_FIELD_INTERLACED;
812*2a0c2806SHans Verkuil 		if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2))
813*2a0c2806SHans Verkuil 			buf->vbuf.field = V4L2_FIELD_INTERLACED;
814*2a0c2806SHans Verkuil 		else
815*2a0c2806SHans Verkuil 			buf->vbuf.field = V4L2_FIELD_TOP;
816*2a0c2806SHans Verkuil 		vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, zr->buffer_size);
817*2a0c2806SHans Verkuil 		vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE);
818*2a0c2806SHans Verkuil 		zr->inuse[0] = NULL;
819*2a0c2806SHans Verkuil 	}
820*2a0c2806SHans Verkuil 
821*2a0c2806SHans Verkuil 	spin_lock_irqsave(&zr->queued_bufs_lock, flags);
822*2a0c2806SHans Verkuil 	if (list_empty(&zr->queued_bufs)) {
823*2a0c2806SHans Verkuil 		btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR);
824*2a0c2806SHans Verkuil 		vb2_queue_error(zr->video_dev->queue);
825*2a0c2806SHans Verkuil 		spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
826*2a0c2806SHans Verkuil 		return -EINVAL;
827*2a0c2806SHans Verkuil 	}
828*2a0c2806SHans Verkuil 	buf = list_first_entry_or_null(&zr->queued_bufs, struct zr_buffer, queue);
829*2a0c2806SHans Verkuil 	if (!buf) {
830*2a0c2806SHans Verkuil 		btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR);
831*2a0c2806SHans Verkuil 		vb2_queue_error(zr->video_dev->queue);
832*2a0c2806SHans Verkuil 		spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
833*2a0c2806SHans Verkuil 		return -EINVAL;
834*2a0c2806SHans Verkuil 	}
835*2a0c2806SHans Verkuil 	list_del(&buf->queue);
836*2a0c2806SHans Verkuil 	zr->buf_in_reserve--;
837*2a0c2806SHans Verkuil 	spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
838*2a0c2806SHans Verkuil 
839*2a0c2806SHans Verkuil 	vbuf = &buf->vbuf;
840*2a0c2806SHans Verkuil 	vbuf->vb2_buf.state = VB2_BUF_STATE_ACTIVE;
841*2a0c2806SHans Verkuil 	phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
842*2a0c2806SHans Verkuil 
843*2a0c2806SHans Verkuil 	if (!phys_addr)
844*2a0c2806SHans Verkuil 		return -EINVAL;
845*2a0c2806SHans Verkuil 
846*2a0c2806SHans Verkuil 	zr->inuse[0] = buf;
847*2a0c2806SHans Verkuil 
848*2a0c2806SHans Verkuil 	reg = phys_addr;
849*2a0c2806SHans Verkuil 	btwrite(reg, ZR36057_VDTR);
850*2a0c2806SHans Verkuil 	if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
851*2a0c2806SHans Verkuil 		reg += zr->v4l_settings.bytesperline;
852*2a0c2806SHans Verkuil 	btwrite(reg, ZR36057_VDBR);
853*2a0c2806SHans Verkuil 
854*2a0c2806SHans Verkuil 	reg = 0;
855*2a0c2806SHans Verkuil 	if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
856*2a0c2806SHans Verkuil 		reg += zr->v4l_settings.bytesperline;
857*2a0c2806SHans Verkuil 	reg = (reg << ZR36057_VSSFGR_DISP_STRIDE);
858*2a0c2806SHans Verkuil 	reg |= ZR36057_VSSFGR_VID_OVF;
859*2a0c2806SHans Verkuil 	reg |= ZR36057_VSSFGR_SNAP_SHOT;
860*2a0c2806SHans Verkuil 	reg |= ZR36057_VSSFGR_FRAME_GRAB;
861*2a0c2806SHans Verkuil 	btwrite(reg, ZR36057_VSSFGR);
862*2a0c2806SHans Verkuil 
863*2a0c2806SHans Verkuil 	btor(ZR36057_VDCR_VID_EN, ZR36057_VDCR);
864*2a0c2806SHans Verkuil 	return 0;
865*2a0c2806SHans Verkuil }
866*2a0c2806SHans Verkuil 
zr_vb2_start_streaming(struct vb2_queue * vq,unsigned int count)867*2a0c2806SHans Verkuil static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
868*2a0c2806SHans Verkuil {
869*2a0c2806SHans Verkuil 	struct zoran *zr = vq->drv_priv;
870*2a0c2806SHans Verkuil 	int j;
871*2a0c2806SHans Verkuil 
872*2a0c2806SHans Verkuil 	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
873*2a0c2806SHans Verkuil 		zr->stat_com[j] = cpu_to_le32(1);
874*2a0c2806SHans Verkuil 		zr->inuse[j] = NULL;
875*2a0c2806SHans Verkuil 	}
876*2a0c2806SHans Verkuil 	zr->vbseq = 0;
877*2a0c2806SHans Verkuil 
878*2a0c2806SHans Verkuil 	if (zr->map_mode != ZORAN_MAP_MODE_RAW) {
879*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "START JPG\n");
880*2a0c2806SHans Verkuil 		zr36057_restart(zr);
881*2a0c2806SHans Verkuil 		zoran_init_hardware(zr);
882*2a0c2806SHans Verkuil 		if (zr->map_mode == ZORAN_MAP_MODE_JPG_REC)
883*2a0c2806SHans Verkuil 			zr36057_enable_jpg(zr, BUZ_MODE_MOTION_DECOMPRESS);
884*2a0c2806SHans Verkuil 		else
885*2a0c2806SHans Verkuil 			zr36057_enable_jpg(zr, BUZ_MODE_MOTION_COMPRESS);
886*2a0c2806SHans Verkuil 		zoran_feed_stat_com(zr);
887*2a0c2806SHans Verkuil 		jpeg_start(zr);
888*2a0c2806SHans Verkuil 		zr->running = zr->map_mode;
889*2a0c2806SHans Verkuil 		btor(ZR36057_ICR_INT_PIN_EN, ZR36057_ICR);
890*2a0c2806SHans Verkuil 		return 0;
891*2a0c2806SHans Verkuil 	}
892*2a0c2806SHans Verkuil 
893*2a0c2806SHans Verkuil 	pci_dbg(zr->pci_dev, "START RAW\n");
894*2a0c2806SHans Verkuil 	zr36057_restart(zr);
895*2a0c2806SHans Verkuil 	zoran_init_hardware(zr);
896*2a0c2806SHans Verkuil 
897*2a0c2806SHans Verkuil 	zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
898*2a0c2806SHans Verkuil 	zr36057_set_memgrab(zr, 1);
899*2a0c2806SHans Verkuil 	zr->running = zr->map_mode;
900*2a0c2806SHans Verkuil 	btor(ZR36057_ICR_INT_PIN_EN, ZR36057_ICR);
901*2a0c2806SHans Verkuil 	return 0;
902*2a0c2806SHans Verkuil }
903*2a0c2806SHans Verkuil 
zr_vb2_stop_streaming(struct vb2_queue * vq)904*2a0c2806SHans Verkuil static void zr_vb2_stop_streaming(struct vb2_queue *vq)
905*2a0c2806SHans Verkuil {
906*2a0c2806SHans Verkuil 	struct zoran *zr = vq->drv_priv;
907*2a0c2806SHans Verkuil 	struct zr_buffer *buf;
908*2a0c2806SHans Verkuil 	unsigned long flags;
909*2a0c2806SHans Verkuil 	int j;
910*2a0c2806SHans Verkuil 
911*2a0c2806SHans Verkuil 	btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR);
912*2a0c2806SHans Verkuil 	if (zr->map_mode != ZORAN_MAP_MODE_RAW)
913*2a0c2806SHans Verkuil 		zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
914*2a0c2806SHans Verkuil 	zr36057_set_memgrab(zr, 0);
915*2a0c2806SHans Verkuil 	zr->running = ZORAN_MAP_MODE_NONE;
916*2a0c2806SHans Verkuil 
917*2a0c2806SHans Verkuil 	zoran_set_pci_master(zr, 0);
918*2a0c2806SHans Verkuil 
919*2a0c2806SHans Verkuil 	if (!pass_through) {	/* Switch to color bar */
920*2a0c2806SHans Verkuil 		decoder_call(zr, video, s_stream, 0);
921*2a0c2806SHans Verkuil 		encoder_call(zr, video, s_routing, 2, 0, 0);
922*2a0c2806SHans Verkuil 	}
923*2a0c2806SHans Verkuil 
924*2a0c2806SHans Verkuil 	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
925*2a0c2806SHans Verkuil 		zr->stat_com[j] = cpu_to_le32(1);
926*2a0c2806SHans Verkuil 		if (!zr->inuse[j])
927*2a0c2806SHans Verkuil 			continue;
928*2a0c2806SHans Verkuil 		buf = zr->inuse[j];
929*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "%s clean buf %d\n", __func__, j);
930*2a0c2806SHans Verkuil 		vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
931*2a0c2806SHans Verkuil 		zr->inuse[j] = NULL;
932*2a0c2806SHans Verkuil 	}
933*2a0c2806SHans Verkuil 
934*2a0c2806SHans Verkuil 	spin_lock_irqsave(&zr->queued_bufs_lock, flags);
935*2a0c2806SHans Verkuil 	while (!list_empty(&zr->queued_bufs)) {
936*2a0c2806SHans Verkuil 		buf = list_entry(zr->queued_bufs.next, struct zr_buffer, queue);
937*2a0c2806SHans Verkuil 		list_del(&buf->queue);
938*2a0c2806SHans Verkuil 		vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
939*2a0c2806SHans Verkuil 		zr->buf_in_reserve--;
940*2a0c2806SHans Verkuil 	}
941*2a0c2806SHans Verkuil 	spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
942*2a0c2806SHans Verkuil 	if (zr->buf_in_reserve)
943*2a0c2806SHans Verkuil 		pci_dbg(zr->pci_dev, "Buffer remaining %d\n", zr->buf_in_reserve);
944*2a0c2806SHans Verkuil 	zr->map_mode = ZORAN_MAP_MODE_RAW;
945*2a0c2806SHans Verkuil }
946*2a0c2806SHans Verkuil 
947*2a0c2806SHans Verkuil static const struct vb2_ops zr_video_qops = {
948*2a0c2806SHans Verkuil 	.queue_setup            = zr_vb2_queue_setup,
949*2a0c2806SHans Verkuil 	.buf_queue              = zr_vb2_queue,
950*2a0c2806SHans Verkuil 	.buf_prepare            = zr_vb2_prepare,
951*2a0c2806SHans Verkuil 	.start_streaming        = zr_vb2_start_streaming,
952*2a0c2806SHans Verkuil 	.stop_streaming         = zr_vb2_stop_streaming,
953*2a0c2806SHans Verkuil 	.wait_prepare           = vb2_ops_wait_prepare,
954*2a0c2806SHans Verkuil 	.wait_finish            = vb2_ops_wait_finish,
955*2a0c2806SHans Verkuil };
956*2a0c2806SHans Verkuil 
zoran_queue_init(struct zoran * zr,struct vb2_queue * vq,int dir)957*2a0c2806SHans Verkuil int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir)
958*2a0c2806SHans Verkuil {
959*2a0c2806SHans Verkuil 	int err;
960*2a0c2806SHans Verkuil 
961*2a0c2806SHans Verkuil 	spin_lock_init(&zr->queued_bufs_lock);
962*2a0c2806SHans Verkuil 	INIT_LIST_HEAD(&zr->queued_bufs);
963*2a0c2806SHans Verkuil 
964*2a0c2806SHans Verkuil 	vq->dev = &zr->pci_dev->dev;
965*2a0c2806SHans Verkuil 	vq->type = dir;
966*2a0c2806SHans Verkuil 
967*2a0c2806SHans Verkuil 	vq->io_modes = VB2_DMABUF | VB2_MMAP;
968*2a0c2806SHans Verkuil 	vq->drv_priv = zr;
969*2a0c2806SHans Verkuil 	vq->buf_struct_size = sizeof(struct zr_buffer);
970*2a0c2806SHans Verkuil 	vq->ops = &zr_video_qops;
971*2a0c2806SHans Verkuil 	vq->mem_ops = &vb2_dma_contig_memops;
972*2a0c2806SHans Verkuil 	vq->gfp_flags = GFP_DMA32;
973*2a0c2806SHans Verkuil 	vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
974*2a0c2806SHans Verkuil 	vq->min_buffers_needed = 9;
975*2a0c2806SHans Verkuil 	vq->lock = &zr->lock;
976*2a0c2806SHans Verkuil 	err = vb2_queue_init(vq);
977*2a0c2806SHans Verkuil 	if (err)
978*2a0c2806SHans Verkuil 		return err;
979*2a0c2806SHans Verkuil 	zr->video_dev->queue = vq;
980*2a0c2806SHans Verkuil 	return 0;
981*2a0c2806SHans Verkuil }
982*2a0c2806SHans Verkuil 
zoran_queue_exit(struct zoran * zr)983*2a0c2806SHans Verkuil void zoran_queue_exit(struct zoran *zr)
984*2a0c2806SHans Verkuil {
985*2a0c2806SHans Verkuil 	vb2_queue_release(zr->video_dev->queue);
986*2a0c2806SHans Verkuil }
987