X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fgpio%2Fgpiolib.c;h=51e5ee8912ca1e10b9e882dabf6e9e172dafeda6;hb=a10ff58e82582898690f3f2328ef5ef772c2a0b1;hp=503104af0ed250e0ac4967ba58cffa8ddba0c46a;hpb=d0411190377b3276a1fd573e6ef3802acbb899ea;p=pandora-kernel.git diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 503104af0ed2..51e5ee8912ca 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -58,6 +58,7 @@ struct gpio_desc { #define FLAG_TRIG_FALL 5 /* trigger on falling edge */ #define FLAG_TRIG_RISE 6 /* trigger on rising edge */ #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ +#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -317,7 +318,7 @@ static ssize_t gpio_value_store(struct device *dev, return status; } -static const DEVICE_ATTR(value, 0644, +static DEVICE_ATTR(value, 0644, gpio_value_show, gpio_value_store); static irqreturn_t gpio_sysfs_irq(int irq, void *priv) @@ -540,17 +541,47 @@ static ssize_t gpio_active_low_store(struct device *dev, return status ? : size; } -static const DEVICE_ATTR(active_low, 0644, +static DEVICE_ATTR(active_low, 0644, gpio_active_low_show, gpio_active_low_store); -static const struct attribute *gpio_attrs[] = { +static mode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr, + int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct gpio_desc *desc = dev_get_drvdata(dev); + unsigned gpio = desc - gpio_desc; + mode_t mode = attr->mode; + bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags); + + if (attr == &dev_attr_direction.attr) { + if (!show_direction) + mode = 0; + } else if (attr == &dev_attr_edge.attr) { + if (gpio_to_irq(gpio) < 0) + mode = 0; + if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags)) + mode = 0; + } + + return mode; +} + +static struct attribute *gpio_attrs[] = { + &dev_attr_direction.attr, + &dev_attr_edge.attr, &dev_attr_value.attr, &dev_attr_active_low.attr, NULL, }; -static const struct attribute_group gpio_attr_group = { - .attrs = (struct attribute **) gpio_attrs, +static const struct attribute_group gpio_group = { + .attrs = gpio_attrs, + .is_visible = gpio_is_visible, +}; + +static const struct attribute_group *gpio_groups[] = { + &gpio_group, + NULL }; /* @@ -587,16 +618,13 @@ static ssize_t chip_ngpio_show(struct device *dev, } static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); -static const struct attribute *gpiochip_attrs[] = { +static 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, -}; +ATTRIBUTE_GROUPS(gpiochip); /* * /sys/class/gpio/export ... write-only @@ -700,8 +728,9 @@ int gpio_export(unsigned gpio, bool direction_may_change) { unsigned long flags; struct gpio_desc *desc; - int status = -EINVAL; + int status; const char *ioname = NULL; + struct device *dev; /* can't export until sysfs is available ... */ if (!gpio_class.p) { @@ -709,59 +738,50 @@ int gpio_export(unsigned gpio, bool direction_may_change) return -ENOENT; } - if (!gpio_is_valid(gpio)) - goto done; + if (!gpio_is_valid(gpio)) { + pr_debug("%s: gpio %d is not valid\n", __func__, gpio); + return -EINVAL; + } 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; + if (!test_bit(FLAG_REQUESTED, &desc->flags) || + test_bit(FLAG_EXPORT, &desc->flags)) { + spin_unlock_irqrestore(&gpio_lock, flags); + pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", + __func__, gpio, + test_bit(FLAG_REQUESTED, &desc->flags), + test_bit(FLAG_EXPORT, &desc->flags)); + return -EPERM; + } + + if (desc->chip->direction_input && desc->chip->direction_output && + direction_may_change) { + set_bit(FLAG_SYSFS_DIR, &desc->flags); } + spin_unlock_irqrestore(&gpio_lock, flags); if (desc->chip->names && desc->chip->names[gpio - desc->chip->base]) ioname = desc->chip->names[gpio - desc->chip->base]; - if (status == 0) { - struct device *dev; - - dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%u", gpio); - if (!IS_ERR(dev)) { - status = sysfs_create_group(&dev->kobj, - &gpio_attr_group); - - if (!status && direction_may_change) - status = device_create_file(dev, - &dev_attr_direction); - - if (!status && gpio_to_irq(gpio) >= 0 - && (direction_may_change - || !test_bit(FLAG_IS_OUT, - &desc->flags))) - status = device_create_file(dev, - &dev_attr_edge); - - if (status != 0) - device_unregister(dev); - } else - status = PTR_ERR(dev); - if (status == 0) - set_bit(FLAG_EXPORT, &desc->flags); + dev = device_create_with_groups(&gpio_class, desc->chip->dev, + MKDEV(0, 0), desc, gpio_groups, + ioname ? ioname : "gpio%u", gpio); + if (IS_ERR(dev)) { + status = PTR_ERR(dev); + goto fail_unlock; } + set_bit(FLAG_EXPORT, &desc->flags); mutex_unlock(&sysfs_lock); + return 0; -done: - if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); - +fail_unlock: + mutex_unlock(&sysfs_lock); + pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); return status; } EXPORT_SYMBOL_GPL(gpio_export); @@ -873,6 +893,7 @@ void gpio_unexport(unsigned gpio) { struct gpio_desc *desc; int status = 0; + struct device *dev = NULL; if (!gpio_is_valid(gpio)) { status = -EINVAL; @@ -884,19 +905,21 @@ void gpio_unexport(unsigned gpio) desc = &gpio_desc[gpio]; if (test_bit(FLAG_EXPORT, &desc->flags)) { - struct device *dev = NULL; dev = class_find_device(&gpio_class, NULL, desc, match_export); if (dev) { gpio_setup_irq(desc, dev, 0); + clear_bit(FLAG_SYSFS_DIR, &desc->flags); clear_bit(FLAG_EXPORT, &desc->flags); - put_device(dev); - device_unregister(dev); } else status = -ENODEV; } mutex_unlock(&sysfs_lock); + if (dev) { + device_unregister(dev); + put_device(dev); + } done: if (status) pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); @@ -918,13 +941,13 @@ static int gpiochip_export(struct gpio_chip *chip) /* use chip->base for the ID; it's already known to be unique */ mutex_lock(&sysfs_lock); - dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip, - "gpiochip%d", chip->base); - if (!IS_ERR(dev)) { - status = sysfs_create_group(&dev->kobj, - &gpiochip_attr_group); - } else + dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0), + chip, gpiochip_groups, + "gpiochip%d", chip->base); + if (IS_ERR(dev)) status = PTR_ERR(dev); + else + status = 0; chip->exported = (status == 0); mutex_unlock(&sysfs_lock);