Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 // Expose the vboot context nvram to userspace
0003 //
0004 // Copyright (C) 2012 Google, Inc.
0005 // Copyright (C) 2015 Collabora Ltd.
0006 
0007 #include <linux/of.h>
0008 #include <linux/platform_device.h>
0009 #include <linux/module.h>
0010 #include <linux/platform_data/cros_ec_commands.h>
0011 #include <linux/platform_data/cros_ec_proto.h>
0012 #include <linux/slab.h>
0013 
0014 #define DRV_NAME "cros-ec-vbc"
0015 
0016 static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj,
0017                   struct bin_attribute *att, char *buf,
0018                   loff_t pos, size_t count)
0019 {
0020     struct device *dev = kobj_to_dev(kobj);
0021     struct cros_ec_dev *ec = to_cros_ec_dev(dev);
0022     struct cros_ec_device *ecdev = ec->ec_dev;
0023     struct ec_params_vbnvcontext *params;
0024     struct cros_ec_command *msg;
0025     int err;
0026     const size_t para_sz = sizeof(params->op);
0027     const size_t resp_sz = sizeof(struct ec_response_vbnvcontext);
0028     const size_t payload = max(para_sz, resp_sz);
0029 
0030     msg = kmalloc(sizeof(*msg) + payload, GFP_KERNEL);
0031     if (!msg)
0032         return -ENOMEM;
0033 
0034     /* NB: we only kmalloc()ated enough space for the op field */
0035     params = (struct ec_params_vbnvcontext *)msg->data;
0036     params->op = EC_VBNV_CONTEXT_OP_READ;
0037 
0038     msg->version = EC_VER_VBNV_CONTEXT;
0039     msg->command = EC_CMD_VBNV_CONTEXT;
0040     msg->outsize = para_sz;
0041     msg->insize = resp_sz;
0042 
0043     err = cros_ec_cmd_xfer_status(ecdev, msg);
0044     if (err < 0) {
0045         dev_err(dev, "Error sending read request: %d\n", err);
0046         kfree(msg);
0047         return err;
0048     }
0049 
0050     memcpy(buf, msg->data, resp_sz);
0051 
0052     kfree(msg);
0053     return resp_sz;
0054 }
0055 
0056 static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj,
0057                    struct bin_attribute *attr, char *buf,
0058                    loff_t pos, size_t count)
0059 {
0060     struct device *dev = kobj_to_dev(kobj);
0061     struct cros_ec_dev *ec = to_cros_ec_dev(dev);
0062     struct cros_ec_device *ecdev = ec->ec_dev;
0063     struct ec_params_vbnvcontext *params;
0064     struct cros_ec_command *msg;
0065     int err;
0066     const size_t para_sz = sizeof(*params);
0067     const size_t data_sz = sizeof(params->block);
0068 
0069     /* Only write full values */
0070     if (count != data_sz)
0071         return -EINVAL;
0072 
0073     msg = kmalloc(sizeof(*msg) + para_sz, GFP_KERNEL);
0074     if (!msg)
0075         return -ENOMEM;
0076 
0077     params = (struct ec_params_vbnvcontext *)msg->data;
0078     params->op = EC_VBNV_CONTEXT_OP_WRITE;
0079     memcpy(params->block, buf, data_sz);
0080 
0081     msg->version = EC_VER_VBNV_CONTEXT;
0082     msg->command = EC_CMD_VBNV_CONTEXT;
0083     msg->outsize = para_sz;
0084     msg->insize = 0;
0085 
0086     err = cros_ec_cmd_xfer_status(ecdev, msg);
0087     if (err < 0) {
0088         dev_err(dev, "Error sending write request: %d\n", err);
0089         kfree(msg);
0090         return err;
0091     }
0092 
0093     kfree(msg);
0094     return data_sz;
0095 }
0096 
0097 static BIN_ATTR_RW(vboot_context, 16);
0098 
0099 static struct bin_attribute *cros_ec_vbc_bin_attrs[] = {
0100     &bin_attr_vboot_context,
0101     NULL
0102 };
0103 
0104 static const struct attribute_group cros_ec_vbc_attr_group = {
0105     .name = "vbc",
0106     .bin_attrs = cros_ec_vbc_bin_attrs,
0107 };
0108 
0109 static int cros_ec_vbc_probe(struct platform_device *pd)
0110 {
0111     struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
0112     struct device *dev = &pd->dev;
0113     int ret;
0114 
0115     ret = sysfs_create_group(&ec_dev->class_dev.kobj,
0116                  &cros_ec_vbc_attr_group);
0117     if (ret < 0)
0118         dev_err(dev, "failed to create %s attributes. err=%d\n",
0119             cros_ec_vbc_attr_group.name, ret);
0120 
0121     return ret;
0122 }
0123 
0124 static int cros_ec_vbc_remove(struct platform_device *pd)
0125 {
0126     struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
0127 
0128     sysfs_remove_group(&ec_dev->class_dev.kobj,
0129                &cros_ec_vbc_attr_group);
0130 
0131     return 0;
0132 }
0133 
0134 static struct platform_driver cros_ec_vbc_driver = {
0135     .driver = {
0136         .name = DRV_NAME,
0137     },
0138     .probe = cros_ec_vbc_probe,
0139     .remove = cros_ec_vbc_remove,
0140 };
0141 
0142 module_platform_driver(cros_ec_vbc_driver);
0143 
0144 MODULE_LICENSE("GPL");
0145 MODULE_DESCRIPTION("Expose the vboot context nvram to userspace");
0146 MODULE_ALIAS("platform:" DRV_NAME);