/*
* vivid-vid-out.c - video output support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/videodev2.h>
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/v4l2-dv-timings.h>
#include "vivid-core.h"
#include "vivid-vid-common.h"
#include "vivid-kthread-out.h"
#include "vivid-vid-out.h"
static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned *nbuffers, unsigned *nplanes,
unsigned sizes[], void *alloc_ctxs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
const struct vivid_fmt *vfmt = dev->fmt_out;
unsigned planes = vfmt->buffers;
unsigned h = dev->fmt_out_rect.height;
unsigned size = dev->bytesperline_out[0] * h;
unsigned p;
for (p = vfmt->buffers; p < vfmt->planes; p++)
size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p];
if (dev->field_out == V4L2_FIELD_ALTERNATE) {
/*
* You cannot use write() with FIELD_ALTERNATE since the field
* information (TOP/BOTTOM) cannot be passed to the kernel.
*/
if (vb2_fileio_is_active(vq))
return -EINVAL;
}
if (dev->queue_setup_error) {
/*
* Error injection: test what happens if queue_setup() returns
* an error.
*/
dev->queue_setup_error = false;
return -EINVAL;
}
if (fmt) {
const struct v4l2_pix_format_mplane *mp;
struct v4l2_format mp_fmt;
if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
fmt_sp2mp(fmt, &mp_fmt);
fmt = &mp_fmt;
}
mp = &fmt->fmt.pix_mp;
/*
* Check if the number of planes in the specified format match
* the number of planes in the current format. You can't mix that.
*/
if (mp->num_planes != planes)
return -EINVAL;
sizes[0] = mp->plane_fmt[0].sizeimage;
if (sizes[0] < size)
return -EINVAL;
for (p = 1; p < planes; p++) {
sizes[p] = mp->plane_fmt[p].sizeimage;
if (sizes[p] < dev->bytesperline_out[p] * h)
return -EINVAL;
}
} else {
for (p = 0; p < planes; p++)
sizes[p] = p ? dev->bytesperline_out[p] * h : size;
}