162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * WMI embedded Binary MOF driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2015 Andrew Lutomirski 662306a36Sopenharmony_ci * Copyright (C) 2017 VMware, Inc. All Rights Reserved. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/acpi.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/fs.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/sysfs.h> 1862306a36Sopenharmony_ci#include <linux/types.h> 1962306a36Sopenharmony_ci#include <linux/wmi.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define WMI_BMOF_GUID "05901221-D566-11D1-B2F0-00A0C9062910" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct bmof_priv { 2462306a36Sopenharmony_ci union acpi_object *bmofdata; 2562306a36Sopenharmony_ci struct bin_attribute bmof_bin_attr; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic ssize_t read_bmof(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, 2962306a36Sopenharmony_ci char *buf, loff_t off, size_t count) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct bmof_priv *priv = container_of(attr, struct bmof_priv, bmof_bin_attr); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci return memory_read_from_buffer(buf, count, &off, priv->bmofdata->buffer.pointer, 3462306a36Sopenharmony_ci priv->bmofdata->buffer.length); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int wmi_bmof_probe(struct wmi_device *wdev, const void *context) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct bmof_priv *priv; 4062306a36Sopenharmony_ci int ret; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci priv = devm_kzalloc(&wdev->dev, sizeof(struct bmof_priv), GFP_KERNEL); 4362306a36Sopenharmony_ci if (!priv) 4462306a36Sopenharmony_ci return -ENOMEM; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci dev_set_drvdata(&wdev->dev, priv); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci priv->bmofdata = wmidev_block_query(wdev, 0); 4962306a36Sopenharmony_ci if (!priv->bmofdata) { 5062306a36Sopenharmony_ci dev_err(&wdev->dev, "failed to read Binary MOF\n"); 5162306a36Sopenharmony_ci return -EIO; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (priv->bmofdata->type != ACPI_TYPE_BUFFER) { 5562306a36Sopenharmony_ci dev_err(&wdev->dev, "Binary MOF is not a buffer\n"); 5662306a36Sopenharmony_ci ret = -EIO; 5762306a36Sopenharmony_ci goto err_free; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci sysfs_bin_attr_init(&priv->bmof_bin_attr); 6162306a36Sopenharmony_ci priv->bmof_bin_attr.attr.name = "bmof"; 6262306a36Sopenharmony_ci priv->bmof_bin_attr.attr.mode = 0400; 6362306a36Sopenharmony_ci priv->bmof_bin_attr.read = read_bmof; 6462306a36Sopenharmony_ci priv->bmof_bin_attr.size = priv->bmofdata->buffer.length; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci ret = device_create_bin_file(&wdev->dev, &priv->bmof_bin_attr); 6762306a36Sopenharmony_ci if (ret) 6862306a36Sopenharmony_ci goto err_free; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci err_free: 7362306a36Sopenharmony_ci kfree(priv->bmofdata); 7462306a36Sopenharmony_ci return ret; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void wmi_bmof_remove(struct wmi_device *wdev) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct bmof_priv *priv = dev_get_drvdata(&wdev->dev); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci device_remove_bin_file(&wdev->dev, &priv->bmof_bin_attr); 8262306a36Sopenharmony_ci kfree(priv->bmofdata); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic const struct wmi_device_id wmi_bmof_id_table[] = { 8662306a36Sopenharmony_ci { .guid_string = WMI_BMOF_GUID }, 8762306a36Sopenharmony_ci { }, 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic struct wmi_driver wmi_bmof_driver = { 9162306a36Sopenharmony_ci .driver = { 9262306a36Sopenharmony_ci .name = "wmi-bmof", 9362306a36Sopenharmony_ci }, 9462306a36Sopenharmony_ci .probe = wmi_bmof_probe, 9562306a36Sopenharmony_ci .remove = wmi_bmof_remove, 9662306a36Sopenharmony_ci .id_table = wmi_bmof_id_table, 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cimodule_wmi_driver(wmi_bmof_driver); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(wmi, wmi_bmof_id_table); 10262306a36Sopenharmony_ciMODULE_AUTHOR("Andrew Lutomirski <luto@kernel.org>"); 10362306a36Sopenharmony_ciMODULE_DESCRIPTION("WMI embedded Binary MOF driver"); 10462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 105