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 31 struct bmof_priv { 32 union acpi_object *bmofdata; 33 struct bin_attribute bmof_bin_attr; 34 }; 35 36 static ssize_t 37 read_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 57 static 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 97 static 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 106 static const struct wmi_device_id wmi_bmof_id_table[] = { 107 { .guid_string = WMI_BMOF_GUID }, 108 { }, 109 }; 110 111 static 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 120 module_wmi_driver(wmi_bmof_driver); 121 122 MODULE_ALIAS("wmi:" WMI_BMOF_GUID); 123 MODULE_AUTHOR("Andrew Lutomirski <luto@kernel.org>"); 124 MODULE_DESCRIPTION("WMI embedded Binary MOF driver"); 125 MODULE_LICENSE("GPL"); 126