mtdram.c revision 783ed81ff39d3f938a6b2efd09fbad96e41e5c1f
1/*
2 * mtdram - a test mtd device
3 * $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $
4 * Author: Alexander Larsson <alex@cendio.se>
5 *
6 * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
7 * Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de>
8 *
9 * This code is GPL
10 *
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/ioport.h>
17#include <linux/vmalloc.h>
18#include <linux/init.h>
19#include <linux/mtd/compatmac.h>
20#include <linux/mtd/mtd.h>
21
22static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
23static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
24#define MTDRAM_TOTAL_SIZE (total_size * 1024)
25#define MTDRAM_ERASE_SIZE (erase_size * 1024)
26
27#ifdef MODULE
28module_param(total_size, ulong, 0);
29MODULE_PARM_DESC(total_size, "Total device size in KiB");
30module_param(erase_size, ulong, 0);
31MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
32#endif
33
34// We could store these in the mtd structure, but we only support 1 device..
35static struct mtd_info *mtd_info;
36
37static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
38{
39	if (instr->addr + instr->len > mtd->size)
40		return -EINVAL;
41
42	memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
43
44	instr->state = MTD_ERASE_DONE;
45	mtd_erase_callback(instr);
46
47	return 0;
48}
49
50static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
51		size_t *retlen, u_char **mtdbuf)
52{
53	if (from + len > mtd->size)
54		return -EINVAL;
55
56	*mtdbuf = mtd->priv + from;
57	*retlen = len;
58	return 0;
59}
60
61static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
62		size_t len)
63{
64}
65
66static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
67		size_t *retlen, u_char *buf)
68{
69	if (from + len > mtd->size)
70		return -EINVAL;
71
72	memcpy(buf, mtd->priv + from, len);
73
74	*retlen = len;
75	return 0;
76}
77
78static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
79		size_t *retlen, const u_char *buf)
80{
81	if (to + len > mtd->size)
82		return -EINVAL;
83
84	memcpy((char *)mtd->priv + to, buf, len);
85
86	*retlen = len;
87	return 0;
88}
89
90static void __exit cleanup_mtdram(void)
91{
92	if (mtd_info) {
93		del_mtd_device(mtd_info);
94		vfree(mtd_info->priv);
95		kfree(mtd_info);
96	}
97}
98
99int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
100		unsigned long size, char *name)
101{
102	memset(mtd, 0, sizeof(*mtd));
103
104	/* Setup the MTD structure */
105	mtd->name = name;
106	mtd->type = MTD_GENERIC_TYPE;
107	mtd->flags = MTD_CAP_RAM;
108	mtd->size = size;
109	mtd->writesize = 1;
110	mtd->erasesize = MTDRAM_ERASE_SIZE;
111	mtd->priv = mapped_address;
112
113	mtd->owner = THIS_MODULE;
114	mtd->erase = ram_erase;
115	mtd->point = ram_point;
116	mtd->unpoint = ram_unpoint;
117	mtd->read = ram_read;
118	mtd->write = ram_write;
119
120	if (add_mtd_device(mtd)) {
121		return -EIO;
122	}
123
124	return 0;
125}
126
127static int __init init_mtdram(void)
128{
129	void *addr;
130	int err;
131
132	if (!total_size)
133		return -EINVAL;
134
135	/* Allocate some memory */
136	mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
137	if (!mtd_info)
138		return -ENOMEM;
139
140	addr = vmalloc(MTDRAM_TOTAL_SIZE);
141	if (!addr) {
142		kfree(mtd_info);
143		mtd_info = NULL;
144		return -ENOMEM;
145	}
146	err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device");
147	if (err) {
148		vfree(addr);
149		kfree(mtd_info);
150		mtd_info = NULL;
151		return err;
152	}
153	memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
154	return err;
155}
156
157module_init(init_mtdram);
158module_exit(cleanup_mtdram);
159
160MODULE_LICENSE("GPL");
161MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>");
162MODULE_DESCRIPTION("Simulated MTD driver for testing");
163