Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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