14b2672ecSJorge Lopez // SPDX-License-Identifier: GPL-2.0
24b2672ecSJorge Lopez /*
34b2672ecSJorge Lopez  * Functions corresponding to ordered list type attributes under
44b2672ecSJorge Lopez  * BIOS ORDERED LIST GUID for use with hp-bioscfg driver.
54b2672ecSJorge Lopez  *
64b2672ecSJorge Lopez  * Copyright (c) 2022 HP Development Company, L.P.
74b2672ecSJorge Lopez  */
84b2672ecSJorge Lopez 
94b2672ecSJorge Lopez #include "bioscfg.h"
104b2672ecSJorge Lopez 
114b2672ecSJorge Lopez GET_INSTANCE_ID(ordered_list);
124b2672ecSJorge Lopez 
current_value_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)134b2672ecSJorge Lopez static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
144b2672ecSJorge Lopez {
154b2672ecSJorge Lopez 	int instance_id = get_ordered_list_instance_id(kobj);
164b2672ecSJorge Lopez 
174b2672ecSJorge Lopez 	if (instance_id < 0)
184b2672ecSJorge Lopez 		return -EIO;
194b2672ecSJorge Lopez 
204b2672ecSJorge Lopez 	return sysfs_emit(buf, "%s\n",
214b2672ecSJorge Lopez 			 bioscfg_drv.ordered_list_data[instance_id].current_value);
224b2672ecSJorge Lopez }
234b2672ecSJorge Lopez 
replace_char_str(u8 * buffer,char * repl_char,char * repl_with)244b2672ecSJorge Lopez static int replace_char_str(u8 *buffer, char *repl_char, char *repl_with)
254b2672ecSJorge Lopez {
264b2672ecSJorge Lopez 	char *src = buffer;
274b2672ecSJorge Lopez 	int buflen = strlen(buffer);
284b2672ecSJorge Lopez 	int item;
294b2672ecSJorge Lopez 
304b2672ecSJorge Lopez 	if (buflen < 1)
314b2672ecSJorge Lopez 		return -EINVAL;
324b2672ecSJorge Lopez 
334b2672ecSJorge Lopez 	for (item = 0; item < buflen; item++)
344b2672ecSJorge Lopez 		if (src[item] == *repl_char)
354b2672ecSJorge Lopez 			src[item] = *repl_with;
364b2672ecSJorge Lopez 
374b2672ecSJorge Lopez 	return 0;
384b2672ecSJorge Lopez }
394b2672ecSJorge Lopez 
404b2672ecSJorge Lopez /**
414b2672ecSJorge Lopez  * validate_ordered_list_input() -
424b2672ecSJorge Lopez  * Validate input of current_value against possible values
434b2672ecSJorge Lopez  *
444b2672ecSJorge Lopez  * @instance: The instance on which input is validated
454b2672ecSJorge Lopez  * @buf: Input value
464b2672ecSJorge Lopez  */
validate_ordered_list_input(int instance,char * buf)474b2672ecSJorge Lopez static int validate_ordered_list_input(int instance, char *buf)
484b2672ecSJorge Lopez {
494b2672ecSJorge Lopez 	/* validation is done by BIOS. This validation function will
504b2672ecSJorge Lopez 	 * convert semicolon to commas. BIOS uses commas as
514b2672ecSJorge Lopez 	 * separators when reporting ordered-list values.
524b2672ecSJorge Lopez 	 */
534b2672ecSJorge Lopez 	return replace_char_str(buf, SEMICOLON_SEP, COMMA_SEP);
544b2672ecSJorge Lopez }
554b2672ecSJorge Lopez 
update_ordered_list_value(int instance,char * attr_value)564b2672ecSJorge Lopez static void update_ordered_list_value(int instance, char *attr_value)
574b2672ecSJorge Lopez {
584b2672ecSJorge Lopez 	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance];
594b2672ecSJorge Lopez 
604b2672ecSJorge Lopez 	strscpy(ordered_list_data->current_value,
614b2672ecSJorge Lopez 		attr_value,
624b2672ecSJorge Lopez 		sizeof(ordered_list_data->current_value));
634b2672ecSJorge Lopez }
644b2672ecSJorge Lopez 
654b2672ecSJorge Lopez ATTRIBUTE_S_COMMON_PROPERTY_SHOW(display_name, ordered_list);
664b2672ecSJorge Lopez static struct kobj_attribute ordered_list_display_name =
674b2672ecSJorge Lopez 	__ATTR_RO(display_name);
684b2672ecSJorge Lopez 
694b2672ecSJorge Lopez ATTRIBUTE_PROPERTY_STORE(current_value, ordered_list);
704b2672ecSJorge Lopez static struct kobj_attribute ordered_list_current_val =
714b2672ecSJorge Lopez 	__ATTR_RW_MODE(current_value, 0644);
724b2672ecSJorge Lopez 
734b2672ecSJorge Lopez ATTRIBUTE_VALUES_PROPERTY_SHOW(elements, ordered_list, SEMICOLON_SEP);
744b2672ecSJorge Lopez static struct kobj_attribute ordered_list_elements_val =
754b2672ecSJorge Lopez 	__ATTR_RO(elements);
764b2672ecSJorge Lopez 
type_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)774b2672ecSJorge Lopez static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
784b2672ecSJorge Lopez 			 char *buf)
794b2672ecSJorge Lopez {
804b2672ecSJorge Lopez 	return sysfs_emit(buf, "ordered-list\n");
814b2672ecSJorge Lopez }
824b2672ecSJorge Lopez 
834b2672ecSJorge Lopez static struct kobj_attribute ordered_list_type =
844b2672ecSJorge Lopez 	__ATTR_RO(type);
854b2672ecSJorge Lopez 
864b2672ecSJorge Lopez static struct attribute *ordered_list_attrs[] = {
874b2672ecSJorge Lopez 	&common_display_langcode.attr,
884b2672ecSJorge Lopez 	&ordered_list_display_name.attr,
894b2672ecSJorge Lopez 	&ordered_list_current_val.attr,
904b2672ecSJorge Lopez 	&ordered_list_elements_val.attr,
914b2672ecSJorge Lopez 	&ordered_list_type.attr,
924b2672ecSJorge Lopez 	NULL
934b2672ecSJorge Lopez };
944b2672ecSJorge Lopez 
954b2672ecSJorge Lopez static const struct attribute_group ordered_list_attr_group = {
964b2672ecSJorge Lopez 	.attrs = ordered_list_attrs,
974b2672ecSJorge Lopez };
984b2672ecSJorge Lopez 
hp_alloc_ordered_list_data(void)994b2672ecSJorge Lopez int hp_alloc_ordered_list_data(void)
1004b2672ecSJorge Lopez {
1014b2672ecSJorge Lopez 	bioscfg_drv.ordered_list_instances_count =
1024b2672ecSJorge Lopez 		hp_get_instance_count(HP_WMI_BIOS_ORDERED_LIST_GUID);
1034b2672ecSJorge Lopez 	bioscfg_drv.ordered_list_data = kcalloc(bioscfg_drv.ordered_list_instances_count,
1044b2672ecSJorge Lopez 						sizeof(*bioscfg_drv.ordered_list_data),
1054b2672ecSJorge Lopez 						GFP_KERNEL);
1064b2672ecSJorge Lopez 	if (!bioscfg_drv.ordered_list_data) {
1074b2672ecSJorge Lopez 		bioscfg_drv.ordered_list_instances_count = 0;
1084b2672ecSJorge Lopez 		return -ENOMEM;
1094b2672ecSJorge Lopez 	}
1104b2672ecSJorge Lopez 	return 0;
1114b2672ecSJorge Lopez }
1124b2672ecSJorge Lopez 
1134b2672ecSJorge Lopez /* Expected Values types associated with each element */
1144b2672ecSJorge Lopez static const acpi_object_type expected_order_types[] = {
1154b2672ecSJorge Lopez 	[NAME]	= ACPI_TYPE_STRING,
1164b2672ecSJorge Lopez 	[VALUE] = ACPI_TYPE_STRING,
1174b2672ecSJorge Lopez 	[PATH] = ACPI_TYPE_STRING,
1184b2672ecSJorge Lopez 	[IS_READONLY] = ACPI_TYPE_INTEGER,
1194b2672ecSJorge Lopez 	[DISPLAY_IN_UI] = ACPI_TYPE_INTEGER,
1204b2672ecSJorge Lopez 	[REQUIRES_PHYSICAL_PRESENCE] = ACPI_TYPE_INTEGER,
1214b2672ecSJorge Lopez 	[SEQUENCE] = ACPI_TYPE_INTEGER,
1224b2672ecSJorge Lopez 	[PREREQUISITES_SIZE] = ACPI_TYPE_INTEGER,
1234b2672ecSJorge Lopez 	[PREREQUISITES] = ACPI_TYPE_STRING,
1244b2672ecSJorge Lopez 	[SECURITY_LEVEL] = ACPI_TYPE_INTEGER,
1254b2672ecSJorge Lopez 	[ORD_LIST_SIZE] = ACPI_TYPE_INTEGER,
1264b2672ecSJorge Lopez 	[ORD_LIST_ELEMENTS] = ACPI_TYPE_STRING,
1274b2672ecSJorge Lopez };
1284b2672ecSJorge Lopez 
hp_populate_ordered_list_elements_from_package(union acpi_object * order_obj,int order_obj_count,int instance_id)1294b2672ecSJorge Lopez static int hp_populate_ordered_list_elements_from_package(union acpi_object *order_obj,
1304b2672ecSJorge Lopez 							  int order_obj_count,
1314b2672ecSJorge Lopez 							  int instance_id)
1324b2672ecSJorge Lopez {
1334b2672ecSJorge Lopez 	char *str_value = NULL;
13480d7ba30SJorge Lopez 	int value_len = 0;
1354b2672ecSJorge Lopez 	int ret;
1364b2672ecSJorge Lopez 	u32 size;
13780d7ba30SJorge Lopez 	u32 int_value = 0;
1384b2672ecSJorge Lopez 	int elem;
139bfecbcb5SJorge Lopez 	int olist_elem;
1404b2672ecSJorge Lopez 	int reqs;
1414b2672ecSJorge Lopez 	int eloc;
1424b2672ecSJorge Lopez 	char *tmpstr = NULL;
1434b2672ecSJorge Lopez 	char *part_tmp = NULL;
1444b2672ecSJorge Lopez 	int tmp_len = 0;
1454b2672ecSJorge Lopez 	char *part = NULL;
1464b2672ecSJorge Lopez 	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id];
1474b2672ecSJorge Lopez 
1484b2672ecSJorge Lopez 	if (!order_obj)
1494b2672ecSJorge Lopez 		return -EINVAL;
1504b2672ecSJorge Lopez 
151bfecbcb5SJorge Lopez 	for (elem = 1, eloc = 1; eloc < ORD_ELEM_CNT; elem++, eloc++) {
1524b2672ecSJorge Lopez 
1534b2672ecSJorge Lopez 		switch (order_obj[elem].type) {
1544b2672ecSJorge Lopez 		case ACPI_TYPE_STRING:
1554b2672ecSJorge Lopez 			if (elem != PREREQUISITES && elem != ORD_LIST_ELEMENTS) {
1564b2672ecSJorge Lopez 				ret = hp_convert_hexstr_to_str(order_obj[elem].string.pointer,
1574b2672ecSJorge Lopez 							       order_obj[elem].string.length,
1584b2672ecSJorge Lopez 							       &str_value, &value_len);
1594b2672ecSJorge Lopez 				if (ret)
1604b2672ecSJorge Lopez 					continue;
1614b2672ecSJorge Lopez 			}
1624b2672ecSJorge Lopez 			break;
1634b2672ecSJorge Lopez 		case ACPI_TYPE_INTEGER:
1644b2672ecSJorge Lopez 			int_value = (u32)order_obj[elem].integer.value;
1654b2672ecSJorge Lopez 			break;
1664b2672ecSJorge Lopez 		default:
1674b2672ecSJorge Lopez 			pr_warn("Unsupported object type [%d]\n", order_obj[elem].type);
1684b2672ecSJorge Lopez 			continue;
1694b2672ecSJorge Lopez 		}
1704b2672ecSJorge Lopez 
1714b2672ecSJorge Lopez 		/* Check that both expected and read object type match */
1724b2672ecSJorge Lopez 		if (expected_order_types[eloc] != order_obj[elem].type) {
1734b2672ecSJorge Lopez 			pr_err("Error expected type %d for elem %d, but got type %d instead\n",
1744b2672ecSJorge Lopez 			       expected_order_types[eloc], elem, order_obj[elem].type);
175467d4163SJorge Lopez 			kfree(str_value);
1764b2672ecSJorge Lopez 			return -EIO;
1774b2672ecSJorge Lopez 		}
1784b2672ecSJorge Lopez 
1794b2672ecSJorge Lopez 		/* Assign appropriate element value to corresponding field*/
1804b2672ecSJorge Lopez 		switch (eloc) {
1814b2672ecSJorge Lopez 		case VALUE:
1824b2672ecSJorge Lopez 			strscpy(ordered_list_data->current_value,
1834b2672ecSJorge Lopez 				str_value, sizeof(ordered_list_data->current_value));
1844b2672ecSJorge Lopez 			replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP);
1854b2672ecSJorge Lopez 			break;
1864b2672ecSJorge Lopez 		case PATH:
1874b2672ecSJorge Lopez 			strscpy(ordered_list_data->common.path, str_value,
1884b2672ecSJorge Lopez 				sizeof(ordered_list_data->common.path));
1894b2672ecSJorge Lopez 			break;
1904b2672ecSJorge Lopez 		case IS_READONLY:
1914b2672ecSJorge Lopez 			ordered_list_data->common.is_readonly = int_value;
1924b2672ecSJorge Lopez 			break;
1934b2672ecSJorge Lopez 		case DISPLAY_IN_UI:
1944b2672ecSJorge Lopez 			ordered_list_data->common.display_in_ui = int_value;
1954b2672ecSJorge Lopez 			break;
1964b2672ecSJorge Lopez 		case REQUIRES_PHYSICAL_PRESENCE:
1974b2672ecSJorge Lopez 			ordered_list_data->common.requires_physical_presence = int_value;
1984b2672ecSJorge Lopez 			break;
1994b2672ecSJorge Lopez 		case SEQUENCE:
2004b2672ecSJorge Lopez 			ordered_list_data->common.sequence = int_value;
2014b2672ecSJorge Lopez 			break;
2024b2672ecSJorge Lopez 		case PREREQUISITES_SIZE:
20308f1f212SJorge Lopez 			if (int_value > MAX_PREREQUISITES_SIZE) {
2044b2672ecSJorge Lopez 				pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
20508f1f212SJorge Lopez 				int_value = MAX_PREREQUISITES_SIZE;
20608f1f212SJorge Lopez 			}
20708f1f212SJorge Lopez 			ordered_list_data->common.prerequisites_size = int_value;
2084b2672ecSJorge Lopez 
2094b2672ecSJorge Lopez 			/*
210a585400bSJorge Lopez 			 * This step is needed to keep the expected
2114b2672ecSJorge Lopez 			 * element list pointing to the right obj[elem].type
2124b2672ecSJorge Lopez 			 * when the size is zero. PREREQUISITES
2134b2672ecSJorge Lopez 			 * object is omitted by BIOS when the size is
2144b2672ecSJorge Lopez 			 * zero.
2154b2672ecSJorge Lopez 			 */
2164b2672ecSJorge Lopez 			if (int_value == 0)
2174b2672ecSJorge Lopez 				eloc++;
2184b2672ecSJorge Lopez 			break;
2194b2672ecSJorge Lopez 		case PREREQUISITES:
2204b2672ecSJorge Lopez 			size = min_t(u32, ordered_list_data->common.prerequisites_size,
2214b2672ecSJorge Lopez 				     MAX_PREREQUISITES_SIZE);
2224b2672ecSJorge Lopez 			for (reqs = 0; reqs < size; reqs++) {
2234b2672ecSJorge Lopez 				ret = hp_convert_hexstr_to_str(order_obj[elem + reqs].string.pointer,
2244b2672ecSJorge Lopez 							       order_obj[elem + reqs].string.length,
2254b2672ecSJorge Lopez 							       &str_value, &value_len);
2264b2672ecSJorge Lopez 
2274b2672ecSJorge Lopez 				if (ret)
2284b2672ecSJorge Lopez 					continue;
2294b2672ecSJorge Lopez 
2304b2672ecSJorge Lopez 				strscpy(ordered_list_data->common.prerequisites[reqs],
2314b2672ecSJorge Lopez 					str_value,
2324b2672ecSJorge Lopez 					sizeof(ordered_list_data->common.prerequisites[reqs]));
2334b2672ecSJorge Lopez 
2344b2672ecSJorge Lopez 				kfree(str_value);
235467d4163SJorge Lopez 				str_value = NULL;
2364b2672ecSJorge Lopez 			}
2374b2672ecSJorge Lopez 			break;
2384b2672ecSJorge Lopez 
2394b2672ecSJorge Lopez 		case SECURITY_LEVEL:
2404b2672ecSJorge Lopez 			ordered_list_data->common.security_level = int_value;
2414b2672ecSJorge Lopez 			break;
2424b2672ecSJorge Lopez 
2434b2672ecSJorge Lopez 		case ORD_LIST_SIZE:
24424652a8cSJorge Lopez 			if (int_value > MAX_ELEMENTS_SIZE) {
24524652a8cSJorge Lopez 				pr_warn("Order List size value exceeded the maximum number of elements supported or data may be malformed\n");
24624652a8cSJorge Lopez 				int_value = MAX_ELEMENTS_SIZE;
24724652a8cSJorge Lopez 			}
2484b2672ecSJorge Lopez 			ordered_list_data->elements_size = int_value;
24924652a8cSJorge Lopez 
2504b2672ecSJorge Lopez 			/*
251a585400bSJorge Lopez 			 * This step is needed to keep the expected
2524b2672ecSJorge Lopez 			 * element list pointing to the right obj[elem].type
2534b2672ecSJorge Lopez 			 * when the size is zero. ORD_LIST_ELEMENTS
2544b2672ecSJorge Lopez 			 * object is omitted by BIOS when the size is
2554b2672ecSJorge Lopez 			 * zero.
2564b2672ecSJorge Lopez 			 */
2574b2672ecSJorge Lopez 			if (int_value == 0)
2584b2672ecSJorge Lopez 				eloc++;
2594b2672ecSJorge Lopez 			break;
2604b2672ecSJorge Lopez 		case ORD_LIST_ELEMENTS:
2614b2672ecSJorge Lopez 
2624b2672ecSJorge Lopez 			/*
2634b2672ecSJorge Lopez 			 * Ordered list data is stored in hex and comma separated format
2644b2672ecSJorge Lopez 			 * Convert the data and split it to show each element
2654b2672ecSJorge Lopez 			 */
2664b2672ecSJorge Lopez 			ret = hp_convert_hexstr_to_str(str_value, value_len, &tmpstr, &tmp_len);
2674b2672ecSJorge Lopez 			if (ret)
2684b2672ecSJorge Lopez 				goto exit_list;
2694b2672ecSJorge Lopez 
2704b2672ecSJorge Lopez 			part_tmp = tmpstr;
2714b2672ecSJorge Lopez 			part = strsep(&part_tmp, COMMA_SEP);
2724b2672ecSJorge Lopez 
273*559eed77SJorge Lopez 			for (olist_elem = 0; olist_elem < MAX_ELEMENTS_SIZE && part; olist_elem++) {
274bfecbcb5SJorge Lopez 				strscpy(ordered_list_data->elements[olist_elem],
2754b2672ecSJorge Lopez 					part,
276bfecbcb5SJorge Lopez 					sizeof(ordered_list_data->elements[olist_elem]));
277*559eed77SJorge Lopez 				part = strsep(&part_tmp, COMMA_SEP);
2784b2672ecSJorge Lopez 			}
279*559eed77SJorge Lopez 			ordered_list_data->elements_size = olist_elem;
2804b2672ecSJorge Lopez 
281467d4163SJorge Lopez 			kfree(str_value);
282467d4163SJorge Lopez 			str_value = NULL;
2834b2672ecSJorge Lopez 			break;
2844b2672ecSJorge Lopez 		default:
2854b2672ecSJorge Lopez 			pr_warn("Invalid element: %d found in Ordered_List attribute or data may be malformed\n", elem);
2864b2672ecSJorge Lopez 			break;
2874b2672ecSJorge Lopez 		}
2884b2672ecSJorge Lopez 		kfree(tmpstr);
289467d4163SJorge Lopez 		tmpstr = NULL;
2904b2672ecSJorge Lopez 		kfree(str_value);
291467d4163SJorge Lopez 		str_value = NULL;
2924b2672ecSJorge Lopez 	}
2934b2672ecSJorge Lopez 
2944b2672ecSJorge Lopez exit_list:
2954b2672ecSJorge Lopez 	kfree(tmpstr);
2964b2672ecSJorge Lopez 	kfree(str_value);
2974b2672ecSJorge Lopez 	return 0;
2984b2672ecSJorge Lopez }
2994b2672ecSJorge Lopez 
3004b2672ecSJorge Lopez /**
3014b2672ecSJorge Lopez  * hp_populate_ordered_list_package_data() -
3024b2672ecSJorge Lopez  * Populate all properties of an instance under ordered_list attribute
3034b2672ecSJorge Lopez  *
3044b2672ecSJorge Lopez  * @order_obj: ACPI object with ordered_list data
3054b2672ecSJorge Lopez  * @instance_id: The instance to enumerate
3064b2672ecSJorge Lopez  * @attr_name_kobj: The parent kernel object
3074b2672ecSJorge Lopez  */
hp_populate_ordered_list_package_data(union acpi_object * order_obj,int instance_id,struct kobject * attr_name_kobj)3084b2672ecSJorge Lopez int hp_populate_ordered_list_package_data(union acpi_object *order_obj, int instance_id,
3094b2672ecSJorge Lopez 					  struct kobject *attr_name_kobj)
3104b2672ecSJorge Lopez {
3114b2672ecSJorge Lopez 	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id];
3124b2672ecSJorge Lopez 
3134b2672ecSJorge Lopez 	ordered_list_data->attr_name_kobj = attr_name_kobj;
3144b2672ecSJorge Lopez 
3154b2672ecSJorge Lopez 	hp_populate_ordered_list_elements_from_package(order_obj,
3164b2672ecSJorge Lopez 						       order_obj->package.count,
3174b2672ecSJorge Lopez 						       instance_id);
3184b2672ecSJorge Lopez 	hp_update_attribute_permissions(ordered_list_data->common.is_readonly,
3194b2672ecSJorge Lopez 					&ordered_list_current_val);
3204b2672ecSJorge Lopez 	hp_friendly_user_name_update(ordered_list_data->common.path,
3214b2672ecSJorge Lopez 				     attr_name_kobj->name,
3224b2672ecSJorge Lopez 				     ordered_list_data->common.display_name,
3234b2672ecSJorge Lopez 				     sizeof(ordered_list_data->common.display_name));
3244b2672ecSJorge Lopez 	return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group);
3254b2672ecSJorge Lopez }
3264b2672ecSJorge Lopez 
hp_populate_ordered_list_elements_from_buffer(u8 * buffer_ptr,u32 * buffer_size,int instance_id)3274b2672ecSJorge Lopez static int hp_populate_ordered_list_elements_from_buffer(u8 *buffer_ptr, u32 *buffer_size,
3284b2672ecSJorge Lopez 							 int instance_id)
3294b2672ecSJorge Lopez {
3304b2672ecSJorge Lopez 	int values;
3314b2672ecSJorge Lopez 	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id];
3324b2672ecSJorge Lopez 	int ret = 0;
3334b2672ecSJorge Lopez 
3344b2672ecSJorge Lopez 	/*
3354b2672ecSJorge Lopez 	 * Only data relevant to this driver and its functionality is
3364b2672ecSJorge Lopez 	 * read. BIOS defines the order in which each * element is
3374b2672ecSJorge Lopez 	 * read. Element 0 data is not relevant to this
3384b2672ecSJorge Lopez 	 * driver hence it is ignored. For clarity, all element names
3394b2672ecSJorge Lopez 	 * (DISPLAY_IN_UI) which defines the order in which is read
3404b2672ecSJorge Lopez 	 * and the name matches the variable where the data is stored.
3414b2672ecSJorge Lopez 	 *
3424b2672ecSJorge Lopez 	 * In earlier implementation, reported errors were ignored
3434b2672ecSJorge Lopez 	 * causing the data to remain uninitialized. It is not
3444b2672ecSJorge Lopez 	 * possible to determine if data read from BIOS is valid or
3454b2672ecSJorge Lopez 	 * not. It is for this reason functions may return a error
3464b2672ecSJorge Lopez 	 * without validating the data itself.
3474b2672ecSJorge Lopez 	 */
3484b2672ecSJorge Lopez 
3494b2672ecSJorge Lopez 	// VALUE:
3504b2672ecSJorge Lopez 	ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, ordered_list_data->current_value,
3514b2672ecSJorge Lopez 					sizeof(ordered_list_data->current_value));
3524b2672ecSJorge Lopez 	if (ret < 0)
3534b2672ecSJorge Lopez 		goto buffer_exit;
3544b2672ecSJorge Lopez 
3554b2672ecSJorge Lopez 	replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP);
3564b2672ecSJorge Lopez 
3574b2672ecSJorge Lopez 	// COMMON:
3584b2672ecSJorge Lopez 	ret = hp_get_common_data_from_buffer(&buffer_ptr, buffer_size,
3594b2672ecSJorge Lopez 					     &ordered_list_data->common);
3604b2672ecSJorge Lopez 	if (ret < 0)
3614b2672ecSJorge Lopez 		goto buffer_exit;
3624b2672ecSJorge Lopez 
3634b2672ecSJorge Lopez 	// ORD_LIST_SIZE:
3644b2672ecSJorge Lopez 	ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size,
3654b2672ecSJorge Lopez 					 &ordered_list_data->elements_size);
3664b2672ecSJorge Lopez 
3674b2672ecSJorge Lopez 	if (ordered_list_data->elements_size > MAX_ELEMENTS_SIZE) {
3684b2672ecSJorge Lopez 		/* Report a message and limit elements size to maximum value */
3694b2672ecSJorge Lopez 		pr_warn("Ordered List size value exceeded the maximum number of elements supported or data may be malformed\n");
3704b2672ecSJorge Lopez 		ordered_list_data->elements_size = MAX_ELEMENTS_SIZE;
3714b2672ecSJorge Lopez 	}
3724b2672ecSJorge Lopez 
3734b2672ecSJorge Lopez 	// ORD_LIST_ELEMENTS:
3744b2672ecSJorge Lopez 	for (values = 0; values < ordered_list_data->elements_size; values++) {
3754b2672ecSJorge Lopez 		ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size,
3764b2672ecSJorge Lopez 						ordered_list_data->elements[values],
3774b2672ecSJorge Lopez 						sizeof(ordered_list_data->elements[values]));
3784b2672ecSJorge Lopez 		if (ret < 0)
3794b2672ecSJorge Lopez 			break;
3804b2672ecSJorge Lopez 	}
3814b2672ecSJorge Lopez 
3824b2672ecSJorge Lopez buffer_exit:
3834b2672ecSJorge Lopez 	return ret;
3844b2672ecSJorge Lopez }
3854b2672ecSJorge Lopez 
3864b2672ecSJorge Lopez /**
3874b2672ecSJorge Lopez  * hp_populate_ordered_list_buffer_data() - Populate all properties of an
3884b2672ecSJorge Lopez  * instance under ordered list attribute
3894b2672ecSJorge Lopez  *
3904b2672ecSJorge Lopez  * @buffer_ptr: Buffer pointer
3914b2672ecSJorge Lopez  * @buffer_size: Buffer size
3924b2672ecSJorge Lopez  * @instance_id: The instance to enumerate
3934b2672ecSJorge Lopez  * @attr_name_kobj: The parent kernel object
3944b2672ecSJorge Lopez  */
hp_populate_ordered_list_buffer_data(u8 * buffer_ptr,u32 * buffer_size,int instance_id,struct kobject * attr_name_kobj)3954b2672ecSJorge Lopez int hp_populate_ordered_list_buffer_data(u8 *buffer_ptr, u32 *buffer_size, int instance_id,
3964b2672ecSJorge Lopez 					 struct kobject *attr_name_kobj)
3974b2672ecSJorge Lopez {
3984b2672ecSJorge Lopez 	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id];
3994b2672ecSJorge Lopez 	int ret = 0;
4004b2672ecSJorge Lopez 
4014b2672ecSJorge Lopez 	ordered_list_data->attr_name_kobj = attr_name_kobj;
4024b2672ecSJorge Lopez 
4034b2672ecSJorge Lopez 	/* Populate ordered list elements */
4044b2672ecSJorge Lopez 	ret = hp_populate_ordered_list_elements_from_buffer(buffer_ptr, buffer_size,
4054b2672ecSJorge Lopez 							    instance_id);
4064b2672ecSJorge Lopez 	if (ret < 0)
4074b2672ecSJorge Lopez 		return ret;
4084b2672ecSJorge Lopez 
4094b2672ecSJorge Lopez 	hp_update_attribute_permissions(ordered_list_data->common.is_readonly,
4104b2672ecSJorge Lopez 					&ordered_list_current_val);
4114b2672ecSJorge Lopez 	hp_friendly_user_name_update(ordered_list_data->common.path,
4124b2672ecSJorge Lopez 				     attr_name_kobj->name,
4134b2672ecSJorge Lopez 				     ordered_list_data->common.display_name,
4144b2672ecSJorge Lopez 				     sizeof(ordered_list_data->common.display_name));
4154b2672ecSJorge Lopez 
4164b2672ecSJorge Lopez 	return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group);
4174b2672ecSJorge Lopez }
4184b2672ecSJorge Lopez 
4194b2672ecSJorge Lopez /**
4204b2672ecSJorge Lopez  * hp_exit_ordered_list_attributes() - Clear all attribute data
4214b2672ecSJorge Lopez  *
4224b2672ecSJorge Lopez  * Clears all data allocated for this group of attributes
4234b2672ecSJorge Lopez  */
hp_exit_ordered_list_attributes(void)4244b2672ecSJorge Lopez void hp_exit_ordered_list_attributes(void)
4254b2672ecSJorge Lopez {
4264b2672ecSJorge Lopez 	int instance_id;
4274b2672ecSJorge Lopez 
4284b2672ecSJorge Lopez 	for (instance_id = 0; instance_id < bioscfg_drv.ordered_list_instances_count;
4294b2672ecSJorge Lopez 	     instance_id++) {
4304b2672ecSJorge Lopez 		struct kobject *attr_name_kobj =
4314b2672ecSJorge Lopez 			bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj;
4324b2672ecSJorge Lopez 
4334b2672ecSJorge Lopez 		if (attr_name_kobj)
4344b2672ecSJorge Lopez 			sysfs_remove_group(attr_name_kobj,
4354b2672ecSJorge Lopez 					   &ordered_list_attr_group);
4364b2672ecSJorge Lopez 	}
4374b2672ecSJorge Lopez 	bioscfg_drv.ordered_list_instances_count = 0;
4384b2672ecSJorge Lopez 
4394b2672ecSJorge Lopez 	kfree(bioscfg_drv.ordered_list_data);
4404b2672ecSJorge Lopez 	bioscfg_drv.ordered_list_data = NULL;
4414b2672ecSJorge Lopez }
442