Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * WMI embedded Binary MOF driver
  3 *
  4 * Copyright (c) 2015 Andrew Lutomirski
  5 * Copyright (C) 2017 VMware, Inc. All Rights Reserved.
  6 *
  7 *  This program is free software; you can redistribute it and/or modify it
  8 *  under the terms of the GNU General Public License version 2 as published
  9 *  by the Free Software Foundation.
 10 *
 11 *  This program is distributed in the hope that it will be useful,
 12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 *  GNU General Public License for more details.
 15 */
 16
 17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 18
 19#include <linux/acpi.h>
 20#include <linux/device.h>
 21#include <linux/fs.h>
 22#include <linux/kernel.h>
 23#include <linux/module.h>
 24#include <linux/string.h>
 25#include <linux/sysfs.h>
 26#include <linux/types.h>
 27#include <linux/wmi.h>
 28
 29#define WMI_BMOF_GUID "05901221-D566-11D1-B2F0-00A0C9062910"
 30
 31struct bmof_priv {
 32	union acpi_object *bmofdata;
 33	struct bin_attribute bmof_bin_attr;
 34};
 35
 36static ssize_t
 37read_bmof(struct file *filp, struct kobject *kobj,
 38	 struct bin_attribute *attr,
 39	 char *buf, loff_t off, size_t count)
 40{
 41	struct bmof_priv *priv =
 42		container_of(attr, struct bmof_priv, bmof_bin_attr);
 43
 44	if (off < 0)
 45		return -EINVAL;
 46
 47	if (off >= priv->bmofdata->buffer.length)
 48		return 0;
 49
 50	if (count > priv->bmofdata->buffer.length - off)
 51		count = priv->bmofdata->buffer.length - off;
 52
 53	memcpy(buf, priv->bmofdata->buffer.pointer + off, count);
 54	return count;
 55}
 56
 57static int wmi_bmof_probe(struct wmi_device *wdev)
 58{
 59	struct bmof_priv *priv;
 60	int ret;
 61
 62	priv = devm_kzalloc(&wdev->dev, sizeof(struct bmof_priv), GFP_KERNEL);
 63	if (!priv)
 64		return -ENOMEM;
 65
 66	dev_set_drvdata(&wdev->dev, priv);
 67
 68	priv->bmofdata = wmidev_block_query(wdev, 0);
 69	if (!priv->bmofdata) {
 70		dev_err(&wdev->dev, "failed to read Binary MOF\n");
 71		return -EIO;
 72	}
 73
 74	if (priv->bmofdata->type != ACPI_TYPE_BUFFER) {
 75		dev_err(&wdev->dev, "Binary MOF is not a buffer\n");
 76		ret = -EIO;
 77		goto err_free;
 78	}
 79
 80	sysfs_bin_attr_init(&priv->bmof_bin_attr);
 81	priv->bmof_bin_attr.attr.name = "bmof";
 82	priv->bmof_bin_attr.attr.mode = 0400;
 83	priv->bmof_bin_attr.read = read_bmof;
 84	priv->bmof_bin_attr.size = priv->bmofdata->buffer.length;
 85
 86	ret = sysfs_create_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr);
 87	if (ret)
 88		goto err_free;
 89
 90	return 0;
 91
 92 err_free:
 93	kfree(priv->bmofdata);
 94	return ret;
 95}
 96
 97static int wmi_bmof_remove(struct wmi_device *wdev)
 98{
 99	struct bmof_priv *priv = dev_get_drvdata(&wdev->dev);
100
101	sysfs_remove_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr);
102	kfree(priv->bmofdata);
103	return 0;
104}
105
106static const struct wmi_device_id wmi_bmof_id_table[] = {
107	{ .guid_string = WMI_BMOF_GUID },
108	{ },
109};
110
111static struct wmi_driver wmi_bmof_driver = {
112	.driver = {
113		.name = "wmi-bmof",
114	},
115	.probe = wmi_bmof_probe,
116	.remove = wmi_bmof_remove,
117	.id_table = wmi_bmof_id_table,
118};
119
120module_wmi_driver(wmi_bmof_driver);
121
122MODULE_ALIAS("wmi:" WMI_BMOF_GUID);
123MODULE_AUTHOR("Andrew Lutomirski <luto@kernel.org>");
124MODULE_DESCRIPTION("WMI embedded Binary MOF driver");
125MODULE_LICENSE("GPL");