http://blog.csdn.net/yi412/article/details/20845789
gpio: sysfs interface
分类: linux系统学习
2014-03-09 15:11
276人阅读
评论(0)
收藏
举报
gpio: sysfs interface (updated)
From: | David Brownell <david-b@pacbell.net> | |
To: | Andrew Morton <akpm@linux-foundation.org>, lkml <linux-kernel@vger.kernel.org> | |
Subject: | [patch 2.6.26-rc5] gpio: sysfs interface (updated) | |
Date: | Thu, 12 Jun 2008 11:53:36 -0700 | |
Message-ID: | <200806121153.36557.david-b@pacbell.net> | |
Cc: | Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> | |
Archive-link: | Article, Thread |
Subject: gpio: sysfs interface From: David Brownell <dbrownell@users.sourceforge.net>This adds a simple sysfs interface for GPIOs./sys/class/gpio/export ... asks the kernel to export a GPIO to userspace/unexport ... to return a GPIO to the kernel/gpioN ... for each exported GPIO #N/value ... always readable, writes fail for input GPIOs/direction ... r/w as: in, out (default low); write high, low/gpiochipN ... for each gpiochip; #N is its first GPIO/base ... (r/o) same as N/label ... (r/o) descriptive, not necessarily unique/ngpio ... (r/o) number of GPIOs; numbered N .. N+(ngpio - 1)GPIOs claimed by kernel code may be exported by its owner using a new gpio_export() call, which should be most useful for driver debugging. Such exports may optionally be done without a "direction" attribute.Userspace may ask to take over a GPIO by writing to a sysfs control file, helping to cope with incomplete board support or other "one-off" requirements that don't merit full kernel support:echo 23 > /sys/class/gpio/export... will gpio_request(23, "sysfs") and gpio_export(23);use /sys/class/gpio/gpio-23/direction to (re)configure it,when that GPIO can be used as both input and output.echo 23 > /sys/class/gpio/unexport... will gpio_free(23), when it was exported as aboveThe extra D-space footprint is a few hundred bytes, except for the sysfs resources associated with each exported GPIO. The additional I-space footprint is about two thirds of the current size of gpiolib (!). Since no /dev node creation is involved, no "udev" support is needed.Related changes:* This adds a device pointer to "struct gpio_chip". When GPIOproviders initialize that, sysfs gpio class devices become children ofthat device instead of being "virtual" devices.* The (few) gpio_chip providers which have such a device node havebeen updated.* Some gpio_chip drivers also needed to update their module "owner"field ... for which missing kerneldoc was added.* Some gpio_chips don't support input GPIOs. Those GPIOs are nowflagged appropriately when the chip is registered.Based on previous patches, and discussion both on and off LKML.Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> --- Changes since previous version: trivial fix for locking issue fromhttp://marc.info/?l=linux-kernel&m=121249999315314&...A Documentation/ABI/testing/sysfs-gpio update is ready to submit once this merges to mainline.Documentation/gpio.txt | 123 +++++++++-arch/arm/plat-omap/gpio.c | 3 arch/avr32/mach-at32ap/pio.c | 2 drivers/gpio/Kconfig | 15 +drivers/gpio/gpiolib.c | 512 ++++++++++++++++++++++++++++++++++++++++++-drivers/gpio/mcp23s08.c | 1 drivers/gpio/pca953x.c | 1 drivers/gpio/pcf857x.c | 1 drivers/i2c/chips/tps65010.c | 2 drivers/mfd/htc-egpio.c | 2 include/asm-generic/gpio.h | 33 ++include/linux/gpio.h | 13 +12 files changed, 692 insertions(+), 16 deletions(-)--- a/Documentation/gpio.txt 2008-06-09 20:02:35.000000000 -0700 +++ b/Documentation/gpio.txt 2008-06-09 20:02:43.000000000 -0700 @@ -347,15 +347,12 @@ necessarily be nonportable.Dynamic definition of GPIOs is not currently standard; for example, asa side effect of configuring an add-on board with some GPIO expanders.-These calls are purely for kernel space, but a userspace API could be built -on top of them. -GPIO implementor's framework (OPTIONAL)=======================================As noted earlier, there is an optional implementation framework making iteasier for platforms to support different kinds of GPIO controller using -the same programming interface. +the same programming interface. This framework is called "gpiolib".As a debugging aid, if debugfs is available a /sys/kernel/debug/gpio filewill be found there. That will list all the controllers registered through @@ -439,4 +436,120 @@ becomes available. That may mean the decalls for that GPIO can work. One way to address such dependencies is forsuch gpio_chip controllers to provide setup() and teardown() callbacks toboard specific code; those board specific callbacks would register devices -once all the necessary resources are available. +once all the necessary resources are available, and remove them later when +the GPIO controller device becomes unavailable. + + +Sysfs Interface for Userspace (OPTIONAL) +======================================== +Platforms which use the "gpiolib" implementors framework may choose to +configure a sysfs user interface to GPIOs. This is different from the +debugfs interface, since it provides control over GPIO direction and +value instead of just showing a gpio state summary. Plus, it could be +present on production systems without debugging support. + +Given approprate hardware documentation for the system, userspace could +know for example that GPIO #23 controls the write protect line used to +protect boot loader segments in flash memory. System upgrade procedures +may need to temporarily remove that protection, first importing a GPIO, +then changing its output state, then updating the code before re-enabling +the write protection. In normal use, GPIO #23 would never be touched, +and the kernel would have no need to know about it. + +Again depending on appropriate hardware documentation, on some systems +userspace GPIO can be used to determine system configuration data that +standard kernels won't know about. And for some tasks, simple userspace +GPIO drivers could be all that the system really needs. + +Note that standard kernel drivers exist for common "LEDs and Buttons" +GPIO tasks: "leds-gpio" and "gpio_keys", respectively. Use those +instead of talking directly to the GPIOs; they integrate with kernel +frameworks better than your userspace code could. + + +Paths in Sysfs +-------------- +There are three kinds of entry in /sys/class/gpio: + + - Control interfaces used to get userspace control over GPIOs; + + - GPIOs themselves; and + + - GPIO controllers ("gpio_chip" instances). + +That's in addition to standard files including the "device" symlink. + +The control interfaces are write-only: + + /sys/class/gpio/ + + "export" ... Userspace may ask the kernel to export control of + a GPIO to userspace by writing its number to this file. + + Example: "echo 19 > export" will create a "gpio19" node + for GPIO #19, if that's not requested by kernel code. + + "unexport" ... Reverses the effect of exporting to userspace. + + Example: "echo 19 > unexport" will remove a "gpio19" + node exported using the "export" file. + +GPIO signals have paths like /sys/class/gpio/gpio42/ (for GPIO #42) +and have the following read/write attributes: + + /sys/class/gpio/gpioN/ + + "direction" ... reads as either "in" or "out". This value may + normally be written. Writing as "out" defaults to + initializing the value as low. To ensure glitch free + operation, values "low" and "high" may be written to + configure the GPIO as an output with that initial value. + + Note that this attribute *will not exist* if the kernel + doesn't support changing the direction of a GPIO, or + it was exported by kernel code that didn't explicitly + allow userspace to reconfigure this GPIO's direction. + + "value" ... reads as either 0 (low) or 1 (high). If the GPIO + is configured as an output, this value may be written; + any nonzero value is treated as high. + +GPIO controllers have paths like /sys/class/gpio/chipchip42/ (for the +controller implementing GPIOs starting at #42) and have the following +read-only attributes: + + /sys/class/gpio/gpiochipN/ + + "base" ... same as N, the first GPIO managed by this chip + + "label" ... provided for diagnostics (not always unique) + + "ngpio" ... how many GPIOs this manges (N to N + ngpio - 1) + +Board documentation should in most cases cover what GPIOs are used for +what purposes. However, those numbers are not always stable; GPIOs on +a daughtercard might be different depending on the base board being used, +or other cards in the stack. In such cases, you may need to use the +gpiochip nodes (possibly in conjunction with schematics) to determine +the correct GPIO number to use for a given signal. + + +Exporting from Kernel code +-------------------------- +Kernel code can explicitly manage exports of GPIOs which have already been +requested using gpio_request(): + + /* export the GPIO to userspace */ + int gpio_export(unsigned gpio, bool direction_may_change); + + /* reverse gpio_export() */ + void gpio_unexport(); + +After a kernel driver requests a GPIO, it may only be made available in +the sysfs interface by gpio_export(). The driver can control whether the +signal direction may change. This helps drivers prevent userspace code +from accidentally clobbering important system state. + +This explicit exporting can help with debugging (by making some kinds +of experiments easier), or can provide an always-there interface that's +suitable for documenting as part of a board support package. --- a/arch/arm/plat-omap/gpio.c 2008-06-09 20:02:34.000000000 -0700 +++ b/arch/arm/plat-omap/gpio.c 2008-06-09 20:02:43.000000000 -0700 @@ -1488,6 +1488,9 @@ static int __init _omap_gpio_init(void)bank->chip.set = gpio_set;if (bank_is_mpuio(bank)) {bank->chip.label = "mpuio"; +#ifdef CONFIG_ARCH_OMAP1 + bank->chip.dev = &omap_mpuio_device.dev; +#endifbank->chip.base = OMAP_MPUIO(0);} else {bank->chip.label = "gpio"; --- a/arch/avr32/mach-at32ap/pio.c 2008-06-09 20:02:34.000000000 -0700 +++ b/arch/avr32/mach-at32ap/pio.c 2008-06-11 13:24:12.000000000 -0700 @@ -358,6 +358,8 @@ static int __init pio_probe(struct platfpio->chip.label = pio->name;pio->chip.base = pdev->id * 32;pio->chip.ngpio = 32; + pio->chip.dev = &pdev->dev; + pio->chip.owner = THIS_MODULE;pio->chip.direction_input = direction_input;pio->chip.get = gpio_get; --- a/drivers/gpio/Kconfig 2008-06-09 20:02:34.000000000 -0700 +++ b/drivers/gpio/Kconfig 2008-06-11 12:46:39.000000000 -0700 @@ -23,6 +23,21 @@ config DEBUG_GPIOslower. The diagnostics help catch the type of setup errorsthat are most common when setting up new platforms or boards.+config GPIO_SYSFS + bool "/sys/class/gpio/... (sysfs interface)" + depends on SYSFS && EXPERIMENTAL + help + Say Y here to add a sysfs interface for GPIOs. + + This is mostly useful to work around omissions in a system's + kernel support. Those are common in custom and semicustom + hardware assembled using standard kernels with a minimum of + custom patches. In those cases, userspace code may import + a given GPIO from the kernel, if no kernel driver requested it. + + Kernel drivers may also request that a particular GPIO be + exported to userspace; this can be useful when debugging. +# put expanders in the right section, in alphabetical ordercomment "I2C GPIO expanders:" --- a/drivers/gpio/gpiolib.c 2008-06-09 20:02:34.000000000 -0700 +++ b/drivers/gpio/gpiolib.c 2008-06-11 12:41:57.000000000 -0700 @@ -2,8 +2,11 @@#include <linux/module.h>#include <linux/irq.h>#include <linux/spinlock.h> - -#include <asm/gpio.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/gpio.h>/* Optional implementation infrastructure for GPIO interfaces. @@ -44,6 +47,8 @@ struct gpio_desc {#define FLAG_REQUESTED 0#define FLAG_IS_OUT 1#define FLAG_RESERVED 2 +#define FLAG_EXPORT 3 /* protected by sysfs_lock */ +#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */#ifdef CONFIG_DEBUG_FSconst char *label; @@ -151,6 +156,484 @@ err:return ret;}+#ifdef CONFIG_GPIO_SYSFS + +/* lock protects against unexport_gpio() being called while + * sysfs files are active. + */ +static DEFINE_MUTEX(sysfs_lock); + +/* + * /sys/class/gpio/gpioN... only for GPIOs that are exported + * /direction + * * MAY BE OMITTED if kernel won't allow direction changes + * * is read/write as "in" or "out" + * * may also be written as "high" or "low", initializing + * output value as specified ("out" implies "low") + * /value + * * always readable, subject to hardware behavior + * * may be writable, as zero/nonzero + * + * REVISIT there will likely be an attribute for configuring async + * notifications, e.g. to specify polling interval or IRQ trigger type + * that would for example trigger a poll() on the "value". + */ + +static ssize_t gpio_direction_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else + status = sprintf(buf, "%s\n", + test_bit(FLAG_IS_OUT, &desc->flags) + ? "out" : "in"); + + mutex_unlock(&sysfs_lock); + return status; +} + +static ssize_t gpio_direction_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + const struct gpio_desc *desc = dev_get_drvdata(dev); + unsigned gpio = desc - gpio_desc; + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else if (sysfs_streq(buf, "high")) + status = gpio_direction_output(gpio, 1); + else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) + status = gpio_direction_output(gpio, 0); + else if (sysfs_streq(buf, "in")) + status = gpio_direction_input(gpio); + else + status = -EINVAL; + + mutex_unlock(&sysfs_lock); + return status ? : size; +} + +static const DEVICE_ATTR(direction, 0644, + gpio_direction_show, gpio_direction_store); + +static ssize_t gpio_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_desc *desc = dev_get_drvdata(dev); + unsigned gpio = desc - gpio_desc; + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else + status = sprintf(buf, "%d\n", gpio_get_value_cansleep(gpio)); + + mutex_unlock(&sysfs_lock); + return status; +} + +static ssize_t gpio_value_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + const struct gpio_desc *desc = dev_get_drvdata(dev); + unsigned gpio = desc - gpio_desc; + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else if (!test_bit(FLAG_IS_OUT, &desc->flags)) + status = -EPERM; + else { + long value; + + status = strict_strtol(buf, 0, &value); + if (status == 0) { + gpio_set_value_cansleep(gpio, value != 0); + status = size; + } + } + + mutex_unlock(&sysfs_lock); + return status; +} + +static /*const*/ DEVICE_ATTR(value, 0644, + gpio_value_show, gpio_value_store); + +static const struct attribute *gpio_attrs[] = { + &dev_attr_direction.attr, + &dev_attr_value.attr, + NULL, +}; + +static const struct attribute_group gpio_attr_group = { + .attrs = (struct attribute **) gpio_attrs, +}; + +/* + * /sys/class/gpio/gpiochipN/ + * /base ... matching gpio_chip.base (N) + * /label ... matching gpio_chip.label + * /ngpio ... matching gpio_chip.ngpio + */ + +static ssize_t chip_base_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_chip *chip = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", chip->base); +} +static DEVICE_ATTR(base, 0444, chip_base_show, NULL); + +static ssize_t chip_label_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_chip *chip = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", chip->label ? : ""); +} +static DEVICE_ATTR(label, 0444, chip_label_show, NULL); + +static ssize_t chip_ngpio_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_chip *chip = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", chip->ngpio); +} +static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); + +static const struct attribute *gpiochip_attrs[] = { + &dev_attr_base.attr, + &dev_attr_label.attr, + &dev_attr_ngpio.attr, + NULL, +}; + +static const struct attribute_group gpiochip_attr_group = { + .attrs = (struct attribute **) gpiochip_attrs, +}; + +/* + * /sys/class/gpio/export ... write-only + * integer N ... number of GPIO to export (full access) + * /sys/class/gpio/unexport ... write-only + * integer N ... number of GPIO to unexport + */ +static ssize_t export_store(struct class *class, const char *buf, size_t len) +{ + long gpio; + int status; + + status = strict_strtol(buf, 0, &gpio); + if (status < 0) + goto done; + + /* No extra locking here; FLAG_SYSFS just signifies that the + * request and export were done by on behalf of userspace, so + * they may be undone on its behalf too. + */ + + status = gpio_request(gpio, "sysfs"); + if (status < 0) + goto done; + + status = gpio_export(gpio, true); + if (status < 0) + gpio_free(gpio); + else + set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags); + +done: + if (status) + pr_debug("%s: status %d\n", __func__, status); + return status ? : len; +} + +static ssize_t unexport_store(struct class *class, const char *buf, size_t len) +{ + long gpio; + int status; + + status = strict_strtol(buf, 0, &gpio); + if (status < 0) + goto done; + + status = -EINVAL; + + /* reject bogus commands (gpio_unexport ignores them) */ + if (!gpio_is_valid(gpio)) + goto done; + + /* No extra locking here; FLAG_SYSFS just signifies that the + * request and export were done by on behalf of userspace, so + * they may be undone on its behalf too. + */ + if (test_and_clear_bit(FLAG_SYSFS, &gpio_desc[gpio].flags)) { + status = 0; + gpio_free(gpio); + } +done: + if (status) + pr_debug("%s: status %d\n", __func__, status); + return status ? : len; +} + +static struct class_attribute gpio_class_attrs[] = { + __ATTR(export, 0200, NULL, export_store), + __ATTR(unexport, 0200, NULL, unexport_store), + __ATTR_NULL, +}; + +static struct class gpio_class = { + .name = "gpio", + .owner = THIS_MODULE, + + .class_attrs = gpio_class_attrs, +}; + + +/** + * gpio_export - export a GPIO through sysfs + * @gpio: gpio to make available, already requested + * @direction_may_change: true if userspace may change gpio direction + * Context: arch_initcall or later + * + * When drivers want to make a GPIO accessible to userspace after they + * have requested it -- perhaps while debugging, or as part of their + * public interface -- they may use this routine. If the GPIO can + * change direction (some can't) and the caller allows it, userspace + * will see "direction" sysfs attribute which may be used to change + * the gpio's direction. A "value" attribute will always be provided. + * + * Returns zero on success, else an error. + */ +int gpio_export(unsigned gpio, bool direction_may_change) +{ + unsigned long flags; + struct gpio_desc *desc; + int status = -EINVAL; + + /* can't export until sysfs is available ... */ + if (!gpio_class.devices.next) { + pr_debug("%s: called too early!\n", __func__); + return -ENOENT; + } + + if (!gpio_is_valid(gpio)) + goto done; + + mutex_lock(&sysfs_lock); + + spin_lock_irqsave(&gpio_lock, flags); + desc = &gpio_desc[gpio]; + if (test_bit(FLAG_REQUESTED, &desc->flags) + && !test_bit(FLAG_EXPORT, &desc->flags)) { + status = 0; + if (!desc->chip->direction_input + || !desc->chip->direction_output) + direction_may_change = false; + } + spin_unlock_irqrestore(&gpio_lock, flags); + + if (status == 0) { + struct device *dev; + + dev = device_create(&gpio_class, desc->chip->dev, 0, + "gpio%d", gpio); + if (dev) { + dev_set_drvdata(dev, desc); + if (direction_may_change) + status = sysfs_create_group(&dev->kobj, + &gpio_attr_group); + else + status = device_create_file(dev, + &dev_attr_value); + if (status != 0) + device_unregister(dev); + } else + status = -ENODEV; + if (status == 0) + set_bit(FLAG_EXPORT, &desc->flags); + } + + mutex_unlock(&sysfs_lock); + +done: + if (status) + pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + + return status; +} +EXPORT_SYMBOL_GPL(gpio_export); + +static int match_export(struct device *dev, void *data) +{ + return dev_get_drvdata(dev) == data; +} + +/** + * gpio_unexport - reverse effect of gpio_export() + * @gpio: gpio to make unavailable + * + * This is implicit on gpio_free(). + */ +void gpio_unexport(unsigned gpio) +{ + struct gpio_desc *desc; + int status = -EINVAL; + + if (!gpio_is_valid(gpio)) + goto done; + + mutex_lock(&sysfs_lock); + + desc = &gpio_desc[gpio]; + if (test_bit(FLAG_EXPORT, &desc->flags)) { + struct device *dev = NULL; + + dev = class_find_device(&gpio_class, desc, match_export); + if (dev) { + clear_bit(FLAG_EXPORT, &desc->flags); + put_device(dev); + device_unregister(dev); + status = 0; + } else + status = -ENODEV; + } + + mutex_unlock(&sysfs_lock); +done: + if (status) + pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); +} +EXPORT_SYMBOL_GPL(gpio_unexport); + +static int gpiochip_export(struct gpio_chip *chip) +{ + int status; + struct device *dev; + + /* Many systems register gpio chips for SOC support very early, + * before driver model support is available. In those cases we + * export this later, in gpiolib_sysfs_init() ... here we just + * verify that _some_ field of gpio_class got initialized. + */ + if (!gpio_class.devices.next) + return 0; + + /* use chip->base for the ID; it's already known to be unique */ + mutex_lock(&sysfs_lock); + dev = device_create(&gpio_class, chip->dev, 0, + "gpiochip%d", chip->base); + if (dev) { + dev_set_drvdata(dev, chip); + status = sysfs_create_group(&dev->kobj, + &gpiochip_attr_group); + } else + status = -ENODEV; + chip->exported = (status == 0); + mutex_unlock(&sysfs_lock); + + if (status) { + unsigned long flags; + unsigned gpio; + + spin_lock_irqsave(&gpio_lock, flags); + gpio = chip->base; + while (gpio_desc[gpio].chip == chip) + gpio_desc[gpio++].chip = NULL; + spin_unlock_irqrestore(&gpio_lock, flags); + + pr_debug("%s: chip %s status %d\n", __func__, + chip->label, status); + } + + return status; +} + +static void gpiochip_unexport(struct gpio_chip *chip) +{ + int status; + struct device *dev; + + mutex_lock(&sysfs_lock); + dev = class_find_device(&gpio_class, chip, match_export); + if (dev) { + put_device(dev); + device_unregister(dev); + chip->exported = 0; + status = 0; + } else + status = -ENODEV; + mutex_unlock(&sysfs_lock); + + if (status) + pr_debug("%s: chip %s status %d\n", __func__, + chip->label, status); +} + +static int __init gpiolib_sysfs_init(void) +{ + int status; + unsigned long flags; + unsigned gpio; + + status = class_register(&gpio_class); + if (status < 0) + return status; + + /* Scan and register the gpio_chips which registered very + * early (e.g. before the class_register above was called). + * + * We run before arch_initcall() so chip->dev nodes can have + * registered, and so arch_initcall() can always gpio_export(). + */ + spin_lock_irqsave(&gpio_lock, flags); + for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { + struct gpio_chip *chip; + + chip = gpio_desc[gpio].chip; + if (!chip || chip->exported) + continue; + + spin_unlock_irqrestore(&gpio_lock, flags); + status = gpiochip_export(chip); + spin_lock_irqsave(&gpio_lock, flags); + } + spin_unlock_irqrestore(&gpio_lock, flags); + + + return status; +} +postcore_initcall(gpiolib_sysfs_init); + +#else +static inline int gpiochip_export(struct gpio_chip *chip) +{ + return 0; +} + +static inline void gpiochip_unexport(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_GPIO_SYSFS */ +/*** gpiochip_add() - register a gpio_chip* @chip: the chip to register, with chip->base initialized @@ -160,6 +643,11 @@ err:* because the chip->base is invalid or already associated with a* different chip. Otherwise it returns zero as a success code.* + * When gpiochip_add() is called very early during boot, so that GPIOs + * can be freely used, the chip->dev device must be registered before + * the gpio framework's arch_initcall(). Otherwise sysfs initialization + * for GPIOs will fail rudely. + ** If chip->base is negative, this requests dynamic assignment of* a range of valid GPIOs.*/ @@ -182,7 +670,7 @@ int gpiochip_add(struct gpio_chip *chip)base = gpiochip_find_base(chip->ngpio);if (base < 0) {status = base; - goto fail_unlock; + goto unlock;}chip->base = base;} @@ -197,12 +685,16 @@ int gpiochip_add(struct gpio_chip *chip)if (status == 0) {for (id = base; id < base + chip->ngpio; id++) {gpio_desc[id].chip = chip; - gpio_desc[id].flags = 0; + gpio_desc[id].flags = chip->direction_input + ? (1 << FLAG_IS_OUT) + : 0;}}-fail_unlock: +unlock:spin_unlock_irqrestore(&gpio_lock, flags); + if (status == 0) + status = gpiochip_export(chip);fail:/* failures here can mean systems won't boot... */if (status) @@ -239,6 +731,10 @@ int gpiochip_remove(struct gpio_chip *ch}spin_unlock_irqrestore(&gpio_lock, flags); + + if (status == 0) + gpiochip_unexport(chip); +return status;}EXPORT_SYMBOL_GPL(gpiochip_remove); @@ -296,6 +792,8 @@ void gpio_free(unsigned gpio)return;}+ gpio_unexport(gpio); +spin_lock_irqsave(&gpio_lock, flags);desc = &gpio_desc[gpio]; @@ -534,10 +1032,6 @@ EXPORT_SYMBOL_GPL(gpio_set_value_canslee#ifdef CONFIG_DEBUG_FS-#include <linux/debugfs.h> -#include <linux/seq_file.h> - -static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip){unsigned i; --- a/drivers/gpio/mcp23s08.c 2008-06-09 20:02:34.000000000 -0700 +++ b/drivers/gpio/mcp23s08.c 2008-06-09 20:02:43.000000000 -0700 @@ -239,6 +239,7 @@ static int mcp23s08_probe(struct spi_devmcp->chip.base = pdata->base;mcp->chip.ngpio = 8;mcp->chip.can_sleep = 1; + mcp->chip.dev = &spi->dev;mcp->chip.owner = THIS_MODULE;spi_set_drvdata(spi, mcp); --- a/drivers/gpio/pca953x.c 2008-06-09 20:02:34.000000000 -0700 +++ b/drivers/gpio/pca953x.c 2008-06-09 20:02:43.000000000 -0700 @@ -188,6 +188,7 @@ static void pca953x_setup_gpio(struct pcgc->base = chip->gpio_start;gc->ngpio = gpios;gc->label = chip->client->name; + gc->dev = &chip->client->dev;gc->owner = THIS_MODULE;}--- a/drivers/gpio/pcf857x.c 2008-06-09 20:02:34.000000000 -0700 +++ b/drivers/gpio/pcf857x.c 2008-06-09 20:02:43.000000000 -0700 @@ -175,6 +175,7 @@ static int pcf857x_probe(struct i2c_cliegpio->chip.base = pdata->gpio_base;gpio->chip.can_sleep = 1; + gpio->chip.dev = &client->dev;gpio->chip.owner = THIS_MODULE;/* NOTE: the OnSemi jlc1562b is also largely compatible with --- a/drivers/i2c/chips/tps65010.c 2008-06-09 20:02:34.000000000 -0700 +++ b/drivers/i2c/chips/tps65010.c 2008-06-09 20:02:43.000000000 -0700 @@ -636,6 +636,8 @@ static int tps65010_probe(struct i2c_clitps->outmask = board->outmask;tps->chip.label = client->name; + tps->chip.dev = &client->dev; + tps->chip.owner = THIS_MODULE;tps->chip.set = tps65010_gpio_set;tps->chip.direction_output = tps65010_output; --- a/drivers/mfd/htc-egpio.c 2008-06-09 20:02:34.000000000 -0700 +++ b/drivers/mfd/htc-egpio.c 2008-06-09 20:02:43.000000000 -0700 @@ -318,6 +318,8 @@ static int __init egpio_probe(struct plaei->chip[i].dev = &(pdev->dev);chip = &(ei->chip[i].chip);chip->label = "htc-egpio"; + chip->dev = &pdev->dev; + chip->owner = THIS_MODULE;chip->get = egpio_get;chip->set = egpio_set;chip->direction_input = egpio_direction_input; --- a/include/asm-generic/gpio.h 2008-06-09 20:02:34.000000000 -0700 +++ b/include/asm-generic/gpio.h 2008-06-09 20:02:43.000000000 -0700 @@ -32,6 +32,8 @@ struct module;/*** struct gpio_chip - abstract a GPIO controller* @label: for diagnostics + * @dev: optional device providing the GPIOs + * @owner: helps prevent removal of modules exporting active GPIOs* @direction_input: configures signal "offset" as input, or returns error* @get: returns value for signal "offset"; for output signals this* returns either the value actually sensed, or zero @@ -59,6 +61,7 @@ struct module;*/struct gpio_chip {char *label; + struct device *dev;struct module *owner;int (*direction_input)(struct gpio_chip *chip, @@ -74,6 +77,7 @@ struct gpio_chip {int base;u16 ngpio;unsigned can_sleep:1; + unsigned exported:1;};extern const char *gpiochip_is_requested(struct gpio_chip *chip, @@ -108,7 +112,18 @@ extern void __gpio_set_value(unsigned gpextern int __gpio_cansleep(unsigned gpio);-#else +#ifdef CONFIG_GPIO_SYSFS + +/* + * A sysfs interface can be exported by individual drivers if they want, + * but more typically is configured entirely from userspace. + */ +extern int gpio_export(unsigned gpio, bool direction_may_change); +extern void gpio_unexport(unsigned gpio); + +#endif /* CONFIG_GPIO_SYSFS */ + +#else /* !CONFIG_HAVE_GPIO_LIB */static inline int gpio_is_valid(int number){ @@ -137,6 +152,20 @@ static inline void gpio_set_value_canslegpio_set_value(gpio, value);}-#endif +#endif /* !CONFIG_HAVE_GPIO_LIB */ + +#ifndef CONFIG_GPIO_SYSFS + +/* sysfs support is only available with gpiolib, where it's optional */ + +static inline int gpio_export(unsigned gpio, bool direction_may_change) +{ + return -ENOSYS; +} + +static inline void gpio_unexport(unsigned gpio) +{ +} +#endif /* CONFIG_GPIO_SYSFS */#endif /* _ASM_GENERIC_GPIO_H */ --- a/include/linux/gpio.h 2008-06-09 20:02:34.000000000 -0700 +++ b/include/linux/gpio.h 2008-06-09 20:02:43.000000000 -0700 @@ -79,6 +79,19 @@ static inline void gpio_set_value_cansleWARN_ON(1);}+static inline int gpio_export(unsigned gpio, bool direction_may_change) +{ + /* GPIO can never have been requested or set as {in,out}put */ + WARN_ON(1); + return -EINVAL; +} + +static inline void gpio_unexport(unsigned gpio) +{ + /* GPIO can never have been exported */ + WARN_ON(1); +} +static inline int gpio_to_irq(unsigned gpio){/* GPIO can never have been requested or set as input */