summaryrefslogtreecommitdiffstats
path: root/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch')
-rw-r--r--target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch93
1 files changed, 93 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch b/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch
new file mode 100644
index 000000000..a6822fc14
--- /dev/null
+++ b/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch
@@ -0,0 +1,93 @@
+From: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
+Date: Mon, 28 Apr 2008 09:14:44 +0000 (-0700)
+Subject: gpiolib: better rmmod infrastructure
+X-Git-Tag: v2.6.26-rc1~851
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=438d8908b379b6322fc3b28d45c9ebdddf58bc20
+
+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 d8db2f8..eb75d12 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -68,6 +68,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc)
+ 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 @@ int gpio_request(unsigned gpio, const char *label)
+ 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 @@ int gpio_request(unsigned gpio, const char *label)
+ 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 @@ void gpio_free(unsigned gpio)
+ 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 seq_file;
+ */
+ struct gpio_chip {
+ char *label;
++ struct module *owner;
+
+ int (*direction_input)(struct gpio_chip *chip,
+ unsigned offset);