1e6c7b3e1SJorge Lopez // SPDX-License-Identifier: GPL-2.0 2e6c7b3e1SJorge Lopez /* 3e6c7b3e1SJorge Lopez * Functions corresponding to string type attributes under 4e6c7b3e1SJorge Lopez * HP_WMI_BIOS_STRING_GUID for use with hp-bioscfg driver. 5e6c7b3e1SJorge Lopez * 6e6c7b3e1SJorge Lopez * Copyright (c) 2022 HP Development Company, L.P. 7e6c7b3e1SJorge Lopez */ 8e6c7b3e1SJorge Lopez 9e6c7b3e1SJorge Lopez #include "bioscfg.h" 10e6c7b3e1SJorge Lopez 11e6c7b3e1SJorge Lopez #define WMI_STRING_TYPE "HPBIOS_BIOSString" 12e6c7b3e1SJorge Lopez 13e6c7b3e1SJorge Lopez GET_INSTANCE_ID(string); 14e6c7b3e1SJorge Lopez 15e6c7b3e1SJorge Lopez static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 16e6c7b3e1SJorge Lopez { 17e6c7b3e1SJorge Lopez int instance_id = get_string_instance_id(kobj); 18e6c7b3e1SJorge Lopez 19e6c7b3e1SJorge Lopez if (instance_id < 0) 20e6c7b3e1SJorge Lopez return -EIO; 21e6c7b3e1SJorge Lopez 22e6c7b3e1SJorge Lopez return sysfs_emit(buf, "%s\n", 23e6c7b3e1SJorge Lopez bioscfg_drv.string_data[instance_id].current_value); 24e6c7b3e1SJorge Lopez } 25e6c7b3e1SJorge Lopez 26e6c7b3e1SJorge Lopez /** 27e6c7b3e1SJorge Lopez * validate_string_input() - 28e6c7b3e1SJorge Lopez * Validate input of current_value against min and max lengths 29e6c7b3e1SJorge Lopez * 30e6c7b3e1SJorge Lopez * @instance_id: The instance on which input is validated 31e6c7b3e1SJorge Lopez * @buf: Input value 32e6c7b3e1SJorge Lopez */ 33e6c7b3e1SJorge Lopez static int validate_string_input(int instance_id, const char *buf) 34e6c7b3e1SJorge Lopez { 35e6c7b3e1SJorge Lopez int in_len = strlen(buf); 36e6c7b3e1SJorge Lopez struct string_data *string_data = &bioscfg_drv.string_data[instance_id]; 37e6c7b3e1SJorge Lopez 38e6c7b3e1SJorge Lopez /* BIOS treats it as a read only attribute */ 39e6c7b3e1SJorge Lopez if (string_data->common.is_readonly) 40e6c7b3e1SJorge Lopez return -EIO; 41e6c7b3e1SJorge Lopez 42e6c7b3e1SJorge Lopez if (in_len < string_data->min_length || in_len > string_data->max_length) 43e6c7b3e1SJorge Lopez return -ERANGE; 44e6c7b3e1SJorge Lopez 45e6c7b3e1SJorge Lopez return 0; 46e6c7b3e1SJorge Lopez } 47e6c7b3e1SJorge Lopez 48e6c7b3e1SJorge Lopez static void update_string_value(int instance_id, char *attr_value) 49e6c7b3e1SJorge Lopez { 50e6c7b3e1SJorge Lopez struct string_data *string_data = &bioscfg_drv.string_data[instance_id]; 51e6c7b3e1SJorge Lopez 52e6c7b3e1SJorge Lopez /* Write settings to BIOS */ 53e6c7b3e1SJorge Lopez strscpy(string_data->current_value, attr_value, sizeof(string_data->current_value)); 54e6c7b3e1SJorge Lopez } 55e6c7b3e1SJorge Lopez 56e6c7b3e1SJorge Lopez /* 57e6c7b3e1SJorge Lopez * ATTRIBUTE_S_COMMON_PROPERTY_SHOW(display_name_language_code, string); 58e6c7b3e1SJorge Lopez * static struct kobj_attribute string_display_langcode = 59e6c7b3e1SJorge Lopez * __ATTR_RO(display_name_language_code); 60e6c7b3e1SJorge Lopez */ 61e6c7b3e1SJorge Lopez 62e6c7b3e1SJorge Lopez ATTRIBUTE_S_COMMON_PROPERTY_SHOW(display_name, string); 63e6c7b3e1SJorge Lopez static struct kobj_attribute string_display_name = 64e6c7b3e1SJorge Lopez __ATTR_RO(display_name); 65e6c7b3e1SJorge Lopez 66e6c7b3e1SJorge Lopez ATTRIBUTE_PROPERTY_STORE(current_value, string); 67e6c7b3e1SJorge Lopez static struct kobj_attribute string_current_val = 68e6c7b3e1SJorge Lopez __ATTR_RW_MODE(current_value, 0644); 69e6c7b3e1SJorge Lopez 70e6c7b3e1SJorge Lopez ATTRIBUTE_N_PROPERTY_SHOW(min_length, string); 71e6c7b3e1SJorge Lopez static struct kobj_attribute string_min_length = 72e6c7b3e1SJorge Lopez __ATTR_RO(min_length); 73e6c7b3e1SJorge Lopez 74e6c7b3e1SJorge Lopez ATTRIBUTE_N_PROPERTY_SHOW(max_length, string); 75e6c7b3e1SJorge Lopez static struct kobj_attribute string_max_length = 76e6c7b3e1SJorge Lopez __ATTR_RO(max_length); 77e6c7b3e1SJorge Lopez 78e6c7b3e1SJorge Lopez static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, 79e6c7b3e1SJorge Lopez char *buf) 80e6c7b3e1SJorge Lopez { 81e6c7b3e1SJorge Lopez return sysfs_emit(buf, "string\n"); 82e6c7b3e1SJorge Lopez } 83e6c7b3e1SJorge Lopez 84e6c7b3e1SJorge Lopez static struct kobj_attribute string_type = 85e6c7b3e1SJorge Lopez __ATTR_RO(type); 86e6c7b3e1SJorge Lopez 87e6c7b3e1SJorge Lopez static struct attribute *string_attrs[] = { 88e6c7b3e1SJorge Lopez &common_display_langcode.attr, 89e6c7b3e1SJorge Lopez &string_display_name.attr, 90e6c7b3e1SJorge Lopez &string_current_val.attr, 91e6c7b3e1SJorge Lopez &string_min_length.attr, 92e6c7b3e1SJorge Lopez &string_max_length.attr, 93e6c7b3e1SJorge Lopez &string_type.attr, 94e6c7b3e1SJorge Lopez NULL 95e6c7b3e1SJorge Lopez }; 96e6c7b3e1SJorge Lopez 97e6c7b3e1SJorge Lopez static const struct attribute_group string_attr_group = { 98e6c7b3e1SJorge Lopez .attrs = string_attrs, 99e6c7b3e1SJorge Lopez }; 100e6c7b3e1SJorge Lopez 101e6c7b3e1SJorge Lopez int hp_alloc_string_data(void) 102e6c7b3e1SJorge Lopez { 103e6c7b3e1SJorge Lopez bioscfg_drv.string_instances_count = hp_get_instance_count(HP_WMI_BIOS_STRING_GUID); 104e6c7b3e1SJorge Lopez bioscfg_drv.string_data = kcalloc(bioscfg_drv.string_instances_count, 105e6c7b3e1SJorge Lopez sizeof(*bioscfg_drv.string_data), GFP_KERNEL); 106e6c7b3e1SJorge Lopez if (!bioscfg_drv.string_data) { 107e6c7b3e1SJorge Lopez bioscfg_drv.string_instances_count = 0; 108e6c7b3e1SJorge Lopez return -ENOMEM; 109e6c7b3e1SJorge Lopez } 110e6c7b3e1SJorge Lopez return 0; 111e6c7b3e1SJorge Lopez } 112e6c7b3e1SJorge Lopez 113e6c7b3e1SJorge Lopez /* Expected Values types associated with each element */ 114e6c7b3e1SJorge Lopez static const acpi_object_type expected_string_types[] = { 115e6c7b3e1SJorge Lopez [NAME] = ACPI_TYPE_STRING, 116e6c7b3e1SJorge Lopez [VALUE] = ACPI_TYPE_STRING, 117e6c7b3e1SJorge Lopez [PATH] = ACPI_TYPE_STRING, 118e6c7b3e1SJorge Lopez [IS_READONLY] = ACPI_TYPE_INTEGER, 119e6c7b3e1SJorge Lopez [DISPLAY_IN_UI] = ACPI_TYPE_INTEGER, 120e6c7b3e1SJorge Lopez [REQUIRES_PHYSICAL_PRESENCE] = ACPI_TYPE_INTEGER, 121e6c7b3e1SJorge Lopez [SEQUENCE] = ACPI_TYPE_INTEGER, 122e6c7b3e1SJorge Lopez [PREREQUISITES_SIZE] = ACPI_TYPE_INTEGER, 123e6c7b3e1SJorge Lopez [PREREQUISITES] = ACPI_TYPE_STRING, 124e6c7b3e1SJorge Lopez [SECURITY_LEVEL] = ACPI_TYPE_INTEGER, 125e6c7b3e1SJorge Lopez [STR_MIN_LENGTH] = ACPI_TYPE_INTEGER, 126e6c7b3e1SJorge Lopez [STR_MAX_LENGTH] = ACPI_TYPE_INTEGER, 127e6c7b3e1SJorge Lopez }; 128e6c7b3e1SJorge Lopez 129e6c7b3e1SJorge Lopez static int hp_populate_string_elements_from_package(union acpi_object *string_obj, 130e6c7b3e1SJorge Lopez int string_obj_count, 131e6c7b3e1SJorge Lopez int instance_id) 132e6c7b3e1SJorge Lopez { 133e6c7b3e1SJorge Lopez char *str_value = NULL; 134e6c7b3e1SJorge Lopez int value_len; 135e6c7b3e1SJorge Lopez int ret = 0; 136e6c7b3e1SJorge Lopez u32 int_value; 137e6c7b3e1SJorge Lopez int elem; 138e6c7b3e1SJorge Lopez int reqs; 139e6c7b3e1SJorge Lopez int eloc; 140e6c7b3e1SJorge Lopez int size; 141e6c7b3e1SJorge Lopez struct string_data *string_data = &bioscfg_drv.string_data[instance_id]; 142e6c7b3e1SJorge Lopez 143e6c7b3e1SJorge Lopez if (!string_obj) 144e6c7b3e1SJorge Lopez return -EINVAL; 145e6c7b3e1SJorge Lopez 146e6c7b3e1SJorge Lopez for (elem = 1, eloc = 1; elem < string_obj_count; elem++, eloc++) { 147e6c7b3e1SJorge Lopez /* ONLY look at the first STRING_ELEM_CNT elements */ 148e6c7b3e1SJorge Lopez if (eloc == STR_ELEM_CNT) 149e6c7b3e1SJorge Lopez goto exit_string_package; 150e6c7b3e1SJorge Lopez 151e6c7b3e1SJorge Lopez switch (string_obj[elem].type) { 152e6c7b3e1SJorge Lopez case ACPI_TYPE_STRING: 153e6c7b3e1SJorge Lopez if (elem != PREREQUISITES) { 154e6c7b3e1SJorge Lopez ret = hp_convert_hexstr_to_str(string_obj[elem].string.pointer, 155e6c7b3e1SJorge Lopez string_obj[elem].string.length, 156e6c7b3e1SJorge Lopez &str_value, &value_len); 157e6c7b3e1SJorge Lopez 158e6c7b3e1SJorge Lopez if (ret) 159e6c7b3e1SJorge Lopez continue; 160e6c7b3e1SJorge Lopez } 161e6c7b3e1SJorge Lopez break; 162e6c7b3e1SJorge Lopez case ACPI_TYPE_INTEGER: 163e6c7b3e1SJorge Lopez int_value = (u32)string_obj[elem].integer.value; 164e6c7b3e1SJorge Lopez break; 165e6c7b3e1SJorge Lopez default: 166e6c7b3e1SJorge Lopez pr_warn("Unsupported object type [%d]\n", string_obj[elem].type); 167e6c7b3e1SJorge Lopez continue; 168e6c7b3e1SJorge Lopez } 169e6c7b3e1SJorge Lopez 170e6c7b3e1SJorge Lopez /* Check that both expected and read object type match */ 171e6c7b3e1SJorge Lopez if (expected_string_types[eloc] != string_obj[elem].type) { 172e6c7b3e1SJorge Lopez pr_err("Error expected type %d for elem %d, but got type %d instead\n", 173e6c7b3e1SJorge Lopez expected_string_types[eloc], elem, string_obj[elem].type); 174*467d4163SJorge Lopez kfree(str_value); 175e6c7b3e1SJorge Lopez return -EIO; 176e6c7b3e1SJorge Lopez } 177e6c7b3e1SJorge Lopez 178e6c7b3e1SJorge Lopez /* Assign appropriate element value to corresponding field*/ 179e6c7b3e1SJorge Lopez switch (eloc) { 180e6c7b3e1SJorge Lopez case VALUE: 181e6c7b3e1SJorge Lopez strscpy(string_data->current_value, 182e6c7b3e1SJorge Lopez str_value, sizeof(string_data->current_value)); 183e6c7b3e1SJorge Lopez break; 184e6c7b3e1SJorge Lopez case PATH: 185e6c7b3e1SJorge Lopez strscpy(string_data->common.path, str_value, 186e6c7b3e1SJorge Lopez sizeof(string_data->common.path)); 187e6c7b3e1SJorge Lopez break; 188e6c7b3e1SJorge Lopez case IS_READONLY: 189e6c7b3e1SJorge Lopez string_data->common.is_readonly = int_value; 190e6c7b3e1SJorge Lopez break; 191e6c7b3e1SJorge Lopez case DISPLAY_IN_UI: 192e6c7b3e1SJorge Lopez string_data->common.display_in_ui = int_value; 193e6c7b3e1SJorge Lopez break; 194e6c7b3e1SJorge Lopez case REQUIRES_PHYSICAL_PRESENCE: 195e6c7b3e1SJorge Lopez string_data->common.requires_physical_presence = int_value; 196e6c7b3e1SJorge Lopez break; 197e6c7b3e1SJorge Lopez case SEQUENCE: 198e6c7b3e1SJorge Lopez string_data->common.sequence = int_value; 199e6c7b3e1SJorge Lopez break; 200e6c7b3e1SJorge Lopez case PREREQUISITES_SIZE: 201e6c7b3e1SJorge Lopez string_data->common.prerequisites_size = int_value; 202e6c7b3e1SJorge Lopez 203e6c7b3e1SJorge Lopez if (string_data->common.prerequisites_size > MAX_PREREQUISITES_SIZE) 204e6c7b3e1SJorge Lopez pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n"); 205e6c7b3e1SJorge Lopez /* 206e6c7b3e1SJorge Lopez * This HACK is needed to keep the expected 207e6c7b3e1SJorge Lopez * element list pointing to the right obj[elem].type 208e6c7b3e1SJorge Lopez * when the size is zero. PREREQUISITES 209e6c7b3e1SJorge Lopez * object is omitted by BIOS when the size is 210e6c7b3e1SJorge Lopez * zero. 211e6c7b3e1SJorge Lopez */ 212e6c7b3e1SJorge Lopez if (string_data->common.prerequisites_size == 0) 213e6c7b3e1SJorge Lopez eloc++; 214e6c7b3e1SJorge Lopez break; 215e6c7b3e1SJorge Lopez case PREREQUISITES: 216e6c7b3e1SJorge Lopez size = min_t(u32, string_data->common.prerequisites_size, 217e6c7b3e1SJorge Lopez MAX_PREREQUISITES_SIZE); 218e6c7b3e1SJorge Lopez 219e6c7b3e1SJorge Lopez for (reqs = 0; reqs < size; reqs++) { 220e6c7b3e1SJorge Lopez if (elem >= string_obj_count) { 221e6c7b3e1SJorge Lopez pr_err("Error elem-objects package is too small\n"); 222e6c7b3e1SJorge Lopez return -EINVAL; 223e6c7b3e1SJorge Lopez } 224e6c7b3e1SJorge Lopez 225e6c7b3e1SJorge Lopez ret = hp_convert_hexstr_to_str(string_obj[elem + reqs].string.pointer, 226e6c7b3e1SJorge Lopez string_obj[elem + reqs].string.length, 227e6c7b3e1SJorge Lopez &str_value, &value_len); 228e6c7b3e1SJorge Lopez 229e6c7b3e1SJorge Lopez if (ret) 230e6c7b3e1SJorge Lopez continue; 231e6c7b3e1SJorge Lopez 232e6c7b3e1SJorge Lopez strscpy(string_data->common.prerequisites[reqs], 233e6c7b3e1SJorge Lopez str_value, 234e6c7b3e1SJorge Lopez sizeof(string_data->common.prerequisites[reqs])); 235e6c7b3e1SJorge Lopez kfree(str_value); 236*467d4163SJorge Lopez str_value = NULL; 237e6c7b3e1SJorge Lopez } 238e6c7b3e1SJorge Lopez break; 239e6c7b3e1SJorge Lopez 240e6c7b3e1SJorge Lopez case SECURITY_LEVEL: 241e6c7b3e1SJorge Lopez string_data->common.security_level = int_value; 242e6c7b3e1SJorge Lopez break; 243e6c7b3e1SJorge Lopez case STR_MIN_LENGTH: 244e6c7b3e1SJorge Lopez string_data->min_length = int_value; 245e6c7b3e1SJorge Lopez break; 246e6c7b3e1SJorge Lopez case STR_MAX_LENGTH: 247e6c7b3e1SJorge Lopez string_data->max_length = int_value; 248e6c7b3e1SJorge Lopez break; 249e6c7b3e1SJorge Lopez default: 250e6c7b3e1SJorge Lopez pr_warn("Invalid element: %d found in String attribute or data may be malformed\n", elem); 251e6c7b3e1SJorge Lopez break; 252e6c7b3e1SJorge Lopez } 253e6c7b3e1SJorge Lopez 254e6c7b3e1SJorge Lopez kfree(str_value); 255*467d4163SJorge Lopez str_value = NULL; 256e6c7b3e1SJorge Lopez } 257e6c7b3e1SJorge Lopez 258e6c7b3e1SJorge Lopez exit_string_package: 259e6c7b3e1SJorge Lopez kfree(str_value); 260e6c7b3e1SJorge Lopez return 0; 261e6c7b3e1SJorge Lopez } 262e6c7b3e1SJorge Lopez 263e6c7b3e1SJorge Lopez /** 264e6c7b3e1SJorge Lopez * hp_populate_string_package_data() - 265e6c7b3e1SJorge Lopez * Populate all properties of an instance under string attribute 266e6c7b3e1SJorge Lopez * 267e6c7b3e1SJorge Lopez * @string_obj: ACPI object with string data 268e6c7b3e1SJorge Lopez * @instance_id: The instance to enumerate 269e6c7b3e1SJorge Lopez * @attr_name_kobj: The parent kernel object 270e6c7b3e1SJorge Lopez */ 271e6c7b3e1SJorge Lopez int hp_populate_string_package_data(union acpi_object *string_obj, 272e6c7b3e1SJorge Lopez int instance_id, 273e6c7b3e1SJorge Lopez struct kobject *attr_name_kobj) 274e6c7b3e1SJorge Lopez { 275e6c7b3e1SJorge Lopez struct string_data *string_data = &bioscfg_drv.string_data[instance_id]; 276e6c7b3e1SJorge Lopez 277e6c7b3e1SJorge Lopez string_data->attr_name_kobj = attr_name_kobj; 278e6c7b3e1SJorge Lopez 279e6c7b3e1SJorge Lopez hp_populate_string_elements_from_package(string_obj, 280e6c7b3e1SJorge Lopez string_obj->package.count, 281e6c7b3e1SJorge Lopez instance_id); 282e6c7b3e1SJorge Lopez 283e6c7b3e1SJorge Lopez hp_update_attribute_permissions(string_data->common.is_readonly, 284e6c7b3e1SJorge Lopez &string_current_val); 285e6c7b3e1SJorge Lopez hp_friendly_user_name_update(string_data->common.path, 286e6c7b3e1SJorge Lopez attr_name_kobj->name, 287e6c7b3e1SJorge Lopez string_data->common.display_name, 288e6c7b3e1SJorge Lopez sizeof(string_data->common.display_name)); 289e6c7b3e1SJorge Lopez return sysfs_create_group(attr_name_kobj, &string_attr_group); 290e6c7b3e1SJorge Lopez } 291e6c7b3e1SJorge Lopez 292e6c7b3e1SJorge Lopez static int hp_populate_string_elements_from_buffer(u8 *buffer_ptr, u32 *buffer_size, 293e6c7b3e1SJorge Lopez int instance_id) 294e6c7b3e1SJorge Lopez { 295e6c7b3e1SJorge Lopez int ret = 0; 296e6c7b3e1SJorge Lopez struct string_data *string_data = &bioscfg_drv.string_data[instance_id]; 297e6c7b3e1SJorge Lopez 298e6c7b3e1SJorge Lopez /* 299e6c7b3e1SJorge Lopez * Only data relevant to this driver and its functionality is 300e6c7b3e1SJorge Lopez * read. BIOS defines the order in which each * element is 301e6c7b3e1SJorge Lopez * read. Element 0 data is not relevant to this 302e6c7b3e1SJorge Lopez * driver hence it is ignored. For clarity, all element names 303e6c7b3e1SJorge Lopez * (DISPLAY_IN_UI) which defines the order in which is read 304e6c7b3e1SJorge Lopez * and the name matches the variable where the data is stored. 305e6c7b3e1SJorge Lopez * 306e6c7b3e1SJorge Lopez * In earlier implementation, reported errors were ignored 307e6c7b3e1SJorge Lopez * causing the data to remain uninitialized. It is not 308e6c7b3e1SJorge Lopez * possible to determine if data read from BIOS is valid or 309e6c7b3e1SJorge Lopez * not. It is for this reason functions may return a error 310e6c7b3e1SJorge Lopez * without validating the data itself. 311e6c7b3e1SJorge Lopez */ 312e6c7b3e1SJorge Lopez 313e6c7b3e1SJorge Lopez // VALUE: 314e6c7b3e1SJorge Lopez ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, string_data->current_value, 315e6c7b3e1SJorge Lopez sizeof(string_data->current_value)); 316e6c7b3e1SJorge Lopez if (ret < 0) 317e6c7b3e1SJorge Lopez goto buffer_exit; 318e6c7b3e1SJorge Lopez 319e6c7b3e1SJorge Lopez // COMMON: 320e6c7b3e1SJorge Lopez ret = hp_get_common_data_from_buffer(&buffer_ptr, buffer_size, &string_data->common); 321e6c7b3e1SJorge Lopez if (ret < 0) 322e6c7b3e1SJorge Lopez goto buffer_exit; 323e6c7b3e1SJorge Lopez 324e6c7b3e1SJorge Lopez // STR_MIN_LENGTH: 325e6c7b3e1SJorge Lopez ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size, 326e6c7b3e1SJorge Lopez &string_data->min_length); 327e6c7b3e1SJorge Lopez if (ret < 0) 328e6c7b3e1SJorge Lopez goto buffer_exit; 329e6c7b3e1SJorge Lopez 330e6c7b3e1SJorge Lopez // STR_MAX_LENGTH: 331e6c7b3e1SJorge Lopez ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size, 332e6c7b3e1SJorge Lopez &string_data->max_length); 333e6c7b3e1SJorge Lopez 334e6c7b3e1SJorge Lopez buffer_exit: 335e6c7b3e1SJorge Lopez 336e6c7b3e1SJorge Lopez return ret; 337e6c7b3e1SJorge Lopez } 338e6c7b3e1SJorge Lopez 339e6c7b3e1SJorge Lopez /** 340e6c7b3e1SJorge Lopez * hp_populate_string_buffer_data() - 341e6c7b3e1SJorge Lopez * Populate all properties of an instance under string attribute 342e6c7b3e1SJorge Lopez * 343e6c7b3e1SJorge Lopez * @buffer_ptr: Buffer pointer 344e6c7b3e1SJorge Lopez * @buffer_size: Buffer size 345e6c7b3e1SJorge Lopez * @instance_id: The instance to enumerate 346e6c7b3e1SJorge Lopez * @attr_name_kobj: The parent kernel object 347e6c7b3e1SJorge Lopez */ 348e6c7b3e1SJorge Lopez int hp_populate_string_buffer_data(u8 *buffer_ptr, u32 *buffer_size, 349e6c7b3e1SJorge Lopez int instance_id, 350e6c7b3e1SJorge Lopez struct kobject *attr_name_kobj) 351e6c7b3e1SJorge Lopez { 352e6c7b3e1SJorge Lopez struct string_data *string_data = &bioscfg_drv.string_data[instance_id]; 353e6c7b3e1SJorge Lopez int ret = 0; 354e6c7b3e1SJorge Lopez 355e6c7b3e1SJorge Lopez string_data->attr_name_kobj = attr_name_kobj; 356e6c7b3e1SJorge Lopez 357e6c7b3e1SJorge Lopez ret = hp_populate_string_elements_from_buffer(buffer_ptr, buffer_size, 358e6c7b3e1SJorge Lopez instance_id); 359e6c7b3e1SJorge Lopez if (ret < 0) 360e6c7b3e1SJorge Lopez return ret; 361e6c7b3e1SJorge Lopez 362e6c7b3e1SJorge Lopez hp_update_attribute_permissions(string_data->common.is_readonly, 363e6c7b3e1SJorge Lopez &string_current_val); 364e6c7b3e1SJorge Lopez hp_friendly_user_name_update(string_data->common.path, 365e6c7b3e1SJorge Lopez attr_name_kobj->name, 366e6c7b3e1SJorge Lopez string_data->common.display_name, 367e6c7b3e1SJorge Lopez sizeof(string_data->common.display_name)); 368e6c7b3e1SJorge Lopez 369e6c7b3e1SJorge Lopez return sysfs_create_group(attr_name_kobj, &string_attr_group); 370e6c7b3e1SJorge Lopez } 371e6c7b3e1SJorge Lopez 372e6c7b3e1SJorge Lopez /** 373e6c7b3e1SJorge Lopez * hp_exit_string_attributes() - Clear all attribute data 374e6c7b3e1SJorge Lopez * 375e6c7b3e1SJorge Lopez * Clears all data allocated for this group of attributes 376e6c7b3e1SJorge Lopez */ 377e6c7b3e1SJorge Lopez void hp_exit_string_attributes(void) 378e6c7b3e1SJorge Lopez { 379e6c7b3e1SJorge Lopez int instance_id; 380e6c7b3e1SJorge Lopez 381e6c7b3e1SJorge Lopez for (instance_id = 0; instance_id < bioscfg_drv.string_instances_count; 382e6c7b3e1SJorge Lopez instance_id++) { 383e6c7b3e1SJorge Lopez struct kobject *attr_name_kobj = 384e6c7b3e1SJorge Lopez bioscfg_drv.string_data[instance_id].attr_name_kobj; 385e6c7b3e1SJorge Lopez 386e6c7b3e1SJorge Lopez if (attr_name_kobj) 387e6c7b3e1SJorge Lopez sysfs_remove_group(attr_name_kobj, &string_attr_group); 388e6c7b3e1SJorge Lopez } 389e6c7b3e1SJorge Lopez bioscfg_drv.string_instances_count = 0; 390e6c7b3e1SJorge Lopez 391e6c7b3e1SJorge Lopez kfree(bioscfg_drv.string_data); 392e6c7b3e1SJorge Lopez bioscfg_drv.string_data = NULL; 393e6c7b3e1SJorge Lopez } 394