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