main.c 16.6 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 35
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/aio.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>

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

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

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

54
	int err;
55

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

	mutex_lock(&dev->device_lock);
61

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

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

	file->private_data = cl;
76

77 78
	mutex_unlock(&dev->device_lock);

79
	return nonseekable_open(inode, file);
80

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

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

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

	dev = cl->dev;

	mutex_lock(&dev->device_lock);
106 107 108 109 110 111
	if (cl == &dev->iamthif_cl) {
		rets = mei_amthif_release(dev, file);
		goto out;
	}
	if (cl->state == MEI_FILE_CONNECTED) {
		cl->state = MEI_FILE_DISCONNECTING;
112
		cl_dbg(dev, cl, "disconnecting\n");
T
Tomas Winkler 已提交
113
		rets = mei_cl_disconnect(cl);
114
	}
T
Tomas Winkler 已提交
115
	mei_cl_flush_queues(cl, file);
116
	cl_dbg(dev, cl, "removing\n");
117

T
Tomas Winkler 已提交
118
	mei_cl_unlink(cl);
119 120

	file->private_data = NULL;
121

122 123
	kfree(cl);
out:
124 125 126 127 128 129 130 131 132 133 134 135 136
	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
 *
137
 * Return: >=0 data length on success , <0 on error
138 139
 */
static ssize_t mei_read(struct file *file, char __user *ubuf,
140
			size_t length, loff_t *offset)
141 142 143
{
	struct mei_cl *cl = file->private_data;
	struct mei_device *dev;
T
Tomas Winkler 已提交
144
	struct mei_cl_cb *cb = NULL;
145 146 147 148 149 150 151 152 153
	int rets;
	int err;


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

	dev = cl->dev;

154

155
	mutex_lock(&dev->device_lock);
156
	if (dev->dev_state != MEI_DEV_ENABLED) {
157 158 159 160
		rets = -ENODEV;
		goto out;
	}

161 162 163 164 165
	if (length == 0) {
		rets = 0;
		goto out;
	}

166
	if (cl == &dev->iamthif_cl) {
167
		rets = mei_amthif_read(dev, file, ubuf, length, offset);
168 169 170
		goto out;
	}

T
Tomas Winkler 已提交
171
	cb = mei_cl_read_cb(cl, file);
172
	if (cb) {
173 174 175 176 177 178 179 180 181 182 183 184
		/* 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) {
185 186 187
		*offset = 0;
	}

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

T
Tomas Winkler 已提交
196
	if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
197 198 199 200 201 202 203 204
		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 已提交
205
				(!list_empty(&cl->rd_completed)) ||
206 207
				mei_cl_is_transitioning(cl))) {

208 209 210 211 212 213
			if (signal_pending(current))
				return -EINTR;
			return -ERESTARTSYS;
		}

		mutex_lock(&dev->device_lock);
214
		if (mei_cl_is_transitioning(cl)) {
215 216 217 218 219
			rets = -EBUSY;
			goto out;
		}
	}

T
Tomas Winkler 已提交
220
	cb = mei_cl_read_cb(cl, file);
221 222 223 224
	if (!cb) {
		rets = 0;
		goto out;
	}
225

226
copy_buffer:
227 228 229 230 231 232 233
	/* 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;
	}

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

241 242 243
	/* length is being truncated to PAGE_SIZE,
	 * however buf_idx may point beyond that */
	length = min_t(size_t, length, cb->buf_idx - *offset);
244

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

	rets = length;
	*offset += length;
253
	if ((unsigned long)*offset < cb->buf_idx)
254 255 256
		goto out;

free:
257
	mei_io_cb_free(cb);
258

259
out:
260
	dev_dbg(dev->dev, "end mei read rets= %d\n", rets);
261 262 263 264 265 266 267 268 269 270 271
	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
 *
272
 * Return: >=0 data length on success , <0 on error
273 274
 */
static ssize_t mei_write(struct file *file, const char __user *ubuf,
275
			 size_t length, loff_t *offset)
276 277
{
	struct mei_cl *cl = file->private_data;
278
	struct mei_me_client *me_cl = NULL;
279 280 281 282 283 284 285 286 287 288 289 290
	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);

291
	if (dev->dev_state != MEI_DEV_ENABLED) {
292
		rets = -ENODEV;
T
Tomas Winkler 已提交
293
		goto out;
294 295
	}

296
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
297
	if (!me_cl) {
298
		rets = -ENOTTY;
T
Tomas Winkler 已提交
299
		goto out;
300
	}
301 302 303 304 305 306

	if (length == 0) {
		rets = 0;
		goto out;
	}

307
	if (length > me_cl->props.max_msg_length) {
308
		rets = -EFBIG;
T
Tomas Winkler 已提交
309
		goto out;
310 311 312
	}

	if (cl->state != MEI_FILE_CONNECTED) {
313
		dev_err(dev->dev, "host client = %d,  is not connected to ME client = %d",
314
			cl->host_client_id, cl->me_client_id);
T
Tomas Winkler 已提交
315 316
		rets = -ENODEV;
		goto out;
317
	}
318
	if (cl == &dev->iamthif_cl) {
319
		write_cb = mei_amthif_find_read_list_entry(dev, file);
320 321 322

		if (write_cb) {
			timeout = write_cb->read_time +
323
				mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
324

T
Tomas Winkler 已提交
325
			if (time_after(jiffies, timeout)) {
326
				*offset = 0;
327
				mei_io_cb_free(write_cb);
328
				write_cb = NULL;
329 330 331 332
			}
		}
	}

T
Tomas Winkler 已提交
333
	*offset = 0;
334
	write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
335
	if (!write_cb) {
336
		rets = -ENOMEM;
T
Tomas Winkler 已提交
337
		goto out;
338 339
	}

340
	rets = copy_from_user(write_cb->buf.data, ubuf, length);
341
	if (rets) {
342
		dev_dbg(dev->dev, "failed to copy data from userland\n");
343
		rets = -EFAULT;
T
Tomas Winkler 已提交
344
		goto out;
345
	}
346 347

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

350
		if (rets) {
351
			dev_err(dev->dev,
352
				"amthif write failed with status = %d\n", rets);
T
Tomas Winkler 已提交
353
			goto out;
354
		}
355
		mei_me_cl_put(me_cl);
356
		mutex_unlock(&dev->device_lock);
357
		return length;
358 359
	}

T
Tomas Winkler 已提交
360
	rets = mei_cl_write(cl, write_cb, false);
361
out:
362
	mei_me_cl_put(me_cl);
363
	mutex_unlock(&dev->device_lock);
T
Tomas Winkler 已提交
364 365
	if (rets < 0)
		mei_io_cb_free(write_cb);
366 367 368
	return rets;
}

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

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

391 392
	if (dev->dev_state != MEI_DEV_ENABLED)
		return -ENODEV;
393 394

	if (cl->state != MEI_FILE_INITIALIZING &&
395 396
	    cl->state != MEI_FILE_DISCONNECTED)
		return  -EBUSY;
397 398

	/* find ME client we're trying to connect to */
399 400
	me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
	if (!me_cl || me_cl->props.fixed_address) {
401
		dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
402
				&data->in_client_uuid);
403
		return  -ENOTTY;
404 405
	}

406
	cl->me_client_id = me_cl->client_id;
407
	cl->cl_uuid = me_cl->props.protocol_name;
408

409
	dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
410
			cl->me_client_id);
411
	dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n",
412
			me_cl->props.protocol_version);
413
	dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
414
			me_cl->props.max_msg_length);
415

416
	/* if we're connecting to amthif client then we will use the
417 418
	 * existing connection
	 */
419
	if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
420
		dev_dbg(dev->dev, "FW Client is amthi\n");
421 422 423 424 425 426 427 428
		if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
			rets = -ENODEV;
			goto end;
		}
		mei_cl_unlink(cl);

		kfree(cl);
		cl = NULL;
T
Tomas Winkler 已提交
429
		dev->iamthif_open_count++;
430 431 432
		file->private_data = &dev->iamthif_cl;

		client = &data->out_client_properties;
433 434
		client->max_msg_length = me_cl->props.max_msg_length;
		client->protocol_version = me_cl->props.protocol_version;
435 436 437 438 439 440 441
		rets = dev->iamthif_cl.status;

		goto end;
	}

	/* prepare the output buffer */
	client = &data->out_client_properties;
442 443
	client->max_msg_length = me_cl->props.max_msg_length;
	client->protocol_version = me_cl->props.protocol_version;
444
	dev_dbg(dev->dev, "Can connect?\n");
445 446 447 448

	rets = mei_cl_connect(cl, file);

end:
449
	mei_me_cl_put(me_cl);
450 451 452
	return rets;
}

453 454 455 456 457 458 459
/**
 * mei_ioctl - the IOCTL function
 *
 * @file: pointer to file structure
 * @cmd: ioctl command
 * @data: pointer to mei message structure
 *
460
 * Return: 0 on success , <0 on error
461 462 463 464 465
 */
static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
{
	struct mei_device *dev;
	struct mei_cl *cl = file->private_data;
466
	struct mei_connect_client_data connect_data;
467 468 469 470 471 472 473 474
	int rets;


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

	dev = cl->dev;

475
	dev_dbg(dev->dev, "IOCTL cmd = 0x%x", cmd);
476 477

	mutex_lock(&dev->device_lock);
478
	if (dev->dev_state != MEI_DEV_ENABLED) {
479 480 481 482
		rets = -ENODEV;
		goto out;
	}

483 484
	switch (cmd) {
	case IOCTL_MEI_CONNECT_CLIENT:
485
		dev_dbg(dev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
486
		if (copy_from_user(&connect_data, (char __user *)data,
487
				sizeof(struct mei_connect_client_data))) {
488
			dev_dbg(dev->dev, "failed to copy data from userland\n");
489 490 491
			rets = -EFAULT;
			goto out;
		}
492

493
		rets = mei_ioctl_connect_client(file, &connect_data);
494 495
		if (rets)
			goto out;
496

497
		/* if all is ok, copying the data back to user. */
498
		if (copy_to_user((char __user *)data, &connect_data,
499
				sizeof(struct mei_connect_client_data))) {
500
			dev_dbg(dev->dev, "failed to copy data to userland\n");
501 502 503 504 505
			rets = -EFAULT;
			goto out;
		}

		break;
506

507
	default:
508
		dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
509
		rets = -ENOIOCTLCMD;
510 511 512 513 514 515 516 517 518 519 520 521 522 523
	}

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
 *
524
 * Return: 0 on success , <0 on error
525 526 527
 */
#ifdef CONFIG_COMPAT
static long mei_compat_ioctl(struct file *file,
528
			unsigned int cmd, unsigned long data)
529 530 531 532 533 534 535 536 537 538 539 540
{
	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
 *
541
 * Return: poll mask
542 543 544 545 546 547 548 549
 */
static unsigned int mei_poll(struct file *file, poll_table *wait)
{
	struct mei_cl *cl = file->private_data;
	struct mei_device *dev;
	unsigned int mask = 0;

	if (WARN_ON(!cl || !cl->dev))
550
		return POLLERR;
551 552 553 554 555

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

556 557
	if (!mei_cl_is_connected(cl)) {
		mask = POLLERR;
558 559 560 561
		goto out;
	}

	mutex_unlock(&dev->device_lock);
562 563 564 565 566


	if (cl == &dev->iamthif_cl)
		return mei_amthif_poll(dev, file, wait);

567
	poll_wait(file, &cl->tx_wait, wait);
568

569
	mutex_lock(&dev->device_lock);
570 571 572 573 574 575

	if (!mei_cl_is_connected(cl)) {
		mask = POLLERR;
		goto out;
	}

576
	mask |= (POLLIN | POLLRDNORM);
577 578 579 580 581 582

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

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 611 612 613 614 615 616 617 618 619 620
/**
 * 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);

621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
/*
 * 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
};

638 639 640 641 642 643 644 645 646 647 648
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
 *
649
 * Return: allocated minor, or -ENOSPC if no free minor left
650
 */
651 652 653 654 655 656 657 658 659
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)
660
		dev_err(dev->dev, "too many mei devices\n");
661

662 663 664
	mutex_unlock(&mei_minor_lock);
	return ret;
}
T
Tomas Winkler 已提交
665

666 667 668 669 670 671
/**
 * mei_minor_free - mark device minor number as free
 *
 * @dev:  device pointer
 */
static void mei_minor_free(struct mei_device *dev)
672
{
673 674 675 676 677 678 679 680 681 682 683 684
	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 已提交
685 686
		return ret;

687 688 689 690 691 692 693 694 695 696 697 698 699
	/* 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;
	}

700 701 702
	clsdev = device_create_with_groups(mei_class, parent, devno,
					   dev, mei_groups,
					   "mei%d", dev->minor);
703 704 705 706 707 708 709 710 711 712 713 714 715

	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 已提交
716 717

	return 0;
718 719 720 721 722 723 724 725

err_dev_dbgfs:
	device_destroy(mei_class, devno);
err_dev_create:
	cdev_del(&dev->cdev);
err_dev_add:
	mei_minor_free(dev);
	return ret;
726
}
727
EXPORT_SYMBOL_GPL(mei_register);
728

T
Tomas Winkler 已提交
729
void mei_deregister(struct mei_device *dev)
730
{
731 732 733 734 735
	int devno;

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

T
Tomas Winkler 已提交
736
	mei_dbgfs_deregister(dev);
737 738 739 740

	device_destroy(mei_class, devno);

	mei_minor_free(dev);
741
}
742
EXPORT_SYMBOL_GPL(mei_deregister);
743

744 745
static int __init mei_init(void)
{
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
	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;
775 776 777 778
}

static void __exit mei_exit(void)
{
779 780
	unregister_chrdev_region(mei_devt, MEI_MAX_DEVS);
	class_destroy(mei_class);
781 782 783 784 785 786
	mei_cl_bus_exit();
}

module_init(mei_init);
module_exit(mei_exit);

787 788
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
789
MODULE_LICENSE("GPL v2");
790