main.c 18.1 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
	cl = mei_cl_alloc_linked(dev);
69 70
	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 163 164 165 166
	if (ubuf == NULL) {
		rets = -EMSGSIZE;
		goto out;
	}

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

T
Tomas Winkler 已提交
172
	cb = mei_cl_read_cb(cl, file);
173 174 175 176
	if (cb)
		goto copy_buffer;

	if (*offset > 0)
177 178
		*offset = 0;

179
	err = mei_cl_read_start(cl, length, file);
180
	if (err && err != -EBUSY) {
181
		cl_dbg(dev, cl, "mei start read failure status = %d\n", err);
182 183 184 185
		rets = err;
		goto out;
	}

186 187
	/* synchronized under device mutex */
	if (!waitqueue_active(&cl->rx_wait)) {
188 189 190 191 192 193 194 195
		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 已提交
196
				(!list_empty(&cl->rd_completed)) ||
197
				(!mei_cl_is_connected(cl)))) {
198

199 200 201 202 203 204
			if (signal_pending(current))
				return -EINTR;
			return -ERESTARTSYS;
		}

		mutex_lock(&dev->device_lock);
205
		if (!mei_cl_is_connected(cl)) {
206
			rets = -ENODEV;
207 208 209 210
			goto out;
		}
	}

T
Tomas Winkler 已提交
211
	cb = mei_cl_read_cb(cl, file);
212 213 214 215
	if (!cb) {
		rets = 0;
		goto out;
	}
216

217
copy_buffer:
218 219 220
	/* now copy the data to user space */
	if (cb->status) {
		rets = cb->status;
221
		cl_dbg(dev, cl, "read operation failed %d\n", rets);
222 223 224
		goto free;
	}

225
	cl_dbg(dev, cl, "buf.size = %zu buf.idx = %zu offset = %lld\n",
226 227 228
	       cb->buf.size, cb->buf_idx, *offset);
	if (*offset >= cb->buf_idx) {
		rets = 0;
229 230 231
		goto free;
	}

232 233 234
	/* length is being truncated to PAGE_SIZE,
	 * however buf_idx may point beyond that */
	length = min_t(size_t, length, cb->buf_idx - *offset);
235

236
	if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
237
		dev_dbg(dev->dev, "failed to copy data to userland\n");
238 239 240 241 242 243
		rets = -EFAULT;
		goto free;
	}

	rets = length;
	*offset += length;
244 245
	/* not all data was read, keep the cb */
	if (*offset < cb->buf_idx)
246 247 248
		goto out;

free:
249
	mei_io_cb_free(cb);
250
	*offset = 0;
251

252
out:
253
	cl_dbg(dev, cl, "end mei read rets = %d\n", rets);
254 255 256 257 258 259 260 261 262 263 264
	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
 *
265
 * Return: >=0 data length on success , <0 on error
266 267
 */
static ssize_t mei_write(struct file *file, const char __user *ubuf,
268
			 size_t length, loff_t *offset)
269 270
{
	struct mei_cl *cl = file->private_data;
271
	struct mei_cl_cb *cb;
272 273 274 275 276 277 278 279 280 281
	struct mei_device *dev;
	int rets;

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

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

282
	if (dev->dev_state != MEI_DEV_ENABLED) {
283
		rets = -ENODEV;
T
Tomas Winkler 已提交
284
		goto out;
285 286
	}

287 288 289
	if (!mei_cl_is_connected(cl)) {
		cl_err(dev, cl, "is not connected");
		rets = -ENODEV;
T
Tomas Winkler 已提交
290
		goto out;
291
	}
292

293 294
	if (!mei_me_cl_is_active(cl->me_cl)) {
		rets = -ENOTTY;
295 296 297
		goto out;
	}

298
	if (length > mei_cl_mtu(cl)) {
299
		rets = -EFBIG;
T
Tomas Winkler 已提交
300
		goto out;
301 302
	}

303 304
	if (length == 0) {
		rets = 0;
T
Tomas Winkler 已提交
305
		goto out;
306
	}
307

T
Tomas Winkler 已提交
308
	*offset = 0;
309 310
	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
	if (!cb) {
311
		rets = -ENOMEM;
T
Tomas Winkler 已提交
312
		goto out;
313 314
	}

315
	rets = copy_from_user(cb->buf.data, ubuf, length);
316
	if (rets) {
317
		dev_dbg(dev->dev, "failed to copy data from userland\n");
318
		rets = -EFAULT;
319
		mei_io_cb_free(cb);
T
Tomas Winkler 已提交
320
		goto out;
321
	}
322 323

	if (cl == &dev->iamthif_cl) {
324 325 326 327
		rets = mei_amthif_write(cl, cb);
		if (!rets)
			rets = length;
		goto out;
328 329
	}

330
	rets = mei_cl_write(cl, cb, false);
331
out:
332 333 334 335
	mutex_unlock(&dev->device_lock);
	return rets;
}

336 337 338 339
/**
 * mei_ioctl_connect_client - the connect to fw client IOCTL function
 *
 * @file: private data of the file object
340
 * @data: IOCTL connect data, input and output parameters
341 342 343
 *
 * Locking: called under "dev->device_lock" lock
 *
344
 * Return: 0 on success, <0 on failure.
345 346 347 348 349 350
 */
static int mei_ioctl_connect_client(struct file *file,
			struct mei_connect_client_data *data)
{
	struct mei_device *dev;
	struct mei_client *client;
351
	struct mei_me_client *me_cl;
352 353 354 355 356 357
	struct mei_cl *cl;
	int rets;

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

358 359
	if (dev->dev_state != MEI_DEV_ENABLED)
		return -ENODEV;
360 361

	if (cl->state != MEI_FILE_INITIALIZING &&
362 363
	    cl->state != MEI_FILE_DISCONNECTED)
		return  -EBUSY;
364 365

	/* find ME client we're trying to connect to */
366
	me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
367
	if (!me_cl) {
368
		dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
369
			&data->in_client_uuid);
370 371 372 373 374 375 376 377 378 379 380 381 382
		rets = -ENOTTY;
		goto end;
	}

	if (me_cl->props.fixed_address) {
		bool forbidden = dev->override_fixed_address ?
			 !dev->allow_fixed_address : !dev->hbm_f_fa_supported;
		if (forbidden) {
			dev_dbg(dev->dev, "Connection forbidden to FW Client UUID = %pUl\n",
				&data->in_client_uuid);
			rets = -ENOTTY;
			goto end;
		}
383 384
	}

385
	dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
386
			me_cl->client_id);
387
	dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n",
388
			me_cl->props.protocol_version);
389
	dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
390
			me_cl->props.max_msg_length);
391

392
	/* if we're connecting to amthif client then we will use the
393 394
	 * existing connection
	 */
395
	if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
396
		dev_dbg(dev->dev, "FW Client is amthi\n");
397
		if (!mei_cl_is_connected(&dev->iamthif_cl)) {
398 399 400 401 402 403 404
			rets = -ENODEV;
			goto end;
		}
		mei_cl_unlink(cl);

		kfree(cl);
		cl = NULL;
T
Tomas Winkler 已提交
405
		dev->iamthif_open_count++;
406 407 408
		file->private_data = &dev->iamthif_cl;

		client = &data->out_client_properties;
409 410
		client->max_msg_length = me_cl->props.max_msg_length;
		client->protocol_version = me_cl->props.protocol_version;
411 412 413 414 415 416 417
		rets = dev->iamthif_cl.status;

		goto end;
	}

	/* prepare the output buffer */
	client = &data->out_client_properties;
418 419
	client->max_msg_length = me_cl->props.max_msg_length;
	client->protocol_version = me_cl->props.protocol_version;
420
	dev_dbg(dev->dev, "Can connect?\n");
421

422
	rets = mei_cl_connect(cl, me_cl, file);
423 424

end:
425
	mei_me_cl_put(me_cl);
426 427 428
	return rets;
}

429 430 431 432 433 434 435 436 437
/**
 * mei_ioctl_client_notify_request -
 *     propagate event notification request to client
 *
 * @file: pointer to file structure
 * @request: 0 - disable, 1 - enable
 *
 * Return: 0 on success , <0 on error
 */
438
static int mei_ioctl_client_notify_request(const struct file *file, u32 request)
439 440 441
{
	struct mei_cl *cl = file->private_data;

442 443 444 445 446
	if (request != MEI_HBM_NOTIFICATION_START &&
	    request != MEI_HBM_NOTIFICATION_STOP)
		return -EINVAL;

	return mei_cl_notify_request(cl, file, (u8)request);
447 448 449 450 451 452 453 454 455 456
}

/**
 * mei_ioctl_client_notify_get -  wait for notification request
 *
 * @file: pointer to file structure
 * @notify_get: 0 - disable, 1 - enable
 *
 * Return: 0 on success , <0 on error
 */
457
static int mei_ioctl_client_notify_get(const struct file *file, u32 *notify_get)
458 459 460 461 462 463 464 465 466 467 468 469 470 471
{
	struct mei_cl *cl = file->private_data;
	bool notify_ev;
	bool block = (file->f_flags & O_NONBLOCK) == 0;
	int rets;

	rets = mei_cl_notify_get(cl, block, &notify_ev);
	if (rets)
		return rets;

	*notify_get = notify_ev ? 1 : 0;
	return 0;
}

472 473 474 475 476 477 478
/**
 * mei_ioctl - the IOCTL function
 *
 * @file: pointer to file structure
 * @cmd: ioctl command
 * @data: pointer to mei message structure
 *
479
 * Return: 0 on success , <0 on error
480 481 482 483 484
 */
static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
{
	struct mei_device *dev;
	struct mei_cl *cl = file->private_data;
485
	struct mei_connect_client_data connect_data;
486
	u32 notify_get, notify_req;
487 488 489 490 491 492 493 494
	int rets;


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

	dev = cl->dev;

495
	dev_dbg(dev->dev, "IOCTL cmd = 0x%x", cmd);
496 497

	mutex_lock(&dev->device_lock);
498
	if (dev->dev_state != MEI_DEV_ENABLED) {
499 500 501 502
		rets = -ENODEV;
		goto out;
	}

503 504
	switch (cmd) {
	case IOCTL_MEI_CONNECT_CLIENT:
505
		dev_dbg(dev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
506
		if (copy_from_user(&connect_data, (char __user *)data,
507
				sizeof(struct mei_connect_client_data))) {
508
			dev_dbg(dev->dev, "failed to copy data from userland\n");
509 510 511
			rets = -EFAULT;
			goto out;
		}
512

513
		rets = mei_ioctl_connect_client(file, &connect_data);
514 515
		if (rets)
			goto out;
516

517
		/* if all is ok, copying the data back to user. */
518
		if (copy_to_user((char __user *)data, &connect_data,
519
				sizeof(struct mei_connect_client_data))) {
520
			dev_dbg(dev->dev, "failed to copy data to userland\n");
521 522 523 524 525
			rets = -EFAULT;
			goto out;
		}

		break;
526

527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
	case IOCTL_MEI_NOTIFY_SET:
		dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_SET.\n");
		if (copy_from_user(&notify_req,
				   (char __user *)data, sizeof(notify_req))) {
			dev_dbg(dev->dev, "failed to copy data from userland\n");
			rets = -EFAULT;
			goto out;
		}
		rets = mei_ioctl_client_notify_request(file, notify_req);
		break;

	case IOCTL_MEI_NOTIFY_GET:
		dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_GET.\n");
		rets = mei_ioctl_client_notify_get(file, &notify_get);
		if (rets)
			goto out;

		dev_dbg(dev->dev, "copy connect data to user\n");
		if (copy_to_user((char __user *)data,
				&notify_get, sizeof(notify_get))) {
			dev_dbg(dev->dev, "failed to copy data to userland\n");
			rets = -EFAULT;
			goto out;

		}
		break;

554
	default:
555
		dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
556
		rets = -ENOIOCTLCMD;
557 558 559 560 561 562 563 564 565 566 567 568 569 570
	}

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
 *
571
 * Return: 0 on success , <0 on error
572 573 574
 */
#ifdef CONFIG_COMPAT
static long mei_compat_ioctl(struct file *file,
575
			unsigned int cmd, unsigned long data)
576 577 578 579 580 581 582 583 584 585 586 587
{
	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
 *
588
 * Return: poll mask
589 590 591
 */
static unsigned int mei_poll(struct file *file, poll_table *wait)
{
T
Tomas Winkler 已提交
592
	unsigned long req_events = poll_requested_events(wait);
593 594 595
	struct mei_cl *cl = file->private_data;
	struct mei_device *dev;
	unsigned int mask = 0;
596
	bool notify_en;
597 598

	if (WARN_ON(!cl || !cl->dev))
599
		return POLLERR;
600 601 602 603 604

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

605
	notify_en = cl->notify_en && (req_events & POLLPRI);
606 607 608

	if (dev->dev_state != MEI_DEV_ENABLED ||
	    !mei_cl_is_connected(cl)) {
609
		mask = POLLERR;
610 611 612
		goto out;
	}

613 614 615 616 617
	if (notify_en) {
		poll_wait(file, &cl->ev_wait, wait);
		if (cl->notify_ev)
			mask |= POLLPRI;
	}
618 619 620 621 622

	if (cl == &dev->iamthif_cl) {
		mask |= mei_amthif_poll(file, wait);
		goto out;
	}
623

T
Tomas Winkler 已提交
624 625 626 627 628 629 630 631
	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);
	}
632 633 634 635 636 637

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

638 639 640 641 642 643 644
/**
 * mei_fasync - asynchronous io support
 *
 * @fd: file descriptor
 * @file: pointer to file structure
 * @band: band bitmap
 *
645 646 647
 * Return: negative on error,
 *         0 if it did no changes,
 *         and positive a process was added or deleted
648 649 650 651 652 653 654
 */
static int mei_fasync(int fd, struct file *file, int band)
{

	struct mei_cl *cl = file->private_data;

	if (!mei_cl_is_connected(cl))
655
		return -ENODEV;
656 657 658 659

	return fasync_helper(fd, file, band, &cl->ev_async);
}

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
/**
 * 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);

698 699 700 701 702 703 704 705 706 707 708 709 710 711
/*
 * 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,
712
	.fasync = mei_fasync,
713 714 715
	.llseek = no_llseek
};

716 717 718 719 720 721 722 723 724 725 726
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
 *
727
 * Return: allocated minor, or -ENOSPC if no free minor left
728
 */
729 730 731 732 733 734 735 736 737
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)
738
		dev_err(dev->dev, "too many mei devices\n");
739

740 741 742
	mutex_unlock(&mei_minor_lock);
	return ret;
}
T
Tomas Winkler 已提交
743

744 745 746 747 748 749
/**
 * mei_minor_free - mark device minor number as free
 *
 * @dev:  device pointer
 */
static void mei_minor_free(struct mei_device *dev)
750
{
751 752 753 754 755 756 757 758 759 760 761 762
	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 已提交
763 764
		return ret;

765 766 767
	/* Fill in the data structures */
	devno = MKDEV(MAJOR(mei_devt), dev->minor);
	cdev_init(&dev->cdev, &mei_fops);
768
	dev->cdev.owner = parent->driver->owner;
769 770 771 772 773 774 775 776 777

	/* 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;
	}

778 779 780
	clsdev = device_create_with_groups(mei_class, parent, devno,
					   dev, mei_groups,
					   "mei%d", dev->minor);
781 782 783 784 785 786 787 788 789 790 791 792 793

	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 已提交
794 795

	return 0;
796 797 798 799 800 801 802 803

err_dev_dbgfs:
	device_destroy(mei_class, devno);
err_dev_create:
	cdev_del(&dev->cdev);
err_dev_add:
	mei_minor_free(dev);
	return ret;
804
}
805
EXPORT_SYMBOL_GPL(mei_register);
806

T
Tomas Winkler 已提交
807
void mei_deregister(struct mei_device *dev)
808
{
809 810 811 812 813
	int devno;

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

T
Tomas Winkler 已提交
814
	mei_dbgfs_deregister(dev);
815 816 817 818

	device_destroy(mei_class, devno);

	mei_minor_free(dev);
819
}
820
EXPORT_SYMBOL_GPL(mei_deregister);
821

822 823
static int __init mei_init(void)
{
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
	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;
853 854 855 856
}

static void __exit mei_exit(void)
{
857 858
	unregister_chrdev_region(mei_devt, MEI_MAX_DEVS);
	class_destroy(mei_class);
859 860 861 862 863 864
	mei_cl_bus_exit();
}

module_init(mei_init);
module_exit(mei_exit);

865 866
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
867
MODULE_LICENSE("GPL v2");
868