tizen 2.4 release
[kernel/u-boot-tm1.git] / nand_fdl / fdl-2 / src / 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 #include <jffs2/jffs2.h>
12
13 #define MTD_WRITEABLE           0x400   /* Device is writeable */
14 #define MTD_BIT_WRITEABLE       0x800   /* Single bits can be flipped */
15 #define MTD_NO_ERASE            0x1000  /* No erase necessary */
16 #define MTD_POWERUP_LOCK        0x2000  /* Always locked after reset */
17
18 #define SIZE_REMAINING          0xffffffff
19 #define OFFSET_CONTINUOUS       0xffffffff
20 #define MTDPARTITION_MAX                40
21
22 struct cmdline_mtd_partition {
23         struct cmdline_mtd_partition *next;
24         char *mtd_id;
25         int num_parts;
26         struct mtd_partition *parts;
27 };
28
29 static struct mtd_partition realpart[MTDPARTITION_MAX];
30 static int real_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 extern char * get_mtdparts(void);
40
41 static unsigned int simple_guess_base(const char *cp)
42 {
43         if (cp[0] == '0') {
44                 if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
45                         return 16;
46                 else
47                         return 8;
48         } else {
49                 return 10;
50         }
51 }
52
53 static unsigned long long memparse(const char *ptr, char **retptr)
54 {
55         char *endptr;   /* local pointer to end of parsed string */
56         unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
57
58         switch (*endptr) {
59         case 'G':
60         case 'g':
61                 ret <<= 10;
62         case 'M':
63         case 'm':
64                 ret <<= 10;
65         case 'K':
66         case 'k':
67                 ret <<= 10;
68                 endptr++;
69         default:
70                 break;
71         }
72
73         if (retptr)
74                 *retptr = endptr;
75
76         return ret;
77 }
78
79 static size_t strlcpy(char *dest, char *src, size_t size)
80 {
81         size_t ret = strlen(src);
82
83         if (size) {
84                 size_t len = (ret >= size) ? size - 1 : ret;
85                 memcpy(dest, src, len);
86                 dest[len] = '\0';
87         }
88         return ret;
89 }
90
91 static struct mtd_partition * newpart(char *s,
92                                       char **retptr,
93                                       int *num_parts,
94                                       int this_part,
95                                       unsigned char **extra_mem_ptr,
96                                       int extra_mem_size)
97 {
98         struct mtd_partition *parts;
99         unsigned long size;
100         unsigned long offset = OFFSET_CONTINUOUS;
101         char *name;
102         int name_len;
103         unsigned char *extra_mem;
104         char delim;
105         unsigned int mask_flags;
106
107         /* fetch the partition size */
108         if (*s == '-')
109         {       /* assign all remaining space to this partition */
110                 size = SIZE_REMAINING;
111                 s++;
112         }
113         else
114         {
115                 size = memparse(s, &s);
116                 if (size < PAGE_SIZE)
117                 {
118                         printf("partition size too small (%lx)\n", size);
119                         return 0;
120                 }
121         }
122
123         /* fetch partition name and flags */
124         mask_flags = 0; /* this is going to be a regular partition */
125         delim = 0;
126         /* check for offset */
127         if (*s == '@')
128         {
129                 s++;
130                 offset = memparse(s, &s);
131         }
132         /* now look for name */
133         if (*s == '(')
134         {
135                 delim = ')';
136         }
137
138         if (delim)
139         {
140                 char *p;
141
142                 name = ++s;
143                 p = strchr(name, delim);
144                 if (!p)
145                 {
146                         printf("no closing %c found in partition name\n", delim);
147                         return 0;
148                 }
149                 name_len = p - name;
150                 s = p + 1;
151         }
152         else
153         {
154                 name = 0;
155                 name_len = 13; /* Partition_000 */
156         }
157
158         /* record name length for memory allocation later */
159         extra_mem_size += name_len + 1;
160
161         /* test for options */
162         if (strncmp(s, "ro", 2) == 0)
163         {
164                 mask_flags |= MTD_WRITEABLE;
165                 s += 2;
166         }
167
168         /* if lk is found do NOT unlock the MTD partition*/
169         if (strncmp(s, "lk", 2) == 0)
170         {
171                 mask_flags |= MTD_POWERUP_LOCK;
172                 s += 2;
173         }
174
175         /* test if more partitions are following */
176         if (*s == ',')
177         {
178                 if (size == SIZE_REMAINING)
179                 {
180                         printf("no partitions allowed after a fill-up partition\n");
181                         return 0;
182                 }
183                 /* more partitions follow, parse them */
184                 parts = newpart(s + 1, &s, num_parts, this_part + 1,
185                                 &extra_mem, extra_mem_size);
186                 if (!parts)
187                         return 0;
188         }
189         else
190         {       /* this is the last partition: allocate space for all */
191                 int alloc_size;
192
193                 *num_parts = this_part + 1;
194                 alloc_size = *num_parts * sizeof(struct mtd_partition) +
195                              extra_mem_size;
196                 parts = (struct mtd_partition *)malloc(alloc_size);
197                 if (!parts)
198                 {
199                         printf("out of memory\n");
200                         return 0;
201                 }
202                 extra_mem = (unsigned char *)(parts + *num_parts);
203         }
204         /* enter this partition (offset will be calculated later if it is zero at this point) */
205         parts[this_part].size = size;
206         parts[this_part].offset = offset;
207         parts[this_part].mask_flags = mask_flags;
208         if (name)
209         {
210                 strlcpy(extra_mem, name, name_len + 1);
211         }
212         else
213         {
214                 sprintf(extra_mem, "Partition_%03d", this_part);
215         }
216         parts[this_part].name = extra_mem;
217         extra_mem += name_len + 1;
218
219         /*printf("partition %02d: name <%14s>, offset %08x, size %08x, mask flags %08x\n",
220         this_part,
221         parts[this_part].name,
222         parts[this_part].offset,
223         parts[this_part].size,
224         parts[this_part].mask_flags);*/
225         
226         if (real_current_part > 0) {
227                 real_current_part --;
228                 realpart[real_current_part].name = parts[this_part].name;
229                 realpart[real_current_part].offset = parts[this_part].offset;
230                 realpart[real_current_part].size = parts[this_part].size;
231                 realpart[real_current_part].mask_flags = parts[this_part].mask_flags;
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 int parse_cmdline_partitions(unsigned long long mastersize)
313 {
314         int i;
315         unsigned long offset;
316
317         cmdline = get_mtdparts();
318
319         /* parse command line */
320         if (!cmdline_parsed) {
321                 mtdpart_setup_real(cmdline);
322
323                 for (i = real_current_part, offset = 0; i < MTDPARTITION_MAX; i ++) {
324                         if (realpart[i].offset == OFFSET_CONTINUOUS)
325                                         realpart[i].offset = offset;
326                                 else
327                                         offset = realpart[i].offset;
328                         
329                                 if (realpart[i].size == SIZE_REMAINING)
330                                         realpart[i].size = mastersize - offset;
331
332                                 if (offset + realpart[i].size > mastersize) {
333                                         printf("partitioning exceeds flash size, truncating\n");
334                                         realpart[i].size = mastersize - offset;
335                                 }
336                                 offset += realpart[i].size;
337
338
339                                 printf("id : %02d, name : %20s, offset : 0x%08x, size : 0x%08x\n",
340                                 (i - real_current_part),
341                                 realpart[i].name,
342                                 realpart[i].offset,
343                                 realpart[i].size);
344                 }
345         }
346
347         return 0;
348 }
349
350 int parse_mtd_part_info(char *name,struct mtd_partition *part)
351 {
352         int i;
353
354         if (!cmdline_parsed){
355                 printf("get_mtd_part_info: partition not parsed!\n");
356                 return 0;
357         }
358
359         for(i=MTDPARTITION_MAX;i>0;i--){
360                 if(0==strcmp(name, realpart[i].name)){
361                         part->offset = realpart[i].offset;
362                         part->size = realpart[i].size;
363                         part->name = realpart[i].name;
364                         part->mask_flags = realpart[i].mask_flags;
365                         //debug print,del later
366                         printf("get mtd part info:debug i=%d\n",i);
367                         return 1;
368                 }
369         }
370
371         printf("get_mtd_part_info: \"%s\" is not a mtd partition.\n",name);
372         return -1;
373 }
374