Loading drivers/gpio/gpiolib-cdev.c +61 −0 Original line number Diff line number Diff line Loading @@ -816,6 +816,65 @@ 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); if (!descs) return -ENOMEM; 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) { Loading Loading @@ -892,6 +951,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); Loading Loading
drivers/gpio/gpiolib-cdev.c +61 −0 Original line number Diff line number Diff line Loading @@ -816,6 +816,65 @@ 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); if (!descs) return -ENOMEM; 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) { Loading Loading @@ -892,6 +951,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); Loading