diff options
-rw-r--r-- | drivers/misc/mei/main.c | 148 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 9 | ||||
-rw-r--r-- | drivers/misc/mei/pci-me.c | 3 | ||||
-rw-r--r-- | drivers/misc/mei/pci-txe.c | 2 |
4 files changed, 131 insertions, 31 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(); } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 5c7e990e2f22..2afa3d69107d 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -400,6 +400,10 @@ struct mei_cfg { /** * struct mei_device - MEI private device struct + * @pdev - pointer to pci device struct + * @cdev - character device + * @minor - minor number allocated for device + * * @reset_count - limits the number of consecutive resets * @hbm_state - state of host bus message protocol * @pg_event - power gating event @@ -412,6 +416,9 @@ struct mei_cfg { */ struct mei_device { struct pci_dev *pdev; /* pointer to pci device struct */ + struct cdev cdev; + int minor; + /* * lists of queues */ @@ -741,7 +748,7 @@ static inline int mei_dbgfs_register(struct mei_device *dev, const char *name) static inline void mei_dbgfs_deregister(struct mei_device *dev) {} #endif /* CONFIG_DEBUG_FS */ -int mei_register(struct mei_device *dev); +int mei_register(struct mei_device *dev, struct device *parent); void mei_deregister(struct mei_device *dev); #define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d internal=%1d comp=%1d" diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 1b46c64a649f..887ace14efa6 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -31,7 +31,6 @@ #include <linux/compat.h> #include <linux/jiffies.h> #include <linux/interrupt.h> -#include <linux/miscdevice.h> #include <linux/pm_runtime.h> @@ -207,7 +206,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); - err = mei_register(dev); + err = mei_register(dev, &pdev->dev); if (err) goto release_irq; diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index 2343c6236df9..d7480fe8994d 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c @@ -149,7 +149,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); - err = mei_register(dev); + err = mei_register(dev, &pdev->dev); if (err) goto release_irq; |