summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpio/gpiolib.c21
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)