mtdram.c revision 783ed81ff39d3f938a6b2efd09fbad96e41e5c1f
1/* 2 * mtdram - a test mtd device 3 * $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $ 4 * Author: Alexander Larsson <alex@cendio.se> 5 * 6 * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> 7 * Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de> 8 * 9 * This code is GPL 10 * 11 */ 12 13#include <linux/config.h> 14#include <linux/module.h> 15#include <linux/slab.h> 16#include <linux/ioport.h> 17#include <linux/vmalloc.h> 18#include <linux/init.h> 19#include <linux/mtd/compatmac.h> 20#include <linux/mtd/mtd.h> 21 22static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; 23static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; 24#define MTDRAM_TOTAL_SIZE (total_size * 1024) 25#define MTDRAM_ERASE_SIZE (erase_size * 1024) 26 27#ifdef MODULE 28module_param(total_size, ulong, 0); 29MODULE_PARM_DESC(total_size, "Total device size in KiB"); 30module_param(erase_size, ulong, 0); 31MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); 32#endif 33 34// We could store these in the mtd structure, but we only support 1 device.. 35static struct mtd_info *mtd_info; 36 37static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) 38{ 39 if (instr->addr + instr->len > mtd->size) 40 return -EINVAL; 41 42 memset((char *)mtd->priv + instr->addr, 0xff, instr->len); 43 44 instr->state = MTD_ERASE_DONE; 45 mtd_erase_callback(instr); 46 47 return 0; 48} 49 50static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, 51 size_t *retlen, u_char **mtdbuf) 52{ 53 if (from + len > mtd->size) 54 return -EINVAL; 55 56 *mtdbuf = mtd->priv + from; 57 *retlen = len; 58 return 0; 59} 60 61static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from, 62 size_t len) 63{ 64} 65 66static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, 67 size_t *retlen, u_char *buf) 68{ 69 if (from + len > mtd->size) 70 return -EINVAL; 71 72 memcpy(buf, mtd->priv + from, len); 73 74 *retlen = len; 75 return 0; 76} 77 78static int ram_write(struct mtd_info *mtd, loff_t to, size_t len, 79 size_t *retlen, const u_char *buf) 80{ 81 if (to + len > mtd->size) 82 return -EINVAL; 83 84 memcpy((char *)mtd->priv + to, buf, len); 85 86 *retlen = len; 87 return 0; 88} 89 90static void __exit cleanup_mtdram(void) 91{ 92 if (mtd_info) { 93 del_mtd_device(mtd_info); 94 vfree(mtd_info->priv); 95 kfree(mtd_info); 96 } 97} 98 99int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 100 unsigned long size, char *name) 101{ 102 memset(mtd, 0, sizeof(*mtd)); 103 104 /* Setup the MTD structure */ 105 mtd->name = name; 106 mtd->type = MTD_GENERIC_TYPE; 107 mtd->flags = MTD_CAP_RAM; 108 mtd->size = size; 109 mtd->writesize = 1; 110 mtd->erasesize = MTDRAM_ERASE_SIZE; 111 mtd->priv = mapped_address; 112 113 mtd->owner = THIS_MODULE; 114 mtd->erase = ram_erase; 115 mtd->point = ram_point; 116 mtd->unpoint = ram_unpoint; 117 mtd->read = ram_read; 118 mtd->write = ram_write; 119 120 if (add_mtd_device(mtd)) { 121 return -EIO; 122 } 123 124 return 0; 125} 126 127static int __init init_mtdram(void) 128{ 129 void *addr; 130 int err; 131 132 if (!total_size) 133 return -EINVAL; 134 135 /* Allocate some memory */ 136 mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); 137 if (!mtd_info) 138 return -ENOMEM; 139 140 addr = vmalloc(MTDRAM_TOTAL_SIZE); 141 if (!addr) { 142 kfree(mtd_info); 143 mtd_info = NULL; 144 return -ENOMEM; 145 } 146 err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device"); 147 if (err) { 148 vfree(addr); 149 kfree(mtd_info); 150 mtd_info = NULL; 151 return err; 152 } 153 memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); 154 return err; 155} 156 157module_init(init_mtdram); 158module_exit(cleanup_mtdram); 159 160MODULE_LICENSE("GPL"); 161MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>"); 162MODULE_DESCRIPTION("Simulated MTD driver for testing"); 163