mtdram.c revision 07be303d22ac7e067b8a7172a4043ebe32b74b33
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) {
107c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		del_mtd_device(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
136c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (add_mtd_device(mtd)) {
137c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return -EIO;
138c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	}
139c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
140c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	return 0;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_mtdram(void)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
145c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	void *addr;
146c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	int err;
147c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
148c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (!total_size)
149c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return -EINVAL;
150c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
151c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	/* Allocate some memory */
152c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
153c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (!mtd_info)
154c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return -ENOMEM;
155c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
156c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	addr = vmalloc(MTDRAM_TOTAL_SIZE);
157c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (!addr) {
158c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		kfree(mtd_info);
159c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		mtd_info = NULL;
160c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return -ENOMEM;
161c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	}
162c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device");
163c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (err) {
164c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		vfree(addr);
165c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		kfree(mtd_info);
166c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		mtd_info = NULL;
167c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return err;
168c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	}
169c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
170c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	return err;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_mtdram);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cleanup_mtdram);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>");
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Simulated MTD driver for testing");
179