1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Functions corresponding to string type attributes under BIOS String GUID for use with |
4 | * dell-wmi-sysman |
5 | * |
6 | * Copyright (c) 2020 Dell Inc. |
7 | */ |
8 | |
9 | #include "dell-wmi-sysman.h" |
10 | |
11 | enum string_properties {MIN_LEN = 6, MAX_LEN}; |
12 | |
13 | get_instance_id(str); |
14 | |
15 | static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) |
16 | { |
17 | int instance_id = get_str_instance_id(kobj); |
18 | union acpi_object *obj; |
19 | ssize_t ret; |
20 | |
21 | if (instance_id < 0) |
22 | return -EIO; |
23 | |
24 | /* need to use specific instance_id and guid combination to get right data */ |
25 | obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID); |
26 | if (!obj) |
27 | return -EIO; |
28 | if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) { |
29 | kfree(objp: obj); |
30 | return -EINVAL; |
31 | } |
32 | ret = snprintf(buf, PAGE_SIZE, fmt: "%s\n" , obj->package.elements[CURRENT_VAL].string.pointer); |
33 | kfree(objp: obj); |
34 | return ret; |
35 | } |
36 | |
37 | /** |
38 | * validate_str_input() - Validate input of current_value against min and max lengths |
39 | * @instance_id: The instance on which input is validated |
40 | * @buf: Input value |
41 | */ |
42 | static int validate_str_input(int instance_id, const char *buf) |
43 | { |
44 | int in_len = strlen(buf); |
45 | |
46 | if ((in_len < wmi_priv.str_data[instance_id].min_length) || |
47 | (in_len > wmi_priv.str_data[instance_id].max_length)) |
48 | return -EINVAL; |
49 | |
50 | return 0; |
51 | } |
52 | |
53 | attribute_s_property_show(display_name_language_code, str); |
54 | static struct kobj_attribute str_displ_langcode = |
55 | __ATTR_RO(display_name_language_code); |
56 | |
57 | attribute_s_property_show(display_name, str); |
58 | static struct kobj_attribute str_displ_name = |
59 | __ATTR_RO(display_name); |
60 | |
61 | attribute_s_property_show(default_value, str); |
62 | static struct kobj_attribute str_default_val = |
63 | __ATTR_RO(default_value); |
64 | |
65 | attribute_property_store(current_value, str); |
66 | static struct kobj_attribute str_current_val = |
67 | __ATTR_RW_MODE(current_value, 0600); |
68 | |
69 | attribute_s_property_show(dell_modifier, str); |
70 | static struct kobj_attribute str_modifier = |
71 | __ATTR_RO(dell_modifier); |
72 | |
73 | attribute_n_property_show(min_length, str); |
74 | static struct kobj_attribute str_min_length = |
75 | __ATTR_RO(min_length); |
76 | |
77 | attribute_n_property_show(max_length, str); |
78 | static struct kobj_attribute str_max_length = |
79 | __ATTR_RO(max_length); |
80 | |
81 | static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, |
82 | char *buf) |
83 | { |
84 | return sprintf(buf, fmt: "string\n" ); |
85 | } |
86 | static struct kobj_attribute str_type = |
87 | __ATTR_RO(type); |
88 | |
89 | static struct attribute *str_attrs[] = { |
90 | &str_displ_langcode.attr, |
91 | &str_displ_name.attr, |
92 | &str_default_val.attr, |
93 | &str_current_val.attr, |
94 | &str_modifier.attr, |
95 | &str_min_length.attr, |
96 | &str_max_length.attr, |
97 | &str_type.attr, |
98 | NULL, |
99 | }; |
100 | |
101 | static const struct attribute_group str_attr_group = { |
102 | .attrs = str_attrs, |
103 | }; |
104 | |
105 | int alloc_str_data(void) |
106 | { |
107 | int ret = 0; |
108 | |
109 | wmi_priv.str_instances_count = get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID); |
110 | wmi_priv.str_data = kcalloc(n: wmi_priv.str_instances_count, |
111 | size: sizeof(struct str_data), GFP_KERNEL); |
112 | if (!wmi_priv.str_data) { |
113 | wmi_priv.str_instances_count = 0; |
114 | ret = -ENOMEM; |
115 | } |
116 | return ret; |
117 | } |
118 | |
119 | /** |
120 | * populate_str_data() - Populate all properties of an instance under string attribute |
121 | * @str_obj: ACPI object with string data |
122 | * @instance_id: The instance to enumerate |
123 | * @attr_name_kobj: The parent kernel object |
124 | */ |
125 | int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj) |
126 | { |
127 | wmi_priv.str_data[instance_id].attr_name_kobj = attr_name_kobj; |
128 | if (check_property_type(str, ATTR_NAME, ACPI_TYPE_STRING)) |
129 | return -EINVAL; |
130 | strlcpy_attr(dest: wmi_priv.str_data[instance_id].attribute_name, |
131 | src: str_obj[ATTR_NAME].string.pointer); |
132 | if (check_property_type(str, DISPL_NAME_LANG_CODE, ACPI_TYPE_STRING)) |
133 | return -EINVAL; |
134 | strlcpy_attr(dest: wmi_priv.str_data[instance_id].display_name_language_code, |
135 | src: str_obj[DISPL_NAME_LANG_CODE].string.pointer); |
136 | if (check_property_type(str, DISPLAY_NAME, ACPI_TYPE_STRING)) |
137 | return -EINVAL; |
138 | strlcpy_attr(dest: wmi_priv.str_data[instance_id].display_name, |
139 | src: str_obj[DISPLAY_NAME].string.pointer); |
140 | if (check_property_type(str, DEFAULT_VAL, ACPI_TYPE_STRING)) |
141 | return -EINVAL; |
142 | strlcpy_attr(dest: wmi_priv.str_data[instance_id].default_value, |
143 | src: str_obj[DEFAULT_VAL].string.pointer); |
144 | if (check_property_type(str, MODIFIER, ACPI_TYPE_STRING)) |
145 | return -EINVAL; |
146 | strlcpy_attr(dest: wmi_priv.str_data[instance_id].dell_modifier, |
147 | src: str_obj[MODIFIER].string.pointer); |
148 | if (check_property_type(str, MIN_LEN, ACPI_TYPE_INTEGER)) |
149 | return -EINVAL; |
150 | wmi_priv.str_data[instance_id].min_length = (uintptr_t)str_obj[MIN_LEN].string.pointer; |
151 | if (check_property_type(str, MAX_LEN, ACPI_TYPE_INTEGER)) |
152 | return -EINVAL; |
153 | wmi_priv.str_data[instance_id].max_length = (uintptr_t) str_obj[MAX_LEN].string.pointer; |
154 | |
155 | return sysfs_create_group(kobj: attr_name_kobj, grp: &str_attr_group); |
156 | } |
157 | |
158 | /** |
159 | * exit_str_attributes() - Clear all attribute data |
160 | * |
161 | * Clears all data allocated for this group of attributes |
162 | */ |
163 | void exit_str_attributes(void) |
164 | { |
165 | int instance_id; |
166 | |
167 | for (instance_id = 0; instance_id < wmi_priv.str_instances_count; instance_id++) { |
168 | if (wmi_priv.str_data[instance_id].attr_name_kobj) |
169 | sysfs_remove_group(kobj: wmi_priv.str_data[instance_id].attr_name_kobj, |
170 | grp: &str_attr_group); |
171 | } |
172 | wmi_priv.str_instances_count = 0; |
173 | |
174 | kfree(objp: wmi_priv.str_data); |
175 | wmi_priv.str_data = NULL; |
176 | } |
177 | |