1 /* 2 * cros_ec_vbc - Expose the vboot context nvram to userspace 3 * 4 * Copyright (C) 2015 Collabora Ltd. 5 * 6 * based on vendor driver, 7 * 8 * Copyright (C) 2012 The Chromium OS Authors 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 #include <linux/of.h> 22 #include <linux/platform_device.h> 23 #include <linux/mfd/cros_ec.h> 24 #include <linux/mfd/cros_ec_commands.h> 25 #include <linux/slab.h> 26 27 static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj, 28 struct bin_attribute *att, char *buf, 29 loff_t pos, size_t count) 30 { 31 struct device *dev = container_of(kobj, struct device, kobj); 32 struct cros_ec_dev *ec = to_cros_ec_dev(dev); 33 struct cros_ec_device *ecdev = ec->ec_dev; 34 struct ec_params_vbnvcontext *params; 35 struct cros_ec_command *msg; 36 int err; 37 const size_t para_sz = sizeof(params->op); 38 const size_t resp_sz = sizeof(struct ec_response_vbnvcontext); 39 const size_t payload = max(para_sz, resp_sz); 40 41 msg = kmalloc(sizeof(*msg) + payload, GFP_KERNEL); 42 if (!msg) 43 return -ENOMEM; 44 45 /* NB: we only kmalloc()ated enough space for the op field */ 46 params = (struct ec_params_vbnvcontext *)msg->data; 47 params->op = EC_VBNV_CONTEXT_OP_READ; 48 49 msg->version = EC_VER_VBNV_CONTEXT; 50 msg->command = EC_CMD_VBNV_CONTEXT; 51 msg->outsize = para_sz; 52 msg->insize = resp_sz; 53 54 err = cros_ec_cmd_xfer(ecdev, msg); 55 if (err < 0) { 56 dev_err(dev, "Error sending read request: %d\n", err); 57 kfree(msg); 58 return err; 59 } 60 61 memcpy(buf, msg->data, resp_sz); 62 63 kfree(msg); 64 return resp_sz; 65 } 66 67 static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj, 68 struct bin_attribute *attr, char *buf, 69 loff_t pos, size_t count) 70 { 71 struct device *dev = container_of(kobj, struct device, kobj); 72 struct cros_ec_dev *ec = to_cros_ec_dev(dev); 73 struct cros_ec_device *ecdev = ec->ec_dev; 74 struct ec_params_vbnvcontext *params; 75 struct cros_ec_command *msg; 76 int err; 77 const size_t para_sz = sizeof(*params); 78 const size_t data_sz = sizeof(params->block); 79 80 /* Only write full values */ 81 if (count != data_sz) 82 return -EINVAL; 83 84 msg = kmalloc(sizeof(*msg) + para_sz, GFP_KERNEL); 85 if (!msg) 86 return -ENOMEM; 87 88 params = (struct ec_params_vbnvcontext *)msg->data; 89 params->op = EC_VBNV_CONTEXT_OP_WRITE; 90 memcpy(params->block, buf, data_sz); 91 92 msg->version = EC_VER_VBNV_CONTEXT; 93 msg->command = EC_CMD_VBNV_CONTEXT; 94 msg->outsize = para_sz; 95 msg->insize = 0; 96 97 err = cros_ec_cmd_xfer(ecdev, msg); 98 if (err < 0) { 99 dev_err(dev, "Error sending write request: %d\n", err); 100 kfree(msg); 101 return err; 102 } 103 104 kfree(msg); 105 return data_sz; 106 } 107 108 static umode_t cros_ec_vbc_is_visible(struct kobject *kobj, 109 struct bin_attribute *a, int n) 110 { 111 struct device *dev = container_of(kobj, struct device, kobj); 112 struct cros_ec_dev *ec = to_cros_ec_dev(dev); 113 struct device_node *np = ec->ec_dev->dev->of_node; 114 115 if (IS_ENABLED(CONFIG_OF) && np) { 116 if (of_property_read_bool(np, "google,has-vbc-nvram")) 117 return a->attr.mode; 118 } 119 120 return 0; 121 } 122 123 static BIN_ATTR_RW(vboot_context, 16); 124 125 static struct bin_attribute *cros_ec_vbc_bin_attrs[] = { 126 &bin_attr_vboot_context, 127 NULL 128 }; 129 130 struct attribute_group cros_ec_vbc_attr_group = { 131 .name = "vbc", 132 .bin_attrs = cros_ec_vbc_bin_attrs, 133 .is_bin_visible = cros_ec_vbc_is_visible, 134 }; 135 EXPORT_SYMBOL(cros_ec_vbc_attr_group); 136