1
2
3
4
5
6
7
8
9#include <linux/init.h>
10#include <linux/module.h>
11#include <linux/freezer.h>
12#include <linux/kthread.h>
13
14#include "vimc-streamer.h"
15
16
17
18
19
20
21
22
23
24static struct media_entity *vimc_get_source_entity(struct media_entity *ent)
25{
26 struct media_pad *pad;
27 int i;
28
29 for (i = 0; i < ent->num_pads; i++) {
30 if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE)
31 continue;
32 pad = media_entity_remote_pad(&ent->pads[i]);
33 return pad ? pad->entity : NULL;
34 }
35 return NULL;
36}
37
38
39
40
41
42
43
44
45
46
47static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream)
48{
49 struct vimc_ent_device *ved;
50 struct v4l2_subdev *sd;
51
52 while (stream->pipe_size) {
53 stream->pipe_size--;
54 ved = stream->ved_pipeline[stream->pipe_size];
55 ved->stream = NULL;
56 stream->ved_pipeline[stream->pipe_size] = NULL;
57
58 if (!is_media_entity_v4l2_subdev(ved->ent))
59 continue;
60
61 sd = media_entity_to_v4l2_subdev(ved->ent);
62 v4l2_subdev_call(sd, video, s_stream, 0);
63 }
64}
65
66
67
68
69
70
71
72
73
74
75
76static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
77 struct vimc_ent_device *ved)
78{
79 struct media_entity *entity;
80 struct video_device *vdev;
81 struct v4l2_subdev *sd;
82 int ret = 0;
83
84 stream->pipe_size = 0;
85 while (stream->pipe_size < VIMC_STREAMER_PIPELINE_MAX_SIZE) {
86 if (!ved) {
87 vimc_streamer_pipeline_terminate(stream);
88 return -EINVAL;
89 }
90 stream->ved_pipeline[stream->pipe_size++] = ved;
91 ved->stream = stream;
92
93 if (is_media_entity_v4l2_subdev(ved->ent)) {
94 sd = media_entity_to_v4l2_subdev(ved->ent);
95 ret = v4l2_subdev_call(sd, video, s_stream, 1);
96 if (ret && ret != -ENOIOCTLCMD) {
97 pr_err("subdev_call error %s\n",
98 ved->ent->name);
99 vimc_streamer_pipeline_terminate(stream);
100 return ret;
101 }
102 }
103
104 entity = vimc_get_source_entity(ved->ent);
105
106 if (!entity)
107 return 0;
108
109
110 if (is_media_entity_v4l2_subdev(entity)) {
111 sd = media_entity_to_v4l2_subdev(entity);
112 ved = v4l2_get_subdevdata(sd);
113 } else {
114 vdev = container_of(entity,
115 struct video_device,
116 entity);
117 ved = video_get_drvdata(vdev);
118 }
119 }
120
121 vimc_streamer_pipeline_terminate(stream);
122 return -EINVAL;
123}
124
125
126
127
128
129
130
131
132
133static int vimc_streamer_thread(void *data)
134{
135 struct vimc_stream *stream = data;
136 u8 *frame = NULL;
137 int i;
138
139 set_freezable();
140
141 for (;;) {
142 try_to_freeze();
143 if (kthread_should_stop())
144 break;
145
146 for (i = stream->pipe_size - 1; i >= 0; i--) {
147 frame = stream->ved_pipeline[i]->process_frame(
148 stream->ved_pipeline[i], frame);
149 if (!frame || IS_ERR(frame))
150 break;
151 }
152
153 set_current_state(TASK_UNINTERRUPTIBLE);
154 schedule_timeout(HZ / 60);
155 }
156
157 return 0;
158}
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174int vimc_streamer_s_stream(struct vimc_stream *stream,
175 struct vimc_ent_device *ved,
176 int enable)
177{
178 int ret;
179
180 if (!stream || !ved)
181 return -EINVAL;
182
183 if (enable) {
184 if (stream->kthread)
185 return 0;
186
187 ret = vimc_streamer_pipeline_init(stream, ved);
188 if (ret)
189 return ret;
190
191 stream->kthread = kthread_run(vimc_streamer_thread, stream,
192 "vimc-streamer thread");
193
194 if (IS_ERR(stream->kthread))
195 return PTR_ERR(stream->kthread);
196
197 } else {
198 if (!stream->kthread)
199 return 0;
200
201 ret = kthread_stop(stream->kthread);
202 if (ret)
203 return ret;
204
205 stream->kthread = NULL;
206
207 vimc_streamer_pipeline_terminate(stream);
208 }
209
210 return 0;
211}
212EXPORT_SYMBOL_GPL(vimc_streamer_s_stream);
213