1a34fc329SJorge Lopez // SPDX-License-Identifier: GPL-2.0
2a34fc329SJorge Lopez /*
3a34fc329SJorge Lopez * Common methods for use with hp-bioscfg driver
4a34fc329SJorge Lopez *
5a34fc329SJorge Lopez * Copyright (c) 2022 HP Development Company, L.P.
6a34fc329SJorge Lopez */
7a34fc329SJorge Lopez
8a34fc329SJorge Lopez #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9a34fc329SJorge Lopez
10a34fc329SJorge Lopez #include <linux/fs.h>
11a34fc329SJorge Lopez #include <linux/module.h>
12a34fc329SJorge Lopez #include <linux/kernel.h>
13a34fc329SJorge Lopez #include <linux/wmi.h>
14a34fc329SJorge Lopez #include "bioscfg.h"
15a34fc329SJorge Lopez #include "../../firmware_attributes_class.h"
16a34fc329SJorge Lopez #include <linux/nls.h>
17a34fc329SJorge Lopez #include <linux/errno.h>
18a34fc329SJorge Lopez
19a34fc329SJorge Lopez MODULE_AUTHOR("Jorge Lopez <jorge.lopez2@hp.com>");
20a34fc329SJorge Lopez MODULE_DESCRIPTION("HP BIOS Configuration Driver");
21a34fc329SJorge Lopez MODULE_LICENSE("GPL");
22a34fc329SJorge Lopez
23a34fc329SJorge Lopez struct bioscfg_priv bioscfg_drv = {
24a34fc329SJorge Lopez .mutex = __MUTEX_INITIALIZER(bioscfg_drv.mutex),
25a34fc329SJorge Lopez };
26a34fc329SJorge Lopez
27a34fc329SJorge Lopez static struct class *fw_attr_class;
28a34fc329SJorge Lopez
display_name_language_code_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)29a34fc329SJorge Lopez ssize_t display_name_language_code_show(struct kobject *kobj,
30a34fc329SJorge Lopez struct kobj_attribute *attr,
31a34fc329SJorge Lopez char *buf)
32a34fc329SJorge Lopez {
33a34fc329SJorge Lopez return sysfs_emit(buf, "%s\n", LANG_CODE_STR);
34a34fc329SJorge Lopez }
35a34fc329SJorge Lopez
36a34fc329SJorge Lopez struct kobj_attribute common_display_langcode =
37a34fc329SJorge Lopez __ATTR_RO(display_name_language_code);
38a34fc329SJorge Lopez
hp_get_integer_from_buffer(u8 ** buffer,u32 * buffer_size,u32 * integer)39a34fc329SJorge Lopez int hp_get_integer_from_buffer(u8 **buffer, u32 *buffer_size, u32 *integer)
40a34fc329SJorge Lopez {
41a34fc329SJorge Lopez int *ptr = PTR_ALIGN((int *)*buffer, sizeof(int));
42a34fc329SJorge Lopez
43a34fc329SJorge Lopez /* Ensure there is enough space remaining to read the integer */
44a34fc329SJorge Lopez if (*buffer_size < sizeof(int))
45a34fc329SJorge Lopez return -EINVAL;
46a34fc329SJorge Lopez
47a34fc329SJorge Lopez *integer = *(ptr++);
48a34fc329SJorge Lopez *buffer = (u8 *)ptr;
49a34fc329SJorge Lopez *buffer_size -= sizeof(int);
50a34fc329SJorge Lopez
51a34fc329SJorge Lopez return 0;
52a34fc329SJorge Lopez }
53a34fc329SJorge Lopez
hp_get_string_from_buffer(u8 ** buffer,u32 * buffer_size,char * dst,u32 dst_size)54a34fc329SJorge Lopez int hp_get_string_from_buffer(u8 **buffer, u32 *buffer_size, char *dst, u32 dst_size)
55a34fc329SJorge Lopez {
56a34fc329SJorge Lopez u16 *src = (u16 *)*buffer;
57a34fc329SJorge Lopez u16 src_size;
58a34fc329SJorge Lopez
59a34fc329SJorge Lopez u16 size;
60a34fc329SJorge Lopez int i;
61a34fc329SJorge Lopez int conv_dst_size;
62a34fc329SJorge Lopez
63a34fc329SJorge Lopez if (*buffer_size < sizeof(u16))
64a34fc329SJorge Lopez return -EINVAL;
65a34fc329SJorge Lopez
66a34fc329SJorge Lopez src_size = *(src++);
67a34fc329SJorge Lopez /* size value in u16 chars */
68a34fc329SJorge Lopez size = src_size / sizeof(u16);
69a34fc329SJorge Lopez
70a34fc329SJorge Lopez /* Ensure there is enough space remaining to read and convert
71a34fc329SJorge Lopez * the string
72a34fc329SJorge Lopez */
73a34fc329SJorge Lopez if (*buffer_size < src_size)
74a34fc329SJorge Lopez return -EINVAL;
75a34fc329SJorge Lopez
76a34fc329SJorge Lopez for (i = 0; i < size; i++)
77a34fc329SJorge Lopez if (src[i] == '\\' ||
78a34fc329SJorge Lopez src[i] == '\r' ||
79a34fc329SJorge Lopez src[i] == '\n' ||
80a34fc329SJorge Lopez src[i] == '\t')
81a34fc329SJorge Lopez size++;
82a34fc329SJorge Lopez
83a34fc329SJorge Lopez /*
84a34fc329SJorge Lopez * Conversion is limited to destination string max number of
85a34fc329SJorge Lopez * bytes.
86a34fc329SJorge Lopez */
87a34fc329SJorge Lopez conv_dst_size = size;
88a34fc329SJorge Lopez if (size > dst_size)
89a34fc329SJorge Lopez conv_dst_size = dst_size - 1;
90a34fc329SJorge Lopez
91a34fc329SJorge Lopez /*
92a34fc329SJorge Lopez * convert from UTF-16 unicode to ASCII
93a34fc329SJorge Lopez */
94a34fc329SJorge Lopez utf16s_to_utf8s(src, src_size, UTF16_HOST_ENDIAN, dst, conv_dst_size);
95a34fc329SJorge Lopez dst[conv_dst_size] = 0;
96a34fc329SJorge Lopez
97b3a8692dSDan Carpenter for (i = 0; i < conv_dst_size; i++) {
98a34fc329SJorge Lopez if (*src == '\\' ||
99a34fc329SJorge Lopez *src == '\r' ||
100a34fc329SJorge Lopez *src == '\n' ||
101b3a8692dSDan Carpenter *src == '\t') {
102a34fc329SJorge Lopez dst[i++] = '\\';
103b3a8692dSDan Carpenter if (i == conv_dst_size)
104b3a8692dSDan Carpenter break;
105b3a8692dSDan Carpenter }
106a34fc329SJorge Lopez
107a34fc329SJorge Lopez if (*src == '\r')
108a34fc329SJorge Lopez dst[i] = 'r';
109a34fc329SJorge Lopez else if (*src == '\n')
110a34fc329SJorge Lopez dst[i] = 'n';
111a34fc329SJorge Lopez else if (*src == '\t')
112a34fc329SJorge Lopez dst[i] = 't';
113a34fc329SJorge Lopez else if (*src == '"')
114a34fc329SJorge Lopez dst[i] = '\'';
115a34fc329SJorge Lopez else
116a34fc329SJorge Lopez dst[i] = *src;
117a34fc329SJorge Lopez src++;
118a34fc329SJorge Lopez }
119a34fc329SJorge Lopez
120a34fc329SJorge Lopez *buffer = (u8 *)src;
121a34fc329SJorge Lopez *buffer_size -= size * sizeof(u16);
122a34fc329SJorge Lopez
123a34fc329SJorge Lopez return size;
124a34fc329SJorge Lopez }
125a34fc329SJorge Lopez
hp_get_common_data_from_buffer(u8 ** buffer_ptr,u32 * buffer_size,struct common_data * common_data)126a34fc329SJorge Lopez int hp_get_common_data_from_buffer(u8 **buffer_ptr, u32 *buffer_size,
127a34fc329SJorge Lopez struct common_data *common_data)
128a34fc329SJorge Lopez {
129a34fc329SJorge Lopez int ret = 0;
130a34fc329SJorge Lopez int reqs;
131a34fc329SJorge Lopez
132a34fc329SJorge Lopez // PATH:
133a34fc329SJorge Lopez ret = hp_get_string_from_buffer(buffer_ptr, buffer_size, common_data->path,
134a34fc329SJorge Lopez sizeof(common_data->path));
135a34fc329SJorge Lopez if (ret < 0)
136a34fc329SJorge Lopez goto common_exit;
137a34fc329SJorge Lopez
138a34fc329SJorge Lopez // IS_READONLY:
139a34fc329SJorge Lopez ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
140a34fc329SJorge Lopez &common_data->is_readonly);
141a34fc329SJorge Lopez if (ret < 0)
142a34fc329SJorge Lopez goto common_exit;
143a34fc329SJorge Lopez
144a34fc329SJorge Lopez //DISPLAY_IN_UI:
145a34fc329SJorge Lopez ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
146a34fc329SJorge Lopez &common_data->display_in_ui);
147a34fc329SJorge Lopez if (ret < 0)
148a34fc329SJorge Lopez goto common_exit;
149a34fc329SJorge Lopez
150a34fc329SJorge Lopez // REQUIRES_PHYSICAL_PRESENCE:
151a34fc329SJorge Lopez ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
152a34fc329SJorge Lopez &common_data->requires_physical_presence);
153a34fc329SJorge Lopez if (ret < 0)
154a34fc329SJorge Lopez goto common_exit;
155a34fc329SJorge Lopez
156a34fc329SJorge Lopez // SEQUENCE:
157a34fc329SJorge Lopez ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
158a34fc329SJorge Lopez &common_data->sequence);
159a34fc329SJorge Lopez if (ret < 0)
160a34fc329SJorge Lopez goto common_exit;
161a34fc329SJorge Lopez
162a34fc329SJorge Lopez // PREREQUISITES_SIZE:
163a34fc329SJorge Lopez ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
164a34fc329SJorge Lopez &common_data->prerequisites_size);
165a34fc329SJorge Lopez if (ret < 0)
166a34fc329SJorge Lopez goto common_exit;
167a34fc329SJorge Lopez
168a34fc329SJorge Lopez if (common_data->prerequisites_size > MAX_PREREQUISITES_SIZE) {
169a34fc329SJorge Lopez /* Report a message and limit prerequisite size to maximum value */
170a34fc329SJorge Lopez pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
171a34fc329SJorge Lopez common_data->prerequisites_size = MAX_PREREQUISITES_SIZE;
172a34fc329SJorge Lopez }
173a34fc329SJorge Lopez
174a34fc329SJorge Lopez // PREREQUISITES:
175a34fc329SJorge Lopez for (reqs = 0; reqs < common_data->prerequisites_size; reqs++) {
176a34fc329SJorge Lopez ret = hp_get_string_from_buffer(buffer_ptr, buffer_size,
177a34fc329SJorge Lopez common_data->prerequisites[reqs],
178a34fc329SJorge Lopez sizeof(common_data->prerequisites[reqs]));
179a34fc329SJorge Lopez if (ret < 0)
180a34fc329SJorge Lopez break;
181a34fc329SJorge Lopez }
182a34fc329SJorge Lopez
183a34fc329SJorge Lopez // SECURITY_LEVEL:
184a34fc329SJorge Lopez ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
185a34fc329SJorge Lopez &common_data->security_level);
186a34fc329SJorge Lopez
187a34fc329SJorge Lopez common_exit:
188a34fc329SJorge Lopez return ret;
189a34fc329SJorge Lopez }
190a34fc329SJorge Lopez
hp_enforce_single_line_input(char * buf,size_t count)191a34fc329SJorge Lopez int hp_enforce_single_line_input(char *buf, size_t count)
192a34fc329SJorge Lopez {
193a34fc329SJorge Lopez char *p;
194a34fc329SJorge Lopez
195a34fc329SJorge Lopez p = memchr(buf, '\n', count);
196a34fc329SJorge Lopez
197a34fc329SJorge Lopez if (p == buf + count - 1)
198a34fc329SJorge Lopez *p = '\0'; /* strip trailing newline */
199a34fc329SJorge Lopez else if (p)
200a34fc329SJorge Lopez return -EINVAL; /* enforce single line input */
201a34fc329SJorge Lopez
202a34fc329SJorge Lopez return 0;
203a34fc329SJorge Lopez }
204a34fc329SJorge Lopez
205a34fc329SJorge Lopez /* Set pending reboot value and generate KOBJ_NAME event */
hp_set_reboot_and_signal_event(void)206a34fc329SJorge Lopez void hp_set_reboot_and_signal_event(void)
207a34fc329SJorge Lopez {
208a34fc329SJorge Lopez bioscfg_drv.pending_reboot = true;
209a34fc329SJorge Lopez kobject_uevent(&bioscfg_drv.class_dev->kobj, KOBJ_CHANGE);
210a34fc329SJorge Lopez }
211a34fc329SJorge Lopez
212a34fc329SJorge Lopez /**
213a34fc329SJorge Lopez * hp_calculate_string_buffer() - determines size of string buffer for
214a34fc329SJorge Lopez * use with BIOS communication
215a34fc329SJorge Lopez *
216a34fc329SJorge Lopez * @str: the string to calculate based upon
217a34fc329SJorge Lopez */
hp_calculate_string_buffer(const char * str)218a34fc329SJorge Lopez size_t hp_calculate_string_buffer(const char *str)
219a34fc329SJorge Lopez {
220a34fc329SJorge Lopez size_t length = strlen(str);
221a34fc329SJorge Lopez
222a34fc329SJorge Lopez /* BIOS expects 4 bytes when an empty string is found */
223a34fc329SJorge Lopez if (length == 0)
224a34fc329SJorge Lopez return 4;
225a34fc329SJorge Lopez
226a34fc329SJorge Lopez /* u16 length field + one UTF16 char for each input char */
227a34fc329SJorge Lopez return sizeof(u16) + strlen(str) * sizeof(u16);
228a34fc329SJorge Lopez }
229a34fc329SJorge Lopez
hp_wmi_error_and_message(int error_code)230a34fc329SJorge Lopez int hp_wmi_error_and_message(int error_code)
231a34fc329SJorge Lopez {
232a34fc329SJorge Lopez char *error_msg = NULL;
233a34fc329SJorge Lopez int ret;
234a34fc329SJorge Lopez
235a34fc329SJorge Lopez switch (error_code) {
236a34fc329SJorge Lopez case SUCCESS:
237a34fc329SJorge Lopez error_msg = "Success";
238a34fc329SJorge Lopez ret = 0;
239a34fc329SJorge Lopez break;
240a34fc329SJorge Lopez case CMD_FAILED:
241a34fc329SJorge Lopez error_msg = "Command failed";
242a34fc329SJorge Lopez ret = -EINVAL;
243a34fc329SJorge Lopez break;
244a34fc329SJorge Lopez case INVALID_SIGN:
245a34fc329SJorge Lopez error_msg = "Invalid signature";
246a34fc329SJorge Lopez ret = -EINVAL;
247a34fc329SJorge Lopez break;
248a34fc329SJorge Lopez case INVALID_CMD_VALUE:
249a34fc329SJorge Lopez error_msg = "Invalid command value/Feature not supported";
250a34fc329SJorge Lopez ret = -EOPNOTSUPP;
251a34fc329SJorge Lopez break;
252a34fc329SJorge Lopez case INVALID_CMD_TYPE:
253a34fc329SJorge Lopez error_msg = "Invalid command type";
254a34fc329SJorge Lopez ret = -EINVAL;
255a34fc329SJorge Lopez break;
256a34fc329SJorge Lopez case INVALID_DATA_SIZE:
257a34fc329SJorge Lopez error_msg = "Invalid data size";
258a34fc329SJorge Lopez ret = -EINVAL;
259a34fc329SJorge Lopez break;
260a34fc329SJorge Lopez case INVALID_CMD_PARAM:
261a34fc329SJorge Lopez error_msg = "Invalid command parameter";
262a34fc329SJorge Lopez ret = -EINVAL;
263a34fc329SJorge Lopez break;
264a34fc329SJorge Lopez case ENCRYP_CMD_REQUIRED:
265a34fc329SJorge Lopez error_msg = "Secure/encrypted command required";
266a34fc329SJorge Lopez ret = -EACCES;
267a34fc329SJorge Lopez break;
268a34fc329SJorge Lopez case NO_SECURE_SESSION:
269a34fc329SJorge Lopez error_msg = "No secure session established";
270a34fc329SJorge Lopez ret = -EACCES;
271a34fc329SJorge Lopez break;
272a34fc329SJorge Lopez case SECURE_SESSION_FOUND:
273a34fc329SJorge Lopez error_msg = "Secure session already established";
274a34fc329SJorge Lopez ret = -EACCES;
275a34fc329SJorge Lopez break;
276a34fc329SJorge Lopez case SECURE_SESSION_FAILED:
277a34fc329SJorge Lopez error_msg = "Secure session failed";
278a34fc329SJorge Lopez ret = -EIO;
279a34fc329SJorge Lopez break;
280a34fc329SJorge Lopez case AUTH_FAILED:
281a34fc329SJorge Lopez error_msg = "Other permission/Authentication failed";
282a34fc329SJorge Lopez ret = -EACCES;
283a34fc329SJorge Lopez break;
284a34fc329SJorge Lopez case INVALID_BIOS_AUTH:
285a34fc329SJorge Lopez error_msg = "Invalid BIOS administrator password";
286a34fc329SJorge Lopez ret = -EINVAL;
287a34fc329SJorge Lopez break;
288a34fc329SJorge Lopez case NONCE_DID_NOT_MATCH:
289a34fc329SJorge Lopez error_msg = "Nonce did not match";
290a34fc329SJorge Lopez ret = -EINVAL;
291a34fc329SJorge Lopez break;
292a34fc329SJorge Lopez case GENERIC_ERROR:
293a34fc329SJorge Lopez error_msg = "Generic/Other error";
294a34fc329SJorge Lopez ret = -EIO;
295a34fc329SJorge Lopez break;
296a34fc329SJorge Lopez case BIOS_ADMIN_POLICY_NOT_MET:
297a34fc329SJorge Lopez error_msg = "BIOS Admin password does not meet password policy requirements";
298a34fc329SJorge Lopez ret = -EINVAL;
299a34fc329SJorge Lopez break;
300a34fc329SJorge Lopez case BIOS_ADMIN_NOT_SET:
301a34fc329SJorge Lopez error_msg = "BIOS Setup password is not set";
302a34fc329SJorge Lopez ret = -EPERM;
303a34fc329SJorge Lopez break;
304a34fc329SJorge Lopez case P21_NO_PROVISIONED:
305a34fc329SJorge Lopez error_msg = "P21 is not provisioned";
306a34fc329SJorge Lopez ret = -EPERM;
307a34fc329SJorge Lopez break;
308a34fc329SJorge Lopez case P21_PROVISION_IN_PROGRESS:
309a34fc329SJorge Lopez error_msg = "P21 is already provisioned or provisioning is in progress and a signing key has already been sent";
310a34fc329SJorge Lopez ret = -EINPROGRESS;
311a34fc329SJorge Lopez break;
312a34fc329SJorge Lopez case P21_IN_USE:
313a34fc329SJorge Lopez error_msg = "P21 in use (cannot deprovision)";
314a34fc329SJorge Lopez ret = -EPERM;
315a34fc329SJorge Lopez break;
316a34fc329SJorge Lopez case HEP_NOT_ACTIVE:
317a34fc329SJorge Lopez error_msg = "HEP not activated";
318a34fc329SJorge Lopez ret = -EPERM;
319a34fc329SJorge Lopez break;
320a34fc329SJorge Lopez case HEP_ALREADY_SET:
321a34fc329SJorge Lopez error_msg = "HEP Transport already set";
322a34fc329SJorge Lopez ret = -EINVAL;
323a34fc329SJorge Lopez break;
324a34fc329SJorge Lopez case HEP_CHECK_STATE:
325a34fc329SJorge Lopez error_msg = "Check the current HEP state";
326a34fc329SJorge Lopez ret = -EINVAL;
327a34fc329SJorge Lopez break;
328a34fc329SJorge Lopez default:
329a34fc329SJorge Lopez error_msg = "Generic/Other error";
330a34fc329SJorge Lopez ret = -EIO;
331a34fc329SJorge Lopez break;
332a34fc329SJorge Lopez }
333a34fc329SJorge Lopez
334a34fc329SJorge Lopez if (error_code)
335a34fc329SJorge Lopez pr_warn_ratelimited("Returned error 0x%x, \"%s\"\n", error_code, error_msg);
336a34fc329SJorge Lopez
337a34fc329SJorge Lopez return ret;
338a34fc329SJorge Lopez }
339a34fc329SJorge Lopez
pending_reboot_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)340a34fc329SJorge Lopez static ssize_t pending_reboot_show(struct kobject *kobj,
341a34fc329SJorge Lopez struct kobj_attribute *attr,
342a34fc329SJorge Lopez char *buf)
343a34fc329SJorge Lopez {
344a34fc329SJorge Lopez return sysfs_emit(buf, "%d\n", bioscfg_drv.pending_reboot);
345a34fc329SJorge Lopez }
346a34fc329SJorge Lopez
347a34fc329SJorge Lopez static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
348a34fc329SJorge Lopez
349a34fc329SJorge Lopez /*
350a34fc329SJorge Lopez * create_attributes_level_sysfs_files() - Creates pending_reboot attributes
351a34fc329SJorge Lopez */
create_attributes_level_sysfs_files(void)352a34fc329SJorge Lopez static int create_attributes_level_sysfs_files(void)
353a34fc329SJorge Lopez {
354a34fc329SJorge Lopez return sysfs_create_file(&bioscfg_drv.main_dir_kset->kobj,
355a34fc329SJorge Lopez &pending_reboot.attr);
356a34fc329SJorge Lopez }
357a34fc329SJorge Lopez
attr_name_release(struct kobject * kobj)358a34fc329SJorge Lopez static void attr_name_release(struct kobject *kobj)
359a34fc329SJorge Lopez {
360a34fc329SJorge Lopez kfree(kobj);
361a34fc329SJorge Lopez }
362a34fc329SJorge Lopez
363a34fc329SJorge Lopez static const struct kobj_type attr_name_ktype = {
364a34fc329SJorge Lopez .release = attr_name_release,
365a34fc329SJorge Lopez .sysfs_ops = &kobj_sysfs_ops,
366a34fc329SJorge Lopez };
367a34fc329SJorge Lopez
368a34fc329SJorge Lopez /**
369a34fc329SJorge Lopez * hp_get_wmiobj_pointer() - Get Content of WMI block for particular instance
370a34fc329SJorge Lopez *
371a34fc329SJorge Lopez * @instance_id: WMI instance ID
372a34fc329SJorge Lopez * @guid_string: WMI GUID (in str form)
373a34fc329SJorge Lopez *
374a34fc329SJorge Lopez * Fetches the content for WMI block (instance_id) under GUID (guid_string)
375a34fc329SJorge Lopez * Caller must kfree the return
376a34fc329SJorge Lopez */
hp_get_wmiobj_pointer(int instance_id,const char * guid_string)377a34fc329SJorge Lopez union acpi_object *hp_get_wmiobj_pointer(int instance_id, const char *guid_string)
378a34fc329SJorge Lopez {
379a34fc329SJorge Lopez struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
380a34fc329SJorge Lopez acpi_status status;
381a34fc329SJorge Lopez
382a34fc329SJorge Lopez status = wmi_query_block(guid_string, instance_id, &out);
383a34fc329SJorge Lopez return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
384a34fc329SJorge Lopez }
385a34fc329SJorge Lopez
386a34fc329SJorge Lopez /**
387a34fc329SJorge Lopez * hp_get_instance_count() - Compute total number of instances under guid_string
388a34fc329SJorge Lopez *
389a34fc329SJorge Lopez * @guid_string: WMI GUID (in string form)
390a34fc329SJorge Lopez */
hp_get_instance_count(const char * guid_string)391a34fc329SJorge Lopez int hp_get_instance_count(const char *guid_string)
392a34fc329SJorge Lopez {
393a34fc329SJorge Lopez union acpi_object *wmi_obj = NULL;
394a34fc329SJorge Lopez int i = 0;
395a34fc329SJorge Lopez
396a34fc329SJorge Lopez do {
397a34fc329SJorge Lopez kfree(wmi_obj);
398a34fc329SJorge Lopez wmi_obj = hp_get_wmiobj_pointer(i, guid_string);
399a34fc329SJorge Lopez i++;
400a34fc329SJorge Lopez } while (wmi_obj);
401a34fc329SJorge Lopez
402a34fc329SJorge Lopez return i - 1;
403a34fc329SJorge Lopez }
404a34fc329SJorge Lopez
405a34fc329SJorge Lopez /**
406a34fc329SJorge Lopez * hp_alloc_attributes_data() - Allocate attributes data for a particular type
407a34fc329SJorge Lopez *
408a34fc329SJorge Lopez * @attr_type: Attribute type to allocate
409a34fc329SJorge Lopez */
hp_alloc_attributes_data(int attr_type)410a34fc329SJorge Lopez static int hp_alloc_attributes_data(int attr_type)
411a34fc329SJorge Lopez {
412a34fc329SJorge Lopez switch (attr_type) {
413a34fc329SJorge Lopez case HPWMI_STRING_TYPE:
414a34fc329SJorge Lopez return hp_alloc_string_data();
415a34fc329SJorge Lopez
416a34fc329SJorge Lopez case HPWMI_INTEGER_TYPE:
417a34fc329SJorge Lopez return hp_alloc_integer_data();
418a34fc329SJorge Lopez
419a34fc329SJorge Lopez case HPWMI_ENUMERATION_TYPE:
420a34fc329SJorge Lopez return hp_alloc_enumeration_data();
421a34fc329SJorge Lopez
422a34fc329SJorge Lopez case HPWMI_ORDERED_LIST_TYPE:
423a34fc329SJorge Lopez return hp_alloc_ordered_list_data();
424a34fc329SJorge Lopez
425a34fc329SJorge Lopez case HPWMI_PASSWORD_TYPE:
426a34fc329SJorge Lopez return hp_alloc_password_data();
427a34fc329SJorge Lopez
428a34fc329SJorge Lopez default:
429a34fc329SJorge Lopez return 0;
430a34fc329SJorge Lopez }
431a34fc329SJorge Lopez }
432a34fc329SJorge Lopez
hp_convert_hexstr_to_str(const char * input,u32 input_len,char ** str,int * len)433a34fc329SJorge Lopez int hp_convert_hexstr_to_str(const char *input, u32 input_len, char **str, int *len)
434a34fc329SJorge Lopez {
435a34fc329SJorge Lopez int ret = 0;
436a34fc329SJorge Lopez int new_len = 0;
437a34fc329SJorge Lopez char tmp[] = "0x00";
438a34fc329SJorge Lopez char *new_str = NULL;
439a34fc329SJorge Lopez long ch;
440a34fc329SJorge Lopez int i;
441a34fc329SJorge Lopez
442a34fc329SJorge Lopez if (input_len <= 0 || !input || !str || !len)
443a34fc329SJorge Lopez return -EINVAL;
444a34fc329SJorge Lopez
445a34fc329SJorge Lopez *len = 0;
446a34fc329SJorge Lopez *str = NULL;
447a34fc329SJorge Lopez
448a34fc329SJorge Lopez new_str = kmalloc(input_len, GFP_KERNEL);
449a34fc329SJorge Lopez if (!new_str)
450a34fc329SJorge Lopez return -ENOMEM;
451a34fc329SJorge Lopez
452a34fc329SJorge Lopez for (i = 0; i < input_len; i += 5) {
453a34fc329SJorge Lopez strncpy(tmp, input + i, strlen(tmp));
454a34fc329SJorge Lopez if (kstrtol(tmp, 16, &ch) == 0) {
455a34fc329SJorge Lopez // escape char
456a34fc329SJorge Lopez if (ch == '\\' ||
457a34fc329SJorge Lopez ch == '\r' ||
458a34fc329SJorge Lopez ch == '\n' || ch == '\t') {
459a34fc329SJorge Lopez if (ch == '\r')
460a34fc329SJorge Lopez ch = 'r';
461a34fc329SJorge Lopez else if (ch == '\n')
462a34fc329SJorge Lopez ch = 'n';
463a34fc329SJorge Lopez else if (ch == '\t')
464a34fc329SJorge Lopez ch = 't';
465a34fc329SJorge Lopez new_str[new_len++] = '\\';
466a34fc329SJorge Lopez }
467a34fc329SJorge Lopez new_str[new_len++] = ch;
468a34fc329SJorge Lopez if (ch == '\0')
469a34fc329SJorge Lopez break;
470a34fc329SJorge Lopez }
471a34fc329SJorge Lopez }
472a34fc329SJorge Lopez
473a34fc329SJorge Lopez if (new_len) {
474a34fc329SJorge Lopez new_str[new_len] = '\0';
475a34fc329SJorge Lopez *str = krealloc(new_str, (new_len + 1) * sizeof(char),
476a34fc329SJorge Lopez GFP_KERNEL);
477a34fc329SJorge Lopez if (*str)
478a34fc329SJorge Lopez *len = new_len;
479a34fc329SJorge Lopez else
480a34fc329SJorge Lopez ret = -ENOMEM;
481a34fc329SJorge Lopez } else {
482a34fc329SJorge Lopez ret = -EFAULT;
483a34fc329SJorge Lopez }
484a34fc329SJorge Lopez
485a34fc329SJorge Lopez if (ret)
486a34fc329SJorge Lopez kfree(new_str);
487a34fc329SJorge Lopez return ret;
488a34fc329SJorge Lopez }
489a34fc329SJorge Lopez
490a34fc329SJorge Lopez /* map output size to the corresponding WMI method id */
hp_encode_outsize_for_pvsz(int outsize)491a34fc329SJorge Lopez int hp_encode_outsize_for_pvsz(int outsize)
492a34fc329SJorge Lopez {
493a34fc329SJorge Lopez if (outsize > 4096)
494a34fc329SJorge Lopez return -EINVAL;
495a34fc329SJorge Lopez if (outsize > 1024)
496a34fc329SJorge Lopez return 5;
497a34fc329SJorge Lopez if (outsize > 128)
498a34fc329SJorge Lopez return 4;
499a34fc329SJorge Lopez if (outsize > 4)
500a34fc329SJorge Lopez return 3;
501a34fc329SJorge Lopez if (outsize > 0)
502a34fc329SJorge Lopez return 2;
503a34fc329SJorge Lopez return 1;
504a34fc329SJorge Lopez }
505a34fc329SJorge Lopez
506a34fc329SJorge Lopez /*
507a34fc329SJorge Lopez * Update friendly display name for several attributes associated to
508a34fc329SJorge Lopez * 'Schedule Power-On'
509a34fc329SJorge Lopez */
hp_friendly_user_name_update(char * path,const char * attr_name,char * attr_display,int attr_size)510a34fc329SJorge Lopez void hp_friendly_user_name_update(char *path, const char *attr_name,
511a34fc329SJorge Lopez char *attr_display, int attr_size)
512a34fc329SJorge Lopez {
513a34fc329SJorge Lopez if (strstr(path, SCHEDULE_POWER_ON))
514a34fc329SJorge Lopez snprintf(attr_display, attr_size, "%s - %s", SCHEDULE_POWER_ON, attr_name);
515a34fc329SJorge Lopez else
516a34fc329SJorge Lopez strscpy(attr_display, attr_name, attr_size);
517a34fc329SJorge Lopez }
518a34fc329SJorge Lopez
519a34fc329SJorge Lopez /**
520a34fc329SJorge Lopez * hp_update_attribute_permissions() - Update attributes permissions when
521a34fc329SJorge Lopez * isReadOnly value is 1
522a34fc329SJorge Lopez *
523a34fc329SJorge Lopez * @is_readonly: bool value to indicate if it a readonly attribute.
524a34fc329SJorge Lopez * @current_val: kobj_attribute corresponding to attribute.
525a34fc329SJorge Lopez *
526a34fc329SJorge Lopez */
hp_update_attribute_permissions(bool is_readonly,struct kobj_attribute * current_val)527a34fc329SJorge Lopez void hp_update_attribute_permissions(bool is_readonly, struct kobj_attribute *current_val)
528a34fc329SJorge Lopez {
529a34fc329SJorge Lopez current_val->attr.mode = is_readonly ? 0444 : 0644;
530a34fc329SJorge Lopez }
531a34fc329SJorge Lopez
532a34fc329SJorge Lopez /**
533a34fc329SJorge Lopez * destroy_attribute_objs() - Free a kset of kobjects
534a34fc329SJorge Lopez * @kset: The kset to destroy
535a34fc329SJorge Lopez *
536a34fc329SJorge Lopez * Fress kobjects created for each attribute_name under attribute type kset
537a34fc329SJorge Lopez */
destroy_attribute_objs(struct kset * kset)538a34fc329SJorge Lopez static void destroy_attribute_objs(struct kset *kset)
539a34fc329SJorge Lopez {
540a34fc329SJorge Lopez struct kobject *pos, *next;
541a34fc329SJorge Lopez
542a34fc329SJorge Lopez list_for_each_entry_safe(pos, next, &kset->list, entry)
543a34fc329SJorge Lopez kobject_put(pos);
544a34fc329SJorge Lopez }
545a34fc329SJorge Lopez
546a34fc329SJorge Lopez /**
547a34fc329SJorge Lopez * release_attributes_data() - Clean-up all sysfs directories and files created
548a34fc329SJorge Lopez */
release_attributes_data(void)549a34fc329SJorge Lopez static void release_attributes_data(void)
550a34fc329SJorge Lopez {
551a34fc329SJorge Lopez mutex_lock(&bioscfg_drv.mutex);
552a34fc329SJorge Lopez
553a34fc329SJorge Lopez hp_exit_string_attributes();
554a34fc329SJorge Lopez hp_exit_integer_attributes();
555a34fc329SJorge Lopez hp_exit_enumeration_attributes();
556a34fc329SJorge Lopez hp_exit_ordered_list_attributes();
557a34fc329SJorge Lopez hp_exit_password_attributes();
558a34fc329SJorge Lopez hp_exit_sure_start_attributes();
559a34fc329SJorge Lopez hp_exit_secure_platform_attributes();
560a34fc329SJorge Lopez
561a34fc329SJorge Lopez if (bioscfg_drv.authentication_dir_kset) {
562a34fc329SJorge Lopez destroy_attribute_objs(bioscfg_drv.authentication_dir_kset);
563a34fc329SJorge Lopez kset_unregister(bioscfg_drv.authentication_dir_kset);
564a34fc329SJorge Lopez bioscfg_drv.authentication_dir_kset = NULL;
565a34fc329SJorge Lopez }
566a34fc329SJorge Lopez if (bioscfg_drv.main_dir_kset) {
567a34fc329SJorge Lopez sysfs_remove_file(&bioscfg_drv.main_dir_kset->kobj, &pending_reboot.attr);
568a34fc329SJorge Lopez destroy_attribute_objs(bioscfg_drv.main_dir_kset);
569a34fc329SJorge Lopez kset_unregister(bioscfg_drv.main_dir_kset);
570a34fc329SJorge Lopez bioscfg_drv.main_dir_kset = NULL;
571a34fc329SJorge Lopez }
572a34fc329SJorge Lopez mutex_unlock(&bioscfg_drv.mutex);
573a34fc329SJorge Lopez }
574a34fc329SJorge Lopez
575a34fc329SJorge Lopez /**
576a34fc329SJorge Lopez * hp_add_other_attributes() - Initialize HP custom attributes not
577a34fc329SJorge Lopez * reported by BIOS and required to support Secure Platform and Sure
578a34fc329SJorge Lopez * Start.
579a34fc329SJorge Lopez *
580a34fc329SJorge Lopez * @attr_type: Custom HP attribute not reported by BIOS
581a34fc329SJorge Lopez *
582a34fc329SJorge Lopez * Initialize all 2 types of attributes: Platform and Sure Start
583a34fc329SJorge Lopez * object. Populates each attribute types respective properties
584a34fc329SJorge Lopez * under sysfs files.
585a34fc329SJorge Lopez *
586a34fc329SJorge Lopez * Returns zero(0) if successful. Otherwise, a negative value.
587a34fc329SJorge Lopez */
hp_add_other_attributes(int attr_type)588a34fc329SJorge Lopez static int hp_add_other_attributes(int attr_type)
589a34fc329SJorge Lopez {
590a34fc329SJorge Lopez struct kobject *attr_name_kobj;
591a34fc329SJorge Lopez union acpi_object *obj = NULL;
592a34fc329SJorge Lopez int ret;
593a34fc329SJorge Lopez char *attr_name;
594a34fc329SJorge Lopez
595a34fc329SJorge Lopez attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
596e73ebb93SHarshit Mogalapalli if (!attr_name_kobj)
597e73ebb93SHarshit Mogalapalli return -ENOMEM;
598e73ebb93SHarshit Mogalapalli
599e73ebb93SHarshit Mogalapalli mutex_lock(&bioscfg_drv.mutex);
600a34fc329SJorge Lopez
601a34fc329SJorge Lopez /* Check if attribute type is supported */
602a34fc329SJorge Lopez switch (attr_type) {
603a34fc329SJorge Lopez case HPWMI_SECURE_PLATFORM_TYPE:
604a34fc329SJorge Lopez attr_name_kobj->kset = bioscfg_drv.authentication_dir_kset;
605a34fc329SJorge Lopez attr_name = SPM_STR;
606a34fc329SJorge Lopez break;
607a34fc329SJorge Lopez
608a34fc329SJorge Lopez case HPWMI_SURE_START_TYPE:
609a34fc329SJorge Lopez attr_name_kobj->kset = bioscfg_drv.main_dir_kset;
610a34fc329SJorge Lopez attr_name = SURE_START_STR;
611a34fc329SJorge Lopez break;
612a34fc329SJorge Lopez
613a34fc329SJorge Lopez default:
614a34fc329SJorge Lopez pr_err("Error: Unknown attr_type: %d\n", attr_type);
615a34fc329SJorge Lopez ret = -EINVAL;
616*9a98ab01SHarshit Mogalapalli kfree(attr_name_kobj);
617*9a98ab01SHarshit Mogalapalli goto unlock_drv_mutex;
618a34fc329SJorge Lopez }
619a34fc329SJorge Lopez
620a34fc329SJorge Lopez ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,
621a34fc329SJorge Lopez NULL, "%s", attr_name);
622a34fc329SJorge Lopez if (ret) {
623a34fc329SJorge Lopez pr_err("Error encountered [%d]\n", ret);
624a34fc329SJorge Lopez goto err_other_attr_init;
625a34fc329SJorge Lopez }
626a34fc329SJorge Lopez
627a34fc329SJorge Lopez /* Populate attribute data */
628a34fc329SJorge Lopez switch (attr_type) {
629a34fc329SJorge Lopez case HPWMI_SECURE_PLATFORM_TYPE:
630a34fc329SJorge Lopez ret = hp_populate_secure_platform_data(attr_name_kobj);
631a34fc329SJorge Lopez break;
632a34fc329SJorge Lopez
633a34fc329SJorge Lopez case HPWMI_SURE_START_TYPE:
634a34fc329SJorge Lopez ret = hp_populate_sure_start_data(attr_name_kobj);
635a34fc329SJorge Lopez break;
636a34fc329SJorge Lopez
637a34fc329SJorge Lopez default:
638d4e695c0SDan Carpenter ret = -EINVAL;
639a34fc329SJorge Lopez }
640a34fc329SJorge Lopez
641a9dc6f2eSHarshit Mogalapalli if (ret)
642a9dc6f2eSHarshit Mogalapalli goto err_other_attr_init;
643a9dc6f2eSHarshit Mogalapalli
644a34fc329SJorge Lopez mutex_unlock(&bioscfg_drv.mutex);
645a34fc329SJorge Lopez return 0;
646a34fc329SJorge Lopez
647a34fc329SJorge Lopez err_other_attr_init:
648*9a98ab01SHarshit Mogalapalli kobject_put(attr_name_kobj);
649*9a98ab01SHarshit Mogalapalli unlock_drv_mutex:
650a34fc329SJorge Lopez mutex_unlock(&bioscfg_drv.mutex);
651a34fc329SJorge Lopez kfree(obj);
652a34fc329SJorge Lopez return ret;
653a34fc329SJorge Lopez }
654a34fc329SJorge Lopez
hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type,union acpi_object * obj,const char * guid,int min_elements,int instance_id)655a34fc329SJorge Lopez static int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type,
656a34fc329SJorge Lopez union acpi_object *obj,
657a34fc329SJorge Lopez const char *guid, int min_elements,
658a34fc329SJorge Lopez int instance_id)
659a34fc329SJorge Lopez {
660981368e1SArmin Wolf struct kobject *attr_name_kobj, *duplicate;
661a34fc329SJorge Lopez union acpi_object *elements;
662a34fc329SJorge Lopez struct kset *temp_kset;
663a34fc329SJorge Lopez
664a34fc329SJorge Lopez char *str_value = NULL;
665a34fc329SJorge Lopez int str_len;
666a34fc329SJorge Lopez int ret = 0;
667a34fc329SJorge Lopez
668a34fc329SJorge Lopez /* Take action appropriate to each ACPI TYPE */
669a34fc329SJorge Lopez if (obj->package.count < min_elements) {
670a34fc329SJorge Lopez pr_err("ACPI-package does not have enough elements: %d < %d\n",
671a34fc329SJorge Lopez obj->package.count, min_elements);
672a34fc329SJorge Lopez goto pack_attr_exit;
673a34fc329SJorge Lopez }
674a34fc329SJorge Lopez
675a34fc329SJorge Lopez elements = obj->package.elements;
676a34fc329SJorge Lopez
677a34fc329SJorge Lopez /* sanity checking */
678a34fc329SJorge Lopez if (elements[NAME].type != ACPI_TYPE_STRING) {
679a34fc329SJorge Lopez pr_debug("incorrect element type\n");
680a34fc329SJorge Lopez goto pack_attr_exit;
681a34fc329SJorge Lopez }
682a34fc329SJorge Lopez if (strlen(elements[NAME].string.pointer) == 0) {
683a34fc329SJorge Lopez pr_debug("empty attribute found\n");
684a34fc329SJorge Lopez goto pack_attr_exit;
685a34fc329SJorge Lopez }
686a34fc329SJorge Lopez
687a34fc329SJorge Lopez if (attr_type == HPWMI_PASSWORD_TYPE)
688a34fc329SJorge Lopez temp_kset = bioscfg_drv.authentication_dir_kset;
689a34fc329SJorge Lopez else
690a34fc329SJorge Lopez temp_kset = bioscfg_drv.main_dir_kset;
691a34fc329SJorge Lopez
692a34fc329SJorge Lopez /* convert attribute name to string */
693a34fc329SJorge Lopez ret = hp_convert_hexstr_to_str(elements[NAME].string.pointer,
694a34fc329SJorge Lopez elements[NAME].string.length,
695a34fc329SJorge Lopez &str_value, &str_len);
696a34fc329SJorge Lopez
697a34fc329SJorge Lopez if (ret) {
698a34fc329SJorge Lopez pr_debug("Failed to populate integer package data. Error [0%0x]\n",
699a34fc329SJorge Lopez ret);
700a34fc329SJorge Lopez kfree(str_value);
701a34fc329SJorge Lopez return ret;
702a34fc329SJorge Lopez }
703a34fc329SJorge Lopez
704a34fc329SJorge Lopez /* All duplicate attributes found are ignored */
705981368e1SArmin Wolf duplicate = kset_find_obj(temp_kset, str_value);
706981368e1SArmin Wolf if (duplicate) {
707a34fc329SJorge Lopez pr_debug("Duplicate attribute name found - %s\n", str_value);
708981368e1SArmin Wolf /* kset_find_obj() returns a reference */
709981368e1SArmin Wolf kobject_put(duplicate);
710a34fc329SJorge Lopez goto pack_attr_exit;
711a34fc329SJorge Lopez }
712a34fc329SJorge Lopez
713a34fc329SJorge Lopez /* build attribute */
714a34fc329SJorge Lopez attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
715a34fc329SJorge Lopez if (!attr_name_kobj) {
716a34fc329SJorge Lopez ret = -ENOMEM;
717a34fc329SJorge Lopez goto pack_attr_exit;
718a34fc329SJorge Lopez }
719a34fc329SJorge Lopez
720a34fc329SJorge Lopez attr_name_kobj->kset = temp_kset;
721a34fc329SJorge Lopez
722a34fc329SJorge Lopez ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,
723a34fc329SJorge Lopez NULL, "%s", str_value);
724a34fc329SJorge Lopez
725a34fc329SJorge Lopez if (ret) {
726a34fc329SJorge Lopez kobject_put(attr_name_kobj);
727a34fc329SJorge Lopez goto pack_attr_exit;
728a34fc329SJorge Lopez }
729a34fc329SJorge Lopez
730a34fc329SJorge Lopez /* enumerate all of these attributes */
731a34fc329SJorge Lopez switch (attr_type) {
732a34fc329SJorge Lopez case HPWMI_STRING_TYPE:
733a34fc329SJorge Lopez ret = hp_populate_string_package_data(elements,
734a34fc329SJorge Lopez instance_id,
735a34fc329SJorge Lopez attr_name_kobj);
736a34fc329SJorge Lopez break;
737a34fc329SJorge Lopez case HPWMI_INTEGER_TYPE:
738a34fc329SJorge Lopez ret = hp_populate_integer_package_data(elements,
739a34fc329SJorge Lopez instance_id,
740a34fc329SJorge Lopez attr_name_kobj);
741a34fc329SJorge Lopez break;
742a34fc329SJorge Lopez case HPWMI_ENUMERATION_TYPE:
743a34fc329SJorge Lopez ret = hp_populate_enumeration_package_data(elements,
744a34fc329SJorge Lopez instance_id,
745a34fc329SJorge Lopez attr_name_kobj);
746a34fc329SJorge Lopez break;
747a34fc329SJorge Lopez case HPWMI_ORDERED_LIST_TYPE:
748a34fc329SJorge Lopez ret = hp_populate_ordered_list_package_data(elements,
749a34fc329SJorge Lopez instance_id,
750a34fc329SJorge Lopez attr_name_kobj);
751a34fc329SJorge Lopez break;
752a34fc329SJorge Lopez case HPWMI_PASSWORD_TYPE:
753a34fc329SJorge Lopez ret = hp_populate_password_package_data(elements,
754a34fc329SJorge Lopez instance_id,
755a34fc329SJorge Lopez attr_name_kobj);
756a34fc329SJorge Lopez break;
757a34fc329SJorge Lopez default:
758a34fc329SJorge Lopez pr_debug("Unknown attribute type found: 0x%x\n", attr_type);
759a34fc329SJorge Lopez break;
760a34fc329SJorge Lopez }
761a34fc329SJorge Lopez
762a34fc329SJorge Lopez pack_attr_exit:
763a34fc329SJorge Lopez kfree(str_value);
764a34fc329SJorge Lopez return ret;
765a34fc329SJorge Lopez }
766a34fc329SJorge Lopez
hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type,union acpi_object * obj,const char * guid,int min_elements,int instance_id)767a34fc329SJorge Lopez static int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type,
768a34fc329SJorge Lopez union acpi_object *obj,
769a34fc329SJorge Lopez const char *guid, int min_elements,
770a34fc329SJorge Lopez int instance_id)
771a34fc329SJorge Lopez {
772981368e1SArmin Wolf struct kobject *attr_name_kobj, *duplicate;
773a34fc329SJorge Lopez struct kset *temp_kset;
774a34fc329SJorge Lopez char str[MAX_BUFF_SIZE];
775a34fc329SJorge Lopez
776a34fc329SJorge Lopez char *temp_str = NULL;
777a34fc329SJorge Lopez char *str_value = NULL;
778a34fc329SJorge Lopez u8 *buffer_ptr = NULL;
779a34fc329SJorge Lopez int buffer_size;
780a34fc329SJorge Lopez int ret = 0;
781a34fc329SJorge Lopez
782a34fc329SJorge Lopez buffer_size = obj->buffer.length;
783a34fc329SJorge Lopez buffer_ptr = obj->buffer.pointer;
784a34fc329SJorge Lopez
785a34fc329SJorge Lopez ret = hp_get_string_from_buffer(&buffer_ptr,
786a34fc329SJorge Lopez &buffer_size, str, MAX_BUFF_SIZE);
787a34fc329SJorge Lopez
788a34fc329SJorge Lopez if (ret < 0)
789a34fc329SJorge Lopez goto buff_attr_exit;
790a34fc329SJorge Lopez
791a34fc329SJorge Lopez if (attr_type == HPWMI_PASSWORD_TYPE ||
792a34fc329SJorge Lopez attr_type == HPWMI_SECURE_PLATFORM_TYPE)
793a34fc329SJorge Lopez temp_kset = bioscfg_drv.authentication_dir_kset;
794a34fc329SJorge Lopez else
795a34fc329SJorge Lopez temp_kset = bioscfg_drv.main_dir_kset;
796a34fc329SJorge Lopez
797a34fc329SJorge Lopez /* All duplicate attributes found are ignored */
798981368e1SArmin Wolf duplicate = kset_find_obj(temp_kset, str);
799981368e1SArmin Wolf if (duplicate) {
800a34fc329SJorge Lopez pr_debug("Duplicate attribute name found - %s\n", str);
801981368e1SArmin Wolf /* kset_find_obj() returns a reference */
802981368e1SArmin Wolf kobject_put(duplicate);
803a34fc329SJorge Lopez goto buff_attr_exit;
804a34fc329SJorge Lopez }
805a34fc329SJorge Lopez
806a34fc329SJorge Lopez /* build attribute */
807a34fc329SJorge Lopez attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
808a34fc329SJorge Lopez if (!attr_name_kobj) {
809a34fc329SJorge Lopez ret = -ENOMEM;
810a34fc329SJorge Lopez goto buff_attr_exit;
811a34fc329SJorge Lopez }
812a34fc329SJorge Lopez
813a34fc329SJorge Lopez attr_name_kobj->kset = temp_kset;
814a34fc329SJorge Lopez
815a34fc329SJorge Lopez temp_str = str;
816a34fc329SJorge Lopez if (attr_type == HPWMI_SECURE_PLATFORM_TYPE)
817a34fc329SJorge Lopez temp_str = "SPM";
818a34fc329SJorge Lopez
819a34fc329SJorge Lopez ret = kobject_init_and_add(attr_name_kobj,
820a34fc329SJorge Lopez &attr_name_ktype, NULL, "%s", temp_str);
821a34fc329SJorge Lopez if (ret) {
822a34fc329SJorge Lopez kobject_put(attr_name_kobj);
823a34fc329SJorge Lopez goto buff_attr_exit;
824a34fc329SJorge Lopez }
825a34fc329SJorge Lopez
826a34fc329SJorge Lopez /* enumerate all of these attributes */
827a34fc329SJorge Lopez switch (attr_type) {
828a34fc329SJorge Lopez case HPWMI_STRING_TYPE:
829a34fc329SJorge Lopez ret = hp_populate_string_buffer_data(buffer_ptr,
830a34fc329SJorge Lopez &buffer_size,
831a34fc329SJorge Lopez instance_id,
832a34fc329SJorge Lopez attr_name_kobj);
833a34fc329SJorge Lopez break;
834a34fc329SJorge Lopez case HPWMI_INTEGER_TYPE:
835a34fc329SJorge Lopez ret = hp_populate_integer_buffer_data(buffer_ptr,
836a34fc329SJorge Lopez &buffer_size,
837a34fc329SJorge Lopez instance_id,
838a34fc329SJorge Lopez attr_name_kobj);
839a34fc329SJorge Lopez break;
840a34fc329SJorge Lopez case HPWMI_ENUMERATION_TYPE:
841a34fc329SJorge Lopez ret = hp_populate_enumeration_buffer_data(buffer_ptr,
842a34fc329SJorge Lopez &buffer_size,
843a34fc329SJorge Lopez instance_id,
844a34fc329SJorge Lopez attr_name_kobj);
845a34fc329SJorge Lopez break;
846a34fc329SJorge Lopez case HPWMI_ORDERED_LIST_TYPE:
847a34fc329SJorge Lopez ret = hp_populate_ordered_list_buffer_data(buffer_ptr,
848a34fc329SJorge Lopez &buffer_size,
849a34fc329SJorge Lopez instance_id,
850a34fc329SJorge Lopez attr_name_kobj);
851a34fc329SJorge Lopez break;
852a34fc329SJorge Lopez case HPWMI_PASSWORD_TYPE:
853a34fc329SJorge Lopez ret = hp_populate_password_buffer_data(buffer_ptr,
854a34fc329SJorge Lopez &buffer_size,
855a34fc329SJorge Lopez instance_id,
856a34fc329SJorge Lopez attr_name_kobj);
857a34fc329SJorge Lopez break;
858a34fc329SJorge Lopez default:
859a34fc329SJorge Lopez pr_debug("Unknown attribute type found: 0x%x\n", attr_type);
860a34fc329SJorge Lopez break;
861a34fc329SJorge Lopez }
862a34fc329SJorge Lopez
863a34fc329SJorge Lopez buff_attr_exit:
864a34fc329SJorge Lopez kfree(str_value);
865a34fc329SJorge Lopez return ret;
866a34fc329SJorge Lopez }
867a34fc329SJorge Lopez
868a34fc329SJorge Lopez /**
869a34fc329SJorge Lopez * hp_init_bios_attributes() - Initialize all attributes for a type
870a34fc329SJorge Lopez * @attr_type: The attribute type to initialize
871a34fc329SJorge Lopez * @guid: The WMI GUID associated with this type to initialize
872a34fc329SJorge Lopez *
873a34fc329SJorge Lopez * Initialize all 5 types of attributes: enumeration, integer,
874a34fc329SJorge Lopez * string, password, ordered list object. Populates each attribute types
875a34fc329SJorge Lopez * respective properties under sysfs files
876a34fc329SJorge Lopez */
hp_init_bios_attributes(enum hp_wmi_data_type attr_type,const char * guid)877a34fc329SJorge Lopez static int hp_init_bios_attributes(enum hp_wmi_data_type attr_type, const char *guid)
878a34fc329SJorge Lopez {
879a34fc329SJorge Lopez union acpi_object *obj = NULL;
880a34fc329SJorge Lopez int min_elements;
881a34fc329SJorge Lopez
882a34fc329SJorge Lopez /* instance_id needs to be reset for each type GUID
883a34fc329SJorge Lopez * also, instance IDs are unique within GUID but not across
884a34fc329SJorge Lopez */
885a34fc329SJorge Lopez int instance_id = 0;
886a34fc329SJorge Lopez int cur_instance_id = instance_id;
887a34fc329SJorge Lopez int ret = 0;
888a34fc329SJorge Lopez
889a34fc329SJorge Lopez ret = hp_alloc_attributes_data(attr_type);
890a34fc329SJorge Lopez if (ret)
891a34fc329SJorge Lopez return ret;
892a34fc329SJorge Lopez
893a34fc329SJorge Lopez switch (attr_type) {
894a34fc329SJorge Lopez case HPWMI_STRING_TYPE:
895a34fc329SJorge Lopez min_elements = STR_ELEM_CNT;
896a34fc329SJorge Lopez break;
897a34fc329SJorge Lopez case HPWMI_INTEGER_TYPE:
898a34fc329SJorge Lopez min_elements = INT_ELEM_CNT;
899a34fc329SJorge Lopez break;
900a34fc329SJorge Lopez case HPWMI_ENUMERATION_TYPE:
901a34fc329SJorge Lopez min_elements = ENUM_ELEM_CNT;
902a34fc329SJorge Lopez break;
903a34fc329SJorge Lopez case HPWMI_ORDERED_LIST_TYPE:
904a34fc329SJorge Lopez min_elements = ORD_ELEM_CNT;
905a34fc329SJorge Lopez break;
906a34fc329SJorge Lopez case HPWMI_PASSWORD_TYPE:
907a34fc329SJorge Lopez min_elements = PSWD_ELEM_CNT;
908a34fc329SJorge Lopez break;
909a34fc329SJorge Lopez default:
910a34fc329SJorge Lopez pr_err("Error: Unknown attr_type: %d\n", attr_type);
911a34fc329SJorge Lopez return -EINVAL;
912a34fc329SJorge Lopez }
913a34fc329SJorge Lopez
914a34fc329SJorge Lopez /* need to use specific instance_id and guid combination to get right data */
915a34fc329SJorge Lopez obj = hp_get_wmiobj_pointer(instance_id, guid);
916a34fc329SJorge Lopez if (!obj)
917a34fc329SJorge Lopez return -ENODEV;
918a34fc329SJorge Lopez
919a34fc329SJorge Lopez mutex_lock(&bioscfg_drv.mutex);
920a34fc329SJorge Lopez while (obj) {
921a34fc329SJorge Lopez /* Take action appropriate to each ACPI TYPE */
922a34fc329SJorge Lopez if (obj->type == ACPI_TYPE_PACKAGE) {
923a34fc329SJorge Lopez ret = hp_init_bios_package_attribute(attr_type, obj,
924a34fc329SJorge Lopez guid, min_elements,
925a34fc329SJorge Lopez cur_instance_id);
926a34fc329SJorge Lopez
927a34fc329SJorge Lopez } else if (obj->type == ACPI_TYPE_BUFFER) {
928a34fc329SJorge Lopez ret = hp_init_bios_buffer_attribute(attr_type, obj,
929a34fc329SJorge Lopez guid, min_elements,
930a34fc329SJorge Lopez cur_instance_id);
931a34fc329SJorge Lopez
932a34fc329SJorge Lopez } else {
933a34fc329SJorge Lopez pr_err("Expected ACPI-package or buffer type, got: %d\n",
934a34fc329SJorge Lopez obj->type);
935a34fc329SJorge Lopez ret = -EIO;
936a34fc329SJorge Lopez goto err_attr_init;
937a34fc329SJorge Lopez }
938a34fc329SJorge Lopez
939a34fc329SJorge Lopez /*
940a34fc329SJorge Lopez * Failure reported in one attribute must not
941a34fc329SJorge Lopez * stop process of the remaining attribute values.
942a34fc329SJorge Lopez */
943a34fc329SJorge Lopez if (ret >= 0)
944a34fc329SJorge Lopez cur_instance_id++;
945a34fc329SJorge Lopez
946a34fc329SJorge Lopez kfree(obj);
947a34fc329SJorge Lopez instance_id++;
948a34fc329SJorge Lopez obj = hp_get_wmiobj_pointer(instance_id, guid);
949a34fc329SJorge Lopez }
950a34fc329SJorge Lopez
951a34fc329SJorge Lopez err_attr_init:
952a34fc329SJorge Lopez mutex_unlock(&bioscfg_drv.mutex);
953a34fc329SJorge Lopez kfree(obj);
954a34fc329SJorge Lopez return ret;
955a34fc329SJorge Lopez }
956a34fc329SJorge Lopez
hp_init(void)957a34fc329SJorge Lopez static int __init hp_init(void)
958a34fc329SJorge Lopez {
959a34fc329SJorge Lopez int ret;
960a34fc329SJorge Lopez int hp_bios_capable = wmi_has_guid(HP_WMI_BIOS_GUID);
961a34fc329SJorge Lopez int set_bios_settings = wmi_has_guid(HP_WMI_SET_BIOS_SETTING_GUID);
962a34fc329SJorge Lopez
963a34fc329SJorge Lopez if (!hp_bios_capable) {
964a34fc329SJorge Lopez pr_err("Unable to run on non-HP system\n");
965a34fc329SJorge Lopez return -ENODEV;
966a34fc329SJorge Lopez }
967a34fc329SJorge Lopez
968a34fc329SJorge Lopez if (!set_bios_settings) {
969a34fc329SJorge Lopez pr_err("Unable to set BIOS settings on HP systems\n");
970a34fc329SJorge Lopez return -ENODEV;
971a34fc329SJorge Lopez }
972a34fc329SJorge Lopez
973a34fc329SJorge Lopez ret = hp_init_attr_set_interface();
974a34fc329SJorge Lopez if (ret)
975a34fc329SJorge Lopez return ret;
976a34fc329SJorge Lopez
977a34fc329SJorge Lopez ret = fw_attributes_class_get(&fw_attr_class);
978a34fc329SJorge Lopez if (ret)
979a34fc329SJorge Lopez goto err_unregister_class;
980a34fc329SJorge Lopez
981a34fc329SJorge Lopez bioscfg_drv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0),
982a34fc329SJorge Lopez NULL, "%s", DRIVER_NAME);
983a34fc329SJorge Lopez if (IS_ERR(bioscfg_drv.class_dev)) {
984a34fc329SJorge Lopez ret = PTR_ERR(bioscfg_drv.class_dev);
985a34fc329SJorge Lopez goto err_unregister_class;
986a34fc329SJorge Lopez }
987a34fc329SJorge Lopez
988a34fc329SJorge Lopez bioscfg_drv.main_dir_kset = kset_create_and_add("attributes", NULL,
989a34fc329SJorge Lopez &bioscfg_drv.class_dev->kobj);
990a34fc329SJorge Lopez if (!bioscfg_drv.main_dir_kset) {
991a34fc329SJorge Lopez ret = -ENOMEM;
992a34fc329SJorge Lopez pr_debug("Failed to create and add attributes\n");
993a34fc329SJorge Lopez goto err_destroy_classdev;
994a34fc329SJorge Lopez }
995a34fc329SJorge Lopez
996a34fc329SJorge Lopez bioscfg_drv.authentication_dir_kset = kset_create_and_add("authentication", NULL,
997a34fc329SJorge Lopez &bioscfg_drv.class_dev->kobj);
998a34fc329SJorge Lopez if (!bioscfg_drv.authentication_dir_kset) {
999a34fc329SJorge Lopez ret = -ENOMEM;
1000a34fc329SJorge Lopez pr_debug("Failed to create and add authentication\n");
1001a34fc329SJorge Lopez goto err_release_attributes_data;
1002a34fc329SJorge Lopez }
1003a34fc329SJorge Lopez
1004a34fc329SJorge Lopez /*
1005a34fc329SJorge Lopez * sysfs level attributes.
1006a34fc329SJorge Lopez * - pending_reboot
1007a34fc329SJorge Lopez */
1008a34fc329SJorge Lopez ret = create_attributes_level_sysfs_files();
1009a34fc329SJorge Lopez if (ret)
1010a34fc329SJorge Lopez pr_debug("Failed to create sysfs level attributes\n");
1011a34fc329SJorge Lopez
1012a34fc329SJorge Lopez ret = hp_init_bios_attributes(HPWMI_STRING_TYPE, HP_WMI_BIOS_STRING_GUID);
1013a34fc329SJorge Lopez if (ret)
1014a34fc329SJorge Lopez pr_debug("Failed to populate string type attributes\n");
1015a34fc329SJorge Lopez
1016a34fc329SJorge Lopez ret = hp_init_bios_attributes(HPWMI_INTEGER_TYPE, HP_WMI_BIOS_INTEGER_GUID);
1017a34fc329SJorge Lopez if (ret)
1018a34fc329SJorge Lopez pr_debug("Failed to populate integer type attributes\n");
1019a34fc329SJorge Lopez
1020a34fc329SJorge Lopez ret = hp_init_bios_attributes(HPWMI_ENUMERATION_TYPE, HP_WMI_BIOS_ENUMERATION_GUID);
1021a34fc329SJorge Lopez if (ret)
1022a34fc329SJorge Lopez pr_debug("Failed to populate enumeration type attributes\n");
1023a34fc329SJorge Lopez
1024a34fc329SJorge Lopez ret = hp_init_bios_attributes(HPWMI_ORDERED_LIST_TYPE, HP_WMI_BIOS_ORDERED_LIST_GUID);
1025a34fc329SJorge Lopez if (ret)
1026a34fc329SJorge Lopez pr_debug("Failed to populate ordered list object type attributes\n");
1027a34fc329SJorge Lopez
1028a34fc329SJorge Lopez ret = hp_init_bios_attributes(HPWMI_PASSWORD_TYPE, HP_WMI_BIOS_PASSWORD_GUID);
1029a34fc329SJorge Lopez if (ret)
1030a34fc329SJorge Lopez pr_debug("Failed to populate password object type attributes\n");
1031a34fc329SJorge Lopez
1032a34fc329SJorge Lopez bioscfg_drv.spm_data.attr_name_kobj = NULL;
1033a34fc329SJorge Lopez ret = hp_add_other_attributes(HPWMI_SECURE_PLATFORM_TYPE);
1034a34fc329SJorge Lopez if (ret)
1035a34fc329SJorge Lopez pr_debug("Failed to populate secure platform object type attribute\n");
1036a34fc329SJorge Lopez
1037a34fc329SJorge Lopez bioscfg_drv.sure_start_attr_kobj = NULL;
1038a34fc329SJorge Lopez ret = hp_add_other_attributes(HPWMI_SURE_START_TYPE);
1039a34fc329SJorge Lopez if (ret)
1040a34fc329SJorge Lopez pr_debug("Failed to populate sure start object type attribute\n");
1041a34fc329SJorge Lopez
1042a34fc329SJorge Lopez return 0;
1043a34fc329SJorge Lopez
1044a34fc329SJorge Lopez err_release_attributes_data:
1045a34fc329SJorge Lopez release_attributes_data();
1046a34fc329SJorge Lopez
1047a34fc329SJorge Lopez err_destroy_classdev:
1048a34fc329SJorge Lopez device_destroy(fw_attr_class, MKDEV(0, 0));
1049a34fc329SJorge Lopez
1050a34fc329SJorge Lopez err_unregister_class:
1051a34fc329SJorge Lopez fw_attributes_class_put();
1052a34fc329SJorge Lopez hp_exit_attr_set_interface();
1053a34fc329SJorge Lopez
1054a34fc329SJorge Lopez return ret;
1055a34fc329SJorge Lopez }
1056a34fc329SJorge Lopez
hp_exit(void)1057a34fc329SJorge Lopez static void __exit hp_exit(void)
1058a34fc329SJorge Lopez {
1059a34fc329SJorge Lopez release_attributes_data();
1060a34fc329SJorge Lopez device_destroy(fw_attr_class, MKDEV(0, 0));
1061a34fc329SJorge Lopez
1062a34fc329SJorge Lopez fw_attributes_class_put();
1063a34fc329SJorge Lopez hp_exit_attr_set_interface();
1064a34fc329SJorge Lopez }
1065a34fc329SJorge Lopez
1066a34fc329SJorge Lopez module_init(hp_init);
1067a34fc329SJorge Lopez module_exit(hp_exit);
1068