surprise :p
SVN-Revision: 11894
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
diff -Nur a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
|
||||
--- a/drivers/mtd/devices/m25p80.c 2008-07-06 14:36:59.000000000 +0200
|
||||
+++ b/drivers/mtd/devices/m25p80.c 2008-07-06 15:17:48.000000000 +0200
|
||||
@@ -631,12 +631,10 @@
|
||||
struct mtd_partition *parts = NULL;
|
||||
int nr_parts = 0;
|
||||
|
||||
-#ifdef CONFIG_MTD_CMDLINE_PARTS
|
||||
- static const char *part_probes[] = { "cmdlinepart", NULL, };
|
||||
+ static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL, };
|
||||
|
||||
nr_parts = parse_mtd_partitions(&flash->mtd,
|
||||
part_probes, &parts, 0);
|
||||
-#endif
|
||||
|
||||
if (nr_parts <= 0 && data && data->parts) {
|
||||
parts = data->parts;
|
||||
@@ -1,18 +0,0 @@
|
||||
Backport gpio_is_valid() for gpiolib from linux-2.6.26
|
||||
Index: linux-2.6.25.10/include/asm-generic/gpio.h
|
||||
===================================================================
|
||||
--- linux-2.6.25.10.orig/include/asm-generic/gpio.h 2008-07-03 05:46:47.000000000 +0200
|
||||
+++ linux-2.6.25.10/include/asm-generic/gpio.h 2008-07-20 20:32:12.000000000 +0200
|
||||
@@ -16,6 +16,12 @@
|
||||
#define ARCH_NR_GPIOS 256
|
||||
#endif
|
||||
|
||||
+static inline int gpio_is_valid(int number)
|
||||
+{
|
||||
+ /* only some non-negative numbers are valid */
|
||||
+ return ((unsigned)number) < ARCH_NR_GPIOS;
|
||||
+}
|
||||
+
|
||||
struct seq_file;
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
@@ -0,0 +1,136 @@
|
||||
From: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
|
||||
Date: Mon, 28 Apr 2008 09:14:46 +0000 (-0700)
|
||||
Subject: gpio: define gpio_is_valid()
|
||||
X-Git-Tag: v2.6.26-rc1~849
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=e6de1808f8ebfeb7e49f3c5a30cb8f2032beb287
|
||||
|
||||
gpio: define gpio_is_valid()
|
||||
|
||||
Introduce a gpio_is_valid() predicate; use it in gpiolib.
|
||||
|
||||
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
|
||||
[ use inline function; follow the gpio_* naming convention;
|
||||
work without gpiolib; all programming interfaces need docs ]
|
||||
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/Documentation/gpio.txt b/Documentation/gpio.txt
|
||||
index 5463009..c35ca9e 100644
|
||||
--- a/Documentation/gpio.txt
|
||||
+++ b/Documentation/gpio.txt
|
||||
@@ -107,6 +107,16 @@ type of GPIO controller, and on one particular board 80-95 with an FPGA.
|
||||
The numbers need not be contiguous; either of those platforms could also
|
||||
use numbers 2000-2063 to identify GPIOs in a bank of I2C GPIO expanders.
|
||||
|
||||
+If you want to initialize a structure with an invalid GPIO number, use
|
||||
+some negative number (perhaps "-EINVAL"); that will never be valid. To
|
||||
+test if a number could reference a GPIO, you may use this predicate:
|
||||
+
|
||||
+ int gpio_is_valid(int number);
|
||||
+
|
||||
+A number that's not valid will be rejected by calls which may request
|
||||
+or free GPIOs (see below). Other numbers may also be rejected; for
|
||||
+example, a number might be valid but unused on a given board.
|
||||
+
|
||||
Whether a platform supports multiple GPIO controllers is currently a
|
||||
platform-specific implementation issue.
|
||||
|
||||
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
|
||||
index eb75d12..623fcd9 100644
|
||||
--- a/drivers/gpio/gpiolib.c
|
||||
+++ b/drivers/gpio/gpiolib.c
|
||||
@@ -99,7 +99,7 @@ int gpiochip_add(struct gpio_chip *chip)
|
||||
* dynamic allocation. We don't currently support that.
|
||||
*/
|
||||
|
||||
- if (chip->base < 0 || (chip->base + chip->ngpio) >= ARCH_NR_GPIOS) {
|
||||
+ if (chip->base < 0 || !gpio_is_valid(chip->base + chip->ngpio)) {
|
||||
status = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ int gpio_request(unsigned gpio, const char *label)
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
- if (gpio >= ARCH_NR_GPIOS)
|
||||
+ if (!gpio_is_valid(gpio))
|
||||
goto done;
|
||||
desc = &gpio_desc[gpio];
|
||||
if (desc->chip == NULL)
|
||||
@@ -209,7 +209,7 @@ void gpio_free(unsigned gpio)
|
||||
unsigned long flags;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
- if (gpio >= ARCH_NR_GPIOS) {
|
||||
+ if (!gpio_is_valid(gpio)) {
|
||||
WARN_ON(extra_checks);
|
||||
return;
|
||||
}
|
||||
@@ -245,7 +245,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
unsigned gpio = chip->base + offset;
|
||||
|
||||
- if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip)
|
||||
+ if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip)
|
||||
return NULL;
|
||||
if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
|
||||
return NULL;
|
||||
@@ -276,7 +276,7 @@ int gpio_direction_input(unsigned gpio)
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
- if (gpio >= ARCH_NR_GPIOS)
|
||||
+ if (!gpio_is_valid(gpio))
|
||||
goto fail;
|
||||
chip = desc->chip;
|
||||
if (!chip || !chip->get || !chip->direction_input)
|
||||
@@ -314,7 +314,7 @@ int gpio_direction_output(unsigned gpio, int value)
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
- if (gpio >= ARCH_NR_GPIOS)
|
||||
+ if (!gpio_is_valid(gpio))
|
||||
goto fail;
|
||||
chip = desc->chip;
|
||||
if (!chip || !chip->set || !chip->direction_output)
|
||||
@@ -531,7 +531,7 @@ static int gpiolib_show(struct seq_file *s, void *unused)
|
||||
|
||||
/* REVISIT this isn't locked against gpio_chip removal ... */
|
||||
|
||||
- for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
|
||||
+ for (gpio = 0; gpio_is_valid(gpio); gpio++) {
|
||||
if (chip == gpio_desc[gpio].chip)
|
||||
continue;
|
||||
chip = gpio_desc[gpio].chip;
|
||||
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
|
||||
index 7e77b6f..464c5b3 100644
|
||||
--- a/include/asm-generic/gpio.h
|
||||
+++ b/include/asm-generic/gpio.h
|
||||
@@ -16,6 +16,12 @@
|
||||
#define ARCH_NR_GPIOS 256
|
||||
#endif
|
||||
|
||||
+static inline int gpio_is_valid(int number)
|
||||
+{
|
||||
+ /* only some non-negative numbers are valid */
|
||||
+ return ((unsigned)number) < ARCH_NR_GPIOS;
|
||||
+}
|
||||
+
|
||||
struct seq_file;
|
||||
struct module;
|
||||
|
||||
@@ -99,6 +105,12 @@ extern int __gpio_cansleep(unsigned gpio);
|
||||
|
||||
#else
|
||||
|
||||
+static inline int gpio_is_valid(int number)
|
||||
+{
|
||||
+ /* only non-negative numbers are valid */
|
||||
+ return number >= 0;
|
||||
+}
|
||||
+
|
||||
/* platforms that don't directly support access to GPIOs through I2C, SPI,
|
||||
* or other blocking infrastructure can use these wrappers.
|
||||
*/
|
||||
@@ -0,0 +1,118 @@
|
||||
From: Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
Date: Mon, 28 Apr 2008 09:14:46 +0000 (-0700)
|
||||
Subject: gpiolib: dynamic gpio number allocation
|
||||
X-Git-Tag: v2.6.26-rc1~848
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=8d0aab2f16c4fa170f32e7a74a52cd0122bbafef
|
||||
|
||||
gpiolib: dynamic gpio number allocation
|
||||
|
||||
If gpio_chip->base is negative during registration, gpiolib performs dynamic
|
||||
base allocation. This is useful for devices that aren't always present, such
|
||||
as GPIOs on hotplugged devices rather than mainboards. (This behavior was
|
||||
previously specified but not implemented.)
|
||||
|
||||
To avoid using any numbers that may have been explicitly assigned but not yet
|
||||
registered, this dynamic allocation assigns GPIO numbers from the biggest
|
||||
number on down, instead of from the smallest on up.
|
||||
|
||||
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
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 623fcd9..2ba6127 100644
|
||||
--- a/drivers/gpio/gpiolib.c
|
||||
+++ b/drivers/gpio/gpiolib.c
|
||||
@@ -80,6 +80,33 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
|
||||
return gpio_desc[gpio].chip;
|
||||
}
|
||||
|
||||
+/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
|
||||
+static int gpiochip_find_base(int ngpio)
|
||||
+{
|
||||
+ int i;
|
||||
+ int spare = 0;
|
||||
+ int base = -ENOSPC;
|
||||
+
|
||||
+ for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
|
||||
+ struct gpio_chip *chip = gpio_desc[i].chip;
|
||||
+
|
||||
+ if (!chip) {
|
||||
+ spare++;
|
||||
+ if (spare == ngpio) {
|
||||
+ base = i;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ spare = 0;
|
||||
+ i -= chip->ngpio - 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (gpio_is_valid(base))
|
||||
+ pr_debug("%s: found new base at %d\n", __func__, base);
|
||||
+ return base;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* gpiochip_add() - register a gpio_chip
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
@@ -88,38 +115,49 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
|
||||
* Returns a negative errno if the chip can't be registered, such as
|
||||
* because the chip->base is invalid or already associated with a
|
||||
* different chip. Otherwise it returns zero as a success code.
|
||||
+ *
|
||||
+ * If chip->base is negative, this requests dynamic assignment of
|
||||
+ * a range of valid GPIOs.
|
||||
*/
|
||||
int gpiochip_add(struct gpio_chip *chip)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status = 0;
|
||||
unsigned id;
|
||||
+ int base = chip->base;
|
||||
|
||||
- /* NOTE chip->base negative is reserved to mean a request for
|
||||
- * dynamic allocation. We don't currently support that.
|
||||
- */
|
||||
-
|
||||
- if (chip->base < 0 || !gpio_is_valid(chip->base + chip->ngpio)) {
|
||||
+ if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio))
|
||||
+ && base >= 0) {
|
||||
status = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
+ if (base < 0) {
|
||||
+ base = gpiochip_find_base(chip->ngpio);
|
||||
+ if (base < 0) {
|
||||
+ status = base;
|
||||
+ goto fail_unlock;
|
||||
+ }
|
||||
+ chip->base = base;
|
||||
+ }
|
||||
+
|
||||
/* these GPIO numbers must not be managed by another gpio_chip */
|
||||
- for (id = chip->base; id < chip->base + chip->ngpio; id++) {
|
||||
+ for (id = base; id < base + chip->ngpio; id++) {
|
||||
if (gpio_desc[id].chip != NULL) {
|
||||
status = -EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (status == 0) {
|
||||
- for (id = chip->base; id < chip->base + chip->ngpio; id++) {
|
||||
+ for (id = base; id < base + chip->ngpio; id++) {
|
||||
gpio_desc[id].chip = chip;
|
||||
gpio_desc[id].flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+fail_unlock:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
fail:
|
||||
/* failures here can mean systems won't boot... */
|
||||
@@ -0,0 +1,116 @@
|
||||
From: Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
Date: Mon, 28 Apr 2008 09:14:47 +0000 (-0700)
|
||||
Subject: gpiochip_reserve()
|
||||
X-Git-Tag: v2.6.26-rc1~847
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=169b6a7a6e91e1ea32136681b475cbaf2074bf35
|
||||
|
||||
gpiochip_reserve()
|
||||
|
||||
Add a new function gpiochip_reserve() to reserve ranges of gpios that platform
|
||||
code has pre-allocated. That is, this marks gpio numbers which will be
|
||||
claimed by drivers that haven't yet been loaded, and thus are not available
|
||||
for dynamic gpio number allocation.
|
||||
|
||||
[akpm@linux-foundation.org: remove unneeded __must_check]
|
||||
[david-b@pacbell.net: don't export gpiochip_reserve (section fix)]
|
||||
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
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 2ba6127..24c62b8 100644
|
||||
--- a/drivers/gpio/gpiolib.c
|
||||
+++ b/drivers/gpio/gpiolib.c
|
||||
@@ -43,6 +43,7 @@ struct gpio_desc {
|
||||
/* flag symbols are bit numbers */
|
||||
#define FLAG_REQUESTED 0
|
||||
#define FLAG_IS_OUT 1
|
||||
+#define FLAG_RESERVED 2
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
const char *label;
|
||||
@@ -88,9 +89,10 @@ static int gpiochip_find_base(int ngpio)
|
||||
int base = -ENOSPC;
|
||||
|
||||
for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
|
||||
- struct gpio_chip *chip = gpio_desc[i].chip;
|
||||
+ struct gpio_desc *desc = &gpio_desc[i];
|
||||
+ struct gpio_chip *chip = desc->chip;
|
||||
|
||||
- if (!chip) {
|
||||
+ if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) {
|
||||
spare++;
|
||||
if (spare == ngpio) {
|
||||
base = i;
|
||||
@@ -98,7 +100,8 @@ static int gpiochip_find_base(int ngpio)
|
||||
}
|
||||
} else {
|
||||
spare = 0;
|
||||
- i -= chip->ngpio - 1;
|
||||
+ if (chip)
|
||||
+ i -= chip->ngpio - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +111,47 @@ static int gpiochip_find_base(int ngpio)
|
||||
}
|
||||
|
||||
/**
|
||||
+ * gpiochip_reserve() - reserve range of gpios to use with platform code only
|
||||
+ * @start: starting gpio number
|
||||
+ * @ngpio: number of gpios to reserve
|
||||
+ * Context: platform init, potentially before irqs or kmalloc will work
|
||||
+ *
|
||||
+ * Returns a negative errno if any gpio within the range is already reserved
|
||||
+ * or registered, else returns zero as a success code. Use this function
|
||||
+ * to mark a range of gpios as unavailable for dynamic gpio number allocation,
|
||||
+ * for example because its driver support is not yet loaded.
|
||||
+ */
|
||||
+int __init gpiochip_reserve(int start, int ngpio)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ unsigned long flags;
|
||||
+ int i;
|
||||
+
|
||||
+ if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ spin_lock_irqsave(&gpio_lock, flags);
|
||||
+
|
||||
+ for (i = start; i < start + ngpio; i++) {
|
||||
+ struct gpio_desc *desc = &gpio_desc[i];
|
||||
+
|
||||
+ if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) {
|
||||
+ ret = -EBUSY;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ set_bit(FLAG_RESERVED, &desc->flags);
|
||||
+ }
|
||||
+
|
||||
+ pr_debug("%s: reserved gpios from %d to %d\n",
|
||||
+ __func__, start, start + ngpio - 1);
|
||||
+err:
|
||||
+ spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* gpiochip_add() - register a gpio_chip
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
* Context: potentially before irqs or kmalloc will work
|
||||
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
|
||||
index 464c5b3..ecf675a 100644
|
||||
--- a/include/asm-generic/gpio.h
|
||||
+++ b/include/asm-generic/gpio.h
|
||||
@@ -74,6 +74,7 @@ struct gpio_chip {
|
||||
|
||||
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
|
||||
unsigned offset);
|
||||
+extern int __init __must_check gpiochip_reserve(int start, int ngpio);
|
||||
|
||||
/* add/remove chips */
|
||||
extern int gpiochip_add(struct gpio_chip *chip);
|
||||
@@ -0,0 +1,48 @@
|
||||
From: Trent Piepho <xyzzy@speakeasy.org>
|
||||
Date: Fri, 23 May 2008 20:04:44 +0000 (-0700)
|
||||
Subject: gpiolib: fix off by one errors
|
||||
X-Git-Tag: v2.6.26-rc4~31
|
||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=bff5fda972dc23bd1806a47c2098ae173585d013
|
||||
|
||||
gpiolib: fix off by one errors
|
||||
|
||||
The last gpio belonging to a chip is chip->base + chip->ngpios - 1. Some
|
||||
places in the code, but not all, forgot the critical minus one.
|
||||
|
||||
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
|
||||
Acked-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 7f138c6..beaf6b3 100644
|
||||
--- a/drivers/gpio/gpiolib.c
|
||||
+++ b/drivers/gpio/gpiolib.c
|
||||
@@ -127,7 +127,7 @@ int __init gpiochip_reserve(int start, int ngpio)
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
- if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio))
|
||||
+ if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
@@ -170,7 +170,7 @@ int gpiochip_add(struct gpio_chip *chip)
|
||||
unsigned id;
|
||||
int base = chip->base;
|
||||
|
||||
- if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio))
|
||||
+ if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
|
||||
&& base >= 0) {
|
||||
status = -EINVAL;
|
||||
goto fail;
|
||||
@@ -207,7 +207,7 @@ fail:
|
||||
/* failures here can mean systems won't boot... */
|
||||
if (status)
|
||||
pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
|
||||
- chip->base, chip->base + chip->ngpio,
|
||||
+ chip->base, chip->base + chip->ngpio - 1,
|
||||
chip->label ? : "generic");
|
||||
return status;
|
||||
}
|
||||
Reference in New Issue
Block a user