linux/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/*
   3 * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
   4 * Copyright (c) 2010-2012 Broadcom. All rights reserved.
   5 */
   6
   7#include <linux/cdev.h>
   8#include <linux/fs.h>
   9#include <linux/device.h>
  10#include <linux/slab.h>
  11#include <linux/compat.h>
  12
  13#include "vchiq_core.h"
  14#include "vchiq_ioctl.h"
  15#include "vchiq_arm.h"
  16#include "vchiq_debugfs.h"
  17
  18#define DEVICE_NAME "vchiq"
  19
  20static struct cdev    vchiq_cdev;
  21static dev_t          vchiq_devid;
  22static struct class  *vchiq_class;
  23
  24static const char *const ioctl_names[] = {
  25        "CONNECT",
  26        "SHUTDOWN",
  27        "CREATE_SERVICE",
  28        "REMOVE_SERVICE",
  29        "QUEUE_MESSAGE",
  30        "QUEUE_BULK_TRANSMIT",
  31        "QUEUE_BULK_RECEIVE",
  32        "AWAIT_COMPLETION",
  33        "DEQUEUE_MESSAGE",
  34        "GET_CLIENT_ID",
  35        "GET_CONFIG",
  36        "CLOSE_SERVICE",
  37        "USE_SERVICE",
  38        "RELEASE_SERVICE",
  39        "SET_SERVICE_OPTION",
  40        "DUMP_PHYS_MEM",
  41        "LIB_VERSION",
  42        "CLOSE_DELIVERED"
  43};
  44
  45static_assert(ARRAY_SIZE(ioctl_names) == (VCHIQ_IOC_MAX + 1));
  46
  47static void
  48user_service_free(void *userdata)
  49{
  50        kfree(userdata);
  51}
  52
  53static void close_delivered(struct user_service *user_service)
  54{
  55        vchiq_log_info(vchiq_arm_log_level,
  56                "%s(handle=%x)",
  57                __func__, user_service->service->handle);
  58
  59        if (user_service->close_pending) {
  60                /* Allow the underlying service to be culled */
  61                vchiq_service_put(user_service->service);
  62
  63                /* Wake the user-thread blocked in close_ or remove_service */
  64                complete(&user_service->close_event);
  65
  66                user_service->close_pending = 0;
  67        }
  68}
  69
  70struct vchiq_io_copy_callback_context {
  71        struct vchiq_element *element;
  72        size_t element_offset;
  73        unsigned long elements_to_go;
  74};
  75
  76static ssize_t vchiq_ioc_copy_element_data(void *context, void *dest,
  77                                           size_t offset, size_t maxsize)
  78{
  79        struct vchiq_io_copy_callback_context *cc = context;
  80        size_t total_bytes_copied = 0;
  81        size_t bytes_this_round;
  82
  83        while (total_bytes_copied < maxsize) {
  84                if (!cc->elements_to_go)
  85                        return total_bytes_copied;
  86
  87                if (!cc->element->size) {
  88                        cc->elements_to_go--;
  89                        cc->element++;
  90                        cc->element_offset = 0;
  91                        continue;
  92                }
  93
  94                bytes_this_round = min(cc->element->size - cc->element_offset,
  95                                       maxsize - total_bytes_copied);
  96
  97                if (copy_from_user(dest + total_bytes_copied,
  98                                  cc->element->data + cc->element_offset,
  99                                  bytes_this_round))
 100                        return -EFAULT;
 101
 102                cc->element_offset += bytes_this_round;
 103                total_bytes_copied += bytes_this_round;
 104
 105                if (cc->element_offset == cc->element->size) {
 106                        cc->elements_to_go--;
 107                        cc->element++;
 108                        cc->element_offset = 0;
 109                }
 110        }
 111
 112        return maxsize;
 113}
 114
 115static int
 116vchiq_ioc_queue_message(unsigned int handle, struct vchiq_element *elements,
 117                        unsigned long count)
 118{
 119        struct vchiq_io_copy_callback_context context;
 120        enum vchiq_status status = VCHIQ_SUCCESS;
 121        unsigned long i;
 122        size_t total_size = 0;
 123
 124        context.element = elements;
 125        context.element_offset = 0;
 126        context.elements_to_go = count;
 127
 128        for (i = 0; i < count; i++) {
 129                if (!elements[i].data && elements[i].size != 0)
 130                        return -EFAULT;
 131
 132                total_size += elements[i].size;
 133        }
 134
 135        status = vchiq_queue_message(handle, vchiq_ioc_copy_element_data,
 136                                     &context, total_size);
 137
 138        if (status == VCHIQ_ERROR)
 139                return -EIO;
 140        else if (status == VCHIQ_RETRY)
 141                return -EINTR;
 142        return 0;
 143}
 144
 145static int vchiq_ioc_create_service(struct vchiq_instance *instance,
 146                                    struct vchiq_create_service *args)
 147{
 148        struct user_service *user_service = NULL;
 149        struct vchiq_service *service;
 150        enum vchiq_status status = VCHIQ_SUCCESS;
 151        struct vchiq_service_params_kernel params;
 152        int srvstate;
 153
 154        user_service = kmalloc(sizeof(*user_service), GFP_KERNEL);
 155        if (!user_service)
 156                return -ENOMEM;
 157
 158        if (args->is_open) {
 159                if (!instance->connected) {
 160                        kfree(user_service);
 161                        return -ENOTCONN;
 162                }
 163                srvstate = VCHIQ_SRVSTATE_OPENING;
 164        } else {
 165                srvstate = instance->connected ?
 166                         VCHIQ_SRVSTATE_LISTENING : VCHIQ_SRVSTATE_HIDDEN;
 167        }
 168
 169        params = (struct vchiq_service_params_kernel) {
 170                .fourcc   = args->params.fourcc,
 171                .callback = service_callback,
 172                .userdata = user_service,
 173                .version  = args->params.version,
 174                .version_min = args->params.version_min,
 175        };
 176        service = vchiq_add_service_internal(instance->state, &params,
 177                                             srvstate, instance,
 178                                             user_service_free);
 179        if (!service) {
 180                kfree(user_service);
 181                return -EEXIST;
 182        }
 183
 184        user_service->service = service;
 185        user_service->userdata = args->params.userdata;
 186        user_service->instance = instance;
 187        user_service->is_vchi = (args->is_vchi != 0);
 188        user_service->dequeue_pending = 0;
 189        user_service->close_pending = 0;
 190        user_service->message_available_pos = instance->completion_remove - 1;
 191        user_service->msg_insert = 0;
 192        user_service->msg_remove = 0;
 193        init_completion(&user_service->insert_event);
 194        init_completion(&user_service->remove_event);
 195        init_completion(&user_service->close_event);
 196
 197        if (args->is_open) {
 198                status = vchiq_open_service_internal(service, instance->pid);
 199                if (status != VCHIQ_SUCCESS) {
 200                        vchiq_remove_service(service->handle);
 201                        return (status == VCHIQ_RETRY) ?
 202                                -EINTR : -EIO;
 203                }
 204        }
 205        args->handle = service->handle;
 206
 207        return 0;
 208}
 209
 210static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
 211                                     struct vchiq_dequeue_message *args)
 212{
 213        struct user_service *user_service;
 214        struct vchiq_service *service;
 215        struct vchiq_header *header;
 216        int ret;
 217
 218        DEBUG_INITIALISE(g_state.local)
 219        DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
 220        service = find_service_for_instance(instance, args->handle);
 221        if (!service)
 222                return -EINVAL;
 223
 224        user_service = (struct user_service *)service->base.userdata;
 225        if (user_service->is_vchi == 0) {
 226                ret = -EINVAL;
 227                goto out;
 228        }
 229
 230        spin_lock(&msg_queue_spinlock);
 231        if (user_service->msg_remove == user_service->msg_insert) {
 232                if (!args->blocking) {
 233                        spin_unlock(&msg_queue_spinlock);
 234                        DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
 235                        ret = -EWOULDBLOCK;
 236                        goto out;
 237                }
 238                user_service->dequeue_pending = 1;
 239                ret = 0;
 240                do {
 241                        spin_unlock(&msg_queue_spinlock);
 242                        DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
 243                        if (wait_for_completion_interruptible(
 244                                &user_service->insert_event)) {
 245                                vchiq_log_info(vchiq_arm_log_level,
 246                                        "DEQUEUE_MESSAGE interrupted");
 247                                ret = -EINTR;
 248                                break;
 249                        }
 250                        spin_lock(&msg_queue_spinlock);
 251                } while (user_service->msg_remove == user_service->msg_insert);
 252
 253                if (ret)
 254                        goto out;
 255        }
 256
 257        if (WARN_ON_ONCE((int)(user_service->msg_insert -
 258                         user_service->msg_remove) < 0)) {
 259                spin_unlock(&msg_queue_spinlock);
 260                ret = -EINVAL;
 261                goto out;
 262        }
 263
 264        header = user_service->msg_queue[user_service->msg_remove &
 265                (MSG_QUEUE_SIZE - 1)];
 266        user_service->msg_remove++;
 267        spin_unlock(&msg_queue_spinlock);
 268
 269        complete(&user_service->remove_event);
 270        if (!header) {
 271                ret = -ENOTCONN;
 272        } else if (header->size <= args->bufsize) {
 273                /* Copy to user space if msgbuf is not NULL */
 274                if (!args->buf || (copy_to_user(args->buf,
 275                                        header->data, header->size) == 0)) {
 276                        ret = header->size;
 277                        vchiq_release_message(service->handle, header);
 278                } else {
 279                        ret = -EFAULT;
 280                }
 281        } else {
 282                vchiq_log_error(vchiq_arm_log_level,
 283                        "header %pK: bufsize %x < size %x",
 284                        header, args->bufsize, header->size);
 285                WARN(1, "invalid size\n");
 286                ret = -EMSGSIZE;
 287        }
 288        DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
 289out:
 290        vchiq_service_put(service);
 291        return ret;
 292}
 293
 294static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
 295                                      struct vchiq_queue_bulk_transfer *args,
 296                                      enum vchiq_bulk_dir dir,
 297                                      enum vchiq_bulk_mode __user *mode)
 298{
 299        struct vchiq_service *service;
 300        struct bulk_waiter_node *waiter = NULL;
 301        bool found = false;
 302        void *userdata;
 303        int status = 0;
 304        int ret;
 305
 306        service = find_service_for_instance(instance, args->handle);
 307        if (!service)
 308                return -EINVAL;
 309
 310        if (args->mode == VCHIQ_BULK_MODE_BLOCKING) {
 311                waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
 312                if (!waiter) {
 313                        ret = -ENOMEM;
 314                        goto out;
 315                }
 316
 317                userdata = &waiter->bulk_waiter;
 318        } else if (args->mode == VCHIQ_BULK_MODE_WAITING) {
 319                mutex_lock(&instance->bulk_waiter_list_mutex);
 320                list_for_each_entry(waiter, &instance->bulk_waiter_list,
 321                                    list) {
 322                        if (waiter->pid == current->pid) {
 323                                list_del(&waiter->list);
 324                                found = true;
 325                                break;
 326                        }
 327                }
 328                mutex_unlock(&instance->bulk_waiter_list_mutex);
 329                if (!found) {
 330                        vchiq_log_error(vchiq_arm_log_level,
 331                                "no bulk_waiter found for pid %d",
 332                                current->pid);
 333                        ret = -ESRCH;
 334                        goto out;
 335                }
 336                vchiq_log_info(vchiq_arm_log_level,
 337                        "found bulk_waiter %pK for pid %d", waiter,
 338                        current->pid);
 339                userdata = &waiter->bulk_waiter;
 340        } else {
 341                userdata = args->userdata;
 342        }
 343
 344        status = vchiq_bulk_transfer(args->handle, NULL, args->data, args->size,
 345                                     userdata, args->mode, dir);
 346
 347        if (!waiter) {
 348                ret = 0;
 349                goto out;
 350        }
 351
 352        if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
 353                !waiter->bulk_waiter.bulk) {
 354                if (waiter->bulk_waiter.bulk) {
 355                        /* Cancel the signal when the transfer completes. */
 356                        spin_lock(&bulk_waiter_spinlock);
 357                        waiter->bulk_waiter.bulk->userdata = NULL;
 358                        spin_unlock(&bulk_waiter_spinlock);
 359                }
 360                kfree(waiter);
 361                ret = 0;
 362        } else {
 363                const enum vchiq_bulk_mode mode_waiting =
 364                        VCHIQ_BULK_MODE_WAITING;
 365                waiter->pid = current->pid;
 366                mutex_lock(&instance->bulk_waiter_list_mutex);
 367                list_add(&waiter->list, &instance->bulk_waiter_list);
 368                mutex_unlock(&instance->bulk_waiter_list_mutex);
 369                vchiq_log_info(vchiq_arm_log_level,
 370                        "saved bulk_waiter %pK for pid %d",
 371                        waiter, current->pid);
 372
 373                ret = put_user(mode_waiting, mode);
 374        }
 375out:
 376        vchiq_service_put(service);
 377        if (ret)
 378                return ret;
 379        else if (status == VCHIQ_ERROR)
 380                return -EIO;
 381        else if (status == VCHIQ_RETRY)
 382                return -EINTR;
 383        return 0;
 384}
 385
 386/* read a user pointer value from an array pointers in user space */
 387static inline int vchiq_get_user_ptr(void __user **buf, void __user *ubuf, int index)
 388{
 389        int ret;
 390
 391        if (in_compat_syscall()) {
 392                compat_uptr_t ptr32;
 393                compat_uptr_t __user *uptr = ubuf;
 394
 395                ret = get_user(ptr32, uptr + index);
 396                if (ret)
 397                        return ret;
 398
 399                *buf = compat_ptr(ptr32);
 400        } else {
 401                uintptr_t ptr, __user *uptr = ubuf;
 402
 403                ret = get_user(ptr, uptr + index);
 404
 405                if (ret)
 406                        return ret;
 407
 408                *buf = (void __user *)ptr;
 409        }
 410
 411        return 0;
 412}
 413
 414struct vchiq_completion_data32 {
 415        enum vchiq_reason reason;
 416        compat_uptr_t header;
 417        compat_uptr_t service_userdata;
 418        compat_uptr_t bulk_userdata;
 419};
 420
 421static int vchiq_put_completion(struct vchiq_completion_data __user *buf,
 422                                struct vchiq_completion_data *completion,
 423                                int index)
 424{
 425        struct vchiq_completion_data32 __user *buf32 = (void __user *)buf;
 426
 427        if (in_compat_syscall()) {
 428                struct vchiq_completion_data32 tmp = {
 429                        .reason           = completion->reason,
 430                        .header           = ptr_to_compat(completion->header),
 431                        .service_userdata = ptr_to_compat(completion->service_userdata),
 432                        .bulk_userdata    = ptr_to_compat(completion->bulk_userdata),
 433                };
 434                if (copy_to_user(&buf32[index], &tmp, sizeof(tmp)))
 435                        return -EFAULT;
 436        } else {
 437                if (copy_to_user(&buf[index], completion, sizeof(*completion)))
 438                        return -EFAULT;
 439        }
 440
 441        return 0;
 442}
 443
 444static int vchiq_ioc_await_completion(struct vchiq_instance *instance,
 445                                      struct vchiq_await_completion *args,
 446                                      int __user *msgbufcountp)
 447{
 448        int msgbufcount;
 449        int remove;
 450        int ret;
 451
 452        DEBUG_INITIALISE(g_state.local)
 453
 454        DEBUG_TRACE(AWAIT_COMPLETION_LINE);
 455        if (!instance->connected) {
 456                return -ENOTCONN;
 457        }
 458
 459        mutex_lock(&instance->completion_mutex);
 460
 461        DEBUG_TRACE(AWAIT_COMPLETION_LINE);
 462        while ((instance->completion_remove == instance->completion_insert)
 463                && !instance->closing) {
 464                int rc;
 465
 466                DEBUG_TRACE(AWAIT_COMPLETION_LINE);
 467                mutex_unlock(&instance->completion_mutex);
 468                rc = wait_for_completion_interruptible(
 469                                        &instance->insert_event);
 470                mutex_lock(&instance->completion_mutex);
 471                if (rc) {
 472                        DEBUG_TRACE(AWAIT_COMPLETION_LINE);
 473                        vchiq_log_info(vchiq_arm_log_level,
 474                                "AWAIT_COMPLETION interrupted");
 475                        ret = -EINTR;
 476                        goto out;
 477                }
 478        }
 479        DEBUG_TRACE(AWAIT_COMPLETION_LINE);
 480
 481        msgbufcount = args->msgbufcount;
 482        remove = instance->completion_remove;
 483
 484        for (ret = 0; ret < args->count; ret++) {
 485                struct vchiq_completion_data_kernel *completion;
 486                struct vchiq_completion_data user_completion;
 487                struct vchiq_service *service;
 488                struct user_service *user_service;
 489                struct vchiq_header *header;
 490
 491                if (remove == instance->completion_insert)
 492                        break;
 493
 494                completion = &instance->completions[
 495                        remove & (MAX_COMPLETIONS - 1)];
 496
 497                /*
 498                 * A read memory barrier is needed to stop
 499                 * prefetch of a stale completion record
 500                 */
 501                rmb();
 502
 503                service = completion->service_userdata;
 504                user_service = service->base.userdata;
 505
 506                memset(&user_completion, 0, sizeof(user_completion));
 507                user_completion = (struct vchiq_completion_data) {
 508                        .reason = completion->reason,
 509                        .service_userdata = user_service->userdata,
 510                };
 511
 512                header = completion->header;
 513                if (header) {
 514                        void __user *msgbuf;
 515                        int msglen;
 516
 517                        msglen = header->size + sizeof(struct vchiq_header);
 518                        /* This must be a VCHIQ-style service */
 519                        if (args->msgbufsize < msglen) {
 520                                vchiq_log_error(vchiq_arm_log_level,
 521                                        "header %pK: msgbufsize %x < msglen %x",
 522                                        header, args->msgbufsize, msglen);
 523                                WARN(1, "invalid message size\n");
 524                                if (ret == 0)
 525                                        ret = -EMSGSIZE;
 526                                break;
 527                        }
 528                        if (msgbufcount <= 0)
 529                                /* Stall here for lack of a buffer for the message. */
 530                                break;
 531                        /* Get the pointer from user space */
 532                        msgbufcount--;
 533                        if (vchiq_get_user_ptr(&msgbuf, args->msgbufs,
 534                                                msgbufcount)) {
 535                                if (ret == 0)
 536                                        ret = -EFAULT;
 537                                break;
 538                        }
 539
 540                        /* Copy the message to user space */
 541                        if (copy_to_user(msgbuf, header, msglen)) {
 542                                if (ret == 0)
 543                                        ret = -EFAULT;
 544                                break;
 545                        }
 546
 547                        /* Now it has been copied, the message can be released. */
 548                        vchiq_release_message(service->handle, header);
 549
 550                        /* The completion must point to the msgbuf. */
 551                        user_completion.header = msgbuf;
 552                }
 553
 554                if ((completion->reason == VCHIQ_SERVICE_CLOSED) &&
 555                    !instance->use_close_delivered)
 556                        vchiq_service_put(service);
 557
 558                /*
 559                 * FIXME: address space mismatch, does bulk_userdata
 560                 * actually point to user or kernel memory?
 561                 */
 562                user_completion.bulk_userdata = completion->bulk_userdata;
 563
 564                if (vchiq_put_completion(args->buf, &user_completion, ret)) {
 565                        if (ret == 0)
 566                                ret = -EFAULT;
 567                        break;
 568                }
 569
 570                /*
 571                 * Ensure that the above copy has completed
 572                 * before advancing the remove pointer.
 573                 */
 574                mb();
 575                remove++;
 576                instance->completion_remove = remove;
 577        }
 578
 579        if (msgbufcount != args->msgbufcount) {
 580                if (put_user(msgbufcount, msgbufcountp))
 581                        ret = -EFAULT;
 582        }
 583out:
 584        if (ret)
 585                complete(&instance->remove_event);
 586        mutex_unlock(&instance->completion_mutex);
 587        DEBUG_TRACE(AWAIT_COMPLETION_LINE);
 588
 589        return ret;
 590}
 591
 592static long
 593vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 594{
 595        struct vchiq_instance *instance = file->private_data;
 596        enum vchiq_status status = VCHIQ_SUCCESS;
 597        struct vchiq_service *service = NULL;
 598        long ret = 0;
 599        int i, rc;
 600
 601        vchiq_log_trace(vchiq_arm_log_level,
 602                "%s - instance %pK, cmd %s, arg %lx",
 603                __func__, instance,
 604                ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) &&
 605                (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
 606                ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
 607
 608        switch (cmd) {
 609        case VCHIQ_IOC_SHUTDOWN:
 610                if (!instance->connected)
 611                        break;
 612
 613                /* Remove all services */
 614                i = 0;
 615                while ((service = next_service_by_instance(instance->state,
 616                        instance, &i))) {
 617                        status = vchiq_remove_service(service->handle);
 618                        vchiq_service_put(service);
 619                        if (status != VCHIQ_SUCCESS)
 620                                break;
 621                }
 622                service = NULL;
 623
 624                if (status == VCHIQ_SUCCESS) {
 625                        /* Wake the completion thread and ask it to exit */
 626                        instance->closing = 1;
 627                        complete(&instance->insert_event);
 628                }
 629
 630                break;
 631
 632        case VCHIQ_IOC_CONNECT:
 633                if (instance->connected) {
 634                        ret = -EINVAL;
 635                        break;
 636                }
 637                rc = mutex_lock_killable(&instance->state->mutex);
 638                if (rc) {
 639                        vchiq_log_error(vchiq_arm_log_level,
 640                                "vchiq: connect: could not lock mutex for state %d: %d",
 641                                instance->state->id, rc);
 642                        ret = -EINTR;
 643                        break;
 644                }
 645                status = vchiq_connect_internal(instance->state, instance);
 646                mutex_unlock(&instance->state->mutex);
 647
 648                if (status == VCHIQ_SUCCESS)
 649                        instance->connected = 1;
 650                else
 651                        vchiq_log_error(vchiq_arm_log_level,
 652                                "vchiq: could not connect: %d", status);
 653                break;
 654
 655        case VCHIQ_IOC_CREATE_SERVICE: {
 656                struct vchiq_create_service __user *argp;
 657                struct vchiq_create_service args;
 658
 659                argp = (void __user *)arg;
 660                if (copy_from_user(&args, argp, sizeof(args))) {
 661                        ret = -EFAULT;
 662                        break;
 663                }
 664
 665                ret = vchiq_ioc_create_service(instance, &args);
 666                if (ret < 0)
 667                        break;
 668
 669                if (put_user(args.handle, &argp->handle)) {
 670                        vchiq_remove_service(args.handle);
 671                        ret = -EFAULT;
 672                }
 673        } break;
 674
 675        case VCHIQ_IOC_CLOSE_SERVICE:
 676        case VCHIQ_IOC_REMOVE_SERVICE: {
 677                unsigned int handle = (unsigned int)arg;
 678                struct user_service *user_service;
 679
 680                service = find_service_for_instance(instance, handle);
 681                if (!service) {
 682                        ret = -EINVAL;
 683                        break;
 684                }
 685
 686                user_service = service->base.userdata;
 687
 688                /*
 689                 * close_pending is false on first entry, and when the
 690                 * wait in vchiq_close_service has been interrupted.
 691                 */
 692                if (!user_service->close_pending) {
 693                        status = (cmd == VCHIQ_IOC_CLOSE_SERVICE) ?
 694                                 vchiq_close_service(service->handle) :
 695                                 vchiq_remove_service(service->handle);
 696                        if (status != VCHIQ_SUCCESS)
 697                                break;
 698                }
 699
 700                /*
 701                 * close_pending is true once the underlying service
 702                 * has been closed until the client library calls the
 703                 * CLOSE_DELIVERED ioctl, signalling close_event.
 704                 */
 705                if (user_service->close_pending &&
 706                        wait_for_completion_interruptible(
 707                                &user_service->close_event))
 708                        status = VCHIQ_RETRY;
 709                break;
 710        }
 711
 712        case VCHIQ_IOC_USE_SERVICE:
 713        case VCHIQ_IOC_RELEASE_SERVICE: {
 714                unsigned int handle = (unsigned int)arg;
 715
 716                service = find_service_for_instance(instance, handle);
 717                if (service) {
 718                        ret = (cmd == VCHIQ_IOC_USE_SERVICE) ?
 719                                vchiq_use_service_internal(service) :
 720                                vchiq_release_service_internal(service);
 721                        if (ret) {
 722                                vchiq_log_error(vchiq_susp_log_level,
 723                                        "%s: cmd %s returned error %ld for service %c%c%c%c:%03d",
 724                                        __func__,
 725                                        (cmd == VCHIQ_IOC_USE_SERVICE) ?
 726                                                "VCHIQ_IOC_USE_SERVICE" :
 727                                                "VCHIQ_IOC_RELEASE_SERVICE",
 728                                        ret,
 729                                        VCHIQ_FOURCC_AS_4CHARS(
 730                                                service->base.fourcc),
 731                                        service->client_id);
 732                        }
 733                } else {
 734                        ret = -EINVAL;
 735                }
 736        } break;
 737
 738        case VCHIQ_IOC_QUEUE_MESSAGE: {
 739                struct vchiq_queue_message args;
 740
 741                if (copy_from_user(&args, (const void __user *)arg,
 742                                   sizeof(args))) {
 743                        ret = -EFAULT;
 744                        break;
 745                }
 746
 747                service = find_service_for_instance(instance, args.handle);
 748
 749                if (service && (args.count <= MAX_ELEMENTS)) {
 750                        /* Copy elements into kernel space */
 751                        struct vchiq_element elements[MAX_ELEMENTS];
 752
 753                        if (copy_from_user(elements, args.elements,
 754                                args.count * sizeof(struct vchiq_element)) == 0)
 755                                ret = vchiq_ioc_queue_message(args.handle, elements,
 756                                                              args.count);
 757                        else
 758                                ret = -EFAULT;
 759                } else {
 760                        ret = -EINVAL;
 761                }
 762        } break;
 763
 764        case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
 765        case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
 766                struct vchiq_queue_bulk_transfer args;
 767                struct vchiq_queue_bulk_transfer __user *argp;
 768
 769                enum vchiq_bulk_dir dir =
 770                        (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
 771                        VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
 772
 773                argp = (void __user *)arg;
 774                if (copy_from_user(&args, argp, sizeof(args))) {
 775                        ret = -EFAULT;
 776                        break;
 777                }
 778
 779                ret = vchiq_irq_queue_bulk_tx_rx(instance, &args,
 780                                                 dir, &argp->mode);
 781        } break;
 782
 783        case VCHIQ_IOC_AWAIT_COMPLETION: {
 784                struct vchiq_await_completion args;
 785                struct vchiq_await_completion __user *argp;
 786
 787                argp = (void __user *)arg;
 788                if (copy_from_user(&args, argp, sizeof(args))) {
 789                        ret = -EFAULT;
 790                        break;
 791                }
 792
 793                ret = vchiq_ioc_await_completion(instance, &args,
 794                                                 &argp->msgbufcount);
 795        } break;
 796
 797        case VCHIQ_IOC_DEQUEUE_MESSAGE: {
 798                struct vchiq_dequeue_message args;
 799
 800                if (copy_from_user(&args, (const void __user *)arg,
 801                                   sizeof(args))) {
 802                        ret = -EFAULT;
 803                        break;
 804                }
 805
 806                ret = vchiq_ioc_dequeue_message(instance, &args);
 807        } break;
 808
 809        case VCHIQ_IOC_GET_CLIENT_ID: {
 810                unsigned int handle = (unsigned int)arg;
 811
 812                ret = vchiq_get_client_id(handle);
 813        } break;
 814
 815        case VCHIQ_IOC_GET_CONFIG: {
 816                struct vchiq_get_config args;
 817                struct vchiq_config config;
 818
 819                if (copy_from_user(&args, (const void __user *)arg,
 820                                   sizeof(args))) {
 821                        ret = -EFAULT;
 822                        break;
 823                }
 824                if (args.config_size > sizeof(config)) {
 825                        ret = -EINVAL;
 826                        break;
 827                }
 828
 829                vchiq_get_config(&config);
 830                if (copy_to_user(args.pconfig, &config, args.config_size)) {
 831                        ret = -EFAULT;
 832                        break;
 833                }
 834        } break;
 835
 836        case VCHIQ_IOC_SET_SERVICE_OPTION: {
 837                struct vchiq_set_service_option args;
 838
 839                if (copy_from_user(&args, (const void __user *)arg,
 840                                   sizeof(args))) {
 841                        ret = -EFAULT;
 842                        break;
 843                }
 844
 845                service = find_service_for_instance(instance, args.handle);
 846                if (!service) {
 847                        ret = -EINVAL;
 848                        break;
 849                }
 850
 851                ret = vchiq_set_service_option(args.handle, args.option,
 852                                               args.value);
 853        } break;
 854
 855        case VCHIQ_IOC_LIB_VERSION: {
 856                unsigned int lib_version = (unsigned int)arg;
 857
 858                if (lib_version < VCHIQ_VERSION_MIN)
 859                        ret = -EINVAL;
 860                else if (lib_version >= VCHIQ_VERSION_CLOSE_DELIVERED)
 861                        instance->use_close_delivered = 1;
 862        } break;
 863
 864        case VCHIQ_IOC_CLOSE_DELIVERED: {
 865                unsigned int handle = (unsigned int)arg;
 866
 867                service = find_closed_service_for_instance(instance, handle);
 868                if (service) {
 869                        struct user_service *user_service =
 870                                (struct user_service *)service->base.userdata;
 871                        close_delivered(user_service);
 872                } else {
 873                        ret = -EINVAL;
 874                }
 875        } break;
 876
 877        default:
 878                ret = -ENOTTY;
 879                break;
 880        }
 881
 882        if (service)
 883                vchiq_service_put(service);
 884
 885        if (ret == 0) {
 886                if (status == VCHIQ_ERROR)
 887                        ret = -EIO;
 888                else if (status == VCHIQ_RETRY)
 889                        ret = -EINTR;
 890        }
 891
 892        if ((status == VCHIQ_SUCCESS) && (ret < 0) && (ret != -EINTR) &&
 893                (ret != -EWOULDBLOCK))
 894                vchiq_log_info(vchiq_arm_log_level,
 895                        "  ioctl instance %pK, cmd %s -> status %d, %ld",
 896                        instance,
 897                        (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
 898                                ioctl_names[_IOC_NR(cmd)] :
 899                                "<invalid>",
 900                        status, ret);
 901        else
 902                vchiq_log_trace(vchiq_arm_log_level,
 903                        "  ioctl instance %pK, cmd %s -> status %d, %ld",
 904                        instance,
 905                        (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
 906                                ioctl_names[_IOC_NR(cmd)] :
 907                                "<invalid>",
 908                        status, ret);
 909
 910        return ret;
 911}
 912
 913#if defined(CONFIG_COMPAT)
 914
 915struct vchiq_service_params32 {
 916        int fourcc;
 917        compat_uptr_t callback;
 918        compat_uptr_t userdata;
 919        short version; /* Increment for non-trivial changes */
 920        short version_min; /* Update for incompatible changes */
 921};
 922
 923struct vchiq_create_service32 {
 924        struct vchiq_service_params32 params;
 925        int is_open;
 926        int is_vchi;
 927        unsigned int handle; /* OUT */
 928};
 929
 930#define VCHIQ_IOC_CREATE_SERVICE32 \
 931        _IOWR(VCHIQ_IOC_MAGIC, 2, struct vchiq_create_service32)
 932
 933static long
 934vchiq_compat_ioctl_create_service(struct file *file, unsigned int cmd,
 935                                  struct vchiq_create_service32 __user *ptrargs32)
 936{
 937        struct vchiq_create_service args;
 938        struct vchiq_create_service32 args32;
 939        long ret;
 940
 941        if (copy_from_user(&args32, ptrargs32, sizeof(args32)))
 942                return -EFAULT;
 943
 944        args = (struct vchiq_create_service) {
 945                .params = {
 946                        .fourcc      = args32.params.fourcc,
 947                        .callback    = compat_ptr(args32.params.callback),
 948                        .userdata    = compat_ptr(args32.params.userdata),
 949                        .version     = args32.params.version,
 950                        .version_min = args32.params.version_min,
 951                },
 952                .is_open = args32.is_open,
 953                .is_vchi = args32.is_vchi,
 954                .handle  = args32.handle,
 955        };
 956
 957        ret = vchiq_ioc_create_service(file->private_data, &args);
 958        if (ret < 0)
 959                return ret;
 960
 961        if (put_user(args.handle, &ptrargs32->handle)) {
 962                vchiq_remove_service(args.handle);
 963                return -EFAULT;
 964        }
 965
 966        return 0;
 967}
 968
 969struct vchiq_element32 {
 970        compat_uptr_t data;
 971        unsigned int size;
 972};
 973
 974struct vchiq_queue_message32 {
 975        unsigned int handle;
 976        unsigned int count;
 977        compat_uptr_t elements;
 978};
 979
 980#define VCHIQ_IOC_QUEUE_MESSAGE32 \
 981        _IOW(VCHIQ_IOC_MAGIC,  4, struct vchiq_queue_message32)
 982
 983static long
 984vchiq_compat_ioctl_queue_message(struct file *file,
 985                                 unsigned int cmd,
 986                                 struct vchiq_queue_message32 __user *arg)
 987{
 988        struct vchiq_queue_message args;
 989        struct vchiq_queue_message32 args32;
 990        struct vchiq_service *service;
 991        int ret;
 992
 993        if (copy_from_user(&args32, arg, sizeof(args32)))
 994                return -EFAULT;
 995
 996        args = (struct vchiq_queue_message) {
 997                .handle   = args32.handle,
 998                .count    = args32.count,
 999                .elements = compat_ptr(args32.elements),
1000        };
1001
1002        if (args32.count > MAX_ELEMENTS)
1003                return -EINVAL;
1004
1005        service = find_service_for_instance(file->private_data, args.handle);
1006        if (!service)
1007                return -EINVAL;
1008
1009        if (args32.elements && args32.count) {
1010                struct vchiq_element32 element32[MAX_ELEMENTS];
1011                struct vchiq_element elements[MAX_ELEMENTS];
1012                unsigned int count;
1013
1014                if (copy_from_user(&element32, args.elements,
1015                                   sizeof(element32))) {
1016                        vchiq_service_put(service);
1017                        return -EFAULT;
1018                }
1019
1020                for (count = 0; count < args32.count; count++) {
1021                        elements[count].data =
1022                                compat_ptr(element32[count].data);
1023                        elements[count].size = element32[count].size;
1024                }
1025                ret = vchiq_ioc_queue_message(args.handle, elements,
1026                                              args.count);
1027        } else {
1028                ret = -EINVAL;
1029        }
1030        vchiq_service_put(service);
1031
1032        return ret;
1033}
1034
1035struct vchiq_queue_bulk_transfer32 {
1036        unsigned int handle;
1037        compat_uptr_t data;
1038        unsigned int size;
1039        compat_uptr_t userdata;
1040        enum vchiq_bulk_mode mode;
1041};
1042
1043#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT32 \
1044        _IOWR(VCHIQ_IOC_MAGIC, 5, struct vchiq_queue_bulk_transfer32)
1045#define VCHIQ_IOC_QUEUE_BULK_RECEIVE32 \
1046        _IOWR(VCHIQ_IOC_MAGIC, 6, struct vchiq_queue_bulk_transfer32)
1047
1048static long
1049vchiq_compat_ioctl_queue_bulk(struct file *file,
1050                              unsigned int cmd,
1051                              struct vchiq_queue_bulk_transfer32 __user *argp)
1052{
1053        struct vchiq_queue_bulk_transfer32 args32;
1054        struct vchiq_queue_bulk_transfer args;
1055        enum vchiq_bulk_dir dir = (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT32) ?
1056                                  VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
1057
1058        if (copy_from_user(&args32, argp, sizeof(args32)))
1059                return -EFAULT;
1060
1061        args = (struct vchiq_queue_bulk_transfer) {
1062                .handle   = args32.handle,
1063                .data     = compat_ptr(args32.data),
1064                .size     = args32.size,
1065                .userdata = compat_ptr(args32.userdata),
1066                .mode     = args32.mode,
1067        };
1068
1069        return vchiq_irq_queue_bulk_tx_rx(file->private_data, &args,
1070                                          dir, &argp->mode);
1071}
1072
1073struct vchiq_await_completion32 {
1074        unsigned int count;
1075        compat_uptr_t buf;
1076        unsigned int msgbufsize;
1077        unsigned int msgbufcount; /* IN/OUT */
1078        compat_uptr_t msgbufs;
1079};
1080
1081#define VCHIQ_IOC_AWAIT_COMPLETION32 \
1082        _IOWR(VCHIQ_IOC_MAGIC, 7, struct vchiq_await_completion32)
1083
1084static long
1085vchiq_compat_ioctl_await_completion(struct file *file,
1086                                    unsigned int cmd,
1087                                    struct vchiq_await_completion32 __user *argp)
1088{
1089        struct vchiq_await_completion args;
1090        struct vchiq_await_completion32 args32;
1091
1092        if (copy_from_user(&args32, argp, sizeof(args32)))
1093                return -EFAULT;
1094
1095        args = (struct vchiq_await_completion) {
1096                .count          = args32.count,
1097                .buf            = compat_ptr(args32.buf),
1098                .msgbufsize     = args32.msgbufsize,
1099                .msgbufcount    = args32.msgbufcount,
1100                .msgbufs        = compat_ptr(args32.msgbufs),
1101        };
1102
1103        return vchiq_ioc_await_completion(file->private_data, &args,
1104                                          &argp->msgbufcount);
1105}
1106
1107struct vchiq_dequeue_message32 {
1108        unsigned int handle;
1109        int blocking;
1110        unsigned int bufsize;
1111        compat_uptr_t buf;
1112};
1113
1114#define VCHIQ_IOC_DEQUEUE_MESSAGE32 \
1115        _IOWR(VCHIQ_IOC_MAGIC, 8, struct vchiq_dequeue_message32)
1116
1117static long
1118vchiq_compat_ioctl_dequeue_message(struct file *file,
1119                                   unsigned int cmd,
1120                                   struct vchiq_dequeue_message32 __user *arg)
1121{
1122        struct vchiq_dequeue_message32 args32;
1123        struct vchiq_dequeue_message args;
1124
1125        if (copy_from_user(&args32, arg, sizeof(args32)))
1126                return -EFAULT;
1127
1128        args = (struct vchiq_dequeue_message) {
1129                .handle         = args32.handle,
1130                .blocking       = args32.blocking,
1131                .bufsize        = args32.bufsize,
1132                .buf            = compat_ptr(args32.buf),
1133        };
1134
1135        return vchiq_ioc_dequeue_message(file->private_data, &args);
1136}
1137
1138struct vchiq_get_config32 {
1139        unsigned int config_size;
1140        compat_uptr_t pconfig;
1141};
1142
1143#define VCHIQ_IOC_GET_CONFIG32 \
1144        _IOWR(VCHIQ_IOC_MAGIC, 10, struct vchiq_get_config32)
1145
1146static long
1147vchiq_compat_ioctl_get_config(struct file *file,
1148                              unsigned int cmd,
1149                              struct vchiq_get_config32 __user *arg)
1150{
1151        struct vchiq_get_config32 args32;
1152        struct vchiq_config config;
1153        void __user *ptr;
1154
1155        if (copy_from_user(&args32, arg, sizeof(args32)))
1156                return -EFAULT;
1157        if (args32.config_size > sizeof(config))
1158                return -EINVAL;
1159
1160        vchiq_get_config(&config);
1161        ptr = compat_ptr(args32.pconfig);
1162        if (copy_to_user(ptr, &config, args32.config_size))
1163                return -EFAULT;
1164
1165        return 0;
1166}
1167
1168static long
1169vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1170{
1171        void __user *argp = compat_ptr(arg);
1172
1173        switch (cmd) {
1174        case VCHIQ_IOC_CREATE_SERVICE32:
1175                return vchiq_compat_ioctl_create_service(file, cmd, argp);
1176        case VCHIQ_IOC_QUEUE_MESSAGE32:
1177                return vchiq_compat_ioctl_queue_message(file, cmd, argp);
1178        case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32:
1179        case VCHIQ_IOC_QUEUE_BULK_RECEIVE32:
1180                return vchiq_compat_ioctl_queue_bulk(file, cmd, argp);
1181        case VCHIQ_IOC_AWAIT_COMPLETION32:
1182                return vchiq_compat_ioctl_await_completion(file, cmd, argp);
1183        case VCHIQ_IOC_DEQUEUE_MESSAGE32:
1184                return vchiq_compat_ioctl_dequeue_message(file, cmd, argp);
1185        case VCHIQ_IOC_GET_CONFIG32:
1186                return vchiq_compat_ioctl_get_config(file, cmd, argp);
1187        default:
1188                return vchiq_ioctl(file, cmd, (unsigned long)argp);
1189        }
1190}
1191
1192#endif
1193
1194static int vchiq_open(struct inode *inode, struct file *file)
1195{
1196        struct vchiq_state *state = vchiq_get_state();
1197        struct vchiq_instance *instance;
1198
1199        vchiq_log_info(vchiq_arm_log_level, "vchiq_open");
1200
1201        if (!state) {
1202                vchiq_log_error(vchiq_arm_log_level,
1203                                "vchiq has no connection to VideoCore");
1204                return -ENOTCONN;
1205        }
1206
1207        instance = kzalloc(sizeof(*instance), GFP_KERNEL);
1208        if (!instance)
1209                return -ENOMEM;
1210
1211        instance->state = state;
1212        instance->pid = current->tgid;
1213
1214        vchiq_debugfs_add_instance(instance);
1215
1216        init_completion(&instance->insert_event);
1217        init_completion(&instance->remove_event);
1218        mutex_init(&instance->completion_mutex);
1219        mutex_init(&instance->bulk_waiter_list_mutex);
1220        INIT_LIST_HEAD(&instance->bulk_waiter_list);
1221
1222        file->private_data = instance;
1223
1224        return 0;
1225}
1226
1227static int vchiq_release(struct inode *inode, struct file *file)
1228{
1229        struct vchiq_instance *instance = file->private_data;
1230        struct vchiq_state *state = vchiq_get_state();
1231        struct vchiq_service *service;
1232        int ret = 0;
1233        int i;
1234
1235        vchiq_log_info(vchiq_arm_log_level, "%s: instance=%lx", __func__,
1236                       (unsigned long)instance);
1237
1238        if (!state) {
1239                ret = -EPERM;
1240                goto out;
1241        }
1242
1243        /* Ensure videocore is awake to allow termination. */
1244        vchiq_use_internal(instance->state, NULL, USE_TYPE_VCHIQ);
1245
1246        mutex_lock(&instance->completion_mutex);
1247
1248        /* Wake the completion thread and ask it to exit */
1249        instance->closing = 1;
1250        complete(&instance->insert_event);
1251
1252        mutex_unlock(&instance->completion_mutex);
1253
1254        /* Wake the slot handler if the completion queue is full. */
1255        complete(&instance->remove_event);
1256
1257        /* Mark all services for termination... */
1258        i = 0;
1259        while ((service = next_service_by_instance(state, instance, &i))) {
1260                struct user_service *user_service = service->base.userdata;
1261
1262                /* Wake the slot handler if the msg queue is full. */
1263                complete(&user_service->remove_event);
1264
1265                vchiq_terminate_service_internal(service);
1266                vchiq_service_put(service);
1267        }
1268
1269        /* ...and wait for them to die */
1270        i = 0;
1271        while ((service = next_service_by_instance(state, instance, &i))) {
1272                struct user_service *user_service = service->base.userdata;
1273
1274                wait_for_completion(&service->remove_event);
1275
1276                if (WARN_ON(service->srvstate != VCHIQ_SRVSTATE_FREE)) {
1277                        vchiq_service_put(service);
1278                        break;
1279                }
1280
1281                spin_lock(&msg_queue_spinlock);
1282
1283                while (user_service->msg_remove != user_service->msg_insert) {
1284                        struct vchiq_header *header;
1285                        int m = user_service->msg_remove & (MSG_QUEUE_SIZE - 1);
1286
1287                        header = user_service->msg_queue[m];
1288                        user_service->msg_remove++;
1289                        spin_unlock(&msg_queue_spinlock);
1290
1291                        if (header)
1292                                vchiq_release_message(service->handle, header);
1293                        spin_lock(&msg_queue_spinlock);
1294                }
1295
1296                spin_unlock(&msg_queue_spinlock);
1297
1298                vchiq_service_put(service);
1299        }
1300
1301        /* Release any closed services */
1302        while (instance->completion_remove != instance->completion_insert) {
1303                struct vchiq_completion_data_kernel *completion;
1304                struct vchiq_service *service;
1305
1306                completion = &instance->completions[
1307                        instance->completion_remove & (MAX_COMPLETIONS - 1)];
1308                service = completion->service_userdata;
1309                if (completion->reason == VCHIQ_SERVICE_CLOSED) {
1310                        struct user_service *user_service =
1311                                                        service->base.userdata;
1312
1313                        /* Wake any blocked user-thread */
1314                        if (instance->use_close_delivered)
1315                                complete(&user_service->close_event);
1316                        vchiq_service_put(service);
1317                }
1318                instance->completion_remove++;
1319        }
1320
1321        /* Release the PEER service count. */
1322        vchiq_release_internal(instance->state, NULL);
1323
1324        free_bulk_waiter(instance);
1325
1326        vchiq_debugfs_remove_instance(instance);
1327
1328        kfree(instance);
1329        file->private_data = NULL;
1330
1331out:
1332        return ret;
1333}
1334
1335static ssize_t
1336vchiq_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
1337{
1338        struct dump_context context;
1339        int err;
1340
1341        context.buf = buf;
1342        context.actual = 0;
1343        context.space = count;
1344        context.offset = *ppos;
1345
1346        err = vchiq_dump_state(&context, &g_state);
1347        if (err)
1348                return err;
1349
1350        *ppos += context.actual;
1351
1352        return context.actual;
1353}
1354
1355static const struct file_operations
1356vchiq_fops = {
1357        .owner = THIS_MODULE,
1358        .unlocked_ioctl = vchiq_ioctl,
1359#if defined(CONFIG_COMPAT)
1360        .compat_ioctl = vchiq_compat_ioctl,
1361#endif
1362        .open = vchiq_open,
1363        .release = vchiq_release,
1364        .read = vchiq_read
1365};
1366
1367/**
1368 *      vchiq_register_chrdev - Register the char driver for vchiq
1369 *                              and create the necessary class and
1370 *                              device files in userspace.
1371 *      @parent         The parent of the char device.
1372 *
1373 *      Returns 0 on success else returns the error code.
1374 */
1375int vchiq_register_chrdev(struct device *parent)
1376{
1377        struct device *vchiq_dev;
1378        int ret;
1379
1380        vchiq_class = class_create(THIS_MODULE, DEVICE_NAME);
1381        if (IS_ERR(vchiq_class)) {
1382                pr_err("Failed to create vchiq class\n");
1383                ret = PTR_ERR(vchiq_class);
1384                goto error_exit;
1385        }
1386
1387        ret = alloc_chrdev_region(&vchiq_devid, 0, 1, DEVICE_NAME);
1388        if (ret) {
1389                pr_err("vchiq: Failed to allocate vchiq's chrdev region\n");
1390                goto alloc_region_error;
1391        }
1392
1393        cdev_init(&vchiq_cdev, &vchiq_fops);
1394        vchiq_cdev.owner = THIS_MODULE;
1395        ret = cdev_add(&vchiq_cdev, vchiq_devid, 1);
1396        if (ret) {
1397                vchiq_log_error(vchiq_arm_log_level,
1398                                "Unable to register vchiq char device");
1399                goto cdev_add_error;
1400        }
1401
1402        vchiq_dev = device_create(vchiq_class, parent, vchiq_devid, NULL,
1403                                  DEVICE_NAME);
1404        if (IS_ERR(vchiq_dev)) {
1405                vchiq_log_error(vchiq_arm_log_level,
1406                                "Failed to create vchiq char device node");
1407                ret = PTR_ERR(vchiq_dev);
1408                goto device_create_error;
1409        }
1410
1411        vchiq_log_info(vchiq_arm_log_level,
1412                       "vchiq char dev initialised successfully - device %d.%d",
1413                        MAJOR(vchiq_devid), MINOR(vchiq_devid));
1414
1415        return 0;
1416
1417device_create_error:
1418        cdev_del(&vchiq_cdev);
1419
1420cdev_add_error:
1421        unregister_chrdev_region(vchiq_devid, 1);
1422
1423alloc_region_error:
1424        class_destroy(vchiq_class);
1425
1426error_exit:
1427        return ret;
1428}
1429
1430/**
1431 *      vchiq_deregister_chrdev - Deregister and cleanup the vchiq char
1432 *                                driver and device files
1433 */
1434void vchiq_deregister_chrdev(void)
1435{
1436        device_destroy(vchiq_class, vchiq_devid);
1437        cdev_del(&vchiq_cdev);
1438        unregister_chrdev_region(vchiq_devid, 1);
1439        class_destroy(vchiq_class);
1440}
1441