]> git.karo-electronics.de Git - linux-beck.git/commitdiff
mei: move from misc to char device
authorAlexander Usyskin <alexander.usyskin@intel.com>
Mon, 23 Jun 2014 12:10:35 +0000 (15:10 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Jul 2014 21:19:34 +0000 (14:19 -0700)
We need to support more then one mei interface
hence the simple misc devices is not longer an option

In order not break the user space a device with pci function 0
need to be linked to /dev/mei

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
drivers/misc/mei/pci-me.c
drivers/misc/mei/pci-txe.c

index 66f0a1a0645143b6b37d143b8fbfc43ce7a7d9a7..401a3d526cd0a0a316374974a45ffb21861396f5 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/compat.h>
 #include <linux/jiffies.h>
 #include <linux/interrupt.h>
-#include <linux/miscdevice.h>
 
 #include <linux/mei.h>
 
  */
 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();
 }
 
index 5c7e990e2f22a7d5bda8e1d34c88150019754f2a..2afa3d69107d79c6df3d565d4aea400051651014 100644 (file)
@@ -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"
index 1b46c64a649fd773c2fc54477cc73e6914d2a10d..887ace14efa637d4807e8bdf584ada057a187132 100644 (file)
@@ -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;
 
index 2343c6236df98e095df52a777f97d33729a748d9..d7480fe8994d1c027dc26b68370726581e25cd46 100644 (file)
@@ -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;