summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
authorAlex Shi <alex.shi@linaro.org>2015-05-21 10:02:28 +0800
committerAlex Shi <alex.shi@linaro.org>2015-05-21 10:02:28 +0800
commitf5b00d07465c7c955810ebc250108df1d14d1168 (patch)
treefb1349edfda7ca9c692bf4e2030bf77e3de737cb /drivers/gpio/gpiolib.c
parent54db03197e2d0aca252bc377938777b30d3e7f10 (diff)
parentbaf41996d83a6ecd270be42ca1870592827fb30d (diff)
Merge branch 'linux-linaro-lsk-v3.10' into linux-linaro-lsk-v3.10-android
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 931bdf3d0205..9002122c52ae 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -752,6 +752,7 @@ static struct class gpio_class = {
*/
static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{
+ struct gpio_chip *chip;
unsigned long flags;
int status;
const char *ioname = NULL;
@@ -769,8 +770,16 @@ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
return -EINVAL;
}
+ 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);
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags)) {
@@ -1040,6 +1049,8 @@ 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);
@@ -1047,6 +1058,7 @@ static void gpiochip_unexport(struct gpio_chip *chip)
sysfs_remove_group(&dev->kobj, &gpiochip_attr_group);
put_device(dev);
device_unregister(dev);
+ /* prevent further gpiod exports */
chip->exported = 0;
status = 0;
} else
@@ -1056,6 +1068,13 @@ static void gpiochip_unexport(struct gpio_chip *chip)
if (status)
pr_debug("%s: chip %s status %d\n", __func__,
chip->label, status);
+
+ /* unregister gpiod class devices owned by sysfs */
+ for (i = 0; i < chip->ngpio; i++) {
+ desc = &chip->desc[i];
+ if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
+ gpiod_free(desc);
+ }
}
static int __init gpiolib_sysfs_init(void)
@@ -1267,6 +1286,8 @@ int gpiochip_remove(struct gpio_chip *chip)
int status = 0;
unsigned id;
+ gpiochip_unexport(chip);
+
spin_lock_irqsave(&gpio_lock, flags);
gpiochip_remove_pin_ranges(chip);
@@ -1287,9 +1308,6 @@ int gpiochip_remove(struct gpio_chip *chip)
spin_unlock_irqrestore(&gpio_lock, flags);
- if (status == 0)
- gpiochip_unexport(chip);
-
return status;
}
EXPORT_SYMBOL_GPL(gpiochip_remove);