diff options
| author | 2014-11-19 21:32:12 +1100 | |
|---|---|---|
| committer | 2014-11-19 21:32:12 +1100 | |
| commit | b10778a00d40b3d9fdaaf5891e802794781ff71c (patch) | |
| tree | 6ba4cbac86eecedc3f30650e7f764ecf00c83898 /drivers/misc/mei/main.c | |
| parent | integrity: do zero padding of the key id (diff) | |
| parent | Linux 3.17 (diff) | |
| download | wireguard-linux-b10778a00d40b3d9fdaaf5891e802794781ff71c.tar.xz wireguard-linux-b10778a00d40b3d9fdaaf5891e802794781ff71c.zip | |
Merge commit 'v3.17' into next
Diffstat (limited to '')
| -rw-r--r-- | drivers/misc/mei/main.c | 148 | 
1 files changed, 121 insertions, 27 deletions
| diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 66f0a1a06451..401a3d526cd0 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -32,7 +32,6 @@  #include <linux/compat.h>  #include <linux/jiffies.h>  #include <linux/interrupt.h> -#include <linux/miscdevice.h>  #include <linux/mei.h> @@ -49,19 +48,12 @@   */  static int mei_open(struct inode *inode, struct file *file)  { -	struct miscdevice *misc = file->private_data; -	struct pci_dev *pdev; -	struct mei_cl *cl;  	struct mei_device *dev; +	struct mei_cl *cl;  	int err; -	if (!misc->parent) -		return -ENODEV; - -	pdev = container_of(misc->parent, struct pci_dev, dev); - -	dev = pci_get_drvdata(pdev); +	dev = container_of(inode->i_cdev, struct mei_device, cdev);  	if (!dev)  		return -ENODEV; @@ -667,46 +659,148 @@ static const struct file_operations mei_fops = {  	.llseek = no_llseek  }; -/* - * Misc Device Struct +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 + * + * returns allocated minor, or -ENOSPC if no free minor left   */ -static struct miscdevice  mei_misc_device = { -		.name = "mei", -		.fops = &mei_fops, -		.minor = MISC_DYNAMIC_MINOR, -}; +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) +		dev_err(&dev->pdev->dev, "too many mei devices\n"); +	mutex_unlock(&mei_minor_lock); +	return ret; +} -int mei_register(struct mei_device *dev) +/** + * mei_minor_free - mark device minor number as free + * + * @dev:  device pointer + */ +static void mei_minor_free(struct mei_device *dev)  { -	int ret; -	mei_misc_device.parent = &dev->pdev->dev; -	ret = misc_register(&mei_misc_device); -	if (ret) +	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)  		return ret; -	if (mei_dbgfs_register(dev, mei_misc_device.name)) -		dev_err(&dev->pdev->dev, "cannot register debugfs\n"); +	/* 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; +	} + +	clsdev = device_create(mei_class, parent, devno, +			 NULL, "mei%d", dev->minor); + +	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; +	}  	return 0; + +err_dev_dbgfs: +	device_destroy(mei_class, devno); +err_dev_create: +	cdev_del(&dev->cdev); +err_dev_add: +	mei_minor_free(dev); +	return ret;  }  EXPORT_SYMBOL_GPL(mei_register);  void mei_deregister(struct mei_device *dev)  { +	int devno; + +	devno = dev->cdev.dev; +	cdev_del(&dev->cdev); +  	mei_dbgfs_deregister(dev); -	misc_deregister(&mei_misc_device); -	mei_misc_device.parent = NULL; + +	device_destroy(mei_class, devno); + +	mei_minor_free(dev);  }  EXPORT_SYMBOL_GPL(mei_deregister);  static int __init mei_init(void)  { -	return mei_cl_bus_init(); +	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;  }  static void __exit mei_exit(void)  { +	unregister_chrdev_region(mei_devt, MEI_MAX_DEVS); +	class_destroy(mei_class);  	mei_cl_bus_exit();  } | 
