forked from Minki/linux
platform/x86: wmi-bmof: New driver to expose embedded Binary WMI MOF metadata
Many laptops (and maybe servers?) have embedded WMI Binary MOF metadata. We do not yet have open-source tools for processing the data, although one is in the works thanks to Pali: https://github.com/pali/bmfdec There is currently no interface to get the data in the first place. By exposing it, we facilitate the development of new tools. This is based on the original work of Andy Lutomirski <luto@kernel.org>, but contains several modifications in response to various reviews. Signed-off-by: Darren Hart (VMware) <dvhart@infradead.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Mario Limonciello <mario_limonciello@dell.com> Cc: Pali Rohár <pali.rohar@gmail.com> Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
This commit is contained in:
parent
fd70da6a62
commit
f9dd82c0ea
@ -656,6 +656,18 @@ config ACPI_WMI
|
||||
It is safe to enable this driver even if your DSDT doesn't define
|
||||
any ACPI-WMI devices.
|
||||
|
||||
config WMI_BMOF
|
||||
tristate "WMI embedded Binary MOF driver"
|
||||
depends on ACPI_WMI
|
||||
default ACPI_WMI
|
||||
---help---
|
||||
Say Y here if you want to be able to read a firmware-embedded
|
||||
WMI Binary MOF data. Using this requires userspace tools and may be
|
||||
rather tedious.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called wmi-bmof.
|
||||
|
||||
config MSI_WMI
|
||||
tristate "MSI WMI extras"
|
||||
depends on ACPI_WMI
|
||||
|
@ -38,6 +38,7 @@ obj-$(CONFIG_MSI_WMI) += msi-wmi.o
|
||||
obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o
|
||||
obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
|
||||
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
|
||||
obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o
|
||||
|
||||
# toshiba_acpi must link after wmi to ensure that wmi devices are found
|
||||
# before toshiba_acpi initializes
|
||||
|
124
drivers/platform/x86/wmi-bmof.c
Normal file
124
drivers/platform/x86/wmi-bmof.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* WMI embedded Binary MOF driver
|
||||
*
|
||||
* Copyright (c) 2015 Andrew Lutomirski
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#define WMI_BMOF_GUID "05901221-D566-11D1-B2F0-00A0C9062910"
|
||||
|
||||
struct bmof_priv {
|
||||
union acpi_object *bmofdata;
|
||||
struct bin_attribute bmof_bin_attr;
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
read_bmof(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct bmof_priv *priv =
|
||||
container_of(attr, struct bmof_priv, bmof_bin_attr);
|
||||
|
||||
if (off < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (off >= priv->bmofdata->buffer.length)
|
||||
return 0;
|
||||
|
||||
if (count > priv->bmofdata->buffer.length - off)
|
||||
count = priv->bmofdata->buffer.length - off;
|
||||
|
||||
memcpy(buf, priv->bmofdata->buffer.pointer + off, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int wmi_bmof_probe(struct wmi_device *wdev)
|
||||
{
|
||||
struct bmof_priv *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&wdev->dev, sizeof(struct bmof_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
|
||||
priv->bmofdata = wmidev_block_query(wdev, 0);
|
||||
if (!priv->bmofdata) {
|
||||
dev_err(&wdev->dev, "failed to read Binary MOF\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (priv->bmofdata->type != ACPI_TYPE_BUFFER) {
|
||||
dev_err(&wdev->dev, "Binary MOF is not a buffer\n");
|
||||
ret = -EIO;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
sysfs_bin_attr_init(&priv->bmof_bin_attr);
|
||||
priv->bmof_bin_attr.attr.name = "bmof";
|
||||
priv->bmof_bin_attr.attr.mode = 0400;
|
||||
priv->bmof_bin_attr.read = read_bmof;
|
||||
priv->bmof_bin_attr.size = priv->bmofdata->buffer.length;
|
||||
|
||||
ret = sysfs_create_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(priv->bmofdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wmi_bmof_remove(struct wmi_device *wdev)
|
||||
{
|
||||
struct bmof_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
|
||||
sysfs_remove_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr);
|
||||
kfree(priv->bmofdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wmi_device_id wmi_bmof_id_table[] = {
|
||||
{ .guid_string = WMI_BMOF_GUID },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct wmi_driver wmi_bmof_driver = {
|
||||
.driver = {
|
||||
.name = "wmi-bmof",
|
||||
},
|
||||
.probe = wmi_bmof_probe,
|
||||
.remove = wmi_bmof_remove,
|
||||
.id_table = wmi_bmof_id_table,
|
||||
};
|
||||
|
||||
module_wmi_driver(wmi_bmof_driver);
|
||||
|
||||
MODULE_ALIAS("wmi:" WMI_BMOF_GUID);
|
||||
MODULE_AUTHOR("Andrew Lutomirski <luto@kernel.org>");
|
||||
MODULE_DESCRIPTION("WMI embedded Binary MOF driver");
|
||||
MODULE_LICENSE("GPL");
|
Loading…
Reference in New Issue
Block a user