|
@@ -551,6 +551,7 @@ static struct class gpio_class = {
|
|
|
*/
|
|
|
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
|
|
{
|
|
|
+ struct gpio_chip *chip;
|
|
|
unsigned long flags;
|
|
|
int status;
|
|
|
const char *ioname = NULL;
|
|
@@ -568,8 +569,16 @@ 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)) {
|
|
@@ -783,12 +792,15 @@ 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 = false;
|
|
|
status = 0;
|
|
|
} else
|
|
@@ -797,6 +809,13 @@ void gpiochip_unexport(struct gpio_chip *chip)
|
|
|
|
|
|
if (status)
|
|
|
chip_dbg(chip, "%s: status %d\n", __func__, 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)
|