xref: /linux/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c (revision 260f6f4fda93c8485c8037865c941b42b9cba5d2)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Functions corresponding to enumeration type attributes under
4  * BIOS Enumeration GUID for use with dell-wmi-sysman
5  *
6  *  Copyright (c) 2020 Dell Inc.
7  */
8 
9 #include "dell-wmi-sysman.h"
10 
11 get_instance_id(enumeration);
12 
13 static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
14 {
15 	int instance_id = get_enumeration_instance_id(kobj);
16 	union acpi_object *obj;
17 	ssize_t ret;
18 
19 	if (instance_id < 0)
20 		return instance_id;
21 
22 	/* need to use specific instance_id and guid combination to get right data */
23 	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
24 	if (!obj)
25 		return -EIO;
26 	if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < ENUM_MIN_ELEMENTS ||
27 	    obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
28 		kfree(obj);
29 		return -EIO;
30 	}
31 	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
32 	kfree(obj);
33 	return ret;
34 }
35 
36 /**
37  * validate_enumeration_input() - Validate input of current_value against possible values
38  * @instance_id: The instance on which input is validated
39  * @buf: Input value
40  */
41 static int validate_enumeration_input(int instance_id, const char *buf)
42 {
43 	char *options, *tmp, *p;
44 	int ret = -EINVAL;
45 
46 	options = tmp = kstrdup(wmi_priv.enumeration_data[instance_id].possible_values,
47 				 GFP_KERNEL);
48 	if (!options)
49 		return -ENOMEM;
50 
51 	while ((p = strsep(&options, ";")) != NULL) {
52 		if (!*p)
53 			continue;
54 		if (!strcasecmp(p, buf)) {
55 			ret = 0;
56 			break;
57 		}
58 	}
59 
60 	kfree(tmp);
61 	return ret;
62 }
63 
64 attribute_s_property_show(display_name_language_code, enumeration);
65 static struct kobj_attribute displ_langcode =
66 		__ATTR_RO(display_name_language_code);
67 
68 attribute_s_property_show(display_name, enumeration);
69 static struct kobj_attribute displ_name =
70 		__ATTR_RO(display_name);
71 
72 attribute_s_property_show(default_value, enumeration);
73 static struct kobj_attribute default_val =
74 		__ATTR_RO(default_value);
75 
76 attribute_property_store(current_value, enumeration);
77 static struct kobj_attribute current_val =
78 		__ATTR_RW_MODE(current_value, 0600);
79 
80 attribute_s_property_show(dell_modifier, enumeration);
81 static struct kobj_attribute modifier =
82 		__ATTR_RO(dell_modifier);
83 
84 attribute_s_property_show(dell_value_modifier, enumeration);
85 static struct kobj_attribute value_modfr =
86 		__ATTR_RO(dell_value_modifier);
87 
88 attribute_s_property_show(possible_values, enumeration);
89 static struct kobj_attribute poss_val =
90 		__ATTR_RO(possible_values);
91 
92 static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
93 			 char *buf)
94 {
95 	return sprintf(buf, "enumeration\n");
96 }
97 static struct kobj_attribute type =
98 		__ATTR_RO(type);
99 
100 static struct attribute *enumeration_attrs[] = {
101 	&displ_langcode.attr,
102 	&displ_name.attr,
103 	&default_val.attr,
104 	&current_val.attr,
105 	&modifier.attr,
106 	&value_modfr.attr,
107 	&poss_val.attr,
108 	&type.attr,
109 	NULL,
110 };
111 
112 static const struct attribute_group enumeration_attr_group = {
113 	.attrs = enumeration_attrs,
114 };
115 
116 int alloc_enum_data(void)
117 {
118 	int ret = 0;
119 
120 	wmi_priv.enumeration_instances_count =
121 		get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
122 	wmi_priv.enumeration_data = kcalloc(wmi_priv.enumeration_instances_count,
123 					sizeof(struct enumeration_data), GFP_KERNEL);
124 	if (!wmi_priv.enumeration_data) {
125 		wmi_priv.enumeration_instances_count = 0;
126 		ret = -ENOMEM;
127 	}
128 	return ret;
129 }
130 
131 /**
132  * populate_enum_data() - Populate all properties of an instance under enumeration attribute
133  * @enumeration_obj: ACPI object with enumeration data
134  * @instance_id: The instance to enumerate
135  * @attr_name_kobj: The parent kernel object
136  * @enum_property_count: Total properties count under enumeration type
137  */
138 int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
139 			struct kobject *attr_name_kobj, u32 enum_property_count)
140 {
141 	int i, next_obj, value_modifier_count, possible_values_count;
142 
143 	wmi_priv.enumeration_data[instance_id].attr_name_kobj = attr_name_kobj;
144 	if (check_property_type(enumeration, ATTR_NAME, ACPI_TYPE_STRING))
145 		return -EINVAL;
146 	strlcpy_attr(wmi_priv.enumeration_data[instance_id].attribute_name,
147 		enumeration_obj[ATTR_NAME].string.pointer);
148 	if (check_property_type(enumeration, DISPL_NAME_LANG_CODE, ACPI_TYPE_STRING))
149 		return -EINVAL;
150 	strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name_language_code,
151 		enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer);
152 	if (check_property_type(enumeration, DISPLAY_NAME, ACPI_TYPE_STRING))
153 		return -EINVAL;
154 	strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name,
155 		enumeration_obj[DISPLAY_NAME].string.pointer);
156 	if (check_property_type(enumeration, DEFAULT_VAL, ACPI_TYPE_STRING))
157 		return -EINVAL;
158 	strlcpy_attr(wmi_priv.enumeration_data[instance_id].default_value,
159 		enumeration_obj[DEFAULT_VAL].string.pointer);
160 	if (check_property_type(enumeration, MODIFIER, ACPI_TYPE_STRING))
161 		return -EINVAL;
162 	strlcpy_attr(wmi_priv.enumeration_data[instance_id].dell_modifier,
163 		enumeration_obj[MODIFIER].string.pointer);
164 
165 	next_obj = MODIFIER + 1;
166 
167 	if (next_obj >= enum_property_count)
168 		return -EINVAL;
169 
170 	if (check_property_type(enumeration, next_obj, ACPI_TYPE_INTEGER))
171 		return -EINVAL;
172 	value_modifier_count = (uintptr_t)enumeration_obj[next_obj++].string.pointer;
173 
174 	for (i = 0; i < value_modifier_count; i++) {
175 		if (next_obj >= enum_property_count)
176 			return -EINVAL;
177 		if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING))
178 			return -EINVAL;
179 		strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
180 			enumeration_obj[next_obj++].string.pointer);
181 		strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";");
182 	}
183 
184 	if (next_obj >= enum_property_count)
185 		return -EINVAL;
186 
187 	if (check_property_type(enumeration, next_obj, ACPI_TYPE_INTEGER))
188 		return -EINVAL;
189 	possible_values_count = (uintptr_t) enumeration_obj[next_obj++].string.pointer;
190 
191 	for (i = 0; i < possible_values_count; i++) {
192 		if (next_obj >= enum_property_count)
193 			return -EINVAL;
194 		if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING))
195 			return -EINVAL;
196 		strcat(wmi_priv.enumeration_data[instance_id].possible_values,
197 			enumeration_obj[next_obj++].string.pointer);
198 		strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";");
199 	}
200 
201 	return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
202 }
203 
204 /**
205  * exit_enum_attributes() - Clear all attribute data
206  *
207  * Clears all data allocated for this group of attributes
208  */
209 void exit_enum_attributes(void)
210 {
211 	int instance_id;
212 
213 	for (instance_id = 0; instance_id < wmi_priv.enumeration_instances_count; instance_id++) {
214 		if (wmi_priv.enumeration_data[instance_id].attr_name_kobj)
215 			sysfs_remove_group(wmi_priv.enumeration_data[instance_id].attr_name_kobj,
216 								&enumeration_attr_group);
217 	}
218 	wmi_priv.enumeration_instances_count = 0;
219 
220 	kfree(wmi_priv.enumeration_data);
221 	wmi_priv.enumeration_data = NULL;
222 }
223