linux/arch/alpha/kernel/srm_env.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * srm_env.c - Access to SRM environment
   4 *             variables through linux' procfs
   5 *
   6 * (C) 2001,2002,2006 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
   7 *
   8 * This driver is a modified version of Erik Mouw's example proc
   9 * interface, so: thank you, Erik! He can be reached via email at
  10 * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea
  11 * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They
  12 * included a patch like this as well. Thanks for idea!
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/gfp.h>
  17#include <linux/module.h>
  18#include <linux/init.h>
  19#include <linux/proc_fs.h>
  20#include <linux/seq_file.h>
  21#include <asm/console.h>
  22#include <linux/uaccess.h>
  23#include <asm/machvec.h>
  24
  25#define BASE_DIR        "srm_environment"       /* Subdir in /proc/             */
  26#define NAMED_DIR       "named_variables"       /* Subdir for known variables   */
  27#define NUMBERED_DIR    "numbered_variables"    /* Subdir for all variables     */
  28#define VERSION         "0.0.6"                 /* Module version               */
  29#define NAME            "srm_env"               /* Module name                  */
  30
  31MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
  32MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface");
  33MODULE_LICENSE("GPL");
  34
  35typedef struct _srm_env {
  36        char                    *name;
  37        unsigned long           id;
  38} srm_env_t;
  39
  40static struct proc_dir_entry    *base_dir;
  41static struct proc_dir_entry    *named_dir;
  42static struct proc_dir_entry    *numbered_dir;
  43
  44static srm_env_t        srm_named_entries[] = {
  45        { "auto_action",        ENV_AUTO_ACTION         },
  46        { "boot_dev",           ENV_BOOT_DEV            },
  47        { "bootdef_dev",        ENV_BOOTDEF_DEV         },
  48        { "booted_dev",         ENV_BOOTED_DEV          },
  49        { "boot_file",          ENV_BOOT_FILE           },
  50        { "booted_file",        ENV_BOOTED_FILE         },
  51        { "boot_osflags",       ENV_BOOT_OSFLAGS        },
  52        { "booted_osflags",     ENV_BOOTED_OSFLAGS      },
  53        { "boot_reset",         ENV_BOOT_RESET          },
  54        { "dump_dev",           ENV_DUMP_DEV            },
  55        { "enable_audit",       ENV_ENABLE_AUDIT        },
  56        { "license",            ENV_LICENSE             },
  57        { "char_set",           ENV_CHAR_SET            },
  58        { "language",           ENV_LANGUAGE            },
  59        { "tty_dev",            ENV_TTY_DEV             },
  60        { NULL,                 0                       },
  61};
  62
  63static int srm_env_proc_show(struct seq_file *m, void *v)
  64{
  65        unsigned long   ret;
  66        unsigned long   id = (unsigned long)m->private;
  67        char            *page;
  68
  69        page = (char *)__get_free_page(GFP_USER);
  70        if (!page)
  71                return -ENOMEM;
  72
  73        ret = callback_getenv(id, page, PAGE_SIZE);
  74
  75        if ((ret >> 61) == 0) {
  76                seq_write(m, page, ret);
  77                ret = 0;
  78        } else
  79                ret = -EFAULT;
  80        free_page((unsigned long)page);
  81        return ret;
  82}
  83
  84static int srm_env_proc_open(struct inode *inode, struct file *file)
  85{
  86        return single_open(file, srm_env_proc_show, PDE_DATA(inode));
  87}
  88
  89static ssize_t srm_env_proc_write(struct file *file, const char __user *buffer,
  90                                  size_t count, loff_t *pos)
  91{
  92        int res;
  93        unsigned long   id = (unsigned long)PDE_DATA(file_inode(file));
  94        char            *buf = (char *) __get_free_page(GFP_USER);
  95        unsigned long   ret1, ret2;
  96
  97        if (!buf)
  98                return -ENOMEM;
  99
 100        res = -EINVAL;
 101        if (count >= PAGE_SIZE)
 102                goto out;
 103
 104        res = -EFAULT;
 105        if (copy_from_user(buf, buffer, count))
 106                goto out;
 107        buf[count] = '\0';
 108
 109        ret1 = callback_setenv(id, buf, count);
 110        if ((ret1 >> 61) == 0) {
 111                do
 112                        ret2 = callback_save_env();
 113                while((ret2 >> 61) == 1);
 114                res = (int) ret1;
 115        }
 116
 117 out:
 118        free_page((unsigned long)buf);
 119        return res;
 120}
 121
 122static const struct proc_ops srm_env_proc_ops = {
 123        .proc_open      = srm_env_proc_open,
 124        .proc_read      = seq_read,
 125        .proc_lseek     = seq_lseek,
 126        .proc_release   = single_release,
 127        .proc_write     = srm_env_proc_write,
 128};
 129
 130static int __init
 131srm_env_init(void)
 132{
 133        srm_env_t       *entry;
 134        unsigned long   var_num;
 135
 136        /*
 137         * Check system
 138         */
 139        if (!alpha_using_srm) {
 140                printk(KERN_INFO "%s: This Alpha system doesn't "
 141                                "know about SRM (or you've booted "
 142                                "SRM->MILO->Linux, which gets "
 143                                "misdetected)...\n", __func__);
 144                return -ENODEV;
 145        }
 146
 147        /*
 148         * Create base directory
 149         */
 150        base_dir = proc_mkdir(BASE_DIR, NULL);
 151        if (!base_dir) {
 152                printk(KERN_ERR "Couldn't create base dir /proc/%s\n",
 153                                BASE_DIR);
 154                return -ENOMEM;
 155        }
 156
 157        /*
 158         * Create per-name subdirectory
 159         */
 160        named_dir = proc_mkdir(NAMED_DIR, base_dir);
 161        if (!named_dir) {
 162                printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
 163                                BASE_DIR, NAMED_DIR);
 164                goto cleanup;
 165        }
 166
 167        /*
 168         * Create per-number subdirectory
 169         */
 170        numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir);
 171        if (!numbered_dir) {
 172                printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
 173                                BASE_DIR, NUMBERED_DIR);
 174                goto cleanup;
 175
 176        }
 177
 178        /*
 179         * Create all named nodes
 180         */
 181        entry = srm_named_entries;
 182        while (entry->name && entry->id) {
 183                if (!proc_create_data(entry->name, 0644, named_dir,
 184                             &srm_env_proc_ops, (void *)entry->id))
 185                        goto cleanup;
 186                entry++;
 187        }
 188
 189        /*
 190         * Create all numbered nodes
 191         */
 192        for (var_num = 0; var_num <= 255; var_num++) {
 193                char name[4];
 194                sprintf(name, "%ld", var_num);
 195                if (!proc_create_data(name, 0644, numbered_dir,
 196                             &srm_env_proc_ops, (void *)var_num))
 197                        goto cleanup;
 198        }
 199
 200        printk(KERN_INFO "%s: version %s loaded successfully\n", NAME,
 201                        VERSION);
 202
 203        return 0;
 204
 205cleanup:
 206        remove_proc_subtree(BASE_DIR, NULL);
 207        return -ENOMEM;
 208}
 209
 210static void __exit
 211srm_env_exit(void)
 212{
 213        remove_proc_subtree(BASE_DIR, NULL);
 214        printk(KERN_INFO "%s: unloaded successfully\n", NAME);
 215}
 216
 217module_init(srm_env_init);
 218module_exit(srm_env_exit);
 219