forked from mirrors/linux
		
	gpiolib: cdev: support GPIO_V2_LINE_SET_VALUES_IOCTL
Add support for the GPIO_V2_LINE_SET_VALUES_IOCTL. Signed-off-by: Kent Gibson <warthog618@gmail.com> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This commit is contained in:
		
							parent
							
								
									a54756cb24
								
							
						
					
					
						commit
						7b8e00d981
					
				
					 1 changed files with 61 additions and 0 deletions
				
			
		|  | @ -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) | ||||
| { | ||||
|  | @ -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…
	
		Reference in a new issue
	
	 Kent Gibson
						Kent Gibson