xref: /OK3568_Linux_fs/kernel/drivers/media/usb/usbtv/usbtv-video.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2013,2016 Lubomir Rintel
3*4882a593Smuzhiyun  * All rights reserved.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Redistribution and use in source and binary forms, with or without
6*4882a593Smuzhiyun  * modification, are permitted provided that the following conditions
7*4882a593Smuzhiyun  * are met:
8*4882a593Smuzhiyun  * 1. Redistributions of source code must retain the above copyright
9*4882a593Smuzhiyun  *    notice, this list of conditions, and the following disclaimer,
10*4882a593Smuzhiyun  *    without modification.
11*4882a593Smuzhiyun  * 2. The name of the author may not be used to endorse or promote products
12*4882a593Smuzhiyun  *    derived from this software without specific prior written permission.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * Alternatively, this software may be distributed under the terms of the
15*4882a593Smuzhiyun  * GNU General Public License ("GPL").
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*4882a593Smuzhiyun  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*4882a593Smuzhiyun  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*4882a593Smuzhiyun  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*4882a593Smuzhiyun  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*4882a593Smuzhiyun  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*4882a593Smuzhiyun  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*4882a593Smuzhiyun  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*4882a593Smuzhiyun  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*4882a593Smuzhiyun  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*4882a593Smuzhiyun  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun /*
30*4882a593Smuzhiyun  * Fushicai USBTV007 Audio-Video Grabber Driver
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  * Product web site:
33*4882a593Smuzhiyun  * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * Following LWN articles were very useful in construction of this driver:
36*4882a593Smuzhiyun  * Video4Linux2 API series: http://lwn.net/Articles/203924/
37*4882a593Smuzhiyun  * videobuf2 API explanation: http://lwn.net/Articles/447435/
38*4882a593Smuzhiyun  * Thanks go to Jonathan Corbet for providing this quality documentation.
39*4882a593Smuzhiyun  * He is awesome.
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  * No physical hardware was harmed running Windows during the
42*4882a593Smuzhiyun  * reverse-engineering activity
43*4882a593Smuzhiyun  */
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
46*4882a593Smuzhiyun #include <media/videobuf2-v4l2.h>
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #include "usbtv.h"
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun static struct usbtv_norm_params norm_params[] = {
51*4882a593Smuzhiyun 	{
52*4882a593Smuzhiyun 		.norm = V4L2_STD_525_60,
53*4882a593Smuzhiyun 		.cap_width = 720,
54*4882a593Smuzhiyun 		.cap_height = 480,
55*4882a593Smuzhiyun 	},
56*4882a593Smuzhiyun 	{
57*4882a593Smuzhiyun 		.norm = V4L2_STD_625_50,
58*4882a593Smuzhiyun 		.cap_width = 720,
59*4882a593Smuzhiyun 		.cap_height = 576,
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
usbtv_configure_for_norm(struct usbtv * usbtv,v4l2_std_id norm)63*4882a593Smuzhiyun static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	int i, ret = 0;
66*4882a593Smuzhiyun 	struct usbtv_norm_params *params = NULL;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(norm_params); i++) {
69*4882a593Smuzhiyun 		if (norm_params[i].norm & norm) {
70*4882a593Smuzhiyun 			params = &norm_params[i];
71*4882a593Smuzhiyun 			break;
72*4882a593Smuzhiyun 		}
73*4882a593Smuzhiyun 	}
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	if (params) {
76*4882a593Smuzhiyun 		usbtv->width = params->cap_width;
77*4882a593Smuzhiyun 		usbtv->height = params->cap_height;
78*4882a593Smuzhiyun 		usbtv->n_chunks = usbtv->width * usbtv->height
79*4882a593Smuzhiyun 						/ 4 / USBTV_CHUNK;
80*4882a593Smuzhiyun 		usbtv->norm = norm;
81*4882a593Smuzhiyun 	} else
82*4882a593Smuzhiyun 		ret = -EINVAL;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	return ret;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
usbtv_select_input(struct usbtv * usbtv,int input)87*4882a593Smuzhiyun static int usbtv_select_input(struct usbtv *usbtv, int input)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	int ret;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	static const u16 composite[][2] = {
92*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0105, 0x0060 },
93*4882a593Smuzhiyun 		{ USBTV_BASE + 0x011f, 0x00f2 },
94*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0127, 0x0060 },
95*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00ae, 0x0010 },
96*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0239, 0x0060 },
97*4882a593Smuzhiyun 	};
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	static const u16 svideo[][2] = {
100*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0105, 0x0010 },
101*4882a593Smuzhiyun 		{ USBTV_BASE + 0x011f, 0x00ff },
102*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0127, 0x0060 },
103*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00ae, 0x0030 },
104*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0239, 0x0060 },
105*4882a593Smuzhiyun 	};
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	switch (input) {
108*4882a593Smuzhiyun 	case USBTV_COMPOSITE_INPUT:
109*4882a593Smuzhiyun 		ret = usbtv_set_regs(usbtv, composite, ARRAY_SIZE(composite));
110*4882a593Smuzhiyun 		break;
111*4882a593Smuzhiyun 	case USBTV_SVIDEO_INPUT:
112*4882a593Smuzhiyun 		ret = usbtv_set_regs(usbtv, svideo, ARRAY_SIZE(svideo));
113*4882a593Smuzhiyun 		break;
114*4882a593Smuzhiyun 	default:
115*4882a593Smuzhiyun 		ret = -EINVAL;
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (!ret)
119*4882a593Smuzhiyun 		usbtv->input = input;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return ret;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
usbtv_norm_to_16f_reg(v4l2_std_id norm)124*4882a593Smuzhiyun static uint16_t usbtv_norm_to_16f_reg(v4l2_std_id norm)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	/* NTSC M/M-JP/M-KR */
127*4882a593Smuzhiyun 	if (norm & V4L2_STD_NTSC)
128*4882a593Smuzhiyun 		return 0x00b8;
129*4882a593Smuzhiyun 	/* PAL BG/DK/H/I */
130*4882a593Smuzhiyun 	if (norm & V4L2_STD_PAL)
131*4882a593Smuzhiyun 		return 0x00ee;
132*4882a593Smuzhiyun 	/* SECAM B/D/G/H/K/K1/L/Lc */
133*4882a593Smuzhiyun 	if (norm & V4L2_STD_SECAM)
134*4882a593Smuzhiyun 		return 0x00ff;
135*4882a593Smuzhiyun 	if (norm & V4L2_STD_NTSC_443)
136*4882a593Smuzhiyun 		return 0x00a8;
137*4882a593Smuzhiyun 	if (norm & (V4L2_STD_PAL_M | V4L2_STD_PAL_60))
138*4882a593Smuzhiyun 		return 0x00bc;
139*4882a593Smuzhiyun 	/* Fallback to automatic detection for other standards */
140*4882a593Smuzhiyun 	return 0x0000;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
usbtv_select_norm(struct usbtv * usbtv,v4l2_std_id norm)143*4882a593Smuzhiyun static int usbtv_select_norm(struct usbtv *usbtv, v4l2_std_id norm)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	int ret;
146*4882a593Smuzhiyun 	/* These are the series of register values used to configure the
147*4882a593Smuzhiyun 	 * decoder for a specific standard.
148*4882a593Smuzhiyun 	 * The first 21 register writes are copied from the
149*4882a593Smuzhiyun 	 * Settings\DecoderDefaults registry keys present in the Windows driver
150*4882a593Smuzhiyun 	 * .INF file, and control various image tuning parameters (color
151*4882a593Smuzhiyun 	 * correction, sharpness, ...).
152*4882a593Smuzhiyun 	 */
153*4882a593Smuzhiyun 	static const u16 pal[][2] = {
154*4882a593Smuzhiyun 		/* "AVPAL" tuning sequence from .INF file */
155*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0003, 0x0004 },
156*4882a593Smuzhiyun 		{ USBTV_BASE + 0x001a, 0x0068 },
157*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0100, 0x00d3 },
158*4882a593Smuzhiyun 		{ USBTV_BASE + 0x010e, 0x0072 },
159*4882a593Smuzhiyun 		{ USBTV_BASE + 0x010f, 0x00a2 },
160*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0112, 0x00b0 },
161*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0115, 0x0015 },
162*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0117, 0x0001 },
163*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0118, 0x002c },
164*4882a593Smuzhiyun 		{ USBTV_BASE + 0x012d, 0x0010 },
165*4882a593Smuzhiyun 		{ USBTV_BASE + 0x012f, 0x0020 },
166*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0220, 0x002e },
167*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0225, 0x0008 },
168*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024e, 0x0002 },
169*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024f, 0x0002 },
170*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0254, 0x0059 },
171*4882a593Smuzhiyun 		{ USBTV_BASE + 0x025a, 0x0016 },
172*4882a593Smuzhiyun 		{ USBTV_BASE + 0x025b, 0x0035 },
173*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0263, 0x0017 },
174*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0266, 0x0016 },
175*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0267, 0x0036 },
176*4882a593Smuzhiyun 		/* End image tuning */
177*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024e, 0x0002 },
178*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024f, 0x0002 },
179*4882a593Smuzhiyun 	};
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	static const u16 ntsc[][2] = {
182*4882a593Smuzhiyun 		/* "AVNTSC" tuning sequence from .INF file */
183*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0003, 0x0004 },
184*4882a593Smuzhiyun 		{ USBTV_BASE + 0x001a, 0x0079 },
185*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0100, 0x00d3 },
186*4882a593Smuzhiyun 		{ USBTV_BASE + 0x010e, 0x0068 },
187*4882a593Smuzhiyun 		{ USBTV_BASE + 0x010f, 0x009c },
188*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0112, 0x00f0 },
189*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0115, 0x0015 },
190*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0117, 0x0000 },
191*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0118, 0x00fc },
192*4882a593Smuzhiyun 		{ USBTV_BASE + 0x012d, 0x0004 },
193*4882a593Smuzhiyun 		{ USBTV_BASE + 0x012f, 0x0008 },
194*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0220, 0x002e },
195*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0225, 0x0008 },
196*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024e, 0x0002 },
197*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024f, 0x0001 },
198*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0254, 0x005f },
199*4882a593Smuzhiyun 		{ USBTV_BASE + 0x025a, 0x0012 },
200*4882a593Smuzhiyun 		{ USBTV_BASE + 0x025b, 0x0001 },
201*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0263, 0x001c },
202*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0266, 0x0011 },
203*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0267, 0x0005 },
204*4882a593Smuzhiyun 		/* End image tuning */
205*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024e, 0x0002 },
206*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024f, 0x0002 },
207*4882a593Smuzhiyun 	};
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	static const u16 secam[][2] = {
210*4882a593Smuzhiyun 		/* "AVSECAM" tuning sequence from .INF file */
211*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0003, 0x0004 },
212*4882a593Smuzhiyun 		{ USBTV_BASE + 0x001a, 0x0073 },
213*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0100, 0x00dc },
214*4882a593Smuzhiyun 		{ USBTV_BASE + 0x010e, 0x0072 },
215*4882a593Smuzhiyun 		{ USBTV_BASE + 0x010f, 0x00a2 },
216*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0112, 0x0090 },
217*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0115, 0x0035 },
218*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0117, 0x0001 },
219*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0118, 0x0030 },
220*4882a593Smuzhiyun 		{ USBTV_BASE + 0x012d, 0x0004 },
221*4882a593Smuzhiyun 		{ USBTV_BASE + 0x012f, 0x0008 },
222*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0220, 0x002d },
223*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0225, 0x0028 },
224*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024e, 0x0008 },
225*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024f, 0x0002 },
226*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0254, 0x0069 },
227*4882a593Smuzhiyun 		{ USBTV_BASE + 0x025a, 0x0016 },
228*4882a593Smuzhiyun 		{ USBTV_BASE + 0x025b, 0x0035 },
229*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0263, 0x0021 },
230*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0266, 0x0016 },
231*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0267, 0x0036 },
232*4882a593Smuzhiyun 		/* End image tuning */
233*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024e, 0x0002 },
234*4882a593Smuzhiyun 		{ USBTV_BASE + 0x024f, 0x0002 },
235*4882a593Smuzhiyun 	};
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	ret = usbtv_configure_for_norm(usbtv, norm);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (!ret) {
240*4882a593Smuzhiyun 		/* Masks for norms using a NTSC or PAL color encoding. */
241*4882a593Smuzhiyun 		static const v4l2_std_id ntsc_mask =
242*4882a593Smuzhiyun 			V4L2_STD_NTSC | V4L2_STD_NTSC_443;
243*4882a593Smuzhiyun 		static const v4l2_std_id pal_mask =
244*4882a593Smuzhiyun 			V4L2_STD_PAL | V4L2_STD_PAL_60 | V4L2_STD_PAL_M;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 		if (norm & ntsc_mask)
247*4882a593Smuzhiyun 			ret = usbtv_set_regs(usbtv, ntsc, ARRAY_SIZE(ntsc));
248*4882a593Smuzhiyun 		else if (norm & pal_mask)
249*4882a593Smuzhiyun 			ret = usbtv_set_regs(usbtv, pal, ARRAY_SIZE(pal));
250*4882a593Smuzhiyun 		else if (norm & V4L2_STD_SECAM)
251*4882a593Smuzhiyun 			ret = usbtv_set_regs(usbtv, secam, ARRAY_SIZE(secam));
252*4882a593Smuzhiyun 		else
253*4882a593Smuzhiyun 			ret = -EINVAL;
254*4882a593Smuzhiyun 	}
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (!ret) {
257*4882a593Smuzhiyun 		/* Configure the decoder for the color standard */
258*4882a593Smuzhiyun 		const u16 cfg[][2] = {
259*4882a593Smuzhiyun 			{ USBTV_BASE + 0x016f, usbtv_norm_to_16f_reg(norm) }
260*4882a593Smuzhiyun 		};
261*4882a593Smuzhiyun 		ret = usbtv_set_regs(usbtv, cfg, ARRAY_SIZE(cfg));
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	return ret;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
usbtv_setup_capture(struct usbtv * usbtv)267*4882a593Smuzhiyun static int usbtv_setup_capture(struct usbtv *usbtv)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	int ret;
270*4882a593Smuzhiyun 	static const u16 setup[][2] = {
271*4882a593Smuzhiyun 		/* These seem to enable the device. */
272*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0008, 0x0001 },
273*4882a593Smuzhiyun 		{ USBTV_BASE + 0x01d0, 0x00ff },
274*4882a593Smuzhiyun 		{ USBTV_BASE + 0x01d9, 0x0002 },
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 		/* These seem to influence color parameters, such as
277*4882a593Smuzhiyun 		 * brightness, etc. */
278*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0239, 0x0040 },
279*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0240, 0x0000 },
280*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0241, 0x0000 },
281*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0242, 0x0002 },
282*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0243, 0x0080 },
283*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0244, 0x0012 },
284*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0245, 0x0090 },
285*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0246, 0x0000 },
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0278, 0x002d },
288*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0279, 0x000a },
289*4882a593Smuzhiyun 		{ USBTV_BASE + 0x027a, 0x0032 },
290*4882a593Smuzhiyun 		{ 0xf890, 0x000c },
291*4882a593Smuzhiyun 		{ 0xf894, 0x0086 },
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00ac, 0x00c0 },
294*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00ad, 0x0000 },
295*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00a2, 0x0012 },
296*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00a3, 0x00e0 },
297*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00a4, 0x0028 },
298*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00a5, 0x0082 },
299*4882a593Smuzhiyun 		{ USBTV_BASE + 0x00a7, 0x0080 },
300*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0000, 0x0014 },
301*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0006, 0x0003 },
302*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0090, 0x0099 },
303*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0091, 0x0090 },
304*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0094, 0x0068 },
305*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0095, 0x0070 },
306*4882a593Smuzhiyun 		{ USBTV_BASE + 0x009c, 0x0030 },
307*4882a593Smuzhiyun 		{ USBTV_BASE + 0x009d, 0x00c0 },
308*4882a593Smuzhiyun 		{ USBTV_BASE + 0x009e, 0x00e0 },
309*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0019, 0x0006 },
310*4882a593Smuzhiyun 		{ USBTV_BASE + 0x008c, 0x00ba },
311*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0101, 0x00ff },
312*4882a593Smuzhiyun 		{ USBTV_BASE + 0x010c, 0x00b3 },
313*4882a593Smuzhiyun 		{ USBTV_BASE + 0x01b2, 0x0080 },
314*4882a593Smuzhiyun 		{ USBTV_BASE + 0x01b4, 0x00a0 },
315*4882a593Smuzhiyun 		{ USBTV_BASE + 0x014c, 0x00ff },
316*4882a593Smuzhiyun 		{ USBTV_BASE + 0x014d, 0x00ca },
317*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0113, 0x0053 },
318*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0119, 0x008a },
319*4882a593Smuzhiyun 		{ USBTV_BASE + 0x013c, 0x0003 },
320*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0150, 0x009c },
321*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0151, 0x0071 },
322*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0152, 0x00c6 },
323*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0153, 0x0084 },
324*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0154, 0x00bc },
325*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0155, 0x00a0 },
326*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0156, 0x00a0 },
327*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0157, 0x009c },
328*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0158, 0x001f },
329*4882a593Smuzhiyun 		{ USBTV_BASE + 0x0159, 0x0006 },
330*4882a593Smuzhiyun 		{ USBTV_BASE + 0x015d, 0x0000 },
331*4882a593Smuzhiyun 	};
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	ret = usbtv_set_regs(usbtv, setup, ARRAY_SIZE(setup));
334*4882a593Smuzhiyun 	if (ret)
335*4882a593Smuzhiyun 		return ret;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	ret = usbtv_select_norm(usbtv, usbtv->norm);
338*4882a593Smuzhiyun 	if (ret)
339*4882a593Smuzhiyun 		return ret;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	ret = usbtv_select_input(usbtv, usbtv->input);
342*4882a593Smuzhiyun 	if (ret)
343*4882a593Smuzhiyun 		return ret;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	ret = v4l2_ctrl_handler_setup(&usbtv->ctrl);
346*4882a593Smuzhiyun 	if (ret)
347*4882a593Smuzhiyun 		return ret;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	return 0;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun /* Copy data from chunk into a frame buffer, deinterlacing the data
353*4882a593Smuzhiyun  * into every second line. Unfortunately, they don't align nicely into
354*4882a593Smuzhiyun  * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
355*4882a593Smuzhiyun  * Therefore, we break down the chunk into two halves before copying,
356*4882a593Smuzhiyun  * so that we can interleave a line if needed.
357*4882a593Smuzhiyun  *
358*4882a593Smuzhiyun  * Each "chunk" is 240 words; a word in this context equals 4 bytes.
359*4882a593Smuzhiyun  * Image format is YUYV/YUV 4:2:2, consisting of Y Cr Y Cb, defining two
360*4882a593Smuzhiyun  * pixels, the Cr and Cb shared between the two pixels, but each having
361*4882a593Smuzhiyun  * separate Y values. Thus, the 240 words equal 480 pixels. It therefore,
362*4882a593Smuzhiyun  * takes 1.5 chunks to make a 720 pixel-wide line for the frame.
363*4882a593Smuzhiyun  * The image is interlaced, so there is a "scan" of odd lines, followed
364*4882a593Smuzhiyun  * by "scan" of even numbered lines.
365*4882a593Smuzhiyun  *
366*4882a593Smuzhiyun  * Following code is writing the chunks in correct sequence, skipping
367*4882a593Smuzhiyun  * the rows based on "odd" value.
368*4882a593Smuzhiyun  * line 1: chunk[0][  0..479] chunk[0][480..959] chunk[1][  0..479]
369*4882a593Smuzhiyun  * line 3: chunk[1][480..959] chunk[2][  0..479] chunk[2][480..959]
370*4882a593Smuzhiyun  * ...etc.
371*4882a593Smuzhiyun  */
usbtv_chunk_to_vbuf(u32 * frame,__be32 * src,int chunk_no,int odd)372*4882a593Smuzhiyun static void usbtv_chunk_to_vbuf(u32 *frame, __be32 *src, int chunk_no, int odd)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	int half;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	for (half = 0; half < 2; half++) {
377*4882a593Smuzhiyun 		int part_no = chunk_no * 2 + half;
378*4882a593Smuzhiyun 		int line = part_no / 3;
379*4882a593Smuzhiyun 		int part_index = (line * 2 + !odd) * 3 + (part_no % 3);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 		u32 *dst = &frame[part_index * USBTV_CHUNK/2];
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 		memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src));
384*4882a593Smuzhiyun 		src += USBTV_CHUNK/2;
385*4882a593Smuzhiyun 	}
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun /* Called for each 256-byte image chunk.
389*4882a593Smuzhiyun  * First word identifies the chunk, followed by 240 words of image
390*4882a593Smuzhiyun  * data and padding. */
usbtv_image_chunk(struct usbtv * usbtv,__be32 * chunk)391*4882a593Smuzhiyun static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	int frame_id, odd, chunk_no;
394*4882a593Smuzhiyun 	u32 *frame;
395*4882a593Smuzhiyun 	struct usbtv_buf *buf;
396*4882a593Smuzhiyun 	unsigned long flags;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	/* Ignore corrupted lines. */
399*4882a593Smuzhiyun 	if (!USBTV_MAGIC_OK(chunk))
400*4882a593Smuzhiyun 		return;
401*4882a593Smuzhiyun 	frame_id = USBTV_FRAME_ID(chunk);
402*4882a593Smuzhiyun 	odd = USBTV_ODD(chunk);
403*4882a593Smuzhiyun 	chunk_no = USBTV_CHUNK_NO(chunk);
404*4882a593Smuzhiyun 	if (chunk_no >= usbtv->n_chunks)
405*4882a593Smuzhiyun 		return;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	/* Beginning of a frame. */
408*4882a593Smuzhiyun 	if (chunk_no == 0) {
409*4882a593Smuzhiyun 		usbtv->frame_id = frame_id;
410*4882a593Smuzhiyun 		usbtv->chunks_done = 0;
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	if (usbtv->frame_id != frame_id)
414*4882a593Smuzhiyun 		return;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	spin_lock_irqsave(&usbtv->buflock, flags);
417*4882a593Smuzhiyun 	if (list_empty(&usbtv->bufs)) {
418*4882a593Smuzhiyun 		/* No free buffers. Userspace likely too slow. */
419*4882a593Smuzhiyun 		spin_unlock_irqrestore(&usbtv->buflock, flags);
420*4882a593Smuzhiyun 		return;
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	/* First available buffer. */
424*4882a593Smuzhiyun 	buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list);
425*4882a593Smuzhiyun 	frame = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	/* Copy the chunk data. */
428*4882a593Smuzhiyun 	usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd);
429*4882a593Smuzhiyun 	usbtv->chunks_done++;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	/* Last chunk in a field */
432*4882a593Smuzhiyun 	if (chunk_no == usbtv->n_chunks-1) {
433*4882a593Smuzhiyun 		/* Last chunk in a frame, signalling an end */
434*4882a593Smuzhiyun 		if (odd && !usbtv->last_odd) {
435*4882a593Smuzhiyun 			int size = vb2_plane_size(&buf->vb.vb2_buf, 0);
436*4882a593Smuzhiyun 			enum vb2_buffer_state state = usbtv->chunks_done ==
437*4882a593Smuzhiyun 				usbtv->n_chunks ?
438*4882a593Smuzhiyun 				VB2_BUF_STATE_DONE :
439*4882a593Smuzhiyun 				VB2_BUF_STATE_ERROR;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 			buf->vb.field = V4L2_FIELD_INTERLACED;
442*4882a593Smuzhiyun 			buf->vb.sequence = usbtv->sequence++;
443*4882a593Smuzhiyun 			buf->vb.vb2_buf.timestamp = ktime_get_ns();
444*4882a593Smuzhiyun 			vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
445*4882a593Smuzhiyun 			vb2_buffer_done(&buf->vb.vb2_buf, state);
446*4882a593Smuzhiyun 			list_del(&buf->list);
447*4882a593Smuzhiyun 		}
448*4882a593Smuzhiyun 		usbtv->last_odd = odd;
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	spin_unlock_irqrestore(&usbtv->buflock, flags);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun /* Got image data. Each packet contains a number of 256-word chunks we
455*4882a593Smuzhiyun  * compose the image from. */
usbtv_iso_cb(struct urb * ip)456*4882a593Smuzhiyun static void usbtv_iso_cb(struct urb *ip)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun 	int ret;
459*4882a593Smuzhiyun 	int i;
460*4882a593Smuzhiyun 	struct usbtv *usbtv = (struct usbtv *)ip->context;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	switch (ip->status) {
463*4882a593Smuzhiyun 	/* All fine. */
464*4882a593Smuzhiyun 	case 0:
465*4882a593Smuzhiyun 		break;
466*4882a593Smuzhiyun 	/* Device disconnected or capture stopped? */
467*4882a593Smuzhiyun 	case -ENODEV:
468*4882a593Smuzhiyun 	case -ENOENT:
469*4882a593Smuzhiyun 	case -ECONNRESET:
470*4882a593Smuzhiyun 	case -ESHUTDOWN:
471*4882a593Smuzhiyun 		return;
472*4882a593Smuzhiyun 	/* Unknown error. Retry. */
473*4882a593Smuzhiyun 	default:
474*4882a593Smuzhiyun 		dev_warn(usbtv->dev, "Bad response for ISO request.\n");
475*4882a593Smuzhiyun 		goto resubmit;
476*4882a593Smuzhiyun 	}
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	for (i = 0; i < ip->number_of_packets; i++) {
479*4882a593Smuzhiyun 		int size = ip->iso_frame_desc[i].actual_length;
480*4882a593Smuzhiyun 		unsigned char *data = ip->transfer_buffer +
481*4882a593Smuzhiyun 				ip->iso_frame_desc[i].offset;
482*4882a593Smuzhiyun 		int offset;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 		for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++)
485*4882a593Smuzhiyun 			usbtv_image_chunk(usbtv,
486*4882a593Smuzhiyun 				(__be32 *)&data[USBTV_CHUNK_SIZE * offset]);
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun resubmit:
490*4882a593Smuzhiyun 	ret = usb_submit_urb(ip, GFP_ATOMIC);
491*4882a593Smuzhiyun 	if (ret < 0)
492*4882a593Smuzhiyun 		dev_warn(usbtv->dev, "Could not resubmit ISO URB\n");
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
usbtv_setup_iso_transfer(struct usbtv * usbtv)495*4882a593Smuzhiyun static struct urb *usbtv_setup_iso_transfer(struct usbtv *usbtv)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun 	struct urb *ip;
498*4882a593Smuzhiyun 	int size = usbtv->iso_size;
499*4882a593Smuzhiyun 	int i;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	ip = usb_alloc_urb(USBTV_ISOC_PACKETS, GFP_KERNEL);
502*4882a593Smuzhiyun 	if (ip == NULL)
503*4882a593Smuzhiyun 		return NULL;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	ip->dev = usbtv->udev;
506*4882a593Smuzhiyun 	ip->context = usbtv;
507*4882a593Smuzhiyun 	ip->pipe = usb_rcvisocpipe(usbtv->udev, USBTV_VIDEO_ENDP);
508*4882a593Smuzhiyun 	ip->interval = 1;
509*4882a593Smuzhiyun 	ip->transfer_flags = URB_ISO_ASAP;
510*4882a593Smuzhiyun 	ip->transfer_buffer = kcalloc(USBTV_ISOC_PACKETS, size,
511*4882a593Smuzhiyun 						GFP_KERNEL);
512*4882a593Smuzhiyun 	if (!ip->transfer_buffer) {
513*4882a593Smuzhiyun 		usb_free_urb(ip);
514*4882a593Smuzhiyun 		return NULL;
515*4882a593Smuzhiyun 	}
516*4882a593Smuzhiyun 	ip->complete = usbtv_iso_cb;
517*4882a593Smuzhiyun 	ip->number_of_packets = USBTV_ISOC_PACKETS;
518*4882a593Smuzhiyun 	ip->transfer_buffer_length = size * USBTV_ISOC_PACKETS;
519*4882a593Smuzhiyun 	for (i = 0; i < USBTV_ISOC_PACKETS; i++) {
520*4882a593Smuzhiyun 		ip->iso_frame_desc[i].offset = size * i;
521*4882a593Smuzhiyun 		ip->iso_frame_desc[i].length = size;
522*4882a593Smuzhiyun 	}
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	return ip;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun 
usbtv_stop(struct usbtv * usbtv)527*4882a593Smuzhiyun static void usbtv_stop(struct usbtv *usbtv)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	int i;
530*4882a593Smuzhiyun 	unsigned long flags;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	/* Cancel running transfers. */
533*4882a593Smuzhiyun 	for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
534*4882a593Smuzhiyun 		struct urb *ip = usbtv->isoc_urbs[i];
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 		if (ip == NULL)
537*4882a593Smuzhiyun 			continue;
538*4882a593Smuzhiyun 		usb_kill_urb(ip);
539*4882a593Smuzhiyun 		kfree(ip->transfer_buffer);
540*4882a593Smuzhiyun 		usb_free_urb(ip);
541*4882a593Smuzhiyun 		usbtv->isoc_urbs[i] = NULL;
542*4882a593Smuzhiyun 	}
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	/* Return buffers to userspace. */
545*4882a593Smuzhiyun 	spin_lock_irqsave(&usbtv->buflock, flags);
546*4882a593Smuzhiyun 	while (!list_empty(&usbtv->bufs)) {
547*4882a593Smuzhiyun 		struct usbtv_buf *buf = list_first_entry(&usbtv->bufs,
548*4882a593Smuzhiyun 						struct usbtv_buf, list);
549*4882a593Smuzhiyun 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
550*4882a593Smuzhiyun 		list_del(&buf->list);
551*4882a593Smuzhiyun 	}
552*4882a593Smuzhiyun 	spin_unlock_irqrestore(&usbtv->buflock, flags);
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
usbtv_start(struct usbtv * usbtv)555*4882a593Smuzhiyun static int usbtv_start(struct usbtv *usbtv)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun 	int i;
558*4882a593Smuzhiyun 	int ret;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	usbtv_audio_suspend(usbtv);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	ret = usb_set_interface(usbtv->udev, 0, 0);
563*4882a593Smuzhiyun 	if (ret < 0)
564*4882a593Smuzhiyun 		return ret;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	ret = usbtv_setup_capture(usbtv);
567*4882a593Smuzhiyun 	if (ret < 0)
568*4882a593Smuzhiyun 		return ret;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	ret = usb_set_interface(usbtv->udev, 0, 1);
571*4882a593Smuzhiyun 	if (ret < 0)
572*4882a593Smuzhiyun 		return ret;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	usbtv_audio_resume(usbtv);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
577*4882a593Smuzhiyun 		struct urb *ip;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 		ip = usbtv_setup_iso_transfer(usbtv);
580*4882a593Smuzhiyun 		if (ip == NULL) {
581*4882a593Smuzhiyun 			ret = -ENOMEM;
582*4882a593Smuzhiyun 			goto start_fail;
583*4882a593Smuzhiyun 		}
584*4882a593Smuzhiyun 		usbtv->isoc_urbs[i] = ip;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 		ret = usb_submit_urb(ip, GFP_KERNEL);
587*4882a593Smuzhiyun 		if (ret < 0)
588*4882a593Smuzhiyun 			goto start_fail;
589*4882a593Smuzhiyun 	}
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	return 0;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun start_fail:
594*4882a593Smuzhiyun 	usbtv_stop(usbtv);
595*4882a593Smuzhiyun 	return ret;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun 
usbtv_querycap(struct file * file,void * priv,struct v4l2_capability * cap)598*4882a593Smuzhiyun static int usbtv_querycap(struct file *file, void *priv,
599*4882a593Smuzhiyun 				struct v4l2_capability *cap)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun 	struct usbtv *dev = video_drvdata(file);
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	strscpy(cap->driver, "usbtv", sizeof(cap->driver));
604*4882a593Smuzhiyun 	strscpy(cap->card, "usbtv", sizeof(cap->card));
605*4882a593Smuzhiyun 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
606*4882a593Smuzhiyun 	return 0;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
usbtv_enum_input(struct file * file,void * priv,struct v4l2_input * i)609*4882a593Smuzhiyun static int usbtv_enum_input(struct file *file, void *priv,
610*4882a593Smuzhiyun 					struct v4l2_input *i)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	struct usbtv *dev = video_drvdata(file);
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	switch (i->index) {
615*4882a593Smuzhiyun 	case USBTV_COMPOSITE_INPUT:
616*4882a593Smuzhiyun 		strscpy(i->name, "Composite", sizeof(i->name));
617*4882a593Smuzhiyun 		break;
618*4882a593Smuzhiyun 	case USBTV_SVIDEO_INPUT:
619*4882a593Smuzhiyun 		strscpy(i->name, "S-Video", sizeof(i->name));
620*4882a593Smuzhiyun 		break;
621*4882a593Smuzhiyun 	default:
622*4882a593Smuzhiyun 		return -EINVAL;
623*4882a593Smuzhiyun 	}
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	i->type = V4L2_INPUT_TYPE_CAMERA;
626*4882a593Smuzhiyun 	i->std = dev->vdev.tvnorms;
627*4882a593Smuzhiyun 	return 0;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
usbtv_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)630*4882a593Smuzhiyun static int usbtv_enum_fmt_vid_cap(struct file *file, void  *priv,
631*4882a593Smuzhiyun 					struct v4l2_fmtdesc *f)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun 	if (f->index > 0)
634*4882a593Smuzhiyun 		return -EINVAL;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	f->pixelformat = V4L2_PIX_FMT_YUYV;
637*4882a593Smuzhiyun 	return 0;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun 
usbtv_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)640*4882a593Smuzhiyun static int usbtv_fmt_vid_cap(struct file *file, void *priv,
641*4882a593Smuzhiyun 					struct v4l2_format *f)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	struct usbtv *usbtv = video_drvdata(file);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	f->fmt.pix.width = usbtv->width;
646*4882a593Smuzhiyun 	f->fmt.pix.height = usbtv->height;
647*4882a593Smuzhiyun 	f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
648*4882a593Smuzhiyun 	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
649*4882a593Smuzhiyun 	f->fmt.pix.bytesperline = usbtv->width * 2;
650*4882a593Smuzhiyun 	f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height);
651*4882a593Smuzhiyun 	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	return 0;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun 
usbtv_g_std(struct file * file,void * priv,v4l2_std_id * norm)656*4882a593Smuzhiyun static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun 	struct usbtv *usbtv = video_drvdata(file);
659*4882a593Smuzhiyun 	*norm = usbtv->norm;
660*4882a593Smuzhiyun 	return 0;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
usbtv_s_std(struct file * file,void * priv,v4l2_std_id norm)663*4882a593Smuzhiyun static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	int ret = -EINVAL;
666*4882a593Smuzhiyun 	struct usbtv *usbtv = video_drvdata(file);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	if (norm & USBTV_TV_STD)
669*4882a593Smuzhiyun 		ret = usbtv_select_norm(usbtv, norm);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	return ret;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun 
usbtv_g_input(struct file * file,void * priv,unsigned int * i)674*4882a593Smuzhiyun static int usbtv_g_input(struct file *file, void *priv, unsigned int *i)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun 	struct usbtv *usbtv = video_drvdata(file);
677*4882a593Smuzhiyun 	*i = usbtv->input;
678*4882a593Smuzhiyun 	return 0;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
usbtv_s_input(struct file * file,void * priv,unsigned int i)681*4882a593Smuzhiyun static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun 	struct usbtv *usbtv = video_drvdata(file);
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	return usbtv_select_input(usbtv, i);
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun static struct v4l2_ioctl_ops usbtv_ioctl_ops = {
689*4882a593Smuzhiyun 	.vidioc_querycap = usbtv_querycap,
690*4882a593Smuzhiyun 	.vidioc_enum_input = usbtv_enum_input,
691*4882a593Smuzhiyun 	.vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap,
692*4882a593Smuzhiyun 	.vidioc_g_fmt_vid_cap = usbtv_fmt_vid_cap,
693*4882a593Smuzhiyun 	.vidioc_try_fmt_vid_cap = usbtv_fmt_vid_cap,
694*4882a593Smuzhiyun 	.vidioc_s_fmt_vid_cap = usbtv_fmt_vid_cap,
695*4882a593Smuzhiyun 	.vidioc_g_std = usbtv_g_std,
696*4882a593Smuzhiyun 	.vidioc_s_std = usbtv_s_std,
697*4882a593Smuzhiyun 	.vidioc_g_input = usbtv_g_input,
698*4882a593Smuzhiyun 	.vidioc_s_input = usbtv_s_input,
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	.vidioc_reqbufs = vb2_ioctl_reqbufs,
701*4882a593Smuzhiyun 	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
702*4882a593Smuzhiyun 	.vidioc_querybuf = vb2_ioctl_querybuf,
703*4882a593Smuzhiyun 	.vidioc_create_bufs = vb2_ioctl_create_bufs,
704*4882a593Smuzhiyun 	.vidioc_qbuf = vb2_ioctl_qbuf,
705*4882a593Smuzhiyun 	.vidioc_dqbuf = vb2_ioctl_dqbuf,
706*4882a593Smuzhiyun 	.vidioc_streamon = vb2_ioctl_streamon,
707*4882a593Smuzhiyun 	.vidioc_streamoff = vb2_ioctl_streamoff,
708*4882a593Smuzhiyun };
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun static const struct v4l2_file_operations usbtv_fops = {
711*4882a593Smuzhiyun 	.owner = THIS_MODULE,
712*4882a593Smuzhiyun 	.unlocked_ioctl = video_ioctl2,
713*4882a593Smuzhiyun 	.mmap = vb2_fop_mmap,
714*4882a593Smuzhiyun 	.open = v4l2_fh_open,
715*4882a593Smuzhiyun 	.release = vb2_fop_release,
716*4882a593Smuzhiyun 	.read = vb2_fop_read,
717*4882a593Smuzhiyun 	.poll = vb2_fop_poll,
718*4882a593Smuzhiyun };
719*4882a593Smuzhiyun 
usbtv_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])720*4882a593Smuzhiyun static int usbtv_queue_setup(struct vb2_queue *vq,
721*4882a593Smuzhiyun 	unsigned int *nbuffers,
722*4882a593Smuzhiyun 	unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[])
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	struct usbtv *usbtv = vb2_get_drv_priv(vq);
725*4882a593Smuzhiyun 	unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	if (vq->num_buffers + *nbuffers < 2)
728*4882a593Smuzhiyun 		*nbuffers = 2 - vq->num_buffers;
729*4882a593Smuzhiyun 	if (*nplanes)
730*4882a593Smuzhiyun 		return sizes[0] < size ? -EINVAL : 0;
731*4882a593Smuzhiyun 	*nplanes = 1;
732*4882a593Smuzhiyun 	sizes[0] = size;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun 
usbtv_buf_queue(struct vb2_buffer * vb)737*4882a593Smuzhiyun static void usbtv_buf_queue(struct vb2_buffer *vb)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
740*4882a593Smuzhiyun 	struct usbtv *usbtv = vb2_get_drv_priv(vb->vb2_queue);
741*4882a593Smuzhiyun 	struct usbtv_buf *buf = container_of(vbuf, struct usbtv_buf, vb);
742*4882a593Smuzhiyun 	unsigned long flags;
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	if (usbtv->udev == NULL) {
745*4882a593Smuzhiyun 		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
746*4882a593Smuzhiyun 		return;
747*4882a593Smuzhiyun 	}
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	spin_lock_irqsave(&usbtv->buflock, flags);
750*4882a593Smuzhiyun 	list_add_tail(&buf->list, &usbtv->bufs);
751*4882a593Smuzhiyun 	spin_unlock_irqrestore(&usbtv->buflock, flags);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun 
usbtv_start_streaming(struct vb2_queue * vq,unsigned int count)754*4882a593Smuzhiyun static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun 	struct usbtv *usbtv = vb2_get_drv_priv(vq);
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	if (usbtv->udev == NULL)
759*4882a593Smuzhiyun 		return -ENODEV;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	usbtv->last_odd = 1;
762*4882a593Smuzhiyun 	usbtv->sequence = 0;
763*4882a593Smuzhiyun 	return usbtv_start(usbtv);
764*4882a593Smuzhiyun }
765*4882a593Smuzhiyun 
usbtv_stop_streaming(struct vb2_queue * vq)766*4882a593Smuzhiyun static void usbtv_stop_streaming(struct vb2_queue *vq)
767*4882a593Smuzhiyun {
768*4882a593Smuzhiyun 	struct usbtv *usbtv = vb2_get_drv_priv(vq);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	if (usbtv->udev)
771*4882a593Smuzhiyun 		usbtv_stop(usbtv);
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun static const struct vb2_ops usbtv_vb2_ops = {
775*4882a593Smuzhiyun 	.queue_setup = usbtv_queue_setup,
776*4882a593Smuzhiyun 	.buf_queue = usbtv_buf_queue,
777*4882a593Smuzhiyun 	.start_streaming = usbtv_start_streaming,
778*4882a593Smuzhiyun 	.stop_streaming = usbtv_stop_streaming,
779*4882a593Smuzhiyun 	.wait_prepare = vb2_ops_wait_prepare,
780*4882a593Smuzhiyun 	.wait_finish = vb2_ops_wait_finish,
781*4882a593Smuzhiyun };
782*4882a593Smuzhiyun 
usbtv_s_ctrl(struct v4l2_ctrl * ctrl)783*4882a593Smuzhiyun static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl)
784*4882a593Smuzhiyun {
785*4882a593Smuzhiyun 	struct usbtv *usbtv = container_of(ctrl->handler, struct usbtv,
786*4882a593Smuzhiyun 								ctrl);
787*4882a593Smuzhiyun 	u8 *data;
788*4882a593Smuzhiyun 	u16 index, size;
789*4882a593Smuzhiyun 	int ret;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	data = kmalloc(3, GFP_KERNEL);
792*4882a593Smuzhiyun 	if (!data)
793*4882a593Smuzhiyun 		return -ENOMEM;
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	/*
796*4882a593Smuzhiyun 	 * Read in the current brightness/contrast registers. We need them
797*4882a593Smuzhiyun 	 * both, because the values are for some reason interleaved.
798*4882a593Smuzhiyun 	 */
799*4882a593Smuzhiyun 	if (ctrl->id == V4L2_CID_BRIGHTNESS || ctrl->id == V4L2_CID_CONTRAST) {
800*4882a593Smuzhiyun 		ret = usb_control_msg(usbtv->udev,
801*4882a593Smuzhiyun 			usb_rcvctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG,
802*4882a593Smuzhiyun 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
803*4882a593Smuzhiyun 			0, USBTV_BASE + 0x0244, (void *)data, 3,
804*4882a593Smuzhiyun 			USB_CTRL_GET_TIMEOUT);
805*4882a593Smuzhiyun 		if (ret < 0)
806*4882a593Smuzhiyun 			goto error;
807*4882a593Smuzhiyun 	}
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	switch (ctrl->id) {
810*4882a593Smuzhiyun 	case V4L2_CID_BRIGHTNESS:
811*4882a593Smuzhiyun 		index = USBTV_BASE + 0x0244;
812*4882a593Smuzhiyun 		size = 3;
813*4882a593Smuzhiyun 		data[0] &= 0xf0;
814*4882a593Smuzhiyun 		data[0] |= (ctrl->val >> 8) & 0xf;
815*4882a593Smuzhiyun 		data[2] = ctrl->val & 0xff;
816*4882a593Smuzhiyun 		break;
817*4882a593Smuzhiyun 	case V4L2_CID_CONTRAST:
818*4882a593Smuzhiyun 		index = USBTV_BASE + 0x0244;
819*4882a593Smuzhiyun 		size = 3;
820*4882a593Smuzhiyun 		data[0] &= 0x0f;
821*4882a593Smuzhiyun 		data[0] |= (ctrl->val >> 4) & 0xf0;
822*4882a593Smuzhiyun 		data[1] = ctrl->val & 0xff;
823*4882a593Smuzhiyun 		break;
824*4882a593Smuzhiyun 	case V4L2_CID_SATURATION:
825*4882a593Smuzhiyun 		index = USBTV_BASE + 0x0242;
826*4882a593Smuzhiyun 		data[0] = ctrl->val >> 8;
827*4882a593Smuzhiyun 		data[1] = ctrl->val & 0xff;
828*4882a593Smuzhiyun 		size = 2;
829*4882a593Smuzhiyun 		break;
830*4882a593Smuzhiyun 	case V4L2_CID_HUE:
831*4882a593Smuzhiyun 		index = USBTV_BASE + 0x0240;
832*4882a593Smuzhiyun 		size = 2;
833*4882a593Smuzhiyun 		if (ctrl->val > 0) {
834*4882a593Smuzhiyun 			data[0] = 0x92 + (ctrl->val >> 8);
835*4882a593Smuzhiyun 			data[1] = ctrl->val & 0xff;
836*4882a593Smuzhiyun 		} else {
837*4882a593Smuzhiyun 			data[0] = 0x82 + (-ctrl->val >> 8);
838*4882a593Smuzhiyun 			data[1] = -ctrl->val & 0xff;
839*4882a593Smuzhiyun 		}
840*4882a593Smuzhiyun 		break;
841*4882a593Smuzhiyun 	case V4L2_CID_SHARPNESS:
842*4882a593Smuzhiyun 		index = USBTV_BASE + 0x0239;
843*4882a593Smuzhiyun 		data[0] = 0;
844*4882a593Smuzhiyun 		data[1] = ctrl->val;
845*4882a593Smuzhiyun 		size = 2;
846*4882a593Smuzhiyun 		break;
847*4882a593Smuzhiyun 	default:
848*4882a593Smuzhiyun 		kfree(data);
849*4882a593Smuzhiyun 		return -EINVAL;
850*4882a593Smuzhiyun 	}
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	ret = usb_control_msg(usbtv->udev, usb_sndctrlpipe(usbtv->udev, 0),
853*4882a593Smuzhiyun 			USBTV_CONTROL_REG,
854*4882a593Smuzhiyun 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
855*4882a593Smuzhiyun 			0, index, (void *)data, size, USB_CTRL_SET_TIMEOUT);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun error:
858*4882a593Smuzhiyun 	if (ret < 0)
859*4882a593Smuzhiyun 		dev_warn(usbtv->dev, "Failed to submit a control request.\n");
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	kfree(data);
862*4882a593Smuzhiyun 	return ret;
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun static const struct v4l2_ctrl_ops usbtv_ctrl_ops = {
866*4882a593Smuzhiyun 	.s_ctrl = usbtv_s_ctrl,
867*4882a593Smuzhiyun };
868*4882a593Smuzhiyun 
usbtv_release(struct v4l2_device * v4l2_dev)869*4882a593Smuzhiyun static void usbtv_release(struct v4l2_device *v4l2_dev)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun 	struct usbtv *usbtv = container_of(v4l2_dev, struct usbtv, v4l2_dev);
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	v4l2_device_unregister(&usbtv->v4l2_dev);
874*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(&usbtv->ctrl);
875*4882a593Smuzhiyun 	kfree(usbtv);
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun 
usbtv_video_init(struct usbtv * usbtv)878*4882a593Smuzhiyun int usbtv_video_init(struct usbtv *usbtv)
879*4882a593Smuzhiyun {
880*4882a593Smuzhiyun 	int ret;
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	(void)usbtv_configure_for_norm(usbtv, V4L2_STD_525_60);
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	spin_lock_init(&usbtv->buflock);
885*4882a593Smuzhiyun 	mutex_init(&usbtv->v4l2_lock);
886*4882a593Smuzhiyun 	mutex_init(&usbtv->vb2q_lock);
887*4882a593Smuzhiyun 	INIT_LIST_HEAD(&usbtv->bufs);
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	/* videobuf2 structure */
890*4882a593Smuzhiyun 	usbtv->vb2q.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
891*4882a593Smuzhiyun 	usbtv->vb2q.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
892*4882a593Smuzhiyun 	usbtv->vb2q.drv_priv = usbtv;
893*4882a593Smuzhiyun 	usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf);
894*4882a593Smuzhiyun 	usbtv->vb2q.ops = &usbtv_vb2_ops;
895*4882a593Smuzhiyun 	usbtv->vb2q.mem_ops = &vb2_vmalloc_memops;
896*4882a593Smuzhiyun 	usbtv->vb2q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
897*4882a593Smuzhiyun 	usbtv->vb2q.lock = &usbtv->vb2q_lock;
898*4882a593Smuzhiyun 	ret = vb2_queue_init(&usbtv->vb2q);
899*4882a593Smuzhiyun 	if (ret < 0) {
900*4882a593Smuzhiyun 		dev_warn(usbtv->dev, "Could not initialize videobuf2 queue\n");
901*4882a593Smuzhiyun 		return ret;
902*4882a593Smuzhiyun 	}
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	/* controls */
905*4882a593Smuzhiyun 	v4l2_ctrl_handler_init(&usbtv->ctrl, 4);
906*4882a593Smuzhiyun 	v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
907*4882a593Smuzhiyun 			V4L2_CID_CONTRAST, 0, 0x3ff, 1, 0x1d0);
908*4882a593Smuzhiyun 	v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
909*4882a593Smuzhiyun 			V4L2_CID_BRIGHTNESS, 0, 0x3ff, 1, 0x1c0);
910*4882a593Smuzhiyun 	v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
911*4882a593Smuzhiyun 			V4L2_CID_SATURATION, 0, 0x3ff, 1, 0x200);
912*4882a593Smuzhiyun 	v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
913*4882a593Smuzhiyun 			V4L2_CID_HUE, -0xdff, 0xdff, 1, 0x000);
914*4882a593Smuzhiyun 	v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
915*4882a593Smuzhiyun 			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x60);
916*4882a593Smuzhiyun 	ret = usbtv->ctrl.error;
917*4882a593Smuzhiyun 	if (ret < 0) {
918*4882a593Smuzhiyun 		dev_warn(usbtv->dev, "Could not initialize controls\n");
919*4882a593Smuzhiyun 		goto ctrl_fail;
920*4882a593Smuzhiyun 	}
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	/* v4l2 structure */
923*4882a593Smuzhiyun 	usbtv->v4l2_dev.ctrl_handler = &usbtv->ctrl;
924*4882a593Smuzhiyun 	usbtv->v4l2_dev.release = usbtv_release;
925*4882a593Smuzhiyun 	ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev);
926*4882a593Smuzhiyun 	if (ret < 0) {
927*4882a593Smuzhiyun 		dev_warn(usbtv->dev, "Could not register v4l2 device\n");
928*4882a593Smuzhiyun 		goto v4l2_fail;
929*4882a593Smuzhiyun 	}
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	/* Video structure */
932*4882a593Smuzhiyun 	strscpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name));
933*4882a593Smuzhiyun 	usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev;
934*4882a593Smuzhiyun 	usbtv->vdev.release = video_device_release_empty;
935*4882a593Smuzhiyun 	usbtv->vdev.fops = &usbtv_fops;
936*4882a593Smuzhiyun 	usbtv->vdev.ioctl_ops = &usbtv_ioctl_ops;
937*4882a593Smuzhiyun 	usbtv->vdev.tvnorms = USBTV_TV_STD;
938*4882a593Smuzhiyun 	usbtv->vdev.queue = &usbtv->vb2q;
939*4882a593Smuzhiyun 	usbtv->vdev.lock = &usbtv->v4l2_lock;
940*4882a593Smuzhiyun 	usbtv->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
941*4882a593Smuzhiyun 				  V4L2_CAP_STREAMING;
942*4882a593Smuzhiyun 	video_set_drvdata(&usbtv->vdev, usbtv);
943*4882a593Smuzhiyun 	ret = video_register_device(&usbtv->vdev, VFL_TYPE_VIDEO, -1);
944*4882a593Smuzhiyun 	if (ret < 0) {
945*4882a593Smuzhiyun 		dev_warn(usbtv->dev, "Could not register video device\n");
946*4882a593Smuzhiyun 		goto vdev_fail;
947*4882a593Smuzhiyun 	}
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	return 0;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun vdev_fail:
952*4882a593Smuzhiyun 	v4l2_device_unregister(&usbtv->v4l2_dev);
953*4882a593Smuzhiyun v4l2_fail:
954*4882a593Smuzhiyun ctrl_fail:
955*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(&usbtv->ctrl);
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	return ret;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun 
usbtv_video_free(struct usbtv * usbtv)960*4882a593Smuzhiyun void usbtv_video_free(struct usbtv *usbtv)
961*4882a593Smuzhiyun {
962*4882a593Smuzhiyun 	mutex_lock(&usbtv->vb2q_lock);
963*4882a593Smuzhiyun 	mutex_lock(&usbtv->v4l2_lock);
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	usbtv_stop(usbtv);
966*4882a593Smuzhiyun 	vb2_video_unregister_device(&usbtv->vdev);
967*4882a593Smuzhiyun 	v4l2_device_disconnect(&usbtv->v4l2_dev);
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	mutex_unlock(&usbtv->v4l2_lock);
970*4882a593Smuzhiyun 	mutex_unlock(&usbtv->vb2q_lock);
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	v4l2_device_put(&usbtv->v4l2_dev);
973*4882a593Smuzhiyun }
974