linux/drivers/char/generic_nvram.c
<<
>>
Prefs
   1/*
   2 * Generic /dev/nvram driver for architectures providing some
   3 * "generic" hooks, that is :
   4 *
   5 * nvram_read_byte, nvram_write_byte, nvram_sync, nvram_get_size
   6 *
   7 * Note that an additional hook is supported for PowerMac only
   8 * for getting the nvram "partition" informations
   9 *
  10 */
  11
  12#define NVRAM_VERSION "1.1"
  13
  14#include <linux/module.h>
  15
  16#include <linux/types.h>
  17#include <linux/errno.h>
  18#include <linux/fs.h>
  19#include <linux/miscdevice.h>
  20#include <linux/fcntl.h>
  21#include <linux/init.h>
  22#include <linux/mutex.h>
  23#include <asm/uaccess.h>
  24#include <asm/nvram.h>
  25#ifdef CONFIG_PPC_PMAC
  26#include <asm/machdep.h>
  27#endif
  28
  29#define NVRAM_SIZE      8192
  30
  31static DEFINE_MUTEX(nvram_mutex);
  32static ssize_t nvram_len;
  33
  34static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
  35{
  36        switch (origin) {
  37        case 0:
  38                break;
  39        case 1:
  40                offset += file->f_pos;
  41                break;
  42        case 2:
  43                offset += nvram_len;
  44                break;
  45        default:
  46                offset = -1;
  47        }
  48        if (offset < 0)
  49                return -EINVAL;
  50
  51        file->f_pos = offset;
  52
  53        return file->f_pos;
  54}
  55
  56static ssize_t read_nvram(struct file *file, char __user *buf,
  57                          size_t count, loff_t *ppos)
  58{
  59        unsigned int i;
  60        char __user *p = buf;
  61
  62        if (!access_ok(VERIFY_WRITE, buf, count))
  63                return -EFAULT;
  64        if (*ppos >= nvram_len)
  65                return 0;
  66        for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
  67                if (__put_user(nvram_read_byte(i), p))
  68                        return -EFAULT;
  69        *ppos = i;
  70        return p - buf;
  71}
  72
  73static ssize_t write_nvram(struct file *file, const char __user *buf,
  74                           size_t count, loff_t *ppos)
  75{
  76        unsigned int i;
  77        const char __user *p = buf;
  78        char c;
  79
  80        if (!access_ok(VERIFY_READ, buf, count))
  81                return -EFAULT;
  82        if (*ppos >= nvram_len)
  83                return 0;
  84        for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count) {
  85                if (__get_user(c, p))
  86                        return -EFAULT;
  87                nvram_write_byte(c, i);
  88        }
  89        *ppos = i;
  90        return p - buf;
  91}
  92
  93static int nvram_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  94{
  95        switch(cmd) {
  96#ifdef CONFIG_PPC_PMAC
  97        case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
  98                printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
  99        case IOC_NVRAM_GET_OFFSET: {
 100                int part, offset;
 101
 102                if (!machine_is(powermac))
 103                        return -EINVAL;
 104                if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
 105                        return -EFAULT;
 106                if (part < pmac_nvram_OF || part > pmac_nvram_NR)
 107                        return -EINVAL;
 108                offset = pmac_get_partition(part);
 109                if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
 110                        return -EFAULT;
 111                break;
 112        }
 113#endif /* CONFIG_PPC_PMAC */
 114        case IOC_NVRAM_SYNC:
 115                nvram_sync();
 116                break;
 117        default:
 118                return -EINVAL;
 119        }
 120
 121        return 0;
 122}
 123
 124static long nvram_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 125{
 126        int ret;
 127
 128        mutex_lock(&nvram_mutex);
 129        ret = nvram_ioctl(file, cmd, arg);
 130        mutex_unlock(&nvram_mutex);
 131
 132        return ret;
 133}
 134
 135const struct file_operations nvram_fops = {
 136        .owner          = THIS_MODULE,
 137        .llseek         = nvram_llseek,
 138        .read           = read_nvram,
 139        .write          = write_nvram,
 140        .unlocked_ioctl = nvram_unlocked_ioctl,
 141};
 142
 143static struct miscdevice nvram_dev = {
 144        NVRAM_MINOR,
 145        "nvram",
 146        &nvram_fops
 147};
 148
 149int __init nvram_init(void)
 150{
 151        int ret = 0;
 152
 153        printk(KERN_INFO "Generic non-volatile memory driver v%s\n",
 154                NVRAM_VERSION);
 155        ret = misc_register(&nvram_dev);
 156        if (ret != 0)
 157                goto out;
 158
 159        nvram_len = nvram_get_size();
 160        if (nvram_len < 0)
 161                nvram_len = NVRAM_SIZE;
 162
 163out:
 164        return ret;
 165}
 166
 167void __exit nvram_cleanup(void)
 168{
 169        misc_deregister( &nvram_dev );
 170}
 171
 172module_init(nvram_init);
 173module_exit(nvram_cleanup);
 174MODULE_LICENSE("GPL");
 175