linux/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
   3#include <linux/module.h>
   4#include <linux/types.h>
   5
   6#include "interface/vchi/vchi.h"
   7#include "vchiq.h"
   8#include "vchiq_core.h"
   9
  10#include "vchiq_util.h"
  11
  12#define vchiq_status_to_vchi(status) ((int32_t)status)
  13
  14struct shim_service {
  15        VCHIQ_SERVICE_HANDLE_T handle;
  16
  17        struct vchiu_queue queue;
  18
  19        VCHI_CALLBACK_T callback;
  20        void *callback_param;
  21};
  22
  23/***********************************************************
  24 * Name: vchi_msg_peek
  25 *
  26 * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
  27 *             void **data,
  28 *             uint32_t *msg_size,
  29
  30 *             VCHI_FLAGS_T flags
  31 *
  32 * Description: Routine to return a pointer to the current message (to allow in
  33 *              place processing). The message can be removed using
  34 *              vchi_msg_remove when you're finished
  35 *
  36 * Returns: int32_t - success == 0
  37 *
  38 ***********************************************************/
  39int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
  40        void **data,
  41        uint32_t *msg_size,
  42        VCHI_FLAGS_T flags)
  43{
  44        struct shim_service *service = (struct shim_service *)handle;
  45        struct vchiq_header *header;
  46
  47        WARN_ON((flags != VCHI_FLAGS_NONE) &&
  48                (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
  49
  50        if (flags == VCHI_FLAGS_NONE)
  51                if (vchiu_queue_is_empty(&service->queue))
  52                        return -1;
  53
  54        header = vchiu_queue_peek(&service->queue);
  55
  56        *data = header->data;
  57        *msg_size = header->size;
  58
  59        return 0;
  60}
  61EXPORT_SYMBOL(vchi_msg_peek);
  62
  63/***********************************************************
  64 * Name: vchi_msg_remove
  65 *
  66 * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
  67 *
  68 * Description: Routine to remove a message (after it has been read with
  69 *              vchi_msg_peek)
  70 *
  71 * Returns: int32_t - success == 0
  72 *
  73 ***********************************************************/
  74int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
  75{
  76        struct shim_service *service = (struct shim_service *)handle;
  77        struct vchiq_header *header;
  78
  79        header = vchiu_queue_pop(&service->queue);
  80
  81        vchiq_release_message(service->handle, header);
  82
  83        return 0;
  84}
  85EXPORT_SYMBOL(vchi_msg_remove);
  86
  87/***********************************************************
  88 * Name: vchi_msg_queue
  89 *
  90 * Arguments:  VCHI_SERVICE_HANDLE_T handle,
  91 *             ssize_t (*copy_callback)(void *context, void *dest,
  92 *                                      size_t offset, size_t maxsize),
  93 *             void *context,
  94 *             uint32_t data_size
  95 *
  96 * Description: Thin wrapper to queue a message onto a connection
  97 *
  98 * Returns: int32_t - success == 0
  99 *
 100 ***********************************************************/
 101static
 102int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
 103        ssize_t (*copy_callback)(void *context, void *dest,
 104                                 size_t offset, size_t maxsize),
 105        void *context,
 106        uint32_t data_size)
 107{
 108        struct shim_service *service = (struct shim_service *)handle;
 109        VCHIQ_STATUS_T status;
 110
 111        while (1) {
 112                status = vchiq_queue_message(service->handle,
 113                                             copy_callback,
 114                                             context,
 115                                             data_size);
 116
 117                /*
 118                 * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
 119                 * implement a retry mechanism since this function is supposed
 120                 * to block until queued
 121                 */
 122                if (status != VCHIQ_RETRY)
 123                        break;
 124
 125                msleep(1);
 126        }
 127
 128        return vchiq_status_to_vchi(status);
 129}
 130
 131static ssize_t
 132vchi_queue_kernel_message_callback(void *context,
 133                                   void *dest,
 134                                   size_t offset,
 135                                   size_t maxsize)
 136{
 137        memcpy(dest, context + offset, maxsize);
 138        return maxsize;
 139}
 140
 141int
 142vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,
 143                          void *data,
 144                          unsigned int size)
 145{
 146        return vchi_msg_queue(handle,
 147                              vchi_queue_kernel_message_callback,
 148                              data,
 149                              size);
 150}
 151EXPORT_SYMBOL(vchi_queue_kernel_message);
 152
 153struct vchi_queue_user_message_context {
 154        void __user *data;
 155};
 156
 157static ssize_t
 158vchi_queue_user_message_callback(void *context,
 159                                 void *dest,
 160                                 size_t offset,
 161                                 size_t maxsize)
 162{
 163        struct vchi_queue_user_message_context *copycontext = context;
 164
 165        if (copy_from_user(dest, copycontext->data + offset, maxsize))
 166                return -EFAULT;
 167
 168        return maxsize;
 169}
 170
 171int
 172vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
 173                        void __user *data,
 174                        unsigned int size)
 175{
 176        struct vchi_queue_user_message_context copycontext = {
 177                .data = data
 178        };
 179
 180        return vchi_msg_queue(handle,
 181                              vchi_queue_user_message_callback,
 182                              &copycontext,
 183                              size);
 184}
 185EXPORT_SYMBOL(vchi_queue_user_message);
 186
 187/***********************************************************
 188 * Name: vchi_bulk_queue_receive
 189 *
 190 * Arguments:  VCHI_BULK_HANDLE_T handle,
 191 *             void *data_dst,
 192 *             const uint32_t data_size,
 193 *             VCHI_FLAGS_T flags
 194 *             void *bulk_handle
 195 *
 196 * Description: Routine to setup a rcv buffer
 197 *
 198 * Returns: int32_t - success == 0
 199 *
 200 ***********************************************************/
 201int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
 202        void *data_dst,
 203        uint32_t data_size,
 204        VCHI_FLAGS_T flags,
 205        void *bulk_handle)
 206{
 207        struct shim_service *service = (struct shim_service *)handle;
 208        VCHIQ_BULK_MODE_T mode;
 209        VCHIQ_STATUS_T status;
 210
 211        switch ((int)flags) {
 212        case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
 213                | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
 214                WARN_ON(!service->callback);
 215                mode = VCHIQ_BULK_MODE_CALLBACK;
 216                break;
 217        case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
 218                mode = VCHIQ_BULK_MODE_BLOCKING;
 219                break;
 220        case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
 221        case VCHI_FLAGS_NONE:
 222                mode = VCHIQ_BULK_MODE_NOCALLBACK;
 223                break;
 224        default:
 225                WARN(1, "unsupported message\n");
 226                return vchiq_status_to_vchi(VCHIQ_ERROR);
 227        }
 228
 229        while (1) {
 230                status = vchiq_bulk_receive(service->handle, data_dst,
 231                        data_size, bulk_handle, mode);
 232                /*
 233                 * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
 234                 * implement a retry mechanism since this function is supposed
 235                 * to block until queued
 236                 */
 237                if (status != VCHIQ_RETRY)
 238                        break;
 239
 240                msleep(1);
 241        }
 242
 243        return vchiq_status_to_vchi(status);
 244}
 245EXPORT_SYMBOL(vchi_bulk_queue_receive);
 246
 247/***********************************************************
 248 * Name: vchi_bulk_queue_transmit
 249 *
 250 * Arguments:  VCHI_BULK_HANDLE_T handle,
 251 *             const void *data_src,
 252 *             uint32_t data_size,
 253 *             VCHI_FLAGS_T flags,
 254 *             void *bulk_handle
 255 *
 256 * Description: Routine to transmit some data
 257 *
 258 * Returns: int32_t - success == 0
 259 *
 260 ***********************************************************/
 261int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
 262        const void *data_src,
 263        uint32_t data_size,
 264        VCHI_FLAGS_T flags,
 265        void *bulk_handle)
 266{
 267        struct shim_service *service = (struct shim_service *)handle;
 268        VCHIQ_BULK_MODE_T mode;
 269        VCHIQ_STATUS_T status;
 270
 271        switch ((int)flags) {
 272        case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
 273                | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
 274                WARN_ON(!service->callback);
 275                mode = VCHIQ_BULK_MODE_CALLBACK;
 276                break;
 277        case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
 278        case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
 279                mode = VCHIQ_BULK_MODE_BLOCKING;
 280                break;
 281        case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
 282        case VCHI_FLAGS_NONE:
 283                mode = VCHIQ_BULK_MODE_NOCALLBACK;
 284                break;
 285        default:
 286                WARN(1, "unsupported message\n");
 287                return vchiq_status_to_vchi(VCHIQ_ERROR);
 288        }
 289
 290        while (1) {
 291                status = vchiq_bulk_transmit(service->handle, data_src,
 292                        data_size, bulk_handle, mode);
 293
 294                /*
 295                 * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
 296                 * implement a retry mechanism since this function is supposed
 297                 * to block until queued
 298                 */
 299                if (status != VCHIQ_RETRY)
 300                        break;
 301
 302                msleep(1);
 303        }
 304
 305        return vchiq_status_to_vchi(status);
 306}
 307EXPORT_SYMBOL(vchi_bulk_queue_transmit);
 308
 309/***********************************************************
 310 * Name: vchi_msg_dequeue
 311 *
 312 * Arguments:  VCHI_SERVICE_HANDLE_T handle,
 313 *             void *data,
 314 *             uint32_t max_data_size_to_read,
 315 *             uint32_t *actual_msg_size
 316 *             VCHI_FLAGS_T flags
 317 *
 318 * Description: Routine to dequeue a message into the supplied buffer
 319 *
 320 * Returns: int32_t - success == 0
 321 *
 322 ***********************************************************/
 323int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
 324        void *data,
 325        uint32_t max_data_size_to_read,
 326        uint32_t *actual_msg_size,
 327        VCHI_FLAGS_T flags)
 328{
 329        struct shim_service *service = (struct shim_service *)handle;
 330        struct vchiq_header *header;
 331
 332        WARN_ON((flags != VCHI_FLAGS_NONE) &&
 333                (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
 334
 335        if (flags == VCHI_FLAGS_NONE)
 336                if (vchiu_queue_is_empty(&service->queue))
 337                        return -1;
 338
 339        header = vchiu_queue_pop(&service->queue);
 340
 341        memcpy(data, header->data, header->size < max_data_size_to_read ?
 342                header->size : max_data_size_to_read);
 343
 344        *actual_msg_size = header->size;
 345
 346        vchiq_release_message(service->handle, header);
 347
 348        return 0;
 349}
 350EXPORT_SYMBOL(vchi_msg_dequeue);
 351
 352/***********************************************************
 353 * Name: vchi_held_msg_release
 354 *
 355 * Arguments:  struct vchi_held_msg *message
 356 *
 357 * Description: Routine to release a held message (after it has been read with
 358 *              vchi_msg_hold)
 359 *
 360 * Returns: int32_t - success == 0
 361 *
 362 ***********************************************************/
 363int32_t vchi_held_msg_release(struct vchi_held_msg *message)
 364{
 365        /*
 366         * Convert the service field pointer back to an
 367         * VCHIQ_SERVICE_HANDLE_T which is an int.
 368         * This pointer is opaque to everything except
 369         * vchi_msg_hold which simply upcasted the int
 370         * to a pointer.
 371         */
 372
 373        vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(long)message->service,
 374                              (struct vchiq_header *)message->message);
 375
 376        return 0;
 377}
 378EXPORT_SYMBOL(vchi_held_msg_release);
 379
 380/***********************************************************
 381 * Name: vchi_msg_hold
 382 *
 383 * Arguments:  VCHI_SERVICE_HANDLE_T handle,
 384 *             void **data,
 385 *             uint32_t *msg_size,
 386 *             VCHI_FLAGS_T flags,
 387 *             struct vchi_held_msg *message_handle
 388 *
 389 * Description: Routine to return a pointer to the current message (to allow
 390 *              in place processing). The message is dequeued - don't forget
 391 *              to release the message using vchi_held_msg_release when you're
 392 *              finished.
 393 *
 394 * Returns: int32_t - success == 0
 395 *
 396 ***********************************************************/
 397int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
 398        void **data,
 399        uint32_t *msg_size,
 400        VCHI_FLAGS_T flags,
 401        struct vchi_held_msg *message_handle)
 402{
 403        struct shim_service *service = (struct shim_service *)handle;
 404        struct vchiq_header *header;
 405
 406        WARN_ON((flags != VCHI_FLAGS_NONE) &&
 407                (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
 408
 409        if (flags == VCHI_FLAGS_NONE)
 410                if (vchiu_queue_is_empty(&service->queue))
 411                        return -1;
 412
 413        header = vchiu_queue_pop(&service->queue);
 414
 415        *data = header->data;
 416        *msg_size = header->size;
 417
 418        /*
 419         * upcast the VCHIQ_SERVICE_HANDLE_T which is an int
 420         * to a pointer and stuff it in the held message.
 421         * This pointer is opaque to everything except
 422         * vchi_held_msg_release which simply downcasts it back
 423         * to an int.
 424         */
 425
 426        message_handle->service =
 427                (struct opaque_vchi_service_t *)(long)service->handle;
 428        message_handle->message = header;
 429
 430        return 0;
 431}
 432EXPORT_SYMBOL(vchi_msg_hold);
 433
 434/***********************************************************
 435 * Name: vchi_initialise
 436 *
 437 * Arguments: VCHI_INSTANCE_T *instance_handle
 438 *
 439 * Description: Initialises the hardware but does not transmit anything
 440 *              When run as a Host App this will be called twice hence the need
 441 *              to malloc the state information
 442 *
 443 * Returns: 0 if successful, failure otherwise
 444 *
 445 ***********************************************************/
 446
 447int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
 448{
 449        VCHIQ_INSTANCE_T instance;
 450        VCHIQ_STATUS_T status;
 451
 452        status = vchiq_initialise(&instance);
 453
 454        *instance_handle = (VCHI_INSTANCE_T)instance;
 455
 456        return vchiq_status_to_vchi(status);
 457}
 458EXPORT_SYMBOL(vchi_initialise);
 459
 460/***********************************************************
 461 * Name: vchi_connect
 462 *
 463 * Arguments: VCHI_INSTANCE_T instance_handle
 464 *
 465 * Description: Starts the command service on each connection,
 466 *              causing INIT messages to be pinged back and forth
 467 *
 468 * Returns: 0 if successful, failure otherwise
 469 *
 470 ***********************************************************/
 471int32_t vchi_connect(VCHI_INSTANCE_T instance_handle)
 472{
 473        VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
 474
 475        return vchiq_connect(instance);
 476}
 477EXPORT_SYMBOL(vchi_connect);
 478
 479/***********************************************************
 480 * Name: vchi_disconnect
 481 *
 482 * Arguments: VCHI_INSTANCE_T instance_handle
 483 *
 484 * Description: Stops the command service on each connection,
 485 *              causing DE-INIT messages to be pinged back and forth
 486 *
 487 * Returns: 0 if successful, failure otherwise
 488 *
 489 ***********************************************************/
 490int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
 491{
 492        VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
 493
 494        return vchiq_status_to_vchi(vchiq_shutdown(instance));
 495}
 496EXPORT_SYMBOL(vchi_disconnect);
 497
 498/***********************************************************
 499 * Name: vchi_service_open
 500 * Name: vchi_service_create
 501 *
 502 * Arguments: VCHI_INSTANCE_T *instance_handle
 503 *            struct service_creation *setup,
 504 *            VCHI_SERVICE_HANDLE_T *handle
 505 *
 506 * Description: Routine to open a service
 507 *
 508 * Returns: int32_t - success == 0
 509 *
 510 ***********************************************************/
 511
 512static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
 513                                    struct vchiq_header *header,
 514                                    VCHIQ_SERVICE_HANDLE_T handle,
 515                                    void *bulk_user)
 516{
 517        struct shim_service *service =
 518                (struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle);
 519
 520        if (!service->callback)
 521                goto release;
 522
 523        switch (reason) {
 524        case VCHIQ_MESSAGE_AVAILABLE:
 525                vchiu_queue_push(&service->queue, header);
 526
 527                service->callback(service->callback_param,
 528                                  VCHI_CALLBACK_MSG_AVAILABLE, NULL);
 529
 530                goto done;
 531
 532        case VCHIQ_BULK_TRANSMIT_DONE:
 533                service->callback(service->callback_param,
 534                                  VCHI_CALLBACK_BULK_SENT, bulk_user);
 535                break;
 536
 537        case VCHIQ_BULK_RECEIVE_DONE:
 538                service->callback(service->callback_param,
 539                                  VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
 540                break;
 541
 542        case VCHIQ_SERVICE_CLOSED:
 543                service->callback(service->callback_param,
 544                                  VCHI_CALLBACK_SERVICE_CLOSED, NULL);
 545                break;
 546
 547        case VCHIQ_SERVICE_OPENED:
 548                /* No equivalent VCHI reason */
 549                break;
 550
 551        case VCHIQ_BULK_TRANSMIT_ABORTED:
 552                service->callback(service->callback_param,
 553                                  VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
 554                                  bulk_user);
 555                break;
 556
 557        case VCHIQ_BULK_RECEIVE_ABORTED:
 558                service->callback(service->callback_param,
 559                                  VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
 560                                  bulk_user);
 561                break;
 562
 563        default:
 564                WARN(1, "not supported\n");
 565                break;
 566        }
 567
 568release:
 569        vchiq_release_message(service->handle, header);
 570done:
 571        return VCHIQ_SUCCESS;
 572}
 573
 574static struct shim_service *service_alloc(VCHIQ_INSTANCE_T instance,
 575        struct service_creation *setup)
 576{
 577        struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL);
 578
 579        (void)instance;
 580
 581        if (service) {
 582                if (vchiu_queue_init(&service->queue, 64)) {
 583                        service->callback = setup->callback;
 584                        service->callback_param = setup->callback_param;
 585                } else {
 586                        kfree(service);
 587                        service = NULL;
 588                }
 589        }
 590
 591        return service;
 592}
 593
 594static void service_free(struct shim_service *service)
 595{
 596        if (service) {
 597                vchiu_queue_delete(&service->queue);
 598                kfree(service);
 599        }
 600}
 601
 602int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
 603        struct service_creation *setup,
 604        VCHI_SERVICE_HANDLE_T *handle)
 605{
 606        VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
 607        struct shim_service *service = service_alloc(instance, setup);
 608
 609        *handle = (VCHI_SERVICE_HANDLE_T)service;
 610
 611        if (service) {
 612                struct vchiq_service_params params;
 613                VCHIQ_STATUS_T status;
 614
 615                memset(&params, 0, sizeof(params));
 616                params.fourcc = setup->service_id;
 617                params.callback = shim_callback;
 618                params.userdata = service;
 619                params.version = setup->version.version;
 620                params.version_min = setup->version.version_min;
 621
 622                status = vchiq_open_service(instance, &params,
 623                        &service->handle);
 624                if (status != VCHIQ_SUCCESS) {
 625                        service_free(service);
 626                        service = NULL;
 627                        *handle = NULL;
 628                }
 629        }
 630
 631        return (service != NULL) ? 0 : -1;
 632}
 633EXPORT_SYMBOL(vchi_service_open);
 634
 635int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
 636{
 637        int32_t ret = -1;
 638        struct shim_service *service = (struct shim_service *)handle;
 639
 640        if (service) {
 641                VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
 642                if (status == VCHIQ_SUCCESS) {
 643                        service_free(service);
 644                        service = NULL;
 645                }
 646
 647                ret = vchiq_status_to_vchi(status);
 648        }
 649        return ret;
 650}
 651EXPORT_SYMBOL(vchi_service_close);
 652
 653int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
 654{
 655        int32_t ret = -1;
 656        struct shim_service *service = (struct shim_service *)handle;
 657
 658        if (service) {
 659                VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
 660
 661                if (status == VCHIQ_SUCCESS) {
 662                        service_free(service);
 663                        service = NULL;
 664                }
 665
 666                ret = vchiq_status_to_vchi(status);
 667        }
 668        return ret;
 669}
 670EXPORT_SYMBOL(vchi_service_destroy);
 671
 672int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
 673                                VCHI_SERVICE_OPTION_T option,
 674                                int value)
 675{
 676        int32_t ret = -1;
 677        struct shim_service *service = (struct shim_service *)handle;
 678        VCHIQ_SERVICE_OPTION_T vchiq_option;
 679
 680        switch (option) {
 681        case VCHI_SERVICE_OPTION_TRACE:
 682                vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
 683                break;
 684        case VCHI_SERVICE_OPTION_SYNCHRONOUS:
 685                vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
 686                break;
 687        default:
 688                service = NULL;
 689                break;
 690        }
 691        if (service) {
 692                VCHIQ_STATUS_T status =
 693                        vchiq_set_service_option(service->handle,
 694                                                vchiq_option,
 695                                                value);
 696
 697                ret = vchiq_status_to_vchi(status);
 698        }
 699        return ret;
 700}
 701EXPORT_SYMBOL(vchi_service_set_option);
 702
 703int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version)
 704{
 705        int32_t ret = -1;
 706        struct shim_service *service = (struct shim_service *)handle;
 707
 708        if (service) {
 709                VCHIQ_STATUS_T status;
 710
 711                status = vchiq_get_peer_version(service->handle, peer_version);
 712                ret = vchiq_status_to_vchi(status);
 713        }
 714        return ret;
 715}
 716EXPORT_SYMBOL(vchi_get_peer_version);
 717
 718/***********************************************************
 719 * Name: vchi_service_use
 720 *
 721 * Arguments: const VCHI_SERVICE_HANDLE_T handle
 722 *
 723 * Description: Routine to increment refcount on a service
 724 *
 725 * Returns: void
 726 *
 727 ***********************************************************/
 728int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
 729{
 730        int32_t ret = -1;
 731
 732        struct shim_service *service = (struct shim_service *)handle;
 733        if (service)
 734                ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
 735        return ret;
 736}
 737EXPORT_SYMBOL(vchi_service_use);
 738
 739/***********************************************************
 740 * Name: vchi_service_release
 741 *
 742 * Arguments: const VCHI_SERVICE_HANDLE_T handle
 743 *
 744 * Description: Routine to decrement refcount on a service
 745 *
 746 * Returns: void
 747 *
 748 ***********************************************************/
 749int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
 750{
 751        int32_t ret = -1;
 752
 753        struct shim_service *service = (struct shim_service *)handle;
 754        if (service)
 755                ret = vchiq_status_to_vchi(
 756                        vchiq_release_service(service->handle));
 757        return ret;
 758}
 759EXPORT_SYMBOL(vchi_service_release);
 760