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 = container_of(dev, struct cros_ec_dev, 33 class_dev); 34 struct cros_ec_device *ecdev = ec->ec_dev; 35 struct ec_params_vbnvcontext *params; 36 struct cros_ec_command *msg; 37 int err; 38 const size_t para_sz = sizeof(params->op); 39 const size_t resp_sz = sizeof(struct ec_response_vbnvcontext); 40 const size_t payload = max(para_sz, resp_sz); 41 42 msg = kmalloc(sizeof(*msg) + payload, GFP_KERNEL); 43 if (!msg) 44 return -ENOMEM; 45 46 /* NB: we only kmalloc()ated enough space for the op field */ 47 params = (struct ec_params_vbnvcontext *)msg->data; 48 params->op = EC_VBNV_CONTEXT_OP_READ; 49 50 msg->version = EC_VER_VBNV_CONTEXT; 51 msg->command = EC_CMD_VBNV_CONTEXT; 52 msg->outsize = para_sz; 53 msg->insize = resp_sz; 54 55 err = cros_ec_cmd_xfer(ecdev, msg); 56 if (err < 0) { 57 dev_err(dev, "Error sending read request: %d\n", err); 58 kfree(msg); 59 return err; 60 } 61 62 memcpy(buf, msg->data, resp_sz); 63 64 kfree(msg); 65 return resp_sz; 66 } 67 68 static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj, 69 struct bin_attribute *attr, char *buf, 70 loff_t pos, size_t count) 71 { 72 struct device *dev = container_of(kobj, struct device, kobj); 73 struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, 74 class_dev); 75 struct cros_ec_device *ecdev = ec->ec_dev; 76 struct ec_params_vbnvcontext *params; 77 struct cros_ec_command *msg; 78 int err; 79 const size_t para_sz = sizeof(*params); 80 const size_t data_sz = sizeof(params->block); 81 82 /* Only write full values */ 83 if (count != data_sz) 84 return -EINVAL; 85 86 msg = kmalloc(sizeof(*msg) + para_sz, GFP_KERNEL); 87 if (!msg) 88 return -ENOMEM; 89 90 params = (struct ec_params_vbnvcontext *)msg->data; 91 params->op = EC_VBNV_CONTEXT_OP_WRITE; 92 memcpy(params->block, buf, data_sz); 93 94 msg->version = EC_VER_VBNV_CONTEXT; 95 msg->command = EC_CMD_VBNV_CONTEXT; 96 msg->outsize = para_sz; 97 msg->insize = 0; 98 99 err = cros_ec_cmd_xfer(ecdev, msg); 100 if (err < 0) { 101 dev_err(dev, "Error sending write request: %d\n", err); 102 kfree(msg); 103 return err; 104 } 105 106 kfree(msg); 107 return data_sz; 108 } 109 110 static umode_t cros_ec_vbc_is_visible(struct kobject *kobj, 111 struct bin_attribute *a, int n) 112 { 113 struct device *dev = container_of(kobj, struct device, kobj); 114 struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, 115 class_dev); 116 struct device_node *np = ec->ec_dev->dev->of_node; 117 118 if (IS_ENABLED(CONFIG_OF) && np) { 119 if (of_property_read_bool(np, "google,has-vbc-nvram")) 120 return a->attr.mode; 121 } 122 123 return 0; 124 } 125 126 static BIN_ATTR_RW(vboot_context, 16); 127 128 static struct bin_attribute *cros_ec_vbc_bin_attrs[] = { 129 &bin_attr_vboot_context, 130 NULL 131 }; 132 133 struct attribute_group cros_ec_vbc_attr_group = { 134 .name = "vbc", 135 .bin_attrs = cros_ec_vbc_bin_attrs, 136 .is_bin_visible = cros_ec_vbc_is_visible, 137 }; 138