1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * vivid-vid-cap.c - video capture 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/sched.h> |
11 | #include <linux/vmalloc.h> |
12 | #include <linux/videodev2.h> |
13 | #include <linux/v4l2-dv-timings.h> |
14 | #include <media/v4l2-common.h> |
15 | #include <media/v4l2-event.h> |
16 | #include <media/v4l2-dv-timings.h> |
17 | #include <media/v4l2-rect.h> |
18 | |
19 | #include "vivid-core.h" |
20 | #include "vivid-vid-common.h" |
21 | #include "vivid-kthread-cap.h" |
22 | #include "vivid-vid-cap.h" |
23 | |
24 | /* Sizes must be in increasing order */ |
25 | static const struct v4l2_frmsize_discrete webcam_sizes[] = { |
26 | { 320, 180 }, |
27 | { 640, 360 }, |
28 | { 640, 480 }, |
29 | { 1280, 720 }, |
30 | { 1920, 1080 }, |
31 | { 3840, 2160 }, |
32 | }; |
33 | |
34 | /* |
35 | * Intervals must be in increasing order and there must be twice as many |
36 | * elements in this array as there are in webcam_sizes. |
37 | */ |
38 | static const struct v4l2_fract webcam_intervals[] = { |
39 | { 1, 1 }, |
40 | { 1, 2 }, |
41 | { 1, 4 }, |
42 | { 1, 5 }, |
43 | { 1, 10 }, |
44 | { 2, 25 }, |
45 | { 1, 15 }, /* 7 - maximum for 2160p */ |
46 | { 1, 25 }, |
47 | { 1, 30 }, /* 9 - maximum for 1080p */ |
48 | { 1, 40 }, |
49 | { 1, 50 }, |
50 | { 1, 60 }, /* 12 - maximum for 720p */ |
51 | { 1, 120 }, |
52 | }; |
53 | |
54 | /* Limit maximum FPS rates for high resolutions */ |
55 | #define IVAL_COUNT_720P 12 /* 720p and up is limited to 60 fps */ |
56 | #define IVAL_COUNT_1080P 9 /* 1080p and up is limited to 30 fps */ |
57 | #define IVAL_COUNT_2160P 7 /* 2160p and up is limited to 15 fps */ |
58 | |
59 | static inline unsigned int webcam_ival_count(const struct vivid_dev *dev, |
60 | unsigned int frmsize_idx) |
61 | { |
62 | if (webcam_sizes[frmsize_idx].height >= 2160) |
63 | return IVAL_COUNT_2160P; |
64 | |
65 | if (webcam_sizes[frmsize_idx].height >= 1080) |
66 | return IVAL_COUNT_1080P; |
67 | |
68 | if (webcam_sizes[frmsize_idx].height >= 720) |
69 | return IVAL_COUNT_720P; |
70 | |
71 | /* For low resolutions, allow all FPS rates */ |
72 | return ARRAY_SIZE(webcam_intervals); |
73 | } |
74 | |
75 | static int vid_cap_queue_setup(struct vb2_queue *vq, |
76 | unsigned *nbuffers, unsigned *nplanes, |
77 | unsigned sizes[], struct device *alloc_devs[]) |
78 | { |
79 | struct vivid_dev *dev = vb2_get_drv_priv(q: vq); |
80 | unsigned buffers = tpg_g_buffers(tpg: &dev->tpg); |
81 | unsigned h = dev->fmt_cap_rect.height; |
82 | unsigned p; |
83 | |
84 | if (dev->field_cap == V4L2_FIELD_ALTERNATE) { |
85 | /* |
86 | * You cannot use read() with FIELD_ALTERNATE since the field |
87 | * information (TOP/BOTTOM) cannot be passed back to the user. |
88 | */ |
89 | if (vb2_fileio_is_active(q: vq)) |
90 | return -EINVAL; |
91 | } |
92 | |
93 | if (dev->queue_setup_error) { |
94 | /* |
95 | * Error injection: test what happens if queue_setup() returns |
96 | * an error. |
97 | */ |
98 | dev->queue_setup_error = false; |
99 | return -EINVAL; |
100 | } |
101 | if (*nplanes) { |
102 | /* |
103 | * Check if the number of requested planes match |
104 | * the number of buffers in the current format. You can't mix that. |
105 | */ |
106 | if (*nplanes != buffers) |
107 | return -EINVAL; |
108 | for (p = 0; p < buffers; p++) { |
109 | if (sizes[p] < tpg_g_line_width(tpg: &dev->tpg, plane: p) * h + |
110 | dev->fmt_cap->data_offset[p]) |
111 | return -EINVAL; |
112 | } |
113 | } else { |
114 | for (p = 0; p < buffers; p++) |
115 | sizes[p] = (tpg_g_line_width(tpg: &dev->tpg, plane: p) * h) / |
116 | dev->fmt_cap->vdownsampling[p] + |
117 | dev->fmt_cap->data_offset[p]; |
118 | } |
119 | |
120 | *nplanes = buffers; |
121 | |
122 | dprintk(dev, 1, "%s: count=%d\n" , __func__, *nbuffers); |
123 | for (p = 0; p < buffers; p++) |
124 | dprintk(dev, 1, "%s: size[%u]=%u\n" , __func__, p, sizes[p]); |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | static int vid_cap_buf_prepare(struct vb2_buffer *vb) |
130 | { |
131 | struct vivid_dev *dev = vb2_get_drv_priv(q: vb->vb2_queue); |
132 | unsigned long size; |
133 | unsigned buffers = tpg_g_buffers(tpg: &dev->tpg); |
134 | unsigned p; |
135 | |
136 | dprintk(dev, 1, "%s\n" , __func__); |
137 | |
138 | if (WARN_ON(NULL == dev->fmt_cap)) |
139 | return -EINVAL; |
140 | |
141 | if (dev->buf_prepare_error) { |
142 | /* |
143 | * Error injection: test what happens if buf_prepare() returns |
144 | * an error. |
145 | */ |
146 | dev->buf_prepare_error = false; |
147 | return -EINVAL; |
148 | } |
149 | for (p = 0; p < buffers; p++) { |
150 | size = (tpg_g_line_width(tpg: &dev->tpg, plane: p) * |
151 | dev->fmt_cap_rect.height) / |
152 | dev->fmt_cap->vdownsampling[p] + |
153 | dev->fmt_cap->data_offset[p]; |
154 | |
155 | if (vb2_plane_size(vb, plane_no: p) < size) { |
156 | dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n" , |
157 | __func__, p, vb2_plane_size(vb, p), size); |
158 | return -EINVAL; |
159 | } |
160 | |
161 | vb2_set_plane_payload(vb, plane_no: p, size); |
162 | vb->planes[p].data_offset = dev->fmt_cap->data_offset[p]; |
163 | } |
164 | |
165 | return 0; |
166 | } |
167 | |
168 | static void vid_cap_buf_finish(struct vb2_buffer *vb) |
169 | { |
170 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
171 | struct vivid_dev *dev = vb2_get_drv_priv(q: vb->vb2_queue); |
172 | struct v4l2_timecode *tc = &vbuf->timecode; |
173 | unsigned fps = 25; |
174 | unsigned seq = vbuf->sequence; |
175 | |
176 | if (!vivid_is_sdtv_cap(dev)) |
177 | return; |
178 | |
179 | /* |
180 | * Set the timecode. Rarely used, so it is interesting to |
181 | * test this. |
182 | */ |
183 | vbuf->flags |= V4L2_BUF_FLAG_TIMECODE; |
184 | if (dev->std_cap[dev->input] & V4L2_STD_525_60) |
185 | fps = 30; |
186 | tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS; |
187 | tc->flags = 0; |
188 | tc->frames = seq % fps; |
189 | tc->seconds = (seq / fps) % 60; |
190 | tc->minutes = (seq / (60 * fps)) % 60; |
191 | tc->hours = (seq / (60 * 60 * fps)) % 24; |
192 | } |
193 | |
194 | static void vid_cap_buf_queue(struct vb2_buffer *vb) |
195 | { |
196 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
197 | struct vivid_dev *dev = vb2_get_drv_priv(q: vb->vb2_queue); |
198 | struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); |
199 | |
200 | dprintk(dev, 1, "%s\n" , __func__); |
201 | |
202 | spin_lock(lock: &dev->slock); |
203 | list_add_tail(new: &buf->list, head: &dev->vid_cap_active); |
204 | spin_unlock(lock: &dev->slock); |
205 | } |
206 | |
207 | static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count) |
208 | { |
209 | struct vivid_dev *dev = vb2_get_drv_priv(q: vq); |
210 | unsigned i; |
211 | int err; |
212 | |
213 | if (vb2_is_streaming(q: &dev->vb_vid_out_q)) |
214 | dev->can_loop_video = vivid_vid_can_loop(dev); |
215 | |
216 | dev->vid_cap_seq_count = 0; |
217 | dprintk(dev, 1, "%s\n" , __func__); |
218 | for (i = 0; i < VIDEO_MAX_FRAME; i++) |
219 | dev->must_blank[i] = tpg_g_perc_fill(tpg: &dev->tpg) < 100; |
220 | if (dev->start_streaming_error) { |
221 | dev->start_streaming_error = false; |
222 | err = -EINVAL; |
223 | } else { |
224 | err = vivid_start_generating_vid_cap(dev, pstreaming: &dev->vid_cap_streaming); |
225 | } |
226 | if (err) { |
227 | struct vivid_buffer *buf, *tmp; |
228 | |
229 | list_for_each_entry_safe(buf, tmp, &dev->vid_cap_active, list) { |
230 | list_del(entry: &buf->list); |
231 | vb2_buffer_done(vb: &buf->vb.vb2_buf, |
232 | state: VB2_BUF_STATE_QUEUED); |
233 | } |
234 | } |
235 | return err; |
236 | } |
237 | |
238 | /* abort streaming and wait for last buffer */ |
239 | static void vid_cap_stop_streaming(struct vb2_queue *vq) |
240 | { |
241 | struct vivid_dev *dev = vb2_get_drv_priv(q: vq); |
242 | |
243 | dprintk(dev, 1, "%s\n" , __func__); |
244 | vivid_stop_generating_vid_cap(dev, pstreaming: &dev->vid_cap_streaming); |
245 | dev->can_loop_video = false; |
246 | } |
247 | |
248 | static void vid_cap_buf_request_complete(struct vb2_buffer *vb) |
249 | { |
250 | struct vivid_dev *dev = vb2_get_drv_priv(q: vb->vb2_queue); |
251 | |
252 | v4l2_ctrl_request_complete(req: vb->req_obj.req, parent: &dev->ctrl_hdl_vid_cap); |
253 | } |
254 | |
255 | const struct vb2_ops vivid_vid_cap_qops = { |
256 | .queue_setup = vid_cap_queue_setup, |
257 | .buf_prepare = vid_cap_buf_prepare, |
258 | .buf_finish = vid_cap_buf_finish, |
259 | .buf_queue = vid_cap_buf_queue, |
260 | .start_streaming = vid_cap_start_streaming, |
261 | .stop_streaming = vid_cap_stop_streaming, |
262 | .buf_request_complete = vid_cap_buf_request_complete, |
263 | .wait_prepare = vb2_ops_wait_prepare, |
264 | .wait_finish = vb2_ops_wait_finish, |
265 | }; |
266 | |
267 | /* |
268 | * Determine the 'picture' quality based on the current TV frequency: either |
269 | * COLOR for a good 'signal', GRAY (grayscale picture) for a slightly off |
270 | * signal or NOISE for no signal. |
271 | */ |
272 | void vivid_update_quality(struct vivid_dev *dev) |
273 | { |
274 | unsigned freq_modulus; |
275 | |
276 | if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) { |
277 | /* |
278 | * The 'noise' will only be replaced by the actual video |
279 | * if the output video matches the input video settings. |
280 | */ |
281 | tpg_s_quality(tpg: &dev->tpg, qual: TPG_QUAL_NOISE, qual_offset: 0); |
282 | return; |
283 | } |
284 | if (vivid_is_hdmi_cap(dev) && |
285 | VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])) { |
286 | tpg_s_quality(tpg: &dev->tpg, qual: TPG_QUAL_NOISE, qual_offset: 0); |
287 | return; |
288 | } |
289 | if (vivid_is_sdtv_cap(dev) && |
290 | VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { |
291 | tpg_s_quality(tpg: &dev->tpg, qual: TPG_QUAL_NOISE, qual_offset: 0); |
292 | return; |
293 | } |
294 | if (!vivid_is_tv_cap(dev)) { |
295 | tpg_s_quality(tpg: &dev->tpg, qual: TPG_QUAL_COLOR, qual_offset: 0); |
296 | return; |
297 | } |
298 | |
299 | /* |
300 | * There is a fake channel every 6 MHz at 49.25, 55.25, etc. |
301 | * From +/- 0.25 MHz around the channel there is color, and from |
302 | * +/- 1 MHz there is grayscale (chroma is lost). |
303 | * Everywhere else it is just noise. |
304 | */ |
305 | freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); |
306 | if (freq_modulus > 2 * 16) { |
307 | tpg_s_quality(tpg: &dev->tpg, qual: TPG_QUAL_NOISE, |
308 | qual_offset: next_pseudo_random32(seed: dev->tv_freq ^ 0x55) & 0x3f); |
309 | return; |
310 | } |
311 | if (freq_modulus < 12 /*0.75 * 16*/ || freq_modulus > 20 /*1.25 * 16*/) |
312 | tpg_s_quality(tpg: &dev->tpg, qual: TPG_QUAL_GRAY, qual_offset: 0); |
313 | else |
314 | tpg_s_quality(tpg: &dev->tpg, qual: TPG_QUAL_COLOR, qual_offset: 0); |
315 | } |
316 | |
317 | /* |
318 | * Get the current picture quality and the associated afc value. |
319 | */ |
320 | static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc) |
321 | { |
322 | unsigned freq_modulus; |
323 | |
324 | if (afc) |
325 | *afc = 0; |
326 | if (tpg_g_quality(tpg: &dev->tpg) == TPG_QUAL_COLOR || |
327 | tpg_g_quality(tpg: &dev->tpg) == TPG_QUAL_NOISE) |
328 | return tpg_g_quality(tpg: &dev->tpg); |
329 | |
330 | /* |
331 | * There is a fake channel every 6 MHz at 49.25, 55.25, etc. |
332 | * From +/- 0.25 MHz around the channel there is color, and from |
333 | * +/- 1 MHz there is grayscale (chroma is lost). |
334 | * Everywhere else it is just gray. |
335 | */ |
336 | freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); |
337 | if (afc) |
338 | *afc = freq_modulus - 1 * 16; |
339 | return TPG_QUAL_GRAY; |
340 | } |
341 | |
342 | enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) |
343 | { |
344 | if (vivid_is_sdtv_cap(dev)) |
345 | return dev->std_aspect_ratio[dev->input]; |
346 | |
347 | if (vivid_is_hdmi_cap(dev)) |
348 | return dev->dv_timings_aspect_ratio[dev->input]; |
349 | |
350 | return TPG_VIDEO_ASPECT_IMAGE; |
351 | } |
352 | |
353 | static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) |
354 | { |
355 | if (vivid_is_sdtv_cap(dev)) |
356 | return (dev->std_cap[dev->input] & V4L2_STD_525_60) ? |
357 | TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; |
358 | |
359 | if (vivid_is_hdmi_cap(dev) && |
360 | dev->src_rect.width == 720 && dev->src_rect.height <= 576) |
361 | return dev->src_rect.height == 480 ? |
362 | TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; |
363 | |
364 | return TPG_PIXEL_ASPECT_SQUARE; |
365 | } |
366 | |
367 | /* |
368 | * Called whenever the format has to be reset which can occur when |
369 | * changing inputs, standard, timings, etc. |
370 | */ |
371 | void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) |
372 | { |
373 | struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; |
374 | u32 dims[V4L2_CTRL_MAX_DIMS] = {}; |
375 | unsigned size; |
376 | u64 pixelclock; |
377 | |
378 | switch (dev->input_type[dev->input]) { |
379 | case WEBCAM: |
380 | default: |
381 | dev->src_rect.width = webcam_sizes[dev->webcam_size_idx].width; |
382 | dev->src_rect.height = webcam_sizes[dev->webcam_size_idx].height; |
383 | dev->timeperframe_vid_cap = webcam_intervals[dev->webcam_ival_idx]; |
384 | dev->field_cap = V4L2_FIELD_NONE; |
385 | tpg_s_rgb_range(tpg: &dev->tpg, rgb_range: V4L2_DV_RGB_RANGE_AUTO); |
386 | break; |
387 | case TV: |
388 | case SVID: |
389 | dev->field_cap = dev->tv_field_cap; |
390 | dev->src_rect.width = 720; |
391 | if (dev->std_cap[dev->input] & V4L2_STD_525_60) { |
392 | dev->src_rect.height = 480; |
393 | dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 }; |
394 | dev->service_set_cap = V4L2_SLICED_CAPTION_525; |
395 | } else { |
396 | dev->src_rect.height = 576; |
397 | dev->timeperframe_vid_cap = (struct v4l2_fract) { 1000, 25000 }; |
398 | dev->service_set_cap = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; |
399 | } |
400 | tpg_s_rgb_range(tpg: &dev->tpg, rgb_range: V4L2_DV_RGB_RANGE_AUTO); |
401 | break; |
402 | case HDMI: |
403 | dev->src_rect.width = bt->width; |
404 | dev->src_rect.height = bt->height; |
405 | size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); |
406 | if (dev->reduced_fps && can_reduce_fps(bt)) { |
407 | pixelclock = div_u64(dividend: bt->pixelclock * 1000, divisor: 1001); |
408 | bt->flags |= V4L2_DV_FL_REDUCED_FPS; |
409 | } else { |
410 | pixelclock = bt->pixelclock; |
411 | bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; |
412 | } |
413 | dev->timeperframe_vid_cap = (struct v4l2_fract) { |
414 | size / 100, (u32)pixelclock / 100 |
415 | }; |
416 | if (bt->interlaced) |
417 | dev->field_cap = V4L2_FIELD_ALTERNATE; |
418 | else |
419 | dev->field_cap = V4L2_FIELD_NONE; |
420 | |
421 | /* |
422 | * We can be called from within s_ctrl, in that case we can't |
423 | * set/get controls. Luckily we don't need to in that case. |
424 | */ |
425 | if (keep_controls || !dev->colorspace) |
426 | break; |
427 | if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { |
428 | if (bt->width == 720 && bt->height <= 576) |
429 | v4l2_ctrl_s_ctrl(ctrl: dev->colorspace, val: VIVID_CS_170M); |
430 | else |
431 | v4l2_ctrl_s_ctrl(ctrl: dev->colorspace, val: VIVID_CS_709); |
432 | v4l2_ctrl_s_ctrl(ctrl: dev->real_rgb_range_cap, val: 1); |
433 | } else { |
434 | v4l2_ctrl_s_ctrl(ctrl: dev->colorspace, val: VIVID_CS_SRGB); |
435 | v4l2_ctrl_s_ctrl(ctrl: dev->real_rgb_range_cap, val: 0); |
436 | } |
437 | tpg_s_rgb_range(tpg: &dev->tpg, rgb_range: v4l2_ctrl_g_ctrl(ctrl: dev->rgb_range_cap)); |
438 | break; |
439 | } |
440 | vivid_update_quality(dev); |
441 | tpg_reset_source(tpg: &dev->tpg, width: dev->src_rect.width, height: dev->src_rect.height, field: dev->field_cap); |
442 | dev->crop_cap = dev->src_rect; |
443 | dev->crop_bounds_cap = dev->src_rect; |
444 | dev->compose_cap = dev->crop_cap; |
445 | if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap)) |
446 | dev->compose_cap.height /= 2; |
447 | dev->fmt_cap_rect = dev->compose_cap; |
448 | tpg_s_video_aspect(tpg: &dev->tpg, vid_aspect: vivid_get_video_aspect(dev)); |
449 | tpg_s_pixel_aspect(tpg: &dev->tpg, pix_aspect: vivid_get_pixel_aspect(dev)); |
450 | tpg_update_mv_step(tpg: &dev->tpg); |
451 | |
452 | /* |
453 | * We can be called from within s_ctrl, in that case we can't |
454 | * modify controls. Luckily we don't need to in that case. |
455 | */ |
456 | if (keep_controls) |
457 | return; |
458 | |
459 | dims[0] = roundup(dev->src_rect.width, PIXEL_ARRAY_DIV); |
460 | dims[1] = roundup(dev->src_rect.height, PIXEL_ARRAY_DIV); |
461 | v4l2_ctrl_modify_dimensions(ctrl: dev->pixel_array, dims); |
462 | } |
463 | |
464 | /* Map the field to something that is valid for the current input */ |
465 | static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field field) |
466 | { |
467 | if (vivid_is_sdtv_cap(dev)) { |
468 | switch (field) { |
469 | case V4L2_FIELD_INTERLACED_TB: |
470 | case V4L2_FIELD_INTERLACED_BT: |
471 | case V4L2_FIELD_SEQ_TB: |
472 | case V4L2_FIELD_SEQ_BT: |
473 | case V4L2_FIELD_TOP: |
474 | case V4L2_FIELD_BOTTOM: |
475 | case V4L2_FIELD_ALTERNATE: |
476 | return field; |
477 | case V4L2_FIELD_INTERLACED: |
478 | default: |
479 | return V4L2_FIELD_INTERLACED; |
480 | } |
481 | } |
482 | if (vivid_is_hdmi_cap(dev)) |
483 | return dev->dv_timings_cap[dev->input].bt.interlaced ? |
484 | V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE; |
485 | return V4L2_FIELD_NONE; |
486 | } |
487 | |
488 | static unsigned vivid_colorspace_cap(struct vivid_dev *dev) |
489 | { |
490 | if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) |
491 | return tpg_g_colorspace(tpg: &dev->tpg); |
492 | return dev->colorspace_out; |
493 | } |
494 | |
495 | static unsigned vivid_xfer_func_cap(struct vivid_dev *dev) |
496 | { |
497 | if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) |
498 | return tpg_g_xfer_func(tpg: &dev->tpg); |
499 | return dev->xfer_func_out; |
500 | } |
501 | |
502 | static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev) |
503 | { |
504 | if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) |
505 | return tpg_g_ycbcr_enc(tpg: &dev->tpg); |
506 | return dev->ycbcr_enc_out; |
507 | } |
508 | |
509 | static unsigned int vivid_hsv_enc_cap(struct vivid_dev *dev) |
510 | { |
511 | if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) |
512 | return tpg_g_hsv_enc(tpg: &dev->tpg); |
513 | return dev->hsv_enc_out; |
514 | } |
515 | |
516 | static unsigned vivid_quantization_cap(struct vivid_dev *dev) |
517 | { |
518 | if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) |
519 | return tpg_g_quantization(tpg: &dev->tpg); |
520 | return dev->quantization_out; |
521 | } |
522 | |
523 | int vivid_g_fmt_vid_cap(struct file *file, void *priv, |
524 | struct v4l2_format *f) |
525 | { |
526 | struct vivid_dev *dev = video_drvdata(file); |
527 | struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; |
528 | unsigned p; |
529 | |
530 | mp->width = dev->fmt_cap_rect.width; |
531 | mp->height = dev->fmt_cap_rect.height; |
532 | mp->field = dev->field_cap; |
533 | mp->pixelformat = dev->fmt_cap->fourcc; |
534 | mp->colorspace = vivid_colorspace_cap(dev); |
535 | mp->xfer_func = vivid_xfer_func_cap(dev); |
536 | if (dev->fmt_cap->color_enc == TGP_COLOR_ENC_HSV) |
537 | mp->hsv_enc = vivid_hsv_enc_cap(dev); |
538 | else |
539 | mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); |
540 | mp->quantization = vivid_quantization_cap(dev); |
541 | mp->num_planes = dev->fmt_cap->buffers; |
542 | for (p = 0; p < mp->num_planes; p++) { |
543 | mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(tpg: &dev->tpg, plane: p); |
544 | mp->plane_fmt[p].sizeimage = |
545 | (tpg_g_line_width(tpg: &dev->tpg, plane: p) * mp->height) / |
546 | dev->fmt_cap->vdownsampling[p] + |
547 | dev->fmt_cap->data_offset[p]; |
548 | } |
549 | return 0; |
550 | } |
551 | |
552 | int vivid_try_fmt_vid_cap(struct file *file, void *priv, |
553 | struct v4l2_format *f) |
554 | { |
555 | struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; |
556 | struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; |
557 | struct vivid_dev *dev = video_drvdata(file); |
558 | const struct vivid_fmt *fmt; |
559 | unsigned bytesperline, max_bpl; |
560 | unsigned factor = 1; |
561 | unsigned w, h; |
562 | unsigned p; |
563 | bool user_set_csc = !!(mp->flags & V4L2_PIX_FMT_FLAG_SET_CSC); |
564 | |
565 | fmt = vivid_get_format(dev, pixelformat: mp->pixelformat); |
566 | if (!fmt) { |
567 | dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n" , |
568 | mp->pixelformat); |
569 | mp->pixelformat = V4L2_PIX_FMT_YUYV; |
570 | fmt = vivid_get_format(dev, pixelformat: mp->pixelformat); |
571 | } |
572 | |
573 | mp->field = vivid_field_cap(dev, field: mp->field); |
574 | if (vivid_is_webcam(dev)) { |
575 | const struct v4l2_frmsize_discrete *sz = |
576 | v4l2_find_nearest_size(webcam_sizes, |
577 | ARRAY_SIZE(webcam_sizes), width, |
578 | height, mp->width, mp->height); |
579 | |
580 | w = sz->width; |
581 | h = sz->height; |
582 | } else if (vivid_is_sdtv_cap(dev)) { |
583 | w = 720; |
584 | h = (dev->std_cap[dev->input] & V4L2_STD_525_60) ? 480 : 576; |
585 | } else { |
586 | w = dev->src_rect.width; |
587 | h = dev->src_rect.height; |
588 | } |
589 | if (V4L2_FIELD_HAS_T_OR_B(mp->field)) |
590 | factor = 2; |
591 | if (vivid_is_webcam(dev) || |
592 | (!dev->has_scaler_cap && !dev->has_crop_cap && !dev->has_compose_cap)) { |
593 | mp->width = w; |
594 | mp->height = h / factor; |
595 | } else { |
596 | struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; |
597 | |
598 | v4l2_rect_set_min_size(r: &r, min_size: &vivid_min_rect); |
599 | v4l2_rect_set_max_size(r: &r, max_size: &vivid_max_rect); |
600 | if (dev->has_scaler_cap && !dev->has_compose_cap) { |
601 | struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; |
602 | |
603 | v4l2_rect_set_max_size(r: &r, max_size: &max_r); |
604 | } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) { |
605 | v4l2_rect_set_max_size(r: &r, max_size: &dev->src_rect); |
606 | } else if (!dev->has_scaler_cap && !dev->has_crop_cap) { |
607 | v4l2_rect_set_min_size(r: &r, min_size: &dev->src_rect); |
608 | } |
609 | mp->width = r.width; |
610 | mp->height = r.height / factor; |
611 | } |
612 | |
613 | /* This driver supports custom bytesperline values */ |
614 | |
615 | mp->num_planes = fmt->buffers; |
616 | for (p = 0; p < fmt->buffers; p++) { |
617 | /* Calculate the minimum supported bytesperline value */ |
618 | bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; |
619 | /* Calculate the maximum supported bytesperline value */ |
620 | max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; |
621 | |
622 | if (pfmt[p].bytesperline > max_bpl) |
623 | pfmt[p].bytesperline = max_bpl; |
624 | if (pfmt[p].bytesperline < bytesperline) |
625 | pfmt[p].bytesperline = bytesperline; |
626 | |
627 | pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / |
628 | fmt->vdownsampling[p] + fmt->data_offset[p]; |
629 | |
630 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); |
631 | } |
632 | for (p = fmt->buffers; p < fmt->planes; p++) |
633 | pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * |
634 | (fmt->bit_depth[p] / fmt->vdownsampling[p])) / |
635 | (fmt->bit_depth[0] / fmt->vdownsampling[0]); |
636 | |
637 | if (!user_set_csc || !v4l2_is_colorspace_valid(colorspace: mp->colorspace)) |
638 | mp->colorspace = vivid_colorspace_cap(dev); |
639 | |
640 | if (!user_set_csc || !v4l2_is_xfer_func_valid(xfer_func: mp->xfer_func)) |
641 | mp->xfer_func = vivid_xfer_func_cap(dev); |
642 | |
643 | if (fmt->color_enc == TGP_COLOR_ENC_HSV) { |
644 | if (!user_set_csc || !v4l2_is_hsv_enc_valid(hsv_enc: mp->hsv_enc)) |
645 | mp->hsv_enc = vivid_hsv_enc_cap(dev); |
646 | } else if (fmt->color_enc == TGP_COLOR_ENC_YCBCR) { |
647 | if (!user_set_csc || !v4l2_is_ycbcr_enc_valid(ycbcr_enc: mp->ycbcr_enc)) |
648 | mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); |
649 | } else { |
650 | mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); |
651 | } |
652 | |
653 | if (fmt->color_enc == TGP_COLOR_ENC_YCBCR || |
654 | fmt->color_enc == TGP_COLOR_ENC_RGB) { |
655 | if (!user_set_csc || !v4l2_is_quant_valid(quantization: mp->quantization)) |
656 | mp->quantization = vivid_quantization_cap(dev); |
657 | } else { |
658 | mp->quantization = vivid_quantization_cap(dev); |
659 | } |
660 | |
661 | memset(mp->reserved, 0, sizeof(mp->reserved)); |
662 | return 0; |
663 | } |
664 | |
665 | int vivid_s_fmt_vid_cap(struct file *file, void *priv, |
666 | struct v4l2_format *f) |
667 | { |
668 | struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; |
669 | struct vivid_dev *dev = video_drvdata(file); |
670 | struct v4l2_rect *crop = &dev->crop_cap; |
671 | struct v4l2_rect *compose = &dev->compose_cap; |
672 | struct vb2_queue *q = &dev->vb_vid_cap_q; |
673 | int ret = vivid_try_fmt_vid_cap(file, priv, f); |
674 | unsigned factor = 1; |
675 | unsigned p; |
676 | unsigned i; |
677 | |
678 | if (ret < 0) |
679 | return ret; |
680 | |
681 | if (vb2_is_busy(q)) { |
682 | dprintk(dev, 1, "%s device busy\n" , __func__); |
683 | return -EBUSY; |
684 | } |
685 | |
686 | dev->fmt_cap = vivid_get_format(dev, pixelformat: mp->pixelformat); |
687 | if (V4L2_FIELD_HAS_T_OR_B(mp->field)) |
688 | factor = 2; |
689 | |
690 | /* Note: the webcam input doesn't support scaling, cropping or composing */ |
691 | |
692 | if (!vivid_is_webcam(dev) && |
693 | (dev->has_scaler_cap || dev->has_crop_cap || dev->has_compose_cap)) { |
694 | struct v4l2_rect r = { 0, 0, mp->width, mp->height }; |
695 | |
696 | if (dev->has_scaler_cap) { |
697 | if (dev->has_compose_cap) |
698 | v4l2_rect_map_inside(r: compose, boundary: &r); |
699 | else |
700 | *compose = r; |
701 | if (dev->has_crop_cap && !dev->has_compose_cap) { |
702 | struct v4l2_rect min_r = { |
703 | 0, 0, |
704 | r.width / MAX_ZOOM, |
705 | factor * r.height / MAX_ZOOM |
706 | }; |
707 | struct v4l2_rect max_r = { |
708 | 0, 0, |
709 | r.width * MAX_ZOOM, |
710 | factor * r.height * MAX_ZOOM |
711 | }; |
712 | |
713 | v4l2_rect_set_min_size(r: crop, min_size: &min_r); |
714 | v4l2_rect_set_max_size(r: crop, max_size: &max_r); |
715 | v4l2_rect_map_inside(r: crop, boundary: &dev->crop_bounds_cap); |
716 | } else if (dev->has_crop_cap) { |
717 | struct v4l2_rect min_r = { |
718 | 0, 0, |
719 | compose->width / MAX_ZOOM, |
720 | factor * compose->height / MAX_ZOOM |
721 | }; |
722 | struct v4l2_rect max_r = { |
723 | 0, 0, |
724 | compose->width * MAX_ZOOM, |
725 | factor * compose->height * MAX_ZOOM |
726 | }; |
727 | |
728 | v4l2_rect_set_min_size(r: crop, min_size: &min_r); |
729 | v4l2_rect_set_max_size(r: crop, max_size: &max_r); |
730 | v4l2_rect_map_inside(r: crop, boundary: &dev->crop_bounds_cap); |
731 | } |
732 | } else if (dev->has_crop_cap && !dev->has_compose_cap) { |
733 | r.height *= factor; |
734 | v4l2_rect_set_size_to(r: crop, size: &r); |
735 | v4l2_rect_map_inside(r: crop, boundary: &dev->crop_bounds_cap); |
736 | r = *crop; |
737 | r.height /= factor; |
738 | v4l2_rect_set_size_to(r: compose, size: &r); |
739 | } else if (!dev->has_crop_cap) { |
740 | v4l2_rect_map_inside(r: compose, boundary: &r); |
741 | } else { |
742 | r.height *= factor; |
743 | v4l2_rect_set_max_size(r: crop, max_size: &r); |
744 | v4l2_rect_map_inside(r: crop, boundary: &dev->crop_bounds_cap); |
745 | compose->top *= factor; |
746 | compose->height *= factor; |
747 | v4l2_rect_set_size_to(r: compose, size: crop); |
748 | v4l2_rect_map_inside(r: compose, boundary: &r); |
749 | compose->top /= factor; |
750 | compose->height /= factor; |
751 | } |
752 | } else if (vivid_is_webcam(dev)) { |
753 | unsigned int ival_sz = webcam_ival_count(dev, frmsize_idx: dev->webcam_size_idx); |
754 | |
755 | /* Guaranteed to be a match */ |
756 | for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) |
757 | if (webcam_sizes[i].width == mp->width && |
758 | webcam_sizes[i].height == mp->height) |
759 | break; |
760 | dev->webcam_size_idx = i; |
761 | if (dev->webcam_ival_idx >= ival_sz) |
762 | dev->webcam_ival_idx = ival_sz - 1; |
763 | vivid_update_format_cap(dev, keep_controls: false); |
764 | } else { |
765 | struct v4l2_rect r = { 0, 0, mp->width, mp->height }; |
766 | |
767 | v4l2_rect_set_size_to(r: compose, size: &r); |
768 | r.height *= factor; |
769 | v4l2_rect_set_size_to(r: crop, size: &r); |
770 | } |
771 | |
772 | dev->fmt_cap_rect.width = mp->width; |
773 | dev->fmt_cap_rect.height = mp->height; |
774 | tpg_s_buf_height(tpg: &dev->tpg, h: mp->height); |
775 | tpg_s_fourcc(tpg: &dev->tpg, fourcc: dev->fmt_cap->fourcc); |
776 | for (p = 0; p < tpg_g_buffers(tpg: &dev->tpg); p++) |
777 | tpg_s_bytesperline(tpg: &dev->tpg, plane: p, bpl: mp->plane_fmt[p].bytesperline); |
778 | dev->field_cap = mp->field; |
779 | if (dev->field_cap == V4L2_FIELD_ALTERNATE) |
780 | tpg_s_field(tpg: &dev->tpg, field: V4L2_FIELD_TOP, alternate: true); |
781 | else |
782 | tpg_s_field(tpg: &dev->tpg, field: dev->field_cap, alternate: false); |
783 | tpg_s_crop_compose(tpg: &dev->tpg, crop: &dev->crop_cap, compose: &dev->compose_cap); |
784 | if (vivid_is_sdtv_cap(dev)) |
785 | dev->tv_field_cap = mp->field; |
786 | tpg_update_mv_step(tpg: &dev->tpg); |
787 | dev->tpg.colorspace = mp->colorspace; |
788 | dev->tpg.xfer_func = mp->xfer_func; |
789 | if (dev->fmt_cap->color_enc == TGP_COLOR_ENC_YCBCR) |
790 | dev->tpg.ycbcr_enc = mp->ycbcr_enc; |
791 | else |
792 | dev->tpg.hsv_enc = mp->hsv_enc; |
793 | dev->tpg.quantization = mp->quantization; |
794 | |
795 | return 0; |
796 | } |
797 | |
798 | int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, |
799 | struct v4l2_format *f) |
800 | { |
801 | struct vivid_dev *dev = video_drvdata(file); |
802 | |
803 | if (!dev->multiplanar) |
804 | return -ENOTTY; |
805 | return vivid_g_fmt_vid_cap(file, priv, f); |
806 | } |
807 | |
808 | int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, |
809 | struct v4l2_format *f) |
810 | { |
811 | struct vivid_dev *dev = video_drvdata(file); |
812 | |
813 | if (!dev->multiplanar) |
814 | return -ENOTTY; |
815 | return vivid_try_fmt_vid_cap(file, priv, f); |
816 | } |
817 | |
818 | int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, |
819 | struct v4l2_format *f) |
820 | { |
821 | struct vivid_dev *dev = video_drvdata(file); |
822 | |
823 | if (!dev->multiplanar) |
824 | return -ENOTTY; |
825 | return vivid_s_fmt_vid_cap(file, priv, f); |
826 | } |
827 | |
828 | int vidioc_g_fmt_vid_cap(struct file *file, void *priv, |
829 | struct v4l2_format *f) |
830 | { |
831 | struct vivid_dev *dev = video_drvdata(file); |
832 | |
833 | if (dev->multiplanar) |
834 | return -ENOTTY; |
835 | return fmt_sp2mp_func(file, priv, f, func: vivid_g_fmt_vid_cap); |
836 | } |
837 | |
838 | int vidioc_try_fmt_vid_cap(struct file *file, void *priv, |
839 | struct v4l2_format *f) |
840 | { |
841 | struct vivid_dev *dev = video_drvdata(file); |
842 | |
843 | if (dev->multiplanar) |
844 | return -ENOTTY; |
845 | return fmt_sp2mp_func(file, priv, f, func: vivid_try_fmt_vid_cap); |
846 | } |
847 | |
848 | int vidioc_s_fmt_vid_cap(struct file *file, void *priv, |
849 | struct v4l2_format *f) |
850 | { |
851 | struct vivid_dev *dev = video_drvdata(file); |
852 | |
853 | if (dev->multiplanar) |
854 | return -ENOTTY; |
855 | return fmt_sp2mp_func(file, priv, f, func: vivid_s_fmt_vid_cap); |
856 | } |
857 | |
858 | int vivid_vid_cap_g_selection(struct file *file, void *priv, |
859 | struct v4l2_selection *sel) |
860 | { |
861 | struct vivid_dev *dev = video_drvdata(file); |
862 | |
863 | if (!dev->has_crop_cap && !dev->has_compose_cap) |
864 | return -ENOTTY; |
865 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
866 | return -EINVAL; |
867 | if (vivid_is_webcam(dev)) |
868 | return -ENODATA; |
869 | |
870 | sel->r.left = sel->r.top = 0; |
871 | switch (sel->target) { |
872 | case V4L2_SEL_TGT_CROP: |
873 | if (!dev->has_crop_cap) |
874 | return -EINVAL; |
875 | sel->r = dev->crop_cap; |
876 | break; |
877 | case V4L2_SEL_TGT_CROP_DEFAULT: |
878 | case V4L2_SEL_TGT_CROP_BOUNDS: |
879 | if (!dev->has_crop_cap) |
880 | return -EINVAL; |
881 | sel->r = dev->src_rect; |
882 | break; |
883 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: |
884 | if (!dev->has_compose_cap) |
885 | return -EINVAL; |
886 | sel->r = vivid_max_rect; |
887 | break; |
888 | case V4L2_SEL_TGT_COMPOSE: |
889 | if (!dev->has_compose_cap) |
890 | return -EINVAL; |
891 | sel->r = dev->compose_cap; |
892 | break; |
893 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: |
894 | if (!dev->has_compose_cap) |
895 | return -EINVAL; |
896 | sel->r = dev->fmt_cap_rect; |
897 | break; |
898 | default: |
899 | return -EINVAL; |
900 | } |
901 | return 0; |
902 | } |
903 | |
904 | int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s) |
905 | { |
906 | struct vivid_dev *dev = video_drvdata(file); |
907 | struct v4l2_rect *crop = &dev->crop_cap; |
908 | struct v4l2_rect *compose = &dev->compose_cap; |
909 | unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; |
910 | int ret; |
911 | |
912 | if (!dev->has_crop_cap && !dev->has_compose_cap) |
913 | return -ENOTTY; |
914 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
915 | return -EINVAL; |
916 | if (vivid_is_webcam(dev)) |
917 | return -ENODATA; |
918 | |
919 | switch (s->target) { |
920 | case V4L2_SEL_TGT_CROP: |
921 | if (!dev->has_crop_cap) |
922 | return -EINVAL; |
923 | ret = vivid_vid_adjust_sel(flags: s->flags, r: &s->r); |
924 | if (ret) |
925 | return ret; |
926 | v4l2_rect_set_min_size(r: &s->r, min_size: &vivid_min_rect); |
927 | v4l2_rect_set_max_size(r: &s->r, max_size: &dev->src_rect); |
928 | v4l2_rect_map_inside(r: &s->r, boundary: &dev->crop_bounds_cap); |
929 | s->r.top /= factor; |
930 | s->r.height /= factor; |
931 | if (dev->has_scaler_cap) { |
932 | struct v4l2_rect fmt = dev->fmt_cap_rect; |
933 | struct v4l2_rect max_rect = { |
934 | 0, 0, |
935 | s->r.width * MAX_ZOOM, |
936 | s->r.height * MAX_ZOOM |
937 | }; |
938 | struct v4l2_rect min_rect = { |
939 | 0, 0, |
940 | s->r.width / MAX_ZOOM, |
941 | s->r.height / MAX_ZOOM |
942 | }; |
943 | |
944 | v4l2_rect_set_min_size(r: &fmt, min_size: &min_rect); |
945 | if (!dev->has_compose_cap) |
946 | v4l2_rect_set_max_size(r: &fmt, max_size: &max_rect); |
947 | if (!v4l2_rect_same_size(r1: &dev->fmt_cap_rect, r2: &fmt) && |
948 | vb2_is_busy(q: &dev->vb_vid_cap_q)) |
949 | return -EBUSY; |
950 | if (dev->has_compose_cap) { |
951 | v4l2_rect_set_min_size(r: compose, min_size: &min_rect); |
952 | v4l2_rect_set_max_size(r: compose, max_size: &max_rect); |
953 | v4l2_rect_map_inside(r: compose, boundary: &fmt); |
954 | } |
955 | dev->fmt_cap_rect = fmt; |
956 | tpg_s_buf_height(tpg: &dev->tpg, h: fmt.height); |
957 | } else if (dev->has_compose_cap) { |
958 | struct v4l2_rect fmt = dev->fmt_cap_rect; |
959 | |
960 | v4l2_rect_set_min_size(r: &fmt, min_size: &s->r); |
961 | if (!v4l2_rect_same_size(r1: &dev->fmt_cap_rect, r2: &fmt) && |
962 | vb2_is_busy(q: &dev->vb_vid_cap_q)) |
963 | return -EBUSY; |
964 | dev->fmt_cap_rect = fmt; |
965 | tpg_s_buf_height(tpg: &dev->tpg, h: fmt.height); |
966 | v4l2_rect_set_size_to(r: compose, size: &s->r); |
967 | v4l2_rect_map_inside(r: compose, boundary: &dev->fmt_cap_rect); |
968 | } else { |
969 | if (!v4l2_rect_same_size(r1: &s->r, r2: &dev->fmt_cap_rect) && |
970 | vb2_is_busy(q: &dev->vb_vid_cap_q)) |
971 | return -EBUSY; |
972 | v4l2_rect_set_size_to(r: &dev->fmt_cap_rect, size: &s->r); |
973 | v4l2_rect_set_size_to(r: compose, size: &s->r); |
974 | v4l2_rect_map_inside(r: compose, boundary: &dev->fmt_cap_rect); |
975 | tpg_s_buf_height(tpg: &dev->tpg, h: dev->fmt_cap_rect.height); |
976 | } |
977 | s->r.top *= factor; |
978 | s->r.height *= factor; |
979 | *crop = s->r; |
980 | break; |
981 | case V4L2_SEL_TGT_COMPOSE: |
982 | if (!dev->has_compose_cap) |
983 | return -EINVAL; |
984 | ret = vivid_vid_adjust_sel(flags: s->flags, r: &s->r); |
985 | if (ret) |
986 | return ret; |
987 | v4l2_rect_set_min_size(r: &s->r, min_size: &vivid_min_rect); |
988 | v4l2_rect_set_max_size(r: &s->r, max_size: &dev->fmt_cap_rect); |
989 | if (dev->has_scaler_cap) { |
990 | struct v4l2_rect max_rect = { |
991 | 0, 0, |
992 | dev->src_rect.width * MAX_ZOOM, |
993 | (dev->src_rect.height / factor) * MAX_ZOOM |
994 | }; |
995 | |
996 | v4l2_rect_set_max_size(r: &s->r, max_size: &max_rect); |
997 | if (dev->has_crop_cap) { |
998 | struct v4l2_rect min_rect = { |
999 | 0, 0, |
1000 | s->r.width / MAX_ZOOM, |
1001 | (s->r.height * factor) / MAX_ZOOM |
1002 | }; |
1003 | struct v4l2_rect max_rect = { |
1004 | 0, 0, |
1005 | s->r.width * MAX_ZOOM, |
1006 | (s->r.height * factor) * MAX_ZOOM |
1007 | }; |
1008 | |
1009 | v4l2_rect_set_min_size(r: crop, min_size: &min_rect); |
1010 | v4l2_rect_set_max_size(r: crop, max_size: &max_rect); |
1011 | v4l2_rect_map_inside(r: crop, boundary: &dev->crop_bounds_cap); |
1012 | } |
1013 | } else if (dev->has_crop_cap) { |
1014 | s->r.top *= factor; |
1015 | s->r.height *= factor; |
1016 | v4l2_rect_set_max_size(r: &s->r, max_size: &dev->src_rect); |
1017 | v4l2_rect_set_size_to(r: crop, size: &s->r); |
1018 | v4l2_rect_map_inside(r: crop, boundary: &dev->crop_bounds_cap); |
1019 | s->r.top /= factor; |
1020 | s->r.height /= factor; |
1021 | } else { |
1022 | v4l2_rect_set_size_to(r: &s->r, size: &dev->src_rect); |
1023 | s->r.height /= factor; |
1024 | } |
1025 | v4l2_rect_map_inside(r: &s->r, boundary: &dev->fmt_cap_rect); |
1026 | *compose = s->r; |
1027 | break; |
1028 | default: |
1029 | return -EINVAL; |
1030 | } |
1031 | |
1032 | tpg_s_crop_compose(tpg: &dev->tpg, crop, compose); |
1033 | return 0; |
1034 | } |
1035 | |
1036 | int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, |
1037 | int type, struct v4l2_fract *f) |
1038 | { |
1039 | struct vivid_dev *dev = video_drvdata(file); |
1040 | |
1041 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1042 | return -EINVAL; |
1043 | |
1044 | switch (vivid_get_pixel_aspect(dev)) { |
1045 | case TPG_PIXEL_ASPECT_NTSC: |
1046 | f->numerator = 11; |
1047 | f->denominator = 10; |
1048 | break; |
1049 | case TPG_PIXEL_ASPECT_PAL: |
1050 | f->numerator = 54; |
1051 | f->denominator = 59; |
1052 | break; |
1053 | default: |
1054 | break; |
1055 | } |
1056 | return 0; |
1057 | } |
1058 | |
1059 | static const struct v4l2_audio vivid_audio_inputs[] = { |
1060 | { 0, "TV" , V4L2_AUDCAP_STEREO }, |
1061 | { 1, "Line-In" , V4L2_AUDCAP_STEREO }, |
1062 | }; |
1063 | |
1064 | int vidioc_enum_input(struct file *file, void *priv, |
1065 | struct v4l2_input *inp) |
1066 | { |
1067 | struct vivid_dev *dev = video_drvdata(file); |
1068 | |
1069 | if (inp->index >= dev->num_inputs) |
1070 | return -EINVAL; |
1071 | |
1072 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
1073 | switch (dev->input_type[inp->index]) { |
1074 | case WEBCAM: |
1075 | snprintf(buf: inp->name, size: sizeof(inp->name), fmt: "Webcam %u" , |
1076 | dev->input_name_counter[inp->index]); |
1077 | inp->capabilities = 0; |
1078 | break; |
1079 | case TV: |
1080 | snprintf(buf: inp->name, size: sizeof(inp->name), fmt: "TV %u" , |
1081 | dev->input_name_counter[inp->index]); |
1082 | inp->type = V4L2_INPUT_TYPE_TUNER; |
1083 | inp->std = V4L2_STD_ALL; |
1084 | if (dev->has_audio_inputs) |
1085 | inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1; |
1086 | inp->capabilities = V4L2_IN_CAP_STD; |
1087 | break; |
1088 | case SVID: |
1089 | snprintf(buf: inp->name, size: sizeof(inp->name), fmt: "S-Video %u" , |
1090 | dev->input_name_counter[inp->index]); |
1091 | inp->std = V4L2_STD_ALL; |
1092 | if (dev->has_audio_inputs) |
1093 | inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1; |
1094 | inp->capabilities = V4L2_IN_CAP_STD; |
1095 | break; |
1096 | case HDMI: |
1097 | snprintf(buf: inp->name, size: sizeof(inp->name), fmt: "HDMI %u" , |
1098 | dev->input_name_counter[inp->index]); |
1099 | inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; |
1100 | if (dev->edid_blocks == 0 || |
1101 | dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL) |
1102 | inp->status |= V4L2_IN_ST_NO_SIGNAL; |
1103 | else if (dev->dv_timings_signal_mode[dev->input] == NO_LOCK || |
1104 | dev->dv_timings_signal_mode[dev->input] == OUT_OF_RANGE) |
1105 | inp->status |= V4L2_IN_ST_NO_H_LOCK; |
1106 | break; |
1107 | } |
1108 | if (dev->sensor_hflip) |
1109 | inp->status |= V4L2_IN_ST_HFLIP; |
1110 | if (dev->sensor_vflip) |
1111 | inp->status |= V4L2_IN_ST_VFLIP; |
1112 | if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) { |
1113 | if (dev->std_signal_mode[dev->input] == NO_SIGNAL) { |
1114 | inp->status |= V4L2_IN_ST_NO_SIGNAL; |
1115 | } else if (dev->std_signal_mode[dev->input] == NO_LOCK) { |
1116 | inp->status |= V4L2_IN_ST_NO_H_LOCK; |
1117 | } else if (vivid_is_tv_cap(dev)) { |
1118 | switch (tpg_g_quality(tpg: &dev->tpg)) { |
1119 | case TPG_QUAL_GRAY: |
1120 | inp->status |= V4L2_IN_ST_COLOR_KILL; |
1121 | break; |
1122 | case TPG_QUAL_NOISE: |
1123 | inp->status |= V4L2_IN_ST_NO_H_LOCK; |
1124 | break; |
1125 | default: |
1126 | break; |
1127 | } |
1128 | } |
1129 | } |
1130 | return 0; |
1131 | } |
1132 | |
1133 | int vidioc_g_input(struct file *file, void *priv, unsigned *i) |
1134 | { |
1135 | struct vivid_dev *dev = video_drvdata(file); |
1136 | |
1137 | *i = dev->input; |
1138 | return 0; |
1139 | } |
1140 | |
1141 | int vidioc_s_input(struct file *file, void *priv, unsigned i) |
1142 | { |
1143 | struct vivid_dev *dev = video_drvdata(file); |
1144 | struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; |
1145 | unsigned brightness; |
1146 | |
1147 | if (i >= dev->num_inputs) |
1148 | return -EINVAL; |
1149 | |
1150 | if (i == dev->input) |
1151 | return 0; |
1152 | |
1153 | if (vb2_is_busy(q: &dev->vb_vid_cap_q) || |
1154 | vb2_is_busy(q: &dev->vb_vbi_cap_q) || |
1155 | vb2_is_busy(q: &dev->vb_meta_cap_q)) |
1156 | return -EBUSY; |
1157 | |
1158 | dev->input = i; |
1159 | dev->vid_cap_dev.tvnorms = 0; |
1160 | if (dev->input_type[i] == TV || dev->input_type[i] == SVID) { |
1161 | dev->tv_audio_input = (dev->input_type[i] == TV) ? 0 : 1; |
1162 | dev->vid_cap_dev.tvnorms = V4L2_STD_ALL; |
1163 | } |
1164 | dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; |
1165 | dev->meta_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; |
1166 | vivid_update_format_cap(dev, keep_controls: false); |
1167 | |
1168 | if (dev->colorspace) { |
1169 | switch (dev->input_type[i]) { |
1170 | case WEBCAM: |
1171 | v4l2_ctrl_s_ctrl(ctrl: dev->colorspace, val: VIVID_CS_SRGB); |
1172 | break; |
1173 | case TV: |
1174 | case SVID: |
1175 | v4l2_ctrl_s_ctrl(ctrl: dev->colorspace, val: VIVID_CS_170M); |
1176 | break; |
1177 | case HDMI: |
1178 | if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { |
1179 | if (dev->src_rect.width == 720 && dev->src_rect.height <= 576) |
1180 | v4l2_ctrl_s_ctrl(ctrl: dev->colorspace, val: VIVID_CS_170M); |
1181 | else |
1182 | v4l2_ctrl_s_ctrl(ctrl: dev->colorspace, val: VIVID_CS_709); |
1183 | } else { |
1184 | v4l2_ctrl_s_ctrl(ctrl: dev->colorspace, val: VIVID_CS_SRGB); |
1185 | } |
1186 | break; |
1187 | } |
1188 | } |
1189 | |
1190 | /* |
1191 | * Modify the brightness range depending on the input. |
1192 | * This makes it easy to use vivid to test if applications can |
1193 | * handle control range modifications and is also how this is |
1194 | * typically used in practice as different inputs may be hooked |
1195 | * up to different receivers with different control ranges. |
1196 | */ |
1197 | brightness = 128 * i + dev->input_brightness[i]; |
1198 | v4l2_ctrl_modify_range(ctrl: dev->brightness, |
1199 | min: 128 * i, max: 255 + 128 * i, step: 1, def: 128 + 128 * i); |
1200 | v4l2_ctrl_s_ctrl(ctrl: dev->brightness, val: brightness); |
1201 | |
1202 | /* Restore per-input states. */ |
1203 | v4l2_ctrl_activate(ctrl: dev->ctrl_dv_timings_signal_mode, |
1204 | active: vivid_is_hdmi_cap(dev)); |
1205 | v4l2_ctrl_activate(ctrl: dev->ctrl_dv_timings, active: vivid_is_hdmi_cap(dev) && |
1206 | dev->dv_timings_signal_mode[dev->input] == |
1207 | SELECTED_DV_TIMINGS); |
1208 | v4l2_ctrl_activate(ctrl: dev->ctrl_std_signal_mode, active: vivid_is_sdtv_cap(dev)); |
1209 | v4l2_ctrl_activate(ctrl: dev->ctrl_standard, active: vivid_is_sdtv_cap(dev) && |
1210 | dev->std_signal_mode[dev->input]); |
1211 | |
1212 | if (vivid_is_hdmi_cap(dev)) { |
1213 | v4l2_ctrl_s_ctrl(ctrl: dev->ctrl_dv_timings_signal_mode, |
1214 | val: dev->dv_timings_signal_mode[dev->input]); |
1215 | v4l2_ctrl_s_ctrl(ctrl: dev->ctrl_dv_timings, |
1216 | val: dev->query_dv_timings[dev->input]); |
1217 | } else if (vivid_is_sdtv_cap(dev)) { |
1218 | v4l2_ctrl_s_ctrl(ctrl: dev->ctrl_std_signal_mode, |
1219 | val: dev->std_signal_mode[dev->input]); |
1220 | v4l2_ctrl_s_ctrl(ctrl: dev->ctrl_standard, |
1221 | val: dev->std_signal_mode[dev->input]); |
1222 | } |
1223 | |
1224 | return 0; |
1225 | } |
1226 | |
1227 | int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) |
1228 | { |
1229 | if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) |
1230 | return -EINVAL; |
1231 | *vin = vivid_audio_inputs[vin->index]; |
1232 | return 0; |
1233 | } |
1234 | |
1235 | int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) |
1236 | { |
1237 | struct vivid_dev *dev = video_drvdata(file); |
1238 | |
1239 | if (!vivid_is_sdtv_cap(dev)) |
1240 | return -EINVAL; |
1241 | *vin = vivid_audio_inputs[dev->tv_audio_input]; |
1242 | return 0; |
1243 | } |
1244 | |
1245 | int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin) |
1246 | { |
1247 | struct vivid_dev *dev = video_drvdata(file); |
1248 | |
1249 | if (!vivid_is_sdtv_cap(dev)) |
1250 | return -EINVAL; |
1251 | if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) |
1252 | return -EINVAL; |
1253 | dev->tv_audio_input = vin->index; |
1254 | return 0; |
1255 | } |
1256 | |
1257 | int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) |
1258 | { |
1259 | struct vivid_dev *dev = video_drvdata(file); |
1260 | |
1261 | if (vf->tuner != 0) |
1262 | return -EINVAL; |
1263 | vf->frequency = dev->tv_freq; |
1264 | return 0; |
1265 | } |
1266 | |
1267 | int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) |
1268 | { |
1269 | struct vivid_dev *dev = video_drvdata(file); |
1270 | |
1271 | if (vf->tuner != 0) |
1272 | return -EINVAL; |
1273 | dev->tv_freq = clamp_t(unsigned, vf->frequency, MIN_TV_FREQ, MAX_TV_FREQ); |
1274 | if (vivid_is_tv_cap(dev)) |
1275 | vivid_update_quality(dev); |
1276 | return 0; |
1277 | } |
1278 | |
1279 | int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) |
1280 | { |
1281 | struct vivid_dev *dev = video_drvdata(file); |
1282 | |
1283 | if (vt->index != 0) |
1284 | return -EINVAL; |
1285 | if (vt->audmode > V4L2_TUNER_MODE_LANG1_LANG2) |
1286 | return -EINVAL; |
1287 | dev->tv_audmode = vt->audmode; |
1288 | return 0; |
1289 | } |
1290 | |
1291 | int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) |
1292 | { |
1293 | struct vivid_dev *dev = video_drvdata(file); |
1294 | enum tpg_quality qual; |
1295 | |
1296 | if (vt->index != 0) |
1297 | return -EINVAL; |
1298 | |
1299 | vt->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | |
1300 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; |
1301 | vt->audmode = dev->tv_audmode; |
1302 | vt->rangelow = MIN_TV_FREQ; |
1303 | vt->rangehigh = MAX_TV_FREQ; |
1304 | qual = vivid_get_quality(dev, afc: &vt->afc); |
1305 | if (qual == TPG_QUAL_COLOR) |
1306 | vt->signal = 0xffff; |
1307 | else if (qual == TPG_QUAL_GRAY) |
1308 | vt->signal = 0x8000; |
1309 | else |
1310 | vt->signal = 0; |
1311 | if (qual == TPG_QUAL_NOISE) { |
1312 | vt->rxsubchans = 0; |
1313 | } else if (qual == TPG_QUAL_GRAY) { |
1314 | vt->rxsubchans = V4L2_TUNER_SUB_MONO; |
1315 | } else { |
1316 | unsigned int channel_nr = dev->tv_freq / (6 * 16); |
1317 | unsigned int options = |
1318 | (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) ? 4 : 3; |
1319 | |
1320 | switch (channel_nr % options) { |
1321 | case 0: |
1322 | vt->rxsubchans = V4L2_TUNER_SUB_MONO; |
1323 | break; |
1324 | case 1: |
1325 | vt->rxsubchans = V4L2_TUNER_SUB_STEREO; |
1326 | break; |
1327 | case 2: |
1328 | if (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) |
1329 | vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP; |
1330 | else |
1331 | vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; |
1332 | break; |
1333 | case 3: |
1334 | vt->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP; |
1335 | break; |
1336 | } |
1337 | } |
1338 | strscpy(vt->name, "TV Tuner" , sizeof(vt->name)); |
1339 | return 0; |
1340 | } |
1341 | |
1342 | /* Must remain in sync with the vivid_ctrl_standard_strings array */ |
1343 | const v4l2_std_id vivid_standard[] = { |
1344 | V4L2_STD_NTSC_M, |
1345 | V4L2_STD_NTSC_M_JP, |
1346 | V4L2_STD_NTSC_M_KR, |
1347 | V4L2_STD_NTSC_443, |
1348 | V4L2_STD_PAL_BG | V4L2_STD_PAL_H, |
1349 | V4L2_STD_PAL_I, |
1350 | V4L2_STD_PAL_DK, |
1351 | V4L2_STD_PAL_M, |
1352 | V4L2_STD_PAL_N, |
1353 | V4L2_STD_PAL_Nc, |
1354 | V4L2_STD_PAL_60, |
1355 | V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, |
1356 | V4L2_STD_SECAM_DK, |
1357 | V4L2_STD_SECAM_L, |
1358 | V4L2_STD_SECAM_LC, |
1359 | V4L2_STD_UNKNOWN |
1360 | }; |
1361 | |
1362 | /* Must remain in sync with the vivid_standard array */ |
1363 | const char * const vivid_ctrl_standard_strings[] = { |
1364 | "NTSC-M" , |
1365 | "NTSC-M-JP" , |
1366 | "NTSC-M-KR" , |
1367 | "NTSC-443" , |
1368 | "PAL-BGH" , |
1369 | "PAL-I" , |
1370 | "PAL-DK" , |
1371 | "PAL-M" , |
1372 | "PAL-N" , |
1373 | "PAL-Nc" , |
1374 | "PAL-60" , |
1375 | "SECAM-BGH" , |
1376 | "SECAM-DK" , |
1377 | "SECAM-L" , |
1378 | "SECAM-Lc" , |
1379 | NULL, |
1380 | }; |
1381 | |
1382 | int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id) |
1383 | { |
1384 | struct vivid_dev *dev = video_drvdata(file); |
1385 | unsigned int last = dev->query_std_last[dev->input]; |
1386 | |
1387 | if (!vivid_is_sdtv_cap(dev)) |
1388 | return -ENODATA; |
1389 | if (dev->std_signal_mode[dev->input] == NO_SIGNAL || |
1390 | dev->std_signal_mode[dev->input] == NO_LOCK) { |
1391 | *id = V4L2_STD_UNKNOWN; |
1392 | return 0; |
1393 | } |
1394 | if (vivid_is_tv_cap(dev) && tpg_g_quality(tpg: &dev->tpg) == TPG_QUAL_NOISE) { |
1395 | *id = V4L2_STD_UNKNOWN; |
1396 | } else if (dev->std_signal_mode[dev->input] == CURRENT_STD) { |
1397 | *id = dev->std_cap[dev->input]; |
1398 | } else if (dev->std_signal_mode[dev->input] == SELECTED_STD) { |
1399 | *id = dev->query_std[dev->input]; |
1400 | } else { |
1401 | *id = vivid_standard[last]; |
1402 | dev->query_std_last[dev->input] = |
1403 | (last + 1) % ARRAY_SIZE(vivid_standard); |
1404 | } |
1405 | |
1406 | return 0; |
1407 | } |
1408 | |
1409 | int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) |
1410 | { |
1411 | struct vivid_dev *dev = video_drvdata(file); |
1412 | |
1413 | if (!vivid_is_sdtv_cap(dev)) |
1414 | return -ENODATA; |
1415 | if (dev->std_cap[dev->input] == id) |
1416 | return 0; |
1417 | if (vb2_is_busy(q: &dev->vb_vid_cap_q) || vb2_is_busy(q: &dev->vb_vbi_cap_q)) |
1418 | return -EBUSY; |
1419 | dev->std_cap[dev->input] = id; |
1420 | vivid_update_format_cap(dev, keep_controls: false); |
1421 | return 0; |
1422 | } |
1423 | |
1424 | static void find_aspect_ratio(u32 width, u32 height, |
1425 | u32 *num, u32 *denom) |
1426 | { |
1427 | if (!(height % 3) && ((height * 4 / 3) == width)) { |
1428 | *num = 4; |
1429 | *denom = 3; |
1430 | } else if (!(height % 9) && ((height * 16 / 9) == width)) { |
1431 | *num = 16; |
1432 | *denom = 9; |
1433 | } else if (!(height % 10) && ((height * 16 / 10) == width)) { |
1434 | *num = 16; |
1435 | *denom = 10; |
1436 | } else if (!(height % 4) && ((height * 5 / 4) == width)) { |
1437 | *num = 5; |
1438 | *denom = 4; |
1439 | } else if (!(height % 9) && ((height * 15 / 9) == width)) { |
1440 | *num = 15; |
1441 | *denom = 9; |
1442 | } else { /* default to 16:9 */ |
1443 | *num = 16; |
1444 | *denom = 9; |
1445 | } |
1446 | } |
1447 | |
1448 | static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) |
1449 | { |
1450 | struct v4l2_bt_timings *bt = &timings->bt; |
1451 | u32 total_h_pixel; |
1452 | u32 total_v_lines; |
1453 | u32 h_freq; |
1454 | |
1455 | if (!v4l2_valid_dv_timings(t: timings, cap: &vivid_dv_timings_cap, |
1456 | NULL, NULL)) |
1457 | return false; |
1458 | |
1459 | total_h_pixel = V4L2_DV_BT_FRAME_WIDTH(bt); |
1460 | total_v_lines = V4L2_DV_BT_FRAME_HEIGHT(bt); |
1461 | |
1462 | h_freq = (u32)bt->pixelclock / total_h_pixel; |
1463 | |
1464 | if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { |
1465 | if (v4l2_detect_cvt(frame_height: total_v_lines, hfreq: h_freq, vsync: bt->vsync, active_width: bt->width, |
1466 | polarities: bt->polarities, interlaced: bt->interlaced, fmt: timings)) |
1467 | return true; |
1468 | } |
1469 | |
1470 | if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) { |
1471 | struct v4l2_fract aspect_ratio; |
1472 | |
1473 | find_aspect_ratio(width: bt->width, height: bt->height, |
1474 | num: &aspect_ratio.numerator, |
1475 | denom: &aspect_ratio.denominator); |
1476 | if (v4l2_detect_gtf(frame_height: total_v_lines, hfreq: h_freq, vsync: bt->vsync, |
1477 | polarities: bt->polarities, interlaced: bt->interlaced, |
1478 | aspect: aspect_ratio, fmt: timings)) |
1479 | return true; |
1480 | } |
1481 | return false; |
1482 | } |
1483 | |
1484 | int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, |
1485 | struct v4l2_dv_timings *timings) |
1486 | { |
1487 | struct vivid_dev *dev = video_drvdata(file); |
1488 | |
1489 | if (!vivid_is_hdmi_cap(dev)) |
1490 | return -ENODATA; |
1491 | if (!v4l2_find_dv_timings_cap(t: timings, cap: &vivid_dv_timings_cap, |
1492 | pclock_delta: 0, NULL, NULL) && |
1493 | !valid_cvt_gtf_timings(timings)) |
1494 | return -EINVAL; |
1495 | |
1496 | if (v4l2_match_dv_timings(measured: timings, standard: &dev->dv_timings_cap[dev->input], |
1497 | pclock_delta: 0, match_reduced_fps: false)) |
1498 | return 0; |
1499 | if (vb2_is_busy(q: &dev->vb_vid_cap_q)) |
1500 | return -EBUSY; |
1501 | |
1502 | dev->dv_timings_cap[dev->input] = *timings; |
1503 | vivid_update_format_cap(dev, keep_controls: false); |
1504 | return 0; |
1505 | } |
1506 | |
1507 | int vidioc_query_dv_timings(struct file *file, void *_fh, |
1508 | struct v4l2_dv_timings *timings) |
1509 | { |
1510 | struct vivid_dev *dev = video_drvdata(file); |
1511 | unsigned int input = dev->input; |
1512 | unsigned int last = dev->query_dv_timings_last[input]; |
1513 | |
1514 | if (!vivid_is_hdmi_cap(dev)) |
1515 | return -ENODATA; |
1516 | if (dev->dv_timings_signal_mode[input] == NO_SIGNAL || |
1517 | dev->edid_blocks == 0) |
1518 | return -ENOLINK; |
1519 | if (dev->dv_timings_signal_mode[input] == NO_LOCK) |
1520 | return -ENOLCK; |
1521 | if (dev->dv_timings_signal_mode[input] == OUT_OF_RANGE) { |
1522 | timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2; |
1523 | return -ERANGE; |
1524 | } |
1525 | if (dev->dv_timings_signal_mode[input] == CURRENT_DV_TIMINGS) { |
1526 | *timings = dev->dv_timings_cap[input]; |
1527 | } else if (dev->dv_timings_signal_mode[input] == |
1528 | SELECTED_DV_TIMINGS) { |
1529 | *timings = |
1530 | v4l2_dv_timings_presets[dev->query_dv_timings[input]]; |
1531 | } else { |
1532 | *timings = |
1533 | v4l2_dv_timings_presets[last]; |
1534 | dev->query_dv_timings_last[input] = |
1535 | (last + 1) % dev->query_dv_timings_size; |
1536 | } |
1537 | return 0; |
1538 | } |
1539 | |
1540 | int vidioc_s_edid(struct file *file, void *_fh, |
1541 | struct v4l2_edid *edid) |
1542 | { |
1543 | struct vivid_dev *dev = video_drvdata(file); |
1544 | u16 phys_addr; |
1545 | u32 display_present = 0; |
1546 | unsigned int i, j; |
1547 | int ret; |
1548 | |
1549 | memset(edid->reserved, 0, sizeof(edid->reserved)); |
1550 | if (edid->pad >= dev->num_inputs) |
1551 | return -EINVAL; |
1552 | if (dev->input_type[edid->pad] != HDMI || edid->start_block) |
1553 | return -EINVAL; |
1554 | if (edid->blocks == 0) { |
1555 | dev->edid_blocks = 0; |
1556 | v4l2_ctrl_s_ctrl(ctrl: dev->ctrl_tx_edid_present, val: 0); |
1557 | v4l2_ctrl_s_ctrl(ctrl: dev->ctrl_tx_hotplug, val: 0); |
1558 | phys_addr = CEC_PHYS_ADDR_INVALID; |
1559 | goto set_phys_addr; |
1560 | } |
1561 | if (edid->blocks > dev->edid_max_blocks) { |
1562 | edid->blocks = dev->edid_max_blocks; |
1563 | return -E2BIG; |
1564 | } |
1565 | phys_addr = cec_get_edid_phys_addr(edid: edid->edid, size: edid->blocks * 128, NULL); |
1566 | ret = v4l2_phys_addr_validate(phys_addr, parent: &phys_addr, NULL); |
1567 | if (ret) |
1568 | return ret; |
1569 | |
1570 | if (vb2_is_busy(q: &dev->vb_vid_cap_q)) |
1571 | return -EBUSY; |
1572 | |
1573 | dev->edid_blocks = edid->blocks; |
1574 | memcpy(dev->edid, edid->edid, edid->blocks * 128); |
1575 | |
1576 | for (i = 0, j = 0; i < dev->num_outputs; i++) |
1577 | if (dev->output_type[i] == HDMI) |
1578 | display_present |= |
1579 | dev->display_present[i] << j++; |
1580 | |
1581 | v4l2_ctrl_s_ctrl(ctrl: dev->ctrl_tx_edid_present, val: display_present); |
1582 | v4l2_ctrl_s_ctrl(ctrl: dev->ctrl_tx_hotplug, val: display_present); |
1583 | |
1584 | set_phys_addr: |
1585 | /* TODO: a proper hotplug detect cycle should be emulated here */ |
1586 | cec_s_phys_addr(adap: dev->cec_rx_adap, phys_addr, block: false); |
1587 | |
1588 | for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) |
1589 | cec_s_phys_addr(adap: dev->cec_tx_adap[i], |
1590 | phys_addr: dev->display_present[i] ? |
1591 | v4l2_phys_addr_for_input(phys_addr, input: i + 1) : |
1592 | CEC_PHYS_ADDR_INVALID, |
1593 | block: false); |
1594 | return 0; |
1595 | } |
1596 | |
1597 | int vidioc_enum_framesizes(struct file *file, void *fh, |
1598 | struct v4l2_frmsizeenum *fsize) |
1599 | { |
1600 | struct vivid_dev *dev = video_drvdata(file); |
1601 | |
1602 | if (!vivid_is_webcam(dev) && !dev->has_scaler_cap) |
1603 | return -EINVAL; |
1604 | if (vivid_get_format(dev, pixelformat: fsize->pixel_format) == NULL) |
1605 | return -EINVAL; |
1606 | if (vivid_is_webcam(dev)) { |
1607 | if (fsize->index >= ARRAY_SIZE(webcam_sizes)) |
1608 | return -EINVAL; |
1609 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; |
1610 | fsize->discrete = webcam_sizes[fsize->index]; |
1611 | return 0; |
1612 | } |
1613 | if (fsize->index) |
1614 | return -EINVAL; |
1615 | fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; |
1616 | fsize->stepwise.min_width = MIN_WIDTH; |
1617 | fsize->stepwise.max_width = MAX_WIDTH * MAX_ZOOM; |
1618 | fsize->stepwise.step_width = 2; |
1619 | fsize->stepwise.min_height = MIN_HEIGHT; |
1620 | fsize->stepwise.max_height = MAX_HEIGHT * MAX_ZOOM; |
1621 | fsize->stepwise.step_height = 2; |
1622 | return 0; |
1623 | } |
1624 | |
1625 | /* timeperframe is arbitrary and continuous */ |
1626 | int vidioc_enum_frameintervals(struct file *file, void *priv, |
1627 | struct v4l2_frmivalenum *fival) |
1628 | { |
1629 | struct vivid_dev *dev = video_drvdata(file); |
1630 | const struct vivid_fmt *fmt; |
1631 | int i; |
1632 | |
1633 | fmt = vivid_get_format(dev, pixelformat: fival->pixel_format); |
1634 | if (!fmt) |
1635 | return -EINVAL; |
1636 | |
1637 | if (!vivid_is_webcam(dev)) { |
1638 | if (fival->index) |
1639 | return -EINVAL; |
1640 | if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM) |
1641 | return -EINVAL; |
1642 | if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM) |
1643 | return -EINVAL; |
1644 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; |
1645 | fival->discrete = dev->timeperframe_vid_cap; |
1646 | return 0; |
1647 | } |
1648 | |
1649 | for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) |
1650 | if (fival->width == webcam_sizes[i].width && |
1651 | fival->height == webcam_sizes[i].height) |
1652 | break; |
1653 | if (i == ARRAY_SIZE(webcam_sizes)) |
1654 | return -EINVAL; |
1655 | if (fival->index >= webcam_ival_count(dev, frmsize_idx: i)) |
1656 | return -EINVAL; |
1657 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; |
1658 | fival->discrete = webcam_intervals[fival->index]; |
1659 | return 0; |
1660 | } |
1661 | |
1662 | int vivid_vid_cap_g_parm(struct file *file, void *priv, |
1663 | struct v4l2_streamparm *parm) |
1664 | { |
1665 | struct vivid_dev *dev = video_drvdata(file); |
1666 | |
1667 | if (parm->type != (dev->multiplanar ? |
1668 | V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : |
1669 | V4L2_BUF_TYPE_VIDEO_CAPTURE)) |
1670 | return -EINVAL; |
1671 | |
1672 | parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; |
1673 | parm->parm.capture.timeperframe = dev->timeperframe_vid_cap; |
1674 | parm->parm.capture.readbuffers = 1; |
1675 | return 0; |
1676 | } |
1677 | |
1678 | int vivid_vid_cap_s_parm(struct file *file, void *priv, |
1679 | struct v4l2_streamparm *parm) |
1680 | { |
1681 | struct vivid_dev *dev = video_drvdata(file); |
1682 | unsigned int ival_sz = webcam_ival_count(dev, frmsize_idx: dev->webcam_size_idx); |
1683 | struct v4l2_fract tpf; |
1684 | unsigned i; |
1685 | |
1686 | if (parm->type != (dev->multiplanar ? |
1687 | V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : |
1688 | V4L2_BUF_TYPE_VIDEO_CAPTURE)) |
1689 | return -EINVAL; |
1690 | if (!vivid_is_webcam(dev)) |
1691 | return vivid_vid_cap_g_parm(file, priv, parm); |
1692 | |
1693 | tpf = parm->parm.capture.timeperframe; |
1694 | |
1695 | if (tpf.denominator == 0) |
1696 | tpf = webcam_intervals[ival_sz - 1]; |
1697 | for (i = 0; i < ival_sz; i++) |
1698 | if (V4L2_FRACT_COMPARE(tpf, >=, webcam_intervals[i])) |
1699 | break; |
1700 | if (i == ival_sz) |
1701 | i = ival_sz - 1; |
1702 | dev->webcam_ival_idx = i; |
1703 | tpf = webcam_intervals[dev->webcam_ival_idx]; |
1704 | |
1705 | /* resync the thread's timings */ |
1706 | dev->cap_seq_resync = true; |
1707 | dev->timeperframe_vid_cap = tpf; |
1708 | parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; |
1709 | parm->parm.capture.timeperframe = tpf; |
1710 | parm->parm.capture.readbuffers = 1; |
1711 | return 0; |
1712 | } |
1713 | |