main.c 18.2 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
		cl_dbg(dev, cl, "mei start read failure status = %d\n", err);
187 188 189 190
		rets = err;
		goto out;
	}

T
Tomas Winkler 已提交
191
	if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
192 193 194 195 196 197 198 199
		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 已提交
200
				(!list_empty(&cl->rd_completed)) ||
201
				(!mei_cl_is_connected(cl)))) {
202

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

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

T
Tomas Winkler 已提交
215
	cb = mei_cl_read_cb(cl, file);
216
	if (!cb) {
217 218 219 220 221
		if (mei_cl_is_fixed_address(cl) && dev->allow_fixed_address) {
			cb = mei_cl_read_cb(cl, NULL);
			if (cb)
				goto copy_buffer;
		}
222 223 224
		rets = 0;
		goto out;
	}
225

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

234
	cl_dbg(dev, cl, "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
	cl_dbg(dev, cl, "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 278 279 280 281 282 283 284 285 286 287 288 289
{
	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);

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

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

301 302
	if (!mei_me_cl_is_active(cl->me_cl)) {
		rets = -ENOTTY;
303 304 305
		goto out;
	}

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

311 312
	if (length == 0) {
		rets = 0;
T
Tomas Winkler 已提交
313
		goto out;
314
	}
315

316
	if (cl == &dev->iamthif_cl) {
317
		write_cb = mei_amthif_find_read_list_entry(dev, file);
318 319 320

		if (write_cb) {
			timeout = write_cb->read_time +
321
				mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
322

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

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

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

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

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

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

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

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

387 388
	if (dev->dev_state != MEI_DEV_ENABLED)
		return -ENODEV;
389 390

	if (cl->state != MEI_FILE_INITIALIZING &&
391 392
	    cl->state != MEI_FILE_DISCONNECTED)
		return  -EBUSY;
393 394

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

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

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

		kfree(cl);
		cl = NULL;
T
Tomas Winkler 已提交
424
		dev->iamthif_open_count++;
425 426 427
		file->private_data = &dev->iamthif_cl;

		client = &data->out_client_properties;
428 429
		client->max_msg_length = me_cl->props.max_msg_length;
		client->protocol_version = me_cl->props.protocol_version;
430 431 432 433 434 435 436
		rets = dev->iamthif_cl.status;

		goto end;
	}

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

441
	rets = mei_cl_connect(cl, me_cl, file);
442 443

end:
444
	mei_me_cl_put(me_cl);
445 446 447
	return rets;
}

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

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


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

	dev = cl->dev;

510
	dev_dbg(dev->dev, "IOCTL cmd = 0x%x", cmd);
511 512

	mutex_lock(&dev->device_lock);
513
	if (dev->dev_state != MEI_DEV_ENABLED) {
514 515 516 517
		rets = -ENODEV;
		goto out;
	}

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

528
		rets = mei_ioctl_connect_client(file, &connect_data);
529 530
		if (rets)
			goto out;
531

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

		break;
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 566 567 568
	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;

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

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

	if (WARN_ON(!cl || !cl->dev))
614
		return POLLERR;
615 616 617 618 619

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

620
	notify_en = cl->notify_en && (req_events & POLLPRI);
621 622 623

	if (dev->dev_state != MEI_DEV_ENABLED ||
	    !mei_cl_is_connected(cl)) {
624
		mask = POLLERR;
625 626 627
		goto out;
	}

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

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

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

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

653 654 655 656 657 658 659 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
/**
 * 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);

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
/*
 * 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
};

708 709 710 711 712 713 714 715 716 717 718
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
 *
719
 * Return: allocated minor, or -ENOSPC if no free minor left
720
 */
721 722 723 724 725 726 727 728 729
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)
730
		dev_err(dev->dev, "too many mei devices\n");
731

732 733 734
	mutex_unlock(&mei_minor_lock);
	return ret;
}
T
Tomas Winkler 已提交
735

736 737 738 739 740 741
/**
 * mei_minor_free - mark device minor number as free
 *
 * @dev:  device pointer
 */
static void mei_minor_free(struct mei_device *dev)
742
{
743 744 745 746 747 748 749 750 751 752 753 754
	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 已提交
755 756
		return ret;

757 758 759
	/* Fill in the data structures */
	devno = MKDEV(MAJOR(mei_devt), dev->minor);
	cdev_init(&dev->cdev, &mei_fops);
760
	dev->cdev.owner = parent->driver->owner;
761 762 763 764 765 766 767 768 769

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

770 771 772
	clsdev = device_create_with_groups(mei_class, parent, devno,
					   dev, mei_groups,
					   "mei%d", dev->minor);
773 774 775 776 777 778 779 780 781 782 783 784 785

	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 已提交
786 787

	return 0;
788 789 790 791 792 793 794 795

err_dev_dbgfs:
	device_destroy(mei_class, devno);
err_dev_create:
	cdev_del(&dev->cdev);
err_dev_add:
	mei_minor_free(dev);
	return ret;
796
}
797
EXPORT_SYMBOL_GPL(mei_register);
798

T
Tomas Winkler 已提交
799
void mei_deregister(struct mei_device *dev)
800
{
801 802 803 804 805
	int devno;

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

T
Tomas Winkler 已提交
806
	mei_dbgfs_deregister(dev);
807 808 809 810

	device_destroy(mei_class, devno);

	mei_minor_free(dev);
811
}
812
EXPORT_SYMBOL_GPL(mei_deregister);
813

814 815
static int __init mei_init(void)
{
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
	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;
845 846 847 848
}

static void __exit mei_exit(void)
{
849 850
	unregister_chrdev_region(mei_devt, MEI_MAX_DEVS);
	class_destroy(mei_class);
851 852 853 854 855 856
	mei_cl_bus_exit();
}

module_init(mei_init);
module_exit(mei_exit);

857 858
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
859
MODULE_LICENSE("GPL v2");
860