cregit-Linux how code gets into the kernel

Release 4.11 drivers/mtd/devices/phram.c

/**
 * Copyright (c) ????           Jochen Schäuble <psionic@psionic.de>
 * Copyright (c) 2003-2004      Joern Engel <joern@wh.fh-wedel.de>
 *
 * Usage:
 *
 * one commend line parameter per device, each in the form:
 *   phram=<name>,<start>,<len>
 * <name> may be up to 63 characters.
 * <start> and <len> can be octal, decimal or hexadecimal.  If followed
 * by "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or
 * gigabytes.
 *
 * Example:
 *      phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/io.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>


struct phram_mtd_list {
	
struct mtd_info mtd;
	
struct list_head list;
};

static LIST_HEAD(phram_list);


static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) { u_char *start = mtd->priv; memset(start + instr->addr, 0xff, instr->len); /* * This'll catch a few races. Free the thing before returning :) * I don't feel at all ashamed. This kind of thing is possible anyway * with flash, but unlikely. */ instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse5398.15%375.00%
Hervé Fache11.85%125.00%
Total54100.00%4100.00%


static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys) { *virt = mtd->priv + from; *retlen = len; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse3778.72%266.67%
Jared Hulbert1021.28%133.33%
Total47100.00%3100.00%


static int phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse1470.00%266.67%
Artem B. Bityutskiy630.00%133.33%
Total20100.00%3100.00%


static int phram_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { u_char *start = mtd->priv; memcpy(buf, start + from, len); *retlen = len; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse52100.00%2100.00%
Total52100.00%2100.00%


static int phram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { u_char *start = mtd->priv; memcpy(start + to, buf, len); *retlen = len; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse53100.00%2100.00%
Total53100.00%2100.00%


static void unregister_devices(void) { struct phram_mtd_list *this, *safe; list_for_each_entry_safe(this, safe, &phram_list, list) { mtd_device_unregister(&this->mtd); iounmap(this->mtd.priv); kfree(this->mtd.name); kfree(this); } }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse3966.10%120.00%
Jörn Engel1016.95%240.00%
Mathias Krause915.25%120.00%
Jamie Iles11.69%120.00%
Total59100.00%5100.00%


static int register_device(char *name, phys_addr_t start, size_t len) { struct phram_mtd_list *new; int ret = -ENOMEM; new = kzalloc(sizeof(*new), GFP_KERNEL); if (!new) goto out0; ret = -EIO; new->mtd.priv = ioremap(start, len); if (!new->mtd.priv) { pr_err("ioremap failed\n"); goto out1; } new->mtd.name = name; new->mtd.size = len; new->mtd.flags = MTD_CAP_RAM; new->mtd._erase = phram_erase; new->mtd._point = phram_point; new->mtd._unpoint = phram_unpoint; new->mtd._read = phram_read; new->mtd._write = phram_write; new->mtd.owner = THIS_MODULE; new->mtd.type = MTD_RAM; new->mtd.erasesize = PAGE_SIZE; new->mtd.writesize = 1; ret = -EAGAIN; if (mtd_device_register(&new->mtd, NULL, 0)) { pr_err("Failed to register new device\n"); goto out2; } list_add_tail(&new->list, &phram_list); return 0; out2: iounmap(new->mtd.priv); out1: kfree(new); out0: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse19076.92%220.00%
Jörn Engel3413.77%220.00%
Artem B. Bityutskiy135.26%220.00%
Jamie Iles52.02%110.00%
Alexander Sverdlin20.81%110.00%
Mike Frysinger20.81%110.00%
Burman Yan10.40%110.00%
Total247100.00%10100.00%


static int parse_num64(uint64_t *num64, char *token) { size_t len; int shift = 0; int ret; len = strlen(token); /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */ if (len > 2) { if (token[len - 1] == 'i') { switch (token[len - 2]) { case 'G': shift += 10; case 'M': shift += 10; case 'k': shift += 10; token[len - 2] = 0; break; default: return -EINVAL; } } } ret = kstrtou64(token, 0, num64); *num64 <<= shift; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Sverdlin7461.67%133.33%
David Woodhouse4638.33%266.67%
Total120100.00%3100.00%


static int parse_name(char **pname, const char *token) { size_t len; char *name; len = strlen(token) + 1; if (len > 64) return -ENOSPC; name = kstrdup(token, GFP_KERNEL); if (!name) return -ENOMEM; *pname = name; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse6697.06%150.00%
Fabian Frederick22.94%150.00%
Total68100.00%2100.00%


static inline void kill_final_newline(char *str) { char *newline = strrchr(str, '\n'); if (newline && !newline[1]) *newline = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jörn Engel37100.00%1100.00%
Total37100.00%1100.00%

#define parse_err(fmt, args...) do { \ pr_err(fmt , ## args); \ return 1; \ } while (0) #ifndef MODULE static int phram_init_called; /* * This shall contain the module parameter if any. It is of the form: * - phram=<device>,<address>,<size> for module case * - phram.phram=<device>,<address>,<size> for built-in case * We leave 64 bytes for the device name, 20 for the address and 20 for the * size. * Example: phram.phram=rootfs,0xa0000000,512Mi */ static char phram_paramline[64 + 20 + 20]; #endif
static int phram_setup(const char *val) { char buf[64 + 20 + 20], *str = buf; char *token[3]; char *name; uint64_t start; uint64_t len; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) parse_err("parameter too long\n"); strcpy(str, val); kill_final_newline(str); for (i = 0; i < 3; i++) token[i] = strsep(&str, ","); if (str) parse_err("too many arguments\n"); if (!token[2]) parse_err("not enough arguments\n"); ret = parse_name(&name, token[0]); if (ret) return ret; ret = parse_num64(&start, token[1]); if (ret) { kfree(name); parse_err("illegal start address\n"); } ret = parse_num64(&len, token[2]); if (ret) { kfree(name); parse_err("illegal device length\n"); } ret = register_device(name, start, len); if (!ret) pr_info("%s device: %#llx at %#llx\n", name, len, start); else kfree(name); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse19379.10%228.57%
Mike Frysinger197.79%114.29%
Jesper Juhl145.74%114.29%
Alexander Sverdlin72.87%114.29%
Mathias Krause62.46%114.29%
Jörn Engel52.05%114.29%
Total244100.00%7100.00%


static int phram_param_call(const char *val, struct kernel_param *kp) { #ifdef MODULE return phram_setup(val); #else /* * If more parameters are later passed in via * /sys/module/phram/parameters/phram * and init_phram() has already been called, * we can parse the argument now. */ if (phram_init_called) return phram_setup(val); /* * During early boot stage, we only save the parameters * here. We must parse them later: if the param passed * from kernel boot command line, phram_param_call() is * called so early that it is not possible to resolve * the device (even kmalloc() fails). Defer that work to * phram_setup(). */ if (strlen(val) >= sizeof(phram_paramline)) return -ENOSPC; strcpy(phram_paramline, val); return 0; #endif }

Contributors

PersonTokensPropCommitsCommitProp
Hervé Fache4262.69%150.00%
Alexander Sverdlin2537.31%150.00%
Total67100.00%2100.00%

module_param_call(phram, phram_param_call, NULL, NULL, 000); MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
static int __init init_phram(void) { int ret = 0; #ifndef MODULE if (phram_paramline[0]) ret = phram_setup(phram_paramline); phram_init_called = 1; #endif return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Sverdlin1845.00%125.00%
David Woodhouse1127.50%250.00%
Hervé Fache1127.50%125.00%
Total40100.00%4100.00%


static void __exit cleanup_phram(void) { unregister_devices(); }

Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse12100.00%1100.00%
Total12100.00%1100.00%

module_init(init_phram); module_exit(cleanup_phram); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Joern Engel <joern@wh.fh-wedel.de>"); MODULE_DESCRIPTION("MTD driver for physical RAM");

Overall Contributors

PersonTokensPropCommitsCommitProp
David Woodhouse85268.32%518.52%
Alexander Sverdlin13811.07%27.41%
Jörn Engel917.30%414.81%
Hervé Fache645.13%13.70%
Mike Frysinger282.25%13.70%
Artem B. Bityutskiy191.52%311.11%
Mathias Krause151.20%13.70%
Jesper Juhl141.12%13.70%
Jared Hulbert100.80%13.70%
Jamie Iles60.48%13.70%
Tim Schmielau30.24%13.70%
Fabian Frederick20.16%13.70%
Burman Yan10.08%13.70%
Rob Ward10.08%13.70%
Joe Perches10.08%13.70%
Mark Hindley10.08%13.70%
Adrian Bunk10.08%13.70%
Total1247100.00%27100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.