1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Broadcom BCM2835 V4L2 driver
4 *
5 * Copyright © 2013 Raspberry Pi (Trading) Ltd.
6 *
7 * Authors: Vincent Sanders @ Collabora
8 * Dave Stevenson @ Broadcom
9 * (now dave.stevenson@raspberrypi.org)
10 * Simon Mellor @ Broadcom
11 * Luke Diamand @ Broadcom
12 *
13 * V4L2 driver MMAL vchiq interface code
14 */
15
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18 #include <linux/errno.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/mutex.h>
22 #include <linux/mm.h>
23 #include <linux/slab.h>
24 #include <linux/completion.h>
25 #include <linux/vmalloc.h>
26 #include <linux/raspberrypi/vchiq.h>
27 #include <media/videobuf2-vmalloc.h>
28
29 #include "mmal-common.h"
30 #include "mmal-vchiq.h"
31 #include "mmal-msg.h"
32
33 /*
34 * maximum number of components supported.
35 * This matches the maximum permitted by default on the VPU
36 */
37 #define VCHIQ_MMAL_MAX_COMPONENTS 64
38
39 /*
40 * Timeout for synchronous msg responses in seconds.
41 * Helpful to increase this if stopping in the VPU debugger.
42 */
43 #define SYNC_MSG_TIMEOUT 3
44
45 /*#define FULL_MSG_DUMP 1*/
46
47 #ifdef DEBUG
48 static const char *const msg_type_names[] = {
49 "UNKNOWN",
50 "QUIT",
51 "SERVICE_CLOSED",
52 "GET_VERSION",
53 "COMPONENT_CREATE",
54 "COMPONENT_DESTROY",
55 "COMPONENT_ENABLE",
56 "COMPONENT_DISABLE",
57 "PORT_INFO_GET",
58 "PORT_INFO_SET",
59 "PORT_ACTION",
60 "BUFFER_FROM_HOST",
61 "BUFFER_TO_HOST",
62 "GET_STATS",
63 "PORT_PARAMETER_SET",
64 "PORT_PARAMETER_GET",
65 "EVENT_TO_HOST",
66 "GET_CORE_STATS_FOR_PORT",
67 "OPAQUE_ALLOCATOR",
68 "CONSUME_MEM",
69 "LMK",
70 "OPAQUE_ALLOCATOR_DESC",
71 "DRM_GET_LHS32",
72 "DRM_GET_TIME",
73 "BUFFER_FROM_HOST_ZEROLEN",
74 "PORT_FLUSH",
75 "HOST_LOG",
76 };
77 #endif
78
79 static const char *const port_action_type_names[] = {
80 "UNKNOWN",
81 "ENABLE",
82 "DISABLE",
83 "FLUSH",
84 "CONNECT",
85 "DISCONNECT",
86 "SET_REQUIREMENTS",
87 };
88
89 #if defined(DEBUG)
90 #if defined(FULL_MSG_DUMP)
91 #define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
92 do { \
93 pr_debug(TITLE" type:%s(%d) length:%d\n", \
94 msg_type_names[(MSG)->h.type], \
95 (MSG)->h.type, (MSG_LEN)); \
96 print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
97 16, 4, (MSG), \
98 sizeof(struct mmal_msg_header), 1); \
99 print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
100 16, 4, \
101 ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
102 (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
103 } while (0)
104 #else
105 #define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
106 { \
107 pr_debug(TITLE" type:%s(%d) length:%d\n", \
108 msg_type_names[(MSG)->h.type], \
109 (MSG)->h.type, (MSG_LEN)); \
110 }
111 #endif
112 #else
113 #define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
114 #endif
115
116 struct vchiq_mmal_instance;
117
118 /* normal message context */
119 struct mmal_msg_context {
120 struct vchiq_mmal_instance *instance;
121
122 /* Index in the context_map idr so that we can find the
123 * mmal_msg_context again when servicing the VCHI reply.
124 */
125 int handle;
126
127 union {
128 struct {
129 /* work struct for buffer_cb callback */
130 struct work_struct work;
131 /* work struct for deferred callback */
132 struct work_struct buffer_to_host_work;
133 /* mmal instance */
134 struct vchiq_mmal_instance *instance;
135 /* mmal port */
136 struct vchiq_mmal_port *port;
137 /* actual buffer used to store bulk reply */
138 struct mmal_buffer *buffer;
139 /* amount of buffer used */
140 unsigned long buffer_used;
141 /* MMAL buffer flags */
142 u32 mmal_flags;
143 /* Presentation and Decode timestamps */
144 s64 pts;
145 s64 dts;
146
147 int status; /* context status */
148
149 } bulk; /* bulk data */
150
151 struct {
152 /* message handle to release */
153 struct vchiq_header *msg_handle;
154 /* pointer to received message */
155 struct mmal_msg *msg;
156 /* received message length */
157 u32 msg_len;
158 /* completion upon reply */
159 struct completion cmplt;
160 } sync; /* synchronous response */
161 } u;
162
163 };
164
165 struct vchiq_mmal_instance {
166 unsigned int service_handle;
167
168 /* ensure serialised access to service */
169 struct mutex vchiq_mutex;
170
171 struct idr context_map;
172 /* protect accesses to context_map */
173 struct mutex context_map_lock;
174
175 struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
176
177 /* ordered workqueue to process all bulk operations */
178 struct workqueue_struct *bulk_wq;
179
180 /* handle for a vchiq instance */
181 struct vchiq_instance *vchiq_instance;
182 };
183
184 static struct mmal_msg_context *
get_msg_context(struct vchiq_mmal_instance * instance)185 get_msg_context(struct vchiq_mmal_instance *instance)
186 {
187 struct mmal_msg_context *msg_context;
188 int handle;
189
190 /* todo: should this be allocated from a pool to avoid kzalloc */
191 msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL);
192
193 if (!msg_context)
194 return ERR_PTR(-ENOMEM);
195
196 /* Create an ID that will be passed along with our message so
197 * that when we service the VCHI reply, we can look up what
198 * message is being replied to.
199 */
200 mutex_lock(&instance->context_map_lock);
201 handle = idr_alloc(&instance->context_map, msg_context,
202 0, 0, GFP_KERNEL);
203 mutex_unlock(&instance->context_map_lock);
204
205 if (handle < 0) {
206 kfree(msg_context);
207 return ERR_PTR(handle);
208 }
209
210 msg_context->instance = instance;
211 msg_context->handle = handle;
212
213 return msg_context;
214 }
215
216 static struct mmal_msg_context *
lookup_msg_context(struct vchiq_mmal_instance * instance,int handle)217 lookup_msg_context(struct vchiq_mmal_instance *instance, int handle)
218 {
219 return idr_find(&instance->context_map, handle);
220 }
221
222 static void
release_msg_context(struct mmal_msg_context * msg_context)223 release_msg_context(struct mmal_msg_context *msg_context)
224 {
225 struct vchiq_mmal_instance *instance = msg_context->instance;
226
227 mutex_lock(&instance->context_map_lock);
228 idr_remove(&instance->context_map, msg_context->handle);
229 mutex_unlock(&instance->context_map_lock);
230 kfree(msg_context);
231 }
232
233 /* deals with receipt of event to host message */
event_to_host_cb(struct vchiq_mmal_instance * instance,struct mmal_msg * msg,u32 msg_len)234 static void event_to_host_cb(struct vchiq_mmal_instance *instance,
235 struct mmal_msg *msg, u32 msg_len)
236 {
237 pr_debug("unhandled event\n");
238 pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
239 msg->u.event_to_host.client_component,
240 msg->u.event_to_host.port_type,
241 msg->u.event_to_host.port_num,
242 msg->u.event_to_host.cmd, msg->u.event_to_host.length);
243 }
244
245 /* workqueue scheduled callback
246 *
247 * we do this because it is important we do not call any other vchiq
248 * sync calls from witin the message delivery thread
249 */
buffer_work_cb(struct work_struct * work)250 static void buffer_work_cb(struct work_struct *work)
251 {
252 struct mmal_msg_context *msg_context =
253 container_of(work, struct mmal_msg_context, u.bulk.work);
254 struct mmal_buffer *buffer = msg_context->u.bulk.buffer;
255
256 if (!buffer) {
257 pr_err("%s: ctx: %p, No mmal buffer to pass details\n",
258 __func__, msg_context);
259 return;
260 }
261
262 buffer->length = msg_context->u.bulk.buffer_used;
263 buffer->mmal_flags = msg_context->u.bulk.mmal_flags;
264 buffer->dts = msg_context->u.bulk.dts;
265 buffer->pts = msg_context->u.bulk.pts;
266
267 atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
268
269 msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
270 msg_context->u.bulk.port,
271 msg_context->u.bulk.status,
272 msg_context->u.bulk.buffer);
273 }
274
275 /* workqueue scheduled callback to handle receiving buffers
276 *
277 * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
278 * If we block in the service_callback context then we can't process the
279 * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
280 * vchiq_bulk_receive() call to complete.
281 */
buffer_to_host_work_cb(struct work_struct * work)282 static void buffer_to_host_work_cb(struct work_struct *work)
283 {
284 struct mmal_msg_context *msg_context =
285 container_of(work, struct mmal_msg_context,
286 u.bulk.buffer_to_host_work);
287 struct vchiq_mmal_instance *instance = msg_context->instance;
288 unsigned long len = msg_context->u.bulk.buffer_used;
289 int ret;
290
291 if (!len)
292 /* Dummy receive to ensure the buffers remain in order */
293 len = 8;
294 /* queue the bulk submission */
295 vchiq_use_service(instance->vchiq_instance, instance->service_handle);
296 ret = vchiq_bulk_receive(instance->vchiq_instance, instance->service_handle,
297 msg_context->u.bulk.buffer->buffer,
298 /* Actual receive needs to be a multiple
299 * of 4 bytes
300 */
301 (len + 3) & ~3,
302 msg_context,
303 VCHIQ_BULK_MODE_CALLBACK);
304
305 vchiq_release_service(instance->vchiq_instance, instance->service_handle);
306
307 if (ret != 0)
308 pr_err("%s: ctx: %p, vchiq_bulk_receive failed %d\n",
309 __func__, msg_context, ret);
310 }
311
312 /* enqueue a bulk receive for a given message context */
bulk_receive(struct vchiq_mmal_instance * instance,struct mmal_msg * msg,struct mmal_msg_context * msg_context)313 static int bulk_receive(struct vchiq_mmal_instance *instance,
314 struct mmal_msg *msg,
315 struct mmal_msg_context *msg_context)
316 {
317 unsigned long rd_len;
318
319 rd_len = msg->u.buffer_from_host.buffer_header.length;
320
321 if (!msg_context->u.bulk.buffer) {
322 pr_err("bulk.buffer not configured - error in buffer_from_host\n");
323
324 /* todo: this is a serious error, we should never have
325 * committed a buffer_to_host operation to the mmal
326 * port without the buffer to back it up (underflow
327 * handling) and there is no obvious way to deal with
328 * this - how is the mmal servie going to react when
329 * we fail to do the xfer and reschedule a buffer when
330 * it arrives? perhaps a starved flag to indicate a
331 * waiting bulk receive?
332 */
333
334 return -EINVAL;
335 }
336
337 /* ensure we do not overrun the available buffer */
338 if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
339 rd_len = msg_context->u.bulk.buffer->buffer_size;
340 pr_warn("short read as not enough receive buffer space\n");
341 /* todo: is this the correct response, what happens to
342 * the rest of the message data?
343 */
344 }
345
346 /* store length */
347 msg_context->u.bulk.buffer_used = rd_len;
348 msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
349 msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
350
351 queue_work(msg_context->instance->bulk_wq,
352 &msg_context->u.bulk.buffer_to_host_work);
353
354 return 0;
355 }
356
357 /* data in message, memcpy from packet into output buffer */
inline_receive(struct vchiq_mmal_instance * instance,struct mmal_msg * msg,struct mmal_msg_context * msg_context)358 static int inline_receive(struct vchiq_mmal_instance *instance,
359 struct mmal_msg *msg,
360 struct mmal_msg_context *msg_context)
361 {
362 memcpy(msg_context->u.bulk.buffer->buffer,
363 msg->u.buffer_from_host.short_data,
364 msg->u.buffer_from_host.payload_in_message);
365
366 msg_context->u.bulk.buffer_used =
367 msg->u.buffer_from_host.payload_in_message;
368
369 return 0;
370 }
371
372 /* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
373 static int
buffer_from_host(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,struct mmal_buffer * buf)374 buffer_from_host(struct vchiq_mmal_instance *instance,
375 struct vchiq_mmal_port *port, struct mmal_buffer *buf)
376 {
377 struct mmal_msg_context *msg_context;
378 struct mmal_msg m;
379 int ret;
380
381 if (!port->enabled)
382 return -EINVAL;
383
384 pr_debug("instance:%u buffer:%p\n", instance->service_handle, buf);
385
386 /* get context */
387 if (!buf->msg_context) {
388 pr_err("%s: msg_context not allocated, buf %p\n", __func__,
389 buf);
390 return -EINVAL;
391 }
392 msg_context = buf->msg_context;
393
394 /* store bulk message context for when data arrives */
395 msg_context->u.bulk.instance = instance;
396 msg_context->u.bulk.port = port;
397 msg_context->u.bulk.buffer = buf;
398 msg_context->u.bulk.buffer_used = 0;
399
400 /* initialise work structure ready to schedule callback */
401 INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
402 INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
403 buffer_to_host_work_cb);
404
405 atomic_inc(&port->buffers_with_vpu);
406
407 /* prep the buffer from host message */
408 memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
409
410 m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
411 m.h.magic = MMAL_MAGIC;
412 m.h.context = msg_context->handle;
413 m.h.status = 0;
414
415 /* drvbuf is our private data passed back */
416 m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
417 m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
418 m.u.buffer_from_host.drvbuf.port_handle = port->handle;
419 m.u.buffer_from_host.drvbuf.client_context = msg_context->handle;
420
421 /* buffer header */
422 m.u.buffer_from_host.buffer_header.cmd = 0;
423 m.u.buffer_from_host.buffer_header.data =
424 (u32)(unsigned long)buf->buffer;
425 m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
426 m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
427 m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
428 m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
429 m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
430 m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
431
432 /* clear buffer type specific data */
433 memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
434 sizeof(m.u.buffer_from_host.buffer_header_type_specific));
435
436 /* no payload in message */
437 m.u.buffer_from_host.payload_in_message = 0;
438
439 vchiq_use_service(instance->vchiq_instance, instance->service_handle);
440
441 ret = vchiq_queue_kernel_message(instance->vchiq_instance, instance->service_handle, &m,
442 sizeof(struct mmal_msg_header) +
443 sizeof(m.u.buffer_from_host));
444 if (ret)
445 atomic_dec(&port->buffers_with_vpu);
446
447 vchiq_release_service(instance->vchiq_instance, instance->service_handle);
448
449 return ret;
450 }
451
452 /* deals with receipt of buffer to host message */
buffer_to_host_cb(struct vchiq_mmal_instance * instance,struct mmal_msg * msg,u32 msg_len)453 static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
454 struct mmal_msg *msg, u32 msg_len)
455 {
456 struct mmal_msg_context *msg_context;
457 u32 handle;
458
459 pr_debug("%s: instance:%p msg:%p msg_len:%d\n",
460 __func__, instance, msg, msg_len);
461
462 if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
463 handle = msg->u.buffer_from_host.drvbuf.client_context;
464 msg_context = lookup_msg_context(instance, handle);
465
466 if (!msg_context) {
467 pr_err("drvbuf.client_context(%u) is invalid\n",
468 handle);
469 return;
470 }
471 } else {
472 pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
473 return;
474 }
475
476 msg_context->u.bulk.mmal_flags =
477 msg->u.buffer_from_host.buffer_header.flags;
478
479 if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
480 /* message reception had an error */
481 pr_warn("error %d in reply\n", msg->h.status);
482
483 msg_context->u.bulk.status = msg->h.status;
484
485 } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
486 /* empty buffer */
487 if (msg->u.buffer_from_host.buffer_header.flags &
488 MMAL_BUFFER_HEADER_FLAG_EOS) {
489 msg_context->u.bulk.status =
490 bulk_receive(instance, msg, msg_context);
491 if (msg_context->u.bulk.status == 0)
492 return; /* successful bulk submission, bulk
493 * completion will trigger callback
494 */
495 } else {
496 /* do callback with empty buffer - not EOS though */
497 msg_context->u.bulk.status = 0;
498 msg_context->u.bulk.buffer_used = 0;
499 }
500 } else if (msg->u.buffer_from_host.payload_in_message == 0) {
501 /* data is not in message, queue a bulk receive */
502 msg_context->u.bulk.status =
503 bulk_receive(instance, msg, msg_context);
504 if (msg_context->u.bulk.status == 0)
505 return; /* successful bulk submission, bulk
506 * completion will trigger callback
507 */
508
509 /* failed to submit buffer, this will end badly */
510 pr_err("error %d on bulk submission\n",
511 msg_context->u.bulk.status);
512
513 } else if (msg->u.buffer_from_host.payload_in_message <=
514 MMAL_VC_SHORT_DATA) {
515 /* data payload within message */
516 msg_context->u.bulk.status = inline_receive(instance, msg,
517 msg_context);
518 } else {
519 pr_err("message with invalid short payload\n");
520
521 /* signal error */
522 msg_context->u.bulk.status = -EINVAL;
523 msg_context->u.bulk.buffer_used =
524 msg->u.buffer_from_host.payload_in_message;
525 }
526
527 /* schedule the port callback */
528 schedule_work(&msg_context->u.bulk.work);
529 }
530
bulk_receive_cb(struct vchiq_mmal_instance * instance,struct mmal_msg_context * msg_context)531 static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
532 struct mmal_msg_context *msg_context)
533 {
534 msg_context->u.bulk.status = 0;
535
536 /* schedule the port callback */
537 schedule_work(&msg_context->u.bulk.work);
538 }
539
bulk_abort_cb(struct vchiq_mmal_instance * instance,struct mmal_msg_context * msg_context)540 static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
541 struct mmal_msg_context *msg_context)
542 {
543 pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
544
545 msg_context->u.bulk.status = -EINTR;
546
547 schedule_work(&msg_context->u.bulk.work);
548 }
549
550 /* incoming event service callback */
service_callback(struct vchiq_instance * vchiq_instance,enum vchiq_reason reason,struct vchiq_header * header,unsigned int handle,void * bulk_ctx)551 static enum vchiq_status service_callback(struct vchiq_instance *vchiq_instance,
552 enum vchiq_reason reason,
553 struct vchiq_header *header,
554 unsigned int handle, void *bulk_ctx)
555 {
556 struct vchiq_mmal_instance *instance = vchiq_get_service_userdata(vchiq_instance, handle);
557 u32 msg_len;
558 struct mmal_msg *msg;
559 struct mmal_msg_context *msg_context;
560
561 if (!instance) {
562 pr_err("Message callback passed NULL instance\n");
563 return VCHIQ_SUCCESS;
564 }
565
566 switch (reason) {
567 case VCHIQ_MESSAGE_AVAILABLE:
568 msg = (void *)header->data;
569 msg_len = header->size;
570
571 DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
572
573 /* handling is different for buffer messages */
574 switch (msg->h.type) {
575 case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
576 vchiq_release_message(vchiq_instance, handle, header);
577 break;
578
579 case MMAL_MSG_TYPE_EVENT_TO_HOST:
580 event_to_host_cb(instance, msg, msg_len);
581 vchiq_release_message(vchiq_instance, handle, header);
582
583 break;
584
585 case MMAL_MSG_TYPE_BUFFER_TO_HOST:
586 buffer_to_host_cb(instance, msg, msg_len);
587 vchiq_release_message(vchiq_instance, handle, header);
588 break;
589
590 default:
591 /* messages dependent on header context to complete */
592 if (!msg->h.context) {
593 pr_err("received message context was null!\n");
594 vchiq_release_message(vchiq_instance, handle, header);
595 break;
596 }
597
598 msg_context = lookup_msg_context(instance,
599 msg->h.context);
600 if (!msg_context) {
601 pr_err("received invalid message context %u!\n",
602 msg->h.context);
603 vchiq_release_message(vchiq_instance, handle, header);
604 break;
605 }
606
607 /* fill in context values */
608 msg_context->u.sync.msg_handle = header;
609 msg_context->u.sync.msg = msg;
610 msg_context->u.sync.msg_len = msg_len;
611
612 /* todo: should this check (completion_done()
613 * == 1) for no one waiting? or do we need a
614 * flag to tell us the completion has been
615 * interrupted so we can free the message and
616 * its context. This probably also solves the
617 * message arriving after interruption todo
618 * below
619 */
620
621 /* complete message so caller knows it happened */
622 complete(&msg_context->u.sync.cmplt);
623 break;
624 }
625
626 break;
627
628 case VCHIQ_BULK_RECEIVE_DONE:
629 bulk_receive_cb(instance, bulk_ctx);
630 break;
631
632 case VCHIQ_BULK_RECEIVE_ABORTED:
633 bulk_abort_cb(instance, bulk_ctx);
634 break;
635
636 case VCHIQ_SERVICE_CLOSED:
637 /* TODO: consider if this requires action if received when
638 * driver is not explicitly closing the service
639 */
640 break;
641
642 default:
643 pr_err("Received unhandled message reason %d\n", reason);
644 break;
645 }
646
647 return VCHIQ_SUCCESS;
648 }
649
send_synchronous_mmal_msg(struct vchiq_mmal_instance * instance,struct mmal_msg * msg,unsigned int payload_len,struct mmal_msg ** msg_out,struct vchiq_header ** msg_handle)650 static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
651 struct mmal_msg *msg,
652 unsigned int payload_len,
653 struct mmal_msg **msg_out,
654 struct vchiq_header **msg_handle)
655 {
656 struct mmal_msg_context *msg_context;
657 int ret;
658 unsigned long timeout;
659
660 /* payload size must not cause message to exceed max size */
661 if (payload_len >
662 (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
663 pr_err("payload length %d exceeds max:%d\n", payload_len,
664 (int)(MMAL_MSG_MAX_SIZE -
665 sizeof(struct mmal_msg_header)));
666 return -EINVAL;
667 }
668
669 msg_context = get_msg_context(instance);
670 if (IS_ERR(msg_context))
671 return PTR_ERR(msg_context);
672
673 init_completion(&msg_context->u.sync.cmplt);
674
675 msg->h.magic = MMAL_MAGIC;
676 msg->h.context = msg_context->handle;
677 msg->h.status = 0;
678
679 DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
680 ">>> sync message");
681
682 vchiq_use_service(instance->vchiq_instance, instance->service_handle);
683
684 ret = vchiq_queue_kernel_message(instance->vchiq_instance, instance->service_handle, msg,
685 sizeof(struct mmal_msg_header) +
686 payload_len);
687
688 vchiq_release_service(instance->vchiq_instance, instance->service_handle);
689
690 if (ret) {
691 pr_err("error %d queuing message\n", ret);
692 release_msg_context(msg_context);
693 return ret;
694 }
695
696 timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt,
697 SYNC_MSG_TIMEOUT * HZ);
698 if (timeout == 0) {
699 pr_err("timed out waiting for sync completion\n");
700 ret = -ETIME;
701 /* todo: what happens if the message arrives after aborting */
702 release_msg_context(msg_context);
703 return ret;
704 }
705
706 *msg_out = msg_context->u.sync.msg;
707 *msg_handle = msg_context->u.sync.msg_handle;
708 release_msg_context(msg_context);
709
710 return 0;
711 }
712
dump_port_info(struct vchiq_mmal_port * port)713 static void dump_port_info(struct vchiq_mmal_port *port)
714 {
715 pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
716
717 pr_debug("buffer minimum num:%d size:%d align:%d\n",
718 port->minimum_buffer.num,
719 port->minimum_buffer.size, port->minimum_buffer.alignment);
720
721 pr_debug("buffer recommended num:%d size:%d align:%d\n",
722 port->recommended_buffer.num,
723 port->recommended_buffer.size,
724 port->recommended_buffer.alignment);
725
726 pr_debug("buffer current values num:%d size:%d align:%d\n",
727 port->current_buffer.num,
728 port->current_buffer.size, port->current_buffer.alignment);
729
730 pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n",
731 port->format.type,
732 port->format.encoding, port->format.encoding_variant);
733
734 pr_debug(" bitrate:%d flags:0x%x\n",
735 port->format.bitrate, port->format.flags);
736
737 if (port->format.type == MMAL_ES_TYPE_VIDEO) {
738 pr_debug
739 ("es video format: width:%d height:%d colourspace:0x%x\n",
740 port->es.video.width, port->es.video.height,
741 port->es.video.color_space);
742
743 pr_debug(" : crop xywh %d,%d,%d,%d\n",
744 port->es.video.crop.x,
745 port->es.video.crop.y,
746 port->es.video.crop.width, port->es.video.crop.height);
747 pr_debug(" : framerate %d/%d aspect %d/%d\n",
748 port->es.video.frame_rate.numerator,
749 port->es.video.frame_rate.denominator,
750 port->es.video.par.numerator, port->es.video.par.denominator);
751 }
752 }
753
port_to_mmal_msg(struct vchiq_mmal_port * port,struct mmal_port * p)754 static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
755 {
756 /* todo do readonly fields need setting at all? */
757 p->type = port->type;
758 p->index = port->index;
759 p->index_all = 0;
760 p->is_enabled = port->enabled;
761 p->buffer_num_min = port->minimum_buffer.num;
762 p->buffer_size_min = port->minimum_buffer.size;
763 p->buffer_alignment_min = port->minimum_buffer.alignment;
764 p->buffer_num_recommended = port->recommended_buffer.num;
765 p->buffer_size_recommended = port->recommended_buffer.size;
766
767 /* only three writable fields in a port */
768 p->buffer_num = port->current_buffer.num;
769 p->buffer_size = port->current_buffer.size;
770 p->userdata = (u32)(unsigned long)port;
771 }
772
port_info_set(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port)773 static int port_info_set(struct vchiq_mmal_instance *instance,
774 struct vchiq_mmal_port *port)
775 {
776 int ret;
777 struct mmal_msg m;
778 struct mmal_msg *rmsg;
779 struct vchiq_header *rmsg_handle;
780
781 pr_debug("setting port info port %p\n", port);
782 if (!port)
783 return -1;
784 dump_port_info(port);
785
786 m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
787
788 m.u.port_info_set.component_handle = port->component->handle;
789 m.u.port_info_set.port_type = port->type;
790 m.u.port_info_set.port_index = port->index;
791
792 port_to_mmal_msg(port, &m.u.port_info_set.port);
793
794 /* elementary stream format setup */
795 m.u.port_info_set.format.type = port->format.type;
796 m.u.port_info_set.format.encoding = port->format.encoding;
797 m.u.port_info_set.format.encoding_variant =
798 port->format.encoding_variant;
799 m.u.port_info_set.format.bitrate = port->format.bitrate;
800 m.u.port_info_set.format.flags = port->format.flags;
801
802 memcpy(&m.u.port_info_set.es, &port->es,
803 sizeof(union mmal_es_specific_format));
804
805 m.u.port_info_set.format.extradata_size = port->format.extradata_size;
806 memcpy(&m.u.port_info_set.extradata, port->format.extradata,
807 port->format.extradata_size);
808
809 ret = send_synchronous_mmal_msg(instance, &m,
810 sizeof(m.u.port_info_set),
811 &rmsg, &rmsg_handle);
812 if (ret)
813 return ret;
814
815 if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
816 /* got an unexpected message type in reply */
817 ret = -EINVAL;
818 goto release_msg;
819 }
820
821 /* return operation status */
822 ret = -rmsg->u.port_info_get_reply.status;
823
824 pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
825 port->component->handle, port->handle);
826
827 release_msg:
828 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
829
830 return ret;
831 }
832
833 /* use port info get message to retrieve port information */
port_info_get(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port)834 static int port_info_get(struct vchiq_mmal_instance *instance,
835 struct vchiq_mmal_port *port)
836 {
837 int ret;
838 struct mmal_msg m;
839 struct mmal_msg *rmsg;
840 struct vchiq_header *rmsg_handle;
841
842 /* port info time */
843 m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
844 m.u.port_info_get.component_handle = port->component->handle;
845 m.u.port_info_get.port_type = port->type;
846 m.u.port_info_get.index = port->index;
847
848 ret = send_synchronous_mmal_msg(instance, &m,
849 sizeof(m.u.port_info_get),
850 &rmsg, &rmsg_handle);
851 if (ret)
852 return ret;
853
854 if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
855 /* got an unexpected message type in reply */
856 ret = -EINVAL;
857 goto release_msg;
858 }
859
860 /* return operation status */
861 ret = -rmsg->u.port_info_get_reply.status;
862 if (ret != MMAL_MSG_STATUS_SUCCESS)
863 goto release_msg;
864
865 if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
866 port->enabled = 0;
867 else
868 port->enabled = 1;
869
870 /* copy the values out of the message */
871 port->handle = rmsg->u.port_info_get_reply.port_handle;
872
873 /* port type and index cached to use on port info set because
874 * it does not use a port handle
875 */
876 port->type = rmsg->u.port_info_get_reply.port_type;
877 port->index = rmsg->u.port_info_get_reply.port_index;
878
879 port->minimum_buffer.num =
880 rmsg->u.port_info_get_reply.port.buffer_num_min;
881 port->minimum_buffer.size =
882 rmsg->u.port_info_get_reply.port.buffer_size_min;
883 port->minimum_buffer.alignment =
884 rmsg->u.port_info_get_reply.port.buffer_alignment_min;
885
886 port->recommended_buffer.alignment =
887 rmsg->u.port_info_get_reply.port.buffer_alignment_min;
888 port->recommended_buffer.num =
889 rmsg->u.port_info_get_reply.port.buffer_num_recommended;
890
891 port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
892 port->current_buffer.size =
893 rmsg->u.port_info_get_reply.port.buffer_size;
894
895 /* stream format */
896 port->format.type = rmsg->u.port_info_get_reply.format.type;
897 port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
898 port->format.encoding_variant =
899 rmsg->u.port_info_get_reply.format.encoding_variant;
900 port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
901 port->format.flags = rmsg->u.port_info_get_reply.format.flags;
902
903 /* elementary stream format */
904 memcpy(&port->es,
905 &rmsg->u.port_info_get_reply.es,
906 sizeof(union mmal_es_specific_format));
907 port->format.es = &port->es;
908
909 port->format.extradata_size =
910 rmsg->u.port_info_get_reply.format.extradata_size;
911 memcpy(port->format.extradata,
912 rmsg->u.port_info_get_reply.extradata,
913 port->format.extradata_size);
914
915 pr_debug("received port info\n");
916 dump_port_info(port);
917
918 release_msg:
919
920 pr_debug("%s:result:%d component:0x%x port:%d\n",
921 __func__, ret, port->component->handle, port->handle);
922
923 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
924
925 return ret;
926 }
927
928 /* create component on vc */
create_component(struct vchiq_mmal_instance * instance,struct vchiq_mmal_component * component,const char * name)929 static int create_component(struct vchiq_mmal_instance *instance,
930 struct vchiq_mmal_component *component,
931 const char *name)
932 {
933 int ret;
934 struct mmal_msg m;
935 struct mmal_msg *rmsg;
936 struct vchiq_header *rmsg_handle;
937
938 /* build component create message */
939 m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
940 m.u.component_create.client_component = component->client_component;
941 strncpy(m.u.component_create.name, name,
942 sizeof(m.u.component_create.name));
943
944 ret = send_synchronous_mmal_msg(instance, &m,
945 sizeof(m.u.component_create),
946 &rmsg, &rmsg_handle);
947 if (ret)
948 return ret;
949
950 if (rmsg->h.type != m.h.type) {
951 /* got an unexpected message type in reply */
952 ret = -EINVAL;
953 goto release_msg;
954 }
955
956 ret = -rmsg->u.component_create_reply.status;
957 if (ret != MMAL_MSG_STATUS_SUCCESS)
958 goto release_msg;
959
960 /* a valid component response received */
961 component->handle = rmsg->u.component_create_reply.component_handle;
962 component->inputs = rmsg->u.component_create_reply.input_num;
963 component->outputs = rmsg->u.component_create_reply.output_num;
964 component->clocks = rmsg->u.component_create_reply.clock_num;
965
966 pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
967 component->handle,
968 component->inputs, component->outputs, component->clocks);
969
970 release_msg:
971 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
972
973 return ret;
974 }
975
976 /* destroys a component on vc */
destroy_component(struct vchiq_mmal_instance * instance,struct vchiq_mmal_component * component)977 static int destroy_component(struct vchiq_mmal_instance *instance,
978 struct vchiq_mmal_component *component)
979 {
980 int ret;
981 struct mmal_msg m;
982 struct mmal_msg *rmsg;
983 struct vchiq_header *rmsg_handle;
984
985 m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
986 m.u.component_destroy.component_handle = component->handle;
987
988 ret = send_synchronous_mmal_msg(instance, &m,
989 sizeof(m.u.component_destroy),
990 &rmsg, &rmsg_handle);
991 if (ret)
992 return ret;
993
994 if (rmsg->h.type != m.h.type) {
995 /* got an unexpected message type in reply */
996 ret = -EINVAL;
997 goto release_msg;
998 }
999
1000 ret = -rmsg->u.component_destroy_reply.status;
1001
1002 release_msg:
1003
1004 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
1005
1006 return ret;
1007 }
1008
1009 /* enable a component on vc */
enable_component(struct vchiq_mmal_instance * instance,struct vchiq_mmal_component * component)1010 static int enable_component(struct vchiq_mmal_instance *instance,
1011 struct vchiq_mmal_component *component)
1012 {
1013 int ret;
1014 struct mmal_msg m;
1015 struct mmal_msg *rmsg;
1016 struct vchiq_header *rmsg_handle;
1017
1018 m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
1019 m.u.component_enable.component_handle = component->handle;
1020
1021 ret = send_synchronous_mmal_msg(instance, &m,
1022 sizeof(m.u.component_enable),
1023 &rmsg, &rmsg_handle);
1024 if (ret)
1025 return ret;
1026
1027 if (rmsg->h.type != m.h.type) {
1028 /* got an unexpected message type in reply */
1029 ret = -EINVAL;
1030 goto release_msg;
1031 }
1032
1033 ret = -rmsg->u.component_enable_reply.status;
1034
1035 release_msg:
1036 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
1037
1038 return ret;
1039 }
1040
1041 /* disable a component on vc */
disable_component(struct vchiq_mmal_instance * instance,struct vchiq_mmal_component * component)1042 static int disable_component(struct vchiq_mmal_instance *instance,
1043 struct vchiq_mmal_component *component)
1044 {
1045 int ret;
1046 struct mmal_msg m;
1047 struct mmal_msg *rmsg;
1048 struct vchiq_header *rmsg_handle;
1049
1050 m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
1051 m.u.component_disable.component_handle = component->handle;
1052
1053 ret = send_synchronous_mmal_msg(instance, &m,
1054 sizeof(m.u.component_disable),
1055 &rmsg, &rmsg_handle);
1056 if (ret)
1057 return ret;
1058
1059 if (rmsg->h.type != m.h.type) {
1060 /* got an unexpected message type in reply */
1061 ret = -EINVAL;
1062 goto release_msg;
1063 }
1064
1065 ret = -rmsg->u.component_disable_reply.status;
1066
1067 release_msg:
1068
1069 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
1070
1071 return ret;
1072 }
1073
1074 /* get version of mmal implementation */
get_version(struct vchiq_mmal_instance * instance,u32 * major_out,u32 * minor_out)1075 static int get_version(struct vchiq_mmal_instance *instance,
1076 u32 *major_out, u32 *minor_out)
1077 {
1078 int ret;
1079 struct mmal_msg m;
1080 struct mmal_msg *rmsg;
1081 struct vchiq_header *rmsg_handle;
1082
1083 m.h.type = MMAL_MSG_TYPE_GET_VERSION;
1084
1085 ret = send_synchronous_mmal_msg(instance, &m,
1086 sizeof(m.u.version),
1087 &rmsg, &rmsg_handle);
1088 if (ret)
1089 return ret;
1090
1091 if (rmsg->h.type != m.h.type) {
1092 /* got an unexpected message type in reply */
1093 ret = -EINVAL;
1094 goto release_msg;
1095 }
1096
1097 *major_out = rmsg->u.version.major;
1098 *minor_out = rmsg->u.version.minor;
1099
1100 release_msg:
1101 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
1102
1103 return ret;
1104 }
1105
1106 /* do a port action with a port as a parameter */
port_action_port(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,enum mmal_msg_port_action_type action_type)1107 static int port_action_port(struct vchiq_mmal_instance *instance,
1108 struct vchiq_mmal_port *port,
1109 enum mmal_msg_port_action_type action_type)
1110 {
1111 int ret;
1112 struct mmal_msg m;
1113 struct mmal_msg *rmsg;
1114 struct vchiq_header *rmsg_handle;
1115
1116 m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
1117 m.u.port_action_port.component_handle = port->component->handle;
1118 m.u.port_action_port.port_handle = port->handle;
1119 m.u.port_action_port.action = action_type;
1120
1121 port_to_mmal_msg(port, &m.u.port_action_port.port);
1122
1123 ret = send_synchronous_mmal_msg(instance, &m,
1124 sizeof(m.u.port_action_port),
1125 &rmsg, &rmsg_handle);
1126 if (ret)
1127 return ret;
1128
1129 if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
1130 /* got an unexpected message type in reply */
1131 ret = -EINVAL;
1132 goto release_msg;
1133 }
1134
1135 ret = -rmsg->u.port_action_reply.status;
1136
1137 pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
1138 __func__,
1139 ret, port->component->handle, port->handle,
1140 port_action_type_names[action_type], action_type);
1141
1142 release_msg:
1143 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
1144
1145 return ret;
1146 }
1147
1148 /* do a port action with handles as parameters */
port_action_handle(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,enum mmal_msg_port_action_type action_type,u32 connect_component_handle,u32 connect_port_handle)1149 static int port_action_handle(struct vchiq_mmal_instance *instance,
1150 struct vchiq_mmal_port *port,
1151 enum mmal_msg_port_action_type action_type,
1152 u32 connect_component_handle,
1153 u32 connect_port_handle)
1154 {
1155 int ret;
1156 struct mmal_msg m;
1157 struct mmal_msg *rmsg;
1158 struct vchiq_header *rmsg_handle;
1159
1160 m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
1161
1162 m.u.port_action_handle.component_handle = port->component->handle;
1163 m.u.port_action_handle.port_handle = port->handle;
1164 m.u.port_action_handle.action = action_type;
1165
1166 m.u.port_action_handle.connect_component_handle =
1167 connect_component_handle;
1168 m.u.port_action_handle.connect_port_handle = connect_port_handle;
1169
1170 ret = send_synchronous_mmal_msg(instance, &m,
1171 sizeof(m.u.port_action_handle),
1172 &rmsg, &rmsg_handle);
1173 if (ret)
1174 return ret;
1175
1176 if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
1177 /* got an unexpected message type in reply */
1178 ret = -EINVAL;
1179 goto release_msg;
1180 }
1181
1182 ret = -rmsg->u.port_action_reply.status;
1183
1184 pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n",
1185 __func__,
1186 ret, port->component->handle, port->handle,
1187 port_action_type_names[action_type],
1188 action_type, connect_component_handle, connect_port_handle);
1189
1190 release_msg:
1191 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
1192
1193 return ret;
1194 }
1195
port_parameter_set(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,u32 parameter_id,void * value,u32 value_size)1196 static int port_parameter_set(struct vchiq_mmal_instance *instance,
1197 struct vchiq_mmal_port *port,
1198 u32 parameter_id, void *value, u32 value_size)
1199 {
1200 int ret;
1201 struct mmal_msg m;
1202 struct mmal_msg *rmsg;
1203 struct vchiq_header *rmsg_handle;
1204
1205 m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
1206
1207 m.u.port_parameter_set.component_handle = port->component->handle;
1208 m.u.port_parameter_set.port_handle = port->handle;
1209 m.u.port_parameter_set.id = parameter_id;
1210 m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
1211 memcpy(&m.u.port_parameter_set.value, value, value_size);
1212
1213 ret = send_synchronous_mmal_msg(instance, &m,
1214 (4 * sizeof(u32)) + value_size,
1215 &rmsg, &rmsg_handle);
1216 if (ret)
1217 return ret;
1218
1219 if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
1220 /* got an unexpected message type in reply */
1221 ret = -EINVAL;
1222 goto release_msg;
1223 }
1224
1225 ret = -rmsg->u.port_parameter_set_reply.status;
1226
1227 pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
1228 __func__,
1229 ret, port->component->handle, port->handle, parameter_id);
1230
1231 release_msg:
1232 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
1233
1234 return ret;
1235 }
1236
port_parameter_get(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,u32 parameter_id,void * value,u32 * value_size)1237 static int port_parameter_get(struct vchiq_mmal_instance *instance,
1238 struct vchiq_mmal_port *port,
1239 u32 parameter_id, void *value, u32 *value_size)
1240 {
1241 int ret;
1242 struct mmal_msg m;
1243 struct mmal_msg *rmsg;
1244 struct vchiq_header *rmsg_handle;
1245
1246 m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
1247
1248 m.u.port_parameter_get.component_handle = port->component->handle;
1249 m.u.port_parameter_get.port_handle = port->handle;
1250 m.u.port_parameter_get.id = parameter_id;
1251 m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
1252
1253 ret = send_synchronous_mmal_msg(instance, &m,
1254 sizeof(struct
1255 mmal_msg_port_parameter_get),
1256 &rmsg, &rmsg_handle);
1257 if (ret)
1258 return ret;
1259
1260 if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
1261 /* got an unexpected message type in reply */
1262 pr_err("Incorrect reply type %d\n", rmsg->h.type);
1263 ret = -EINVAL;
1264 goto release_msg;
1265 }
1266
1267 ret = rmsg->u.port_parameter_get_reply.status;
1268
1269 /* port_parameter_get_reply.size includes the header,
1270 * whilst *value_size doesn't.
1271 */
1272 rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32));
1273
1274 if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) {
1275 /* Copy only as much as we have space for
1276 * but report true size of parameter
1277 */
1278 memcpy(value, &rmsg->u.port_parameter_get_reply.value,
1279 *value_size);
1280 } else {
1281 memcpy(value, &rmsg->u.port_parameter_get_reply.value,
1282 rmsg->u.port_parameter_get_reply.size);
1283 }
1284 /* Always report the size of the returned parameter to the caller */
1285 *value_size = rmsg->u.port_parameter_get_reply.size;
1286
1287 pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
1288 ret, port->component->handle, port->handle, parameter_id);
1289
1290 release_msg:
1291 vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle);
1292
1293 return ret;
1294 }
1295
1296 /* disables a port and drains buffers from it */
port_disable(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port)1297 static int port_disable(struct vchiq_mmal_instance *instance,
1298 struct vchiq_mmal_port *port)
1299 {
1300 int ret;
1301 struct list_head *q, *buf_head;
1302 unsigned long flags = 0;
1303
1304 if (!port->enabled)
1305 return 0;
1306
1307 port->enabled = 0;
1308
1309 ret = port_action_port(instance, port,
1310 MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
1311 if (ret == 0) {
1312 /*
1313 * Drain all queued buffers on port. This should only
1314 * apply to buffers that have been queued before the port
1315 * has been enabled. If the port has been enabled and buffers
1316 * passed, then the buffers should have been removed from this
1317 * list, and we should get the relevant callbacks via VCHIQ
1318 * to release the buffers.
1319 */
1320 spin_lock_irqsave(&port->slock, flags);
1321
1322 list_for_each_safe(buf_head, q, &port->buffers) {
1323 struct mmal_buffer *mmalbuf;
1324
1325 mmalbuf = list_entry(buf_head, struct mmal_buffer,
1326 list);
1327 list_del(buf_head);
1328 if (port->buffer_cb) {
1329 mmalbuf->length = 0;
1330 mmalbuf->mmal_flags = 0;
1331 mmalbuf->dts = MMAL_TIME_UNKNOWN;
1332 mmalbuf->pts = MMAL_TIME_UNKNOWN;
1333 port->buffer_cb(instance,
1334 port, 0, mmalbuf);
1335 }
1336 }
1337
1338 spin_unlock_irqrestore(&port->slock, flags);
1339
1340 ret = port_info_get(instance, port);
1341 }
1342
1343 return ret;
1344 }
1345
1346 /* enable a port */
port_enable(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port)1347 static int port_enable(struct vchiq_mmal_instance *instance,
1348 struct vchiq_mmal_port *port)
1349 {
1350 unsigned int hdr_count;
1351 struct list_head *q, *buf_head;
1352 int ret;
1353
1354 if (port->enabled)
1355 return 0;
1356
1357 ret = port_action_port(instance, port,
1358 MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
1359 if (ret)
1360 goto done;
1361
1362 port->enabled = 1;
1363
1364 if (port->buffer_cb) {
1365 /* send buffer headers to videocore */
1366 hdr_count = 1;
1367 list_for_each_safe(buf_head, q, &port->buffers) {
1368 struct mmal_buffer *mmalbuf;
1369
1370 mmalbuf = list_entry(buf_head, struct mmal_buffer,
1371 list);
1372 ret = buffer_from_host(instance, port, mmalbuf);
1373 if (ret)
1374 goto done;
1375
1376 list_del(buf_head);
1377 hdr_count++;
1378 if (hdr_count > port->current_buffer.num)
1379 break;
1380 }
1381 }
1382
1383 ret = port_info_get(instance, port);
1384
1385 done:
1386 return ret;
1387 }
1388
1389 /* ------------------------------------------------------------------
1390 * Exported API
1391 *------------------------------------------------------------------
1392 */
1393
vchiq_mmal_port_set_format(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port)1394 int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
1395 struct vchiq_mmal_port *port)
1396 {
1397 int ret;
1398
1399 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1400 return -EINTR;
1401
1402 ret = port_info_set(instance, port);
1403 if (ret)
1404 goto release_unlock;
1405
1406 /* read what has actually been set */
1407 ret = port_info_get(instance, port);
1408
1409 release_unlock:
1410 mutex_unlock(&instance->vchiq_mutex);
1411
1412 return ret;
1413 }
1414 EXPORT_SYMBOL_GPL(vchiq_mmal_port_set_format);
1415
vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,u32 parameter,void * value,u32 value_size)1416 int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
1417 struct vchiq_mmal_port *port,
1418 u32 parameter, void *value, u32 value_size)
1419 {
1420 int ret;
1421
1422 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1423 return -EINTR;
1424
1425 ret = port_parameter_set(instance, port, parameter, value, value_size);
1426
1427 mutex_unlock(&instance->vchiq_mutex);
1428
1429 return ret;
1430 }
1431 EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set);
1432
vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,u32 parameter,void * value,u32 * value_size)1433 int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
1434 struct vchiq_mmal_port *port,
1435 u32 parameter, void *value, u32 *value_size)
1436 {
1437 int ret;
1438
1439 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1440 return -EINTR;
1441
1442 ret = port_parameter_get(instance, port, parameter, value, value_size);
1443
1444 mutex_unlock(&instance->vchiq_mutex);
1445
1446 return ret;
1447 }
1448 EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_get);
1449
1450 /* enable a port
1451 *
1452 * enables a port and queues buffers for satisfying callbacks if we
1453 * provide a callback handler
1454 */
vchiq_mmal_port_enable(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,vchiq_mmal_buffer_cb buffer_cb)1455 int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
1456 struct vchiq_mmal_port *port,
1457 vchiq_mmal_buffer_cb buffer_cb)
1458 {
1459 int ret;
1460
1461 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1462 return -EINTR;
1463
1464 /* already enabled - noop */
1465 if (port->enabled) {
1466 ret = 0;
1467 goto unlock;
1468 }
1469
1470 port->buffer_cb = buffer_cb;
1471
1472 ret = port_enable(instance, port);
1473
1474 unlock:
1475 mutex_unlock(&instance->vchiq_mutex);
1476
1477 return ret;
1478 }
1479 EXPORT_SYMBOL_GPL(vchiq_mmal_port_enable);
1480
vchiq_mmal_port_disable(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port)1481 int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
1482 struct vchiq_mmal_port *port)
1483 {
1484 int ret;
1485
1486 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1487 return -EINTR;
1488
1489 if (!port->enabled) {
1490 mutex_unlock(&instance->vchiq_mutex);
1491 return 0;
1492 }
1493
1494 ret = port_disable(instance, port);
1495
1496 mutex_unlock(&instance->vchiq_mutex);
1497
1498 return ret;
1499 }
1500 EXPORT_SYMBOL_GPL(vchiq_mmal_port_disable);
1501
1502 /* ports will be connected in a tunneled manner so data buffers
1503 * are not handled by client.
1504 */
vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * src,struct vchiq_mmal_port * dst)1505 int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
1506 struct vchiq_mmal_port *src,
1507 struct vchiq_mmal_port *dst)
1508 {
1509 int ret;
1510
1511 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1512 return -EINTR;
1513
1514 /* disconnect ports if connected */
1515 if (src->connected) {
1516 ret = port_disable(instance, src);
1517 if (ret) {
1518 pr_err("failed disabling src port(%d)\n", ret);
1519 goto release_unlock;
1520 }
1521
1522 /* do not need to disable the destination port as they
1523 * are connected and it is done automatically
1524 */
1525
1526 ret = port_action_handle(instance, src,
1527 MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
1528 src->connected->component->handle,
1529 src->connected->handle);
1530 if (ret < 0) {
1531 pr_err("failed disconnecting src port\n");
1532 goto release_unlock;
1533 }
1534 src->connected->enabled = 0;
1535 src->connected = NULL;
1536 }
1537
1538 if (!dst) {
1539 /* do not make new connection */
1540 ret = 0;
1541 pr_debug("not making new connection\n");
1542 goto release_unlock;
1543 }
1544
1545 /* copy src port format to dst */
1546 dst->format.encoding = src->format.encoding;
1547 dst->es.video.width = src->es.video.width;
1548 dst->es.video.height = src->es.video.height;
1549 dst->es.video.crop.x = src->es.video.crop.x;
1550 dst->es.video.crop.y = src->es.video.crop.y;
1551 dst->es.video.crop.width = src->es.video.crop.width;
1552 dst->es.video.crop.height = src->es.video.crop.height;
1553 dst->es.video.frame_rate.numerator = src->es.video.frame_rate.numerator;
1554 dst->es.video.frame_rate.denominator = src->es.video.frame_rate.denominator;
1555
1556 /* set new format */
1557 ret = port_info_set(instance, dst);
1558 if (ret) {
1559 pr_debug("setting port info failed\n");
1560 goto release_unlock;
1561 }
1562
1563 /* read what has actually been set */
1564 ret = port_info_get(instance, dst);
1565 if (ret) {
1566 pr_debug("read back port info failed\n");
1567 goto release_unlock;
1568 }
1569
1570 /* connect two ports together */
1571 ret = port_action_handle(instance, src,
1572 MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
1573 dst->component->handle, dst->handle);
1574 if (ret < 0) {
1575 pr_debug("connecting port %d:%d to %d:%d failed\n",
1576 src->component->handle, src->handle,
1577 dst->component->handle, dst->handle);
1578 goto release_unlock;
1579 }
1580 src->connected = dst;
1581
1582 release_unlock:
1583
1584 mutex_unlock(&instance->vchiq_mutex);
1585
1586 return ret;
1587 }
1588 EXPORT_SYMBOL_GPL(vchiq_mmal_port_connect_tunnel);
1589
vchiq_mmal_submit_buffer(struct vchiq_mmal_instance * instance,struct vchiq_mmal_port * port,struct mmal_buffer * buffer)1590 int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
1591 struct vchiq_mmal_port *port,
1592 struct mmal_buffer *buffer)
1593 {
1594 unsigned long flags = 0;
1595 int ret;
1596
1597 ret = buffer_from_host(instance, port, buffer);
1598 if (ret == -EINVAL) {
1599 /* Port is disabled. Queue for when it is enabled. */
1600 spin_lock_irqsave(&port->slock, flags);
1601 list_add_tail(&buffer->list, &port->buffers);
1602 spin_unlock_irqrestore(&port->slock, flags);
1603 }
1604
1605 return 0;
1606 }
1607 EXPORT_SYMBOL_GPL(vchiq_mmal_submit_buffer);
1608
mmal_vchi_buffer_init(struct vchiq_mmal_instance * instance,struct mmal_buffer * buf)1609 int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
1610 struct mmal_buffer *buf)
1611 {
1612 struct mmal_msg_context *msg_context = get_msg_context(instance);
1613
1614 if (IS_ERR(msg_context))
1615 return (PTR_ERR(msg_context));
1616
1617 buf->msg_context = msg_context;
1618 return 0;
1619 }
1620 EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init);
1621
mmal_vchi_buffer_cleanup(struct mmal_buffer * buf)1622 int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
1623 {
1624 struct mmal_msg_context *msg_context = buf->msg_context;
1625
1626 if (msg_context)
1627 release_msg_context(msg_context);
1628 buf->msg_context = NULL;
1629
1630 return 0;
1631 }
1632 EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
1633
1634 /* Initialise a mmal component and its ports
1635 *
1636 */
vchiq_mmal_component_init(struct vchiq_mmal_instance * instance,const char * name,struct vchiq_mmal_component ** component_out)1637 int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
1638 const char *name,
1639 struct vchiq_mmal_component **component_out)
1640 {
1641 int ret;
1642 int idx; /* port index */
1643 struct vchiq_mmal_component *component = NULL;
1644
1645 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1646 return -EINTR;
1647
1648 for (idx = 0; idx < VCHIQ_MMAL_MAX_COMPONENTS; idx++) {
1649 if (!instance->component[idx].in_use) {
1650 component = &instance->component[idx];
1651 component->in_use = 1;
1652 break;
1653 }
1654 }
1655
1656 if (!component) {
1657 ret = -EINVAL; /* todo is this correct error? */
1658 goto unlock;
1659 }
1660
1661 /* We need a handle to reference back to our component structure.
1662 * Use the array index in instance->component rather than rolling
1663 * another IDR.
1664 */
1665 component->client_component = idx;
1666
1667 ret = create_component(instance, component, name);
1668 if (ret < 0) {
1669 pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
1670 __func__, ret);
1671 goto unlock;
1672 }
1673
1674 /* ports info needs gathering */
1675 component->control.type = MMAL_PORT_TYPE_CONTROL;
1676 component->control.index = 0;
1677 component->control.component = component;
1678 spin_lock_init(&component->control.slock);
1679 INIT_LIST_HEAD(&component->control.buffers);
1680 ret = port_info_get(instance, &component->control);
1681 if (ret < 0)
1682 goto release_component;
1683
1684 for (idx = 0; idx < component->inputs; idx++) {
1685 component->input[idx].type = MMAL_PORT_TYPE_INPUT;
1686 component->input[idx].index = idx;
1687 component->input[idx].component = component;
1688 spin_lock_init(&component->input[idx].slock);
1689 INIT_LIST_HEAD(&component->input[idx].buffers);
1690 ret = port_info_get(instance, &component->input[idx]);
1691 if (ret < 0)
1692 goto release_component;
1693 }
1694
1695 for (idx = 0; idx < component->outputs; idx++) {
1696 component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
1697 component->output[idx].index = idx;
1698 component->output[idx].component = component;
1699 spin_lock_init(&component->output[idx].slock);
1700 INIT_LIST_HEAD(&component->output[idx].buffers);
1701 ret = port_info_get(instance, &component->output[idx]);
1702 if (ret < 0)
1703 goto release_component;
1704 }
1705
1706 for (idx = 0; idx < component->clocks; idx++) {
1707 component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
1708 component->clock[idx].index = idx;
1709 component->clock[idx].component = component;
1710 spin_lock_init(&component->clock[idx].slock);
1711 INIT_LIST_HEAD(&component->clock[idx].buffers);
1712 ret = port_info_get(instance, &component->clock[idx]);
1713 if (ret < 0)
1714 goto release_component;
1715 }
1716
1717 *component_out = component;
1718
1719 mutex_unlock(&instance->vchiq_mutex);
1720
1721 return 0;
1722
1723 release_component:
1724 destroy_component(instance, component);
1725 unlock:
1726 if (component)
1727 component->in_use = 0;
1728 mutex_unlock(&instance->vchiq_mutex);
1729
1730 return ret;
1731 }
1732 EXPORT_SYMBOL_GPL(vchiq_mmal_component_init);
1733
1734 /*
1735 * cause a mmal component to be destroyed
1736 */
vchiq_mmal_component_finalise(struct vchiq_mmal_instance * instance,struct vchiq_mmal_component * component)1737 int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
1738 struct vchiq_mmal_component *component)
1739 {
1740 int ret;
1741
1742 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1743 return -EINTR;
1744
1745 if (component->enabled)
1746 ret = disable_component(instance, component);
1747
1748 ret = destroy_component(instance, component);
1749
1750 component->in_use = 0;
1751
1752 mutex_unlock(&instance->vchiq_mutex);
1753
1754 return ret;
1755 }
1756 EXPORT_SYMBOL_GPL(vchiq_mmal_component_finalise);
1757
1758 /*
1759 * cause a mmal component to be enabled
1760 */
vchiq_mmal_component_enable(struct vchiq_mmal_instance * instance,struct vchiq_mmal_component * component)1761 int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
1762 struct vchiq_mmal_component *component)
1763 {
1764 int ret;
1765
1766 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1767 return -EINTR;
1768
1769 if (component->enabled) {
1770 mutex_unlock(&instance->vchiq_mutex);
1771 return 0;
1772 }
1773
1774 ret = enable_component(instance, component);
1775 if (ret == 0)
1776 component->enabled = true;
1777
1778 mutex_unlock(&instance->vchiq_mutex);
1779
1780 return ret;
1781 }
1782 EXPORT_SYMBOL_GPL(vchiq_mmal_component_enable);
1783
1784 /*
1785 * cause a mmal component to be enabled
1786 */
vchiq_mmal_component_disable(struct vchiq_mmal_instance * instance,struct vchiq_mmal_component * component)1787 int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
1788 struct vchiq_mmal_component *component)
1789 {
1790 int ret;
1791
1792 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1793 return -EINTR;
1794
1795 if (!component->enabled) {
1796 mutex_unlock(&instance->vchiq_mutex);
1797 return 0;
1798 }
1799
1800 ret = disable_component(instance, component);
1801 if (ret == 0)
1802 component->enabled = 0;
1803
1804 mutex_unlock(&instance->vchiq_mutex);
1805
1806 return ret;
1807 }
1808 EXPORT_SYMBOL_GPL(vchiq_mmal_component_disable);
1809
vchiq_mmal_version(struct vchiq_mmal_instance * instance,u32 * major_out,u32 * minor_out)1810 int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
1811 u32 *major_out, u32 *minor_out)
1812 {
1813 int ret;
1814
1815 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1816 return -EINTR;
1817
1818 ret = get_version(instance, major_out, minor_out);
1819
1820 mutex_unlock(&instance->vchiq_mutex);
1821
1822 return ret;
1823 }
1824 EXPORT_SYMBOL_GPL(vchiq_mmal_version);
1825
vchiq_mmal_finalise(struct vchiq_mmal_instance * instance)1826 int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
1827 {
1828 int status = 0;
1829
1830 if (!instance)
1831 return -EINVAL;
1832
1833 if (mutex_lock_interruptible(&instance->vchiq_mutex))
1834 return -EINTR;
1835
1836 vchiq_use_service(instance->vchiq_instance, instance->service_handle);
1837
1838 status = vchiq_close_service(instance->vchiq_instance, instance->service_handle);
1839 if (status != 0)
1840 pr_err("mmal-vchiq: VCHIQ close failed\n");
1841
1842 mutex_unlock(&instance->vchiq_mutex);
1843
1844 vchiq_shutdown(instance->vchiq_instance);
1845 destroy_workqueue(instance->bulk_wq);
1846
1847 idr_destroy(&instance->context_map);
1848
1849 kfree(instance);
1850
1851 return status;
1852 }
1853 EXPORT_SYMBOL_GPL(vchiq_mmal_finalise);
1854
vchiq_mmal_init(struct vchiq_mmal_instance ** out_instance)1855 int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
1856 {
1857 int status;
1858 int err = -ENODEV;
1859 struct vchiq_mmal_instance *instance;
1860 struct vchiq_instance *vchiq_instance;
1861 struct vchiq_service_params_kernel params = {
1862 .version = VC_MMAL_VER,
1863 .version_min = VC_MMAL_MIN_VER,
1864 .fourcc = VCHIQ_MAKE_FOURCC('m', 'm', 'a', 'l'),
1865 .callback = service_callback,
1866 .userdata = NULL,
1867 };
1868
1869 /* compile time checks to ensure structure size as they are
1870 * directly (de)serialised from memory.
1871 */
1872
1873 /* ensure the header structure has packed to the correct size */
1874 BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
1875
1876 /* ensure message structure does not exceed maximum length */
1877 BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
1878
1879 /* mmal port struct is correct size */
1880 BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
1881
1882 /* create a vchi instance */
1883 status = vchiq_initialise(&vchiq_instance);
1884 if (status) {
1885 pr_err("Failed to initialise VCHI instance (status=%d)\n",
1886 status);
1887 return -EIO;
1888 }
1889
1890 status = vchiq_connect(vchiq_instance);
1891 if (status) {
1892 pr_err("Failed to connect VCHI instance (status=%d)\n", status);
1893 err = -EIO;
1894 goto err_shutdown_vchiq;
1895 }
1896
1897 instance = kzalloc(sizeof(*instance), GFP_KERNEL);
1898
1899 if (!instance) {
1900 err = -ENOMEM;
1901 goto err_shutdown_vchiq;
1902 }
1903
1904 mutex_init(&instance->vchiq_mutex);
1905
1906 instance->vchiq_instance = vchiq_instance;
1907
1908 mutex_init(&instance->context_map_lock);
1909 idr_init_base(&instance->context_map, 1);
1910
1911 params.userdata = instance;
1912
1913 instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
1914 WQ_MEM_RECLAIM);
1915 if (!instance->bulk_wq)
1916 goto err_free;
1917
1918 status = vchiq_open_service(vchiq_instance, ¶ms,
1919 &instance->service_handle);
1920 if (status) {
1921 pr_err("Failed to open VCHI service connection (status=%d)\n",
1922 status);
1923 goto err_close_services;
1924 }
1925
1926 vchiq_release_service(instance->vchiq_instance, instance->service_handle);
1927
1928 *out_instance = instance;
1929
1930 return 0;
1931
1932 err_close_services:
1933 vchiq_close_service(instance->vchiq_instance, instance->service_handle);
1934 destroy_workqueue(instance->bulk_wq);
1935 err_free:
1936 kfree(instance);
1937 err_shutdown_vchiq:
1938 vchiq_shutdown(vchiq_instance);
1939 return err;
1940 }
1941 EXPORT_SYMBOL_GPL(vchiq_mmal_init);
1942
1943 MODULE_DESCRIPTION("BCM2835 MMAL VCHIQ interface");
1944 MODULE_AUTHOR("Dave Stevenson, <dave.stevenson@raspberrypi.org>");
1945 MODULE_LICENSE("GPL");
1946