From: Guennadi Liakhovetski 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 [ gpio_ensure_requested() needs to update module usecounts too ] Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- 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);