Merge branch 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6
[deliverable/linux.git] / drivers / mtd / afs.c
CommitLineData
1da177e4
LT
1/*======================================================================
2
3 drivers/mtd/afs.c: ARM Flash Layout/Partitioning
97894cda 4
1da177e4 5 Copyright (C) 2000 ARM Limited
97894cda 6
1da177e4
LT
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
97894cda 11
1da177e4
LT
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
97894cda 16
1da177e4
LT
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
97894cda
TG
20
21 This is access code for flashes using ARM's flash partitioning
1da177e4
LT
22 standards.
23
97894cda 24 $Id: afs.c,v 1.15 2005/11/07 11:14:19 gleixner Exp $
1da177e4
LT
25
26======================================================================*/
27
28#include <linux/module.h>
29#include <linux/types.h>
30#include <linux/kernel.h>
31#include <linux/slab.h>
32#include <linux/string.h>
33#include <linux/init.h>
34
35#include <linux/mtd/mtd.h>
36#include <linux/mtd/map.h>
37#include <linux/mtd/partitions.h>
38
39struct footer_struct {
40 u32 image_info_base; /* Address of first word of ImageFooter */
41 u32 image_start; /* Start of area reserved by this footer */
42 u32 signature; /* 'Magic' number proves it's a footer */
43 u32 type; /* Area type: ARM Image, SIB, customer */
44 u32 checksum; /* Just this structure */
45};
46
47struct image_info_struct {
48 u32 bootFlags; /* Boot flags, compression etc. */
49 u32 imageNumber; /* Unique number, selects for boot etc. */
50 u32 loadAddress; /* Address program should be loaded to */
51 u32 length; /* Actual size of image */
52 u32 address; /* Image is executed from here */
53 char name[16]; /* Null terminated */
54 u32 headerBase; /* Flash Address of any stripped header */
55 u32 header_length; /* Length of header in memory */
56 u32 headerType; /* AIF, RLF, s-record etc. */
57 u32 checksum; /* Image checksum (inc. this struct) */
58};
59
60static u32 word_sum(void *words, int num)
61{
62 u32 *p = words;
63 u32 sum = 0;
64
65 while (num--)
66 sum += *p++;
67
68 return sum;
69}
70
71static int
72afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
73 u_int off, u_int mask)
74{
75 struct footer_struct fs;
76 u_int ptr = off + mtd->erasesize - sizeof(fs);
77 size_t sz;
78 int ret;
79
80 ret = mtd->read(mtd, ptr, sizeof(fs), &sz, (u_char *) &fs);
81 if (ret >= 0 && sz != sizeof(fs))
82 ret = -EINVAL;
83
84 if (ret < 0) {
85 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
86 ptr, ret);
87 return ret;
88 }
89
90 ret = 1;
91
92 /*
93 * Does it contain the magic number?
94 */
95 if (fs.signature != 0xa0ffff9f)
96 ret = 0;
97
98 /*
99 * Check the checksum.
100 */
101 if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
102 ret = 0;
103
104 /*
105 * Don't touch the SIB.
106 */
107 if (fs.type == 2)
108 ret = 0;
109
110 *iis_start = fs.image_info_base & mask;
111 *img_start = fs.image_start & mask;
112
113 /*
114 * Check the image info base. This can not
115 * be located after the footer structure.
116 */
117 if (*iis_start >= ptr)
118 ret = 0;
119
120 /*
121 * Check the start of this image. The image
122 * data can not be located after this block.
123 */
124 if (*img_start > off)
125 ret = 0;
126
127 return ret;
128}
129
130static int
131afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
132{
133 size_t sz;
134 int ret, i;
135
136 memset(iis, 0, sizeof(*iis));
137 ret = mtd->read(mtd, ptr, sizeof(*iis), &sz, (u_char *) iis);
138 if (ret < 0)
139 goto failed;
140
141 if (sz != sizeof(*iis)) {
142 ret = -EINVAL;
143 goto failed;
144 }
145
146 ret = 0;
147
148 /*
149 * Validate the name - it must be NUL terminated.
150 */
151 for (i = 0; i < sizeof(iis->name); i++)
152 if (iis->name[i] == '\0')
153 break;
154
155 if (i < sizeof(iis->name))
156 ret = 1;
157
158 return ret;
159
160 failed:
161 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
162 ptr, ret);
163 return ret;
164}
165
97894cda 166static int parse_afs_partitions(struct mtd_info *mtd,
1da177e4
LT
167 struct mtd_partition **pparts,
168 unsigned long origin)
169{
170 struct mtd_partition *parts;
171 u_int mask, off, idx, sz;
172 int ret = 0;
173 char *str;
174
175 /*
176 * This is the address mask; we use this to mask off out of
177 * range address bits.
178 */
179 mask = mtd->size - 1;
180
181 /*
182 * First, calculate the size of the array we need for the
183 * partition information. We include in this the size of
184 * the strings.
185 */
186 for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) {
187 struct image_info_struct iis;
188 u_int iis_ptr, img_ptr;
189
190 ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
191 if (ret < 0)
192 break;
193 if (ret == 0)
194 continue;
195
196 ret = afs_read_iis(mtd, &iis, iis_ptr);
197 if (ret < 0)
198 break;
199 if (ret == 0)
200 continue;
201
202 sz += sizeof(struct mtd_partition);
203 sz += strlen(iis.name) + 1;
204 idx += 1;
205 }
206
207 if (!sz)
208 return ret;
209
95b93a0c 210 parts = kzalloc(sz, GFP_KERNEL);
1da177e4
LT
211 if (!parts)
212 return -ENOMEM;
213
1da177e4
LT
214 str = (char *)(parts + idx);
215
216 /*
217 * Identify the partitions
218 */
219 for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
220 struct image_info_struct iis;
747aead3 221 u_int iis_ptr, img_ptr;
1da177e4
LT
222
223 /* Read the footer. */
224 ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
225 if (ret < 0)
226 break;
227 if (ret == 0)
228 continue;
229
230 /* Read the image info block */
231 ret = afs_read_iis(mtd, &iis, iis_ptr);
232 if (ret < 0)
233 break;
234 if (ret == 0)
235 continue;
236
237 strcpy(str, iis.name);
1da177e4
LT
238
239 parts[idx].name = str;
747aead3 240 parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1);
1da177e4
LT
241 parts[idx].offset = img_ptr;
242 parts[idx].mask_flags = 0;
243
244 printk(" mtd%d: at 0x%08x, %5dKB, %8u, %s\n",
245 idx, img_ptr, parts[idx].size / 1024,
246 iis.imageNumber, str);
247
248 idx += 1;
249 str = str + strlen(iis.name) + 1;
250 }
251
252 if (!idx) {
253 kfree(parts);
254 parts = NULL;
255 }
256
257 *pparts = parts;
258 return idx ? idx : ret;
259}
260
261static struct mtd_part_parser afs_parser = {
262 .owner = THIS_MODULE,
263 .parse_fn = parse_afs_partitions,
264 .name = "afs",
265};
266
267static int __init afs_parser_init(void)
268{
269 return register_mtd_parser(&afs_parser);
270}
271
272static void __exit afs_parser_exit(void)
273{
274 deregister_mtd_parser(&afs_parser);
275}
276
277module_init(afs_parser_init);
278module_exit(afs_parser_exit);
279
280
281MODULE_AUTHOR("ARM Ltd");
282MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
283MODULE_LICENSE("GPL");
This page took 0.200869 seconds and 5 git commands to generate.