main.c 16.3 KB
Newer Older
1 2 3
/*
 *
 * Intel Management Engine Interface (Intel MEI) Linux driver
4
 * Copyright (c) 2003-2012, Intel Corporation.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/device.h>
20
#include <linux/slab.h>
21 22 23 24 25 26 27 28 29 30 31 32 33 34
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/uuid.h>
#include <linux/compat.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>

35
#include <linux/mei.h>
36 37

#include "mei_dev.h"
T
Tomas Winkler 已提交
38
#include "client.h"
39 40 41 42 43 44

/**
 * mei_open - the open function
 *
 * @inode: pointer to inode structure
 * @file: pointer to file structure
45
 *
46
 * Return: 0 on success, <0 on error
47 48 49 50
 */
static int mei_open(struct inode *inode, struct file *file)
{
	struct mei_device *dev;
51
	struct mei_cl *cl;
52

53
	int err;
54

55
	dev = container_of(inode->i_cdev, struct mei_device, cdev);
56
	if (!dev)
57
		return -ENODEV;
58 59

	mutex_lock(&dev->device_lock);
60

61
	if (dev->dev_state != MEI_DEV_ENABLED) {
62
		dev_dbg(dev->dev, "dev_state != MEI_ENABLED  dev_state = %s\n",
63
		    mei_dev_state_str(dev->dev_state));
64
		err = -ENODEV;
65
		goto err_unlock;
66
	}
67

68 69 70
	cl = mei_cl_alloc_linked(dev, MEI_HOST_CLIENT_ID_ANY);
	if (IS_ERR(cl)) {
		err = PTR_ERR(cl);
71
		goto err_unlock;
72
	}
73 74

	file->private_data = cl;
75

76 77
	mutex_unlock(&dev->device_lock);

78
	return nonseekable_open(inode, file);
79

80
err_unlock:
81 82 83 84 85 86 87 88 89 90
	mutex_unlock(&dev->device_lock);
	return err;
}

/**
 * mei_release - the release function
 *
 * @inode: pointer to inode structure
 * @file: pointer to file structure
 *
91
 * Return: 0 on success, <0 on error
92 93 94 95 96
 */
static int mei_release(struct inode *inode, struct file *file)
{
	struct mei_cl *cl = file->private_data;
	struct mei_device *dev;
97
	int rets;
98 99 100 101 102 103 104

	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

	mutex_lock(&dev->device_lock);
105 106 107 108
	if (cl == &dev->iamthif_cl) {
		rets = mei_amthif_release(dev, file);
		goto out;
	}
109 110
	rets = mei_cl_disconnect(cl);

T
Tomas Winkler 已提交
111
	mei_cl_flush_queues(cl, file);
112
	cl_dbg(dev, cl, "removing\n");
113

T
Tomas Winkler 已提交
114
	mei_cl_unlink(cl);
115 116

	file->private_data = NULL;
117

118 119
	kfree(cl);
out:
120 121 122 123 124 125 126 127 128 129 130 131 132
	mutex_unlock(&dev->device_lock);
	return rets;
}


/**
 * mei_read - the read function.
 *
 * @file: pointer to file structure
 * @ubuf: pointer to user buffer
 * @length: buffer length
 * @offset: data offset in buffer
 *
133
 * Return: >=0 data length on success , <0 on error
134 135
 */
static ssize_t mei_read(struct file *file, char __user *ubuf,
136
			size_t length, loff_t *offset)
137 138 139
{
	struct mei_cl *cl = file->private_data;
	struct mei_device *dev;
T
Tomas Winkler 已提交
140
	struct mei_cl_cb *cb = NULL;
141 142 143 144 145 146 147 148 149
	int rets;
	int err;


	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

150

151
	mutex_lock(&dev->device_lock);
152
	if (dev->dev_state != MEI_DEV_ENABLED) {
153 154 155 156
		rets = -ENODEV;
		goto out;
	}

157 158 159 160 161
	if (length == 0) {
		rets = 0;
		goto out;
	}

162
	if (cl == &dev->iamthif_cl) {
163
		rets = mei_amthif_read(dev, file, ubuf, length, offset);
164 165 166
		goto out;
	}

T
Tomas Winkler 已提交
167
	cb = mei_cl_read_cb(cl, file);
168
	if (cb) {
169 170 171 172 173 174 175 176 177 178 179 180
		/* read what left */
		if (cb->buf_idx > *offset)
			goto copy_buffer;
		/* offset is beyond buf_idx we have no more data return 0 */
		if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
			rets = 0;
			goto free;
		}
		/* Offset needs to be cleaned for contiguous reads*/
		if (cb->buf_idx == 0 && *offset > 0)
			*offset = 0;
	} else if (*offset > 0) {
181 182 183
		*offset = 0;
	}

184
	err = mei_cl_read_start(cl, length, file);
185
	if (err && err != -EBUSY) {
186
		dev_dbg(dev->dev,
187 188 189 190 191
			"mei start read failure with status = %d\n", err);
		rets = err;
		goto out;
	}

T
Tomas Winkler 已提交
192
	if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
193 194 195 196 197 198 199 200
		if (file->f_flags & O_NONBLOCK) {
			rets = -EAGAIN;
			goto out;
		}

		mutex_unlock(&dev->device_lock);

		if (wait_event_interruptible(cl->rx_wait,
T
Tomas Winkler 已提交
201
				(!list_empty(&cl->rd_completed)) ||
202
				(!mei_cl_is_connected(cl)))) {
203

204 205 206 207 208 209
			if (signal_pending(current))
				return -EINTR;
			return -ERESTARTSYS;
		}

		mutex_lock(&dev->device_lock);
210
		if (!mei_cl_is_connected(cl)) {
211 212 213 214 215
			rets = -EBUSY;
			goto out;
		}
	}

T
Tomas Winkler 已提交
216
	cb = mei_cl_read_cb(cl, file);
217 218 219 220
	if (!cb) {
		rets = 0;
		goto out;
	}
221

222
copy_buffer:
223 224 225 226 227 228 229
	/* now copy the data to user space */
	if (cb->status) {
		rets = cb->status;
		dev_dbg(dev->dev, "read operation failed %d\n", rets);
		goto free;
	}

230
	dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n",
231
	    cb->buf.size, cb->buf_idx);
232
	if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
233 234 235 236
		rets = -EMSGSIZE;
		goto free;
	}

237 238 239
	/* length is being truncated to PAGE_SIZE,
	 * however buf_idx may point beyond that */
	length = min_t(size_t, length, cb->buf_idx - *offset);
240

241
	if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
242
		dev_dbg(dev->dev, "failed to copy data to userland\n");
243 244 245 246 247 248
		rets = -EFAULT;
		goto free;
	}

	rets = length;
	*offset += length;
249
	if ((unsigned long)*offset < cb->buf_idx)
250 251 252
		goto out;

free:
253
	mei_io_cb_free(cb);
254

255
out:
256
	dev_dbg(dev->dev, "end mei read rets= %d\n", rets);
257 258 259 260 261 262 263 264 265 266 267
	mutex_unlock(&dev->device_lock);
	return rets;
}
/**
 * mei_write - the write function.
 *
 * @file: pointer to file structure
 * @ubuf: pointer to user buffer
 * @length: buffer length
 * @offset: data offset in buffer
 *
268
 * Return: >=0 data length on success , <0 on error
269 270
 */
static ssize_t mei_write(struct file *file, const char __user *ubuf,
271
			 size_t length, loff_t *offset)
272 273 274 275 276 277 278 279 280 281 282 283 284 285
{
	struct mei_cl *cl = file->private_data;
	struct mei_cl_cb *write_cb = NULL;
	struct mei_device *dev;
	unsigned long timeout = 0;
	int rets;

	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

286
	if (dev->dev_state != MEI_DEV_ENABLED) {
287
		rets = -ENODEV;
T
Tomas Winkler 已提交
288
		goto out;
289 290
	}

291 292 293
	if (!mei_cl_is_connected(cl)) {
		cl_err(dev, cl, "is not connected");
		rets = -ENODEV;
T
Tomas Winkler 已提交
294
		goto out;
295
	}
296

297 298
	if (!mei_me_cl_is_active(cl->me_cl)) {
		rets = -ENOTTY;
299 300 301
		goto out;
	}

302
	if (length > mei_cl_mtu(cl)) {
303
		rets = -EFBIG;
T
Tomas Winkler 已提交
304
		goto out;
305 306
	}

307 308
	if (length == 0) {
		rets = 0;
T
Tomas Winkler 已提交
309
		goto out;
310
	}
311

312
	if (cl == &dev->iamthif_cl) {
313
		write_cb = mei_amthif_find_read_list_entry(dev, file);
314 315 316

		if (write_cb) {
			timeout = write_cb->read_time +
317
				mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
318

T
Tomas Winkler 已提交
319
			if (time_after(jiffies, timeout)) {
320
				*offset = 0;
321
				mei_io_cb_free(write_cb);
322
				write_cb = NULL;
323 324 325 326
			}
		}
	}

T
Tomas Winkler 已提交
327
	*offset = 0;
328
	write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
329
	if (!write_cb) {
330
		rets = -ENOMEM;
T
Tomas Winkler 已提交
331
		goto out;
332 333
	}

334
	rets = copy_from_user(write_cb->buf.data, ubuf, length);
335
	if (rets) {
336
		dev_dbg(dev->dev, "failed to copy data from userland\n");
337
		rets = -EFAULT;
T
Tomas Winkler 已提交
338
		goto out;
339
	}
340 341

	if (cl == &dev->iamthif_cl) {
342
		rets = mei_amthif_write(cl, write_cb);
343

344
		if (rets) {
345
			dev_err(dev->dev,
346
				"amthif write failed with status = %d\n", rets);
T
Tomas Winkler 已提交
347
			goto out;
348 349
		}
		mutex_unlock(&dev->device_lock);
350
		return length;
351 352
	}

T
Tomas Winkler 已提交
353
	rets = mei_cl_write(cl, write_cb, false);
354
out:
355
	mutex_unlock(&dev->device_lock);
T
Tomas Winkler 已提交
356 357
	if (rets < 0)
		mei_io_cb_free(write_cb);
358 359 360
	return rets;
}

361 362 363 364
/**
 * mei_ioctl_connect_client - the connect to fw client IOCTL function
 *
 * @file: private data of the file object
365
 * @data: IOCTL connect data, input and output parameters
366 367 368
 *
 * Locking: called under "dev->device_lock" lock
 *
369
 * Return: 0 on success, <0 on failure.
370 371 372 373 374 375
 */
static int mei_ioctl_connect_client(struct file *file,
			struct mei_connect_client_data *data)
{
	struct mei_device *dev;
	struct mei_client *client;
376
	struct mei_me_client *me_cl;
377 378 379 380 381 382
	struct mei_cl *cl;
	int rets;

	cl = file->private_data;
	dev = cl->dev;

383 384
	if (dev->dev_state != MEI_DEV_ENABLED)
		return -ENODEV;
385 386

	if (cl->state != MEI_FILE_INITIALIZING &&
387 388
	    cl->state != MEI_FILE_DISCONNECTED)
		return  -EBUSY;
389 390

	/* find ME client we're trying to connect to */
391 392
	me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
	if (!me_cl || me_cl->props.fixed_address) {
393
		dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
394 395
			&data->in_client_uuid);
		mei_me_cl_put(me_cl);
396
		return  -ENOTTY;
397 398
	}

399
	dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
400
			me_cl->client_id);
401
	dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n",
402
			me_cl->props.protocol_version);
403
	dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
404
			me_cl->props.max_msg_length);
405

406
	/* if we're connecting to amthif client then we will use the
407 408
	 * existing connection
	 */
409
	if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
410
		dev_dbg(dev->dev, "FW Client is amthi\n");
411
		if (!mei_cl_is_connected(&dev->iamthif_cl)) {
412 413 414 415 416 417 418
			rets = -ENODEV;
			goto end;
		}
		mei_cl_unlink(cl);

		kfree(cl);
		cl = NULL;
T
Tomas Winkler 已提交
419
		dev->iamthif_open_count++;
420 421 422
		file->private_data = &dev->iamthif_cl;

		client = &data->out_client_properties;
423 424
		client->max_msg_length = me_cl->props.max_msg_length;
		client->protocol_version = me_cl->props.protocol_version;
425 426 427 428 429 430 431
		rets = dev->iamthif_cl.status;

		goto end;
	}

	/* prepare the output buffer */
	client = &data->out_client_properties;
432 433
	client->max_msg_length = me_cl->props.max_msg_length;
	client->protocol_version = me_cl->props.protocol_version;
434
	dev_dbg(dev->dev, "Can connect?\n");
435

436
	rets = mei_cl_connect(cl, me_cl, file);
437 438

end:
439
	mei_me_cl_put(me_cl);
440 441 442
	return rets;
}

443 444 445 446 447 448 449
/**
 * mei_ioctl - the IOCTL function
 *
 * @file: pointer to file structure
 * @cmd: ioctl command
 * @data: pointer to mei message structure
 *
450
 * Return: 0 on success , <0 on error
451 452 453 454 455
 */
static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
{
	struct mei_device *dev;
	struct mei_cl *cl = file->private_data;
456
	struct mei_connect_client_data connect_data;
457 458 459 460 461 462 463 464
	int rets;


	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

465
	dev_dbg(dev->dev, "IOCTL cmd = 0x%x", cmd);
466 467

	mutex_lock(&dev->device_lock);
468
	if (dev->dev_state != MEI_DEV_ENABLED) {
469 470 471 472
		rets = -ENODEV;
		goto out;
	}

473 474
	switch (cmd) {
	case IOCTL_MEI_CONNECT_CLIENT:
475
		dev_dbg(dev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
476
		if (copy_from_user(&connect_data, (char __user *)data,
477
				sizeof(struct mei_connect_client_data))) {
478
			dev_dbg(dev->dev, "failed to copy data from userland\n");
479 480 481
			rets = -EFAULT;
			goto out;
		}
482

483
		rets = mei_ioctl_connect_client(file, &connect_data);
484 485
		if (rets)
			goto out;
486

487
		/* if all is ok, copying the data back to user. */
488
		if (copy_to_user((char __user *)data, &connect_data,
489
				sizeof(struct mei_connect_client_data))) {
490
			dev_dbg(dev->dev, "failed to copy data to userland\n");
491 492 493 494 495
			rets = -EFAULT;
			goto out;
		}

		break;
496

497
	default:
498
		dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
499
		rets = -ENOIOCTLCMD;
500 501 502 503 504 505 506 507 508 509 510 511 512 513
	}

out:
	mutex_unlock(&dev->device_lock);
	return rets;
}

/**
 * mei_compat_ioctl - the compat IOCTL function
 *
 * @file: pointer to file structure
 * @cmd: ioctl command
 * @data: pointer to mei message structure
 *
514
 * Return: 0 on success , <0 on error
515 516 517
 */
#ifdef CONFIG_COMPAT
static long mei_compat_ioctl(struct file *file,
518
			unsigned int cmd, unsigned long data)
519 520 521 522 523 524 525 526 527 528 529 530
{
	return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data));
}
#endif


/**
 * mei_poll - the poll function
 *
 * @file: pointer to file structure
 * @wait: pointer to poll_table structure
 *
531
 * Return: poll mask
532 533 534
 */
static unsigned int mei_poll(struct file *file, poll_table *wait)
{
T
Tomas Winkler 已提交
535
	unsigned long req_events = poll_requested_events(wait);
536 537 538 539 540
	struct mei_cl *cl = file->private_data;
	struct mei_device *dev;
	unsigned int mask = 0;

	if (WARN_ON(!cl || !cl->dev))
541
		return POLLERR;
542 543 544 545 546

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

547 548 549

	if (dev->dev_state != MEI_DEV_ENABLED ||
	    !mei_cl_is_connected(cl)) {
550
		mask = POLLERR;
551 552 553
		goto out;
	}

T
Tomas Winkler 已提交
554 555
	if (cl == &dev->iamthif_cl) {
		mask = mei_amthif_poll(dev, file, wait);
556 557 558
		goto out;
	}

T
Tomas Winkler 已提交
559 560 561 562 563 564 565 566
	if (req_events & (POLLIN | POLLRDNORM)) {
		poll_wait(file, &cl->rx_wait, wait);

		if (!list_empty(&cl->rd_completed))
			mask |= POLLIN | POLLRDNORM;
		else
			mei_cl_read_start(cl, 0, file);
	}
567 568 569 570 571 572

out:
	mutex_unlock(&dev->device_lock);
	return mask;
}

573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
/**
 * fw_status_show - mei device attribute show method
 *
 * @device: device pointer
 * @attr: attribute pointer
 * @buf:  char out buffer
 *
 * Return: number of the bytes printed into buf or error
 */
static ssize_t fw_status_show(struct device *device,
		struct device_attribute *attr, char *buf)
{
	struct mei_device *dev = dev_get_drvdata(device);
	struct mei_fw_status fw_status;
	int err, i;
	ssize_t cnt = 0;

	mutex_lock(&dev->device_lock);
	err = mei_fw_status(dev, &fw_status);
	mutex_unlock(&dev->device_lock);
	if (err) {
		dev_err(device, "read fw_status error = %d\n", err);
		return err;
	}

	for (i = 0; i < fw_status.count; i++)
		cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, "%08X\n",
				fw_status.status[i]);
	return cnt;
}
static DEVICE_ATTR_RO(fw_status);

static struct attribute *mei_attrs[] = {
	&dev_attr_fw_status.attr,
	NULL
};
ATTRIBUTE_GROUPS(mei);

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
/*
 * file operations structure will be used for mei char device.
 */
static const struct file_operations mei_fops = {
	.owner = THIS_MODULE,
	.read = mei_read,
	.unlocked_ioctl = mei_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = mei_compat_ioctl,
#endif
	.open = mei_open,
	.release = mei_release,
	.write = mei_write,
	.poll = mei_poll,
	.llseek = no_llseek
};

628 629 630 631 632 633 634 635 636 637 638
static struct class *mei_class;
static dev_t mei_devt;
#define MEI_MAX_DEVS  MINORMASK
static DEFINE_MUTEX(mei_minor_lock);
static DEFINE_IDR(mei_idr);

/**
 * mei_minor_get - obtain next free device minor number
 *
 * @dev:  device pointer
 *
639
 * Return: allocated minor, or -ENOSPC if no free minor left
640
 */
641 642 643 644 645 646 647 648 649
static int mei_minor_get(struct mei_device *dev)
{
	int ret;

	mutex_lock(&mei_minor_lock);
	ret = idr_alloc(&mei_idr, dev, 0, MEI_MAX_DEVS, GFP_KERNEL);
	if (ret >= 0)
		dev->minor = ret;
	else if (ret == -ENOSPC)
650
		dev_err(dev->dev, "too many mei devices\n");
651

652 653 654
	mutex_unlock(&mei_minor_lock);
	return ret;
}
T
Tomas Winkler 已提交
655

656 657 658 659 660 661
/**
 * mei_minor_free - mark device minor number as free
 *
 * @dev:  device pointer
 */
static void mei_minor_free(struct mei_device *dev)
662
{
663 664 665 666 667 668 669 670 671 672 673 674
	mutex_lock(&mei_minor_lock);
	idr_remove(&mei_idr, dev->minor);
	mutex_unlock(&mei_minor_lock);
}

int mei_register(struct mei_device *dev, struct device *parent)
{
	struct device *clsdev; /* class device */
	int ret, devno;

	ret = mei_minor_get(dev);
	if (ret < 0)
T
Tomas Winkler 已提交
675 676
		return ret;

677 678 679 680 681 682 683 684 685 686 687 688 689
	/* Fill in the data structures */
	devno = MKDEV(MAJOR(mei_devt), dev->minor);
	cdev_init(&dev->cdev, &mei_fops);
	dev->cdev.owner = mei_fops.owner;

	/* Add the device */
	ret = cdev_add(&dev->cdev, devno, 1);
	if (ret) {
		dev_err(parent, "unable to add device %d:%d\n",
			MAJOR(mei_devt), dev->minor);
		goto err_dev_add;
	}

690 691 692
	clsdev = device_create_with_groups(mei_class, parent, devno,
					   dev, mei_groups,
					   "mei%d", dev->minor);
693 694 695 696 697 698 699 700 701 702 703 704 705

	if (IS_ERR(clsdev)) {
		dev_err(parent, "unable to create device %d:%d\n",
			MAJOR(mei_devt), dev->minor);
		ret = PTR_ERR(clsdev);
		goto err_dev_create;
	}

	ret = mei_dbgfs_register(dev, dev_name(clsdev));
	if (ret) {
		dev_err(clsdev, "cannot register debugfs ret = %d\n", ret);
		goto err_dev_dbgfs;
	}
T
Tomas Winkler 已提交
706 707

	return 0;
708 709 710 711 712 713 714 715

err_dev_dbgfs:
	device_destroy(mei_class, devno);
err_dev_create:
	cdev_del(&dev->cdev);
err_dev_add:
	mei_minor_free(dev);
	return ret;
716
}
717
EXPORT_SYMBOL_GPL(mei_register);
718

T
Tomas Winkler 已提交
719
void mei_deregister(struct mei_device *dev)
720
{
721 722 723 724 725
	int devno;

	devno = dev->cdev.dev;
	cdev_del(&dev->cdev);

T
Tomas Winkler 已提交
726
	mei_dbgfs_deregister(dev);
727 728 729 730

	device_destroy(mei_class, devno);

	mei_minor_free(dev);
731
}
732
EXPORT_SYMBOL_GPL(mei_deregister);
733

734 735
static int __init mei_init(void)
{
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
	int ret;

	mei_class = class_create(THIS_MODULE, "mei");
	if (IS_ERR(mei_class)) {
		pr_err("couldn't create class\n");
		ret = PTR_ERR(mei_class);
		goto err;
	}

	ret = alloc_chrdev_region(&mei_devt, 0, MEI_MAX_DEVS, "mei");
	if (ret < 0) {
		pr_err("unable to allocate char dev region\n");
		goto err_class;
	}

	ret = mei_cl_bus_init();
	if (ret < 0) {
		pr_err("unable to initialize bus\n");
		goto err_chrdev;
	}

	return 0;

err_chrdev:
	unregister_chrdev_region(mei_devt, MEI_MAX_DEVS);
err_class:
	class_destroy(mei_class);
err:
	return ret;
765 766 767 768
}

static void __exit mei_exit(void)
{
769 770
	unregister_chrdev_region(mei_devt, MEI_MAX_DEVS);
	class_destroy(mei_class);
771 772 773 774 775 776
	mei_cl_bus_exit();
}

module_init(mei_init);
module_exit(mei_exit);

777 778
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
779
MODULE_LICENSE("GPL v2");
780