1dacca5f0SHans Verkuil // SPDX-License-Identifier: GPL-2.0-only
2dacca5f0SHans Verkuil /*
3dacca5f0SHans Verkuil  * vivid-ctrls.c - control support functions.
4dacca5f0SHans Verkuil  *
5dacca5f0SHans Verkuil  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6dacca5f0SHans Verkuil  */
7dacca5f0SHans Verkuil 
8dacca5f0SHans Verkuil #include <linux/errno.h>
9dacca5f0SHans Verkuil #include <linux/kernel.h>
10dacca5f0SHans Verkuil #include <linux/videodev2.h>
11dacca5f0SHans Verkuil #include <media/v4l2-event.h>
12dacca5f0SHans Verkuil #include <media/v4l2-common.h>
13dacca5f0SHans Verkuil 
14dacca5f0SHans Verkuil #include "vivid-core.h"
15dacca5f0SHans Verkuil #include "vivid-vid-cap.h"
16dacca5f0SHans Verkuil #include "vivid-vid-out.h"
17dacca5f0SHans Verkuil #include "vivid-vid-common.h"
18dacca5f0SHans Verkuil #include "vivid-radio-common.h"
19dacca5f0SHans Verkuil #include "vivid-osd.h"
20dacca5f0SHans Verkuil #include "vivid-ctrls.h"
21dacca5f0SHans Verkuil #include "vivid-cec.h"
22dacca5f0SHans Verkuil 
23dacca5f0SHans Verkuil #define VIVID_CID_CUSTOM_BASE		(V4L2_CID_USER_BASE | 0xf000)
24dacca5f0SHans Verkuil #define VIVID_CID_BUTTON		(VIVID_CID_CUSTOM_BASE + 0)
25dacca5f0SHans Verkuil #define VIVID_CID_BOOLEAN		(VIVID_CID_CUSTOM_BASE + 1)
26dacca5f0SHans Verkuil #define VIVID_CID_INTEGER		(VIVID_CID_CUSTOM_BASE + 2)
27dacca5f0SHans Verkuil #define VIVID_CID_INTEGER64		(VIVID_CID_CUSTOM_BASE + 3)
28dacca5f0SHans Verkuil #define VIVID_CID_MENU			(VIVID_CID_CUSTOM_BASE + 4)
29dacca5f0SHans Verkuil #define VIVID_CID_STRING		(VIVID_CID_CUSTOM_BASE + 5)
30dacca5f0SHans Verkuil #define VIVID_CID_BITMASK		(VIVID_CID_CUSTOM_BASE + 6)
31dacca5f0SHans Verkuil #define VIVID_CID_INTMENU		(VIVID_CID_CUSTOM_BASE + 7)
32dacca5f0SHans Verkuil #define VIVID_CID_U32_ARRAY		(VIVID_CID_CUSTOM_BASE + 8)
33dacca5f0SHans Verkuil #define VIVID_CID_U16_MATRIX		(VIVID_CID_CUSTOM_BASE + 9)
34dacca5f0SHans Verkuil #define VIVID_CID_U8_4D_ARRAY		(VIVID_CID_CUSTOM_BASE + 10)
35dacca5f0SHans Verkuil #define VIVID_CID_AREA			(VIVID_CID_CUSTOM_BASE + 11)
36dacca5f0SHans Verkuil 
37dacca5f0SHans Verkuil #define VIVID_CID_VIVID_BASE		(0x00f00000 | 0xf000)
38dacca5f0SHans Verkuil #define VIVID_CID_VIVID_CLASS		(0x00f00000 | 1)
39dacca5f0SHans Verkuil #define VIVID_CID_TEST_PATTERN		(VIVID_CID_VIVID_BASE + 0)
40dacca5f0SHans Verkuil #define VIVID_CID_OSD_TEXT_MODE		(VIVID_CID_VIVID_BASE + 1)
41dacca5f0SHans Verkuil #define VIVID_CID_HOR_MOVEMENT		(VIVID_CID_VIVID_BASE + 2)
42dacca5f0SHans Verkuil #define VIVID_CID_VERT_MOVEMENT		(VIVID_CID_VIVID_BASE + 3)
43dacca5f0SHans Verkuil #define VIVID_CID_SHOW_BORDER		(VIVID_CID_VIVID_BASE + 4)
44dacca5f0SHans Verkuil #define VIVID_CID_SHOW_SQUARE		(VIVID_CID_VIVID_BASE + 5)
45dacca5f0SHans Verkuil #define VIVID_CID_INSERT_SAV		(VIVID_CID_VIVID_BASE + 6)
46dacca5f0SHans Verkuil #define VIVID_CID_INSERT_EAV		(VIVID_CID_VIVID_BASE + 7)
47dacca5f0SHans Verkuil #define VIVID_CID_VBI_CAP_INTERLACED	(VIVID_CID_VIVID_BASE + 8)
48dacca5f0SHans Verkuil 
49dacca5f0SHans Verkuil #define VIVID_CID_HFLIP			(VIVID_CID_VIVID_BASE + 20)
50dacca5f0SHans Verkuil #define VIVID_CID_VFLIP			(VIVID_CID_VIVID_BASE + 21)
51dacca5f0SHans Verkuil #define VIVID_CID_STD_ASPECT_RATIO	(VIVID_CID_VIVID_BASE + 22)
52dacca5f0SHans Verkuil #define VIVID_CID_DV_TIMINGS_ASPECT_RATIO	(VIVID_CID_VIVID_BASE + 23)
53dacca5f0SHans Verkuil #define VIVID_CID_TSTAMP_SRC		(VIVID_CID_VIVID_BASE + 24)
54dacca5f0SHans Verkuil #define VIVID_CID_COLORSPACE		(VIVID_CID_VIVID_BASE + 25)
55dacca5f0SHans Verkuil #define VIVID_CID_XFER_FUNC		(VIVID_CID_VIVID_BASE + 26)
56dacca5f0SHans Verkuil #define VIVID_CID_YCBCR_ENC		(VIVID_CID_VIVID_BASE + 27)
57dacca5f0SHans Verkuil #define VIVID_CID_QUANTIZATION		(VIVID_CID_VIVID_BASE + 28)
58dacca5f0SHans Verkuil #define VIVID_CID_LIMITED_RGB_RANGE	(VIVID_CID_VIVID_BASE + 29)
59dacca5f0SHans Verkuil #define VIVID_CID_ALPHA_MODE		(VIVID_CID_VIVID_BASE + 30)
60dacca5f0SHans Verkuil #define VIVID_CID_HAS_CROP_CAP		(VIVID_CID_VIVID_BASE + 31)
61dacca5f0SHans Verkuil #define VIVID_CID_HAS_COMPOSE_CAP	(VIVID_CID_VIVID_BASE + 32)
62dacca5f0SHans Verkuil #define VIVID_CID_HAS_SCALER_CAP	(VIVID_CID_VIVID_BASE + 33)
63dacca5f0SHans Verkuil #define VIVID_CID_HAS_CROP_OUT		(VIVID_CID_VIVID_BASE + 34)
64dacca5f0SHans Verkuil #define VIVID_CID_HAS_COMPOSE_OUT	(VIVID_CID_VIVID_BASE + 35)
65dacca5f0SHans Verkuil #define VIVID_CID_HAS_SCALER_OUT	(VIVID_CID_VIVID_BASE + 36)
66dacca5f0SHans Verkuil #define VIVID_CID_LOOP_VIDEO		(VIVID_CID_VIVID_BASE + 37)
67dacca5f0SHans Verkuil #define VIVID_CID_SEQ_WRAP		(VIVID_CID_VIVID_BASE + 38)
68dacca5f0SHans Verkuil #define VIVID_CID_TIME_WRAP		(VIVID_CID_VIVID_BASE + 39)
69dacca5f0SHans Verkuil #define VIVID_CID_MAX_EDID_BLOCKS	(VIVID_CID_VIVID_BASE + 40)
70dacca5f0SHans Verkuil #define VIVID_CID_PERCENTAGE_FILL	(VIVID_CID_VIVID_BASE + 41)
71dacca5f0SHans Verkuil #define VIVID_CID_REDUCED_FPS		(VIVID_CID_VIVID_BASE + 42)
72dacca5f0SHans Verkuil #define VIVID_CID_HSV_ENC		(VIVID_CID_VIVID_BASE + 43)
73dacca5f0SHans Verkuil #define VIVID_CID_DISPLAY_PRESENT	(VIVID_CID_VIVID_BASE + 44)
74dacca5f0SHans Verkuil 
75dacca5f0SHans Verkuil #define VIVID_CID_STD_SIGNAL_MODE	(VIVID_CID_VIVID_BASE + 60)
76dacca5f0SHans Verkuil #define VIVID_CID_STANDARD		(VIVID_CID_VIVID_BASE + 61)
77dacca5f0SHans Verkuil #define VIVID_CID_DV_TIMINGS_SIGNAL_MODE	(VIVID_CID_VIVID_BASE + 62)
78dacca5f0SHans Verkuil #define VIVID_CID_DV_TIMINGS		(VIVID_CID_VIVID_BASE + 63)
79dacca5f0SHans Verkuil #define VIVID_CID_PERC_DROPPED		(VIVID_CID_VIVID_BASE + 64)
80dacca5f0SHans Verkuil #define VIVID_CID_DISCONNECT		(VIVID_CID_VIVID_BASE + 65)
81dacca5f0SHans Verkuil #define VIVID_CID_DQBUF_ERROR		(VIVID_CID_VIVID_BASE + 66)
82dacca5f0SHans Verkuil #define VIVID_CID_QUEUE_SETUP_ERROR	(VIVID_CID_VIVID_BASE + 67)
83dacca5f0SHans Verkuil #define VIVID_CID_BUF_PREPARE_ERROR	(VIVID_CID_VIVID_BASE + 68)
84dacca5f0SHans Verkuil #define VIVID_CID_START_STR_ERROR	(VIVID_CID_VIVID_BASE + 69)
85dacca5f0SHans Verkuil #define VIVID_CID_QUEUE_ERROR		(VIVID_CID_VIVID_BASE + 70)
86dacca5f0SHans Verkuil #define VIVID_CID_CLEAR_FB		(VIVID_CID_VIVID_BASE + 71)
87dacca5f0SHans Verkuil #define VIVID_CID_REQ_VALIDATE_ERROR	(VIVID_CID_VIVID_BASE + 72)
88dacca5f0SHans Verkuil 
89dacca5f0SHans Verkuil #define VIVID_CID_RADIO_SEEK_MODE	(VIVID_CID_VIVID_BASE + 90)
90dacca5f0SHans Verkuil #define VIVID_CID_RADIO_SEEK_PROG_LIM	(VIVID_CID_VIVID_BASE + 91)
91dacca5f0SHans Verkuil #define VIVID_CID_RADIO_RX_RDS_RBDS	(VIVID_CID_VIVID_BASE + 92)
92dacca5f0SHans Verkuil #define VIVID_CID_RADIO_RX_RDS_BLOCKIO	(VIVID_CID_VIVID_BASE + 93)
93dacca5f0SHans Verkuil 
94dacca5f0SHans Verkuil #define VIVID_CID_RADIO_TX_RDS_BLOCKIO	(VIVID_CID_VIVID_BASE + 94)
95dacca5f0SHans Verkuil 
96dacca5f0SHans Verkuil #define VIVID_CID_SDR_CAP_FM_DEVIATION	(VIVID_CID_VIVID_BASE + 110)
97dacca5f0SHans Verkuil 
98dacca5f0SHans Verkuil #define VIVID_CID_META_CAP_GENERATE_PTS	(VIVID_CID_VIVID_BASE + 111)
99dacca5f0SHans Verkuil #define VIVID_CID_META_CAP_GENERATE_SCR	(VIVID_CID_VIVID_BASE + 112)
100dacca5f0SHans Verkuil 
101dacca5f0SHans Verkuil /* General User Controls */
102dacca5f0SHans Verkuil 
103dacca5f0SHans Verkuil static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl)
104dacca5f0SHans Verkuil {
105dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_gen);
106dacca5f0SHans Verkuil 
107dacca5f0SHans Verkuil 	switch (ctrl->id) {
108dacca5f0SHans Verkuil 	case VIVID_CID_DISCONNECT:
109dacca5f0SHans Verkuil 		v4l2_info(&dev->v4l2_dev, "disconnect\n");
110dacca5f0SHans Verkuil 		clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags);
111dacca5f0SHans Verkuil 		clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags);
112dacca5f0SHans Verkuil 		clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags);
113dacca5f0SHans Verkuil 		clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags);
114dacca5f0SHans Verkuil 		clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
115dacca5f0SHans Verkuil 		clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
116dacca5f0SHans Verkuil 		clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
117dacca5f0SHans Verkuil 		clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
118dacca5f0SHans Verkuil 		break;
119dacca5f0SHans Verkuil 	case VIVID_CID_BUTTON:
120dacca5f0SHans Verkuil 		dev->button_pressed = 30;
121dacca5f0SHans Verkuil 		break;
122dacca5f0SHans Verkuil 	}
123dacca5f0SHans Verkuil 	return 0;
124dacca5f0SHans Verkuil }
125dacca5f0SHans Verkuil 
126dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_user_gen_ctrl_ops = {
127dacca5f0SHans Verkuil 	.s_ctrl = vivid_user_gen_s_ctrl,
128dacca5f0SHans Verkuil };
129dacca5f0SHans Verkuil 
130dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_button = {
131dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
132dacca5f0SHans Verkuil 	.id = VIVID_CID_BUTTON,
133dacca5f0SHans Verkuil 	.name = "Button",
134dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
135dacca5f0SHans Verkuil };
136dacca5f0SHans Verkuil 
137dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_boolean = {
138dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
139dacca5f0SHans Verkuil 	.id = VIVID_CID_BOOLEAN,
140dacca5f0SHans Verkuil 	.name = "Boolean",
141dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
142dacca5f0SHans Verkuil 	.min = 0,
143dacca5f0SHans Verkuil 	.max = 1,
144dacca5f0SHans Verkuil 	.step = 1,
145dacca5f0SHans Verkuil 	.def = 1,
146dacca5f0SHans Verkuil };
147dacca5f0SHans Verkuil 
148dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_int32 = {
149dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
150dacca5f0SHans Verkuil 	.id = VIVID_CID_INTEGER,
151dacca5f0SHans Verkuil 	.name = "Integer 32 Bits",
152dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
153dacca5f0SHans Verkuil 	.min = 0xffffffff80000000ULL,
154dacca5f0SHans Verkuil 	.max = 0x7fffffff,
155dacca5f0SHans Verkuil 	.step = 1,
156dacca5f0SHans Verkuil };
157dacca5f0SHans Verkuil 
158dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_int64 = {
159dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
160dacca5f0SHans Verkuil 	.id = VIVID_CID_INTEGER64,
161dacca5f0SHans Verkuil 	.name = "Integer 64 Bits",
162dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER64,
163dacca5f0SHans Verkuil 	.min = 0x8000000000000000ULL,
164dacca5f0SHans Verkuil 	.max = 0x7fffffffffffffffLL,
165dacca5f0SHans Verkuil 	.step = 1,
166dacca5f0SHans Verkuil };
167dacca5f0SHans Verkuil 
168dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_u32_array = {
169dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
170dacca5f0SHans Verkuil 	.id = VIVID_CID_U32_ARRAY,
171dacca5f0SHans Verkuil 	.name = "U32 1 Element Array",
172dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_U32,
173dacca5f0SHans Verkuil 	.def = 0x18,
174dacca5f0SHans Verkuil 	.min = 0x10,
175dacca5f0SHans Verkuil 	.max = 0x20000,
176dacca5f0SHans Verkuil 	.step = 1,
177dacca5f0SHans Verkuil 	.dims = { 1 },
178dacca5f0SHans Verkuil };
179dacca5f0SHans Verkuil 
180dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_u16_matrix = {
181dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
182dacca5f0SHans Verkuil 	.id = VIVID_CID_U16_MATRIX,
183dacca5f0SHans Verkuil 	.name = "U16 8x16 Matrix",
184dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_U16,
185dacca5f0SHans Verkuil 	.def = 0x18,
186dacca5f0SHans Verkuil 	.min = 0x10,
187dacca5f0SHans Verkuil 	.max = 0x2000,
188dacca5f0SHans Verkuil 	.step = 1,
189dacca5f0SHans Verkuil 	.dims = { 8, 16 },
190dacca5f0SHans Verkuil };
191dacca5f0SHans Verkuil 
192dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_u8_4d_array = {
193dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
194dacca5f0SHans Verkuil 	.id = VIVID_CID_U8_4D_ARRAY,
195dacca5f0SHans Verkuil 	.name = "U8 2x3x4x5 Array",
196dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_U8,
197dacca5f0SHans Verkuil 	.def = 0x18,
198dacca5f0SHans Verkuil 	.min = 0x10,
199dacca5f0SHans Verkuil 	.max = 0x20,
200dacca5f0SHans Verkuil 	.step = 1,
201dacca5f0SHans Verkuil 	.dims = { 2, 3, 4, 5 },
202dacca5f0SHans Verkuil };
203dacca5f0SHans Verkuil 
204dacca5f0SHans Verkuil static const char * const vivid_ctrl_menu_strings[] = {
205dacca5f0SHans Verkuil 	"Menu Item 0 (Skipped)",
206dacca5f0SHans Verkuil 	"Menu Item 1",
207dacca5f0SHans Verkuil 	"Menu Item 2 (Skipped)",
208dacca5f0SHans Verkuil 	"Menu Item 3",
209dacca5f0SHans Verkuil 	"Menu Item 4",
210dacca5f0SHans Verkuil 	"Menu Item 5 (Skipped)",
211dacca5f0SHans Verkuil 	NULL,
212dacca5f0SHans Verkuil };
213dacca5f0SHans Verkuil 
214dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_menu = {
215dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
216dacca5f0SHans Verkuil 	.id = VIVID_CID_MENU,
217dacca5f0SHans Verkuil 	.name = "Menu",
218dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
219dacca5f0SHans Verkuil 	.min = 1,
220dacca5f0SHans Verkuil 	.max = 4,
221dacca5f0SHans Verkuil 	.def = 3,
222dacca5f0SHans Verkuil 	.menu_skip_mask = 0x04,
223dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_menu_strings,
224dacca5f0SHans Verkuil };
225dacca5f0SHans Verkuil 
226dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_string = {
227dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
228dacca5f0SHans Verkuil 	.id = VIVID_CID_STRING,
229dacca5f0SHans Verkuil 	.name = "String",
230dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_STRING,
231dacca5f0SHans Verkuil 	.min = 2,
232dacca5f0SHans Verkuil 	.max = 4,
233dacca5f0SHans Verkuil 	.step = 1,
234dacca5f0SHans Verkuil };
235dacca5f0SHans Verkuil 
236dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_bitmask = {
237dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
238dacca5f0SHans Verkuil 	.id = VIVID_CID_BITMASK,
239dacca5f0SHans Verkuil 	.name = "Bitmask",
240dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BITMASK,
241dacca5f0SHans Verkuil 	.def = 0x80002000,
242dacca5f0SHans Verkuil 	.min = 0,
243dacca5f0SHans Verkuil 	.max = 0x80402010,
244dacca5f0SHans Verkuil 	.step = 0,
245dacca5f0SHans Verkuil };
246dacca5f0SHans Verkuil 
247dacca5f0SHans Verkuil static const s64 vivid_ctrl_int_menu_values[] = {
248dacca5f0SHans Verkuil 	1, 1, 2, 3, 5, 8, 13, 21, 42,
249dacca5f0SHans Verkuil };
250dacca5f0SHans Verkuil 
251dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_int_menu = {
252dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
253dacca5f0SHans Verkuil 	.id = VIVID_CID_INTMENU,
254dacca5f0SHans Verkuil 	.name = "Integer Menu",
255dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
256dacca5f0SHans Verkuil 	.min = 1,
257dacca5f0SHans Verkuil 	.max = 8,
258dacca5f0SHans Verkuil 	.def = 4,
259dacca5f0SHans Verkuil 	.menu_skip_mask = 0x02,
260dacca5f0SHans Verkuil 	.qmenu_int = vivid_ctrl_int_menu_values,
261dacca5f0SHans Verkuil };
262dacca5f0SHans Verkuil 
263dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_disconnect = {
264dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
265dacca5f0SHans Verkuil 	.id = VIVID_CID_DISCONNECT,
266dacca5f0SHans Verkuil 	.name = "Disconnect",
267dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
268dacca5f0SHans Verkuil };
269dacca5f0SHans Verkuil 
270dacca5f0SHans Verkuil static const struct v4l2_area area = {
271dacca5f0SHans Verkuil 	.width = 1000,
272dacca5f0SHans Verkuil 	.height = 2000,
273dacca5f0SHans Verkuil };
274dacca5f0SHans Verkuil 
275dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_area = {
276dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
277dacca5f0SHans Verkuil 	.id = VIVID_CID_AREA,
278dacca5f0SHans Verkuil 	.name = "Area",
279dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_AREA,
280dacca5f0SHans Verkuil 	.p_def.p_const = &area,
281dacca5f0SHans Verkuil };
282dacca5f0SHans Verkuil 
283dacca5f0SHans Verkuil /* Framebuffer Controls */
284dacca5f0SHans Verkuil 
285dacca5f0SHans Verkuil static int vivid_fb_s_ctrl(struct v4l2_ctrl *ctrl)
286dacca5f0SHans Verkuil {
287dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler,
288dacca5f0SHans Verkuil 					     struct vivid_dev, ctrl_hdl_fb);
289dacca5f0SHans Verkuil 
290dacca5f0SHans Verkuil 	switch (ctrl->id) {
291dacca5f0SHans Verkuil 	case VIVID_CID_CLEAR_FB:
292dacca5f0SHans Verkuil 		vivid_clear_fb(dev);
293dacca5f0SHans Verkuil 		break;
294dacca5f0SHans Verkuil 	}
295dacca5f0SHans Verkuil 	return 0;
296dacca5f0SHans Verkuil }
297dacca5f0SHans Verkuil 
298dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_fb_ctrl_ops = {
299dacca5f0SHans Verkuil 	.s_ctrl = vivid_fb_s_ctrl,
300dacca5f0SHans Verkuil };
301dacca5f0SHans Verkuil 
302dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_clear_fb = {
303dacca5f0SHans Verkuil 	.ops = &vivid_fb_ctrl_ops,
304dacca5f0SHans Verkuil 	.id = VIVID_CID_CLEAR_FB,
305dacca5f0SHans Verkuil 	.name = "Clear Framebuffer",
306dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
307dacca5f0SHans Verkuil };
308dacca5f0SHans Verkuil 
309dacca5f0SHans Verkuil 
310dacca5f0SHans Verkuil /* Video User Controls */
311dacca5f0SHans Verkuil 
312dacca5f0SHans Verkuil static int vivid_user_vid_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
313dacca5f0SHans Verkuil {
314dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid);
315dacca5f0SHans Verkuil 
316dacca5f0SHans Verkuil 	switch (ctrl->id) {
317dacca5f0SHans Verkuil 	case V4L2_CID_AUTOGAIN:
318dacca5f0SHans Verkuil 		dev->gain->val = (jiffies_to_msecs(jiffies) / 1000) & 0xff;
319dacca5f0SHans Verkuil 		break;
320dacca5f0SHans Verkuil 	}
321dacca5f0SHans Verkuil 	return 0;
322dacca5f0SHans Verkuil }
323dacca5f0SHans Verkuil 
324dacca5f0SHans Verkuil static int vivid_user_vid_s_ctrl(struct v4l2_ctrl *ctrl)
325dacca5f0SHans Verkuil {
326dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid);
327dacca5f0SHans Verkuil 
328dacca5f0SHans Verkuil 	switch (ctrl->id) {
329dacca5f0SHans Verkuil 	case V4L2_CID_BRIGHTNESS:
330dacca5f0SHans Verkuil 		dev->input_brightness[dev->input] = ctrl->val - dev->input * 128;
331dacca5f0SHans Verkuil 		tpg_s_brightness(&dev->tpg, dev->input_brightness[dev->input]);
332dacca5f0SHans Verkuil 		break;
333dacca5f0SHans Verkuil 	case V4L2_CID_CONTRAST:
334dacca5f0SHans Verkuil 		tpg_s_contrast(&dev->tpg, ctrl->val);
335dacca5f0SHans Verkuil 		break;
336dacca5f0SHans Verkuil 	case V4L2_CID_SATURATION:
337dacca5f0SHans Verkuil 		tpg_s_saturation(&dev->tpg, ctrl->val);
338dacca5f0SHans Verkuil 		break;
339dacca5f0SHans Verkuil 	case V4L2_CID_HUE:
340dacca5f0SHans Verkuil 		tpg_s_hue(&dev->tpg, ctrl->val);
341dacca5f0SHans Verkuil 		break;
342dacca5f0SHans Verkuil 	case V4L2_CID_HFLIP:
343dacca5f0SHans Verkuil 		dev->hflip = ctrl->val;
344dacca5f0SHans Verkuil 		tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
345dacca5f0SHans Verkuil 		break;
346dacca5f0SHans Verkuil 	case V4L2_CID_VFLIP:
347dacca5f0SHans Verkuil 		dev->vflip = ctrl->val;
348dacca5f0SHans Verkuil 		tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
349dacca5f0SHans Verkuil 		break;
350dacca5f0SHans Verkuil 	case V4L2_CID_ALPHA_COMPONENT:
351dacca5f0SHans Verkuil 		tpg_s_alpha_component(&dev->tpg, ctrl->val);
352dacca5f0SHans Verkuil 		break;
353dacca5f0SHans Verkuil 	}
354dacca5f0SHans Verkuil 	return 0;
355dacca5f0SHans Verkuil }
356dacca5f0SHans Verkuil 
357dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = {
358dacca5f0SHans Verkuil 	.g_volatile_ctrl = vivid_user_vid_g_volatile_ctrl,
359dacca5f0SHans Verkuil 	.s_ctrl = vivid_user_vid_s_ctrl,
360dacca5f0SHans Verkuil };
361dacca5f0SHans Verkuil 
362dacca5f0SHans Verkuil 
363dacca5f0SHans Verkuil /* Video Capture Controls */
364dacca5f0SHans Verkuil 
365dacca5f0SHans Verkuil static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
366dacca5f0SHans Verkuil {
367dacca5f0SHans Verkuil 	static const u32 colorspaces[] = {
368dacca5f0SHans Verkuil 		V4L2_COLORSPACE_SMPTE170M,
369dacca5f0SHans Verkuil 		V4L2_COLORSPACE_REC709,
370dacca5f0SHans Verkuil 		V4L2_COLORSPACE_SRGB,
371dacca5f0SHans Verkuil 		V4L2_COLORSPACE_OPRGB,
372dacca5f0SHans Verkuil 		V4L2_COLORSPACE_BT2020,
373dacca5f0SHans Verkuil 		V4L2_COLORSPACE_DCI_P3,
374dacca5f0SHans Verkuil 		V4L2_COLORSPACE_SMPTE240M,
375dacca5f0SHans Verkuil 		V4L2_COLORSPACE_470_SYSTEM_M,
376dacca5f0SHans Verkuil 		V4L2_COLORSPACE_470_SYSTEM_BG,
377dacca5f0SHans Verkuil 	};
378dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap);
379dacca5f0SHans Verkuil 	unsigned int i, j;
380dacca5f0SHans Verkuil 
381dacca5f0SHans Verkuil 	switch (ctrl->id) {
382dacca5f0SHans Verkuil 	case VIVID_CID_TEST_PATTERN:
383dacca5f0SHans Verkuil 		vivid_update_quality(dev);
384dacca5f0SHans Verkuil 		tpg_s_pattern(&dev->tpg, ctrl->val);
385dacca5f0SHans Verkuil 		break;
386dacca5f0SHans Verkuil 	case VIVID_CID_COLORSPACE:
387dacca5f0SHans Verkuil 		tpg_s_colorspace(&dev->tpg, colorspaces[ctrl->val]);
388dacca5f0SHans Verkuil 		vivid_send_source_change(dev, TV);
389dacca5f0SHans Verkuil 		vivid_send_source_change(dev, SVID);
390dacca5f0SHans Verkuil 		vivid_send_source_change(dev, HDMI);
391dacca5f0SHans Verkuil 		vivid_send_source_change(dev, WEBCAM);
392dacca5f0SHans Verkuil 		break;
393dacca5f0SHans Verkuil 	case VIVID_CID_XFER_FUNC:
394dacca5f0SHans Verkuil 		tpg_s_xfer_func(&dev->tpg, ctrl->val);
395dacca5f0SHans Verkuil 		vivid_send_source_change(dev, TV);
396dacca5f0SHans Verkuil 		vivid_send_source_change(dev, SVID);
397dacca5f0SHans Verkuil 		vivid_send_source_change(dev, HDMI);
398dacca5f0SHans Verkuil 		vivid_send_source_change(dev, WEBCAM);
399dacca5f0SHans Verkuil 		break;
400dacca5f0SHans Verkuil 	case VIVID_CID_YCBCR_ENC:
401dacca5f0SHans Verkuil 		tpg_s_ycbcr_enc(&dev->tpg, ctrl->val);
402dacca5f0SHans Verkuil 		vivid_send_source_change(dev, TV);
403dacca5f0SHans Verkuil 		vivid_send_source_change(dev, SVID);
404dacca5f0SHans Verkuil 		vivid_send_source_change(dev, HDMI);
405dacca5f0SHans Verkuil 		vivid_send_source_change(dev, WEBCAM);
406dacca5f0SHans Verkuil 		break;
407dacca5f0SHans Verkuil 	case VIVID_CID_HSV_ENC:
408dacca5f0SHans Verkuil 		tpg_s_hsv_enc(&dev->tpg, ctrl->val ? V4L2_HSV_ENC_256 :
409dacca5f0SHans Verkuil 						     V4L2_HSV_ENC_180);
410dacca5f0SHans Verkuil 		vivid_send_source_change(dev, TV);
411dacca5f0SHans Verkuil 		vivid_send_source_change(dev, SVID);
412dacca5f0SHans Verkuil 		vivid_send_source_change(dev, HDMI);
413dacca5f0SHans Verkuil 		vivid_send_source_change(dev, WEBCAM);
414dacca5f0SHans Verkuil 		break;
415dacca5f0SHans Verkuil 	case VIVID_CID_QUANTIZATION:
416dacca5f0SHans Verkuil 		tpg_s_quantization(&dev->tpg, ctrl->val);
417dacca5f0SHans Verkuil 		vivid_send_source_change(dev, TV);
418dacca5f0SHans Verkuil 		vivid_send_source_change(dev, SVID);
419dacca5f0SHans Verkuil 		vivid_send_source_change(dev, HDMI);
420dacca5f0SHans Verkuil 		vivid_send_source_change(dev, WEBCAM);
421dacca5f0SHans Verkuil 		break;
422dacca5f0SHans Verkuil 	case V4L2_CID_DV_RX_RGB_RANGE:
423dacca5f0SHans Verkuil 		if (!vivid_is_hdmi_cap(dev))
424dacca5f0SHans Verkuil 			break;
425dacca5f0SHans Verkuil 		tpg_s_rgb_range(&dev->tpg, ctrl->val);
426dacca5f0SHans Verkuil 		break;
427dacca5f0SHans Verkuil 	case VIVID_CID_LIMITED_RGB_RANGE:
428dacca5f0SHans Verkuil 		tpg_s_real_rgb_range(&dev->tpg, ctrl->val ?
429dacca5f0SHans Verkuil 				V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL);
430dacca5f0SHans Verkuil 		break;
431dacca5f0SHans Verkuil 	case VIVID_CID_ALPHA_MODE:
432dacca5f0SHans Verkuil 		tpg_s_alpha_mode(&dev->tpg, ctrl->val);
433dacca5f0SHans Verkuil 		break;
434dacca5f0SHans Verkuil 	case VIVID_CID_HOR_MOVEMENT:
435dacca5f0SHans Verkuil 		tpg_s_mv_hor_mode(&dev->tpg, ctrl->val);
436dacca5f0SHans Verkuil 		break;
437dacca5f0SHans Verkuil 	case VIVID_CID_VERT_MOVEMENT:
438dacca5f0SHans Verkuil 		tpg_s_mv_vert_mode(&dev->tpg, ctrl->val);
439dacca5f0SHans Verkuil 		break;
440dacca5f0SHans Verkuil 	case VIVID_CID_OSD_TEXT_MODE:
441dacca5f0SHans Verkuil 		dev->osd_mode = ctrl->val;
442dacca5f0SHans Verkuil 		break;
443dacca5f0SHans Verkuil 	case VIVID_CID_PERCENTAGE_FILL:
444dacca5f0SHans Verkuil 		tpg_s_perc_fill(&dev->tpg, ctrl->val);
445dacca5f0SHans Verkuil 		for (i = 0; i < VIDEO_MAX_FRAME; i++)
446dacca5f0SHans Verkuil 			dev->must_blank[i] = ctrl->val < 100;
447dacca5f0SHans Verkuil 		break;
448dacca5f0SHans Verkuil 	case VIVID_CID_INSERT_SAV:
449dacca5f0SHans Verkuil 		tpg_s_insert_sav(&dev->tpg, ctrl->val);
450dacca5f0SHans Verkuil 		break;
451dacca5f0SHans Verkuil 	case VIVID_CID_INSERT_EAV:
452dacca5f0SHans Verkuil 		tpg_s_insert_eav(&dev->tpg, ctrl->val);
453dacca5f0SHans Verkuil 		break;
454dacca5f0SHans Verkuil 	case VIVID_CID_HFLIP:
455dacca5f0SHans Verkuil 		dev->sensor_hflip = ctrl->val;
456dacca5f0SHans Verkuil 		tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
457dacca5f0SHans Verkuil 		break;
458dacca5f0SHans Verkuil 	case VIVID_CID_VFLIP:
459dacca5f0SHans Verkuil 		dev->sensor_vflip = ctrl->val;
460dacca5f0SHans Verkuil 		tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
461dacca5f0SHans Verkuil 		break;
462dacca5f0SHans Verkuil 	case VIVID_CID_REDUCED_FPS:
463dacca5f0SHans Verkuil 		dev->reduced_fps = ctrl->val;
464dacca5f0SHans Verkuil 		vivid_update_format_cap(dev, true);
465dacca5f0SHans Verkuil 		break;
466dacca5f0SHans Verkuil 	case VIVID_CID_HAS_CROP_CAP:
467dacca5f0SHans Verkuil 		dev->has_crop_cap = ctrl->val;
468dacca5f0SHans Verkuil 		vivid_update_format_cap(dev, true);
469dacca5f0SHans Verkuil 		break;
470dacca5f0SHans Verkuil 	case VIVID_CID_HAS_COMPOSE_CAP:
471dacca5f0SHans Verkuil 		dev->has_compose_cap = ctrl->val;
472dacca5f0SHans Verkuil 		vivid_update_format_cap(dev, true);
473dacca5f0SHans Verkuil 		break;
474dacca5f0SHans Verkuil 	case VIVID_CID_HAS_SCALER_CAP:
475dacca5f0SHans Verkuil 		dev->has_scaler_cap = ctrl->val;
476dacca5f0SHans Verkuil 		vivid_update_format_cap(dev, true);
477dacca5f0SHans Verkuil 		break;
478dacca5f0SHans Verkuil 	case VIVID_CID_SHOW_BORDER:
479dacca5f0SHans Verkuil 		tpg_s_show_border(&dev->tpg, ctrl->val);
480dacca5f0SHans Verkuil 		break;
481dacca5f0SHans Verkuil 	case VIVID_CID_SHOW_SQUARE:
482dacca5f0SHans Verkuil 		tpg_s_show_square(&dev->tpg, ctrl->val);
483dacca5f0SHans Verkuil 		break;
484dacca5f0SHans Verkuil 	case VIVID_CID_STD_ASPECT_RATIO:
485dacca5f0SHans Verkuil 		dev->std_aspect_ratio[dev->input] = ctrl->val;
486dacca5f0SHans Verkuil 		tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
487dacca5f0SHans Verkuil 		break;
488dacca5f0SHans Verkuil 	case VIVID_CID_DV_TIMINGS_SIGNAL_MODE:
489dacca5f0SHans Verkuil 		dev->dv_timings_signal_mode[dev->input] =
490dacca5f0SHans Verkuil 			dev->ctrl_dv_timings_signal_mode->val;
491dacca5f0SHans Verkuil 		dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val;
492dacca5f0SHans Verkuil 
493dacca5f0SHans Verkuil 		dev->power_present = 0;
494dacca5f0SHans Verkuil 		for (i = 0, j = 0;
495dacca5f0SHans Verkuil 		     i < ARRAY_SIZE(dev->dv_timings_signal_mode);
496dacca5f0SHans Verkuil 		     i++)
497dacca5f0SHans Verkuil 			if (dev->input_type[i] == HDMI) {
498dacca5f0SHans Verkuil 				if (dev->dv_timings_signal_mode[i] != NO_SIGNAL)
499dacca5f0SHans Verkuil 					dev->power_present |= (1 << j);
500dacca5f0SHans Verkuil 				j++;
501dacca5f0SHans Verkuil 			}
502dacca5f0SHans Verkuil 		__v4l2_ctrl_s_ctrl(dev->ctrl_rx_power_present,
503dacca5f0SHans Verkuil 				   dev->power_present);
504dacca5f0SHans Verkuil 
505dacca5f0SHans Verkuil 		v4l2_ctrl_activate(dev->ctrl_dv_timings,
506dacca5f0SHans Verkuil 			dev->dv_timings_signal_mode[dev->input] ==
507dacca5f0SHans Verkuil 				SELECTED_DV_TIMINGS);
508dacca5f0SHans Verkuil 
509dacca5f0SHans Verkuil 		vivid_update_quality(dev);
510dacca5f0SHans Verkuil 		vivid_send_source_change(dev, HDMI);
511dacca5f0SHans Verkuil 		break;
512dacca5f0SHans Verkuil 	case VIVID_CID_DV_TIMINGS_ASPECT_RATIO:
513dacca5f0SHans Verkuil 		dev->dv_timings_aspect_ratio[dev->input] = ctrl->val;
514dacca5f0SHans Verkuil 		tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
515dacca5f0SHans Verkuil 		break;
516dacca5f0SHans Verkuil 	case VIVID_CID_TSTAMP_SRC:
517dacca5f0SHans Verkuil 		dev->tstamp_src_is_soe = ctrl->val;
518dacca5f0SHans Verkuil 		dev->vb_vid_cap_q.timestamp_flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
519dacca5f0SHans Verkuil 		if (dev->tstamp_src_is_soe)
520dacca5f0SHans Verkuil 			dev->vb_vid_cap_q.timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
521dacca5f0SHans Verkuil 		break;
522dacca5f0SHans Verkuil 	case VIVID_CID_MAX_EDID_BLOCKS:
523dacca5f0SHans Verkuil 		dev->edid_max_blocks = ctrl->val;
524dacca5f0SHans Verkuil 		if (dev->edid_blocks > dev->edid_max_blocks)
525dacca5f0SHans Verkuil 			dev->edid_blocks = dev->edid_max_blocks;
526dacca5f0SHans Verkuil 		break;
527dacca5f0SHans Verkuil 	}
528dacca5f0SHans Verkuil 	return 0;
529dacca5f0SHans Verkuil }
530dacca5f0SHans Verkuil 
531dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_vid_cap_ctrl_ops = {
532dacca5f0SHans Verkuil 	.s_ctrl = vivid_vid_cap_s_ctrl,
533dacca5f0SHans Verkuil };
534dacca5f0SHans Verkuil 
535dacca5f0SHans Verkuil static const char * const vivid_ctrl_hor_movement_strings[] = {
536dacca5f0SHans Verkuil 	"Move Left Fast",
537dacca5f0SHans Verkuil 	"Move Left",
538dacca5f0SHans Verkuil 	"Move Left Slow",
539dacca5f0SHans Verkuil 	"No Movement",
540dacca5f0SHans Verkuil 	"Move Right Slow",
541dacca5f0SHans Verkuil 	"Move Right",
542dacca5f0SHans Verkuil 	"Move Right Fast",
543dacca5f0SHans Verkuil 	NULL,
544dacca5f0SHans Verkuil };
545dacca5f0SHans Verkuil 
546dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_hor_movement = {
547dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
548dacca5f0SHans Verkuil 	.id = VIVID_CID_HOR_MOVEMENT,
549dacca5f0SHans Verkuil 	.name = "Horizontal Movement",
550dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
551dacca5f0SHans Verkuil 	.max = TPG_MOVE_POS_FAST,
552dacca5f0SHans Verkuil 	.def = TPG_MOVE_NONE,
553dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_hor_movement_strings,
554dacca5f0SHans Verkuil };
555dacca5f0SHans Verkuil 
556dacca5f0SHans Verkuil static const char * const vivid_ctrl_vert_movement_strings[] = {
557dacca5f0SHans Verkuil 	"Move Up Fast",
558dacca5f0SHans Verkuil 	"Move Up",
559dacca5f0SHans Verkuil 	"Move Up Slow",
560dacca5f0SHans Verkuil 	"No Movement",
561dacca5f0SHans Verkuil 	"Move Down Slow",
562dacca5f0SHans Verkuil 	"Move Down",
563dacca5f0SHans Verkuil 	"Move Down Fast",
564dacca5f0SHans Verkuil 	NULL,
565dacca5f0SHans Verkuil };
566dacca5f0SHans Verkuil 
567dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_vert_movement = {
568dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
569dacca5f0SHans Verkuil 	.id = VIVID_CID_VERT_MOVEMENT,
570dacca5f0SHans Verkuil 	.name = "Vertical Movement",
571dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
572dacca5f0SHans Verkuil 	.max = TPG_MOVE_POS_FAST,
573dacca5f0SHans Verkuil 	.def = TPG_MOVE_NONE,
574dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_vert_movement_strings,
575dacca5f0SHans Verkuil };
576dacca5f0SHans Verkuil 
577dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_show_border = {
578dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
579dacca5f0SHans Verkuil 	.id = VIVID_CID_SHOW_BORDER,
580dacca5f0SHans Verkuil 	.name = "Show Border",
581dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
582dacca5f0SHans Verkuil 	.max = 1,
583dacca5f0SHans Verkuil 	.step = 1,
584dacca5f0SHans Verkuil };
585dacca5f0SHans Verkuil 
586dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_show_square = {
587dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
588dacca5f0SHans Verkuil 	.id = VIVID_CID_SHOW_SQUARE,
589dacca5f0SHans Verkuil 	.name = "Show Square",
590dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
591dacca5f0SHans Verkuil 	.max = 1,
592dacca5f0SHans Verkuil 	.step = 1,
593dacca5f0SHans Verkuil };
594dacca5f0SHans Verkuil 
595dacca5f0SHans Verkuil static const char * const vivid_ctrl_osd_mode_strings[] = {
596dacca5f0SHans Verkuil 	"All",
597dacca5f0SHans Verkuil 	"Counters Only",
598dacca5f0SHans Verkuil 	"None",
599dacca5f0SHans Verkuil 	NULL,
600dacca5f0SHans Verkuil };
601dacca5f0SHans Verkuil 
602dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_osd_mode = {
603dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
604dacca5f0SHans Verkuil 	.id = VIVID_CID_OSD_TEXT_MODE,
605dacca5f0SHans Verkuil 	.name = "OSD Text Mode",
606dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
607dacca5f0SHans Verkuil 	.max = ARRAY_SIZE(vivid_ctrl_osd_mode_strings) - 2,
608dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_osd_mode_strings,
609dacca5f0SHans Verkuil };
610dacca5f0SHans Verkuil 
611dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_perc_fill = {
612dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
613dacca5f0SHans Verkuil 	.id = VIVID_CID_PERCENTAGE_FILL,
614dacca5f0SHans Verkuil 	.name = "Fill Percentage of Frame",
615dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
616dacca5f0SHans Verkuil 	.min = 0,
617dacca5f0SHans Verkuil 	.max = 100,
618dacca5f0SHans Verkuil 	.def = 100,
619dacca5f0SHans Verkuil 	.step = 1,
620dacca5f0SHans Verkuil };
621dacca5f0SHans Verkuil 
622dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_insert_sav = {
623dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
624dacca5f0SHans Verkuil 	.id = VIVID_CID_INSERT_SAV,
625dacca5f0SHans Verkuil 	.name = "Insert SAV Code in Image",
626dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
627dacca5f0SHans Verkuil 	.max = 1,
628dacca5f0SHans Verkuil 	.step = 1,
629dacca5f0SHans Verkuil };
630dacca5f0SHans Verkuil 
631dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = {
632dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
633dacca5f0SHans Verkuil 	.id = VIVID_CID_INSERT_EAV,
634dacca5f0SHans Verkuil 	.name = "Insert EAV Code in Image",
635dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
636dacca5f0SHans Verkuil 	.max = 1,
637dacca5f0SHans Verkuil 	.step = 1,
638dacca5f0SHans Verkuil };
639dacca5f0SHans Verkuil 
640dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_hflip = {
641dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
642dacca5f0SHans Verkuil 	.id = VIVID_CID_HFLIP,
643dacca5f0SHans Verkuil 	.name = "Sensor Flipped Horizontally",
644dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
645dacca5f0SHans Verkuil 	.max = 1,
646dacca5f0SHans Verkuil 	.step = 1,
647dacca5f0SHans Verkuil };
648dacca5f0SHans Verkuil 
649dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_vflip = {
650dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
651dacca5f0SHans Verkuil 	.id = VIVID_CID_VFLIP,
652dacca5f0SHans Verkuil 	.name = "Sensor Flipped Vertically",
653dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
654dacca5f0SHans Verkuil 	.max = 1,
655dacca5f0SHans Verkuil 	.step = 1,
656dacca5f0SHans Verkuil };
657dacca5f0SHans Verkuil 
658dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_reduced_fps = {
659dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
660dacca5f0SHans Verkuil 	.id = VIVID_CID_REDUCED_FPS,
661dacca5f0SHans Verkuil 	.name = "Reduced Framerate",
662dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
663dacca5f0SHans Verkuil 	.max = 1,
664dacca5f0SHans Verkuil 	.step = 1,
665dacca5f0SHans Verkuil };
666dacca5f0SHans Verkuil 
667dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = {
668dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
669dacca5f0SHans Verkuil 	.id = VIVID_CID_HAS_CROP_CAP,
670dacca5f0SHans Verkuil 	.name = "Enable Capture Cropping",
671dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
672dacca5f0SHans Verkuil 	.max = 1,
673dacca5f0SHans Verkuil 	.def = 1,
674dacca5f0SHans Verkuil 	.step = 1,
675dacca5f0SHans Verkuil };
676dacca5f0SHans Verkuil 
677dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_has_compose_cap = {
678dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
679dacca5f0SHans Verkuil 	.id = VIVID_CID_HAS_COMPOSE_CAP,
680dacca5f0SHans Verkuil 	.name = "Enable Capture Composing",
681dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
682dacca5f0SHans Verkuil 	.max = 1,
683dacca5f0SHans Verkuil 	.def = 1,
684dacca5f0SHans Verkuil 	.step = 1,
685dacca5f0SHans Verkuil };
686dacca5f0SHans Verkuil 
687dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_cap = {
688dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
689dacca5f0SHans Verkuil 	.id = VIVID_CID_HAS_SCALER_CAP,
690dacca5f0SHans Verkuil 	.name = "Enable Capture Scaler",
691dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
692dacca5f0SHans Verkuil 	.max = 1,
693dacca5f0SHans Verkuil 	.def = 1,
694dacca5f0SHans Verkuil 	.step = 1,
695dacca5f0SHans Verkuil };
696dacca5f0SHans Verkuil 
697dacca5f0SHans Verkuil static const char * const vivid_ctrl_tstamp_src_strings[] = {
698dacca5f0SHans Verkuil 	"End of Frame",
699dacca5f0SHans Verkuil 	"Start of Exposure",
700dacca5f0SHans Verkuil 	NULL,
701dacca5f0SHans Verkuil };
702dacca5f0SHans Verkuil 
703dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_tstamp_src = {
704dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
705dacca5f0SHans Verkuil 	.id = VIVID_CID_TSTAMP_SRC,
706dacca5f0SHans Verkuil 	.name = "Timestamp Source",
707dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
708dacca5f0SHans Verkuil 	.max = ARRAY_SIZE(vivid_ctrl_tstamp_src_strings) - 2,
709dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_tstamp_src_strings,
710dacca5f0SHans Verkuil };
711dacca5f0SHans Verkuil 
712dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_std_aspect_ratio = {
713dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
714dacca5f0SHans Verkuil 	.id = VIVID_CID_STD_ASPECT_RATIO,
715dacca5f0SHans Verkuil 	.name = "Standard Aspect Ratio",
716dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
717dacca5f0SHans Verkuil 	.min = 1,
718dacca5f0SHans Verkuil 	.max = 4,
719dacca5f0SHans Verkuil 	.def = 1,
720dacca5f0SHans Verkuil 	.qmenu = tpg_aspect_strings,
721dacca5f0SHans Verkuil };
722dacca5f0SHans Verkuil 
723dacca5f0SHans Verkuil static const char * const vivid_ctrl_dv_timings_signal_mode_strings[] = {
724dacca5f0SHans Verkuil 	"Current DV Timings",
725dacca5f0SHans Verkuil 	"No Signal",
726dacca5f0SHans Verkuil 	"No Lock",
727dacca5f0SHans Verkuil 	"Out of Range",
728dacca5f0SHans Verkuil 	"Selected DV Timings",
729dacca5f0SHans Verkuil 	"Cycle Through All DV Timings",
730dacca5f0SHans Verkuil 	"Custom DV Timings",
731dacca5f0SHans Verkuil 	NULL,
732dacca5f0SHans Verkuil };
733dacca5f0SHans Verkuil 
734dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_signal_mode = {
735dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
736dacca5f0SHans Verkuil 	.id = VIVID_CID_DV_TIMINGS_SIGNAL_MODE,
737dacca5f0SHans Verkuil 	.name = "DV Timings Signal Mode",
738dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
739dacca5f0SHans Verkuil 	.max = 5,
740dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_dv_timings_signal_mode_strings,
741dacca5f0SHans Verkuil };
742dacca5f0SHans Verkuil 
743dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_aspect_ratio = {
744dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
745dacca5f0SHans Verkuil 	.id = VIVID_CID_DV_TIMINGS_ASPECT_RATIO,
746dacca5f0SHans Verkuil 	.name = "DV Timings Aspect Ratio",
747dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
748dacca5f0SHans Verkuil 	.max = 3,
749dacca5f0SHans Verkuil 	.qmenu = tpg_aspect_strings,
750dacca5f0SHans Verkuil };
751dacca5f0SHans Verkuil 
752dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = {
753dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
754dacca5f0SHans Verkuil 	.id = VIVID_CID_MAX_EDID_BLOCKS,
755dacca5f0SHans Verkuil 	.name = "Maximum EDID Blocks",
756dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
757dacca5f0SHans Verkuil 	.min = 1,
758dacca5f0SHans Verkuil 	.max = 256,
759dacca5f0SHans Verkuil 	.def = 2,
760dacca5f0SHans Verkuil 	.step = 1,
761dacca5f0SHans Verkuil };
762dacca5f0SHans Verkuil 
763dacca5f0SHans Verkuil static const char * const vivid_ctrl_colorspace_strings[] = {
764dacca5f0SHans Verkuil 	"SMPTE 170M",
765dacca5f0SHans Verkuil 	"Rec. 709",
766dacca5f0SHans Verkuil 	"sRGB",
767dacca5f0SHans Verkuil 	"opRGB",
768dacca5f0SHans Verkuil 	"BT.2020",
769dacca5f0SHans Verkuil 	"DCI-P3",
770dacca5f0SHans Verkuil 	"SMPTE 240M",
771dacca5f0SHans Verkuil 	"470 System M",
772dacca5f0SHans Verkuil 	"470 System BG",
773dacca5f0SHans Verkuil 	NULL,
774dacca5f0SHans Verkuil };
775dacca5f0SHans Verkuil 
776dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_colorspace = {
777dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
778dacca5f0SHans Verkuil 	.id = VIVID_CID_COLORSPACE,
779dacca5f0SHans Verkuil 	.name = "Colorspace",
780dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
781dacca5f0SHans Verkuil 	.max = ARRAY_SIZE(vivid_ctrl_colorspace_strings) - 2,
782dacca5f0SHans Verkuil 	.def = 2,
783dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_colorspace_strings,
784dacca5f0SHans Verkuil };
785dacca5f0SHans Verkuil 
786dacca5f0SHans Verkuil static const char * const vivid_ctrl_xfer_func_strings[] = {
787dacca5f0SHans Verkuil 	"Default",
788dacca5f0SHans Verkuil 	"Rec. 709",
789dacca5f0SHans Verkuil 	"sRGB",
790dacca5f0SHans Verkuil 	"opRGB",
791dacca5f0SHans Verkuil 	"SMPTE 240M",
792dacca5f0SHans Verkuil 	"None",
793dacca5f0SHans Verkuil 	"DCI-P3",
794dacca5f0SHans Verkuil 	"SMPTE 2084",
795dacca5f0SHans Verkuil 	NULL,
796dacca5f0SHans Verkuil };
797dacca5f0SHans Verkuil 
798dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_xfer_func = {
799dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
800dacca5f0SHans Verkuil 	.id = VIVID_CID_XFER_FUNC,
801dacca5f0SHans Verkuil 	.name = "Transfer Function",
802dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
803dacca5f0SHans Verkuil 	.max = ARRAY_SIZE(vivid_ctrl_xfer_func_strings) - 2,
804dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_xfer_func_strings,
805dacca5f0SHans Verkuil };
806dacca5f0SHans Verkuil 
807dacca5f0SHans Verkuil static const char * const vivid_ctrl_ycbcr_enc_strings[] = {
808dacca5f0SHans Verkuil 	"Default",
809dacca5f0SHans Verkuil 	"ITU-R 601",
810dacca5f0SHans Verkuil 	"Rec. 709",
811dacca5f0SHans Verkuil 	"xvYCC 601",
812dacca5f0SHans Verkuil 	"xvYCC 709",
813dacca5f0SHans Verkuil 	"",
814dacca5f0SHans Verkuil 	"BT.2020",
815dacca5f0SHans Verkuil 	"BT.2020 Constant Luminance",
816dacca5f0SHans Verkuil 	"SMPTE 240M",
817dacca5f0SHans Verkuil 	NULL,
818dacca5f0SHans Verkuil };
819dacca5f0SHans Verkuil 
820dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_ycbcr_enc = {
821dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
822dacca5f0SHans Verkuil 	.id = VIVID_CID_YCBCR_ENC,
823dacca5f0SHans Verkuil 	.name = "Y'CbCr Encoding",
824dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
825dacca5f0SHans Verkuil 	.menu_skip_mask = 1 << 5,
826dacca5f0SHans Verkuil 	.max = ARRAY_SIZE(vivid_ctrl_ycbcr_enc_strings) - 2,
827dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_ycbcr_enc_strings,
828dacca5f0SHans Verkuil };
829dacca5f0SHans Verkuil 
830dacca5f0SHans Verkuil static const char * const vivid_ctrl_hsv_enc_strings[] = {
831dacca5f0SHans Verkuil 	"Hue 0-179",
832dacca5f0SHans Verkuil 	"Hue 0-256",
833dacca5f0SHans Verkuil 	NULL,
834dacca5f0SHans Verkuil };
835dacca5f0SHans Verkuil 
836dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_hsv_enc = {
837dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
838dacca5f0SHans Verkuil 	.id = VIVID_CID_HSV_ENC,
839dacca5f0SHans Verkuil 	.name = "HSV Encoding",
840dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
841dacca5f0SHans Verkuil 	.max = ARRAY_SIZE(vivid_ctrl_hsv_enc_strings) - 2,
842dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_hsv_enc_strings,
843dacca5f0SHans Verkuil };
844dacca5f0SHans Verkuil 
845dacca5f0SHans Verkuil static const char * const vivid_ctrl_quantization_strings[] = {
846dacca5f0SHans Verkuil 	"Default",
847dacca5f0SHans Verkuil 	"Full Range",
848dacca5f0SHans Verkuil 	"Limited Range",
849dacca5f0SHans Verkuil 	NULL,
850dacca5f0SHans Verkuil };
851dacca5f0SHans Verkuil 
852dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_quantization = {
853dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
854dacca5f0SHans Verkuil 	.id = VIVID_CID_QUANTIZATION,
855dacca5f0SHans Verkuil 	.name = "Quantization",
856dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
857dacca5f0SHans Verkuil 	.max = ARRAY_SIZE(vivid_ctrl_quantization_strings) - 2,
858dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_quantization_strings,
859dacca5f0SHans Verkuil };
860dacca5f0SHans Verkuil 
861dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = {
862dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
863dacca5f0SHans Verkuil 	.id = VIVID_CID_ALPHA_MODE,
864dacca5f0SHans Verkuil 	.name = "Apply Alpha To Red Only",
865dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
866dacca5f0SHans Verkuil 	.max = 1,
867dacca5f0SHans Verkuil 	.step = 1,
868dacca5f0SHans Verkuil };
869dacca5f0SHans Verkuil 
870dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = {
871dacca5f0SHans Verkuil 	.ops = &vivid_vid_cap_ctrl_ops,
872dacca5f0SHans Verkuil 	.id = VIVID_CID_LIMITED_RGB_RANGE,
873dacca5f0SHans Verkuil 	.name = "Limited RGB Range (16-235)",
874dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
875dacca5f0SHans Verkuil 	.max = 1,
876dacca5f0SHans Verkuil 	.step = 1,
877dacca5f0SHans Verkuil };
878dacca5f0SHans Verkuil 
879dacca5f0SHans Verkuil 
880dacca5f0SHans Verkuil /* Video Loop Control */
881dacca5f0SHans Verkuil 
882dacca5f0SHans Verkuil static int vivid_loop_cap_s_ctrl(struct v4l2_ctrl *ctrl)
883dacca5f0SHans Verkuil {
884dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_cap);
885dacca5f0SHans Verkuil 
886dacca5f0SHans Verkuil 	switch (ctrl->id) {
887dacca5f0SHans Verkuil 	case VIVID_CID_LOOP_VIDEO:
888dacca5f0SHans Verkuil 		dev->loop_video = ctrl->val;
889dacca5f0SHans Verkuil 		vivid_update_quality(dev);
890dacca5f0SHans Verkuil 		vivid_send_source_change(dev, SVID);
891dacca5f0SHans Verkuil 		vivid_send_source_change(dev, HDMI);
892dacca5f0SHans Verkuil 		break;
893dacca5f0SHans Verkuil 	}
894dacca5f0SHans Verkuil 	return 0;
895dacca5f0SHans Verkuil }
896dacca5f0SHans Verkuil 
897dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_loop_cap_ctrl_ops = {
898dacca5f0SHans Verkuil 	.s_ctrl = vivid_loop_cap_s_ctrl,
899dacca5f0SHans Verkuil };
900dacca5f0SHans Verkuil 
901dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_loop_video = {
902dacca5f0SHans Verkuil 	.ops = &vivid_loop_cap_ctrl_ops,
903dacca5f0SHans Verkuil 	.id = VIVID_CID_LOOP_VIDEO,
904dacca5f0SHans Verkuil 	.name = "Loop Video",
905dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
906dacca5f0SHans Verkuil 	.max = 1,
907dacca5f0SHans Verkuil 	.step = 1,
908dacca5f0SHans Verkuil };
909dacca5f0SHans Verkuil 
910dacca5f0SHans Verkuil 
911dacca5f0SHans Verkuil /* VBI Capture Control */
912dacca5f0SHans Verkuil 
913dacca5f0SHans Verkuil static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl)
914dacca5f0SHans Verkuil {
915dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vbi_cap);
916dacca5f0SHans Verkuil 
917dacca5f0SHans Verkuil 	switch (ctrl->id) {
918dacca5f0SHans Verkuil 	case VIVID_CID_VBI_CAP_INTERLACED:
919dacca5f0SHans Verkuil 		dev->vbi_cap_interlaced = ctrl->val;
920dacca5f0SHans Verkuil 		break;
921dacca5f0SHans Verkuil 	}
922dacca5f0SHans Verkuil 	return 0;
923dacca5f0SHans Verkuil }
924dacca5f0SHans Verkuil 
925dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_vbi_cap_ctrl_ops = {
926dacca5f0SHans Verkuil 	.s_ctrl = vivid_vbi_cap_s_ctrl,
927dacca5f0SHans Verkuil };
928dacca5f0SHans Verkuil 
929dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_vbi_cap_interlaced = {
930dacca5f0SHans Verkuil 	.ops = &vivid_vbi_cap_ctrl_ops,
931dacca5f0SHans Verkuil 	.id = VIVID_CID_VBI_CAP_INTERLACED,
932dacca5f0SHans Verkuil 	.name = "Interlaced VBI Format",
933dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
934dacca5f0SHans Verkuil 	.max = 1,
935dacca5f0SHans Verkuil 	.step = 1,
936dacca5f0SHans Verkuil };
937dacca5f0SHans Verkuil 
938dacca5f0SHans Verkuil 
939dacca5f0SHans Verkuil /* Video Output Controls */
940dacca5f0SHans Verkuil 
941dacca5f0SHans Verkuil static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
942dacca5f0SHans Verkuil {
943dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out);
944dacca5f0SHans Verkuil 	struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
945dacca5f0SHans Verkuil 	u32 display_present = 0;
946dacca5f0SHans Verkuil 	unsigned int i, j, bus_idx;
947dacca5f0SHans Verkuil 
948dacca5f0SHans Verkuil 	switch (ctrl->id) {
949dacca5f0SHans Verkuil 	case VIVID_CID_HAS_CROP_OUT:
950dacca5f0SHans Verkuil 		dev->has_crop_out = ctrl->val;
951dacca5f0SHans Verkuil 		vivid_update_format_out(dev);
952dacca5f0SHans Verkuil 		break;
953dacca5f0SHans Verkuil 	case VIVID_CID_HAS_COMPOSE_OUT:
954dacca5f0SHans Verkuil 		dev->has_compose_out = ctrl->val;
955dacca5f0SHans Verkuil 		vivid_update_format_out(dev);
956dacca5f0SHans Verkuil 		break;
957dacca5f0SHans Verkuil 	case VIVID_CID_HAS_SCALER_OUT:
958dacca5f0SHans Verkuil 		dev->has_scaler_out = ctrl->val;
959dacca5f0SHans Verkuil 		vivid_update_format_out(dev);
960dacca5f0SHans Verkuil 		break;
961dacca5f0SHans Verkuil 	case V4L2_CID_DV_TX_MODE:
962dacca5f0SHans Verkuil 		dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D;
963dacca5f0SHans Verkuil 		if (!vivid_is_hdmi_out(dev))
964dacca5f0SHans Verkuil 			break;
965dacca5f0SHans Verkuil 		if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) {
966dacca5f0SHans Verkuil 			if (bt->width == 720 && bt->height <= 576)
967dacca5f0SHans Verkuil 				dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
968dacca5f0SHans Verkuil 			else
969dacca5f0SHans Verkuil 				dev->colorspace_out = V4L2_COLORSPACE_REC709;
970dacca5f0SHans Verkuil 			dev->quantization_out = V4L2_QUANTIZATION_DEFAULT;
971dacca5f0SHans Verkuil 		} else {
972dacca5f0SHans Verkuil 			dev->colorspace_out = V4L2_COLORSPACE_SRGB;
973dacca5f0SHans Verkuil 			dev->quantization_out = dev->dvi_d_out ?
974dacca5f0SHans Verkuil 					V4L2_QUANTIZATION_LIM_RANGE :
975dacca5f0SHans Verkuil 					V4L2_QUANTIZATION_DEFAULT;
976dacca5f0SHans Verkuil 		}
977dacca5f0SHans Verkuil 		if (dev->loop_video)
978dacca5f0SHans Verkuil 			vivid_send_source_change(dev, HDMI);
979dacca5f0SHans Verkuil 		break;
980dacca5f0SHans Verkuil 	case VIVID_CID_DISPLAY_PRESENT:
981dacca5f0SHans Verkuil 		if (dev->output_type[dev->output] != HDMI)
982dacca5f0SHans Verkuil 			break;
983dacca5f0SHans Verkuil 
984dacca5f0SHans Verkuil 		dev->display_present[dev->output] = ctrl->val;
985dacca5f0SHans Verkuil 		for (i = 0, j = 0; i < dev->num_outputs; i++)
986dacca5f0SHans Verkuil 			if (dev->output_type[i] == HDMI)
987dacca5f0SHans Verkuil 				display_present |=
988dacca5f0SHans Verkuil 					dev->display_present[i] << j++;
989dacca5f0SHans Verkuil 
990dacca5f0SHans Verkuil 		__v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, display_present);
991dacca5f0SHans Verkuil 
992dacca5f0SHans Verkuil 		if (dev->edid_blocks) {
993dacca5f0SHans Verkuil 			__v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present,
994dacca5f0SHans Verkuil 					   display_present);
995dacca5f0SHans Verkuil 			__v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug,
996dacca5f0SHans Verkuil 					   display_present);
997dacca5f0SHans Verkuil 		}
998dacca5f0SHans Verkuil 
999dacca5f0SHans Verkuil 		bus_idx = dev->cec_output2bus_map[dev->output];
1000dacca5f0SHans Verkuil 		if (!dev->cec_tx_adap[bus_idx])
1001dacca5f0SHans Verkuil 			break;
1002dacca5f0SHans Verkuil 
1003dacca5f0SHans Verkuil 		if (ctrl->val && dev->edid_blocks)
1004dacca5f0SHans Verkuil 			cec_s_phys_addr(dev->cec_tx_adap[bus_idx],
1005dacca5f0SHans Verkuil 					dev->cec_tx_adap[bus_idx]->phys_addr,
1006dacca5f0SHans Verkuil 					false);
1007dacca5f0SHans Verkuil 		else
1008dacca5f0SHans Verkuil 			cec_phys_addr_invalidate(dev->cec_tx_adap[bus_idx]);
1009dacca5f0SHans Verkuil 
1010dacca5f0SHans Verkuil 		break;
1011dacca5f0SHans Verkuil 	}
1012dacca5f0SHans Verkuil 	return 0;
1013dacca5f0SHans Verkuil }
1014dacca5f0SHans Verkuil 
1015dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_vid_out_ctrl_ops = {
1016dacca5f0SHans Verkuil 	.s_ctrl = vivid_vid_out_s_ctrl,
1017dacca5f0SHans Verkuil };
1018dacca5f0SHans Verkuil 
1019dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_has_crop_out = {
1020dacca5f0SHans Verkuil 	.ops = &vivid_vid_out_ctrl_ops,
1021dacca5f0SHans Verkuil 	.id = VIVID_CID_HAS_CROP_OUT,
1022dacca5f0SHans Verkuil 	.name = "Enable Output Cropping",
1023dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1024dacca5f0SHans Verkuil 	.max = 1,
1025dacca5f0SHans Verkuil 	.def = 1,
1026dacca5f0SHans Verkuil 	.step = 1,
1027dacca5f0SHans Verkuil };
1028dacca5f0SHans Verkuil 
1029dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_has_compose_out = {
1030dacca5f0SHans Verkuil 	.ops = &vivid_vid_out_ctrl_ops,
1031dacca5f0SHans Verkuil 	.id = VIVID_CID_HAS_COMPOSE_OUT,
1032dacca5f0SHans Verkuil 	.name = "Enable Output Composing",
1033dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1034dacca5f0SHans Verkuil 	.max = 1,
1035dacca5f0SHans Verkuil 	.def = 1,
1036dacca5f0SHans Verkuil 	.step = 1,
1037dacca5f0SHans Verkuil };
1038dacca5f0SHans Verkuil 
1039dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = {
1040dacca5f0SHans Verkuil 	.ops = &vivid_vid_out_ctrl_ops,
1041dacca5f0SHans Verkuil 	.id = VIVID_CID_HAS_SCALER_OUT,
1042dacca5f0SHans Verkuil 	.name = "Enable Output Scaler",
1043dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1044dacca5f0SHans Verkuil 	.max = 1,
1045dacca5f0SHans Verkuil 	.def = 1,
1046dacca5f0SHans Verkuil 	.step = 1,
1047dacca5f0SHans Verkuil };
1048dacca5f0SHans Verkuil 
1049dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_display_present = {
1050dacca5f0SHans Verkuil 	.ops = &vivid_vid_out_ctrl_ops,
1051dacca5f0SHans Verkuil 	.id = VIVID_CID_DISPLAY_PRESENT,
1052dacca5f0SHans Verkuil 	.name = "Display Present",
1053dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1054dacca5f0SHans Verkuil 	.max = 1,
1055dacca5f0SHans Verkuil 	.def = 1,
1056dacca5f0SHans Verkuil 	.step = 1,
1057dacca5f0SHans Verkuil };
1058dacca5f0SHans Verkuil 
1059dacca5f0SHans Verkuil /* Streaming Controls */
1060dacca5f0SHans Verkuil 
1061dacca5f0SHans Verkuil static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
1062dacca5f0SHans Verkuil {
1063dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming);
1064dacca5f0SHans Verkuil 	u64 rem;
1065dacca5f0SHans Verkuil 
1066dacca5f0SHans Verkuil 	switch (ctrl->id) {
1067dacca5f0SHans Verkuil 	case VIVID_CID_DQBUF_ERROR:
1068dacca5f0SHans Verkuil 		dev->dqbuf_error = true;
1069dacca5f0SHans Verkuil 		break;
1070dacca5f0SHans Verkuil 	case VIVID_CID_PERC_DROPPED:
1071dacca5f0SHans Verkuil 		dev->perc_dropped_buffers = ctrl->val;
1072dacca5f0SHans Verkuil 		break;
1073dacca5f0SHans Verkuil 	case VIVID_CID_QUEUE_SETUP_ERROR:
1074dacca5f0SHans Verkuil 		dev->queue_setup_error = true;
1075dacca5f0SHans Verkuil 		break;
1076dacca5f0SHans Verkuil 	case VIVID_CID_BUF_PREPARE_ERROR:
1077dacca5f0SHans Verkuil 		dev->buf_prepare_error = true;
1078dacca5f0SHans Verkuil 		break;
1079dacca5f0SHans Verkuil 	case VIVID_CID_START_STR_ERROR:
1080dacca5f0SHans Verkuil 		dev->start_streaming_error = true;
1081dacca5f0SHans Verkuil 		break;
1082dacca5f0SHans Verkuil 	case VIVID_CID_REQ_VALIDATE_ERROR:
1083dacca5f0SHans Verkuil 		dev->req_validate_error = true;
1084dacca5f0SHans Verkuil 		break;
1085dacca5f0SHans Verkuil 	case VIVID_CID_QUEUE_ERROR:
1086dacca5f0SHans Verkuil 		if (vb2_start_streaming_called(&dev->vb_vid_cap_q))
1087dacca5f0SHans Verkuil 			vb2_queue_error(&dev->vb_vid_cap_q);
1088dacca5f0SHans Verkuil 		if (vb2_start_streaming_called(&dev->vb_vbi_cap_q))
1089dacca5f0SHans Verkuil 			vb2_queue_error(&dev->vb_vbi_cap_q);
1090dacca5f0SHans Verkuil 		if (vb2_start_streaming_called(&dev->vb_vid_out_q))
1091dacca5f0SHans Verkuil 			vb2_queue_error(&dev->vb_vid_out_q);
1092dacca5f0SHans Verkuil 		if (vb2_start_streaming_called(&dev->vb_vbi_out_q))
1093dacca5f0SHans Verkuil 			vb2_queue_error(&dev->vb_vbi_out_q);
1094dacca5f0SHans Verkuil 		if (vb2_start_streaming_called(&dev->vb_sdr_cap_q))
1095dacca5f0SHans Verkuil 			vb2_queue_error(&dev->vb_sdr_cap_q);
1096dacca5f0SHans Verkuil 		break;
1097dacca5f0SHans Verkuil 	case VIVID_CID_SEQ_WRAP:
1098dacca5f0SHans Verkuil 		dev->seq_wrap = ctrl->val;
1099dacca5f0SHans Verkuil 		break;
1100dacca5f0SHans Verkuil 	case VIVID_CID_TIME_WRAP:
1101dacca5f0SHans Verkuil 		dev->time_wrap = ctrl->val;
1102dacca5f0SHans Verkuil 		if (ctrl->val == 0) {
1103dacca5f0SHans Verkuil 			dev->time_wrap_offset = 0;
1104dacca5f0SHans Verkuil 			break;
1105dacca5f0SHans Verkuil 		}
1106dacca5f0SHans Verkuil 		/*
1107dacca5f0SHans Verkuil 		 * We want to set the time 16 seconds before the 32 bit tv_sec
1108dacca5f0SHans Verkuil 		 * value of struct timeval would wrap around. So first we
1109dacca5f0SHans Verkuil 		 * calculate ktime_get_ns() % ((1 << 32) * NSEC_PER_SEC), and
1110dacca5f0SHans Verkuil 		 * then we set the offset to ((1 << 32) - 16) * NSEC_PER_SEC).
1111dacca5f0SHans Verkuil 		 */
1112dacca5f0SHans Verkuil 		div64_u64_rem(ktime_get_ns(),
1113dacca5f0SHans Verkuil 			0x100000000ULL * NSEC_PER_SEC, &rem);
1114dacca5f0SHans Verkuil 		dev->time_wrap_offset =
1115dacca5f0SHans Verkuil 			(0x100000000ULL - 16) * NSEC_PER_SEC - rem;
1116dacca5f0SHans Verkuil 		break;
1117dacca5f0SHans Verkuil 	}
1118dacca5f0SHans Verkuil 	return 0;
1119dacca5f0SHans Verkuil }
1120dacca5f0SHans Verkuil 
1121dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_streaming_ctrl_ops = {
1122dacca5f0SHans Verkuil 	.s_ctrl = vivid_streaming_s_ctrl,
1123dacca5f0SHans Verkuil };
1124dacca5f0SHans Verkuil 
1125dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_dqbuf_error = {
1126dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1127dacca5f0SHans Verkuil 	.id = VIVID_CID_DQBUF_ERROR,
1128dacca5f0SHans Verkuil 	.name = "Inject V4L2_BUF_FLAG_ERROR",
1129dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
1130dacca5f0SHans Verkuil };
1131dacca5f0SHans Verkuil 
1132dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_perc_dropped = {
1133dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1134dacca5f0SHans Verkuil 	.id = VIVID_CID_PERC_DROPPED,
1135dacca5f0SHans Verkuil 	.name = "Percentage of Dropped Buffers",
1136dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
1137dacca5f0SHans Verkuil 	.min = 0,
1138dacca5f0SHans Verkuil 	.max = 100,
1139dacca5f0SHans Verkuil 	.step = 1,
1140dacca5f0SHans Verkuil };
1141dacca5f0SHans Verkuil 
1142dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_queue_setup_error = {
1143dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1144dacca5f0SHans Verkuil 	.id = VIVID_CID_QUEUE_SETUP_ERROR,
1145dacca5f0SHans Verkuil 	.name = "Inject VIDIOC_REQBUFS Error",
1146dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
1147dacca5f0SHans Verkuil };
1148dacca5f0SHans Verkuil 
1149dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_buf_prepare_error = {
1150dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1151dacca5f0SHans Verkuil 	.id = VIVID_CID_BUF_PREPARE_ERROR,
1152dacca5f0SHans Verkuil 	.name = "Inject VIDIOC_QBUF Error",
1153dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
1154dacca5f0SHans Verkuil };
1155dacca5f0SHans Verkuil 
1156dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_start_streaming_error = {
1157dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1158dacca5f0SHans Verkuil 	.id = VIVID_CID_START_STR_ERROR,
1159dacca5f0SHans Verkuil 	.name = "Inject VIDIOC_STREAMON Error",
1160dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
1161dacca5f0SHans Verkuil };
1162dacca5f0SHans Verkuil 
1163dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_queue_error = {
1164dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1165dacca5f0SHans Verkuil 	.id = VIVID_CID_QUEUE_ERROR,
1166dacca5f0SHans Verkuil 	.name = "Inject Fatal Streaming Error",
1167dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
1168dacca5f0SHans Verkuil };
1169dacca5f0SHans Verkuil 
1170dacca5f0SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER
1171dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_req_validate_error = {
1172dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1173dacca5f0SHans Verkuil 	.id = VIVID_CID_REQ_VALIDATE_ERROR,
1174dacca5f0SHans Verkuil 	.name = "Inject req_validate() Error",
1175dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BUTTON,
1176dacca5f0SHans Verkuil };
1177dacca5f0SHans Verkuil #endif
1178dacca5f0SHans Verkuil 
1179dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_seq_wrap = {
1180dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1181dacca5f0SHans Verkuil 	.id = VIVID_CID_SEQ_WRAP,
1182dacca5f0SHans Verkuil 	.name = "Wrap Sequence Number",
1183dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1184dacca5f0SHans Verkuil 	.max = 1,
1185dacca5f0SHans Verkuil 	.step = 1,
1186dacca5f0SHans Verkuil };
1187dacca5f0SHans Verkuil 
1188dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_time_wrap = {
1189dacca5f0SHans Verkuil 	.ops = &vivid_streaming_ctrl_ops,
1190dacca5f0SHans Verkuil 	.id = VIVID_CID_TIME_WRAP,
1191dacca5f0SHans Verkuil 	.name = "Wrap Timestamp",
1192dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1193dacca5f0SHans Verkuil 	.max = 1,
1194dacca5f0SHans Verkuil 	.step = 1,
1195dacca5f0SHans Verkuil };
1196dacca5f0SHans Verkuil 
1197dacca5f0SHans Verkuil 
1198dacca5f0SHans Verkuil /* SDTV Capture Controls */
1199dacca5f0SHans Verkuil 
1200dacca5f0SHans Verkuil static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl)
1201dacca5f0SHans Verkuil {
1202dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdtv_cap);
1203dacca5f0SHans Verkuil 
1204dacca5f0SHans Verkuil 	switch (ctrl->id) {
1205dacca5f0SHans Verkuil 	case VIVID_CID_STD_SIGNAL_MODE:
1206dacca5f0SHans Verkuil 		dev->std_signal_mode[dev->input] =
1207dacca5f0SHans Verkuil 			dev->ctrl_std_signal_mode->val;
1208dacca5f0SHans Verkuil 		if (dev->std_signal_mode[dev->input] == SELECTED_STD)
1209dacca5f0SHans Verkuil 			dev->query_std[dev->input] =
1210dacca5f0SHans Verkuil 				vivid_standard[dev->ctrl_standard->val];
1211dacca5f0SHans Verkuil 		v4l2_ctrl_activate(dev->ctrl_standard,
1212dacca5f0SHans Verkuil 				   dev->std_signal_mode[dev->input] ==
1213dacca5f0SHans Verkuil 					SELECTED_STD);
1214dacca5f0SHans Verkuil 		vivid_update_quality(dev);
1215dacca5f0SHans Verkuil 		vivid_send_source_change(dev, TV);
1216dacca5f0SHans Verkuil 		vivid_send_source_change(dev, SVID);
1217dacca5f0SHans Verkuil 		break;
1218dacca5f0SHans Verkuil 	}
1219dacca5f0SHans Verkuil 	return 0;
1220dacca5f0SHans Verkuil }
1221dacca5f0SHans Verkuil 
1222dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_sdtv_cap_ctrl_ops = {
1223dacca5f0SHans Verkuil 	.s_ctrl = vivid_sdtv_cap_s_ctrl,
1224dacca5f0SHans Verkuil };
1225dacca5f0SHans Verkuil 
1226dacca5f0SHans Verkuil static const char * const vivid_ctrl_std_signal_mode_strings[] = {
1227dacca5f0SHans Verkuil 	"Current Standard",
1228dacca5f0SHans Verkuil 	"No Signal",
1229dacca5f0SHans Verkuil 	"No Lock",
1230dacca5f0SHans Verkuil 	"",
1231dacca5f0SHans Verkuil 	"Selected Standard",
1232dacca5f0SHans Verkuil 	"Cycle Through All Standards",
1233dacca5f0SHans Verkuil 	NULL,
1234dacca5f0SHans Verkuil };
1235dacca5f0SHans Verkuil 
1236dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_std_signal_mode = {
1237dacca5f0SHans Verkuil 	.ops = &vivid_sdtv_cap_ctrl_ops,
1238dacca5f0SHans Verkuil 	.id = VIVID_CID_STD_SIGNAL_MODE,
1239dacca5f0SHans Verkuil 	.name = "Standard Signal Mode",
1240dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
1241dacca5f0SHans Verkuil 	.max = ARRAY_SIZE(vivid_ctrl_std_signal_mode_strings) - 2,
1242dacca5f0SHans Verkuil 	.menu_skip_mask = 1 << 3,
1243dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_std_signal_mode_strings,
1244dacca5f0SHans Verkuil };
1245dacca5f0SHans Verkuil 
1246dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_standard = {
1247dacca5f0SHans Verkuil 	.ops = &vivid_sdtv_cap_ctrl_ops,
1248dacca5f0SHans Verkuil 	.id = VIVID_CID_STANDARD,
1249dacca5f0SHans Verkuil 	.name = "Standard",
1250dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
1251dacca5f0SHans Verkuil 	.max = 14,
1252dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_standard_strings,
1253dacca5f0SHans Verkuil };
1254dacca5f0SHans Verkuil 
1255dacca5f0SHans Verkuil 
1256dacca5f0SHans Verkuil 
1257dacca5f0SHans Verkuil /* Radio Receiver Controls */
1258dacca5f0SHans Verkuil 
1259dacca5f0SHans Verkuil static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl)
1260dacca5f0SHans Verkuil {
1261dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_rx);
1262dacca5f0SHans Verkuil 
1263dacca5f0SHans Verkuil 	switch (ctrl->id) {
1264dacca5f0SHans Verkuil 	case VIVID_CID_RADIO_SEEK_MODE:
1265dacca5f0SHans Verkuil 		dev->radio_rx_hw_seek_mode = ctrl->val;
1266dacca5f0SHans Verkuil 		break;
1267dacca5f0SHans Verkuil 	case VIVID_CID_RADIO_SEEK_PROG_LIM:
1268dacca5f0SHans Verkuil 		dev->radio_rx_hw_seek_prog_lim = ctrl->val;
1269dacca5f0SHans Verkuil 		break;
1270dacca5f0SHans Verkuil 	case VIVID_CID_RADIO_RX_RDS_RBDS:
1271dacca5f0SHans Verkuil 		dev->rds_gen.use_rbds = ctrl->val;
1272dacca5f0SHans Verkuil 		break;
1273dacca5f0SHans Verkuil 	case VIVID_CID_RADIO_RX_RDS_BLOCKIO:
1274dacca5f0SHans Verkuil 		dev->radio_rx_rds_controls = ctrl->val;
1275dacca5f0SHans Verkuil 		dev->radio_rx_caps &= ~V4L2_CAP_READWRITE;
1276dacca5f0SHans Verkuil 		dev->radio_rx_rds_use_alternates = false;
1277dacca5f0SHans Verkuil 		if (!dev->radio_rx_rds_controls) {
1278dacca5f0SHans Verkuil 			dev->radio_rx_caps |= V4L2_CAP_READWRITE;
1279dacca5f0SHans Verkuil 			__v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, 0);
1280dacca5f0SHans Verkuil 			__v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, 0);
1281dacca5f0SHans Verkuil 			__v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, 0);
1282dacca5f0SHans Verkuil 			__v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, 0);
1283dacca5f0SHans Verkuil 			__v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, "");
1284dacca5f0SHans Verkuil 			__v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, "");
1285dacca5f0SHans Verkuil 		}
1286dacca5f0SHans Verkuil 		v4l2_ctrl_activate(dev->radio_rx_rds_pty, dev->radio_rx_rds_controls);
1287dacca5f0SHans Verkuil 		v4l2_ctrl_activate(dev->radio_rx_rds_psname, dev->radio_rx_rds_controls);
1288dacca5f0SHans Verkuil 		v4l2_ctrl_activate(dev->radio_rx_rds_radiotext, dev->radio_rx_rds_controls);
1289dacca5f0SHans Verkuil 		v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls);
1290dacca5f0SHans Verkuil 		v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls);
1291dacca5f0SHans Verkuil 		v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls);
1292dacca5f0SHans Verkuil 		dev->radio_rx_dev.device_caps = dev->radio_rx_caps;
1293dacca5f0SHans Verkuil 		break;
1294dacca5f0SHans Verkuil 	case V4L2_CID_RDS_RECEPTION:
1295dacca5f0SHans Verkuil 		dev->radio_rx_rds_enabled = ctrl->val;
1296dacca5f0SHans Verkuil 		break;
1297dacca5f0SHans Verkuil 	}
1298dacca5f0SHans Verkuil 	return 0;
1299dacca5f0SHans Verkuil }
1300dacca5f0SHans Verkuil 
1301dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_radio_rx_ctrl_ops = {
1302dacca5f0SHans Verkuil 	.s_ctrl = vivid_radio_rx_s_ctrl,
1303dacca5f0SHans Verkuil };
1304dacca5f0SHans Verkuil 
1305dacca5f0SHans Verkuil static const char * const vivid_ctrl_radio_rds_mode_strings[] = {
1306dacca5f0SHans Verkuil 	"Block I/O",
1307dacca5f0SHans Verkuil 	"Controls",
1308dacca5f0SHans Verkuil 	NULL,
1309dacca5f0SHans Verkuil };
1310dacca5f0SHans Verkuil 
1311dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_blockio = {
1312dacca5f0SHans Verkuil 	.ops = &vivid_radio_rx_ctrl_ops,
1313dacca5f0SHans Verkuil 	.id = VIVID_CID_RADIO_RX_RDS_BLOCKIO,
1314dacca5f0SHans Verkuil 	.name = "RDS Rx I/O Mode",
1315dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
1316dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_radio_rds_mode_strings,
1317dacca5f0SHans Verkuil 	.max = 1,
1318dacca5f0SHans Verkuil };
1319dacca5f0SHans Verkuil 
1320dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_rbds = {
1321dacca5f0SHans Verkuil 	.ops = &vivid_radio_rx_ctrl_ops,
1322dacca5f0SHans Verkuil 	.id = VIVID_CID_RADIO_RX_RDS_RBDS,
1323dacca5f0SHans Verkuil 	.name = "Generate RBDS Instead of RDS",
1324dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1325dacca5f0SHans Verkuil 	.max = 1,
1326dacca5f0SHans Verkuil 	.step = 1,
1327dacca5f0SHans Verkuil };
1328dacca5f0SHans Verkuil 
1329dacca5f0SHans Verkuil static const char * const vivid_ctrl_radio_hw_seek_mode_strings[] = {
1330dacca5f0SHans Verkuil 	"Bounded",
1331dacca5f0SHans Verkuil 	"Wrap Around",
1332dacca5f0SHans Verkuil 	"Both",
1333dacca5f0SHans Verkuil 	NULL,
1334dacca5f0SHans Verkuil };
1335dacca5f0SHans Verkuil 
1336dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_mode = {
1337dacca5f0SHans Verkuil 	.ops = &vivid_radio_rx_ctrl_ops,
1338dacca5f0SHans Verkuil 	.id = VIVID_CID_RADIO_SEEK_MODE,
1339dacca5f0SHans Verkuil 	.name = "Radio HW Seek Mode",
1340dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
1341dacca5f0SHans Verkuil 	.max = 2,
1342dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_radio_hw_seek_mode_strings,
1343dacca5f0SHans Verkuil };
1344dacca5f0SHans Verkuil 
1345dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_prog_lim = {
1346dacca5f0SHans Verkuil 	.ops = &vivid_radio_rx_ctrl_ops,
1347dacca5f0SHans Verkuil 	.id = VIVID_CID_RADIO_SEEK_PROG_LIM,
1348dacca5f0SHans Verkuil 	.name = "Radio Programmable HW Seek",
1349dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1350dacca5f0SHans Verkuil 	.max = 1,
1351dacca5f0SHans Verkuil 	.step = 1,
1352dacca5f0SHans Verkuil };
1353dacca5f0SHans Verkuil 
1354dacca5f0SHans Verkuil 
1355dacca5f0SHans Verkuil /* Radio Transmitter Controls */
1356dacca5f0SHans Verkuil 
1357dacca5f0SHans Verkuil static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl)
1358dacca5f0SHans Verkuil {
1359dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_tx);
1360dacca5f0SHans Verkuil 
1361dacca5f0SHans Verkuil 	switch (ctrl->id) {
1362dacca5f0SHans Verkuil 	case VIVID_CID_RADIO_TX_RDS_BLOCKIO:
1363dacca5f0SHans Verkuil 		dev->radio_tx_rds_controls = ctrl->val;
1364dacca5f0SHans Verkuil 		dev->radio_tx_caps &= ~V4L2_CAP_READWRITE;
1365dacca5f0SHans Verkuil 		if (!dev->radio_tx_rds_controls)
1366dacca5f0SHans Verkuil 			dev->radio_tx_caps |= V4L2_CAP_READWRITE;
1367dacca5f0SHans Verkuil 		dev->radio_tx_dev.device_caps = dev->radio_tx_caps;
1368dacca5f0SHans Verkuil 		break;
1369dacca5f0SHans Verkuil 	case V4L2_CID_RDS_TX_PTY:
1370dacca5f0SHans Verkuil 		if (dev->radio_rx_rds_controls)
1371dacca5f0SHans Verkuil 			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, ctrl->val);
1372dacca5f0SHans Verkuil 		break;
1373dacca5f0SHans Verkuil 	case V4L2_CID_RDS_TX_PS_NAME:
1374dacca5f0SHans Verkuil 		if (dev->radio_rx_rds_controls)
1375dacca5f0SHans Verkuil 			v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ctrl->p_new.p_char);
1376dacca5f0SHans Verkuil 		break;
1377dacca5f0SHans Verkuil 	case V4L2_CID_RDS_TX_RADIO_TEXT:
1378dacca5f0SHans Verkuil 		if (dev->radio_rx_rds_controls)
1379dacca5f0SHans Verkuil 			v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ctrl->p_new.p_char);
1380dacca5f0SHans Verkuil 		break;
1381dacca5f0SHans Verkuil 	case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
1382dacca5f0SHans Verkuil 		if (dev->radio_rx_rds_controls)
1383dacca5f0SHans Verkuil 			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, ctrl->val);
1384dacca5f0SHans Verkuil 		break;
1385dacca5f0SHans Verkuil 	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
1386dacca5f0SHans Verkuil 		if (dev->radio_rx_rds_controls)
1387dacca5f0SHans Verkuil 			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, ctrl->val);
1388dacca5f0SHans Verkuil 		break;
1389dacca5f0SHans Verkuil 	case V4L2_CID_RDS_TX_MUSIC_SPEECH:
1390dacca5f0SHans Verkuil 		if (dev->radio_rx_rds_controls)
1391dacca5f0SHans Verkuil 			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, ctrl->val);
1392dacca5f0SHans Verkuil 		break;
1393dacca5f0SHans Verkuil 	}
1394dacca5f0SHans Verkuil 	return 0;
1395dacca5f0SHans Verkuil }
1396dacca5f0SHans Verkuil 
1397dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_radio_tx_ctrl_ops = {
1398dacca5f0SHans Verkuil 	.s_ctrl = vivid_radio_tx_s_ctrl,
1399dacca5f0SHans Verkuil };
1400dacca5f0SHans Verkuil 
1401dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_radio_tx_rds_blockio = {
1402dacca5f0SHans Verkuil 	.ops = &vivid_radio_tx_ctrl_ops,
1403dacca5f0SHans Verkuil 	.id = VIVID_CID_RADIO_TX_RDS_BLOCKIO,
1404dacca5f0SHans Verkuil 	.name = "RDS Tx I/O Mode",
1405dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_MENU,
1406dacca5f0SHans Verkuil 	.qmenu = vivid_ctrl_radio_rds_mode_strings,
1407dacca5f0SHans Verkuil 	.max = 1,
1408dacca5f0SHans Verkuil 	.def = 1,
1409dacca5f0SHans Verkuil };
1410dacca5f0SHans Verkuil 
1411dacca5f0SHans Verkuil 
1412dacca5f0SHans Verkuil /* SDR Capture Controls */
1413dacca5f0SHans Verkuil 
1414dacca5f0SHans Verkuil static int vivid_sdr_cap_s_ctrl(struct v4l2_ctrl *ctrl)
1415dacca5f0SHans Verkuil {
1416dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdr_cap);
1417dacca5f0SHans Verkuil 
1418dacca5f0SHans Verkuil 	switch (ctrl->id) {
1419dacca5f0SHans Verkuil 	case VIVID_CID_SDR_CAP_FM_DEVIATION:
1420dacca5f0SHans Verkuil 		dev->sdr_fm_deviation = ctrl->val;
1421dacca5f0SHans Verkuil 		break;
1422dacca5f0SHans Verkuil 	}
1423dacca5f0SHans Verkuil 	return 0;
1424dacca5f0SHans Verkuil }
1425dacca5f0SHans Verkuil 
1426dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_sdr_cap_ctrl_ops = {
1427dacca5f0SHans Verkuil 	.s_ctrl = vivid_sdr_cap_s_ctrl,
1428dacca5f0SHans Verkuil };
1429dacca5f0SHans Verkuil 
1430dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_sdr_cap_fm_deviation = {
1431dacca5f0SHans Verkuil 	.ops = &vivid_sdr_cap_ctrl_ops,
1432dacca5f0SHans Verkuil 	.id = VIVID_CID_SDR_CAP_FM_DEVIATION,
1433dacca5f0SHans Verkuil 	.name = "FM Deviation",
1434dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
1435dacca5f0SHans Verkuil 	.min =    100,
1436dacca5f0SHans Verkuil 	.max = 200000,
1437dacca5f0SHans Verkuil 	.def =  75000,
1438dacca5f0SHans Verkuil 	.step =     1,
1439dacca5f0SHans Verkuil };
1440dacca5f0SHans Verkuil 
1441dacca5f0SHans Verkuil /* Metadata Capture Control */
1442dacca5f0SHans Verkuil 
1443dacca5f0SHans Verkuil static int vivid_meta_cap_s_ctrl(struct v4l2_ctrl *ctrl)
1444dacca5f0SHans Verkuil {
1445dacca5f0SHans Verkuil 	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev,
1446dacca5f0SHans Verkuil 					     ctrl_hdl_meta_cap);
1447dacca5f0SHans Verkuil 
1448dacca5f0SHans Verkuil 	switch (ctrl->id) {
1449dacca5f0SHans Verkuil 	case VIVID_CID_META_CAP_GENERATE_PTS:
1450dacca5f0SHans Verkuil 		dev->meta_pts = ctrl->val;
1451dacca5f0SHans Verkuil 		break;
1452dacca5f0SHans Verkuil 	case VIVID_CID_META_CAP_GENERATE_SCR:
1453dacca5f0SHans Verkuil 		dev->meta_scr = ctrl->val;
1454dacca5f0SHans Verkuil 		break;
1455dacca5f0SHans Verkuil 	}
1456dacca5f0SHans Verkuil 	return 0;
1457dacca5f0SHans Verkuil }
1458dacca5f0SHans Verkuil 
1459dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vivid_meta_cap_ctrl_ops = {
1460dacca5f0SHans Verkuil 	.s_ctrl = vivid_meta_cap_s_ctrl,
1461dacca5f0SHans Verkuil };
1462dacca5f0SHans Verkuil 
1463dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_meta_has_pts = {
1464dacca5f0SHans Verkuil 	.ops = &vivid_meta_cap_ctrl_ops,
1465dacca5f0SHans Verkuil 	.id = VIVID_CID_META_CAP_GENERATE_PTS,
1466dacca5f0SHans Verkuil 	.name = "Generate PTS",
1467dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1468dacca5f0SHans Verkuil 	.max = 1,
1469dacca5f0SHans Verkuil 	.def = 1,
1470dacca5f0SHans Verkuil 	.step = 1,
1471dacca5f0SHans Verkuil };
1472dacca5f0SHans Verkuil 
1473dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_meta_has_src_clk = {
1474dacca5f0SHans Verkuil 	.ops = &vivid_meta_cap_ctrl_ops,
1475dacca5f0SHans Verkuil 	.id = VIVID_CID_META_CAP_GENERATE_SCR,
1476dacca5f0SHans Verkuil 	.name = "Generate SCR",
1477dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1478dacca5f0SHans Verkuil 	.max = 1,
1479dacca5f0SHans Verkuil 	.def = 1,
1480dacca5f0SHans Verkuil 	.step = 1,
1481dacca5f0SHans Verkuil };
1482dacca5f0SHans Verkuil 
1483dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vivid_ctrl_class = {
1484dacca5f0SHans Verkuil 	.ops = &vivid_user_gen_ctrl_ops,
1485dacca5f0SHans Verkuil 	.flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
1486dacca5f0SHans Verkuil 	.id = VIVID_CID_VIVID_CLASS,
1487dacca5f0SHans Verkuil 	.name = "Vivid Controls",
1488dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_CTRL_CLASS,
1489dacca5f0SHans Verkuil };
1490dacca5f0SHans Verkuil 
1491dacca5f0SHans Verkuil int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
1492dacca5f0SHans Verkuil 		bool show_ccs_out, bool no_error_inj,
1493dacca5f0SHans Verkuil 		bool has_sdtv, bool has_hdmi)
1494dacca5f0SHans Verkuil {
1495dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_user_gen = &dev->ctrl_hdl_user_gen;
1496dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_user_vid = &dev->ctrl_hdl_user_vid;
1497dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_user_aud = &dev->ctrl_hdl_user_aud;
1498dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_streaming = &dev->ctrl_hdl_streaming;
1499dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_sdtv_cap = &dev->ctrl_hdl_sdtv_cap;
1500dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_loop_cap = &dev->ctrl_hdl_loop_cap;
1501dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_fb = &dev->ctrl_hdl_fb;
1502dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_vid_cap = &dev->ctrl_hdl_vid_cap;
1503dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_vid_out = &dev->ctrl_hdl_vid_out;
1504dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_vbi_cap = &dev->ctrl_hdl_vbi_cap;
1505dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_vbi_out = &dev->ctrl_hdl_vbi_out;
1506dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx;
1507dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx;
1508dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap;
1509dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_meta_cap = &dev->ctrl_hdl_meta_cap;
1510dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_meta_out = &dev->ctrl_hdl_meta_out;
1511dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler *hdl_tch_cap = &dev->ctrl_hdl_touch_cap;
1512dacca5f0SHans Verkuil 
1513dacca5f0SHans Verkuil 	struct v4l2_ctrl_config vivid_ctrl_dv_timings = {
1514dacca5f0SHans Verkuil 		.ops = &vivid_vid_cap_ctrl_ops,
1515dacca5f0SHans Verkuil 		.id = VIVID_CID_DV_TIMINGS,
1516dacca5f0SHans Verkuil 		.name = "DV Timings",
1517dacca5f0SHans Verkuil 		.type = V4L2_CTRL_TYPE_MENU,
1518dacca5f0SHans Verkuil 	};
1519dacca5f0SHans Verkuil 	int i;
1520dacca5f0SHans Verkuil 
1521dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_user_gen, 10);
1522dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_class, NULL);
1523dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_user_vid, 9);
1524dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_user_vid, &vivid_ctrl_class, NULL);
1525dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_user_aud, 2);
1526dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_user_aud, &vivid_ctrl_class, NULL);
1527dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_streaming, 8);
1528dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_class, NULL);
1529dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_sdtv_cap, 2);
1530dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_sdtv_cap, &vivid_ctrl_class, NULL);
1531dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_loop_cap, 1);
1532dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_class, NULL);
1533dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_fb, 1);
1534dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_fb, &vivid_ctrl_class, NULL);
1535dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_vid_cap, 55);
1536dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL);
1537dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_vid_out, 26);
1538dacca5f0SHans Verkuil 	if (!no_error_inj || dev->has_fb || dev->num_hdmi_outputs)
1539dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
1540dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_vbi_cap, 21);
1541dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL);
1542dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_vbi_out, 19);
1543dacca5f0SHans Verkuil 	if (!no_error_inj)
1544dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL);
1545dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_radio_rx, 17);
1546dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL);
1547dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_radio_tx, 17);
1548dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL);
1549dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_sdr_cap, 19);
1550dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL);
1551dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_meta_cap, 2);
1552dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_meta_cap, &vivid_ctrl_class, NULL);
1553dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_meta_out, 2);
1554dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_meta_out, &vivid_ctrl_class, NULL);
1555dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(hdl_tch_cap, 2);
1556dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_tch_cap, &vivid_ctrl_class, NULL);
1557dacca5f0SHans Verkuil 
1558dacca5f0SHans Verkuil 	/* User Controls */
1559dacca5f0SHans Verkuil 	dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL,
1560dacca5f0SHans Verkuil 		V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
1561dacca5f0SHans Verkuil 	dev->mute = v4l2_ctrl_new_std(hdl_user_aud, NULL,
1562dacca5f0SHans Verkuil 		V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
1563dacca5f0SHans Verkuil 	if (dev->has_vid_cap) {
1564dacca5f0SHans Verkuil 		dev->brightness = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1565dacca5f0SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1566dacca5f0SHans Verkuil 		for (i = 0; i < MAX_INPUTS; i++)
1567dacca5f0SHans Verkuil 			dev->input_brightness[i] = 128;
1568dacca5f0SHans Verkuil 		dev->contrast = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1569dacca5f0SHans Verkuil 			V4L2_CID_CONTRAST, 0, 255, 1, 128);
1570dacca5f0SHans Verkuil 		dev->saturation = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1571dacca5f0SHans Verkuil 			V4L2_CID_SATURATION, 0, 255, 1, 128);
1572dacca5f0SHans Verkuil 		dev->hue = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1573dacca5f0SHans Verkuil 			V4L2_CID_HUE, -128, 128, 1, 0);
1574dacca5f0SHans Verkuil 		v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1575dacca5f0SHans Verkuil 			V4L2_CID_HFLIP, 0, 1, 1, 0);
1576dacca5f0SHans Verkuil 		v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1577dacca5f0SHans Verkuil 			V4L2_CID_VFLIP, 0, 1, 1, 0);
1578dacca5f0SHans Verkuil 		dev->autogain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1579dacca5f0SHans Verkuil 			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
1580dacca5f0SHans Verkuil 		dev->gain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1581dacca5f0SHans Verkuil 			V4L2_CID_GAIN, 0, 255, 1, 100);
1582dacca5f0SHans Verkuil 		dev->alpha = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
1583dacca5f0SHans Verkuil 			V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
1584dacca5f0SHans Verkuil 	}
1585dacca5f0SHans Verkuil 	dev->button = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_button, NULL);
1586dacca5f0SHans Verkuil 	dev->int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int32, NULL);
1587dacca5f0SHans Verkuil 	dev->int64 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int64, NULL);
1588dacca5f0SHans Verkuil 	dev->boolean = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_boolean, NULL);
1589dacca5f0SHans Verkuil 	dev->menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_menu, NULL);
1590dacca5f0SHans Verkuil 	dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL);
1591dacca5f0SHans Verkuil 	dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL);
1592dacca5f0SHans Verkuil 	dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL);
1593dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL);
1594dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL);
1595dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL);
1596dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL);
1597dacca5f0SHans Verkuil 
1598dacca5f0SHans Verkuil 	if (dev->has_vid_cap) {
1599dacca5f0SHans Verkuil 		/* Image Processing Controls */
1600dacca5f0SHans Verkuil 		struct v4l2_ctrl_config vivid_ctrl_test_pattern = {
1601dacca5f0SHans Verkuil 			.ops = &vivid_vid_cap_ctrl_ops,
1602dacca5f0SHans Verkuil 			.id = VIVID_CID_TEST_PATTERN,
1603dacca5f0SHans Verkuil 			.name = "Test Pattern",
1604dacca5f0SHans Verkuil 			.type = V4L2_CTRL_TYPE_MENU,
1605dacca5f0SHans Verkuil 			.max = TPG_PAT_NOISE,
1606dacca5f0SHans Verkuil 			.qmenu = tpg_pattern_strings,
1607dacca5f0SHans Verkuil 		};
1608dacca5f0SHans Verkuil 
1609dacca5f0SHans Verkuil 		dev->test_pattern = v4l2_ctrl_new_custom(hdl_vid_cap,
1610dacca5f0SHans Verkuil 				&vivid_ctrl_test_pattern, NULL);
1611dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_perc_fill, NULL);
1612dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hor_movement, NULL);
1613dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vert_movement, NULL);
1614dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_osd_mode, NULL);
1615dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_border, NULL);
1616dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_square, NULL);
1617dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hflip, NULL);
1618dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL);
1619dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL);
1620dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL);
1621dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_reduced_fps, NULL);
1622dacca5f0SHans Verkuil 		if (show_ccs_cap) {
1623dacca5f0SHans Verkuil 			dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
1624dacca5f0SHans Verkuil 				&vivid_ctrl_has_crop_cap, NULL);
1625dacca5f0SHans Verkuil 			dev->ctrl_has_compose_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
1626dacca5f0SHans Verkuil 				&vivid_ctrl_has_compose_cap, NULL);
1627dacca5f0SHans Verkuil 			dev->ctrl_has_scaler_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
1628dacca5f0SHans Verkuil 				&vivid_ctrl_has_scaler_cap, NULL);
1629dacca5f0SHans Verkuil 		}
1630dacca5f0SHans Verkuil 
1631dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL);
1632dacca5f0SHans Verkuil 		dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap,
1633dacca5f0SHans Verkuil 			&vivid_ctrl_colorspace, NULL);
1634dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_xfer_func, NULL);
1635dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_ycbcr_enc, NULL);
1636dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hsv_enc, NULL);
1637dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL);
1638dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL);
1639dacca5f0SHans Verkuil 	}
1640dacca5f0SHans Verkuil 
1641dacca5f0SHans Verkuil 	if (dev->has_vid_out && show_ccs_out) {
1642dacca5f0SHans Verkuil 		dev->ctrl_has_crop_out = v4l2_ctrl_new_custom(hdl_vid_out,
1643dacca5f0SHans Verkuil 			&vivid_ctrl_has_crop_out, NULL);
1644dacca5f0SHans Verkuil 		dev->ctrl_has_compose_out = v4l2_ctrl_new_custom(hdl_vid_out,
1645dacca5f0SHans Verkuil 			&vivid_ctrl_has_compose_out, NULL);
1646dacca5f0SHans Verkuil 		dev->ctrl_has_scaler_out = v4l2_ctrl_new_custom(hdl_vid_out,
1647dacca5f0SHans Verkuil 			&vivid_ctrl_has_scaler_out, NULL);
1648dacca5f0SHans Verkuil 	}
1649dacca5f0SHans Verkuil 
1650dacca5f0SHans Verkuil 	/*
1651dacca5f0SHans Verkuil 	 * Testing this driver with v4l2-compliance will trigger the error
1652dacca5f0SHans Verkuil 	 * injection controls, and after that nothing will work as expected.
1653dacca5f0SHans Verkuil 	 * So we have a module option to drop these error injecting controls
1654dacca5f0SHans Verkuil 	 * allowing us to run v4l2_compliance again.
1655dacca5f0SHans Verkuil 	 */
1656dacca5f0SHans Verkuil 	if (!no_error_inj) {
1657dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_disconnect, NULL);
1658dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_dqbuf_error, NULL);
1659dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_perc_dropped, NULL);
1660dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_setup_error, NULL);
1661dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_buf_prepare_error, NULL);
1662dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_start_streaming_error, NULL);
1663dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_error, NULL);
1664dacca5f0SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER
1665dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_req_validate_error, NULL);
1666dacca5f0SHans Verkuil #endif
1667dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_seq_wrap, NULL);
1668dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_time_wrap, NULL);
1669dacca5f0SHans Verkuil 	}
1670dacca5f0SHans Verkuil 
1671dacca5f0SHans Verkuil 	if (has_sdtv && (dev->has_vid_cap || dev->has_vbi_cap)) {
1672dacca5f0SHans Verkuil 		if (dev->has_vid_cap)
1673dacca5f0SHans Verkuil 			v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_std_aspect_ratio, NULL);
1674dacca5f0SHans Verkuil 		dev->ctrl_std_signal_mode = v4l2_ctrl_new_custom(hdl_sdtv_cap,
1675dacca5f0SHans Verkuil 			&vivid_ctrl_std_signal_mode, NULL);
1676dacca5f0SHans Verkuil 		dev->ctrl_standard = v4l2_ctrl_new_custom(hdl_sdtv_cap,
1677dacca5f0SHans Verkuil 			&vivid_ctrl_standard, NULL);
1678dacca5f0SHans Verkuil 		if (dev->ctrl_std_signal_mode)
1679dacca5f0SHans Verkuil 			v4l2_ctrl_cluster(2, &dev->ctrl_std_signal_mode);
1680dacca5f0SHans Verkuil 		if (dev->has_raw_vbi_cap)
1681dacca5f0SHans Verkuil 			v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL);
1682dacca5f0SHans Verkuil 	}
1683dacca5f0SHans Verkuil 
1684dacca5f0SHans Verkuil 	if (dev->num_hdmi_inputs) {
1685dacca5f0SHans Verkuil 		s64 hdmi_input_mask = GENMASK(dev->num_hdmi_inputs - 1, 0);
1686dacca5f0SHans Verkuil 
1687dacca5f0SHans Verkuil 		dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap,
1688dacca5f0SHans Verkuil 					&vivid_ctrl_dv_timings_signal_mode, NULL);
1689dacca5f0SHans Verkuil 
1690dacca5f0SHans Verkuil 		vivid_ctrl_dv_timings.max = dev->query_dv_timings_size - 1;
1691dacca5f0SHans Verkuil 		vivid_ctrl_dv_timings.qmenu =
1692dacca5f0SHans Verkuil 			(const char * const *)dev->query_dv_timings_qmenu;
1693dacca5f0SHans Verkuil 		dev->ctrl_dv_timings = v4l2_ctrl_new_custom(hdl_vid_cap,
1694dacca5f0SHans Verkuil 			&vivid_ctrl_dv_timings, NULL);
1695dacca5f0SHans Verkuil 		if (dev->ctrl_dv_timings_signal_mode)
1696dacca5f0SHans Verkuil 			v4l2_ctrl_cluster(2, &dev->ctrl_dv_timings_signal_mode);
1697dacca5f0SHans Verkuil 
1698dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_aspect_ratio, NULL);
1699dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_max_edid_blocks, NULL);
1700dacca5f0SHans Verkuil 		dev->real_rgb_range_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
1701dacca5f0SHans Verkuil 			&vivid_ctrl_limited_rgb_range, NULL);
1702dacca5f0SHans Verkuil 		dev->rgb_range_cap = v4l2_ctrl_new_std_menu(hdl_vid_cap,
1703dacca5f0SHans Verkuil 			&vivid_vid_cap_ctrl_ops,
1704dacca5f0SHans Verkuil 			V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
1705dacca5f0SHans Verkuil 			0, V4L2_DV_RGB_RANGE_AUTO);
1706dacca5f0SHans Verkuil 		dev->ctrl_rx_power_present = v4l2_ctrl_new_std(hdl_vid_cap,
1707dacca5f0SHans Verkuil 			NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, hdmi_input_mask,
1708dacca5f0SHans Verkuil 			0, hdmi_input_mask);
1709dacca5f0SHans Verkuil 
1710dacca5f0SHans Verkuil 	}
1711dacca5f0SHans Verkuil 	if (dev->num_hdmi_outputs) {
1712dacca5f0SHans Verkuil 		s64 hdmi_output_mask = GENMASK(dev->num_hdmi_outputs - 1, 0);
1713dacca5f0SHans Verkuil 
1714dacca5f0SHans Verkuil 		/*
1715dacca5f0SHans Verkuil 		 * We aren't doing anything with this at the moment, but
1716dacca5f0SHans Verkuil 		 * HDMI outputs typically have this controls.
1717dacca5f0SHans Verkuil 		 */
1718dacca5f0SHans Verkuil 		dev->ctrl_tx_rgb_range = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
1719dacca5f0SHans Verkuil 			V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
1720dacca5f0SHans Verkuil 			0, V4L2_DV_RGB_RANGE_AUTO);
1721dacca5f0SHans Verkuil 		dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
1722dacca5f0SHans Verkuil 			V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
1723dacca5f0SHans Verkuil 			0, V4L2_DV_TX_MODE_HDMI);
1724dacca5f0SHans Verkuil 		dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out,
1725dacca5f0SHans Verkuil 			&vivid_ctrl_display_present, NULL);
1726dacca5f0SHans Verkuil 		dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out,
1727dacca5f0SHans Verkuil 			NULL, V4L2_CID_DV_TX_HOTPLUG, 0, hdmi_output_mask,
1728dacca5f0SHans Verkuil 			0, hdmi_output_mask);
1729dacca5f0SHans Verkuil 		dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out,
1730dacca5f0SHans Verkuil 			NULL, V4L2_CID_DV_TX_RXSENSE, 0, hdmi_output_mask,
1731dacca5f0SHans Verkuil 			0, hdmi_output_mask);
1732dacca5f0SHans Verkuil 		dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out,
1733dacca5f0SHans Verkuil 			NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, hdmi_output_mask,
1734dacca5f0SHans Verkuil 			0, hdmi_output_mask);
1735dacca5f0SHans Verkuil 	}
1736dacca5f0SHans Verkuil 	if ((dev->has_vid_cap && dev->has_vid_out) ||
1737dacca5f0SHans Verkuil 	    (dev->has_vbi_cap && dev->has_vbi_out))
1738dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_loop_video, NULL);
1739dacca5f0SHans Verkuil 
1740dacca5f0SHans Verkuil 	if (dev->has_fb)
1741dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_fb, &vivid_ctrl_clear_fb, NULL);
1742dacca5f0SHans Verkuil 
1743dacca5f0SHans Verkuil 	if (dev->has_radio_rx) {
1744dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_mode, NULL);
1745dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_prog_lim, NULL);
1746dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_blockio, NULL);
1747dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_rbds, NULL);
1748dacca5f0SHans Verkuil 		v4l2_ctrl_new_std(hdl_radio_rx, &vivid_radio_rx_ctrl_ops,
1749dacca5f0SHans Verkuil 			V4L2_CID_RDS_RECEPTION, 0, 1, 1, 1);
1750dacca5f0SHans Verkuil 		dev->radio_rx_rds_pty = v4l2_ctrl_new_std(hdl_radio_rx,
1751dacca5f0SHans Verkuil 			&vivid_radio_rx_ctrl_ops,
1752dacca5f0SHans Verkuil 			V4L2_CID_RDS_RX_PTY, 0, 31, 1, 0);
1753dacca5f0SHans Verkuil 		dev->radio_rx_rds_psname = v4l2_ctrl_new_std(hdl_radio_rx,
1754dacca5f0SHans Verkuil 			&vivid_radio_rx_ctrl_ops,
1755dacca5f0SHans Verkuil 			V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0);
1756dacca5f0SHans Verkuil 		dev->radio_rx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_rx,
1757dacca5f0SHans Verkuil 			&vivid_radio_rx_ctrl_ops,
1758dacca5f0SHans Verkuil 			V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0);
1759dacca5f0SHans Verkuil 		dev->radio_rx_rds_ta = v4l2_ctrl_new_std(hdl_radio_rx,
1760dacca5f0SHans Verkuil 			&vivid_radio_rx_ctrl_ops,
1761dacca5f0SHans Verkuil 			V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
1762dacca5f0SHans Verkuil 		dev->radio_rx_rds_tp = v4l2_ctrl_new_std(hdl_radio_rx,
1763dacca5f0SHans Verkuil 			&vivid_radio_rx_ctrl_ops,
1764dacca5f0SHans Verkuil 			V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
1765dacca5f0SHans Verkuil 		dev->radio_rx_rds_ms = v4l2_ctrl_new_std(hdl_radio_rx,
1766dacca5f0SHans Verkuil 			&vivid_radio_rx_ctrl_ops,
1767dacca5f0SHans Verkuil 			V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1);
1768dacca5f0SHans Verkuil 	}
1769dacca5f0SHans Verkuil 	if (dev->has_radio_tx) {
1770dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_radio_tx,
1771dacca5f0SHans Verkuil 			&vivid_ctrl_radio_tx_rds_blockio, NULL);
1772dacca5f0SHans Verkuil 		dev->radio_tx_rds_pi = v4l2_ctrl_new_std(hdl_radio_tx,
1773dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1774dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, 0x8088);
1775dacca5f0SHans Verkuil 		dev->radio_tx_rds_pty = v4l2_ctrl_new_std(hdl_radio_tx,
1776dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1777dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_PTY, 0, 31, 1, 3);
1778dacca5f0SHans Verkuil 		dev->radio_tx_rds_psname = v4l2_ctrl_new_std(hdl_radio_tx,
1779dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1780dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_PS_NAME, 0, 8, 8, 0);
1781dacca5f0SHans Verkuil 		if (dev->radio_tx_rds_psname)
1782dacca5f0SHans Verkuil 			v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_psname, "VIVID-TX");
1783dacca5f0SHans Verkuil 		dev->radio_tx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_tx,
1784dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1785dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_RADIO_TEXT, 0, 64 * 2, 64, 0);
1786dacca5f0SHans Verkuil 		if (dev->radio_tx_rds_radiotext)
1787dacca5f0SHans Verkuil 			v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_radiotext,
1788dacca5f0SHans Verkuil 			       "This is a VIVID default Radio Text template text, change at will");
1789dacca5f0SHans Verkuil 		dev->radio_tx_rds_mono_stereo = v4l2_ctrl_new_std(hdl_radio_tx,
1790dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1791dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1);
1792dacca5f0SHans Verkuil 		dev->radio_tx_rds_art_head = v4l2_ctrl_new_std(hdl_radio_tx,
1793dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1794dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0);
1795dacca5f0SHans Verkuil 		dev->radio_tx_rds_compressed = v4l2_ctrl_new_std(hdl_radio_tx,
1796dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1797dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0);
1798dacca5f0SHans Verkuil 		dev->radio_tx_rds_dyn_pty = v4l2_ctrl_new_std(hdl_radio_tx,
1799dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1800dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0);
1801dacca5f0SHans Verkuil 		dev->radio_tx_rds_ta = v4l2_ctrl_new_std(hdl_radio_tx,
1802dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1803dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
1804dacca5f0SHans Verkuil 		dev->radio_tx_rds_tp = v4l2_ctrl_new_std(hdl_radio_tx,
1805dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1806dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 1);
1807dacca5f0SHans Verkuil 		dev->radio_tx_rds_ms = v4l2_ctrl_new_std(hdl_radio_tx,
1808dacca5f0SHans Verkuil 			&vivid_radio_tx_ctrl_ops,
1809dacca5f0SHans Verkuil 			V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1);
1810dacca5f0SHans Verkuil 	}
1811dacca5f0SHans Verkuil 	if (dev->has_sdr_cap) {
1812dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_sdr_cap,
1813dacca5f0SHans Verkuil 			&vivid_ctrl_sdr_cap_fm_deviation, NULL);
1814dacca5f0SHans Verkuil 	}
1815dacca5f0SHans Verkuil 	if (dev->has_meta_cap) {
1816dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_meta_cap,
1817dacca5f0SHans Verkuil 				     &vivid_ctrl_meta_has_pts, NULL);
1818dacca5f0SHans Verkuil 		v4l2_ctrl_new_custom(hdl_meta_cap,
1819dacca5f0SHans Verkuil 				     &vivid_ctrl_meta_has_src_clk, NULL);
1820dacca5f0SHans Verkuil 	}
1821dacca5f0SHans Verkuil 
1822dacca5f0SHans Verkuil 	if (hdl_user_gen->error)
1823dacca5f0SHans Verkuil 		return hdl_user_gen->error;
1824dacca5f0SHans Verkuil 	if (hdl_user_vid->error)
1825dacca5f0SHans Verkuil 		return hdl_user_vid->error;
1826dacca5f0SHans Verkuil 	if (hdl_user_aud->error)
1827dacca5f0SHans Verkuil 		return hdl_user_aud->error;
1828dacca5f0SHans Verkuil 	if (hdl_streaming->error)
1829dacca5f0SHans Verkuil 		return hdl_streaming->error;
1830dacca5f0SHans Verkuil 	if (hdl_sdr_cap->error)
1831dacca5f0SHans Verkuil 		return hdl_sdr_cap->error;
1832dacca5f0SHans Verkuil 	if (hdl_loop_cap->error)
1833dacca5f0SHans Verkuil 		return hdl_loop_cap->error;
1834dacca5f0SHans Verkuil 
1835dacca5f0SHans Verkuil 	if (dev->autogain)
1836dacca5f0SHans Verkuil 		v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
1837dacca5f0SHans Verkuil 
1838dacca5f0SHans Verkuil 	if (dev->has_vid_cap) {
1839dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL, false);
1840dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL, false);
1841dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL, false);
1842dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL, false);
1843dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL, false);
1844dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_loop_cap, NULL, false);
1845dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_fb, NULL, false);
1846dacca5f0SHans Verkuil 		if (hdl_vid_cap->error)
1847dacca5f0SHans Verkuil 			return hdl_vid_cap->error;
1848dacca5f0SHans Verkuil 		dev->vid_cap_dev.ctrl_handler = hdl_vid_cap;
1849dacca5f0SHans Verkuil 	}
1850dacca5f0SHans Verkuil 	if (dev->has_vid_out) {
1851dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL, false);
1852dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL, false);
1853dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL, false);
1854dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vid_out, hdl_fb, NULL, false);
1855dacca5f0SHans Verkuil 		if (hdl_vid_out->error)
1856dacca5f0SHans Verkuil 			return hdl_vid_out->error;
1857dacca5f0SHans Verkuil 		dev->vid_out_dev.ctrl_handler = hdl_vid_out;
1858dacca5f0SHans Verkuil 	}
1859dacca5f0SHans Verkuil 	if (dev->has_vbi_cap) {
1860dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL, false);
1861dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL, false);
1862dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL, false);
1863dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_loop_cap, NULL, false);
1864dacca5f0SHans Verkuil 		if (hdl_vbi_cap->error)
1865dacca5f0SHans Verkuil 			return hdl_vbi_cap->error;
1866dacca5f0SHans Verkuil 		dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap;
1867dacca5f0SHans Verkuil 	}
1868dacca5f0SHans Verkuil 	if (dev->has_vbi_out) {
1869dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL, false);
1870dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL, false);
1871dacca5f0SHans Verkuil 		if (hdl_vbi_out->error)
1872dacca5f0SHans Verkuil 			return hdl_vbi_out->error;
1873dacca5f0SHans Verkuil 		dev->vbi_out_dev.ctrl_handler = hdl_vbi_out;
1874dacca5f0SHans Verkuil 	}
1875dacca5f0SHans Verkuil 	if (dev->has_radio_rx) {
1876dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL, false);
1877dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL, false);
1878dacca5f0SHans Verkuil 		if (hdl_radio_rx->error)
1879dacca5f0SHans Verkuil 			return hdl_radio_rx->error;
1880dacca5f0SHans Verkuil 		dev->radio_rx_dev.ctrl_handler = hdl_radio_rx;
1881dacca5f0SHans Verkuil 	}
1882dacca5f0SHans Verkuil 	if (dev->has_radio_tx) {
1883dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL, false);
1884dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL, false);
1885dacca5f0SHans Verkuil 		if (hdl_radio_tx->error)
1886dacca5f0SHans Verkuil 			return hdl_radio_tx->error;
1887dacca5f0SHans Verkuil 		dev->radio_tx_dev.ctrl_handler = hdl_radio_tx;
1888dacca5f0SHans Verkuil 	}
1889dacca5f0SHans Verkuil 	if (dev->has_sdr_cap) {
1890dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL, false);
1891dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL, false);
1892dacca5f0SHans Verkuil 		if (hdl_sdr_cap->error)
1893dacca5f0SHans Verkuil 			return hdl_sdr_cap->error;
1894dacca5f0SHans Verkuil 		dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap;
1895dacca5f0SHans Verkuil 	}
1896dacca5f0SHans Verkuil 	if (dev->has_meta_cap) {
1897dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_meta_cap, hdl_user_gen, NULL, false);
1898dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_meta_cap, hdl_streaming, NULL, false);
1899dacca5f0SHans Verkuil 		if (hdl_meta_cap->error)
1900dacca5f0SHans Verkuil 			return hdl_meta_cap->error;
1901dacca5f0SHans Verkuil 		dev->meta_cap_dev.ctrl_handler = hdl_meta_cap;
1902dacca5f0SHans Verkuil 	}
1903dacca5f0SHans Verkuil 	if (dev->has_meta_out) {
1904dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_meta_out, hdl_user_gen, NULL, false);
1905dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_meta_out, hdl_streaming, NULL, false);
1906dacca5f0SHans Verkuil 		if (hdl_meta_out->error)
1907dacca5f0SHans Verkuil 			return hdl_meta_out->error;
1908dacca5f0SHans Verkuil 		dev->meta_out_dev.ctrl_handler = hdl_meta_out;
1909dacca5f0SHans Verkuil 	}
1910dacca5f0SHans Verkuil 	if (dev->has_touch_cap) {
1911dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_tch_cap, hdl_user_gen, NULL, false);
1912dacca5f0SHans Verkuil 		v4l2_ctrl_add_handler(hdl_tch_cap, hdl_streaming, NULL, false);
1913dacca5f0SHans Verkuil 		if (hdl_tch_cap->error)
1914dacca5f0SHans Verkuil 			return hdl_tch_cap->error;
1915dacca5f0SHans Verkuil 		dev->touch_cap_dev.ctrl_handler = hdl_tch_cap;
1916dacca5f0SHans Verkuil 	}
1917dacca5f0SHans Verkuil 	return 0;
1918dacca5f0SHans Verkuil }
1919dacca5f0SHans Verkuil 
1920dacca5f0SHans Verkuil void vivid_free_controls(struct vivid_dev *dev)
1921dacca5f0SHans Verkuil {
1922dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_cap);
1923dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_out);
1924dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_cap);
1925dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_out);
1926dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_rx);
1927dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_tx);
1928dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdr_cap);
1929dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_gen);
1930dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_vid);
1931dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_aud);
1932dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_streaming);
1933dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap);
1934dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap);
1935dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb);
1936dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_cap);
1937dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_out);
1938dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_hdl_touch_cap);
1939dacca5f0SHans Verkuil }
1940