Add support for the GPIO_V2_LINE_SET_VALUES_IOCTL. Signed-off-by: Kent Gibson <warthog618@xxxxxxxxx> --- drivers/gpio/gpiolib-cdev.c | 59 +++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 9c1e3f5f01af..3d2d9eefdfa0 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -799,6 +799,63 @@ static long linereq_get_values(struct linereq *lr, void __user *ip) return 0; } +static long linereq_set_values_unlocked(struct linereq *lr, + struct gpio_v2_line_values *lv) +{ + DECLARE_BITMAP(vals, GPIO_V2_LINES_MAX); + struct gpio_desc **descs; + unsigned int i, didx, num_set; + int ret; + + bitmap_zero(vals, GPIO_V2_LINES_MAX); + for (num_set = 0, i = 0; i < lr->num_lines; i++) { + if (lv->mask & BIT_ULL(i)) { + if (!test_bit(FLAG_IS_OUT, &lr->lines[i].desc->flags)) + return -EPERM; + if (lv->bits & BIT_ULL(i)) + __set_bit(num_set, vals); + num_set++; + descs = &lr->lines[i].desc; + } + } + if (num_set == 0) + return -EINVAL; + + if (num_set != 1) { + /* build compacted desc array and values */ + descs = kmalloc_array(num_set, sizeof(*descs), GFP_KERNEL); + for (didx = 0, i = 0; i < lr->num_lines; i++) { + if (lv->mask & BIT_ULL(i)) { + descs[didx] = lr->lines[i].desc; + didx++; + } + } + } + ret = gpiod_set_array_value_complex(false, true, num_set, + descs, NULL, vals); + + if (num_set != 1) + kfree(descs); + return ret; +} + +static long linereq_set_values(struct linereq *lr, void __user *ip) +{ + struct gpio_v2_line_values lv; + int ret; + + if (copy_from_user(&lv, ip, sizeof(lv))) + return -EFAULT; + + mutex_lock(&lr->config_mutex); + + ret = linereq_set_values_unlocked(lr, &lv); + + mutex_unlock(&lr->config_mutex); + + return ret; +} + static long linereq_set_config_unlocked(struct linereq *lr, struct gpio_v2_line_config *lc) { @@ -869,6 +926,8 @@ static long linereq_ioctl(struct file *file, unsigned int cmd, if (cmd == GPIO_V2_LINE_GET_VALUES_IOCTL) return linereq_get_values(lr, ip); + else if (cmd == GPIO_V2_LINE_SET_VALUES_IOCTL) + return linereq_set_values(lr, ip); else if (cmd == GPIO_V2_LINE_SET_CONFIG_IOCTL) return linereq_set_config(lr, ip); -- 2.28.0