[patch 2.6.26-rc5] gpio: sysfs interface (updated) - Kernel

This is a discussion on [patch 2.6.26-rc5] gpio: sysfs interface (updated) - Kernel ; Subject: gpio: sysfs interface From: David Brownell 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 ...

+ Reply to Thread
Results 1 to 9 of 9

Thread: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

  1. [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    Subject: gpio: sysfs interface
    From: David Brownell

    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 above

    The 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 GPIO
    providers initialize that, sysfs gpio class devices become children of
    that device instead of being "virtual" devices.

    * The (few) gpio_chip providers which have such a device node have
    been 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 now
    flagged appropriately when the chip is registered.

    Based on previous patches, and discussion both on and off LKML.

    Signed-off-by: David Brownell
    ---
    Changes since previous version: trivial fix for locking issue from
    http://marc.info/?l=linux-kernel&m=121249999315314&w=2

    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, as
    a 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 it
    easier 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 file
    will be found there. That will list all the controllers registered through
    @@ -439,4 +436,120 @@ becomes available. That may mean the de
    calls for that GPIO can work. One way to address such dependencies is for
    such gpio_chip controllers to provide setup() and teardown() callbacks to
    board 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;
    +#endif
    bank->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 platf
    pio->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_GPIO
    slower. The diagnostics help catch the type of setup errors
    that 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 order

    comment "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
    #include
    #include
    -
    -#include
    +#include
    +#include
    +#include
    +#include
    +#include


    /* 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_FS
    const 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
    -#include
    -
    -
    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_dev
    mcp->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 pc
    gc->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_clie

    gpio->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_cli
    tps->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 pla
    ei->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 gp
    extern 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_cansle
    gpio_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_cansle
    WARN_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 */
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. Re: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    On Thu, 12 Jun 2008 11:53:36 -0700
    David Brownell wrote:

    > This adds a simple sysfs interface for GPIOs.


    device_create_drvdata() has magically vanished from today's linux-next,
    so this code doesn't compile any more.

    This:

    --- a/drivers/gpio/gpiolib.c~gpio-sysfs-interface-updated-gpio-linux-next-fixes-for-sysfs-support-fix
    +++ a/drivers/gpio/gpiolib.c
    @@ -453,8 +453,8 @@ int gpio_export(unsigned gpio, bool dire
    if (status == 0) {
    struct device *dev;

    - dev = device_create_drvdata(&gpio_class, desc->chip->dev, 0,
    - desc, "gpio%d", gpio);
    + dev = device_create(&gpio_class, desc->chip->dev, 0, desc,
    + "gpio%d", gpio);
    if (dev) {
    if (direction_may_change)
    status = sysfs_create_group(&dev->kobj,
    @@ -537,8 +537,8 @@ static int gpiochip_export(struct gpio_c

    /* use chip->base for the ID; it's already known to be unique */
    mutex_lock(&sysfs_lock);
    - dev = device_create_drvdata(&gpio_class, chip->dev, 0, chip,
    - "gpiochip%d", chip->base);
    + dev = device_create(&gpio_class, chip->dev, 0, chip, "gpiochip%d",
    + chip->base);
    if (dev) {
    status = sysfs_create_group(&dev->kobj,
    &gpiochip_attr_group);
    _

    seems to compile.
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. Re: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    On Tue, Jul 22, 2008 at 04:27:51PM -0700, Andrew Morton wrote:
    > On Thu, 12 Jun 2008 11:53:36 -0700
    > David Brownell wrote:
    >
    > > This adds a simple sysfs interface for GPIOs.

    >
    > device_create_drvdata() has magically vanished from today's linux-next,
    > so this code doesn't compile any more.
    >
    > This:
    >
    > --- a/drivers/gpio/gpiolib.c~gpio-sysfs-interface-updated-gpio-linux-next-fixes-for-sysfs-support-fix
    > +++ a/drivers/gpio/gpiolib.c
    > @@ -453,8 +453,8 @@ int gpio_export(unsigned gpio, bool dire
    > if (status == 0) {
    > struct device *dev;
    >
    > - dev = device_create_drvdata(&gpio_class, desc->chip->dev, 0,
    > - desc, "gpio%d", gpio);
    > + dev = device_create(&gpio_class, desc->chip->dev, 0, desc,
    > + "gpio%d", gpio);


    Should be NULL instead of 0 there, otherwise sparse will complain.


    > if (dev) {
    > if (direction_may_change)
    > status = sysfs_create_group(&dev->kobj,
    > @@ -537,8 +537,8 @@ static int gpiochip_export(struct gpio_c
    >
    > /* use chip->base for the ID; it's already known to be unique */
    > mutex_lock(&sysfs_lock);
    > - dev = device_create_drvdata(&gpio_class, chip->dev, 0, chip,
    > - "gpiochip%d", chip->base);
    > + dev = device_create(&gpio_class, chip->dev, 0, chip, "gpiochip%d",
    > + chip->base);


    Same here.

    thanks,

    greg k-h
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. Re: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    On Tue, 22 Jul 2008 16:28:24 -0700
    Greg KH wrote:

    > On Tue, Jul 22, 2008 at 04:27:51PM -0700, Andrew Morton wrote:
    > > On Thu, 12 Jun 2008 11:53:36 -0700
    > > David Brownell wrote:
    > >
    > > > This adds a simple sysfs interface for GPIOs.

    > >
    > > device_create_drvdata() has magically vanished from today's linux-next,
    > > so this code doesn't compile any more.
    > >
    > > This:
    > >
    > > --- a/drivers/gpio/gpiolib.c~gpio-sysfs-interface-updated-gpio-linux-next-fixes-for-sysfs-support-fix
    > > +++ a/drivers/gpio/gpiolib.c
    > > @@ -453,8 +453,8 @@ int gpio_export(unsigned gpio, bool dire
    > > if (status == 0) {
    > > struct device *dev;
    > >
    > > - dev = device_create_drvdata(&gpio_class, desc->chip->dev, 0,
    > > - desc, "gpio%d", gpio);
    > > + dev = device_create(&gpio_class, desc->chip->dev, 0, desc,
    > > + "gpio%d", gpio);

    >
    > Should be NULL instead of 0 there, otherwise sparse will complain.
    >
    >
    > > if (dev) {
    > > if (direction_may_change)
    > > status = sysfs_create_group(&dev->kobj,
    > > @@ -537,8 +537,8 @@ static int gpiochip_export(struct gpio_c
    > >
    > > /* use chip->base for the ID; it's already known to be unique */
    > > mutex_lock(&sysfs_lock);
    > > - dev = device_create_drvdata(&gpio_class, chip->dev, 0, chip,
    > > - "gpiochip%d", chip->base);
    > > + dev = device_create(&gpio_class, chip->dev, 0, chip, "gpiochip%d",
    > > + chip->base);

    >
    > Same here.
    >


    And is this change safe to merge into mainline? Or should it wait
    until device_create_drvdata-removal and any associated stuff has
    merged?

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. Re: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    On Tue, Jul 22, 2008 at 04:39:24PM -0700, Andrew Morton wrote:
    > On Tue, 22 Jul 2008 16:28:24 -0700
    > Greg KH wrote:
    >
    > > On Tue, Jul 22, 2008 at 04:27:51PM -0700, Andrew Morton wrote:
    > > > On Thu, 12 Jun 2008 11:53:36 -0700
    > > > David Brownell wrote:
    > > >
    > > > > This adds a simple sysfs interface for GPIOs.
    > > >
    > > > device_create_drvdata() has magically vanished from today's linux-next,
    > > > so this code doesn't compile any more.
    > > >
    > > > This:
    > > >
    > > > --- a/drivers/gpio/gpiolib.c~gpio-sysfs-interface-updated-gpio-linux-next-fixes-for-sysfs-support-fix
    > > > +++ a/drivers/gpio/gpiolib.c
    > > > @@ -453,8 +453,8 @@ int gpio_export(unsigned gpio, bool dire
    > > > if (status == 0) {
    > > > struct device *dev;
    > > >
    > > > - dev = device_create_drvdata(&gpio_class, desc->chip->dev, 0,
    > > > - desc, "gpio%d", gpio);
    > > > + dev = device_create(&gpio_class, desc->chip->dev, 0, desc,
    > > > + "gpio%d", gpio);

    > >
    > > Should be NULL instead of 0 there, otherwise sparse will complain.
    > >
    > >
    > > > if (dev) {
    > > > if (direction_may_change)
    > > > status = sysfs_create_group(&dev->kobj,
    > > > @@ -537,8 +537,8 @@ static int gpiochip_export(struct gpio_c
    > > >
    > > > /* use chip->base for the ID; it's already known to be unique */
    > > > mutex_lock(&sysfs_lock);
    > > > - dev = device_create_drvdata(&gpio_class, chip->dev, 0, chip,
    > > > - "gpiochip%d", chip->base);
    > > > + dev = device_create(&gpio_class, chip->dev, 0, chip, "gpiochip%d",
    > > > + chip->base);

    > >
    > > Same here.
    > >

    >
    > And is this change safe to merge into mainline? Or should it wait
    > until device_create_drvdata-removal and any associated stuff has
    > merged?


    This is safe to go to mainline now, device_create() and
    device_create_drvdata() are both there (they are the same thing right
    now), so it is fine.

    after -rc1 is out, device_create_drvdata() is going to go away.

    thanks,

    greg k-h
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. Re: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    On Tue, 22 Jul 2008 16:28:24 -0700
    Greg KH wrote:

    > On Tue, Jul 22, 2008 at 04:27:51PM -0700, Andrew Morton wrote:
    > > On Thu, 12 Jun 2008 11:53:36 -0700
    > > David Brownell wrote:
    > >
    > > > This adds a simple sysfs interface for GPIOs.

    > >
    > > device_create_drvdata() has magically vanished from today's linux-next,
    > > so this code doesn't compile any more.
    > >
    > > This:
    > >
    > > --- a/drivers/gpio/gpiolib.c~gpio-sysfs-interface-updated-gpio-linux-next-fixes-for-sysfs-support-fix
    > > +++ a/drivers/gpio/gpiolib.c
    > > @@ -453,8 +453,8 @@ int gpio_export(unsigned gpio, bool dire
    > > if (status == 0) {
    > > struct device *dev;
    > >
    > > - dev = device_create_drvdata(&gpio_class, desc->chip->dev, 0,
    > > - desc, "gpio%d", gpio);
    > > + dev = device_create(&gpio_class, desc->chip->dev, 0, desc,
    > > + "gpio%d", gpio);

    >
    > Should be NULL instead of 0 there, otherwise sparse will complain.


    The third arg to device_create is a dev_t, so 0 is correct

    Confused.
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. Re: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    On Tue, Jul 22, 2008 at 04:50:56PM -0700, Andrew Morton wrote:
    > On Tue, 22 Jul 2008 16:28:24 -0700
    > Greg KH wrote:
    >
    > > On Tue, Jul 22, 2008 at 04:27:51PM -0700, Andrew Morton wrote:
    > > > On Thu, 12 Jun 2008 11:53:36 -0700
    > > > David Brownell wrote:
    > > >
    > > > > This adds a simple sysfs interface for GPIOs.
    > > >
    > > > device_create_drvdata() has magically vanished from today's linux-next,
    > > > so this code doesn't compile any more.
    > > >
    > > > This:
    > > >
    > > > --- a/drivers/gpio/gpiolib.c~gpio-sysfs-interface-updated-gpio-linux-next-fixes-for-sysfs-support-fix
    > > > +++ a/drivers/gpio/gpiolib.c
    > > > @@ -453,8 +453,8 @@ int gpio_export(unsigned gpio, bool dire
    > > > if (status == 0) {
    > > > struct device *dev;
    > > >
    > > > - dev = device_create_drvdata(&gpio_class, desc->chip->dev, 0,
    > > > - desc, "gpio%d", gpio);
    > > > + dev = device_create(&gpio_class, desc->chip->dev, 0, desc,
    > > > + "gpio%d", gpio);

    > >
    > > Should be NULL instead of 0 there, otherwise sparse will complain.

    >
    > The third arg to device_create is a dev_t, so 0 is correct


    Bah, sorry about that, MK_DEV(0,0) would be safer

    thanks,

    greg k-h
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. Re: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    On Tuesday 22 July 2008, Greg KH wrote:
    >
    > > device_create_drvdata() has magically vanished from today's linux-next,
    > > so this code doesn't compile any more.
    > >
    > > This:
    > >
    > > @@ -453,8 +453,8 @@ int gpio_export(unsigned gpio, bool dire
    > > ******if (status == 0) {
    > > **************struct device****dev;
    > > *
    > > -*************dev = device_create_drvdata(&gpio_class, desc->chip->dev, 0,
    > > -*****************************desc, "gpio%d", gpio);
    > > +*************dev = device_create(&gpio_class, desc->chip->dev, 0, desc,
    > > +*************************************"gpio%d", gpio);

    >
    > Should be NULL instead of 0 there, otherwise sparse will complain.


    The zero is a dev_t ... ?? (As Andrew just noted too.)

    "desc" might need to be NULL, but it's a valid pointer
    (for driver_data). I think this was a mental off-by-one...





    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. Re: [patch 2.6.26-rc5] gpio: sysfs interface (updated)

    On Tue, Jul 22, 2008 at 05:01:36PM -0700, David Brownell wrote:
    > On Tuesday 22 July 2008, Greg KH wrote:
    > >
    > > > device_create_drvdata() has magically vanished from today's linux-next,
    > > > so this code doesn't compile any more.
    > > >
    > > > This:
    > > >
    > > > @@ -453,8 +453,8 @@ int gpio_export(unsigned gpio, bool dire
    > > > ******if (status == 0) {
    > > > **************struct device****dev;
    > > > *
    > > > -*************dev = device_create_drvdata(&gpio_class, desc->chip->dev, 0,
    > > > -*****************************desc, "gpio%d", gpio);
    > > > +*************dev = device_create(&gpio_class, desc->chip->dev, 0, desc,
    > > > +*************************************"gpio%d", gpio);

    > >
    > > Should be NULL instead of 0 there, otherwise sparse will complain.

    >
    > The zero is a dev_t ... ?? (As Andrew just noted too.)
    >
    > "desc" might need to be NULL, but it's a valid pointer
    > (for driver_data). I think this was a mental off-by-one...


    Yes, you are correct, my mistake.

    greg k-h
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread