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 memset((char *)mtd->priv + instr->addr, 0xff, instr->len); 38c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel instr->state = MTD_ERASE_DONE; 39c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd_erase_callback(instr); 40c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelstatic int ram_point(struct mtd_info *mtd, loff_t from, size_t len, 44a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert size_t *retlen, void **virt, resource_size_t *phys) 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert *virt = mtd->priv + from; 47c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel *retlen = len; 48c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 515e4e6e3fdf48c1b012e2b6e80ed1d7e99d4fa6d1Artem Bityutskiystatic int ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 535e4e6e3fdf48c1b012e2b6e80ed1d7e99d4fa6d1Artem Bityutskiy return 0; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56402d326519c1a4859c527702383f4e60f606ef52David Howells/* 57402d326519c1a4859c527702383f4e60f606ef52David Howells * Allow NOMMU mmap() to directly map the device (if not NULL) 58402d326519c1a4859c527702383f4e60f606ef52David Howells * - return the address to which the offset maps 59402d326519c1a4859c527702383f4e60f606ef52David Howells * - return -ENOSYS to indicate refusal to do the mapping 60402d326519c1a4859c527702383f4e60f606ef52David Howells */ 61402d326519c1a4859c527702383f4e60f606ef52David Howellsstatic unsigned long ram_get_unmapped_area(struct mtd_info *mtd, 62402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long len, 63402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long offset, 64402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long flags) 65402d326519c1a4859c527702383f4e60f606ef52David Howells{ 66402d326519c1a4859c527702383f4e60f606ef52David Howells return (unsigned long) mtd->priv + offset; 67402d326519c1a4859c527702383f4e60f606ef52David Howells} 68402d326519c1a4859c527702383f4e60f606ef52David Howells 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ram_read(struct mtd_info *mtd, loff_t from, size_t len, 70c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel size_t *retlen, u_char *buf) 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 72c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memcpy(buf, mtd->priv + from, len); 73c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel *retlen = len; 74c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ram_write(struct mtd_info *mtd, loff_t to, size_t len, 78c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel size_t *retlen, const u_char *buf) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memcpy((char *)mtd->priv + to, buf, len); 81c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel *retlen = len; 82c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup_mtdram(void) 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 87c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (mtd_info) { 88ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles mtd_device_unregister(mtd_info); 89f9101210e7aa72daf92722d451a2f7e3af5f781fJesper Juhl vfree(mtd_info->priv); 90c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel kfree(mtd_info); 91c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel } 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelint mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 950a8899b31a7d6c4a3bc7fdbd7c8c1fc79e726363Brian Norris unsigned long size, const char *name) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 97c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memset(mtd, 0, sizeof(*mtd)); 98c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 99c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel /* Setup the MTD structure */ 100c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->name = name; 10121c8db9eff95260e543535dfc6f27164c4c0c0ffDavid Woodhouse mtd->type = MTD_RAM; 102c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->flags = MTD_CAP_RAM; 103c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->size = size; 104783ed81ff39d3f938a6b2efd09fbad96e41e5c1fArtem B. Bityutskiy mtd->writesize = 1; 10507be303d22ac7e067b8a7172a4043ebe32b74b33Artem Bityutskiy mtd->writebufsize = 64; /* Mimic CFI NOR flashes */ 106c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->erasesize = MTDRAM_ERASE_SIZE; 107c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->priv = mapped_address; 108c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 109c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd->owner = THIS_MODULE; 1103c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_erase = ram_erase; 1113c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_point = ram_point; 1123c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_unpoint = ram_unpoint; 1133c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_get_unmapped_area = ram_get_unmapped_area; 1143c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_read = ram_read; 1153c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_write = ram_write; 116c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 117ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles if (mtd_device_register(mtd, NULL, 0)) 118c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -EIO; 119c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 120c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return 0; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_mtdram(void) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 125c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel void *addr; 126c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel int err; 127c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 128c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (!total_size) 129c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -EINVAL; 130c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 131c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel /* Allocate some memory */ 132c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); 133c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (!mtd_info) 134c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -ENOMEM; 135c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel 136c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel addr = vmalloc(MTDRAM_TOTAL_SIZE); 137c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (!addr) { 138c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel kfree(mtd_info); 139c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd_info = NULL; 140c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return -ENOMEM; 141c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel } 142c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device"); 143c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel if (err) { 144c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel vfree(addr); 145c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel kfree(mtd_info); 146c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel mtd_info = NULL; 147c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return err; 148c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel } 149c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); 150c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel return err; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_mtdram); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cleanup_mtdram); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>"); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Simulated MTD driver for testing"); 159