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