mtdram.c revision 402d326519c1a4859c527702383f4e60f606ef52
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/compatmac.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/mtd.h>
19456d9fc92eb8635d53e8facc57764464b8759173Adrian Bunk#include <linux/mtd/mtdram.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MTDRAM_TOTAL_SIZE (total_size * 1024)
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MTDRAM_ERASE_SIZE (erase_size * 1024)
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel#ifdef MODULE
27c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelmodule_param(total_size, ulong, 0);
28c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern EngelMODULE_PARM_DESC(total_size, "Total device size in KiB");
29c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelmodule_param(erase_size, ulong, 0);
30c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern EngelMODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
31c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel#endif
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// We could store these in the mtd structure, but we only support 1 device..
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_info *mtd_info;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelstatic int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
38c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (instr->addr + instr->len > mtd->size)
39c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return -EINVAL;
40c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
41c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
42c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
43c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	instr->state = MTD_ERASE_DONE;
44c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	mtd_erase_callback(instr);
45c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
46c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	return 0;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelstatic int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
50a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert		size_t *retlen, void **virt, resource_size_t *phys)
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
52c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (from + len > mtd->size)
53c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return -EINVAL;
54c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
55a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert	/* can we return a physical address with this driver? */
56a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert	if (phys)
57a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert		return -EINVAL;
58a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert
59a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbert	*virt = mtd->priv + from;
60c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	*retlen = len;
61c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	return 0;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64a98889f3d8882995b5aa2255b931cf0202325cc0Jared Hulbertstatic void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
68402d326519c1a4859c527702383f4e60f606ef52David Howells/*
69402d326519c1a4859c527702383f4e60f606ef52David Howells * Allow NOMMU mmap() to directly map the device (if not NULL)
70402d326519c1a4859c527702383f4e60f606ef52David Howells * - return the address to which the offset maps
71402d326519c1a4859c527702383f4e60f606ef52David Howells * - return -ENOSYS to indicate refusal to do the mapping
72402d326519c1a4859c527702383f4e60f606ef52David Howells */
73402d326519c1a4859c527702383f4e60f606ef52David Howellsstatic unsigned long ram_get_unmapped_area(struct mtd_info *mtd,
74402d326519c1a4859c527702383f4e60f606ef52David Howells					   unsigned long len,
75402d326519c1a4859c527702383f4e60f606ef52David Howells					   unsigned long offset,
76402d326519c1a4859c527702383f4e60f606ef52David Howells					   unsigned long flags)
77402d326519c1a4859c527702383f4e60f606ef52David Howells{
78402d326519c1a4859c527702383f4e60f606ef52David Howells	return (unsigned long) mtd->priv + offset;
79402d326519c1a4859c527702383f4e60f606ef52David Howells}
80402d326519c1a4859c527702383f4e60f606ef52David Howells
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
82c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		size_t *retlen, u_char *buf)
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
84c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (from + len > mtd->size)
85c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return -EINVAL;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
87c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	memcpy(buf, mtd->priv + from, len);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	*retlen = len;
90c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	return 0;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
94c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		size_t *retlen, const u_char *buf)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
96c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (to + len > mtd->size)
97c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		return -EINVAL;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
99c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	memcpy((char *)mtd->priv + to, buf, len);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	*retlen = len;
102c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	return 0;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup_mtdram(void)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
107c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	if (mtd_info) {
108c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		del_mtd_device(mtd_info);
109f9101210e7aa72daf92722d451a2f7e3af5f781fJesper Juhl		vfree(mtd_info->priv);
110c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		kfree(mtd_info);
111c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
114c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engelint mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
115c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel		unsigned long size, char *name)
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
117c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	memset(mtd, 0, sizeof(*mtd));
118c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel
119c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	/* Setup the MTD structure */
120c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	mtd->name = name;
12121c8db9eff95260e543535dfc6f27164c4c0c0ffDavid Woodhouse	mtd->type = MTD_RAM;
122c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	mtd->flags = MTD_CAP_RAM;
123c13cbf3b5086d4ed51360b86b6b0ef8b82b179dcJoern Engel	mtd->size = size;
124783ed81ff39d3f938a6b2efd09fbad96e41e5c1fArtem B. Bityutskiy	mtd->writesize = 1;
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