当前位置: 代码迷 >> 综合 >> gpio: sysfs interface
  详细解决方案

gpio: sysfs interface

热度:40   发布时间:2023-12-21 21:28:20.0
http://blog.csdn.net/yi412/article/details/20845789
 

gpio: sysfs interface

分类: linux系统学习   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 */
  相关解决方案