diff options
-rw-r--r-- | drivers/gpio/gpiolib.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5cd019bd7f0e..e901fefd0ede 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -726,6 +726,7 @@ static struct class gpio_class = { */ int gpio_export(unsigned gpio, bool direction_may_change) { + struct gpio_chip *chip; unsigned long flags; struct gpio_desc *desc; int status; @@ -743,10 +744,18 @@ int gpio_export(unsigned gpio, bool direction_may_change) return -EINVAL; } + desc = &gpio_desc[gpio]; + chip = desc->chip; + mutex_lock(&sysfs_lock); + /* check if chip is being removed */ + if (!chip || !chip->exported) { + status = -ENODEV; + goto fail_unlock; + } + spin_lock_irqsave(&gpio_lock, flags); - desc = &gpio_desc[gpio]; if (!test_bit(FLAG_REQUESTED, &desc->flags) || test_bit(FLAG_EXPORT, &desc->flags)) { spin_unlock_irqrestore(&gpio_lock, flags); @@ -973,12 +982,15 @@ static void gpiochip_unexport(struct gpio_chip *chip) { int status; struct device *dev; + struct gpio_desc *desc; + unsigned int i; mutex_lock(&sysfs_lock); dev = class_find_device(&gpio_class, NULL, chip, match_export); if (dev) { put_device(dev); device_unregister(dev); + /* prevent further gpiod exports */ chip->exported = 0; status = 0; } else @@ -988,6 +1000,13 @@ static void gpiochip_unexport(struct gpio_chip *chip) if (status) pr_debug("%s: chip %s status %d\n", __func__, chip->label, status); + + /* unregister gpio class devices owned by sysfs */ + for (i = 0; i < chip->ngpio; i++) { + desc = &gpio_desc[chip->base + i]; + if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) + gpio_free(chip->base + i); + } } static int __init gpiolib_sysfs_init(void) |