1 /* 2 * mtdram - a test mtd device 3 * $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $ 4 * Author: Alexander Larsson <alex@cendio.se> 5 * 6 * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> 7 * 8 * This code is GPL 9 * 10 */ 11 12 #include <linux/config.h> 13 #include <linux/module.h> 14 #include <linux/slab.h> 15 #include <linux/ioport.h> 16 #include <linux/vmalloc.h> 17 #include <linux/init.h> 18 #include <linux/mtd/compatmac.h> 19 #include <linux/mtd/mtd.h> 20 21 #ifndef CONFIG_MTDRAM_ABS_POS 22 #define CONFIG_MTDRAM_ABS_POS 0 23 #endif 24 25 #if CONFIG_MTDRAM_ABS_POS > 0 26 #include <asm/io.h> 27 #endif 28 29 #ifdef MODULE 30 static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; 31 static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; 32 module_param(total_size,ulong,0); 33 MODULE_PARM_DESC(total_size, "Total device size in KiB"); 34 module_param(erase_size,ulong,0); 35 MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); 36 #define MTDRAM_TOTAL_SIZE (total_size * 1024) 37 #define MTDRAM_ERASE_SIZE (erase_size * 1024) 38 #else 39 #define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024) 40 #define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024) 41 #endif 42 43 44 // We could store these in the mtd structure, but we only support 1 device.. 45 static struct mtd_info *mtd_info; 46 47 48 static int 49 ram_erase(struct mtd_info *mtd, struct erase_info *instr) 50 { 51 DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len); 52 if (instr->addr + instr->len > mtd->size) { 53 DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size); 54 return -EINVAL; 55 } 56 57 memset((char *)mtd->priv + instr->addr, 0xff, instr->len); 58 59 instr->state = MTD_ERASE_DONE; 60 mtd_erase_callback(instr); 61 62 return 0; 63 } 64 65 static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) 66 { 67 if (from + len > mtd->size) 68 return -EINVAL; 69 70 *mtdbuf = mtd->priv + from; 71 *retlen = len; 72 return 0; 73 } 74 75 static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, 76 size_t len) 77 { 78 DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n"); 79 } 80 81 static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, 82 size_t *retlen, u_char *buf) 83 { 84 DEBUG(MTD_DEBUG_LEVEL2, "ram_read(pos:%ld, len:%ld)\n", (long)from, (long)len); 85 if (from + len > mtd->size) { 86 DEBUG(MTD_DEBUG_LEVEL1, "ram_read() out of bounds (%ld > %ld)\n", (long)(from + len), (long)mtd->size); 87 return -EINVAL; 88 } 89 90 memcpy(buf, mtd->priv + from, len); 91 92 *retlen=len; 93 return 0; 94 } 95 96 static int ram_write(struct mtd_info *mtd, loff_t to, size_t len, 97 size_t *retlen, const u_char *buf) 98 { 99 DEBUG(MTD_DEBUG_LEVEL2, "ram_write(pos:%ld, len:%ld)\n", (long)to, (long)len); 100 if (to + len > mtd->size) { 101 DEBUG(MTD_DEBUG_LEVEL1, "ram_write() out of bounds (%ld > %ld)\n", (long)(to + len), (long)mtd->size); 102 return -EINVAL; 103 } 104 105 memcpy ((char *)mtd->priv + to, buf, len); 106 107 *retlen=len; 108 return 0; 109 } 110 111 static void __exit cleanup_mtdram(void) 112 { 113 if (mtd_info) { 114 del_mtd_device(mtd_info); 115 #if CONFIG_MTDRAM_TOTAL_SIZE > 0 116 if (mtd_info->priv) 117 #if CONFIG_MTDRAM_ABS_POS > 0 118 iounmap(mtd_info->priv); 119 #else 120 vfree(mtd_info->priv); 121 #endif 122 #endif 123 kfree(mtd_info); 124 } 125 } 126 127 int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 128 unsigned long size, char *name) 129 { 130 memset(mtd, 0, sizeof(*mtd)); 131 132 /* Setup the MTD structure */ 133 mtd->name = name; 134 mtd->type = MTD_RAM; 135 mtd->flags = MTD_CAP_RAM; 136 mtd->size = size; 137 mtd->erasesize = MTDRAM_ERASE_SIZE; 138 mtd->priv = mapped_address; 139 140 mtd->owner = THIS_MODULE; 141 mtd->erase = ram_erase; 142 mtd->point = ram_point; 143 mtd->unpoint = ram_unpoint; 144 mtd->read = ram_read; 145 mtd->write = ram_write; 146 147 if (add_mtd_device(mtd)) { 148 return -EIO; 149 } 150 151 return 0; 152 } 153 154 #if CONFIG_MTDRAM_TOTAL_SIZE > 0 155 #if CONFIG_MTDRAM_ABS_POS > 0 156 static int __init init_mtdram(void) 157 { 158 void *addr; 159 int err; 160 /* Allocate some memory */ 161 mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); 162 if (!mtd_info) 163 return -ENOMEM; 164 165 addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE); 166 if (!addr) { 167 DEBUG(MTD_DEBUG_LEVEL1, 168 "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n", 169 (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS); 170 kfree(mtd_info); 171 mtd_info = NULL; 172 return -ENOMEM; 173 } 174 err = mtdram_init_device(mtd_info, addr, 175 MTDRAM_TOTAL_SIZE, "mtdram test device"); 176 if (err) 177 { 178 iounmap(addr); 179 kfree(mtd_info); 180 mtd_info = NULL; 181 return err; 182 } 183 memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); 184 return err; 185 } 186 187 #else /* CONFIG_MTDRAM_ABS_POS > 0 */ 188 189 static int __init init_mtdram(void) 190 { 191 void *addr; 192 int err; 193 /* Allocate some memory */ 194 mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); 195 if (!mtd_info) 196 return -ENOMEM; 197 198 addr = vmalloc(MTDRAM_TOTAL_SIZE); 199 if (!addr) { 200 DEBUG(MTD_DEBUG_LEVEL1, 201 "Failed to vmalloc memory region of size %ld\n", 202 (long)MTDRAM_TOTAL_SIZE); 203 kfree(mtd_info); 204 mtd_info = NULL; 205 return -ENOMEM; 206 } 207 err = mtdram_init_device(mtd_info, addr, 208 MTDRAM_TOTAL_SIZE, "mtdram test device"); 209 if (err) 210 { 211 vfree(addr); 212 kfree(mtd_info); 213 mtd_info = NULL; 214 return err; 215 } 216 memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); 217 return err; 218 } 219 #endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */ 220 221 #else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */ 222 223 static int __init init_mtdram(void) 224 { 225 return 0; 226 } 227 #endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */ 228 229 module_init(init_mtdram); 230 module_exit(cleanup_mtdram); 231 232 MODULE_LICENSE("GPL"); 233 MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>"); 234 MODULE_DESCRIPTION("Simulated MTD driver for testing"); 235 236