root/drivers/power/reset/reboot-mode.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_reboot_mode_magic
  2. reboot_mode_notify
  3. reboot_mode_register
  4. reboot_mode_unregister
  5. devm_reboot_mode_release
  6. devm_reboot_mode_register
  7. devm_reboot_mode_match
  8. devm_reboot_mode_unregister

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
   4  */
   5 
   6 #include <linux/device.h>
   7 #include <linux/init.h>
   8 #include <linux/kernel.h>
   9 #include <linux/module.h>
  10 #include <linux/of.h>
  11 #include <linux/reboot.h>
  12 #include <linux/reboot-mode.h>
  13 
  14 #define PREFIX "mode-"
  15 
  16 struct mode_info {
  17         const char *mode;
  18         u32 magic;
  19         struct list_head list;
  20 };
  21 
  22 static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot,
  23                                           const char *cmd)
  24 {
  25         const char *normal = "normal";
  26         int magic = 0;
  27         struct mode_info *info;
  28 
  29         if (!cmd)
  30                 cmd = normal;
  31 
  32         list_for_each_entry(info, &reboot->head, list) {
  33                 if (!strcmp(info->mode, cmd)) {
  34                         magic = info->magic;
  35                         break;
  36                 }
  37         }
  38 
  39         return magic;
  40 }
  41 
  42 static int reboot_mode_notify(struct notifier_block *this,
  43                               unsigned long mode, void *cmd)
  44 {
  45         struct reboot_mode_driver *reboot;
  46         unsigned int magic;
  47 
  48         reboot = container_of(this, struct reboot_mode_driver, reboot_notifier);
  49         magic = get_reboot_mode_magic(reboot, cmd);
  50         if (magic)
  51                 reboot->write(reboot, magic);
  52 
  53         return NOTIFY_DONE;
  54 }
  55 
  56 /**
  57  * reboot_mode_register - register a reboot mode driver
  58  * @reboot: reboot mode driver
  59  *
  60  * Returns: 0 on success or a negative error code on failure.
  61  */
  62 int reboot_mode_register(struct reboot_mode_driver *reboot)
  63 {
  64         struct mode_info *info;
  65         struct property *prop;
  66         struct device_node *np = reboot->dev->of_node;
  67         size_t len = strlen(PREFIX);
  68         int ret;
  69 
  70         INIT_LIST_HEAD(&reboot->head);
  71 
  72         for_each_property_of_node(np, prop) {
  73                 if (strncmp(prop->name, PREFIX, len))
  74                         continue;
  75 
  76                 info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL);
  77                 if (!info) {
  78                         ret = -ENOMEM;
  79                         goto error;
  80                 }
  81 
  82                 if (of_property_read_u32(np, prop->name, &info->magic)) {
  83                         dev_err(reboot->dev, "reboot mode %s without magic number\n",
  84                                 info->mode);
  85                         devm_kfree(reboot->dev, info);
  86                         continue;
  87                 }
  88 
  89                 info->mode = kstrdup_const(prop->name + len, GFP_KERNEL);
  90                 if (!info->mode) {
  91                         ret =  -ENOMEM;
  92                         goto error;
  93                 } else if (info->mode[0] == '\0') {
  94                         kfree_const(info->mode);
  95                         ret = -EINVAL;
  96                         dev_err(reboot->dev, "invalid mode name(%s): too short!\n",
  97                                 prop->name);
  98                         goto error;
  99                 }
 100 
 101                 list_add_tail(&info->list, &reboot->head);
 102         }
 103 
 104         reboot->reboot_notifier.notifier_call = reboot_mode_notify;
 105         register_reboot_notifier(&reboot->reboot_notifier);
 106 
 107         return 0;
 108 
 109 error:
 110         list_for_each_entry(info, &reboot->head, list)
 111                 kfree_const(info->mode);
 112 
 113         return ret;
 114 }
 115 EXPORT_SYMBOL_GPL(reboot_mode_register);
 116 
 117 /**
 118  * reboot_mode_unregister - unregister a reboot mode driver
 119  * @reboot: reboot mode driver
 120  */
 121 int reboot_mode_unregister(struct reboot_mode_driver *reboot)
 122 {
 123         struct mode_info *info;
 124 
 125         unregister_reboot_notifier(&reboot->reboot_notifier);
 126 
 127         list_for_each_entry(info, &reboot->head, list)
 128                 kfree_const(info->mode);
 129 
 130         return 0;
 131 }
 132 EXPORT_SYMBOL_GPL(reboot_mode_unregister);
 133 
 134 static void devm_reboot_mode_release(struct device *dev, void *res)
 135 {
 136         reboot_mode_unregister(*(struct reboot_mode_driver **)res);
 137 }
 138 
 139 /**
 140  * devm_reboot_mode_register() - resource managed reboot_mode_register()
 141  * @dev: device to associate this resource with
 142  * @reboot: reboot mode driver
 143  *
 144  * Returns: 0 on success or a negative error code on failure.
 145  */
 146 int devm_reboot_mode_register(struct device *dev,
 147                               struct reboot_mode_driver *reboot)
 148 {
 149         struct reboot_mode_driver **dr;
 150         int rc;
 151 
 152         dr = devres_alloc(devm_reboot_mode_release, sizeof(*dr), GFP_KERNEL);
 153         if (!dr)
 154                 return -ENOMEM;
 155 
 156         rc = reboot_mode_register(reboot);
 157         if (rc) {
 158                 devres_free(dr);
 159                 return rc;
 160         }
 161 
 162         *dr = reboot;
 163         devres_add(dev, dr);
 164 
 165         return 0;
 166 }
 167 EXPORT_SYMBOL_GPL(devm_reboot_mode_register);
 168 
 169 static int devm_reboot_mode_match(struct device *dev, void *res, void *data)
 170 {
 171         struct reboot_mode_driver **p = res;
 172 
 173         if (WARN_ON(!p || !*p))
 174                 return 0;
 175 
 176         return *p == data;
 177 }
 178 
 179 /**
 180  * devm_reboot_mode_unregister() - resource managed reboot_mode_unregister()
 181  * @dev: device to associate this resource with
 182  * @reboot: reboot mode driver
 183  */
 184 void devm_reboot_mode_unregister(struct device *dev,
 185                                  struct reboot_mode_driver *reboot)
 186 {
 187         WARN_ON(devres_release(dev,
 188                                devm_reboot_mode_release,
 189                                devm_reboot_mode_match, reboot));
 190 }
 191 EXPORT_SYMBOL_GPL(devm_reboot_mode_unregister);
 192 
 193 MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
 194 MODULE_DESCRIPTION("System reboot mode core library");
 195 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */