| 1 | |
| 2 | |
| 3 | * Copyright 2014 Google, Inc.
|
| 4 |
|
| 5 |
|
| 6 | #include <linux/cdev.h>
|
| 7 | #include <linux/device.h>
|
| 8 | #include <linux/fs.h>
|
| 9 | #include <linux/uaccess.h>
|
| 10 | #include "internal.h"
|
| 11 |
|
| 12 | static DEFINE_MUTEX(pmsg_lock);
|
| 13 |
|
| 14 | static ssize_t write_pmsg(struct file *file, const char __user *buf,
|
| 15 | size_t count, loff_t *ppos)
|
| 16 | {
|
| 17 | struct pstore_record record;
|
| 18 | int ret;
|
| 19 |
|
| 20 | if (!count)
|
| 21 | return 0;
|
| 22 |
|
| 23 | pstore_record_init(&record, psinfo);
|
| 24 | record.type = PSTORE_TYPE_PMSG;
|
| 25 | record.size = count;
|
| 26 |
|
| 27 |
|
| 28 | if (!access_ok(buf, count))
|
| 29 | return -EFAULT;
|
| 30 |
|
| 31 | mutex_lock(&pmsg_lock);
|
| 32 | ret = psinfo->write_user(&record, buf);
|
| 33 | mutex_unlock(&pmsg_lock);
|
| 34 | return ret ? ret : count;
|
| 35 | }
|
| 36 |
|
| 37 | static const struct file_operations pmsg_fops = {
|
| 38 | .owner = THIS_MODULE,
|
| 39 | .llseek = noop_llseek,
|
| 40 | .write = write_pmsg,
|
| 41 | };
|
| 42 |
|
| 43 | static struct class *pmsg_class;
|
| 44 | static int pmsg_major;
|
| 45 | #define PMSG_NAME "pmsg"
|
| 46 | #undef pr_fmt
|
| 47 | #define pr_fmt(fmt) PMSG_NAME ": " fmt
|
| 48 |
|
| 49 | static char *pmsg_devnode(const struct device *dev, umode_t *mode)
|
| 50 | {
|
| 51 | if (mode)
|
| 52 | *mode = 0220;
|
| 53 | return NULL;
|
| 54 | }
|
| 55 |
|
| 56 | void pstore_register_pmsg(void)
|
| 57 | {
|
| 58 | struct device *pmsg_device;
|
| 59 |
|
| 60 | pmsg_major = register_chrdev(0, PMSG_NAME, &pmsg_fops);
|
| 61 | if (pmsg_major < 0) {
|
| 62 | pr_err("register_chrdev failed\n");
|
| 63 | goto err;
|
| 64 | }
|
| 65 |
|
| 66 | pmsg_class = class_create(PMSG_NAME);
|
| 67 | if (IS_ERR(pmsg_class)) {
|
| 68 | pr_err("device class file already in use\n");
|
| 69 | goto err_class;
|
| 70 | }
|
| 71 | pmsg_class->devnode = pmsg_devnode;
|
| 72 |
|
| 73 | pmsg_device = device_create(pmsg_class, NULL, MKDEV(pmsg_major, 0),
|
| 74 | NULL, "%s%d", PMSG_NAME, 0);
|
| 75 | if (IS_ERR(pmsg_device)) {
|
| 76 | pr_err("failed to create device\n");
|
| 77 | goto err_device;
|
| 78 | }
|
| 79 | return;
|
| 80 |
|
| 81 | err_device:
|
| 82 | class_destroy(pmsg_class);
|
| 83 | err_class:
|
| 84 | unregister_chrdev(pmsg_major, PMSG_NAME);
|
| 85 | err:
|
| 86 | return;
|
| 87 | }
|
| 88 |
|
| 89 | void pstore_unregister_pmsg(void)
|
| 90 | {
|
| 91 | device_destroy(pmsg_class, MKDEV(pmsg_major, 0));
|
| 92 | class_destroy(pmsg_class);
|
| 93 | unregister_chrdev(pmsg_major, PMSG_NAME);
|
| 94 | }
|