b79bdb8412ba9b8f432cb86bb385a5a88a12bf2f
[oweals/openwrt.git] /
1 From adab474d1f91594d6d96d44054586ba36d7f26d4 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Mon, 24 Sep 2018 18:15:38 +0100
4 Subject: [PATCH] staging: mmal-vchiq: Add support for event callbacks.
5
6 (Preparation for the codec driver).
7 The codec uses the event mechanism to report things such as
8 resolution changes. It is signalled by the cmd field of the buffer
9 being non-zero.
10
11 Add support for passing this information out to the client.
12
13 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
14 ---
15  .../vc04_services/vchiq-mmal/mmal-common.h    |   1 +
16  .../vc04_services/vchiq-mmal/mmal-msg.h       |  35 ++++
17  .../vc04_services/vchiq-mmal/mmal-vchiq.c     | 170 ++++++++++++++++--
18  .../vc04_services/vchiq-mmal/mmal-vchiq.h     |   4 +
19  4 files changed, 196 insertions(+), 14 deletions(-)
20
21 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
22 +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
23 @@ -51,6 +51,7 @@ struct mmal_buffer {
24  
25         struct mmal_msg_context *msg_context;
26  
27 +       u32 cmd;                /* MMAL command. 0=data. */
28         unsigned long length;
29         u32 mmal_flags;
30         s64 dts;
31 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
32 +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
33 @@ -346,6 +346,41 @@ struct mmal_msg_port_parameter_get_reply
34  /* event messages */
35  #define MMAL_WORKER_EVENT_SPACE 256
36  
37 +/* Four CC's for events */
38 +#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
39 +
40 +#define MMAL_EVENT_ERROR               MMAL_FOURCC('E', 'R', 'R', 'O')
41 +#define MMAL_EVENT_EOS                 MMAL_FOURCC('E', 'E', 'O', 'S')
42 +#define MMAL_EVENT_FORMAT_CHANGED      MMAL_FOURCC('E', 'F', 'C', 'H')
43 +#define MMAL_EVENT_PARAMETER_CHANGED   MMAL_FOURCC('E', 'P', 'C', 'H')
44 +
45 +/* Structs for each of the event message payloads */
46 +struct mmal_msg_event_eos {
47 +       u32 port_type;  /**< Type of port that received the end of stream */
48 +       u32 port_index; /**< Index of port that received the end of stream */
49 +};
50 +
51 +/** Format changed event data. */
52 +struct mmal_msg_event_format_changed {
53 +       /* Minimum size of buffers the port requires */
54 +       u32 buffer_size_min;
55 +       /* Minimum number of buffers the port requires */
56 +       u32 buffer_num_min;
57 +       /* Size of buffers the port recommends for optimal performance.
58 +        * A value of zero means no special recommendation.
59 +        */
60 +       u32 buffer_size_recommended;
61 +       /* Number of buffers the port recommends for optimal
62 +        * performance. A value of zero means no special recommendation.
63 +        */
64 +       u32 buffer_num_recommended;
65 +
66 +       u32 es_ptr;
67 +       struct mmal_es_format format;
68 +       union mmal_es_specific_format es;
69 +       u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
70 +};
71 +
72  struct mmal_msg_event_to_host {
73         u32 client_component;   /* component context */
74  
75 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
76 +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
77 @@ -151,6 +151,8 @@ struct mmal_msg_context {
78                         /* Presentation and Decode timestamps */
79                         s64 pts;
80                         s64 dts;
81 +                       /* MMAL buffer command flag */
82 +                       u32 cmd;
83  
84                         int status;     /* context status */
85  
86 @@ -238,18 +240,6 @@ release_msg_context(struct mmal_msg_cont
87         kfree(msg_context);
88  }
89  
90 -/* deals with receipt of event to host message */
91 -static void event_to_host_cb(struct vchiq_mmal_instance *instance,
92 -                            struct mmal_msg *msg, u32 msg_len)
93 -{
94 -       pr_debug("unhandled event\n");
95 -       pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
96 -                msg->u.event_to_host.client_component,
97 -                msg->u.event_to_host.port_type,
98 -                msg->u.event_to_host.port_num,
99 -                msg->u.event_to_host.cmd, msg->u.event_to_host.length);
100 -}
101 -
102  /* workqueue scheduled callback
103   *
104   * we do this because it is important we do not call any other vchiq
105 @@ -271,13 +261,18 @@ static void buffer_work_cb(struct work_s
106         buffer->mmal_flags = msg_context->u.bulk.mmal_flags;
107         buffer->dts = msg_context->u.bulk.dts;
108         buffer->pts = msg_context->u.bulk.pts;
109 +       buffer->cmd = msg_context->u.bulk.cmd;
110  
111 -       atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
112 +       if (!buffer->cmd)
113 +               atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
114  
115         msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
116                                             msg_context->u.bulk.port,
117                                             msg_context->u.bulk.status,
118                                             msg_context->u.bulk.buffer);
119 +
120 +       if (buffer->cmd)
121 +               mutex_unlock(&msg_context->u.bulk.port->event_context_mutex);
122  }
123  
124  /* workqueue scheduled callback to handle receiving buffers
125 @@ -356,6 +351,7 @@ static int bulk_receive(struct vchiq_mma
126         msg_context->u.bulk.buffer_used = rd_len;
127         msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
128         msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
129 +       msg_context->u.bulk.cmd = msg->u.buffer_from_host.buffer_header.cmd;
130  
131         queue_work(msg_context->instance->bulk_wq,
132                    &msg_context->u.bulk.buffer_to_host_work);
133 @@ -457,6 +453,103 @@ buffer_from_host(struct vchiq_mmal_insta
134         return ret;
135  }
136  
137 +/* deals with receipt of event to host message */
138 +static void event_to_host_cb(struct vchiq_mmal_instance *instance,
139 +                            struct mmal_msg *msg, u32 msg_len)
140 +{
141 +       /* FIXME: Not going to work on 64 bit */
142 +       struct vchiq_mmal_component *component =
143 +               (struct vchiq_mmal_component *)msg->u.event_to_host.client_component;
144 +       struct vchiq_mmal_port *port = NULL;
145 +       struct mmal_msg_context *msg_context;
146 +       u32 port_num = msg->u.event_to_host.port_num;
147 +
148 +       if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
149 +               pr_err("%s: MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n",
150 +                      __func__);
151 +               return;
152 +       }
153 +
154 +       switch (msg->u.event_to_host.port_type) {
155 +       case MMAL_PORT_TYPE_CONTROL:
156 +               if (port_num) {
157 +                       pr_err("%s: port_num of %u >= number of ports 1",
158 +                              __func__, port_num);
159 +                       return;
160 +               }
161 +               port = &component->control;
162 +               break;
163 +       case MMAL_PORT_TYPE_INPUT:
164 +               if (port_num >= component->inputs) {
165 +                       pr_err("%s: port_num of %u >= number of ports %u",
166 +                              __func__, port_num,
167 +                              port_num >= component->inputs);
168 +                       return;
169 +               }
170 +               port = &component->input[port_num];
171 +               break;
172 +       case MMAL_PORT_TYPE_OUTPUT:
173 +               if (port_num >= component->outputs) {
174 +                       pr_err("%s: port_num of %u >= number of ports %u",
175 +                              __func__, port_num,
176 +                              port_num >= component->outputs);
177 +                       return;
178 +               }
179 +               port = &component->output[port_num];
180 +               break;
181 +       case MMAL_PORT_TYPE_CLOCK:
182 +               if (port_num >= component->clocks) {
183 +                       pr_err("%s: port_num of %u >= number of ports %u",
184 +                              __func__, port_num,
185 +                              port_num >= component->clocks);
186 +                       return;
187 +               }
188 +               port = &component->clock[port_num];
189 +               break;
190 +       default:
191 +               break;
192 +       }
193 +
194 +       if (!mutex_trylock(&port->event_context_mutex)) {
195 +               pr_err("dropping event 0x%x\n", msg->u.event_to_host.cmd);
196 +               return;
197 +       }
198 +       msg_context = port->event_context;
199 +
200 +       if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
201 +               /* message reception had an error */
202 +               //pr_warn
203 +               pr_err("%s: error %d in reply\n", __func__, msg->h.status);
204 +
205 +               msg_context->u.bulk.status = msg->h.status;
206 +       } else if (msg->u.event_to_host.length > MMAL_WORKER_EVENT_SPACE) {
207 +               /* data is not in message, queue a bulk receive */
208 +               pr_err("%s: payload not in message - bulk receive??! NOT SUPPORTED\n",
209 +                      __func__);
210 +               msg_context->u.bulk.status = -1;
211 +       } else {
212 +               memcpy(msg_context->u.bulk.buffer->buffer,
213 +                      msg->u.event_to_host.data,
214 +                      msg->u.event_to_host.length);
215 +
216 +               msg_context->u.bulk.buffer_used =
217 +                   msg->u.event_to_host.length;
218 +
219 +               msg_context->u.bulk.mmal_flags = 0;
220 +               msg_context->u.bulk.dts = MMAL_TIME_UNKNOWN;
221 +               msg_context->u.bulk.pts = MMAL_TIME_UNKNOWN;
222 +               msg_context->u.bulk.cmd = msg->u.event_to_host.cmd;
223 +
224 +               pr_debug("event component:%u port type:%d num:%d cmd:0x%x length:%d\n",
225 +                        msg->u.event_to_host.client_component,
226 +                        msg->u.event_to_host.port_type,
227 +                        msg->u.event_to_host.port_num,
228 +                        msg->u.event_to_host.cmd, msg->u.event_to_host.length);
229 +       }
230 +
231 +       schedule_work(&msg_context->u.bulk.work);
232 +}
233 +
234  /* deals with receipt of buffer to host message */
235  static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
236                               struct mmal_msg *msg, u32 msg_len)
237 @@ -1340,6 +1433,7 @@ static int port_disable(struct vchiq_mma
238                                 mmalbuf->mmal_flags = 0;
239                                 mmalbuf->dts = MMAL_TIME_UNKNOWN;
240                                 mmalbuf->pts = MMAL_TIME_UNKNOWN;
241 +                               mmalbuf->cmd = 0;
242                                 port->buffer_cb(instance,
243                                                 port, 0, mmalbuf);
244                         }
245 @@ -1641,6 +1735,43 @@ int mmal_vchi_buffer_cleanup(struct mmal
246  }
247  EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
248  
249 +static void init_event_context(struct vchiq_mmal_instance *instance,
250 +                              struct vchiq_mmal_port *port)
251 +{
252 +       struct mmal_msg_context *ctx = get_msg_context(instance);
253 +
254 +       mutex_init(&port->event_context_mutex);
255 +
256 +       port->event_context = ctx;
257 +       ctx->u.bulk.instance = instance;
258 +       ctx->u.bulk.port = port;
259 +       ctx->u.bulk.buffer =
260 +               kzalloc(sizeof(*ctx->u.bulk.buffer), GFP_KERNEL);
261 +       if (!ctx->u.bulk.buffer)
262 +               goto release_msg_context;
263 +       ctx->u.bulk.buffer->buffer = kzalloc(MMAL_WORKER_EVENT_SPACE,
264 +                                            GFP_KERNEL);
265 +       if (!ctx->u.bulk.buffer->buffer)
266 +               goto release_buffer;
267 +
268 +       INIT_WORK(&ctx->u.bulk.work, buffer_work_cb);
269 +       return;
270 +
271 +release_buffer:
272 +       kfree(ctx->u.bulk.buffer);
273 +release_msg_context:
274 +       release_msg_context(ctx);
275 +}
276 +
277 +static void free_event_context(struct vchiq_mmal_port *port)
278 +{
279 +       struct mmal_msg_context *ctx = port->event_context;
280 +
281 +       kfree(ctx->u.bulk.buffer->buffer);
282 +       kfree(ctx->u.bulk.buffer);
283 +       release_msg_context(ctx);
284 +}
285 +
286  /* Initialise a mmal component and its ports
287   *
288   */
289 @@ -1684,6 +1815,7 @@ int vchiq_mmal_component_init(struct vch
290         ret = port_info_get(instance, &component->control);
291         if (ret < 0)
292                 goto release_component;
293 +       init_event_context(instance, &component->control);
294  
295         for (idx = 0; idx < component->inputs; idx++) {
296                 component->input[idx].type = MMAL_PORT_TYPE_INPUT;
297 @@ -1694,6 +1826,7 @@ int vchiq_mmal_component_init(struct vch
298                 ret = port_info_get(instance, &component->input[idx]);
299                 if (ret < 0)
300                         goto release_component;
301 +               init_event_context(instance, &component->input[idx]);
302         }
303  
304         for (idx = 0; idx < component->outputs; idx++) {
305 @@ -1705,6 +1838,7 @@ int vchiq_mmal_component_init(struct vch
306                 ret = port_info_get(instance, &component->output[idx]);
307                 if (ret < 0)
308                         goto release_component;
309 +               init_event_context(instance, &component->output[idx]);
310         }
311  
312         for (idx = 0; idx < component->clocks; idx++) {
313 @@ -1716,6 +1850,7 @@ int vchiq_mmal_component_init(struct vch
314                 ret = port_info_get(instance, &component->clock[idx]);
315                 if (ret < 0)
316                         goto release_component;
317 +               init_event_context(instance, &component->clock[idx]);
318         }
319  
320         *component_out = component;
321 @@ -1741,7 +1876,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i
322  int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
323                                   struct vchiq_mmal_component *component)
324  {
325 -       int ret;
326 +       int ret, idx;
327  
328         if (mutex_lock_interruptible(&instance->vchiq_mutex))
329                 return -EINTR;
330 @@ -1753,6 +1888,13 @@ int vchiq_mmal_component_finalise(struct
331  
332         component->in_use = 0;
333  
334 +       for (idx = 0; idx < component->inputs; idx++)
335 +               free_event_context(&component->input[idx]);
336 +       for (idx = 0; idx < component->outputs; idx++)
337 +               free_event_context(&component->output[idx]);
338 +       for (idx = 0; idx < component->clocks; idx++)
339 +               free_event_context(&component->clock[idx]);
340 +
341         mutex_unlock(&instance->vchiq_mutex);
342  
343         return ret;
344 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
345 +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
346 @@ -78,6 +78,10 @@ struct vchiq_mmal_port {
347         vchiq_mmal_buffer_cb buffer_cb;
348         /* callback context */
349         void *cb_ctx;
350 +
351 +       /* ensure serialised use of the one event context structure */
352 +       struct mutex event_context_mutex;
353 +       struct mmal_msg_context *event_context;
354  };
355  
356  struct vchiq_mmal_component {