11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * mtdram - a test mtd device 31da177e4SLinus Torvalds * Author: Alexander Larsson <alex@cendio.se> 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> 6c13cbf3bSJoern Engel * Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This code is GPL 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/slab.h> 141da177e4SLinus Torvalds #include <linux/ioport.h> 151da177e4SLinus Torvalds #include <linux/vmalloc.h> 161da177e4SLinus Torvalds #include <linux/init.h> 171da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 18456d9fc9SAdrian Bunk #include <linux/mtd/mtdram.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; 211da177e4SLinus Torvalds static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; 22c13cbf3bSJoern Engel #define MTDRAM_TOTAL_SIZE (total_size * 1024) 23c13cbf3bSJoern Engel #define MTDRAM_ERASE_SIZE (erase_size * 1024) 24c13cbf3bSJoern Engel 25c13cbf3bSJoern Engel #ifdef MODULE 261da177e4SLinus Torvalds module_param(total_size, ulong, 0); 271da177e4SLinus Torvalds MODULE_PARM_DESC(total_size, "Total device size in KiB"); 281da177e4SLinus Torvalds module_param(erase_size, ulong, 0); 291da177e4SLinus Torvalds MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); 301da177e4SLinus Torvalds #endif 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds // We could store these in the mtd structure, but we only support 1 device.. 331da177e4SLinus Torvalds static struct mtd_info *mtd_info; 341da177e4SLinus Torvalds 35c13cbf3bSJoern Engel static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) 361da177e4SLinus Torvalds { 37c13cbf3bSJoern Engel if (instr->addr + instr->len > mtd->size) 381da177e4SLinus Torvalds return -EINVAL; 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds memset((char *)mtd->priv + instr->addr, 0xff, instr->len); 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds instr->state = MTD_ERASE_DONE; 431da177e4SLinus Torvalds mtd_erase_callback(instr); 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds return 0; 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 48c13cbf3bSJoern Engel static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, 49a98889f3SJared Hulbert size_t *retlen, void **virt, resource_size_t *phys) 501da177e4SLinus Torvalds { 511da177e4SLinus Torvalds if (from + len > mtd->size) 521da177e4SLinus Torvalds return -EINVAL; 531da177e4SLinus Torvalds 54a98889f3SJared Hulbert /* can we return a physical address with this driver? */ 55a98889f3SJared Hulbert if (phys) 56a98889f3SJared Hulbert return -EINVAL; 57a98889f3SJared Hulbert 58a98889f3SJared Hulbert *virt = mtd->priv + from; 591da177e4SLinus Torvalds *retlen = len; 601da177e4SLinus Torvalds return 0; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 63a98889f3SJared Hulbert static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 67402d3265SDavid Howells /* 68402d3265SDavid Howells * Allow NOMMU mmap() to directly map the device (if not NULL) 69402d3265SDavid Howells * - return the address to which the offset maps 70402d3265SDavid Howells * - return -ENOSYS to indicate refusal to do the mapping 71402d3265SDavid Howells */ 72402d3265SDavid Howells static unsigned long ram_get_unmapped_area(struct mtd_info *mtd, 73402d3265SDavid Howells unsigned long len, 74402d3265SDavid Howells unsigned long offset, 75402d3265SDavid Howells unsigned long flags) 76402d3265SDavid Howells { 77402d3265SDavid Howells return (unsigned long) mtd->priv + offset; 78402d3265SDavid Howells } 79402d3265SDavid Howells 801da177e4SLinus Torvalds static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, 811da177e4SLinus Torvalds size_t *retlen, u_char *buf) 821da177e4SLinus Torvalds { 83c13cbf3bSJoern Engel if (from + len > mtd->size) 841da177e4SLinus Torvalds return -EINVAL; 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds memcpy(buf, mtd->priv + from, len); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds *retlen = len; 891da177e4SLinus Torvalds return 0; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static int ram_write(struct mtd_info *mtd, loff_t to, size_t len, 931da177e4SLinus Torvalds size_t *retlen, const u_char *buf) 941da177e4SLinus Torvalds { 95c13cbf3bSJoern Engel if (to + len > mtd->size) 961da177e4SLinus Torvalds return -EINVAL; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds memcpy((char *)mtd->priv + to, buf, len); 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds *retlen = len; 1011da177e4SLinus Torvalds return 0; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds static void __exit cleanup_mtdram(void) 1051da177e4SLinus Torvalds { 1061da177e4SLinus Torvalds if (mtd_info) { 107ee0e87b1SJamie Iles mtd_device_unregister(mtd_info); 1081da177e4SLinus Torvalds vfree(mtd_info->priv); 1091da177e4SLinus Torvalds kfree(mtd_info); 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 1141da177e4SLinus Torvalds unsigned long size, char *name) 1151da177e4SLinus Torvalds { 1161da177e4SLinus Torvalds memset(mtd, 0, sizeof(*mtd)); 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds /* Setup the MTD structure */ 1191da177e4SLinus Torvalds mtd->name = name; 12021c8db9eSDavid Woodhouse mtd->type = MTD_RAM; 1211da177e4SLinus Torvalds mtd->flags = MTD_CAP_RAM; 1221da177e4SLinus Torvalds mtd->size = size; 123783ed81fSArtem B. Bityutskiy mtd->writesize = 1; 12407be303dSArtem Bityutskiy mtd->writebufsize = 64; /* Mimic CFI NOR flashes */ 1251da177e4SLinus Torvalds mtd->erasesize = MTDRAM_ERASE_SIZE; 1261da177e4SLinus Torvalds mtd->priv = mapped_address; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds mtd->owner = THIS_MODULE; 129*3c3c10bbSArtem Bityutskiy mtd->_erase = ram_erase; 130*3c3c10bbSArtem Bityutskiy mtd->_point = ram_point; 131*3c3c10bbSArtem Bityutskiy mtd->_unpoint = ram_unpoint; 132*3c3c10bbSArtem Bityutskiy mtd->_get_unmapped_area = ram_get_unmapped_area; 133*3c3c10bbSArtem Bityutskiy mtd->_read = ram_read; 134*3c3c10bbSArtem Bityutskiy mtd->_write = ram_write; 1351da177e4SLinus Torvalds 136ee0e87b1SJamie Iles if (mtd_device_register(mtd, NULL, 0)) 1371da177e4SLinus Torvalds return -EIO; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds return 0; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds static int __init init_mtdram(void) 1431da177e4SLinus Torvalds { 1441da177e4SLinus Torvalds void *addr; 1451da177e4SLinus Torvalds int err; 1461da177e4SLinus Torvalds 147c13cbf3bSJoern Engel if (!total_size) 148c13cbf3bSJoern Engel return -EINVAL; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds /* Allocate some memory */ 1511da177e4SLinus Torvalds mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); 1521da177e4SLinus Torvalds if (!mtd_info) 1531da177e4SLinus Torvalds return -ENOMEM; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds addr = vmalloc(MTDRAM_TOTAL_SIZE); 1561da177e4SLinus Torvalds if (!addr) { 1571da177e4SLinus Torvalds kfree(mtd_info); 1581da177e4SLinus Torvalds mtd_info = NULL; 1591da177e4SLinus Torvalds return -ENOMEM; 1601da177e4SLinus Torvalds } 161c13cbf3bSJoern Engel err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device"); 162c13cbf3bSJoern Engel if (err) { 1631da177e4SLinus Torvalds vfree(addr); 1641da177e4SLinus Torvalds kfree(mtd_info); 1651da177e4SLinus Torvalds mtd_info = NULL; 1661da177e4SLinus Torvalds return err; 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); 1691da177e4SLinus Torvalds return err; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds module_init(init_mtdram); 1731da177e4SLinus Torvalds module_exit(cleanup_mtdram); 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1761da177e4SLinus Torvalds MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>"); 1771da177e4SLinus Torvalds MODULE_DESCRIPTION("Simulated MTD driver for testing"); 178