]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.19/media-vimc-add-vimc-streamer-for-stream-control.patch
Linux 4.14.108
[thirdparty/kernel/stable-queue.git] / queue-4.19 / media-vimc-add-vimc-streamer-for-stream-control.patch
1 From adc589d2a20808fb99d46a78175cd023f2040338 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Lucas=20A=2E=20M=2E=20Magalh=C3=A3es?= <lucmaga@gmail.com>
3 Date: Mon, 21 Jan 2019 20:05:01 -0500
4 Subject: media: vimc: Add vimc-streamer for stream control
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 From: Lucas A. M. Magalhães <lucmaga@gmail.com>
10
11 commit adc589d2a20808fb99d46a78175cd023f2040338 upstream.
12
13 Add a linear pipeline logic for the stream control. It's created by
14 walking backwards on the entity graph. When the stream starts it will
15 simply loop through the pipeline calling the respective process_frame
16 function of each entity.
17
18 Fixes: f2fe89061d797 ("vimc: Virtual Media Controller core, capture
19 and sensor")
20
21 Cc: stable@vger.kernel.org # for v4.20
22 Signed-off-by: Lucas A. M. Magalhães <lucmaga@gmail.com>
23 Acked-by: Helen Koike <helen.koike@collabora.com>
24 Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
25 [hverkuil-cisco@xs4all.nl: fixed small space-after-tab issue in the patch]
26 Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
27 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
28
29 ---
30 drivers/media/platform/vimc/Makefile | 3
31 drivers/media/platform/vimc/vimc-capture.c | 18 +-
32 drivers/media/platform/vimc/vimc-common.c | 35 -----
33 drivers/media/platform/vimc/vimc-common.h | 15 --
34 drivers/media/platform/vimc/vimc-debayer.c | 26 ---
35 drivers/media/platform/vimc/vimc-scaler.c | 28 ----
36 drivers/media/platform/vimc/vimc-sensor.c | 56 +-------
37 drivers/media/platform/vimc/vimc-streamer.c | 188 ++++++++++++++++++++++++++++
38 drivers/media/platform/vimc/vimc-streamer.h | 38 +++++
39 9 files changed, 260 insertions(+), 147 deletions(-)
40
41 --- a/drivers/media/platform/vimc/Makefile
42 +++ b/drivers/media/platform/vimc/Makefile
43 @@ -5,6 +5,7 @@ vimc_common-objs := vimc-common.o
44 vimc_debayer-objs := vimc-debayer.o
45 vimc_scaler-objs := vimc-scaler.o
46 vimc_sensor-objs := vimc-sensor.o
47 +vimc_streamer-objs := vimc-streamer.o
48
49 obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \
50 - vimc_scaler.o vimc_sensor.o
51 + vimc_scaler.o vimc_sensor.o vimc_streamer.o
52 --- a/drivers/media/platform/vimc/vimc-capture.c
53 +++ b/drivers/media/platform/vimc/vimc-capture.c
54 @@ -24,6 +24,7 @@
55 #include <media/videobuf2-vmalloc.h>
56
57 #include "vimc-common.h"
58 +#include "vimc-streamer.h"
59
60 #define VIMC_CAP_DRV_NAME "vimc-capture"
61
62 @@ -44,7 +45,7 @@ struct vimc_cap_device {
63 spinlock_t qlock;
64 struct mutex lock;
65 u32 sequence;
66 - struct media_pipeline pipe;
67 + struct vimc_stream stream;
68 };
69
70 static const struct v4l2_pix_format fmt_default = {
71 @@ -248,14 +249,13 @@ static int vimc_cap_start_streaming(stru
72 vcap->sequence = 0;
73
74 /* Start the media pipeline */
75 - ret = media_pipeline_start(entity, &vcap->pipe);
76 + ret = media_pipeline_start(entity, &vcap->stream.pipe);
77 if (ret) {
78 vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
79 return ret;
80 }
81
82 - /* Enable streaming from the pipe */
83 - ret = vimc_pipeline_s_stream(&vcap->vdev.entity, 1);
84 + ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1);
85 if (ret) {
86 media_pipeline_stop(entity);
87 vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
88 @@ -273,8 +273,7 @@ static void vimc_cap_stop_streaming(stru
89 {
90 struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);
91
92 - /* Disable streaming from the pipe */
93 - vimc_pipeline_s_stream(&vcap->vdev.entity, 0);
94 + vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0);
95
96 /* Stop the media pipeline */
97 media_pipeline_stop(&vcap->vdev.entity);
98 @@ -355,8 +354,8 @@ static void vimc_cap_comp_unbind(struct
99 kfree(vcap);
100 }
101
102 -static void vimc_cap_process_frame(struct vimc_ent_device *ved,
103 - struct media_pad *sink, const void *frame)
104 +static void *vimc_cap_process_frame(struct vimc_ent_device *ved,
105 + const void *frame)
106 {
107 struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device,
108 ved);
109 @@ -370,7 +369,7 @@ static void vimc_cap_process_frame(struc
110 typeof(*vimc_buf), list);
111 if (!vimc_buf) {
112 spin_unlock(&vcap->qlock);
113 - return;
114 + return ERR_PTR(-EAGAIN);
115 }
116
117 /* Remove this entry from the list */
118 @@ -391,6 +390,7 @@ static void vimc_cap_process_frame(struc
119 vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0,
120 vcap->format.sizeimage);
121 vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE);
122 + return NULL;
123 }
124
125 static int vimc_cap_comp_bind(struct device *comp, struct device *master,
126 --- a/drivers/media/platform/vimc/vimc-common.c
127 +++ b/drivers/media/platform/vimc/vimc-common.c
128 @@ -207,41 +207,6 @@ const struct vimc_pix_map *vimc_pix_map_
129 }
130 EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat);
131
132 -int vimc_propagate_frame(struct media_pad *src, const void *frame)
133 -{
134 - struct media_link *link;
135 -
136 - if (!(src->flags & MEDIA_PAD_FL_SOURCE))
137 - return -EINVAL;
138 -
139 - /* Send this frame to all sink pads that are direct linked */
140 - list_for_each_entry(link, &src->entity->links, list) {
141 - if (link->source == src &&
142 - (link->flags & MEDIA_LNK_FL_ENABLED)) {
143 - struct vimc_ent_device *ved = NULL;
144 - struct media_entity *entity = link->sink->entity;
145 -
146 - if (is_media_entity_v4l2_subdev(entity)) {
147 - struct v4l2_subdev *sd =
148 - container_of(entity, struct v4l2_subdev,
149 - entity);
150 - ved = v4l2_get_subdevdata(sd);
151 - } else if (is_media_entity_v4l2_video_device(entity)) {
152 - struct video_device *vdev =
153 - container_of(entity,
154 - struct video_device,
155 - entity);
156 - ved = video_get_drvdata(vdev);
157 - }
158 - if (ved && ved->process_frame)
159 - ved->process_frame(ved, link->sink, frame);
160 - }
161 - }
162 -
163 - return 0;
164 -}
165 -EXPORT_SYMBOL_GPL(vimc_propagate_frame);
166 -
167 /* Helper function to allocate and initialize pads */
168 struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)
169 {
170 --- a/drivers/media/platform/vimc/vimc-common.h
171 +++ b/drivers/media/platform/vimc/vimc-common.h
172 @@ -113,24 +113,13 @@ struct vimc_pix_map {
173 struct vimc_ent_device {
174 struct media_entity *ent;
175 struct media_pad *pads;
176 - void (*process_frame)(struct vimc_ent_device *ved,
177 - struct media_pad *sink, const void *frame);
178 + void * (*process_frame)(struct vimc_ent_device *ved,
179 + const void *frame);
180 void (*vdev_get_format)(struct vimc_ent_device *ved,
181 struct v4l2_pix_format *fmt);
182 };
183
184 /**
185 - * vimc_propagate_frame - propagate a frame through the topology
186 - *
187 - * @src: the source pad where the frame is being originated
188 - * @frame: the frame to be propagated
189 - *
190 - * This function will call the process_frame callback from the vimc_ent_device
191 - * struct of the nodes directly connected to the @src pad
192 - */
193 -int vimc_propagate_frame(struct media_pad *src, const void *frame);
194 -
195 -/**
196 * vimc_pads_init - initialize pads
197 *
198 * @num_pads: number of pads to initialize
199 --- a/drivers/media/platform/vimc/vimc-debayer.c
200 +++ b/drivers/media/platform/vimc/vimc-debayer.c
201 @@ -321,7 +321,6 @@ static void vimc_deb_set_rgb_mbus_fmt_rg
202 static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
203 {
204 struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
205 - int ret;
206
207 if (enable) {
208 const struct vimc_pix_map *vpix;
209 @@ -351,22 +350,10 @@ static int vimc_deb_s_stream(struct v4l2
210 if (!vdeb->src_frame)
211 return -ENOMEM;
212
213 - /* Turn the stream on in the subdevices directly connected */
214 - ret = vimc_pipeline_s_stream(&vdeb->sd.entity, 1);
215 - if (ret) {
216 - vfree(vdeb->src_frame);
217 - vdeb->src_frame = NULL;
218 - return ret;
219 - }
220 } else {
221 if (!vdeb->src_frame)
222 return 0;
223
224 - /* Disable streaming from the pipe */
225 - ret = vimc_pipeline_s_stream(&vdeb->sd.entity, 0);
226 - if (ret)
227 - return ret;
228 -
229 vfree(vdeb->src_frame);
230 vdeb->src_frame = NULL;
231 }
232 @@ -480,9 +467,8 @@ static void vimc_deb_calc_rgb_sink(struc
233 }
234 }
235
236 -static void vimc_deb_process_frame(struct vimc_ent_device *ved,
237 - struct media_pad *sink,
238 - const void *sink_frame)
239 +static void *vimc_deb_process_frame(struct vimc_ent_device *ved,
240 + const void *sink_frame)
241 {
242 struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device,
243 ved);
244 @@ -491,7 +477,7 @@ static void vimc_deb_process_frame(struc
245
246 /* If the stream in this node is not active, just return */
247 if (!vdeb->src_frame)
248 - return;
249 + return ERR_PTR(-EINVAL);
250
251 for (i = 0; i < vdeb->sink_fmt.height; i++)
252 for (j = 0; j < vdeb->sink_fmt.width; j++) {
253 @@ -499,12 +485,8 @@ static void vimc_deb_process_frame(struc
254 vdeb->set_rgb_src(vdeb, i, j, rgb);
255 }
256
257 - /* Propagate the frame through all source pads */
258 - for (i = 1; i < vdeb->sd.entity.num_pads; i++) {
259 - struct media_pad *pad = &vdeb->sd.entity.pads[i];
260 + return vdeb->src_frame;
261
262 - vimc_propagate_frame(pad, vdeb->src_frame);
263 - }
264 }
265
266 static void vimc_deb_comp_unbind(struct device *comp, struct device *master,
267 --- a/drivers/media/platform/vimc/vimc-scaler.c
268 +++ b/drivers/media/platform/vimc/vimc-scaler.c
269 @@ -217,7 +217,6 @@ static const struct v4l2_subdev_pad_ops
270 static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
271 {
272 struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
273 - int ret;
274
275 if (enable) {
276 const struct vimc_pix_map *vpix;
277 @@ -245,22 +244,10 @@ static int vimc_sca_s_stream(struct v4l2
278 if (!vsca->src_frame)
279 return -ENOMEM;
280
281 - /* Turn the stream on in the subdevices directly connected */
282 - ret = vimc_pipeline_s_stream(&vsca->sd.entity, 1);
283 - if (ret) {
284 - vfree(vsca->src_frame);
285 - vsca->src_frame = NULL;
286 - return ret;
287 - }
288 } else {
289 if (!vsca->src_frame)
290 return 0;
291
292 - /* Disable streaming from the pipe */
293 - ret = vimc_pipeline_s_stream(&vsca->sd.entity, 0);
294 - if (ret)
295 - return ret;
296 -
297 vfree(vsca->src_frame);
298 vsca->src_frame = NULL;
299 }
300 @@ -346,26 +333,19 @@ static void vimc_sca_fill_src_frame(cons
301 vimc_sca_scale_pix(vsca, i, j, sink_frame);
302 }
303
304 -static void vimc_sca_process_frame(struct vimc_ent_device *ved,
305 - struct media_pad *sink,
306 - const void *sink_frame)
307 +static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
308 + const void *sink_frame)
309 {
310 struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device,
311 ved);
312 - unsigned int i;
313
314 /* If the stream in this node is not active, just return */
315 if (!vsca->src_frame)
316 - return;
317 + return ERR_PTR(-EINVAL);
318
319 vimc_sca_fill_src_frame(vsca, sink_frame);
320
321 - /* Propagate the frame through all source pads */
322 - for (i = 1; i < vsca->sd.entity.num_pads; i++) {
323 - struct media_pad *pad = &vsca->sd.entity.pads[i];
324 -
325 - vimc_propagate_frame(pad, vsca->src_frame);
326 - }
327 + return vsca->src_frame;
328 };
329
330 static void vimc_sca_comp_unbind(struct device *comp, struct device *master,
331 --- a/drivers/media/platform/vimc/vimc-sensor.c
332 +++ b/drivers/media/platform/vimc/vimc-sensor.c
333 @@ -16,8 +16,6 @@
334 */
335
336 #include <linux/component.h>
337 -#include <linux/freezer.h>
338 -#include <linux/kthread.h>
339 #include <linux/module.h>
340 #include <linux/mod_devicetable.h>
341 #include <linux/platform_device.h>
342 @@ -201,38 +199,27 @@ static const struct v4l2_subdev_pad_ops
343 .set_fmt = vimc_sen_set_fmt,
344 };
345
346 -static int vimc_sen_tpg_thread(void *data)
347 +static void *vimc_sen_process_frame(struct vimc_ent_device *ved,
348 + const void *sink_frame)
349 {
350 - struct vimc_sen_device *vsen = data;
351 - unsigned int i;
352 -
353 - set_freezable();
354 - set_current_state(TASK_UNINTERRUPTIBLE);
355 -
356 - for (;;) {
357 - try_to_freeze();
358 - if (kthread_should_stop())
359 - break;
360 -
361 - tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame);
362 -
363 - /* Send the frame to all source pads */
364 - for (i = 0; i < vsen->sd.entity.num_pads; i++)
365 - vimc_propagate_frame(&vsen->sd.entity.pads[i],
366 - vsen->frame);
367 + struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device,
368 + ved);
369 + const struct vimc_pix_map *vpix;
370 + unsigned int frame_size;
371
372 - /* 60 frames per second */
373 - schedule_timeout(HZ/60);
374 - }
375 + /* Calculate the frame size */
376 + vpix = vimc_pix_map_by_code(vsen->mbus_format.code);
377 + frame_size = vsen->mbus_format.width * vpix->bpp *
378 + vsen->mbus_format.height;
379
380 - return 0;
381 + tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame);
382 + return vsen->frame;
383 }
384
385 static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
386 {
387 struct vimc_sen_device *vsen =
388 container_of(sd, struct vimc_sen_device, sd);
389 - int ret;
390
391 if (enable) {
392 const struct vimc_pix_map *vpix;
393 @@ -258,26 +245,8 @@ static int vimc_sen_s_stream(struct v4l2
394 /* configure the test pattern generator */
395 vimc_sen_tpg_s_format(vsen);
396
397 - /* Initialize the image generator thread */
398 - vsen->kthread_sen = kthread_run(vimc_sen_tpg_thread, vsen,
399 - "%s-sen", vsen->sd.v4l2_dev->name);
400 - if (IS_ERR(vsen->kthread_sen)) {
401 - dev_err(vsen->dev, "%s: kernel_thread() failed\n",
402 - vsen->sd.name);
403 - vfree(vsen->frame);
404 - vsen->frame = NULL;
405 - return PTR_ERR(vsen->kthread_sen);
406 - }
407 } else {
408 - if (!vsen->kthread_sen)
409 - return 0;
410 -
411 - /* Stop image generator */
412 - ret = kthread_stop(vsen->kthread_sen);
413 - if (ret)
414 - return ret;
415
416 - vsen->kthread_sen = NULL;
417 vfree(vsen->frame);
418 vsen->frame = NULL;
419 return 0;
420 @@ -393,6 +362,7 @@ static int vimc_sen_comp_bind(struct dev
421 if (ret)
422 goto err_free_hdl;
423
424 + vsen->ved.process_frame = vimc_sen_process_frame;
425 dev_set_drvdata(comp, &vsen->ved);
426 vsen->dev = comp;
427
428 --- /dev/null
429 +++ b/drivers/media/platform/vimc/vimc-streamer.c
430 @@ -0,0 +1,188 @@
431 +// SPDX-License-Identifier: GPL-2.0+
432 +/*
433 + * vimc-streamer.c Virtual Media Controller Driver
434 + *
435 + * Copyright (C) 2018 Lucas A. M. Magalhães <lucmaga@gmail.com>
436 + *
437 + */
438 +
439 +#include <linux/init.h>
440 +#include <linux/module.h>
441 +#include <linux/freezer.h>
442 +#include <linux/kthread.h>
443 +
444 +#include "vimc-streamer.h"
445 +
446 +/**
447 + * vimc_get_source_entity - get the entity connected with the first sink pad
448 + *
449 + * @ent: reference media_entity
450 + *
451 + * Helper function that returns the media entity containing the source pad
452 + * linked with the first sink pad from the given media entity pad list.
453 + */
454 +static struct media_entity *vimc_get_source_entity(struct media_entity *ent)
455 +{
456 + struct media_pad *pad;
457 + int i;
458 +
459 + for (i = 0; i < ent->num_pads; i++) {
460 + if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE)
461 + continue;
462 + pad = media_entity_remote_pad(&ent->pads[i]);
463 + return pad ? pad->entity : NULL;
464 + }
465 + return NULL;
466 +}
467 +
468 +/*
469 + * vimc_streamer_pipeline_terminate - Disable stream in all ved in stream
470 + *
471 + * @stream: the pointer to the stream structure with the pipeline to be
472 + * disabled.
473 + *
474 + * Calls s_stream to disable the stream in each entity of the pipeline
475 + *
476 + */
477 +static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream)
478 +{
479 + struct media_entity *entity;
480 + struct v4l2_subdev *sd;
481 +
482 + while (stream->pipe_size) {
483 + stream->pipe_size--;
484 + entity = stream->ved_pipeline[stream->pipe_size]->ent;
485 + entity = vimc_get_source_entity(entity);
486 + stream->ved_pipeline[stream->pipe_size] = NULL;
487 +
488 + if (!is_media_entity_v4l2_subdev(entity))
489 + continue;
490 +
491 + sd = media_entity_to_v4l2_subdev(entity);
492 + v4l2_subdev_call(sd, video, s_stream, 0);
493 + }
494 +}
495 +
496 +/*
497 + * vimc_streamer_pipeline_init - initializes the stream structure
498 + *
499 + * @stream: the pointer to the stream structure to be initialized
500 + * @ved: the pointer to the vimc entity initializing the stream
501 + *
502 + * Initializes the stream structure. Walks through the entity graph to
503 + * construct the pipeline used later on the streamer thread.
504 + * Calls s_stream to enable stream in all entities of the pipeline.
505 + */
506 +static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
507 + struct vimc_ent_device *ved)
508 +{
509 + struct media_entity *entity;
510 + struct video_device *vdev;
511 + struct v4l2_subdev *sd;
512 + int ret = 0;
513 +
514 + stream->pipe_size = 0;
515 + while (stream->pipe_size < VIMC_STREAMER_PIPELINE_MAX_SIZE) {
516 + if (!ved) {
517 + vimc_streamer_pipeline_terminate(stream);
518 + return -EINVAL;
519 + }
520 + stream->ved_pipeline[stream->pipe_size++] = ved;
521 +
522 + entity = vimc_get_source_entity(ved->ent);
523 + /* Check if the end of the pipeline was reached*/
524 + if (!entity)
525 + return 0;
526 +
527 + if (is_media_entity_v4l2_subdev(entity)) {
528 + sd = media_entity_to_v4l2_subdev(entity);
529 + ret = v4l2_subdev_call(sd, video, s_stream, 1);
530 + if (ret && ret != -ENOIOCTLCMD) {
531 + vimc_streamer_pipeline_terminate(stream);
532 + return ret;
533 + }
534 + ved = v4l2_get_subdevdata(sd);
535 + } else {
536 + vdev = container_of(entity,
537 + struct video_device,
538 + entity);
539 + ved = video_get_drvdata(vdev);
540 + }
541 + }
542 +
543 + vimc_streamer_pipeline_terminate(stream);
544 + return -EINVAL;
545 +}
546 +
547 +static int vimc_streamer_thread(void *data)
548 +{
549 + struct vimc_stream *stream = data;
550 + int i;
551 +
552 + set_freezable();
553 + set_current_state(TASK_UNINTERRUPTIBLE);
554 +
555 + for (;;) {
556 + try_to_freeze();
557 + if (kthread_should_stop())
558 + break;
559 +
560 + for (i = stream->pipe_size - 1; i >= 0; i--) {
561 + stream->frame = stream->ved_pipeline[i]->process_frame(
562 + stream->ved_pipeline[i],
563 + stream->frame);
564 + if (!stream->frame)
565 + break;
566 + if (IS_ERR(stream->frame))
567 + break;
568 + }
569 + //wait for 60hz
570 + schedule_timeout(HZ / 60);
571 + }
572 +
573 + return 0;
574 +}
575 +
576 +int vimc_streamer_s_stream(struct vimc_stream *stream,
577 + struct vimc_ent_device *ved,
578 + int enable)
579 +{
580 + int ret;
581 +
582 + if (!stream || !ved)
583 + return -EINVAL;
584 +
585 + if (enable) {
586 + if (stream->kthread)
587 + return 0;
588 +
589 + ret = vimc_streamer_pipeline_init(stream, ved);
590 + if (ret)
591 + return ret;
592 +
593 + stream->kthread = kthread_run(vimc_streamer_thread, stream,
594 + "vimc-streamer thread");
595 +
596 + if (IS_ERR(stream->kthread))
597 + return PTR_ERR(stream->kthread);
598 +
599 + } else {
600 + if (!stream->kthread)
601 + return 0;
602 +
603 + ret = kthread_stop(stream->kthread);
604 + if (ret)
605 + return ret;
606 +
607 + stream->kthread = NULL;
608 +
609 + vimc_streamer_pipeline_terminate(stream);
610 + }
611 +
612 + return 0;
613 +}
614 +EXPORT_SYMBOL_GPL(vimc_streamer_s_stream);
615 +
616 +MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Streamer");
617 +MODULE_AUTHOR("Lucas A. M. Magalhães <lucmaga@gmail.com>");
618 +MODULE_LICENSE("GPL");
619 --- /dev/null
620 +++ b/drivers/media/platform/vimc/vimc-streamer.h
621 @@ -0,0 +1,38 @@
622 +/* SPDX-License-Identifier: GPL-2.0+ */
623 +/*
624 + * vimc-streamer.h Virtual Media Controller Driver
625 + *
626 + * Copyright (C) 2018 Lucas A. M. Magalhães <lucmaga@gmail.com>
627 + *
628 + */
629 +
630 +#ifndef _VIMC_STREAMER_H_
631 +#define _VIMC_STREAMER_H_
632 +
633 +#include <media/media-device.h>
634 +
635 +#include "vimc-common.h"
636 +
637 +#define VIMC_STREAMER_PIPELINE_MAX_SIZE 16
638 +
639 +struct vimc_stream {
640 + struct media_pipeline pipe;
641 + struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE];
642 + unsigned int pipe_size;
643 + u8 *frame;
644 + struct task_struct *kthread;
645 +};
646 +
647 +/**
648 + * vimc_streamer_s_streamer - start/stop the stream
649 + *
650 + * @stream: the pointer to the stream to start or stop
651 + * @ved: The last entity of the streamer pipeline
652 + * @enable: any non-zero number start the stream, zero stop
653 + *
654 + */
655 +int vimc_streamer_s_stream(struct vimc_stream *stream,
656 + struct vimc_ent_device *ved,
657 + int enable);
658 +
659 +#endif //_VIMC_STREAMER_H_