0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/acpi.h>
0018 #include <linux/device.h>
0019 #include <linux/module.h>
0020 #include <linux/slab.h>
0021 #include <linux/sysfs.h>
0022 #include <linux/wmi.h>
0023
0024 #define INTEL_WMI_SBL_GUID "44FADEB1-B204-40F2-8581-394BBDC1B651"
0025
0026 static int get_fwu_request(struct device *dev, u32 *out)
0027 {
0028 struct acpi_buffer result = {ACPI_ALLOCATE_BUFFER, NULL};
0029 union acpi_object *obj;
0030 acpi_status status;
0031
0032 status = wmi_query_block(INTEL_WMI_SBL_GUID, 0, &result);
0033 if (ACPI_FAILURE(status)) {
0034 dev_err(dev, "wmi_query_block failed\n");
0035 return -ENODEV;
0036 }
0037
0038 obj = (union acpi_object *)result.pointer;
0039 if (!obj || obj->type != ACPI_TYPE_INTEGER) {
0040 dev_warn(dev, "wmi_query_block returned invalid value\n");
0041 kfree(obj);
0042 return -EINVAL;
0043 }
0044
0045 *out = obj->integer.value;
0046 kfree(obj);
0047
0048 return 0;
0049 }
0050
0051 static int set_fwu_request(struct device *dev, u32 in)
0052 {
0053 struct acpi_buffer input;
0054 acpi_status status;
0055 u32 value;
0056
0057 value = in;
0058 input.length = sizeof(u32);
0059 input.pointer = &value;
0060
0061 status = wmi_set_block(INTEL_WMI_SBL_GUID, 0, &input);
0062 if (ACPI_FAILURE(status)) {
0063 dev_err(dev, "wmi_set_block failed\n");
0064 return -ENODEV;
0065 }
0066
0067 return 0;
0068 }
0069
0070 static ssize_t firmware_update_request_show(struct device *dev,
0071 struct device_attribute *attr,
0072 char *buf)
0073 {
0074 u32 val;
0075 int ret;
0076
0077 ret = get_fwu_request(dev, &val);
0078 if (ret)
0079 return ret;
0080
0081 return sprintf(buf, "%d\n", val);
0082 }
0083
0084 static ssize_t firmware_update_request_store(struct device *dev,
0085 struct device_attribute *attr,
0086 const char *buf, size_t count)
0087 {
0088 unsigned int val;
0089 int ret;
0090
0091 ret = kstrtouint(buf, 0, &val);
0092 if (ret)
0093 return ret;
0094
0095
0096 if (val > 1)
0097 return -ERANGE;
0098
0099 ret = set_fwu_request(dev, val);
0100 if (ret)
0101 return ret;
0102
0103 return count;
0104 }
0105 static DEVICE_ATTR_RW(firmware_update_request);
0106
0107 static struct attribute *firmware_update_attrs[] = {
0108 &dev_attr_firmware_update_request.attr,
0109 NULL
0110 };
0111 ATTRIBUTE_GROUPS(firmware_update);
0112
0113 static int intel_wmi_sbl_fw_update_probe(struct wmi_device *wdev,
0114 const void *context)
0115 {
0116 dev_info(&wdev->dev, "Slim Bootloader signaling driver attached\n");
0117 return 0;
0118 }
0119
0120 static void intel_wmi_sbl_fw_update_remove(struct wmi_device *wdev)
0121 {
0122 dev_info(&wdev->dev, "Slim Bootloader signaling driver removed\n");
0123 }
0124
0125 static const struct wmi_device_id intel_wmi_sbl_id_table[] = {
0126 { .guid_string = INTEL_WMI_SBL_GUID },
0127 {}
0128 };
0129 MODULE_DEVICE_TABLE(wmi, intel_wmi_sbl_id_table);
0130
0131 static struct wmi_driver intel_wmi_sbl_fw_update_driver = {
0132 .driver = {
0133 .name = "intel-wmi-sbl-fw-update",
0134 .dev_groups = firmware_update_groups,
0135 },
0136 .probe = intel_wmi_sbl_fw_update_probe,
0137 .remove = intel_wmi_sbl_fw_update_remove,
0138 .id_table = intel_wmi_sbl_id_table,
0139 };
0140 module_wmi_driver(intel_wmi_sbl_fw_update_driver);
0141
0142 MODULE_AUTHOR("Jithu Joseph <jithu.joseph@intel.com>");
0143 MODULE_DESCRIPTION("Slim Bootloader firmware update signaling driver");
0144 MODULE_LICENSE("GPL v2");