/** * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline * @pipe: The pipeline * @start: Start (when true) or stop (when false) the pipeline * * Walk the entities chain starting at the pipeline output video node and start * or stop all of them. * * Return: 0 if successful, or the return value of the failed video::s_stream * operation otherwise.
*/ staticint xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
{ struct xvip_dma *dma = pipe->output; struct media_entity *entity; struct media_pad *pad; struct v4l2_subdev *subdev; int ret;
entity = &dma->video.entity; while (1) {
pad = &entity->pads[0]; if (!(pad->flags & MEDIA_PAD_FL_SINK)) break;
pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break;
ret = v4l2_subdev_call(subdev, video, s_stream, start); if (start && ret < 0 && ret != -ENOIOCTLCMD) return ret;
}
return 0;
}
/** * xvip_pipeline_set_stream - Enable/disable streaming on a pipeline * @pipe: The pipeline * @on: Turn the stream on when true or off when false * * The pipeline is shared between all DMA engines connect at its input and * output. While the stream state of DMA engines can be controlled * independently, pipelines have a shared stream state that enable or disable * all entities in the pipeline. For this reason the pipeline uses a streaming * counter that tracks the number of DMA engines that have requested the stream * to be enabled. * * When called with the @on argument set to true, this function will increment * the pipeline streaming count. If the streaming count reaches the number of * DMA engines in the pipeline it will enable all entities that belong to the * pipeline. * * Similarly, when called with the @on argument set to false, this function will * decrement the pipeline streaming count and disable all entities in the * pipeline when the streaming count reaches zero. * * Return: 0 if successful, or the return value of the failed video::s_stream * operation otherwise. Stopping the pipeline never fails. The pipeline state is * not updated when the operation fails.
*/ staticint xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on)
{ int ret = 0;
mutex_lock(&pipe->lock);
if (on) { if (pipe->stream_count == pipe->num_dmas - 1) {
ret = xvip_pipeline_start_stop(pipe, true); if (ret < 0) goto done;
}
pipe->stream_count++;
} else { if (--pipe->stream_count == 0)
xvip_pipeline_start_stop(pipe, false);
}
/** * xvip_pipeline_cleanup - Cleanup the pipeline after streaming * @pipe: the pipeline * * Decrease the pipeline use count and clean it up if we were the last user.
*/ staticvoid xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
{
mutex_lock(&pipe->lock);
/* If we're the last user clean up the pipeline. */ if (--pipe->use_count == 0)
__xvip_pipeline_cleanup(pipe);
mutex_unlock(&pipe->lock);
}
/** * xvip_pipeline_prepare - Prepare the pipeline for streaming * @pipe: the pipeline * @dma: DMA engine at one end of the pipeline * * Validate the pipeline if no user exists yet, otherwise just increase the use * count. * * Return: 0 if successful or -EPIPE if the pipeline is not valid.
*/ staticint xvip_pipeline_prepare(struct xvip_pipeline *pipe, struct xvip_dma *dma)
{ int ret;
mutex_lock(&pipe->lock);
/* If we're the first user validate and initialize the pipeline. */ if (pipe->use_count == 0) {
ret = xvip_pipeline_validate(pipe, dma); if (ret < 0) {
__xvip_pipeline_cleanup(pipe); goto done;
}
}
/* * Start streaming on the pipeline. No link touching an entity in the * pipeline can be activated or deactivated once streaming is started. * * Use the pipeline object embedded in the first DMA object that starts * streaming.
*/
pipe = to_xvip_pipeline(&dma->video) ? : &dma->pipe;
ret = video_device_pipeline_start(&dma->video, &pipe->pipe); if (ret < 0) goto error;
/* Verify that the configured format matches the output of the * connected subdev.
*/
ret = xvip_dma_verify_format(dma); if (ret < 0) goto error_stop;
ret = xvip_pipeline_prepare(pipe, dma); if (ret < 0) goto error_stop;
/* Start the DMA engine. This must be done before starting the blocks * in the pipeline to avoid DMA synchronization issues.
*/
dma_async_issue_pending(dma->dma);
/* Start the pipeline. */
xvip_pipeline_set_stream(pipe, true);
/* FIXME: without this callback function, some applications are not configured * with correct formats, and it results in frames in wrong format. Whether this * callback needs to be required is not clearly defined, so it should be * clarified through the mailing list.
*/ staticint
xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{ struct v4l2_fh *vfh = file->private_data; struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
/* Retrieve format information and select the default format if the * requested format isn't supported.
*/
info = xvip_get_format_by_fourcc(pix->pixelformat);
/* The transfer alignment requirements are expressed in bytes. Compute * the minimum and maximum values, clamp the requested width and convert * it back to pixels.
*/
align = lcm(dma->align, info->bpp);
min_width = roundup(XVIP_DMA_MIN_WIDTH, align);
max_width = rounddown(XVIP_DMA_MAX_WIDTH, align);
width = rounddown(pix->width * info->bpp, align);
/* Clamp the requested bytes per line value. If the maximum bytes per * line value is zero, the module doesn't support user configurable line * sizes. Override the requested value with the minimum in that case.
*/
min_bpl = pix->width * info->bpp;
max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align);
bpl = rounddown(pix->bytesperline, dma->align);
/* ... and the buffers queue... */ /* Don't enable VB2_READ and VB2_WRITE, as using the read() and write() * V4L2 APIs would be inefficient. Testing on the command line with a * 'cat /dev/video?' thus won't be possible, but given that the driver * anyway requires a test tool to setup the pipeline before any video * stream can be started, requiring a specific V4L2 test tool as well * instead of 'cat' isn't really a drawback.
*/
dma->queue.type = type;
dma->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
dma->queue.lock = &dma->lock;
dma->queue.drv_priv = dma;
dma->queue.buf_struct_size = sizeof(struct xvip_dma_buffer);
dma->queue.ops = &xvip_dma_queue_qops;
dma->queue.mem_ops = &vb2_dma_contig_memops;
dma->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
| V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
dma->queue.dev = dma->xdev->dev;
ret = vb2_queue_init(&dma->queue); if (ret < 0) {
dev_err(dma->xdev->dev, "failed to initialize VB2 queue\n"); goto error;
}
/* ... and the DMA channel. */
snprintf(name, sizeof(name), "port%u", port);
dma->dma = dma_request_chan(dma->xdev->dev, name); if (IS_ERR(dma->dma)) {
ret = dev_err_probe(dma->xdev->dev, PTR_ERR(dma->dma), "no VDMA channel found\n"); goto error;
}
dma->align = 1 << dma->dma->device->copy_align;
ret = video_register_device(&dma->video, VFL_TYPE_VIDEO, -1); if (ret < 0) {
dev_err(dma->xdev->dev, "failed to register video device\n"); goto error;
}
return 0;
error:
xvip_dma_cleanup(dma); return ret;
}
void xvip_dma_cleanup(struct xvip_dma *dma)
{ if (video_is_registered(&dma->video))
video_unregister_device(&dma->video);
if (!IS_ERR_OR_NULL(dma->dma))
dma_release_channel(dma->dma);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.