linux/drivers/misc/mei/main.c
<<
>>
Prefs
   1/*
   2 *
   3 * Intel Management Engine Interface (Intel MEI) Linux driver
   4 * Copyright (c) 2003-2012, Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 */
  16
  17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  18
  19#include <linux/module.h>
  20#include <linux/moduleparam.h>
  21#include <linux/kernel.h>
  22#include <linux/device.h>
  23#include <linux/fs.h>
  24#include <linux/errno.h>
  25#include <linux/types.h>
  26#include <linux/fcntl.h>
  27#include <linux/aio.h>
  28#include <linux/pci.h>
  29#include <linux/poll.h>
  30#include <linux/init.h>
  31#include <linux/ioctl.h>
  32#include <linux/cdev.h>
  33#include <linux/sched.h>
  34#include <linux/uuid.h>
  35#include <linux/compat.h>
  36#include <linux/jiffies.h>
  37#include <linux/interrupt.h>
  38#include <linux/miscdevice.h>
  39
  40#include <linux/mei.h>
  41
  42#include "mei_dev.h"
  43#include "hw-me.h"
  44#include "client.h"
  45
  46/**
  47 * mei_open - the open function
  48 *
  49 * @inode: pointer to inode structure
  50 * @file: pointer to file structure
  51 e
  52 * returns 0 on success, <0 on error
  53 */
  54static int mei_open(struct inode *inode, struct file *file)
  55{
  56        struct miscdevice *misc = file->private_data;
  57        struct pci_dev *pdev;
  58        struct mei_cl *cl;
  59        struct mei_device *dev;
  60
  61        int err;
  62
  63        err = -ENODEV;
  64        if (!misc->parent)
  65                goto out;
  66
  67        pdev = container_of(misc->parent, struct pci_dev, dev);
  68
  69        dev = pci_get_drvdata(pdev);
  70        if (!dev)
  71                goto out;
  72
  73        mutex_lock(&dev->device_lock);
  74        err = -ENOMEM;
  75        cl = mei_cl_allocate(dev);
  76        if (!cl)
  77                goto out_unlock;
  78
  79        err = -ENODEV;
  80        if (dev->dev_state != MEI_DEV_ENABLED) {
  81                dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED  dev_state = %s\n",
  82                    mei_dev_state_str(dev->dev_state));
  83                goto out_unlock;
  84        }
  85        err = -EMFILE;
  86        if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
  87                dev_err(&dev->pdev->dev, "open_handle_count exceded %d",
  88                        MEI_MAX_OPEN_HANDLE_COUNT);
  89                goto out_unlock;
  90        }
  91
  92        err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
  93        if (err)
  94                goto out_unlock;
  95
  96        file->private_data = cl;
  97        mutex_unlock(&dev->device_lock);
  98
  99        return nonseekable_open(inode, file);
 100
 101out_unlock:
 102        mutex_unlock(&dev->device_lock);
 103        kfree(cl);
 104out:
 105        return err;
 106}
 107
 108/**
 109 * mei_release - the release function
 110 *
 111 * @inode: pointer to inode structure
 112 * @file: pointer to file structure
 113 *
 114 * returns 0 on success, <0 on error
 115 */
 116static int mei_release(struct inode *inode, struct file *file)
 117{
 118        struct mei_cl *cl = file->private_data;
 119        struct mei_cl_cb *cb;
 120        struct mei_device *dev;
 121        int rets = 0;
 122
 123        if (WARN_ON(!cl || !cl->dev))
 124                return -ENODEV;
 125
 126        dev = cl->dev;
 127
 128        mutex_lock(&dev->device_lock);
 129        if (cl == &dev->iamthif_cl) {
 130                rets = mei_amthif_release(dev, file);
 131                goto out;
 132        }
 133        if (cl->state == MEI_FILE_CONNECTED) {
 134                cl->state = MEI_FILE_DISCONNECTING;
 135                dev_dbg(&dev->pdev->dev,
 136                        "disconnecting client host client = %d, "
 137                    "ME client = %d\n",
 138                    cl->host_client_id,
 139                    cl->me_client_id);
 140                rets = mei_cl_disconnect(cl);
 141        }
 142        mei_cl_flush_queues(cl);
 143        dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
 144            cl->host_client_id,
 145            cl->me_client_id);
 146
 147        if (dev->open_handle_count > 0) {
 148                clear_bit(cl->host_client_id, dev->host_clients_map);
 149                dev->open_handle_count--;
 150        }
 151        mei_cl_unlink(cl);
 152
 153
 154        /* free read cb */
 155        cb = NULL;
 156        if (cl->read_cb) {
 157                cb = mei_cl_find_read_cb(cl);
 158                /* Remove entry from read list */
 159                if (cb)
 160                        list_del(&cb->list);
 161
 162                cb = cl->read_cb;
 163                cl->read_cb = NULL;
 164        }
 165
 166        file->private_data = NULL;
 167
 168        if (cb) {
 169                mei_io_cb_free(cb);
 170                cb = NULL;
 171        }
 172
 173        kfree(cl);
 174out:
 175        mutex_unlock(&dev->device_lock);
 176        return rets;
 177}
 178
 179
 180/**
 181 * mei_read - the read function.
 182 *
 183 * @file: pointer to file structure
 184 * @ubuf: pointer to user buffer
 185 * @length: buffer length
 186 * @offset: data offset in buffer
 187 *
 188 * returns >=0 data length on success , <0 on error
 189 */
 190static ssize_t mei_read(struct file *file, char __user *ubuf,
 191                        size_t length, loff_t *offset)
 192{
 193        struct mei_cl *cl = file->private_data;
 194        struct mei_cl_cb *cb_pos = NULL;
 195        struct mei_cl_cb *cb = NULL;
 196        struct mei_device *dev;
 197        int i;
 198        int rets;
 199        int err;
 200
 201
 202        if (WARN_ON(!cl || !cl->dev))
 203                return -ENODEV;
 204
 205        dev = cl->dev;
 206
 207        mutex_lock(&dev->device_lock);
 208        if (dev->dev_state != MEI_DEV_ENABLED) {
 209                rets = -ENODEV;
 210                goto out;
 211        }
 212
 213        if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
 214                /* Do not allow to read watchdog client */
 215                i = mei_me_cl_by_uuid(dev, &mei_wd_guid);
 216                if (i >= 0) {
 217                        struct mei_me_client *me_client = &dev->me_clients[i];
 218                        if (cl->me_client_id == me_client->client_id) {
 219                                rets = -EBADF;
 220                                goto out;
 221                        }
 222                }
 223        } else {
 224                cl->sm_state &= ~MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
 225        }
 226
 227        if (cl == &dev->iamthif_cl) {
 228                rets = mei_amthif_read(dev, file, ubuf, length, offset);
 229                goto out;
 230        }
 231
 232        if (cl->read_cb && cl->read_cb->buf_idx > *offset) {
 233                cb = cl->read_cb;
 234                goto copy_buffer;
 235        } else if (cl->read_cb && cl->read_cb->buf_idx > 0 &&
 236                   cl->read_cb->buf_idx <= *offset) {
 237                cb = cl->read_cb;
 238                rets = 0;
 239                goto free;
 240        } else if ((!cl->read_cb || !cl->read_cb->buf_idx) && *offset > 0) {
 241                /*Offset needs to be cleaned for contiguous reads*/
 242                *offset = 0;
 243                rets = 0;
 244                goto out;
 245        }
 246
 247        err = mei_cl_read_start(cl, length);
 248        if (err && err != -EBUSY) {
 249                dev_dbg(&dev->pdev->dev,
 250                        "mei start read failure with status = %d\n", err);
 251                rets = err;
 252                goto out;
 253        }
 254
 255        if (MEI_READ_COMPLETE != cl->reading_state &&
 256                        !waitqueue_active(&cl->rx_wait)) {
 257                if (file->f_flags & O_NONBLOCK) {
 258                        rets = -EAGAIN;
 259                        goto out;
 260                }
 261
 262                mutex_unlock(&dev->device_lock);
 263
 264                if (wait_event_interruptible(cl->rx_wait,
 265                        (MEI_READ_COMPLETE == cl->reading_state ||
 266                         MEI_FILE_INITIALIZING == cl->state ||
 267                         MEI_FILE_DISCONNECTED == cl->state ||
 268                         MEI_FILE_DISCONNECTING == cl->state))) {
 269                        if (signal_pending(current))
 270                                return -EINTR;
 271                        return -ERESTARTSYS;
 272                }
 273
 274                mutex_lock(&dev->device_lock);
 275                if (MEI_FILE_INITIALIZING == cl->state ||
 276                    MEI_FILE_DISCONNECTED == cl->state ||
 277                    MEI_FILE_DISCONNECTING == cl->state) {
 278                        rets = -EBUSY;
 279                        goto out;
 280                }
 281        }
 282
 283        cb = cl->read_cb;
 284
 285        if (!cb) {
 286                rets = -ENODEV;
 287                goto out;
 288        }
 289        if (cl->reading_state != MEI_READ_COMPLETE) {
 290                rets = 0;
 291                goto out;
 292        }
 293        /* now copy the data to user space */
 294copy_buffer:
 295        dev_dbg(&dev->pdev->dev, "buf.size = %d buf.idx= %ld\n",
 296            cb->response_buffer.size, cb->buf_idx);
 297        if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
 298                rets = -EMSGSIZE;
 299                goto free;
 300        }
 301
 302        /* length is being truncated to PAGE_SIZE,
 303         * however buf_idx may point beyond that */
 304        length = min_t(size_t, length, cb->buf_idx - *offset);
 305
 306        if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
 307                rets = -EFAULT;
 308                goto free;
 309        }
 310
 311        rets = length;
 312        *offset += length;
 313        if ((unsigned long)*offset < cb->buf_idx)
 314                goto out;
 315
 316free:
 317        cb_pos = mei_cl_find_read_cb(cl);
 318        /* Remove entry from read list */
 319        if (cb_pos)
 320                list_del(&cb_pos->list);
 321        mei_io_cb_free(cb);
 322        cl->reading_state = MEI_IDLE;
 323        cl->read_cb = NULL;
 324out:
 325        dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
 326        mutex_unlock(&dev->device_lock);
 327        return rets;
 328}
 329/**
 330 * mei_write - the write function.
 331 *
 332 * @file: pointer to file structure
 333 * @ubuf: pointer to user buffer
 334 * @length: buffer length
 335 * @offset: data offset in buffer
 336 *
 337 * returns >=0 data length on success , <0 on error
 338 */
 339static ssize_t mei_write(struct file *file, const char __user *ubuf,
 340                         size_t length, loff_t *offset)
 341{
 342        struct mei_cl *cl = file->private_data;
 343        struct mei_cl_cb *write_cb = NULL;
 344        struct mei_device *dev;
 345        unsigned long timeout = 0;
 346        int rets;
 347        int id;
 348
 349        if (WARN_ON(!cl || !cl->dev))
 350                return -ENODEV;
 351
 352        dev = cl->dev;
 353
 354        mutex_lock(&dev->device_lock);
 355
 356        if (dev->dev_state != MEI_DEV_ENABLED) {
 357                rets = -ENODEV;
 358                goto out;
 359        }
 360
 361        id = mei_me_cl_by_id(dev, cl->me_client_id);
 362        if (id < 0) {
 363                rets = -ENODEV;
 364                goto out;
 365        }
 366        if (length > dev->me_clients[id].props.max_msg_length || length <= 0) {
 367                rets = -EMSGSIZE;
 368                goto out;
 369        }
 370
 371        if (cl->state != MEI_FILE_CONNECTED) {
 372                dev_err(&dev->pdev->dev, "host client = %d,  is not connected to ME client = %d",
 373                        cl->host_client_id, cl->me_client_id);
 374                rets = -ENODEV;
 375                goto out;
 376        }
 377        if (cl == &dev->iamthif_cl) {
 378                write_cb = mei_amthif_find_read_list_entry(dev, file);
 379
 380                if (write_cb) {
 381                        timeout = write_cb->read_time +
 382                                mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
 383
 384                        if (time_after(jiffies, timeout) ||
 385                            cl->reading_state == MEI_READ_COMPLETE) {
 386                                *offset = 0;
 387                                list_del(&write_cb->list);
 388                                mei_io_cb_free(write_cb);
 389                                write_cb = NULL;
 390                        }
 391                }
 392        }
 393
 394        /* free entry used in read */
 395        if (cl->reading_state == MEI_READ_COMPLETE) {
 396                *offset = 0;
 397                write_cb = mei_cl_find_read_cb(cl);
 398                if (write_cb) {
 399                        list_del(&write_cb->list);
 400                        mei_io_cb_free(write_cb);
 401                        write_cb = NULL;
 402                        cl->reading_state = MEI_IDLE;
 403                        cl->read_cb = NULL;
 404                }
 405        } else if (cl->reading_state == MEI_IDLE)
 406                *offset = 0;
 407
 408
 409        write_cb = mei_io_cb_init(cl, file);
 410        if (!write_cb) {
 411                dev_err(&dev->pdev->dev, "write cb allocation failed\n");
 412                rets = -ENOMEM;
 413                goto out;
 414        }
 415        rets = mei_io_cb_alloc_req_buf(write_cb, length);
 416        if (rets)
 417                goto out;
 418
 419        rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
 420        if (rets)
 421                goto out;
 422
 423        cl->sm_state = 0;
 424        if (length == 4 &&
 425            ((memcmp(mei_wd_state_independence_msg[0],
 426                                 write_cb->request_buffer.data, 4) == 0) ||
 427             (memcmp(mei_wd_state_independence_msg[1],
 428                                 write_cb->request_buffer.data, 4) == 0) ||
 429             (memcmp(mei_wd_state_independence_msg[2],
 430                                 write_cb->request_buffer.data, 4) == 0)))
 431                cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
 432
 433        if (cl == &dev->iamthif_cl) {
 434                rets = mei_amthif_write(dev, write_cb);
 435
 436                if (rets) {
 437                        dev_err(&dev->pdev->dev,
 438                                "amthif write failed with status = %d\n", rets);
 439                        goto out;
 440                }
 441                mutex_unlock(&dev->device_lock);
 442                return length;
 443        }
 444
 445        rets = mei_cl_write(cl, write_cb, false);
 446out:
 447        mutex_unlock(&dev->device_lock);
 448        if (rets < 0)
 449                mei_io_cb_free(write_cb);
 450        return rets;
 451}
 452
 453/**
 454 * mei_ioctl_connect_client - the connect to fw client IOCTL function
 455 *
 456 * @dev: the device structure
 457 * @data: IOCTL connect data, input and output parameters
 458 * @file: private data of the file object
 459 *
 460 * Locking: called under "dev->device_lock" lock
 461 *
 462 * returns 0 on success, <0 on failure.
 463 */
 464static int mei_ioctl_connect_client(struct file *file,
 465                        struct mei_connect_client_data *data)
 466{
 467        struct mei_device *dev;
 468        struct mei_client *client;
 469        struct mei_cl *cl;
 470        int i;
 471        int rets;
 472
 473        cl = file->private_data;
 474        if (WARN_ON(!cl || !cl->dev))
 475                return -ENODEV;
 476
 477        dev = cl->dev;
 478
 479        if (dev->dev_state != MEI_DEV_ENABLED) {
 480                rets = -ENODEV;
 481                goto end;
 482        }
 483
 484        if (cl->state != MEI_FILE_INITIALIZING &&
 485            cl->state != MEI_FILE_DISCONNECTED) {
 486                rets = -EBUSY;
 487                goto end;
 488        }
 489
 490        /* find ME client we're trying to connect to */
 491        i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
 492        if (i < 0 || dev->me_clients[i].props.fixed_address) {
 493                dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
 494                                &data->in_client_uuid);
 495                rets = -ENODEV;
 496                goto end;
 497        }
 498
 499        cl->me_client_id = dev->me_clients[i].client_id;
 500        cl->state = MEI_FILE_CONNECTING;
 501
 502        dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
 503                        cl->me_client_id);
 504        dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
 505                        dev->me_clients[i].props.protocol_version);
 506        dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
 507                        dev->me_clients[i].props.max_msg_length);
 508
 509        /* if we're connecting to amthif client then we will use the
 510         * existing connection
 511         */
 512        if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
 513                dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
 514                if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
 515                        rets = -ENODEV;
 516                        goto end;
 517                }
 518                clear_bit(cl->host_client_id, dev->host_clients_map);
 519                mei_cl_unlink(cl);
 520
 521                kfree(cl);
 522                cl = NULL;
 523                file->private_data = &dev->iamthif_cl;
 524
 525                client = &data->out_client_properties;
 526                client->max_msg_length =
 527                        dev->me_clients[i].props.max_msg_length;
 528                client->protocol_version =
 529                        dev->me_clients[i].props.protocol_version;
 530                rets = dev->iamthif_cl.status;
 531
 532                goto end;
 533        }
 534
 535
 536        /* prepare the output buffer */
 537        client = &data->out_client_properties;
 538        client->max_msg_length = dev->me_clients[i].props.max_msg_length;
 539        client->protocol_version = dev->me_clients[i].props.protocol_version;
 540        dev_dbg(&dev->pdev->dev, "Can connect?\n");
 541
 542
 543        rets = mei_cl_connect(cl, file);
 544
 545end:
 546        return rets;
 547}
 548
 549
 550/**
 551 * mei_ioctl - the IOCTL function
 552 *
 553 * @file: pointer to file structure
 554 * @cmd: ioctl command
 555 * @data: pointer to mei message structure
 556 *
 557 * returns 0 on success , <0 on error
 558 */
 559static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
 560{
 561        struct mei_device *dev;
 562        struct mei_cl *cl = file->private_data;
 563        struct mei_connect_client_data *connect_data = NULL;
 564        int rets;
 565
 566        if (cmd != IOCTL_MEI_CONNECT_CLIENT)
 567                return -EINVAL;
 568
 569        if (WARN_ON(!cl || !cl->dev))
 570                return -ENODEV;
 571
 572        dev = cl->dev;
 573
 574        dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
 575
 576        mutex_lock(&dev->device_lock);
 577        if (dev->dev_state != MEI_DEV_ENABLED) {
 578                rets = -ENODEV;
 579                goto out;
 580        }
 581
 582        dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
 583
 584        connect_data = kzalloc(sizeof(struct mei_connect_client_data),
 585                                                        GFP_KERNEL);
 586        if (!connect_data) {
 587                rets = -ENOMEM;
 588                goto out;
 589        }
 590        dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
 591        if (copy_from_user(connect_data, (char __user *)data,
 592                                sizeof(struct mei_connect_client_data))) {
 593                dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
 594                rets = -EFAULT;
 595                goto out;
 596        }
 597
 598        rets = mei_ioctl_connect_client(file, connect_data);
 599
 600        /* if all is ok, copying the data back to user. */
 601        if (rets)
 602                goto out;
 603
 604        dev_dbg(&dev->pdev->dev, "copy connect data to user\n");
 605        if (copy_to_user((char __user *)data, connect_data,
 606                                sizeof(struct mei_connect_client_data))) {
 607                dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
 608                rets = -EFAULT;
 609                goto out;
 610        }
 611
 612out:
 613        kfree(connect_data);
 614        mutex_unlock(&dev->device_lock);
 615        return rets;
 616}
 617
 618/**
 619 * mei_compat_ioctl - the compat IOCTL function
 620 *
 621 * @file: pointer to file structure
 622 * @cmd: ioctl command
 623 * @data: pointer to mei message structure
 624 *
 625 * returns 0 on success , <0 on error
 626 */
 627#ifdef CONFIG_COMPAT
 628static long mei_compat_ioctl(struct file *file,
 629                        unsigned int cmd, unsigned long data)
 630{
 631        return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data));
 632}
 633#endif
 634
 635
 636/**
 637 * mei_poll - the poll function
 638 *
 639 * @file: pointer to file structure
 640 * @wait: pointer to poll_table structure
 641 *
 642 * returns poll mask
 643 */
 644static unsigned int mei_poll(struct file *file, poll_table *wait)
 645{
 646        struct mei_cl *cl = file->private_data;
 647        struct mei_device *dev;
 648        unsigned int mask = 0;
 649
 650        if (WARN_ON(!cl || !cl->dev))
 651                return mask;
 652
 653        dev = cl->dev;
 654
 655        mutex_lock(&dev->device_lock);
 656
 657        if (dev->dev_state != MEI_DEV_ENABLED)
 658                goto out;
 659
 660
 661        if (cl == &dev->iamthif_cl) {
 662                mask = mei_amthif_poll(dev, file, wait);
 663                goto out;
 664        }
 665
 666        mutex_unlock(&dev->device_lock);
 667        poll_wait(file, &cl->tx_wait, wait);
 668        mutex_lock(&dev->device_lock);
 669        if (MEI_WRITE_COMPLETE == cl->writing_state)
 670                mask |= (POLLIN | POLLRDNORM);
 671
 672out:
 673        mutex_unlock(&dev->device_lock);
 674        return mask;
 675}
 676
 677/*
 678 * file operations structure will be used for mei char device.
 679 */
 680static const struct file_operations mei_fops = {
 681        .owner = THIS_MODULE,
 682        .read = mei_read,
 683        .unlocked_ioctl = mei_ioctl,
 684#ifdef CONFIG_COMPAT
 685        .compat_ioctl = mei_compat_ioctl,
 686#endif
 687        .open = mei_open,
 688        .release = mei_release,
 689        .write = mei_write,
 690        .poll = mei_poll,
 691        .llseek = no_llseek
 692};
 693
 694/*
 695 * Misc Device Struct
 696 */
 697static struct miscdevice  mei_misc_device = {
 698                .name = "mei",
 699                .fops = &mei_fops,
 700                .minor = MISC_DYNAMIC_MINOR,
 701};
 702
 703
 704int mei_register(struct mei_device *dev)
 705{
 706        int ret;
 707        mei_misc_device.parent = &dev->pdev->dev;
 708        ret = misc_register(&mei_misc_device);
 709        if (ret)
 710                return ret;
 711
 712        if (mei_dbgfs_register(dev, mei_misc_device.name))
 713                dev_err(&dev->pdev->dev, "cannot register debugfs\n");
 714
 715        return 0;
 716}
 717EXPORT_SYMBOL_GPL(mei_register);
 718
 719void mei_deregister(struct mei_device *dev)
 720{
 721        mei_dbgfs_deregister(dev);
 722        misc_deregister(&mei_misc_device);
 723        mei_misc_device.parent = NULL;
 724}
 725EXPORT_SYMBOL_GPL(mei_deregister);
 726
 727static int __init mei_init(void)
 728{
 729        return mei_cl_bus_init();
 730}
 731
 732static void __exit mei_exit(void)
 733{
 734        mei_cl_bus_exit();
 735}
 736
 737module_init(mei_init);
 738module_exit(mei_exit);
 739
 740MODULE_AUTHOR("Intel Corporation");
 741MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
 742MODULE_LICENSE("GPL v2");
 743
 744