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