mtdram.c revision ee0e87b174bb41f0310cf089262bf5dd8f95a212
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mtdram - a test mtd device 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Alexander Larsson <alex@cendio.se> 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> 6c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel * Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This code is GPL 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/mtd.h> 18456d9fc92eb8635d53e8facc57764464b8759173Adrian Bunk#include <linux/mtd/mtdram.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MTDRAM_TOTAL_SIZE (total_size * 1024) 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MTDRAM_ERASE_SIZE (erase_size * 1024) 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel#ifdef MODULE 26c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelmodule_param(total_size, ulong, 0); 27c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern EngelMODULE_PARM_DESC(total_size, "Total device size in KiB"); 28c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelmodule_param(erase_size, ulong, 0); 29c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern EngelMODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); 30c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel#endif 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// We could store these in the mtd structure, but we only support 1 device.. 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_info *mtd_info; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelstatic int ram_erase(struct mtd_info *mtd, struct erase_info *instr) 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (instr->addr + instr->len > mtd->size) 38c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -EINVAL; 39c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 40c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memset((char *)mtd->priv + instr->addr, 0xff, instr->len); 41c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 42c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel instr->state = MTD_ERASE_DONE; 43c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd_erase_callback(instr); 44c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 45c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelstatic int ram_point(struct mtd_info *mtd, loff_t from, size_t len, 49a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert size_t *retlen, void **virt, resource_size_t *phys) 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 51c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (from + len > mtd->size) 52c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -EINVAL; 53c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 54a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert /* can we return a physical address with this driver? */ 55a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert if (phys) 56a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert return -EINVAL; 57a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert 58a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert *virt = mtd->priv + from; 59c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel *retlen = len; 60c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbertstatic void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67402d326519c1a4859c527702383f4e60f606ef52David Howells/* 68402d326519c1a4859c527702383f4e60f606ef52David Howells * Allow NOMMU mmap() to directly map the device (if not NULL) 69402d326519c1a4859c527702383f4e60f606ef52David Howells * - return the address to which the offset maps 70402d326519c1a4859c527702383f4e60f606ef52David Howells * - return -ENOSYS to indicate refusal to do the mapping 71402d326519c1a4859c527702383f4e60f606ef52David Howells */ 72402d326519c1a4859c527702383f4e60f606ef52David Howellsstatic unsigned long ram_get_unmapped_area(struct mtd_info *mtd, 73402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long len, 74402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long offset, 75402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long flags) 76402d326519c1a4859c527702383f4e60f606ef52David Howells{ 77402d326519c1a4859c527702383f4e60f606ef52David Howells return (unsigned long) mtd->priv + offset; 78402d326519c1a4859c527702383f4e60f606ef52David Howells} 79402d326519c1a4859c527702383f4e60f606ef52David Howells 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ram_read(struct mtd_info *mtd, loff_t from, size_t len, 81c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel size_t *retlen, u_char *buf) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 83c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (from + len > mtd->size) 84c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -EINVAL; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memcpy(buf, mtd->priv + from, len); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel *retlen = len; 89c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ram_write(struct mtd_info *mtd, loff_t to, size_t len, 93c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel size_t *retlen, const u_char *buf) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 95c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (to + len > mtd->size) 96c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -EINVAL; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 98c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memcpy((char *)mtd->priv + to, buf, len); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel *retlen = len; 101c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup_mtdram(void) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 106c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (mtd_info) { 107ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles mtd_device_unregister(mtd_info); 108f9101210e7aa72daf92722d451a2f7e3af5f781fJesper Juhl vfree(mtd_info->priv); 109c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel kfree(mtd_info); 110c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel } 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 113c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelint mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 114c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel unsigned long size, char *name) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 116c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memset(mtd, 0, sizeof(*mtd)); 117c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 118c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel /* Setup the MTD structure */ 119c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->name = name; 12021c8db9eff95260e543535dfc6f27164c4c0c0ffDavid Woodhouse mtd->type = MTD_RAM; 121c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->flags = MTD_CAP_RAM; 122c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->size = size; 123783ed81ff39d3f938a6b2efd09fbad96e41e5c1fArtem B. Bityutskiy mtd->writesize = 1; 12407be303d22ac7e067b8a7172a4043ebe32b74b33Artem Bityutskiy mtd->writebufsize = 64; /* Mimic CFI NOR flashes */ 125c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->erasesize = MTDRAM_ERASE_SIZE; 126c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->priv = mapped_address; 127c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 128c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->owner = THIS_MODULE; 129c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->erase = ram_erase; 130c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->point = ram_point; 131c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->unpoint = ram_unpoint; 132402d326519c1a4859c527702383f4e60f606ef52David Howells mtd->get_unmapped_area = ram_get_unmapped_area; 133c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->read = ram_read; 134c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->write = ram_write; 135c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 136ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles if (mtd_device_register(mtd, NULL, 0)) 137c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -EIO; 138c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 139c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_mtdram(void) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 144c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel void *addr; 145c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel int err; 146c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 147c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (!total_size) 148c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -EINVAL; 149c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 150c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel /* Allocate some memory */ 151c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); 152c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (!mtd_info) 153c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -ENOMEM; 154c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 155c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel addr = vmalloc(MTDRAM_TOTAL_SIZE); 156c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (!addr) { 157c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel kfree(mtd_info); 158c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd_info = NULL; 159c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -ENOMEM; 160c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel } 161c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device"); 162c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (err) { 163c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel vfree(addr); 164c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel kfree(mtd_info); 165c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd_info = NULL; 166c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return err; 167c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel } 168c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); 169c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return err; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_mtdram); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cleanup_mtdram); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>"); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Simulated MTD driver for testing"); 178