linux/drivers/mtd/devices/phram.c
<<
>>
Prefs
   1/**
   2 * Copyright (c) ????           Jochen Schäuble <psionic@psionic.de>
   3 * Copyright (c) 2003-2004      Joern Engel <joern@wh.fh-wedel.de>
   4 *
   5 * Usage:
   6 *
   7 * one commend line parameter per device, each in the form:
   8 *   phram=<name>,<start>,<len>
   9 * <name> may be up to 63 characters.
  10 * <start> and <len> can be octal, decimal or hexadecimal.  If followed
  11 * by "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or
  12 * gigabytes.
  13 *
  14 * Example:
  15 *      phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
  16 */
  17
  18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  19
  20#include <asm/io.h>
  21#include <linux/init.h>
  22#include <linux/kernel.h>
  23#include <linux/list.h>
  24#include <linux/module.h>
  25#include <linux/moduleparam.h>
  26#include <linux/slab.h>
  27#include <linux/mtd/mtd.h>
  28
  29struct phram_mtd_list {
  30        struct mtd_info mtd;
  31        struct list_head list;
  32};
  33
  34static LIST_HEAD(phram_list);
  35
  36static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
  37{
  38        u_char *start = mtd->priv;
  39
  40        memset(start + instr->addr, 0xff, instr->len);
  41
  42        /*
  43         * This'll catch a few races. Free the thing before returning :)
  44         * I don't feel at all ashamed. This kind of thing is possible anyway
  45         * with flash, but unlikely.
  46         */
  47        instr->state = MTD_ERASE_DONE;
  48        mtd_erase_callback(instr);
  49        return 0;
  50}
  51
  52static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
  53                size_t *retlen, void **virt, resource_size_t *phys)
  54{
  55        *virt = mtd->priv + from;
  56        *retlen = len;
  57        return 0;
  58}
  59
  60static int phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
  61{
  62        return 0;
  63}
  64
  65static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
  66                size_t *retlen, u_char *buf)
  67{
  68        u_char *start = mtd->priv;
  69
  70        memcpy(buf, start + from, len);
  71        *retlen = len;
  72        return 0;
  73}
  74
  75static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
  76                size_t *retlen, const u_char *buf)
  77{
  78        u_char *start = mtd->priv;
  79
  80        memcpy(start + to, buf, len);
  81        *retlen = len;
  82        return 0;
  83}
  84
  85static void unregister_devices(void)
  86{
  87        struct phram_mtd_list *this, *safe;
  88
  89        list_for_each_entry_safe(this, safe, &phram_list, list) {
  90                mtd_device_unregister(&this->mtd);
  91                iounmap(this->mtd.priv);
  92                kfree(this->mtd.name);
  93                kfree(this);
  94        }
  95}
  96
  97static int register_device(char *name, unsigned long start, unsigned long len)
  98{
  99        struct phram_mtd_list *new;
 100        int ret = -ENOMEM;
 101
 102        new = kzalloc(sizeof(*new), GFP_KERNEL);
 103        if (!new)
 104                goto out0;
 105
 106        ret = -EIO;
 107        new->mtd.priv = ioremap(start, len);
 108        if (!new->mtd.priv) {
 109                pr_err("ioremap failed\n");
 110                goto out1;
 111        }
 112
 113
 114        new->mtd.name = name;
 115        new->mtd.size = len;
 116        new->mtd.flags = MTD_CAP_RAM;
 117        new->mtd._erase = phram_erase;
 118        new->mtd._point = phram_point;
 119        new->mtd._unpoint = phram_unpoint;
 120        new->mtd._read = phram_read;
 121        new->mtd._write = phram_write;
 122        new->mtd.owner = THIS_MODULE;
 123        new->mtd.type = MTD_RAM;
 124        new->mtd.erasesize = PAGE_SIZE;
 125        new->mtd.writesize = 1;
 126
 127        ret = -EAGAIN;
 128        if (mtd_device_register(&new->mtd, NULL, 0)) {
 129                pr_err("Failed to register new device\n");
 130                goto out2;
 131        }
 132
 133        list_add_tail(&new->list, &phram_list);
 134        return 0;
 135
 136out2:
 137        iounmap(new->mtd.priv);
 138out1:
 139        kfree(new);
 140out0:
 141        return ret;
 142}
 143
 144static int ustrtoul(const char *cp, char **endp, unsigned int base)
 145{
 146        unsigned long result = simple_strtoul(cp, endp, base);
 147
 148        switch (**endp) {
 149        case 'G':
 150                result *= 1024;
 151        case 'M':
 152                result *= 1024;
 153        case 'k':
 154                result *= 1024;
 155        /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
 156                if ((*endp)[1] == 'i')
 157                        (*endp) += 2;
 158        }
 159        return result;
 160}
 161
 162static int parse_num32(uint32_t *num32, const char *token)
 163{
 164        char *endp;
 165        unsigned long n;
 166
 167        n = ustrtoul(token, &endp, 0);
 168        if (*endp)
 169                return -EINVAL;
 170
 171        *num32 = n;
 172        return 0;
 173}
 174
 175static int parse_name(char **pname, const char *token)
 176{
 177        size_t len;
 178        char *name;
 179
 180        len = strlen(token) + 1;
 181        if (len > 64)
 182                return -ENOSPC;
 183
 184        name = kmalloc(len, GFP_KERNEL);
 185        if (!name)
 186                return -ENOMEM;
 187
 188        strcpy(name, token);
 189
 190        *pname = name;
 191        return 0;
 192}
 193
 194
 195static inline void kill_final_newline(char *str)
 196{
 197        char *newline = strrchr(str, '\n');
 198        if (newline && !newline[1])
 199                *newline = 0;
 200}
 201
 202
 203#define parse_err(fmt, args...) do {    \
 204        pr_err(fmt , ## args);  \
 205        return 1;               \
 206} while (0)
 207
 208/*
 209 * This shall contain the module parameter if any. It is of the form:
 210 * - phram=<device>,<address>,<size> for module case
 211 * - phram.phram=<device>,<address>,<size> for built-in case
 212 * We leave 64 bytes for the device name, 12 for the address and 12 for the
 213 * size.
 214 * Example: phram.phram=rootfs,0xa0000000,512Mi
 215 */
 216static __initdata char phram_paramline[64+12+12];
 217
 218static int __init phram_setup(const char *val)
 219{
 220        char buf[64+12+12], *str = buf;
 221        char *token[3];
 222        char *name;
 223        uint32_t start;
 224        uint32_t len;
 225        int i, ret;
 226
 227        if (strnlen(val, sizeof(buf)) >= sizeof(buf))
 228                parse_err("parameter too long\n");
 229
 230        strcpy(str, val);
 231        kill_final_newline(str);
 232
 233        for (i=0; i<3; i++)
 234                token[i] = strsep(&str, ",");
 235
 236        if (str)
 237                parse_err("too many arguments\n");
 238
 239        if (!token[2])
 240                parse_err("not enough arguments\n");
 241
 242        ret = parse_name(&name, token[0]);
 243        if (ret)
 244                return ret;
 245
 246        ret = parse_num32(&start, token[1]);
 247        if (ret) {
 248                kfree(name);
 249                parse_err("illegal start address\n");
 250        }
 251
 252        ret = parse_num32(&len, token[2]);
 253        if (ret) {
 254                kfree(name);
 255                parse_err("illegal device length\n");
 256        }
 257
 258        ret = register_device(name, start, len);
 259        if (!ret)
 260                pr_info("%s device: %#x at %#x\n", name, len, start);
 261        else
 262                kfree(name);
 263
 264        return ret;
 265}
 266
 267static int __init phram_param_call(const char *val, struct kernel_param *kp)
 268{
 269        /*
 270         * This function is always called before 'init_phram()', whether
 271         * built-in or module.
 272         */
 273        if (strlen(val) >= sizeof(phram_paramline))
 274                return -ENOSPC;
 275        strcpy(phram_paramline, val);
 276
 277        return 0;
 278}
 279
 280module_param_call(phram, phram_param_call, NULL, NULL, 000);
 281MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
 282
 283
 284static int __init init_phram(void)
 285{
 286        if (phram_paramline[0])
 287                return phram_setup(phram_paramline);
 288
 289        return 0;
 290}
 291
 292static void __exit cleanup_phram(void)
 293{
 294        unregister_devices();
 295}
 296
 297module_init(init_phram);
 298module_exit(cleanup_phram);
 299
 300MODULE_LICENSE("GPL");
 301MODULE_AUTHOR("Joern Engel <joern@wh.fh-wedel.de>");
 302MODULE_DESCRIPTION("MTD driver for physical RAM");
 303