Logo Search packages:      
Sourcecode: linux version File versions  Download package

srm_env.c

/*
 * srm_env.c - Access to SRM environment
 *             variables through linux' procfs
 *
 * (C) 2001,2002,2006 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
 *
 * This driver is at all a modified version of Erik Mouw's
 * Documentation/DocBook/procfs_example.c, so: thank
 * you, Erik! He can be reached via email at
 * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea
 * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They
 * included a patch like this as well. Thanks for idea!
 *
 * This program is free software; you can redistribute
 * it and/or modify it under the terms of the GNU General
 * Public License version 2 as published by the Free Software
 * Foundation.
 *
 * This program is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place,
 * Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/console.h>
#include <asm/uaccess.h>
#include <asm/machvec.h>

#define BASE_DIR  "srm_environment" /* Subdir in /proc/           */
#define NAMED_DIR "named_variables" /* Subdir for known variables */
#define NUMBERED_DIR    "numbered_variables"    /* Subdir for all variables   */
#define VERSION         "0.0.6"                 /* Module version       */
#define NAME            "srm_env"         /* Module name                */

MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface");
MODULE_LICENSE("GPL");

00052 typedef struct _srm_env {
      char              *name;
      unsigned long           id;
      struct proc_dir_entry   *proc_entry;
} srm_env_t;

static struct proc_dir_entry  *base_dir;
static struct proc_dir_entry  *named_dir;
static struct proc_dir_entry  *numbered_dir;
static char             number[256][4];

static srm_env_t  srm_named_entries[] = {
      { "auto_action",  ENV_AUTO_ACTION         },
      { "boot_dev",           ENV_BOOT_DEV            },
      { "bootdef_dev",  ENV_BOOTDEF_DEV         },
      { "booted_dev",         ENV_BOOTED_DEV          },
      { "boot_file",          ENV_BOOT_FILE           },
      { "booted_file",  ENV_BOOTED_FILE         },
      { "boot_osflags", ENV_BOOT_OSFLAGS  },
      { "booted_osflags",     ENV_BOOTED_OSFLAGS      },
      { "boot_reset",         ENV_BOOT_RESET          },
      { "dump_dev",           ENV_DUMP_DEV            },
      { "enable_audit", ENV_ENABLE_AUDIT  },
      { "license",            ENV_LICENSE       },
      { "char_set",           ENV_CHAR_SET            },
      { "language",           ENV_LANGUAGE            },
      { "tty_dev",            ENV_TTY_DEV       },
      { NULL,                 0                 },
};
static srm_env_t  srm_numbered_entries[256];


static int srm_env_proc_show(struct seq_file *m, void *v)
{
      unsigned long     ret;
      srm_env_t   *entry;
      char        *page;

      entry = m->private;
      page = (char *)__get_free_page(GFP_USER);
      if (!page)
            return -ENOMEM;

      ret = callback_getenv(entry->id, page, PAGE_SIZE);

      if ((ret >> 61) == 0) {
            seq_write(m, page, ret);
            ret = 0;
      } else
            ret = -EFAULT;
      free_page((unsigned long)page);
      return ret;
}

static int srm_env_proc_open(struct inode *inode, struct file *file)
{
      return single_open(file, srm_env_proc_show, PDE(inode)->data);
}

static ssize_t srm_env_proc_write(struct file *file, const char __user *buffer,
                          size_t count, loff_t *pos)
{
      int res;
      srm_env_t   *entry = PDE(file->f_path.dentry->d_inode)->data;
      char        *buf = (char *) __get_free_page(GFP_USER);
      unsigned long     ret1, ret2;

      if (!buf)
            return -ENOMEM;

      res = -EINVAL;
      if (count >= PAGE_SIZE)
            goto out;

      res = -EFAULT;
      if (copy_from_user(buf, buffer, count))
            goto out;
      buf[count] = '\0';

      ret1 = callback_setenv(entry->id, buf, count);
      if ((ret1 >> 61) == 0) {
            do
                  ret2 = callback_save_env();
            while((ret2 >> 61) == 1);
            res = (int) ret1;
      }

 out:
      free_page((unsigned long)buf);
      return res;
}

static const struct file_operations srm_env_proc_fops = {
      .owner            = THIS_MODULE,
      .open       = srm_env_proc_open,
      .read       = seq_read,
      .llseek           = seq_lseek,
      .release    = single_release,
      .write            = srm_env_proc_write,
};

static void
srm_env_cleanup(void)
{
      srm_env_t   *entry;
      unsigned long     var_num;

      if (base_dir) {
            /*
             * Remove named entries
             */
            if (named_dir) {
                  entry = srm_named_entries;
                  while (entry->name != NULL && entry->id != 0) {
                        if (entry->proc_entry) {
                              remove_proc_entry(entry->name,
                                          named_dir);
                              entry->proc_entry = NULL;
                        }
                        entry++;
                  }
                  remove_proc_entry(NAMED_DIR, base_dir);
            }

            /*
             * Remove numbered entries
             */
            if (numbered_dir) {
                  for (var_num = 0; var_num <= 255; var_num++) {
                        entry =     &srm_numbered_entries[var_num];

                        if (entry->proc_entry) {
                              remove_proc_entry(entry->name,
                                          numbered_dir);
                              entry->proc_entry = NULL;
                              entry->name       = NULL;
                        }
                  }
                  remove_proc_entry(NUMBERED_DIR, base_dir);
            }

            remove_proc_entry(BASE_DIR, NULL);
      }

      return;
}

static int __init
srm_env_init(void)
{
      srm_env_t   *entry;
      unsigned long     var_num;

      /*
       * Check system
       */
      if (!alpha_using_srm) {
            printk(KERN_INFO "%s: This Alpha system doesn't "
                        "know about SRM (or you've booted "
                        "SRM->MILO->Linux, which gets "
                        "misdetected)...\n", __func__);
            return -ENODEV;
      }

      /*
       * Init numbers
       */
      for (var_num = 0; var_num <= 255; var_num++)
            sprintf(number[var_num], "%ld", var_num);

      /*
       * Create base directory
       */
      base_dir = proc_mkdir(BASE_DIR, NULL);
      if (!base_dir) {
            printk(KERN_ERR "Couldn't create base dir /proc/%s\n",
                        BASE_DIR);
            goto cleanup;
      }

      /*
       * Create per-name subdirectory
       */
      named_dir = proc_mkdir(NAMED_DIR, base_dir);
      if (!named_dir) {
            printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
                        BASE_DIR, NAMED_DIR);
            goto cleanup;
      }

      /*
       * Create per-number subdirectory
       */
      numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir);
      if (!numbered_dir) {
            printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
                        BASE_DIR, NUMBERED_DIR);
            goto cleanup;

      }

      /*
       * Create all named nodes
       */
      entry = srm_named_entries;
      while (entry->name && entry->id) {
            entry->proc_entry = proc_create_data(entry->name, 0644, named_dir,
                                         &srm_env_proc_fops, entry);
            if (!entry->proc_entry)
                  goto cleanup;
            entry++;
      }

      /*
       * Create all numbered nodes
       */
      for (var_num = 0; var_num <= 255; var_num++) {
            entry = &srm_numbered_entries[var_num];
            entry->name = number[var_num];

            entry->proc_entry = proc_create_data(entry->name, 0644, numbered_dir,
                                         &srm_env_proc_fops, entry);
            if (!entry->proc_entry)
                  goto cleanup;

            entry->id               = var_num;
      }

      printk(KERN_INFO "%s: version %s loaded successfully\n", NAME,
                  VERSION);

      return 0;

cleanup:
      srm_env_cleanup();

      return -ENOMEM;
}

static void __exit
srm_env_exit(void)
{
      srm_env_cleanup();
      printk(KERN_INFO "%s: unloaded successfully\n", NAME);

      return;
}

module_init(srm_env_init);
module_exit(srm_env_exit);

Generated by  Doxygen 1.6.0   Back to index