gpiolib: better rmmod infrastructure
As long as one or more GPIOs on a gpio chip are used its driver should not be
unloaded. The existing mechanism (gpiochip_remove failure) doesn't address
that, since rmmod can no longer be made to fail by having the cleanup code
report errors. Module usecounts are the solution.
Assuming standard "initialize struct to zero" policies, this change won't
affect SOC platform drivers. However, drivers for external chips (on I2C and
SPI busses) should be updated if they can be built as modules.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
[ gpio_ensure_requested() needs to update module usecounts too ]
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d8db2f8e..eb75d12e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -68,6 +68,9 @@
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
desc_set_label(desc, "[auto]");
+ if (!try_module_get(desc->chip->owner))
+ pr_err("GPIO-%d: module can't be gotten \n",
+ (int)(desc - gpio_desc));
}
}
@@ -177,6 +180,9 @@
if (desc->chip == NULL)
goto done;
+ if (!try_module_get(desc->chip->owner))
+ goto done;
+
/* NOTE: gpio_request() can be called in early boot,
* before IRQs are enabled.
*/
@@ -184,8 +190,10 @@
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
desc_set_label(desc, label ? : "?");
status = 0;
- } else
+ } else {
status = -EBUSY;
+ module_put(desc->chip->owner);
+ }
done:
if (status)
@@ -209,9 +217,10 @@
spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
- if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags))
+ if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
desc_set_label(desc, NULL);
- else
+ module_put(desc->chip->owner);
+ } else
WARN_ON(extra_checks);
spin_unlock_irqrestore(&gpio_lock, flags);
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index f29a502..7e77b6f 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -17,6 +17,7 @@
#endif
struct seq_file;
+struct module;
/**
* struct gpio_chip - abstract a GPIO controller
@@ -48,6 +49,7 @@
*/
struct gpio_chip {
char *label;
+ struct module *owner;
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);