| From 85b03b3033fd4eba82665b3b9902c095a08cc52f Mon Sep 17 00:00:00 2001 |
| From: Johan Hovold <johan@kernel.org> |
| Date: Sun, 3 Jul 2016 18:32:05 +0200 |
| Subject: Revert "gpiolib: Split GPIO flags parsing and GPIO configuration" |
| |
| From: Johan Hovold <johan@kernel.org> |
| |
| commit 85b03b3033fd4eba82665b3b9902c095a08cc52f upstream. |
| |
| This reverts commit 923b93e451db876d1479d3e4458fce14fec31d1c. |
| |
| Make sure consumers do not overwrite gpio flags for pins that have |
| already been claimed. |
| |
| While adding support for gpio drivers to refuse a request using |
| unsupported flags, the order of when the requested flag was checked and |
| the new flags were applied was reversed to that consumers could |
| overwrite flags for already requested gpios. |
| |
| This not only affects device-tree setups where two drivers could request |
| the same gpio using conflicting configurations, but also allowed user |
| space to clear gpio flags for already claimed pins simply by attempting |
| to export them through the sysfs interface. By for example clearing the |
| FLAG_ACTIVE_LOW flag this way, user space could effectively change the |
| polarity of a signal. |
| |
| Reverting this change obviously prevents gpio drivers from doing sanity |
| checks on the flags in their request callbacks. Fortunately only one |
| recently added driver (gpio-tps65218 in v4.6) appears to do this, and a |
| follow up patch could restore this functionality through a different |
| interface. |
| |
| Signed-off-by: Johan Hovold <johan@kernel.org> |
| Signed-off-by: Linus Walleij <linus.walleij@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpio/gpiolib-legacy.c | 8 +++--- |
| drivers/gpio/gpiolib.c | 52 ++++++++++++------------------------------ |
| 2 files changed, 20 insertions(+), 40 deletions(-) |
| |
| --- a/drivers/gpio/gpiolib-legacy.c |
| +++ b/drivers/gpio/gpiolib-legacy.c |
| @@ -28,6 +28,10 @@ int gpio_request_one(unsigned gpio, unsi |
| if (!desc && gpio_is_valid(gpio)) |
| return -EPROBE_DEFER; |
| |
| + err = gpiod_request(desc, label); |
| + if (err) |
| + return err; |
| + |
| if (flags & GPIOF_OPEN_DRAIN) |
| set_bit(FLAG_OPEN_DRAIN, &desc->flags); |
| |
| @@ -37,10 +41,6 @@ int gpio_request_one(unsigned gpio, unsi |
| if (flags & GPIOF_ACTIVE_LOW) |
| set_bit(FLAG_ACTIVE_LOW, &desc->flags); |
| |
| - err = gpiod_request(desc, label); |
| - if (err) |
| - return err; |
| - |
| if (flags & GPIOF_DIR_IN) |
| err = gpiod_direction_input(desc); |
| else |
| --- a/drivers/gpio/gpiolib.c |
| +++ b/drivers/gpio/gpiolib.c |
| @@ -927,14 +927,6 @@ static int __gpiod_request(struct gpio_d |
| spin_lock_irqsave(&gpio_lock, flags); |
| } |
| done: |
| - if (status < 0) { |
| - /* Clear flags that might have been set by the caller before |
| - * requesting the GPIO. |
| - */ |
| - clear_bit(FLAG_ACTIVE_LOW, &desc->flags); |
| - clear_bit(FLAG_OPEN_DRAIN, &desc->flags); |
| - clear_bit(FLAG_OPEN_SOURCE, &desc->flags); |
| - } |
| spin_unlock_irqrestore(&gpio_lock, flags); |
| return status; |
| } |
| @@ -2062,28 +2054,13 @@ struct gpio_desc *__must_check gpiod_get |
| } |
| EXPORT_SYMBOL_GPL(gpiod_get_optional); |
| |
| -/** |
| - * gpiod_parse_flags - helper function to parse GPIO lookup flags |
| - * @desc: gpio to be setup |
| - * @lflags: gpio_lookup_flags - returned from of_find_gpio() or |
| - * of_get_gpio_hog() |
| - * |
| - * Set the GPIO descriptor flags based on the given GPIO lookup flags. |
| - */ |
| -static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags) |
| -{ |
| - if (lflags & GPIO_ACTIVE_LOW) |
| - set_bit(FLAG_ACTIVE_LOW, &desc->flags); |
| - if (lflags & GPIO_OPEN_DRAIN) |
| - set_bit(FLAG_OPEN_DRAIN, &desc->flags); |
| - if (lflags & GPIO_OPEN_SOURCE) |
| - set_bit(FLAG_OPEN_SOURCE, &desc->flags); |
| -} |
| |
| /** |
| * gpiod_configure_flags - helper function to configure a given GPIO |
| * @desc: gpio whose value will be assigned |
| * @con_id: function within the GPIO consumer |
| + * @lflags: gpio_lookup_flags - returned from of_find_gpio() or |
| + * of_get_gpio_hog() |
| * @dflags: gpiod_flags - optional GPIO initialization flags |
| * |
| * Return 0 on success, -ENOENT if no GPIO has been assigned to the |
| @@ -2091,10 +2068,17 @@ static void gpiod_parse_flags(struct gpi |
| * occurred while trying to acquire the GPIO. |
| */ |
| static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, |
| - enum gpiod_flags dflags) |
| + unsigned long lflags, enum gpiod_flags dflags) |
| { |
| int status; |
| |
| + if (lflags & GPIO_ACTIVE_LOW) |
| + set_bit(FLAG_ACTIVE_LOW, &desc->flags); |
| + if (lflags & GPIO_OPEN_DRAIN) |
| + set_bit(FLAG_OPEN_DRAIN, &desc->flags); |
| + if (lflags & GPIO_OPEN_SOURCE) |
| + set_bit(FLAG_OPEN_SOURCE, &desc->flags); |
| + |
| /* No particular flag request, return here... */ |
| if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { |
| pr_debug("no flags found for %s\n", con_id); |
| @@ -2161,13 +2145,11 @@ struct gpio_desc *__must_check gpiod_get |
| return desc; |
| } |
| |
| - gpiod_parse_flags(desc, lookupflags); |
| - |
| status = gpiod_request(desc, con_id); |
| if (status < 0) |
| return ERR_PTR(status); |
| |
| - status = gpiod_configure_flags(desc, con_id, flags); |
| + status = gpiod_configure_flags(desc, con_id, lookupflags, flags); |
| if (status < 0) { |
| dev_dbg(dev, "setup of GPIO %s failed\n", con_id); |
| gpiod_put(desc); |
| @@ -2223,6 +2205,10 @@ struct gpio_desc *fwnode_get_named_gpiod |
| if (IS_ERR(desc)) |
| return desc; |
| |
| + ret = gpiod_request(desc, NULL); |
| + if (ret) |
| + return ERR_PTR(ret); |
| + |
| if (active_low) |
| set_bit(FLAG_ACTIVE_LOW, &desc->flags); |
| |
| @@ -2233,10 +2219,6 @@ struct gpio_desc *fwnode_get_named_gpiod |
| set_bit(FLAG_OPEN_SOURCE, &desc->flags); |
| } |
| |
| - ret = gpiod_request(desc, NULL); |
| - if (ret) |
| - return ERR_PTR(ret); |
| - |
| return desc; |
| } |
| EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); |
| @@ -2289,8 +2271,6 @@ int gpiod_hog(struct gpio_desc *desc, co |
| chip = gpiod_to_chip(desc); |
| hwnum = gpio_chip_hwgpio(desc); |
| |
| - gpiod_parse_flags(desc, lflags); |
| - |
| local_desc = gpiochip_request_own_desc(chip, hwnum, name); |
| if (IS_ERR(local_desc)) { |
| pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n", |
| @@ -2298,7 +2278,7 @@ int gpiod_hog(struct gpio_desc *desc, co |
| return PTR_ERR(local_desc); |
| } |
| |
| - status = gpiod_configure_flags(desc, name, dflags); |
| + status = gpiod_configure_flags(desc, name, lflags, dflags); |
| if (status < 0) { |
| pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n", |
| name, chip->label, hwnum); |