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