Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *  WMI methods for use with dell-smbios
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *  Copyright (c) 2017 Dell Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/wmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include "dell-smbios.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include "dell-wmi-descriptor.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) static DEFINE_MUTEX(call_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) static DEFINE_MUTEX(list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) static int wmi_supported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) struct misc_bios_flags_structure {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	struct dmi_header header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	u16 flags0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #define FLAG_HAS_ACPI_WMI 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) struct wmi_smbios_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	struct dell_wmi_smbios_buffer *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	struct wmi_device *wdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	struct device *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	u32 req_buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static LIST_HEAD(wmi_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) static inline struct wmi_smbios_priv *get_first_smbios_priv(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	return list_first_entry_or_null(&wmi_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 					struct wmi_smbios_priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 					list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) static int run_smbios_call(struct wmi_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	struct wmi_smbios_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	struct acpi_buffer input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	union acpi_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	priv = dev_get_drvdata(&wdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	input.length = priv->req_buf_size - sizeof(u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	input.pointer = &priv->buf->std;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	dev_dbg(&wdev->dev, "evaluating: %u/%u [%x,%x,%x,%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		priv->buf->std.cmd_class, priv->buf->std.cmd_select,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 		priv->buf->std.input[0], priv->buf->std.input[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 		priv->buf->std.input[2], priv->buf->std.input[3]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	obj = (union acpi_object *)output.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	if (obj->type != ACPI_TYPE_BUFFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		dev_dbg(&wdev->dev, "received type: %d\n", obj->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		if (obj->type == ACPI_TYPE_INTEGER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 			dev_dbg(&wdev->dev, "SMBIOS call failed: %llu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 				obj->integer.value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		kfree(output.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	memcpy(&priv->buf->std, obj->buffer.pointer, obj->buffer.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	dev_dbg(&wdev->dev, "result: [%08x,%08x,%08x,%08x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		priv->buf->std.output[0], priv->buf->std.output[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		priv->buf->std.output[2], priv->buf->std.output[3]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	kfree(output.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) static int dell_smbios_wmi_call(struct calling_interface_buffer *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	struct wmi_smbios_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	size_t difference;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	size_t size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	mutex_lock(&call_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	priv = get_first_smbios_priv();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	if (!priv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		goto out_wmi_call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	size = sizeof(struct calling_interface_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	difference = priv->req_buf_size - sizeof(u64) - size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	memset(&priv->buf->ext, 0, difference);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	memcpy(&priv->buf->std, buffer, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	ret = run_smbios_call(priv->wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	memcpy(buffer, &priv->buf->std, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) out_wmi_call:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	mutex_unlock(&call_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 				   struct wmi_ioctl_buffer *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	struct wmi_smbios_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	case DELL_WMI_SMBIOS_CMD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 		mutex_lock(&call_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		priv = dev_get_drvdata(&wdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		if (!priv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 			ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 			goto fail_smbios_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		memcpy(priv->buf, arg, priv->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		if (dell_smbios_call_filter(&wdev->dev, &priv->buf->std)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 			dev_err(&wdev->dev, "Invalid call %d/%d:%8x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 				priv->buf->std.cmd_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 				priv->buf->std.cmd_select,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 				priv->buf->std.input[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 			ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 			goto fail_smbios_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		ret = run_smbios_call(priv->wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 			goto fail_smbios_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		memcpy(arg, priv->buf, priv->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) fail_smbios_cmd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		mutex_unlock(&call_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		ret = -ENOIOCTLCMD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static int dell_smbios_wmi_probe(struct wmi_device *wdev, const void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	struct wmi_driver *wdriver =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 		container_of(wdev->dev.driver, struct wmi_driver, driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	struct wmi_smbios_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	u32 hotfix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	ret = dell_wmi_get_descriptor_valid();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	priv = devm_kzalloc(&wdev->dev, sizeof(struct wmi_smbios_priv),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 			    GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	/* WMI buffer size will be either 4k or 32k depending on machine */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	if (!dell_wmi_get_size(&priv->req_buf_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	/* some SMBIOS calls fail unless BIOS contains hotfix */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	if (!dell_wmi_get_hotfix(&hotfix))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	if (!hotfix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		dev_warn(&wdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 			"WMI SMBIOS userspace interface not supported(%u), try upgrading to a newer BIOS\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 			hotfix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		wdriver->filter_callback = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	/* add in the length object we will use internally with ioctl */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	priv->req_buf_size += sizeof(u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	ret = set_required_buffer_size(wdev, priv->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	count = get_order(priv->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	priv->buf = (void *)__get_free_pages(GFP_KERNEL, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	if (!priv->buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	/* ID is used by dell-smbios to set priority of drivers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	wdev->dev.id = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	ret = dell_smbios_register_device(&wdev->dev, &dell_smbios_wmi_call);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		goto fail_register;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	priv->wdev = wdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	dev_set_drvdata(&wdev->dev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	mutex_lock(&list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	list_add_tail(&priv->list, &wmi_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	mutex_unlock(&list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) fail_register:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	free_pages((unsigned long)priv->buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int dell_smbios_wmi_remove(struct wmi_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	struct wmi_smbios_priv *priv = dev_get_drvdata(&wdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	mutex_lock(&call_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	mutex_lock(&list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	list_del(&priv->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	mutex_unlock(&list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	dell_smbios_unregister_device(&wdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	count = get_order(priv->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	free_pages((unsigned long)priv->buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	mutex_unlock(&call_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static const struct wmi_device_id dell_smbios_wmi_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	{ .guid_string = DELL_WMI_SMBIOS_GUID },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	{ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static void parse_b1_table(const struct dmi_header *dm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	struct misc_bios_flags_structure *flags =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	container_of(dm, struct misc_bios_flags_structure, header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	/* 4 bytes header, 8 bytes flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	if (dm->length < 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	if (dm->handle != 0xb100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	if ((flags->flags0 & FLAG_HAS_ACPI_WMI))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 		wmi_supported = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static void find_b1(const struct dmi_header *dm, void *dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	switch (dm->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	case 0xb1: /* misc bios flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 		parse_b1_table(dm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static struct wmi_driver dell_smbios_wmi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		.name = "dell-smbios",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	.probe = dell_smbios_wmi_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	.remove = dell_smbios_wmi_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	.id_table = dell_smbios_wmi_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	.filter_callback = dell_smbios_wmi_filter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int init_dell_smbios_wmi(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	dmi_walk(find_b1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	if (!wmi_supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	return wmi_driver_register(&dell_smbios_wmi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) void exit_dell_smbios_wmi(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	if (wmi_supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 		wmi_driver_unregister(&dell_smbios_wmi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) MODULE_DEVICE_TABLE(wmi, dell_smbios_wmi_id_table);