Commit | Line | Data |
---|---|---|
ef834f78 HV |
1 | /* |
2 | * vivid-vid-out.c - video output support functions. | |
3 | * | |
4 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | |
5 | * | |
6 | * This program is free software; you may redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; version 2 of the License. | |
9 | * | |
10 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
12 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
13 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
14 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
15 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
16 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
17 | * SOFTWARE. | |
18 | */ | |
19 | ||
20 | #include <linux/errno.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/sched.h> | |
23 | #include <linux/videodev2.h> | |
24 | #include <linux/v4l2-dv-timings.h> | |
25 | #include <media/v4l2-common.h> | |
26 | #include <media/v4l2-event.h> | |
27 | #include <media/v4l2-dv-timings.h> | |
28 | ||
29 | #include "vivid-core.h" | |
30 | #include "vivid-vid-common.h" | |
31 | #include "vivid-kthread-out.h" | |
32 | #include "vivid-vid-out.h" | |
33 | ||
33119e80 | 34 | static int vid_out_queue_setup(struct vb2_queue *vq, const void *parg, |
ef834f78 HV |
35 | unsigned *nbuffers, unsigned *nplanes, |
36 | unsigned sizes[], void *alloc_ctxs[]) | |
37 | { | |
33119e80 | 38 | const struct v4l2_format *fmt = parg; |
ef834f78 | 39 | struct vivid_dev *dev = vb2_get_drv_priv(vq); |
ddcaee9d HV |
40 | const struct vivid_fmt *vfmt = dev->fmt_out; |
41 | unsigned planes = vfmt->buffers; | |
ef834f78 HV |
42 | unsigned h = dev->fmt_out_rect.height; |
43 | unsigned size = dev->bytesperline_out[0] * h; | |
ddcaee9d HV |
44 | unsigned p; |
45 | ||
46 | for (p = vfmt->buffers; p < vfmt->planes; p++) | |
1f9f23f6 | 47 | size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; |
ef834f78 HV |
48 | |
49 | if (dev->field_out == V4L2_FIELD_ALTERNATE) { | |
50 | /* | |
51 | * You cannot use write() with FIELD_ALTERNATE since the field | |
52 | * information (TOP/BOTTOM) cannot be passed to the kernel. | |
53 | */ | |
54 | if (vb2_fileio_is_active(vq)) | |
55 | return -EINVAL; | |
56 | } | |
57 | ||
58 | if (dev->queue_setup_error) { | |
59 | /* | |
60 | * Error injection: test what happens if queue_setup() returns | |
61 | * an error. | |
62 | */ | |
63 | dev->queue_setup_error = false; | |
64 | return -EINVAL; | |
65 | } | |
66 | ||
67 | if (fmt) { | |
68 | const struct v4l2_pix_format_mplane *mp; | |
69 | struct v4l2_format mp_fmt; | |
70 | ||
71 | if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { | |
72 | fmt_sp2mp(fmt, &mp_fmt); | |
73 | fmt = &mp_fmt; | |
74 | } | |
75 | mp = &fmt->fmt.pix_mp; | |
76 | /* | |
77 | * Check if the number of planes in the specified format match | |
78 | * the number of planes in the current format. You can't mix that. | |
79 | */ | |
80 | if (mp->num_planes != planes) | |
81 | return -EINVAL; | |
82 | sizes[0] = mp->plane_fmt[0].sizeimage; | |
ddcaee9d | 83 | if (sizes[0] < size) |
ef834f78 | 84 | return -EINVAL; |
ddcaee9d HV |
85 | for (p = 1; p < planes; p++) { |
86 | sizes[p] = mp->plane_fmt[p].sizeimage; | |
87 | if (sizes[p] < dev->bytesperline_out[p] * h) | |
88 | return -EINVAL; | |
ef834f78 HV |
89 | } |
90 | } else { | |
ddcaee9d HV |
91 | for (p = 0; p < planes; p++) |
92 | sizes[p] = p ? dev->bytesperline_out[p] * h : size; | |
ef834f78 HV |
93 | } |
94 | ||
95 | if (vq->num_buffers + *nbuffers < 2) | |
96 | *nbuffers = 2 - vq->num_buffers; | |
97 | ||
98 | *nplanes = planes; | |
99 | ||
100 | /* | |
101 | * videobuf2-vmalloc allocator is context-less so no need to set | |
102 | * alloc_ctxs array. | |
103 | */ | |
104 | ||
ddcaee9d HV |
105 | dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); |
106 | for (p = 0; p < planes; p++) | |
107 | dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); | |
ef834f78 HV |
108 | return 0; |
109 | } | |
110 | ||
111 | static int vid_out_buf_prepare(struct vb2_buffer *vb) | |
112 | { | |
2d700715 | 113 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
ef834f78 HV |
114 | struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); |
115 | unsigned long size; | |
4eaa3a6c | 116 | unsigned planes; |
ef834f78 HV |
117 | unsigned p; |
118 | ||
119 | dprintk(dev, 1, "%s\n", __func__); | |
120 | ||
121 | if (WARN_ON(NULL == dev->fmt_out)) | |
122 | return -EINVAL; | |
123 | ||
4eaa3a6c TP |
124 | planes = dev->fmt_out->planes; |
125 | ||
ef834f78 HV |
126 | if (dev->buf_prepare_error) { |
127 | /* | |
128 | * Error injection: test what happens if buf_prepare() returns | |
129 | * an error. | |
130 | */ | |
131 | dev->buf_prepare_error = false; | |
132 | return -EINVAL; | |
133 | } | |
134 | ||
135 | if (dev->field_out != V4L2_FIELD_ALTERNATE) | |
2d700715 JS |
136 | vbuf->field = dev->field_out; |
137 | else if (vbuf->field != V4L2_FIELD_TOP && | |
138 | vbuf->field != V4L2_FIELD_BOTTOM) | |
ef834f78 HV |
139 | return -EINVAL; |
140 | ||
141 | for (p = 0; p < planes; p++) { | |
142 | size = dev->bytesperline_out[p] * dev->fmt_out_rect.height + | |
2d700715 | 143 | vb->planes[p].data_offset; |
ef834f78 HV |
144 | |
145 | if (vb2_get_plane_payload(vb, p) < size) { | |
146 | dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %lu)\n", | |
147 | __func__, p, vb2_get_plane_payload(vb, p), size); | |
148 | return -EINVAL; | |
149 | } | |
150 | } | |
151 | ||
152 | return 0; | |
153 | } | |
154 | ||
155 | static void vid_out_buf_queue(struct vb2_buffer *vb) | |
156 | { | |
2d700715 | 157 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
ef834f78 | 158 | struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); |
2d700715 | 159 | struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); |
ef834f78 HV |
160 | |
161 | dprintk(dev, 1, "%s\n", __func__); | |
162 | ||
163 | spin_lock(&dev->slock); | |
164 | list_add_tail(&buf->list, &dev->vid_out_active); | |
165 | spin_unlock(&dev->slock); | |
166 | } | |
167 | ||
168 | static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count) | |
169 | { | |
170 | struct vivid_dev *dev = vb2_get_drv_priv(vq); | |
171 | int err; | |
172 | ||
173 | if (vb2_is_streaming(&dev->vb_vid_cap_q)) | |
174 | dev->can_loop_video = vivid_vid_can_loop(dev); | |
175 | ||
176 | if (dev->kthread_vid_out) | |
177 | return 0; | |
178 | ||
179 | dev->vid_out_seq_count = 0; | |
180 | dprintk(dev, 1, "%s\n", __func__); | |
181 | if (dev->start_streaming_error) { | |
182 | dev->start_streaming_error = false; | |
183 | err = -EINVAL; | |
184 | } else { | |
185 | err = vivid_start_generating_vid_out(dev, &dev->vid_out_streaming); | |
186 | } | |
187 | if (err) { | |
188 | struct vivid_buffer *buf, *tmp; | |
189 | ||
190 | list_for_each_entry_safe(buf, tmp, &dev->vid_out_active, list) { | |
191 | list_del(&buf->list); | |
2d700715 JS |
192 | vb2_buffer_done(&buf->vb.vb2_buf, |
193 | VB2_BUF_STATE_QUEUED); | |
ef834f78 HV |
194 | } |
195 | } | |
196 | return err; | |
197 | } | |
198 | ||
199 | /* abort streaming and wait for last buffer */ | |
200 | static void vid_out_stop_streaming(struct vb2_queue *vq) | |
201 | { | |
202 | struct vivid_dev *dev = vb2_get_drv_priv(vq); | |
203 | ||
204 | dprintk(dev, 1, "%s\n", __func__); | |
205 | vivid_stop_generating_vid_out(dev, &dev->vid_out_streaming); | |
206 | dev->can_loop_video = false; | |
207 | } | |
208 | ||
209 | const struct vb2_ops vivid_vid_out_qops = { | |
210 | .queue_setup = vid_out_queue_setup, | |
211 | .buf_prepare = vid_out_buf_prepare, | |
212 | .buf_queue = vid_out_buf_queue, | |
213 | .start_streaming = vid_out_start_streaming, | |
214 | .stop_streaming = vid_out_stop_streaming, | |
6dfa5131 PL |
215 | .wait_prepare = vb2_ops_wait_prepare, |
216 | .wait_finish = vb2_ops_wait_finish, | |
ef834f78 HV |
217 | }; |
218 | ||
219 | /* | |
220 | * Called whenever the format has to be reset which can occur when | |
221 | * changing outputs, standard, timings, etc. | |
222 | */ | |
223 | void vivid_update_format_out(struct vivid_dev *dev) | |
224 | { | |
225 | struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; | |
ddcaee9d | 226 | unsigned size, p; |
b883ba75 | 227 | u64 pixelclock; |
ef834f78 HV |
228 | |
229 | switch (dev->output_type[dev->output]) { | |
230 | case SVID: | |
231 | default: | |
232 | dev->field_out = dev->tv_field_out; | |
233 | dev->sink_rect.width = 720; | |
234 | if (dev->std_out & V4L2_STD_525_60) { | |
235 | dev->sink_rect.height = 480; | |
236 | dev->timeperframe_vid_out = (struct v4l2_fract) { 1001, 30000 }; | |
237 | dev->service_set_out = V4L2_SLICED_CAPTION_525; | |
238 | } else { | |
239 | dev->sink_rect.height = 576; | |
240 | dev->timeperframe_vid_out = (struct v4l2_fract) { 1000, 25000 }; | |
62f28725 | 241 | dev->service_set_out = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; |
ef834f78 HV |
242 | } |
243 | dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; | |
244 | break; | |
245 | case HDMI: | |
246 | dev->sink_rect.width = bt->width; | |
247 | dev->sink_rect.height = bt->height; | |
248 | size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); | |
b883ba75 PL |
249 | |
250 | if (can_reduce_fps(bt) && (bt->flags & V4L2_DV_FL_REDUCED_FPS)) | |
251 | pixelclock = div_u64(bt->pixelclock * 1000, 1001); | |
252 | else | |
253 | pixelclock = bt->pixelclock; | |
254 | ||
ef834f78 | 255 | dev->timeperframe_vid_out = (struct v4l2_fract) { |
b883ba75 | 256 | size / 100, (u32)pixelclock / 100 |
ef834f78 HV |
257 | }; |
258 | if (bt->interlaced) | |
259 | dev->field_out = V4L2_FIELD_ALTERNATE; | |
260 | else | |
261 | dev->field_out = V4L2_FIELD_NONE; | |
4a203349 | 262 | if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { |
ef834f78 HV |
263 | if (bt->width == 720 && bt->height <= 576) |
264 | dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; | |
265 | else | |
266 | dev->colorspace_out = V4L2_COLORSPACE_REC709; | |
267 | } else { | |
268 | dev->colorspace_out = V4L2_COLORSPACE_SRGB; | |
269 | } | |
270 | break; | |
271 | } | |
ca5316db | 272 | dev->xfer_func_out = V4L2_XFER_FUNC_DEFAULT; |
3e8a78d1 HV |
273 | dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT; |
274 | dev->quantization_out = V4L2_QUANTIZATION_DEFAULT; | |
ef834f78 HV |
275 | dev->compose_out = dev->sink_rect; |
276 | dev->compose_bounds_out = dev->sink_rect; | |
277 | dev->crop_out = dev->compose_out; | |
278 | if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) | |
279 | dev->crop_out.height /= 2; | |
280 | dev->fmt_out_rect = dev->crop_out; | |
ddcaee9d HV |
281 | for (p = 0; p < dev->fmt_out->planes; p++) |
282 | dev->bytesperline_out[p] = | |
283 | (dev->sink_rect.width * dev->fmt_out->bit_depth[p]) / 8; | |
ef834f78 HV |
284 | } |
285 | ||
286 | /* Map the field to something that is valid for the current output */ | |
287 | static enum v4l2_field vivid_field_out(struct vivid_dev *dev, enum v4l2_field field) | |
288 | { | |
289 | if (vivid_is_svid_out(dev)) { | |
290 | switch (field) { | |
291 | case V4L2_FIELD_INTERLACED_TB: | |
292 | case V4L2_FIELD_INTERLACED_BT: | |
293 | case V4L2_FIELD_SEQ_TB: | |
294 | case V4L2_FIELD_SEQ_BT: | |
295 | case V4L2_FIELD_ALTERNATE: | |
296 | return field; | |
297 | case V4L2_FIELD_INTERLACED: | |
298 | default: | |
299 | return V4L2_FIELD_INTERLACED; | |
300 | } | |
301 | } | |
302 | if (vivid_is_hdmi_out(dev)) | |
303 | return dev->dv_timings_out.bt.interlaced ? V4L2_FIELD_ALTERNATE : | |
304 | V4L2_FIELD_NONE; | |
305 | return V4L2_FIELD_NONE; | |
306 | } | |
307 | ||
308 | static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) | |
309 | { | |
310 | if (vivid_is_svid_out(dev)) | |
311 | return (dev->std_out & V4L2_STD_525_60) ? | |
312 | TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; | |
313 | ||
314 | if (vivid_is_hdmi_out(dev) && | |
315 | dev->sink_rect.width == 720 && dev->sink_rect.height <= 576) | |
316 | return dev->sink_rect.height == 480 ? | |
317 | TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; | |
318 | ||
319 | return TPG_PIXEL_ASPECT_SQUARE; | |
320 | } | |
321 | ||
322 | int vivid_g_fmt_vid_out(struct file *file, void *priv, | |
323 | struct v4l2_format *f) | |
324 | { | |
325 | struct vivid_dev *dev = video_drvdata(file); | |
326 | struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; | |
ddcaee9d | 327 | const struct vivid_fmt *fmt = dev->fmt_out; |
ef834f78 HV |
328 | unsigned p; |
329 | ||
330 | mp->width = dev->fmt_out_rect.width; | |
331 | mp->height = dev->fmt_out_rect.height; | |
332 | mp->field = dev->field_out; | |
ddcaee9d | 333 | mp->pixelformat = fmt->fourcc; |
ef834f78 | 334 | mp->colorspace = dev->colorspace_out; |
ca5316db | 335 | mp->xfer_func = dev->xfer_func_out; |
3e8a78d1 HV |
336 | mp->ycbcr_enc = dev->ycbcr_enc_out; |
337 | mp->quantization = dev->quantization_out; | |
ddcaee9d | 338 | mp->num_planes = fmt->buffers; |
ef834f78 HV |
339 | for (p = 0; p < mp->num_planes; p++) { |
340 | mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; | |
341 | mp->plane_fmt[p].sizeimage = | |
342 | mp->plane_fmt[p].bytesperline * mp->height; | |
343 | } | |
ddcaee9d HV |
344 | for (p = fmt->buffers; p < fmt->planes; p++) { |
345 | unsigned stride = dev->bytesperline_out[p]; | |
346 | ||
1f9f23f6 HV |
347 | mp->plane_fmt[0].sizeimage += |
348 | (stride * mp->height) / fmt->vdownsampling[p]; | |
ddcaee9d | 349 | } |
ef834f78 HV |
350 | return 0; |
351 | } | |
352 | ||
353 | int vivid_try_fmt_vid_out(struct file *file, void *priv, | |
354 | struct v4l2_format *f) | |
355 | { | |
356 | struct vivid_dev *dev = video_drvdata(file); | |
357 | struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; | |
358 | struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; | |
359 | struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; | |
360 | const struct vivid_fmt *fmt; | |
361 | unsigned bytesperline, max_bpl; | |
362 | unsigned factor = 1; | |
363 | unsigned w, h; | |
364 | unsigned p; | |
365 | ||
1fc78bc9 | 366 | fmt = vivid_get_format(dev, mp->pixelformat); |
ef834f78 HV |
367 | if (!fmt) { |
368 | dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", | |
369 | mp->pixelformat); | |
370 | mp->pixelformat = V4L2_PIX_FMT_YUYV; | |
1fc78bc9 | 371 | fmt = vivid_get_format(dev, mp->pixelformat); |
ef834f78 HV |
372 | } |
373 | ||
374 | mp->field = vivid_field_out(dev, mp->field); | |
375 | if (vivid_is_svid_out(dev)) { | |
376 | w = 720; | |
377 | h = (dev->std_out & V4L2_STD_525_60) ? 480 : 576; | |
378 | } else { | |
379 | w = dev->sink_rect.width; | |
380 | h = dev->sink_rect.height; | |
381 | } | |
382 | if (V4L2_FIELD_HAS_T_OR_B(mp->field)) | |
383 | factor = 2; | |
384 | if (!dev->has_scaler_out && !dev->has_crop_out && !dev->has_compose_out) { | |
385 | mp->width = w; | |
386 | mp->height = h / factor; | |
387 | } else { | |
388 | struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; | |
389 | ||
390 | rect_set_min_size(&r, &vivid_min_rect); | |
391 | rect_set_max_size(&r, &vivid_max_rect); | |
392 | if (dev->has_scaler_out && !dev->has_crop_out) { | |
393 | struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; | |
394 | ||
395 | rect_set_max_size(&r, &max_r); | |
396 | } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) { | |
397 | rect_set_max_size(&r, &dev->sink_rect); | |
398 | } else if (!dev->has_scaler_out && !dev->has_compose_out) { | |
399 | rect_set_min_size(&r, &dev->sink_rect); | |
400 | } | |
401 | mp->width = r.width; | |
402 | mp->height = r.height / factor; | |
403 | } | |
404 | ||
405 | /* This driver supports custom bytesperline values */ | |
406 | ||
407 | /* Calculate the minimum supported bytesperline value */ | |
96c76efa | 408 | bytesperline = (mp->width * fmt->bit_depth[0]) >> 3; |
ef834f78 | 409 | /* Calculate the maximum supported bytesperline value */ |
96c76efa | 410 | max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3; |
ddcaee9d | 411 | mp->num_planes = fmt->buffers; |
ef834f78 HV |
412 | for (p = 0; p < mp->num_planes; p++) { |
413 | if (pfmt[p].bytesperline > max_bpl) | |
414 | pfmt[p].bytesperline = max_bpl; | |
415 | if (pfmt[p].bytesperline < bytesperline) | |
416 | pfmt[p].bytesperline = bytesperline; | |
417 | pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height; | |
418 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); | |
419 | } | |
ddcaee9d HV |
420 | for (p = fmt->buffers; p < fmt->planes; p++) |
421 | pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) / | |
1f9f23f6 | 422 | (fmt->bit_depth[0] * fmt->vdownsampling[p]); |
ca5316db | 423 | mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; |
3e8a78d1 HV |
424 | mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
425 | mp->quantization = V4L2_QUANTIZATION_DEFAULT; | |
426 | if (vivid_is_svid_out(dev)) { | |
ef834f78 | 427 | mp->colorspace = V4L2_COLORSPACE_SMPTE170M; |
4a203349 | 428 | } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { |
ef834f78 | 429 | mp->colorspace = V4L2_COLORSPACE_SRGB; |
3e8a78d1 HV |
430 | if (dev->dvi_d_out) |
431 | mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; | |
432 | } else if (bt->width == 720 && bt->height <= 576) { | |
ef834f78 | 433 | mp->colorspace = V4L2_COLORSPACE_SMPTE170M; |
3e8a78d1 HV |
434 | } else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M && |
435 | mp->colorspace != V4L2_COLORSPACE_REC709 && | |
436 | mp->colorspace != V4L2_COLORSPACE_ADOBERGB && | |
437 | mp->colorspace != V4L2_COLORSPACE_BT2020 && | |
438 | mp->colorspace != V4L2_COLORSPACE_SRGB) { | |
ef834f78 | 439 | mp->colorspace = V4L2_COLORSPACE_REC709; |
3e8a78d1 | 440 | } |
ef834f78 HV |
441 | memset(mp->reserved, 0, sizeof(mp->reserved)); |
442 | return 0; | |
443 | } | |
444 | ||
445 | int vivid_s_fmt_vid_out(struct file *file, void *priv, | |
446 | struct v4l2_format *f) | |
447 | { | |
448 | struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; | |
449 | struct vivid_dev *dev = video_drvdata(file); | |
450 | struct v4l2_rect *crop = &dev->crop_out; | |
451 | struct v4l2_rect *compose = &dev->compose_out; | |
452 | struct vb2_queue *q = &dev->vb_vid_out_q; | |
453 | int ret = vivid_try_fmt_vid_out(file, priv, f); | |
454 | unsigned factor = 1; | |
ddcaee9d | 455 | unsigned p; |
ef834f78 HV |
456 | |
457 | if (ret < 0) | |
458 | return ret; | |
459 | ||
460 | if (vb2_is_busy(q) && | |
461 | (vivid_is_svid_out(dev) || | |
462 | mp->width != dev->fmt_out_rect.width || | |
463 | mp->height != dev->fmt_out_rect.height || | |
464 | mp->pixelformat != dev->fmt_out->fourcc || | |
465 | mp->field != dev->field_out)) { | |
466 | dprintk(dev, 1, "%s device busy\n", __func__); | |
467 | return -EBUSY; | |
468 | } | |
469 | ||
470 | /* | |
471 | * Allow for changing the colorspace on the fly. Useful for testing | |
472 | * purposes, and it is something that HDMI transmitters are able | |
473 | * to do. | |
474 | */ | |
475 | if (vb2_is_busy(q)) | |
476 | goto set_colorspace; | |
477 | ||
1fc78bc9 | 478 | dev->fmt_out = vivid_get_format(dev, mp->pixelformat); |
ef834f78 HV |
479 | if (V4L2_FIELD_HAS_T_OR_B(mp->field)) |
480 | factor = 2; | |
481 | ||
482 | if (dev->has_scaler_out || dev->has_crop_out || dev->has_compose_out) { | |
483 | struct v4l2_rect r = { 0, 0, mp->width, mp->height }; | |
484 | ||
485 | if (dev->has_scaler_out) { | |
486 | if (dev->has_crop_out) | |
487 | rect_map_inside(crop, &r); | |
488 | else | |
489 | *crop = r; | |
490 | if (dev->has_compose_out && !dev->has_crop_out) { | |
491 | struct v4l2_rect min_r = { | |
492 | 0, 0, | |
493 | r.width / MAX_ZOOM, | |
494 | factor * r.height / MAX_ZOOM | |
495 | }; | |
496 | struct v4l2_rect max_r = { | |
497 | 0, 0, | |
498 | r.width * MAX_ZOOM, | |
499 | factor * r.height * MAX_ZOOM | |
500 | }; | |
501 | ||
502 | rect_set_min_size(compose, &min_r); | |
503 | rect_set_max_size(compose, &max_r); | |
504 | rect_map_inside(compose, &dev->compose_bounds_out); | |
505 | } else if (dev->has_compose_out) { | |
506 | struct v4l2_rect min_r = { | |
507 | 0, 0, | |
508 | crop->width / MAX_ZOOM, | |
509 | factor * crop->height / MAX_ZOOM | |
510 | }; | |
511 | struct v4l2_rect max_r = { | |
512 | 0, 0, | |
513 | crop->width * MAX_ZOOM, | |
514 | factor * crop->height * MAX_ZOOM | |
515 | }; | |
516 | ||
517 | rect_set_min_size(compose, &min_r); | |
518 | rect_set_max_size(compose, &max_r); | |
519 | rect_map_inside(compose, &dev->compose_bounds_out); | |
520 | } | |
521 | } else if (dev->has_compose_out && !dev->has_crop_out) { | |
522 | rect_set_size_to(crop, &r); | |
523 | r.height *= factor; | |
524 | rect_set_size_to(compose, &r); | |
525 | rect_map_inside(compose, &dev->compose_bounds_out); | |
526 | } else if (!dev->has_compose_out) { | |
527 | rect_map_inside(crop, &r); | |
528 | r.height /= factor; | |
529 | rect_set_size_to(compose, &r); | |
530 | } else { | |
531 | r.height *= factor; | |
532 | rect_set_max_size(compose, &r); | |
533 | rect_map_inside(compose, &dev->compose_bounds_out); | |
534 | crop->top *= factor; | |
535 | crop->height *= factor; | |
536 | rect_set_size_to(crop, compose); | |
537 | rect_map_inside(crop, &r); | |
538 | crop->top /= factor; | |
539 | crop->height /= factor; | |
540 | } | |
541 | } else { | |
542 | struct v4l2_rect r = { 0, 0, mp->width, mp->height }; | |
543 | ||
544 | rect_set_size_to(crop, &r); | |
545 | r.height /= factor; | |
546 | rect_set_size_to(compose, &r); | |
547 | } | |
548 | ||
549 | dev->fmt_out_rect.width = mp->width; | |
550 | dev->fmt_out_rect.height = mp->height; | |
ddcaee9d HV |
551 | for (p = 0; p < mp->num_planes; p++) |
552 | dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline; | |
553 | for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++) | |
554 | dev->bytesperline_out[p] = | |
555 | (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) / | |
556 | dev->fmt_out->bit_depth[0]; | |
ef834f78 HV |
557 | dev->field_out = mp->field; |
558 | if (vivid_is_svid_out(dev)) | |
559 | dev->tv_field_out = mp->field; | |
560 | ||
561 | set_colorspace: | |
562 | dev->colorspace_out = mp->colorspace; | |
ca5316db | 563 | dev->xfer_func_out = mp->xfer_func; |
3e8a78d1 HV |
564 | dev->ycbcr_enc_out = mp->ycbcr_enc; |
565 | dev->quantization_out = mp->quantization; | |
ef834f78 HV |
566 | if (dev->loop_video) { |
567 | vivid_send_source_change(dev, SVID); | |
568 | vivid_send_source_change(dev, HDMI); | |
569 | } | |
570 | return 0; | |
571 | } | |
572 | ||
573 | int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, | |
574 | struct v4l2_format *f) | |
575 | { | |
576 | struct vivid_dev *dev = video_drvdata(file); | |
577 | ||
578 | if (!dev->multiplanar) | |
579 | return -ENOTTY; | |
580 | return vivid_g_fmt_vid_out(file, priv, f); | |
581 | } | |
582 | ||
583 | int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, | |
584 | struct v4l2_format *f) | |
585 | { | |
586 | struct vivid_dev *dev = video_drvdata(file); | |
587 | ||
588 | if (!dev->multiplanar) | |
589 | return -ENOTTY; | |
590 | return vivid_try_fmt_vid_out(file, priv, f); | |
591 | } | |
592 | ||
593 | int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, | |
594 | struct v4l2_format *f) | |
595 | { | |
596 | struct vivid_dev *dev = video_drvdata(file); | |
597 | ||
598 | if (!dev->multiplanar) | |
599 | return -ENOTTY; | |
600 | return vivid_s_fmt_vid_out(file, priv, f); | |
601 | } | |
602 | ||
603 | int vidioc_g_fmt_vid_out(struct file *file, void *priv, | |
604 | struct v4l2_format *f) | |
605 | { | |
606 | struct vivid_dev *dev = video_drvdata(file); | |
607 | ||
608 | if (dev->multiplanar) | |
609 | return -ENOTTY; | |
610 | return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_out); | |
611 | } | |
612 | ||
613 | int vidioc_try_fmt_vid_out(struct file *file, void *priv, | |
614 | struct v4l2_format *f) | |
615 | { | |
616 | struct vivid_dev *dev = video_drvdata(file); | |
617 | ||
618 | if (dev->multiplanar) | |
619 | return -ENOTTY; | |
620 | return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_out); | |
621 | } | |
622 | ||
623 | int vidioc_s_fmt_vid_out(struct file *file, void *priv, | |
624 | struct v4l2_format *f) | |
625 | { | |
626 | struct vivid_dev *dev = video_drvdata(file); | |
627 | ||
628 | if (dev->multiplanar) | |
629 | return -ENOTTY; | |
630 | return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_out); | |
631 | } | |
632 | ||
633 | int vivid_vid_out_g_selection(struct file *file, void *priv, | |
634 | struct v4l2_selection *sel) | |
635 | { | |
636 | struct vivid_dev *dev = video_drvdata(file); | |
637 | ||
638 | if (!dev->has_crop_out && !dev->has_compose_out) | |
639 | return -ENOTTY; | |
640 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
641 | return -EINVAL; | |
642 | ||
643 | sel->r.left = sel->r.top = 0; | |
644 | switch (sel->target) { | |
645 | case V4L2_SEL_TGT_CROP: | |
646 | if (!dev->has_crop_out) | |
647 | return -EINVAL; | |
648 | sel->r = dev->crop_out; | |
649 | break; | |
650 | case V4L2_SEL_TGT_CROP_DEFAULT: | |
651 | if (!dev->has_crop_out) | |
652 | return -EINVAL; | |
653 | sel->r = dev->fmt_out_rect; | |
654 | break; | |
655 | case V4L2_SEL_TGT_CROP_BOUNDS: | |
bb9ff078 | 656 | if (!dev->has_crop_out) |
ef834f78 HV |
657 | return -EINVAL; |
658 | sel->r = vivid_max_rect; | |
659 | break; | |
660 | case V4L2_SEL_TGT_COMPOSE: | |
661 | if (!dev->has_compose_out) | |
662 | return -EINVAL; | |
663 | sel->r = dev->compose_out; | |
664 | break; | |
665 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | |
666 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | |
667 | if (!dev->has_compose_out) | |
668 | return -EINVAL; | |
669 | sel->r = dev->sink_rect; | |
670 | break; | |
671 | default: | |
672 | return -EINVAL; | |
673 | } | |
674 | return 0; | |
675 | } | |
676 | ||
677 | int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s) | |
678 | { | |
679 | struct vivid_dev *dev = video_drvdata(file); | |
680 | struct v4l2_rect *crop = &dev->crop_out; | |
681 | struct v4l2_rect *compose = &dev->compose_out; | |
682 | unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_out) ? 2 : 1; | |
683 | int ret; | |
684 | ||
685 | if (!dev->has_crop_out && !dev->has_compose_out) | |
686 | return -ENOTTY; | |
687 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
688 | return -EINVAL; | |
689 | ||
690 | switch (s->target) { | |
691 | case V4L2_SEL_TGT_CROP: | |
692 | if (!dev->has_crop_out) | |
693 | return -EINVAL; | |
694 | ret = vivid_vid_adjust_sel(s->flags, &s->r); | |
695 | if (ret) | |
696 | return ret; | |
697 | rect_set_min_size(&s->r, &vivid_min_rect); | |
698 | rect_set_max_size(&s->r, &dev->fmt_out_rect); | |
699 | if (dev->has_scaler_out) { | |
700 | struct v4l2_rect max_rect = { | |
701 | 0, 0, | |
702 | dev->sink_rect.width * MAX_ZOOM, | |
703 | (dev->sink_rect.height / factor) * MAX_ZOOM | |
704 | }; | |
705 | ||
706 | rect_set_max_size(&s->r, &max_rect); | |
707 | if (dev->has_compose_out) { | |
708 | struct v4l2_rect min_rect = { | |
709 | 0, 0, | |
710 | s->r.width / MAX_ZOOM, | |
711 | (s->r.height * factor) / MAX_ZOOM | |
712 | }; | |
713 | struct v4l2_rect max_rect = { | |
714 | 0, 0, | |
715 | s->r.width * MAX_ZOOM, | |
716 | (s->r.height * factor) * MAX_ZOOM | |
717 | }; | |
718 | ||
719 | rect_set_min_size(compose, &min_rect); | |
720 | rect_set_max_size(compose, &max_rect); | |
721 | rect_map_inside(compose, &dev->compose_bounds_out); | |
722 | } | |
723 | } else if (dev->has_compose_out) { | |
724 | s->r.top *= factor; | |
725 | s->r.height *= factor; | |
726 | rect_set_max_size(&s->r, &dev->sink_rect); | |
727 | rect_set_size_to(compose, &s->r); | |
728 | rect_map_inside(compose, &dev->compose_bounds_out); | |
729 | s->r.top /= factor; | |
730 | s->r.height /= factor; | |
731 | } else { | |
732 | rect_set_size_to(&s->r, &dev->sink_rect); | |
733 | s->r.height /= factor; | |
734 | } | |
735 | rect_map_inside(&s->r, &dev->fmt_out_rect); | |
736 | *crop = s->r; | |
737 | break; | |
738 | case V4L2_SEL_TGT_COMPOSE: | |
739 | if (!dev->has_compose_out) | |
740 | return -EINVAL; | |
741 | ret = vivid_vid_adjust_sel(s->flags, &s->r); | |
742 | if (ret) | |
743 | return ret; | |
744 | rect_set_min_size(&s->r, &vivid_min_rect); | |
745 | rect_set_max_size(&s->r, &dev->sink_rect); | |
746 | rect_map_inside(&s->r, &dev->compose_bounds_out); | |
747 | s->r.top /= factor; | |
748 | s->r.height /= factor; | |
749 | if (dev->has_scaler_out) { | |
750 | struct v4l2_rect fmt = dev->fmt_out_rect; | |
751 | struct v4l2_rect max_rect = { | |
752 | 0, 0, | |
753 | s->r.width * MAX_ZOOM, | |
754 | s->r.height * MAX_ZOOM | |
755 | }; | |
756 | struct v4l2_rect min_rect = { | |
757 | 0, 0, | |
758 | s->r.width / MAX_ZOOM, | |
759 | s->r.height / MAX_ZOOM | |
760 | }; | |
761 | ||
762 | rect_set_min_size(&fmt, &min_rect); | |
763 | if (!dev->has_crop_out) | |
764 | rect_set_max_size(&fmt, &max_rect); | |
765 | if (!rect_same_size(&dev->fmt_out_rect, &fmt) && | |
766 | vb2_is_busy(&dev->vb_vid_out_q)) | |
767 | return -EBUSY; | |
768 | if (dev->has_crop_out) { | |
769 | rect_set_min_size(crop, &min_rect); | |
770 | rect_set_max_size(crop, &max_rect); | |
771 | } | |
772 | dev->fmt_out_rect = fmt; | |
773 | } else if (dev->has_crop_out) { | |
774 | struct v4l2_rect fmt = dev->fmt_out_rect; | |
775 | ||
776 | rect_set_min_size(&fmt, &s->r); | |
777 | if (!rect_same_size(&dev->fmt_out_rect, &fmt) && | |
778 | vb2_is_busy(&dev->vb_vid_out_q)) | |
779 | return -EBUSY; | |
780 | dev->fmt_out_rect = fmt; | |
781 | rect_set_size_to(crop, &s->r); | |
782 | rect_map_inside(crop, &dev->fmt_out_rect); | |
783 | } else { | |
784 | if (!rect_same_size(&s->r, &dev->fmt_out_rect) && | |
785 | vb2_is_busy(&dev->vb_vid_out_q)) | |
786 | return -EBUSY; | |
787 | rect_set_size_to(&dev->fmt_out_rect, &s->r); | |
788 | rect_set_size_to(crop, &s->r); | |
789 | crop->height /= factor; | |
790 | rect_map_inside(crop, &dev->fmt_out_rect); | |
791 | } | |
792 | s->r.top *= factor; | |
793 | s->r.height *= factor; | |
794 | if (dev->bitmap_out && (compose->width != s->r.width || | |
795 | compose->height != s->r.height)) { | |
796 | kfree(dev->bitmap_out); | |
797 | dev->bitmap_out = NULL; | |
798 | } | |
799 | *compose = s->r; | |
800 | break; | |
801 | default: | |
802 | return -EINVAL; | |
803 | } | |
804 | ||
805 | return 0; | |
806 | } | |
807 | ||
808 | int vivid_vid_out_cropcap(struct file *file, void *priv, | |
809 | struct v4l2_cropcap *cap) | |
810 | { | |
811 | struct vivid_dev *dev = video_drvdata(file); | |
812 | ||
813 | if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
814 | return -EINVAL; | |
815 | ||
816 | switch (vivid_get_pixel_aspect(dev)) { | |
817 | case TPG_PIXEL_ASPECT_NTSC: | |
818 | cap->pixelaspect.numerator = 11; | |
819 | cap->pixelaspect.denominator = 10; | |
820 | break; | |
821 | case TPG_PIXEL_ASPECT_PAL: | |
822 | cap->pixelaspect.numerator = 54; | |
823 | cap->pixelaspect.denominator = 59; | |
824 | break; | |
825 | case TPG_PIXEL_ASPECT_SQUARE: | |
826 | cap->pixelaspect.numerator = 1; | |
827 | cap->pixelaspect.denominator = 1; | |
828 | break; | |
829 | } | |
830 | return 0; | |
831 | } | |
832 | ||
833 | int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, | |
834 | struct v4l2_format *f) | |
835 | { | |
836 | struct vivid_dev *dev = video_drvdata(file); | |
837 | const struct v4l2_rect *compose = &dev->compose_out; | |
838 | struct v4l2_window *win = &f->fmt.win; | |
839 | unsigned clipcount = win->clipcount; | |
840 | ||
841 | if (!dev->has_fb) | |
842 | return -EINVAL; | |
843 | win->w.top = dev->overlay_out_top; | |
844 | win->w.left = dev->overlay_out_left; | |
845 | win->w.width = compose->width; | |
846 | win->w.height = compose->height; | |
847 | win->clipcount = dev->clipcount_out; | |
848 | win->field = V4L2_FIELD_ANY; | |
849 | win->chromakey = dev->chromakey_out; | |
850 | win->global_alpha = dev->global_alpha_out; | |
851 | if (clipcount > dev->clipcount_out) | |
852 | clipcount = dev->clipcount_out; | |
853 | if (dev->bitmap_out == NULL) | |
854 | win->bitmap = NULL; | |
855 | else if (win->bitmap) { | |
856 | if (copy_to_user(win->bitmap, dev->bitmap_out, | |
857 | ((dev->compose_out.width + 7) / 8) * dev->compose_out.height)) | |
858 | return -EFAULT; | |
859 | } | |
860 | if (clipcount && win->clips) { | |
861 | if (copy_to_user(win->clips, dev->clips_out, | |
862 | clipcount * sizeof(dev->clips_out[0]))) | |
863 | return -EFAULT; | |
864 | } | |
865 | return 0; | |
866 | } | |
867 | ||
868 | int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, | |
869 | struct v4l2_format *f) | |
870 | { | |
871 | struct vivid_dev *dev = video_drvdata(file); | |
872 | const struct v4l2_rect *compose = &dev->compose_out; | |
873 | struct v4l2_window *win = &f->fmt.win; | |
874 | int i, j; | |
875 | ||
876 | if (!dev->has_fb) | |
877 | return -EINVAL; | |
878 | win->w.left = clamp_t(int, win->w.left, | |
879 | -dev->display_width, dev->display_width); | |
880 | win->w.top = clamp_t(int, win->w.top, | |
881 | -dev->display_height, dev->display_height); | |
882 | win->w.width = compose->width; | |
883 | win->w.height = compose->height; | |
884 | /* | |
885 | * It makes no sense for an OSD to overlay only top or bottom fields, | |
886 | * so always set this to ANY. | |
887 | */ | |
888 | win->field = V4L2_FIELD_ANY; | |
889 | if (win->clipcount && !win->clips) | |
890 | win->clipcount = 0; | |
891 | if (win->clipcount > MAX_CLIPS) | |
892 | win->clipcount = MAX_CLIPS; | |
893 | if (win->clipcount) { | |
894 | if (copy_from_user(dev->try_clips_out, win->clips, | |
895 | win->clipcount * sizeof(dev->clips_out[0]))) | |
896 | return -EFAULT; | |
897 | for (i = 0; i < win->clipcount; i++) { | |
898 | struct v4l2_rect *r = &dev->try_clips_out[i].c; | |
899 | ||
900 | r->top = clamp_t(s32, r->top, 0, dev->display_height - 1); | |
901 | r->height = clamp_t(s32, r->height, 1, dev->display_height - r->top); | |
902 | r->left = clamp_t(u32, r->left, 0, dev->display_width - 1); | |
903 | r->width = clamp_t(u32, r->width, 1, dev->display_width - r->left); | |
904 | } | |
905 | /* | |
906 | * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small | |
907 | * number and it's typically a one-time deal. | |
908 | */ | |
909 | for (i = 0; i < win->clipcount - 1; i++) { | |
910 | struct v4l2_rect *r1 = &dev->try_clips_out[i].c; | |
911 | ||
912 | for (j = i + 1; j < win->clipcount; j++) { | |
913 | struct v4l2_rect *r2 = &dev->try_clips_out[j].c; | |
914 | ||
915 | if (rect_overlap(r1, r2)) | |
916 | return -EINVAL; | |
917 | } | |
918 | } | |
919 | if (copy_to_user(win->clips, dev->try_clips_out, | |
920 | win->clipcount * sizeof(dev->clips_out[0]))) | |
921 | return -EFAULT; | |
922 | } | |
923 | return 0; | |
924 | } | |
925 | ||
926 | int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, | |
927 | struct v4l2_format *f) | |
928 | { | |
929 | struct vivid_dev *dev = video_drvdata(file); | |
930 | const struct v4l2_rect *compose = &dev->compose_out; | |
931 | struct v4l2_window *win = &f->fmt.win; | |
932 | int ret = vidioc_try_fmt_vid_out_overlay(file, priv, f); | |
933 | unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height; | |
934 | unsigned clips_size = win->clipcount * sizeof(dev->clips_out[0]); | |
935 | void *new_bitmap = NULL; | |
936 | ||
937 | if (ret) | |
938 | return ret; | |
939 | ||
940 | if (win->bitmap) { | |
02829691 | 941 | new_bitmap = memdup_user(win->bitmap, bitmap_size); |
ef834f78 | 942 | |
02829691 MCC |
943 | if (IS_ERR(new_bitmap)) |
944 | return PTR_ERR(new_bitmap); | |
ef834f78 HV |
945 | } |
946 | ||
947 | dev->overlay_out_top = win->w.top; | |
948 | dev->overlay_out_left = win->w.left; | |
949 | kfree(dev->bitmap_out); | |
950 | dev->bitmap_out = new_bitmap; | |
951 | dev->clipcount_out = win->clipcount; | |
952 | if (dev->clipcount_out) | |
953 | memcpy(dev->clips_out, dev->try_clips_out, clips_size); | |
954 | dev->chromakey_out = win->chromakey; | |
955 | dev->global_alpha_out = win->global_alpha; | |
956 | return ret; | |
957 | } | |
958 | ||
959 | int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i) | |
960 | { | |
961 | struct vivid_dev *dev = video_drvdata(file); | |
962 | ||
963 | if (i && !dev->fmt_out->can_do_overlay) { | |
964 | dprintk(dev, 1, "unsupported output format for output overlay\n"); | |
965 | return -EINVAL; | |
966 | } | |
967 | ||
968 | dev->overlay_out_enabled = i; | |
969 | return 0; | |
970 | } | |
971 | ||
972 | int vivid_vid_out_g_fbuf(struct file *file, void *fh, | |
973 | struct v4l2_framebuffer *a) | |
974 | { | |
975 | struct vivid_dev *dev = video_drvdata(file); | |
976 | ||
977 | a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | | |
978 | V4L2_FBUF_CAP_BITMAP_CLIPPING | | |
979 | V4L2_FBUF_CAP_LIST_CLIPPING | | |
980 | V4L2_FBUF_CAP_CHROMAKEY | | |
981 | V4L2_FBUF_CAP_SRC_CHROMAKEY | | |
982 | V4L2_FBUF_CAP_GLOBAL_ALPHA | | |
983 | V4L2_FBUF_CAP_LOCAL_ALPHA | | |
984 | V4L2_FBUF_CAP_LOCAL_INV_ALPHA; | |
985 | a->flags = V4L2_FBUF_FLAG_OVERLAY | dev->fbuf_out_flags; | |
986 | a->base = (void *)dev->video_pbase; | |
987 | a->fmt.width = dev->display_width; | |
988 | a->fmt.height = dev->display_height; | |
989 | if (dev->fb_defined.green.length == 5) | |
990 | a->fmt.pixelformat = V4L2_PIX_FMT_ARGB555; | |
991 | else | |
992 | a->fmt.pixelformat = V4L2_PIX_FMT_RGB565; | |
993 | a->fmt.bytesperline = dev->display_byte_stride; | |
994 | a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline; | |
995 | a->fmt.field = V4L2_FIELD_NONE; | |
996 | a->fmt.colorspace = V4L2_COLORSPACE_SRGB; | |
997 | a->fmt.priv = 0; | |
998 | return 0; | |
999 | } | |
1000 | ||
1001 | int vivid_vid_out_s_fbuf(struct file *file, void *fh, | |
1002 | const struct v4l2_framebuffer *a) | |
1003 | { | |
1004 | struct vivid_dev *dev = video_drvdata(file); | |
1005 | const unsigned chroma_flags = V4L2_FBUF_FLAG_CHROMAKEY | | |
1006 | V4L2_FBUF_FLAG_SRC_CHROMAKEY; | |
1007 | const unsigned alpha_flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA | | |
1008 | V4L2_FBUF_FLAG_LOCAL_ALPHA | | |
1009 | V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; | |
1010 | ||
1011 | ||
1012 | if ((a->flags & chroma_flags) == chroma_flags) | |
1013 | return -EINVAL; | |
1014 | switch (a->flags & alpha_flags) { | |
1015 | case 0: | |
1016 | case V4L2_FBUF_FLAG_GLOBAL_ALPHA: | |
1017 | case V4L2_FBUF_FLAG_LOCAL_ALPHA: | |
1018 | case V4L2_FBUF_FLAG_LOCAL_INV_ALPHA: | |
1019 | break; | |
1020 | default: | |
1021 | return -EINVAL; | |
1022 | } | |
1023 | dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags); | |
1024 | dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags); | |
1025 | return 0; | |
1026 | } | |
1027 | ||
1028 | static const struct v4l2_audioout vivid_audio_outputs[] = { | |
1029 | { 0, "Line-Out 1" }, | |
1030 | { 1, "Line-Out 2" }, | |
1031 | }; | |
1032 | ||
1033 | int vidioc_enum_output(struct file *file, void *priv, | |
1034 | struct v4l2_output *out) | |
1035 | { | |
1036 | struct vivid_dev *dev = video_drvdata(file); | |
1037 | ||
1038 | if (out->index >= dev->num_outputs) | |
1039 | return -EINVAL; | |
1040 | ||
1041 | out->type = V4L2_OUTPUT_TYPE_ANALOG; | |
1042 | switch (dev->output_type[out->index]) { | |
1043 | case SVID: | |
1044 | snprintf(out->name, sizeof(out->name), "S-Video %u", | |
1045 | dev->output_name_counter[out->index]); | |
1046 | out->std = V4L2_STD_ALL; | |
1047 | if (dev->has_audio_outputs) | |
1048 | out->audioset = (1 << ARRAY_SIZE(vivid_audio_outputs)) - 1; | |
1049 | out->capabilities = V4L2_OUT_CAP_STD; | |
1050 | break; | |
1051 | case HDMI: | |
1052 | snprintf(out->name, sizeof(out->name), "HDMI %u", | |
1053 | dev->output_name_counter[out->index]); | |
1054 | out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; | |
1055 | break; | |
1056 | } | |
1057 | return 0; | |
1058 | } | |
1059 | ||
1060 | int vidioc_g_output(struct file *file, void *priv, unsigned *o) | |
1061 | { | |
1062 | struct vivid_dev *dev = video_drvdata(file); | |
1063 | ||
1064 | *o = dev->output; | |
1065 | return 0; | |
1066 | } | |
1067 | ||
1068 | int vidioc_s_output(struct file *file, void *priv, unsigned o) | |
1069 | { | |
1070 | struct vivid_dev *dev = video_drvdata(file); | |
1071 | ||
1072 | if (o >= dev->num_outputs) | |
1073 | return -EINVAL; | |
1074 | ||
1075 | if (o == dev->output) | |
1076 | return 0; | |
1077 | ||
1078 | if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q)) | |
1079 | return -EBUSY; | |
1080 | ||
1081 | dev->output = o; | |
1082 | dev->tv_audio_output = 0; | |
1083 | if (dev->output_type[o] == SVID) | |
1084 | dev->vid_out_dev.tvnorms = V4L2_STD_ALL; | |
1085 | else | |
1086 | dev->vid_out_dev.tvnorms = 0; | |
1087 | ||
1088 | dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms; | |
1089 | vivid_update_format_out(dev); | |
1090 | return 0; | |
1091 | } | |
1092 | ||
1093 | int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout) | |
1094 | { | |
1095 | if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) | |
1096 | return -EINVAL; | |
1097 | *vout = vivid_audio_outputs[vout->index]; | |
1098 | return 0; | |
1099 | } | |
1100 | ||
1101 | int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout) | |
1102 | { | |
1103 | struct vivid_dev *dev = video_drvdata(file); | |
1104 | ||
1105 | if (!vivid_is_svid_out(dev)) | |
1106 | return -EINVAL; | |
1107 | *vout = vivid_audio_outputs[dev->tv_audio_output]; | |
1108 | return 0; | |
1109 | } | |
1110 | ||
1111 | int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) | |
1112 | { | |
1113 | struct vivid_dev *dev = video_drvdata(file); | |
1114 | ||
1115 | if (!vivid_is_svid_out(dev)) | |
1116 | return -EINVAL; | |
1117 | if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) | |
1118 | return -EINVAL; | |
1119 | dev->tv_audio_output = vout->index; | |
1120 | return 0; | |
1121 | } | |
1122 | ||
1123 | int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id) | |
1124 | { | |
1125 | struct vivid_dev *dev = video_drvdata(file); | |
1126 | ||
1127 | if (!vivid_is_svid_out(dev)) | |
1128 | return -ENODATA; | |
1129 | if (dev->std_out == id) | |
1130 | return 0; | |
1131 | if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q)) | |
1132 | return -EBUSY; | |
1133 | dev->std_out = id; | |
1134 | vivid_update_format_out(dev); | |
1135 | return 0; | |
1136 | } | |
1137 | ||
b1304f9b PL |
1138 | static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) |
1139 | { | |
1140 | struct v4l2_bt_timings *bt = &timings->bt; | |
1141 | ||
1142 | if ((bt->standards & (V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF)) && | |
1143 | v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap, NULL, NULL)) | |
1144 | return true; | |
1145 | ||
1146 | return false; | |
1147 | } | |
1148 | ||
ef834f78 HV |
1149 | int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, |
1150 | struct v4l2_dv_timings *timings) | |
1151 | { | |
1152 | struct vivid_dev *dev = video_drvdata(file); | |
ef834f78 HV |
1153 | if (!vivid_is_hdmi_out(dev)) |
1154 | return -ENODATA; | |
ef834f78 | 1155 | if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, |
b1304f9b PL |
1156 | 0, NULL, NULL) && |
1157 | !valid_cvt_gtf_timings(timings)) | |
ef834f78 | 1158 | return -EINVAL; |
85f9e06c | 1159 | if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0, true)) |
ef834f78 | 1160 | return 0; |
1bd0835a HV |
1161 | if (vb2_is_busy(&dev->vb_vid_out_q)) |
1162 | return -EBUSY; | |
ef834f78 HV |
1163 | dev->dv_timings_out = *timings; |
1164 | vivid_update_format_out(dev); | |
1165 | return 0; | |
1166 | } | |
1167 | ||
ef834f78 HV |
1168 | int vivid_vid_out_g_parm(struct file *file, void *priv, |
1169 | struct v4l2_streamparm *parm) | |
1170 | { | |
1171 | struct vivid_dev *dev = video_drvdata(file); | |
1172 | ||
1173 | if (parm->type != (dev->multiplanar ? | |
1174 | V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : | |
1175 | V4L2_BUF_TYPE_VIDEO_OUTPUT)) | |
1176 | return -EINVAL; | |
1177 | ||
1178 | parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | |
1179 | parm->parm.output.timeperframe = dev->timeperframe_vid_out; | |
1180 | parm->parm.output.writebuffers = 1; | |
ee120ae0 MCC |
1181 | |
1182 | return 0; | |
ef834f78 HV |
1183 | } |
1184 | ||
1185 | int vidioc_subscribe_event(struct v4l2_fh *fh, | |
1186 | const struct v4l2_event_subscription *sub) | |
1187 | { | |
1188 | switch (sub->type) { | |
1189 | case V4L2_EVENT_CTRL: | |
1190 | return v4l2_ctrl_subscribe_event(fh, sub); | |
1191 | case V4L2_EVENT_SOURCE_CHANGE: | |
1192 | if (fh->vdev->vfl_dir == VFL_DIR_RX) | |
1193 | return v4l2_src_change_event_subscribe(fh, sub); | |
1194 | break; | |
1195 | default: | |
1196 | break; | |
1197 | } | |
1198 | return -EINVAL; | |
1199 | } |