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