From: Bartosz Golaszewski <[email protected]>

Add a new debugfs attribute 'delete_device' to which the chip label can
be written to dynamically remove the associated dummy device.

Signed-off-by: Bartosz Golaszewski <[email protected]>
---
 drivers/gpio/gpio-mockup.c | 70 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
index 1353239dc315..9d2de78a45c2 100644
--- a/drivers/gpio/gpio-mockup.c
+++ b/drivers/gpio/gpio-mockup.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/string_helpers.h>
 #include <linux/uaccess.h>
 
@@ -668,14 +669,81 @@ static int __init 
gpio_mockup_register_chips_from_params(void)
        return 0;
 }
 
-static int __init gpio_mockup_init(void)
+static ssize_t gpio_mockup_debugfs_delete_device_write(struct file *file,
+                                               const char __user *usr_buf,
+                                               size_t size, loff_t *ppos)
 {
+       struct gpio_mockup_device *mockup_dev;
+       char label[GPIO_MOCKUP_LABEL_SIZE];
+       struct list_head *curr;
+       struct device *dev;
+       const char *prop;
        int ret;
 
+       if (*ppos != 0)
+               return -EINVAL;
+
+       ret = getline_from_user(label, sizeof(label), usr_buf, size);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&gpio_mockup_devices_lock);
+
+       list_for_each(curr, &gpio_mockup_devices) {
+               mockup_dev = list_entry(curr, struct gpio_mockup_device, list);
+               dev = &mockup_dev->pdev->dev;
+
+               ret = device_property_read_string(dev, "chip-label", &prop);
+               if (ret) {
+                       mutex_unlock(&gpio_mockup_devices_lock);
+                       return ret;
+               }
+
+               if (sysfs_streq(label, prop)) {
+                       gpio_mockup_unregister_one_device(mockup_dev);
+                       mutex_unlock(&gpio_mockup_devices_lock);
+                       return size;
+               }
+       }
+
+       mutex_unlock(&gpio_mockup_devices_lock);
+       return -ENODEV;
+}
+
+static const struct file_operations gpio_mockup_debugfs_delete_device_ops = {
+       .owner = THIS_MODULE,
+       .open = gpio_mockup_debugfs_open,
+       .write = gpio_mockup_debugfs_delete_device_write,
+       .llseek = no_llseek,
+       .release = single_release,
+};
+
+static int __init gpio_mockup_debugfs_init(void)
+{
+       struct dentry *entry;
+
        gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup", NULL);
        if (IS_ERR(gpio_mockup_dbg_dir))
                return PTR_ERR(gpio_mockup_dbg_dir);
 
+       entry = debugfs_create_file("delete_device", 0200, gpio_mockup_dbg_dir,
+                               NULL, &gpio_mockup_debugfs_delete_device_ops);
+       if (IS_ERR(entry)) {
+               debugfs_remove_recursive(gpio_mockup_dbg_dir);
+               return PTR_ERR(entry);
+       }
+
+       return 0;
+}
+
+static int __init gpio_mockup_init(void)
+{
+       int ret;
+
+       ret = gpio_mockup_debugfs_init();
+       if (ret)
+               return ret;
+
        ret = platform_driver_register(&gpio_mockup_driver);
        if (ret) {
                pr_err("error registering platform driver\n");
-- 
2.26.1

Reply via email to