linux/arch/alpha/kernel/srm_env.c
<<
>>
Prefs
   1/*
   2 * srm_env.c - Access to SRM environment
   3 *             variables through linux' procfs
   4 *
   5 * (C) 2001,2002,2006 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
   6 *
   7 * This driver is at all a modified version of Erik Mouw's
   8 * Documentation/DocBook/procfs_example.c, so: thank
   9 * 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 * This program is free software; you can redistribute
  15 * it and/or modify it under the terms of the GNU General
  16 * Public License version 2 as published by the Free Software
  17 * Foundation.
  18 *
  19 * This program is distributed in the hope that it will be
  20 * useful, but WITHOUT ANY WARRANTY; without even the implied
  21 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  22 * PURPOSE.  See the GNU General Public License for more
  23 * details.
  24 *
  25 * You should have received a copy of the GNU General Public
  26 * License along with this program; if not, write to the
  27 * Free Software Foundation, Inc., 59 Temple Place,
  28 * Suite 330, Boston, MA  02111-1307  USA
  29 *
  30 */
  31
  32#include <linux/kernel.h>
  33#include <linux/module.h>
  34#include <linux/init.h>
  35#include <linux/proc_fs.h>
  36#include <asm/console.h>
  37#include <asm/uaccess.h>
  38#include <asm/machvec.h>
  39
  40#define BASE_DIR        "srm_environment"       /* Subdir in /proc/             */
  41#define NAMED_DIR       "named_variables"       /* Subdir for known variables   */
  42#define NUMBERED_DIR    "numbered_variables"    /* Subdir for all variables     */
  43#define VERSION         "0.0.6"                 /* Module version               */
  44#define NAME            "srm_env"               /* Module name                  */
  45
  46MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
  47MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface");
  48MODULE_LICENSE("GPL");
  49
  50typedef struct _srm_env {
  51        char                    *name;
  52        unsigned long           id;
  53        struct proc_dir_entry   *proc_entry;
  54} srm_env_t;
  55
  56static struct proc_dir_entry    *base_dir;
  57static struct proc_dir_entry    *named_dir;
  58static struct proc_dir_entry    *numbered_dir;
  59static char                     number[256][4];
  60
  61static srm_env_t        srm_named_entries[] = {
  62        { "auto_action",        ENV_AUTO_ACTION         },
  63        { "boot_dev",           ENV_BOOT_DEV            },
  64        { "bootdef_dev",        ENV_BOOTDEF_DEV         },
  65        { "booted_dev",         ENV_BOOTED_DEV          },
  66        { "boot_file",          ENV_BOOT_FILE           },
  67        { "booted_file",        ENV_BOOTED_FILE         },
  68        { "boot_osflags",       ENV_BOOT_OSFLAGS        },
  69        { "booted_osflags",     ENV_BOOTED_OSFLAGS      },
  70        { "boot_reset",         ENV_BOOT_RESET          },
  71        { "dump_dev",           ENV_DUMP_DEV            },
  72        { "enable_audit",       ENV_ENABLE_AUDIT        },
  73        { "license",            ENV_LICENSE             },
  74        { "char_set",           ENV_CHAR_SET            },
  75        { "language",           ENV_LANGUAGE            },
  76        { "tty_dev",            ENV_TTY_DEV             },
  77        { NULL,                 0                       },
  78};
  79static srm_env_t        srm_numbered_entries[256];
  80
  81
  82static int
  83srm_env_read(char *page, char **start, off_t off, int count, int *eof,
  84                void *data)
  85{
  86        int             nbytes;
  87        unsigned long   ret;
  88        srm_env_t       *entry;
  89
  90        if (off != 0) {
  91                *eof = 1;
  92                return 0;
  93        }
  94
  95        entry   = (srm_env_t *) data;
  96        ret     = callback_getenv(entry->id, page, count);
  97
  98        if ((ret >> 61) == 0) {
  99                nbytes = (int) ret;
 100                *eof = 1;
 101        } else
 102                nbytes = -EFAULT;
 103
 104        return nbytes;
 105}
 106
 107static int
 108srm_env_write(struct file *file, const char __user *buffer, unsigned long count,
 109                void *data)
 110{
 111        int res;
 112        srm_env_t       *entry;
 113        char            *buf = (char *) __get_free_page(GFP_USER);
 114        unsigned long   ret1, ret2;
 115
 116        entry = (srm_env_t *) data;
 117
 118        if (!buf)
 119                return -ENOMEM;
 120
 121        res = -EINVAL;
 122        if (count >= PAGE_SIZE)
 123                goto out;
 124
 125        res = -EFAULT;
 126        if (copy_from_user(buf, buffer, count))
 127                goto out;
 128        buf[count] = '\0';
 129
 130        ret1 = callback_setenv(entry->id, buf, count);
 131        if ((ret1 >> 61) == 0) {
 132                do
 133                        ret2 = callback_save_env();
 134                while((ret2 >> 61) == 1);
 135                res = (int) ret1;
 136        }
 137
 138 out:
 139        free_page((unsigned long)buf);
 140        return res;
 141}
 142
 143static void
 144srm_env_cleanup(void)
 145{
 146        srm_env_t       *entry;
 147        unsigned long   var_num;
 148
 149        if (base_dir) {
 150                /*
 151                 * Remove named entries
 152                 */
 153                if (named_dir) {
 154                        entry = srm_named_entries;
 155                        while (entry->name != NULL && entry->id != 0) {
 156                                if (entry->proc_entry) {
 157                                        remove_proc_entry(entry->name,
 158                                                        named_dir);
 159                                        entry->proc_entry = NULL;
 160                                }
 161                                entry++;
 162                        }
 163                        remove_proc_entry(NAMED_DIR, base_dir);
 164                }
 165
 166                /*
 167                 * Remove numbered entries
 168                 */
 169                if (numbered_dir) {
 170                        for (var_num = 0; var_num <= 255; var_num++) {
 171                                entry = &srm_numbered_entries[var_num];
 172
 173                                if (entry->proc_entry) {
 174                                        remove_proc_entry(entry->name,
 175                                                        numbered_dir);
 176                                        entry->proc_entry       = NULL;
 177                                        entry->name             = NULL;
 178                                }
 179                        }
 180                        remove_proc_entry(NUMBERED_DIR, base_dir);
 181                }
 182
 183                remove_proc_entry(BASE_DIR, NULL);
 184        }
 185
 186        return;
 187}
 188
 189static int __init
 190srm_env_init(void)
 191{
 192        srm_env_t       *entry;
 193        unsigned long   var_num;
 194
 195        /*
 196         * Check system
 197         */
 198        if (!alpha_using_srm) {
 199                printk(KERN_INFO "%s: This Alpha system doesn't "
 200                                "know about SRM (or you've booted "
 201                                "SRM->MILO->Linux, which gets "
 202                                "misdetected)...\n", __FUNCTION__);
 203                return -ENODEV;
 204        }
 205
 206        /*
 207         * Init numbers
 208         */
 209        for (var_num = 0; var_num <= 255; var_num++)
 210                sprintf(number[var_num], "%ld", var_num);
 211
 212        /*
 213         * Create base directory
 214         */
 215        base_dir = proc_mkdir(BASE_DIR, NULL);
 216        if (!base_dir) {
 217                printk(KERN_ERR "Couldn't create base dir /proc/%s\n",
 218                                BASE_DIR);
 219                goto cleanup;
 220        }
 221        base_dir->owner = THIS_MODULE;
 222
 223        /*
 224         * Create per-name subdirectory
 225         */
 226        named_dir = proc_mkdir(NAMED_DIR, base_dir);
 227        if (!named_dir) {
 228                printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
 229                                BASE_DIR, NAMED_DIR);
 230                goto cleanup;
 231        }
 232        named_dir->owner = THIS_MODULE;
 233
 234        /*
 235         * Create per-number subdirectory
 236         */
 237        numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir);
 238        if (!numbered_dir) {
 239                printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
 240                                BASE_DIR, NUMBERED_DIR);
 241                goto cleanup;
 242
 243        }
 244        numbered_dir->owner = THIS_MODULE;
 245
 246        /*
 247         * Create all named nodes
 248         */
 249        entry = srm_named_entries;
 250        while (entry->name && entry->id) {
 251                entry->proc_entry = create_proc_entry(entry->name,
 252                                0644, named_dir);
 253                if (!entry->proc_entry)
 254                        goto cleanup;
 255
 256                entry->proc_entry->data         = (void *) entry;
 257                entry->proc_entry->owner        = THIS_MODULE;
 258                entry->proc_entry->read_proc    = srm_env_read;
 259                entry->proc_entry->write_proc   = srm_env_write;
 260
 261                entry++;
 262        }
 263
 264        /*
 265         * Create all numbered nodes
 266         */
 267        for (var_num = 0; var_num <= 255; var_num++) {
 268                entry = &srm_numbered_entries[var_num];
 269                entry->name = number[var_num];
 270
 271                entry->proc_entry = create_proc_entry(entry->name,
 272                                0644, numbered_dir);
 273                if (!entry->proc_entry)
 274                        goto cleanup;
 275
 276                entry->id                       = var_num;
 277                entry->proc_entry->data         = (void *) entry;
 278                entry->proc_entry->owner        = THIS_MODULE;
 279                entry->proc_entry->read_proc    = srm_env_read;
 280                entry->proc_entry->write_proc   = srm_env_write;
 281        }
 282
 283        printk(KERN_INFO "%s: version %s loaded successfully\n", NAME,
 284                        VERSION);
 285
 286        return 0;
 287
 288cleanup:
 289        srm_env_cleanup();
 290
 291        return -ENOMEM;
 292}
 293
 294static void __exit
 295srm_env_exit(void)
 296{
 297        srm_env_cleanup();
 298        printk(KERN_INFO "%s: unloaded successfully\n", NAME);
 299
 300        return;
 301}
 302
 303module_init(srm_env_init);
 304module_exit(srm_env_exit);
 305