gpiolib: better rmmod infrastructure
authorGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>
Mon, 28 Apr 2008 09:14:44 +0000 (02:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 28 Apr 2008 15:58:34 +0000 (08:58 -0700)
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>
drivers/gpio/gpiolib.c
include/asm-generic/gpio.h

index d8db2f8ee41139a04248aaaf3767d8b947927817..eb75d12e83b7a67fe95cdc18022a4f257d0ecc2d 100644 (file)
@@ -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);
index f29a502f4a6c3d1a656ae5142f52b98fe6421408..7e77b6ff45bb2243f9e6cf0bb79e45664fe1777d 100644 (file)
@@ -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);