|
@@ -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();
|
|
|
}
|
|
|
|