diff options
Diffstat (limited to 'drivers/power/reset/reboot-mode.c')
-rw-r--r-- | drivers/power/reset/reboot-mode.c | 69 |
1 files changed, 62 insertions, 7 deletions
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index 1afccd2300b1..2597d8cf798e 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -10,9 +10,11 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/kobject.h> #include <linux/module.h> #include <linux/of.h> #include <linux/reboot.h> +#include <linux/sysfs.h> #include "reboot-mode.h" #define PREFIX "mode-" @@ -26,9 +28,21 @@ struct mode_info { struct reboot_mode_driver { struct list_head head; int (*write)(int magic); + int (*read)(void); struct notifier_block reboot_notifier; + struct notifier_block panic_notifier; }; +static char *boot_mode = "coldboot"; + +static ssize_t boot_mode_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", boot_mode); +} + +static struct kobj_attribute kobj_boot_mode = __ATTR_RO(boot_mode); + static int get_reboot_mode_magic(struct reboot_mode_driver *reboot, const char *cmd) { @@ -49,23 +63,60 @@ static int get_reboot_mode_magic(struct reboot_mode_driver *reboot, return magic; } -static int reboot_mode_notify(struct notifier_block *this, - unsigned long mode, void *cmd) +static void reboot_mode_write(struct reboot_mode_driver *reboot, + const void *cmd) { - struct reboot_mode_driver *reboot; int magic; - reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); magic = get_reboot_mode_magic(reboot, cmd); if (!magic) magic = get_reboot_mode_magic(reboot, NULL); if (magic) reboot->write(magic); +} + +static int reboot_mode_notify(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct reboot_mode_driver *reboot; + + reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); + reboot_mode_write(reboot, cmd); return NOTIFY_DONE; } -int reboot_mode_register(struct device *dev, int (*write)(int)) +static int reboot_mode_panic_notify(struct notifier_block *this, + unsigned long ev, void *ptr) +{ + struct reboot_mode_driver *reboot; + const char *cmd = "panic"; + + reboot = container_of(this, struct reboot_mode_driver, panic_notifier); + reboot_mode_write(reboot, cmd); + + return NOTIFY_DONE; +} + +static int boot_mode_parse(struct reboot_mode_driver *reboot) +{ + struct mode_info *info; + unsigned int magic = reboot->read(); + + list_for_each_entry(info, &reboot->head, list) { + if (info->magic == magic) { + boot_mode = info->mode; + break; + } + } + + pr_info("Boot mode: %s\n", boot_mode); + + return 0; +} + +int reboot_mode_register(struct device *dev, int (*write)(int), + int (*read)(void)) { struct reboot_mode_driver *reboot; struct mode_info *info; @@ -78,6 +129,7 @@ int reboot_mode_register(struct device *dev, int (*write)(int)) return -ENOMEM; reboot->write = write; + reboot->read = read; INIT_LIST_HEAD(&reboot->head); for_each_property_of_node(dev->of_node, prop) { if (len > strlen(prop->name) || strncmp(prop->name, PREFIX, len)) @@ -94,10 +146,13 @@ int reboot_mode_register(struct device *dev, int (*write)(int)) } list_add_tail(&info->list, &reboot->head); } + boot_mode_parse(reboot); reboot->reboot_notifier.notifier_call = reboot_mode_notify; + reboot->panic_notifier.notifier_call = reboot_mode_panic_notify; ret = register_reboot_notifier(&reboot->reboot_notifier); - if (ret) - dev_err(dev, "can't register reboot notifier\n"); + ret += atomic_notifier_chain_register(&panic_notifier_list, + &reboot->panic_notifier); + ret += sysfs_create_file(kernel_kobj, &kobj_boot_mode.attr); return ret; } |