main.c 18.5 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 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;
	}

T
Tomas Winkler 已提交
186
	if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
187 188 189 190 191 192 193 194
		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 已提交
195
				(!list_empty(&cl->rd_completed)) ||
196
				(!mei_cl_is_connected(cl)))) {
197

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

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

T
Tomas Winkler 已提交
210
	cb = mei_cl_read_cb(cl, file);
211
	if (!cb) {
212 213 214 215 216
		if (mei_cl_is_fixed_address(cl) && dev->allow_fixed_address) {
			cb = mei_cl_read_cb(cl, NULL);
			if (cb)
				goto copy_buffer;
		}
217 218 219
		rets = 0;
		goto out;
	}
220

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

229
	cl_dbg(dev, cl, "buf.size = %zd buf.idx = %zd offset = %lld\n",
230 231 232
	       cb->buf.size, cb->buf_idx, *offset);
	if (*offset >= cb->buf_idx) {
		rets = 0;
233 234 235
		goto free;
	}

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

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

	rets = length;
	*offset += length;
248 249
	/* not all data was read, keep the cb */
	if (*offset < cb->buf_idx)
250 251 252
		goto out;

free:
253
	mei_io_cb_free(cb);
254
	*offset = 0;
255

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		goto end;
	}

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

438
	rets = mei_cl_connect(cl, me_cl, file);
439 440

end:
441
	mei_me_cl_put(me_cl);
442 443 444
	return rets;
}

445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
/**
 * 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
 */
static int mei_ioctl_client_notify_request(struct file *file, u32 request)
{
	struct mei_cl *cl = file->private_data;

	return mei_cl_notify_request(cl, file, request);
}

/**
 * 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
 */
static int mei_ioctl_client_notify_get(struct file *file, u32 *notify_get)
{
	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;
}

484 485 486 487 488 489 490
/**
 * mei_ioctl - the IOCTL function
 *
 * @file: pointer to file structure
 * @cmd: ioctl command
 * @data: pointer to mei message structure
 *
491
 * Return: 0 on success , <0 on error
492 493 494 495 496
 */
static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
{
	struct mei_device *dev;
	struct mei_cl *cl = file->private_data;
497
	struct mei_connect_client_data connect_data;
498
	u32 notify_get, notify_req;
499 500 501 502 503 504 505 506
	int rets;


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

	dev = cl->dev;

507
	dev_dbg(dev->dev, "IOCTL cmd = 0x%x", cmd);
508 509

	mutex_lock(&dev->device_lock);
510
	if (dev->dev_state != MEI_DEV_ENABLED) {
511 512 513 514
		rets = -ENODEV;
		goto out;
	}

515 516
	switch (cmd) {
	case IOCTL_MEI_CONNECT_CLIENT:
517
		dev_dbg(dev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
518
		if (copy_from_user(&connect_data, (char __user *)data,
519
				sizeof(struct mei_connect_client_data))) {
520
			dev_dbg(dev->dev, "failed to copy data from userland\n");
521 522 523
			rets = -EFAULT;
			goto out;
		}
524

525
		rets = mei_ioctl_connect_client(file, &connect_data);
526 527
		if (rets)
			goto out;
528

529
		/* if all is ok, copying the data back to user. */
530
		if (copy_to_user((char __user *)data, &connect_data,
531
				sizeof(struct mei_connect_client_data))) {
532
			dev_dbg(dev->dev, "failed to copy data to userland\n");
533 534 535 536 537
			rets = -EFAULT;
			goto out;
		}

		break;
538

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
	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;

566
	default:
567
		dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
568
		rets = -ENOIOCTLCMD;
569 570 571 572 573 574 575 576 577 578 579 580 581 582
	}

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
 *
583
 * Return: 0 on success , <0 on error
584 585 586
 */
#ifdef CONFIG_COMPAT
static long mei_compat_ioctl(struct file *file,
587
			unsigned int cmd, unsigned long data)
588 589 590 591 592 593 594 595 596 597 598 599
{
	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
 *
600
 * Return: poll mask
601 602 603
 */
static unsigned int mei_poll(struct file *file, poll_table *wait)
{
T
Tomas Winkler 已提交
604
	unsigned long req_events = poll_requested_events(wait);
605 606 607
	struct mei_cl *cl = file->private_data;
	struct mei_device *dev;
	unsigned int mask = 0;
608
	bool notify_en;
609 610

	if (WARN_ON(!cl || !cl->dev))
611
		return POLLERR;
612 613 614 615 616

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

617
	notify_en = cl->notify_en && (req_events & POLLPRI);
618 619 620

	if (dev->dev_state != MEI_DEV_ENABLED ||
	    !mei_cl_is_connected(cl)) {
621
		mask = POLLERR;
622 623 624
		goto out;
	}

T
Tomas Winkler 已提交
625 626
	if (cl == &dev->iamthif_cl) {
		mask = mei_amthif_poll(dev, file, wait);
627 628 629
		goto out;
	}

630 631 632 633 634 635
	if (notify_en) {
		poll_wait(file, &cl->ev_wait, wait);
		if (cl->notify_ev)
			mask |= POLLPRI;
	}

T
Tomas Winkler 已提交
636 637 638 639 640 641 642 643
	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);
	}
644 645 646 647 648 649

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

650 651 652 653 654 655 656
/**
 * mei_fasync - asynchronous io support
 *
 * @fd: file descriptor
 * @file: pointer to file structure
 * @band: band bitmap
 *
657 658 659
 * Return: negative on error,
 *         0 if it did no changes,
 *         and positive a process was added or deleted
660 661 662 663 664 665 666
 */
static int mei_fasync(int fd, struct file *file, int band)
{

	struct mei_cl *cl = file->private_data;

	if (!mei_cl_is_connected(cl))
667
		return -ENODEV;
668 669 670 671

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

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 698 699 700 701 702 703 704 705 706 707 708 709
/**
 * 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);

710 711 712 713 714 715 716 717 718 719 720 721 722 723
/*
 * 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,
724
	.fasync = mei_fasync,
725 726 727
	.llseek = no_llseek
};

728 729 730 731 732 733 734 735 736 737 738
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
 *
739
 * Return: allocated minor, or -ENOSPC if no free minor left
740
 */
741 742 743 744 745 746 747 748 749
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)
750
		dev_err(dev->dev, "too many mei devices\n");
751

752 753 754
	mutex_unlock(&mei_minor_lock);
	return ret;
}
T
Tomas Winkler 已提交
755

756 757 758 759 760 761
/**
 * mei_minor_free - mark device minor number as free
 *
 * @dev:  device pointer
 */
static void mei_minor_free(struct mei_device *dev)
762
{
763 764 765 766 767 768 769 770 771 772 773 774
	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 已提交
775 776
		return ret;

777 778 779
	/* Fill in the data structures */
	devno = MKDEV(MAJOR(mei_devt), dev->minor);
	cdev_init(&dev->cdev, &mei_fops);
780
	dev->cdev.owner = parent->driver->owner;
781 782 783 784 785 786 787 788 789

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

790 791 792
	clsdev = device_create_with_groups(mei_class, parent, devno,
					   dev, mei_groups,
					   "mei%d", dev->minor);
793 794 795 796 797 798 799 800 801 802 803 804 805

	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 已提交
806 807

	return 0;
808 809 810 811 812 813 814 815

err_dev_dbgfs:
	device_destroy(mei_class, devno);
err_dev_create:
	cdev_del(&dev->cdev);
err_dev_add:
	mei_minor_free(dev);
	return ret;
816
}
817
EXPORT_SYMBOL_GPL(mei_register);
818

T
Tomas Winkler 已提交
819
void mei_deregister(struct mei_device *dev)
820
{
821 822 823 824 825
	int devno;

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

T
Tomas Winkler 已提交
826
	mei_dbgfs_deregister(dev);
827 828 829 830

	device_destroy(mei_class, devno);

	mei_minor_free(dev);
831
}
832
EXPORT_SYMBOL_GPL(mei_deregister);
833

834 835
static int __init mei_init(void)
{
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
	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;
865 866 867 868
}

static void __exit mei_exit(void)
{
869 870
	unregister_chrdev_region(mei_devt, MEI_MAX_DEVS);
	class_destroy(mei_class);
871 872 873 874 875 876
	mei_cl_bus_exit();
}

module_init(mei_init);
module_exit(mei_exit);

877 878
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
879
MODULE_LICENSE("GPL v2");
880