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