gpiolib: don't allow setting values on input lines
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Tue, 11 Mar 2025 14:19:51 +0000 (15:19 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 7 Apr 2025 07:00:48 +0000 (09:00 +0200)
Some drivers as well as the character device and sysfs code check
whether the line actually is in output mode before allowing the user to
set a value.

However, GPIO value setters now return integer values and can indicate
failures. This allows us to move these checks into the core code.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20250311-gpio-set-check-output-v1-1-d971bca9e6fa@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/gpiolib-cdev.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c

index 107d75558b5a80db138c361d2a56bcebed5cd20a..e6a289fa0f8fd5edb3b180ef668ac8777e3dac86 100644 (file)
@@ -1366,9 +1366,6 @@ static long linereq_set_values(struct linereq *lr, void __user *ip)
        /* scan requested lines to determine the subset to be set */
        for (num_set = 0, i = 0; i < lr->num_lines; i++) {
                if (lv.mask & BIT_ULL(i)) {
-                       /* setting inputs is not allowed */
-                       if (!test_bit(FLAG_IS_OUT, &lr->lines[i].desc->flags))
-                               return -EPERM;
                        /* add to compacted values */
                        if (lv.bits & BIT_ULL(i))
                                __set_bit(num_set, vals);
index 1acfa43bf1ab02e82b1bc1cfe7f49606651e1907..4a3aa09dad9d54dc77f28d596723fd5546cb3ae8 100644 (file)
@@ -134,17 +134,15 @@ static ssize_t value_store(struct device *dev,
        long value;
 
        status = kstrtol(buf, 0, &value);
+       if (status)
+               return status;
 
        guard(mutex)(&data->mutex);
 
-       if (!test_bit(FLAG_IS_OUT, &desc->flags))
-               return -EPERM;
-
+       status = gpiod_set_value_cansleep(desc, value);
        if (status)
                return status;
 
-       gpiod_set_value_cansleep(desc, value);
-
        return size;
 }
 static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store);
index b8197502a5ac598ce3c88c1e9a1d6c0b74516aac..8252a671d7208105a315bdc914acb092d5f95e79 100644 (file)
@@ -3593,6 +3593,9 @@ static int gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value)
 
 static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
 {
+       if (unlikely(!test_bit(FLAG_IS_OUT, &desc->flags)))
+               return -EPERM;
+
        CLASS(gpio_chip_guard, guard)(desc);
        if (!guard.gc)
                return -ENODEV;
@@ -3664,6 +3667,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
                if (!can_sleep)
                        WARN_ON(array_info->gdev->can_sleep);
 
+               for (i = 0; i < array_size; i++) {
+                       if (unlikely(!test_bit(FLAG_IS_OUT,
+                                              &desc_array[i]->flags)))
+                               return -EPERM;
+               }
+
                guard(srcu)(&array_info->gdev->srcu);
                gc = srcu_dereference(array_info->gdev->chip,
                                      &array_info->gdev->srcu);
@@ -3723,6 +3732,9 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
                        int hwgpio = gpio_chip_hwgpio(desc);
                        int value = test_bit(i, value_bitmap);
 
+                       if (unlikely(!test_bit(FLAG_IS_OUT, &desc->flags)))
+                               return -EPERM;
+
                        /*
                         * Pins applicable for fast input but not for
                         * fast output processing may have been already