summaryrefslogtreecommitdiffstats
path: root/linux-2.4.x/drivers/mtd/maps/mphysmap.c
blob: 05969ec32aa46e3254eae750a21b6c724da4ae27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
 * $Id: mphysmap.c,v 1.4 2005/11/07 11:14:27 gleixner Exp $
 *
 * Several mappings of NOR chips
 *
 * Copyright (c) 2001-2005	Jörn Engel <joern@wh.fh-wedelde>
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
#endif

static struct map_info mphysmap_static_maps[] = {
#if CONFIG_MTD_MULTI_PHYSMAP_1_WIDTH
	{
		.name		= CONFIG_MTD_MULTI_PHYSMAP_1_NAME,
		.phys		= CONFIG_MTD_MULTI_PHYSMAP_1_START,
		.size		= CONFIG_MTD_MULTI_PHYSMAP_1_LEN,
		.bankwidth	= CONFIG_MTD_MULTI_PHYSMAP_1_WIDTH,
	},
#endif
#if CONFIG_MTD_MULTI_PHYSMAP_2_WIDTH
	{
		.name		= CONFIG_MTD_MULTI_PHYSMAP_2_NAME,
		.phys		= CONFIG_MTD_MULTI_PHYSMAP_2_START,
		.size		= CONFIG_MTD_MULTI_PHYSMAP_2_LEN,
		.bankwidth	= CONFIG_MTD_MULTI_PHYSMAP_2_WIDTH,
	},
#endif
#if CONFIG_MTD_MULTI_PHYSMAP_3_WIDTH
	{
		.name		= CONFIG_MTD_MULTI_PHYSMAP_3_NAME,
		.phys		= CONFIG_MTD_MULTI_PHYSMAP_3_START,
		.size		= CONFIG_MTD_MULTI_PHYSMAP_3_LEN,
		.bankwidth	= CONFIG_MTD_MULTI_PHYSMAP_3_WIDTH,
	},
#endif
#if CONFIG_MTD_MULTI_PHYSMAP_4_WIDTH
	{
		.name		= CONFIG_MTD_MULTI_PHYSMAP_4_NAME,
		.phys		= CONFIG_MTD_MULTI_PHYSMAP_4_START,
		.size		= CONFIG_MTD_MULTI_PHYSMAP_4_LEN,
		.bankwidth	= CONFIG_MTD_MULTI_PHYSMAP_4_WIDTH,
	},
#endif
};

DECLARE_MUTEX(map_mutex);


static int mphysmap_map_device(struct map_info *map)
{
	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
	const char **type;
	struct mtd_info* mtd;
#ifdef CONFIG_MTD_PARTITIONS
       struct mtd_partition* mtd_parts;
       int mtd_parts_nb;
       static const char *part_probes[] __initdata = {
#ifdef CONFIG_MTD_CMDLINE_PARTS
       "cmdlinepart",
#endif
#ifdef CONFIG_MTD_REDBOOT_PARTS
       "RedBoot",
#endif
       NULL};
#endif
	map->virt = ioremap(map->phys, map->size);
	if (!map->virt)
		return -EIO;

	simple_map_init(map);
	mtd = NULL;
	type = rom_probe_types;
	for(; !mtd && *type; type++) {
		mtd = do_map_probe(*type, map);
	}

	if (!mtd) {
		iounmap(map->virt);
		return -ENXIO;
	}

	map->map_priv_1 = (unsigned long)mtd;
	mtd->owner = THIS_MODULE;

#ifdef CONFIG_MTD_PARTITIONS
	mtd_parts_nb = parse_mtd_partitions(mtd, part_probes,
					    &mtd_parts, 0);
	if (mtd_parts_nb > 0)
	{
		add_mtd_partitions (mtd, mtd_parts, mtd_parts_nb);
		map->map_priv_2=(unsigned long)mtd_parts;
	}
	else
	{
		add_mtd_device(mtd);
		map->map_priv_2=(unsigned long)NULL;
        };
#else
	add_mtd_device(mtd);
#endif
	return 0;
}


static void mphysmap_unmap_device(struct map_info *map)
{
	struct mtd_info* mtd = (struct mtd_info*)map->map_priv_1;
#ifdef CONFIG_MTD_PARTITIONS
       struct mtd_partition* mtd_parts=(struct mtd_partition*)map->map_priv_2;
#endif
	BUG_ON(!mtd);
	if (!map->virt)
		return;

#ifdef CONFIG_MTD_PARTITIONS
	if (mtd_parts)
	{
		del_mtd_partitions(mtd);
		kfree(mtd_parts);
	}
	else
	    del_mtd_device(mtd);
#else
	del_mtd_device(mtd);
#endif
	map_destroy(mtd);
	iounmap(map->virt);

	map->map_priv_1 = 0;
	map->map_priv_2 = 0;
	map->virt = NULL;
}




static int __init mphysmap_init(void)
{
	int i;
	down(&map_mutex);
	for (i=0;
	     i<sizeof(mphysmap_static_maps)/sizeof(mphysmap_static_maps[0]);
	     i++)
	{
	        if (strcmp(mphysmap_static_maps[i].name,"")!=0 &&
		    mphysmap_static_maps[i].size!=0 &&
		    mphysmap_static_maps[i].bankwidth!=0)
		{
		    mphysmap_map_device(&mphysmap_static_maps[i]);
		};
	};
	up(&map_mutex);
	return 0;
}


static void __exit mphysmap_exit(void)
{
	int i;
	down(&map_mutex);
	for (i=0;
	     i<sizeof(mphysmap_static_maps)/sizeof(mphysmap_static_maps[0]);
	     i++)
	{
	        if (strcmp(mphysmap_static_maps[i].name,"")!=0 &&
		    mphysmap_static_maps[i].size!=0 &&
		    mphysmap_static_maps[i].bankwidth!=0)
		{
		    mphysmap_unmap_device(&mphysmap_static_maps[i]);
		};
	};
	up(&map_mutex);
}


module_init(mphysmap_init);
module_exit(mphysmap_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedelde>");
MODULE_DESCRIPTION("Generic configurable extensible MTD map driver");