tizen 2.4 release
[kernel/u-boot-tm1.git] / fs / yaffs2 / parsemtdparts.c
1 #include <linux/ctype.h>
2 #include "parsemtdparts.h"
3 #include <linux/string.h>
4 #include <malloc.h>
5
6 #include "asm/arch/sci_types.h"
7 #include "asm/arch/nand_controller.h"
8 #include <linux/mtd/mtd.h>
9 #include <nand.h>
10 #include <linux/mtd/nand.h>
11
12 #define MTD_WRITEABLE           0x400   /* Device is writeable */
13 #define MTD_BIT_WRITEABLE       0x800   /* Single bits can be flipped */
14 #define MTD_NO_ERASE            0x1000  /* No erase necessary */
15 #define MTD_POWERUP_LOCK        0x2000  /* Always locked after reset */
16
17 #define SIZE_REMAINING          0xffffffff
18 #define OFFSET_CONTINUOUS       0xffffffff
19 #define MTDPARTITION_MAX                40
20
21 struct cmdline_mtd_partition {
22         struct cmdline_mtd_partition *next;
23         char *mtd_id;
24         int num_parts;
25         struct mtd_partition *parts;
26 };
27
28 static struct mtd_partition realpart[MTDPARTITION_MAX];
29 static char realpartname[MTDPARTITION_MAX][255];
30 static int current_part = MTDPARTITION_MAX;
31
32 /* the command line passed to mtdpart_setupd() */
33 static char *cmdline;
34 static int cmdline_parsed = 0;
35
36
37 #define TOLOWER(x) ((x) | 0x20)
38
39 static unsigned int simple_guess_base(const char *cp)
40 {
41         if (cp[0] == '0') {
42                 if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
43                         return 16;
44                 else
45                         return 8;
46         } else {
47                 return 10;
48         }
49 }
50
51 static unsigned long long memparse(const char *ptr, char **retptr)
52 {
53         char *endptr;   /* local pointer to end of parsed string */
54         unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
55
56         switch (*endptr) {
57         case 'G':
58         case 'g':
59                 ret <<= 10;
60         case 'M':
61         case 'm':
62                 ret <<= 10;
63         case 'K':
64         case 'k':
65                 ret <<= 10;
66                 endptr++;
67         default:
68                 break;
69         }
70
71         if (retptr)
72                 *retptr = endptr;
73
74         return ret;
75 }
76
77 static size_t strlcpy(char *dest, char *src, size_t size)
78 {
79         size_t ret = strlen(src);
80
81         if (size) {
82                 size_t len = (ret >= size) ? size - 1 : ret;
83                 memcpy(dest, src, len);
84                 dest[len] = '\0';
85         }
86         return ret;
87 }
88
89 static struct mtd_partition * newpart(char *s,
90                                       char **retptr,
91                                       int *num_parts,
92                                       int this_part,
93                                       unsigned char **extra_mem_ptr,
94                                       int extra_mem_size)
95 {
96         struct mtd_partition *parts;
97         unsigned long size;
98         unsigned long offset = OFFSET_CONTINUOUS;
99         char *name;
100         int name_len;
101         unsigned char *extra_mem;
102         char delim;
103         unsigned int mask_flags;
104
105         /* fetch the partition size */
106         if (*s == '-')
107         {       /* assign all remaining space to this partition */
108                 size = SIZE_REMAINING;
109                 s++;
110         }
111         else
112         {
113                 size = memparse(s, &s);
114                 if (size < PAGE_SIZE)
115                 {
116                         printf("partition size too small (%lx)\n", size);
117                         return 0;
118                 }
119         }
120
121         /* fetch partition name and flags */
122         mask_flags = 0; /* this is going to be a regular partition */
123         delim = 0;
124         /* check for offset */
125         if (*s == '@')
126         {
127                 s++;
128                 offset = memparse(s, &s);
129         }
130         /* now look for name */
131         if (*s == '(')
132         {
133                 delim = ')';
134         }
135
136         if (delim)
137         {
138                 char *p;
139
140                 name = ++s;
141                 p = strchr(name, delim);
142                 if (!p)
143                 {
144                         printf("no closing %c found in partition name\n", delim);
145                         return 0;
146                 }
147                 name_len = p - name;
148                 s = p + 1;
149         }
150         else
151         {
152                 name = 0;
153                 name_len = 13; /* Partition_000 */
154         }
155
156         /* record name length for memory allocation later */
157         extra_mem_size += name_len + 1;
158
159         /* test for options */
160         if (strncmp(s, "ro", 2) == 0)
161         {
162                 mask_flags |= MTD_WRITEABLE;
163                 s += 2;
164         }
165
166         /* if lk is found do NOT unlock the MTD partition*/
167         if (strncmp(s, "lk", 2) == 0)
168         {
169                 mask_flags |= MTD_POWERUP_LOCK;
170                 s += 2;
171         }
172
173         /* test if more partitions are following */
174         if (*s == ',')
175         {
176                 if (size == SIZE_REMAINING)
177                 {
178                         printf("no partitions allowed after a fill-up partition\n");
179                         return 0;
180                 }
181                 /* more partitions follow, parse them */
182                 parts = newpart(s + 1, &s, num_parts, this_part + 1,
183                                 &extra_mem, extra_mem_size);
184                 if (!parts)
185                         return 0;
186         }
187         else
188         {       /* this is the last partition: allocate space for all */
189                 int alloc_size;
190
191                 *num_parts = this_part + 1;
192                 alloc_size = *num_parts * sizeof(struct mtd_partition) +
193                              extra_mem_size;
194                 parts = (struct mtd_partition *)malloc(alloc_size);
195                 if (!parts)
196                 {
197                         printf("out of memory\n");
198                         return 0;
199                 }
200                 extra_mem = (unsigned char *)(parts + *num_parts);
201         }
202         /* enter this partition (offset will be calculated later if it is zero at this point) */
203         parts[this_part].size = size;
204         parts[this_part].offset = offset;
205         parts[this_part].mask_flags = mask_flags;
206         if (name)
207         {
208                 strlcpy(extra_mem, name, name_len + 1);
209         }
210         else
211         {
212                 sprintf(extra_mem, "Partition_%03d", this_part);
213         }
214         parts[this_part].name = extra_mem;
215         extra_mem += name_len + 1;
216
217         /*printf("partition %02d: name <%14s>, offset %08x, size %08x, mask flags %08x\n",
218              this_part,
219              parts[this_part].name,
220              parts[this_part].offset,
221              parts[this_part].size,
222              parts[this_part].mask_flags);*/
223         
224              if (current_part >= 0) {
225                 current_part --;
226                 memset(&(realpartname[current_part]), 0, 255);
227                 strcpy(realpartname[current_part], parts[this_part].name);
228                 realpart[current_part].name = realpartname[current_part];
229                 //printf("realname = %14s  partname = %14s\n", realpart[current_part].name, parts[this_part].name);
230                 realpart[current_part].offset = parts[this_part].offset;
231                 realpart[current_part].size = parts[this_part].size;
232             } else
233                 printf("mtdparts partition is too much\n");
234
235
236         /* return (updated) pointer to extra_mem memory */
237         if (extra_mem_ptr)
238           *extra_mem_ptr = extra_mem;
239
240         /* return (updated) pointer command line string */
241         *retptr = s;
242
243         /* return partition table */
244         return parts;
245 }
246
247 /*
248  * Parse the command line.
249  */
250 static int mtdpart_setup_real(char *s)
251 {
252         cmdline_parsed = 1;
253
254         for( ; s != '\0'; )
255         {
256                 struct cmdline_mtd_partition *this_mtd;
257                 struct mtd_partition *parts;
258                 int mtd_id_len;
259                 int num_parts;
260                 char *p, *mtd_id;
261
262                 mtd_id = s;
263                 /* fetch <mtd-id> */
264                 if (!(p = strchr(s, ':')))
265                 {
266                         printf("no mtd-id\n");
267                         return 0;
268                 }
269                 mtd_id_len = p - mtd_id;
270
271                 //printf("\nparsing <%s>\n", p+1);
272
273                 /*
274                  * parse one mtd. have it reserve memory for the
275                  * struct cmdline_mtd_partition and the mtd-id string.
276                  */
277                 parts = newpart(p + 1,          /* cmdline */
278                                 &s,             /* out: updated cmdline ptr */
279                                 &num_parts,     /* out: number of parts */
280                                 0,              /* first partition */
281                                 (unsigned char**)&this_mtd, /* out: extra mem */
282                                 mtd_id_len + 1 + sizeof(*this_mtd) +
283                                 sizeof(void*)-1 /*alignment*/);
284                 if(!parts)
285                 {
286                         /*
287                          * An error occurred. We're either:
288                          * a) out of memory, or
289                          * b) in the middle of the partition spec
290                          * Either way, this mtd is hosed and we're
291                          * unlikely to succeed in parsing any more
292                          */
293                          return 0;
294                  }
295
296                 //printf("mtdid=<%s> num_parts=<%d>\n", this_mtd->mtd_id, this_mtd->num_parts);
297                 /* EOS - we're done */
298                 if (*s == 0)
299                         break;
300
301                 /* does another spec follow? */
302                 if (*s != ';')
303                 {
304                         printf("bad character after partition (%c)\n", *s);
305                         return 0;
306                 }
307                 s++;
308         }
309         return 1;
310 }
311
312 char * get_mtdparts(void);
313 int yaffs_parse_cmdline_partitions(struct mtd_partition *current, unsigned long long mastersize)
314 {
315         unsigned long offset;
316         int i;
317         struct cmdline_mtd_partition *part;
318
319         cmdline = get_mtdparts();
320
321         /* parse command line */
322         if (!cmdline_parsed) {
323                 mtdpart_setup_real(cmdline);
324
325                 for (i = current_part, offset = 0; i < MTDPARTITION_MAX; i ++) {
326                         if (realpart[i].offset == OFFSET_CONTINUOUS)
327                                         realpart[i].offset = offset;
328                                 else
329                                         offset = realpart[i].offset;
330                         
331                                 if (realpart[i].size == SIZE_REMAINING)
332                                         realpart[i].size = mastersize - offset;
333
334                                 if (offset + realpart[i].size > mastersize) {
335                                         printf("partitioning exceeds flash size, truncating\n");
336                                         realpart[i].size = mastersize - offset;
337                                 }
338                                 offset += realpart[i].size;
339
340
341                                 /*printf("realpart %02d : offset %08x, size %08x  name %14s\n",
342                                 (i - current_part),
343                                 realpart[i].offset,
344                                 realpart[i].size,
345                                 realpart[i].name);*/
346                 }
347         }
348
349         
350         for (i = current_part; i < MTDPARTITION_MAX; i ++) {
351                 if (realpart[i].offset == current->offset) {
352                         current->size = realpart[i].size;
353                         strcpy(current->name, realpart[i].name);
354                         return 0;
355                 }
356
357                 if (strcmp(realpart[i].name, current->name) == 0) {
358                         current->size = realpart[i].size;
359                         current->offset = realpart[i].offset;
360                         return 0;
361                 }
362         }
363
364         return 1;
365 }
366
367