Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpiolib: cdev: Ignore reconfiguration without direction

linereq_set_config() behaves badly when direction is not set.
The configuration validation is borrowed from linereq_create(), where,
to verify the intent of the user, the direction must be set to in order to
effect a change to the electrical configuration of a line. But, when
applied to reconfiguration, that validation does not allow for the unset
direction case, making it possible to clear flags set previously without
specifying the line direction.

Adding to the inconsistency, those changes are not immediately applied by
linereq_set_config(), but will take effect when the line value is next get
or set.

For example, by requesting a configuration with no flags set, an output
line with GPIO_V2_LINE_FLAG_ACTIVE_LOW and GPIO_V2_LINE_FLAG_OPEN_DRAIN
set could have those flags cleared, inverting the sense of the line and
changing the line drive to push-pull on the next line value set.

Skip the reconfiguration of lines for which the direction is not set, and
only reconfigure the lines for which direction is set.

Fixes: a54756cb24ea ("gpiolib: cdev: support GPIO_V2_LINE_SET_CONFIG_IOCTL")
Signed-off-by: Kent Gibson <warthog618@gmail.com>
Link: https://lore.kernel.org/r/20240626052925.174272-3-warthog618@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

authored by

Kent Gibson and committed by
Bartosz Golaszewski
b4403963 9919cce6

+7 -5
+7 -5
drivers/gpio/gpiolib-cdev.c
··· 1534 1534 line = &lr->lines[i]; 1535 1535 desc = lr->lines[i].desc; 1536 1536 flags = gpio_v2_line_config_flags(&lc, i); 1537 + /* 1538 + * Lines not explicitly reconfigured as input or output 1539 + * are left unchanged. 1540 + */ 1541 + if (!(flags & GPIO_V2_LINE_DIRECTION_FLAGS)) 1542 + continue; 1537 1543 gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags); 1538 1544 edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS; 1539 - /* 1540 - * Lines have to be requested explicitly for input 1541 - * or output, else the line will be treated "as is". 1542 - */ 1543 1545 if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { 1544 1546 int val = gpio_v2_line_config_output_value(&lc, i); 1545 1547 ··· 1549 1547 ret = gpiod_direction_output(desc, val); 1550 1548 if (ret) 1551 1549 return ret; 1552 - } else if (flags & GPIO_V2_LINE_FLAG_INPUT) { 1550 + } else { 1553 1551 ret = gpiod_direction_input(desc); 1554 1552 if (ret) 1555 1553 return ret;