Add support for the GPIO_V2_LINE_SET_VALUES_IOCTL. Signed-off-by: Kent Gibson <warthog618@xxxxxxxxx> --- drivers/gpio/gpiolib-cdev.c | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index d34dad50a048..2f5cc835133c 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -811,6 +811,71 @@ static long line_get_values(struct line *line, void __user *ip) return 0; } +static long line_set_values_locked(struct line *line, + struct gpio_v2_line_values *lv) +{ + DECLARE_BITMAP(vals, GPIO_V2_LINES_MAX); + struct gpio_desc **descs; + int ret, i, didx, num_set = 0; + + bitmap_zero(vals, GPIO_V2_LINES_MAX); + for (i = 0; i < line->num_descs; i++) { + if (lv->mask & BIT_ULL(i)) { + if (!test_bit(FLAG_IS_OUT, &line->descs[i]->flags)) + return -EPERM; + if (lv->bits & BIT_ULL(i)) + __set_bit(num_set, vals); + num_set++; + } + } + if (num_set == 0) + return -EINVAL; + + if (num_set == line->num_descs) + /* Reuse the array setting function */ + return gpiod_set_array_value_complex(false, + true, + line->num_descs, + line->descs, + NULL, + vals); + + /* build compacted desc array and values */ + descs = kmalloc_array(num_set, sizeof(*descs), GFP_KERNEL); + for (didx = 0, i = 0; i < line->num_descs; i++) { + if (lv->mask & BIT_ULL(i)) { + descs[didx] = line->descs[i]; + didx++; + } + } + ret = gpiod_set_array_value_complex(false, + true, + num_set, + descs, + NULL, + vals); + + kfree(descs); + return ret; +} + +static long line_set_values(struct line *line, void __user *ip) +{ + struct gpio_v2_line_values lv; + int ret; + + if (copy_from_user(&lv, ip, sizeof(lv))) + return -EFAULT; + + mutex_lock(&line->config_mutex); + + ret = line_set_values_locked(line, &lv); + + mutex_unlock(&line->config_mutex); + + return ret; +} + static long line_set_config_locked(struct line *line, struct gpio_v2_line_config *lc) { @@ -880,6 +945,8 @@ static long line_ioctl(struct file *file, unsigned int cmd, if (cmd == GPIO_V2_LINE_GET_VALUES_IOCTL) return line_get_values(line, ip); + else if (cmd == GPIO_V2_LINE_SET_VALUES_IOCTL) + return line_set_values(line, ip); else if (cmd == GPIO_V2_LINE_SET_CONFIG_IOCTL) return line_set_config(line, ip); -- 2.28.0