]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - common/cmd_jffs2.c
Merge branch 'master' of git://git.denx.de/u-boot-i2c
[karo-tx-uboot.git] / common / cmd_jffs2.c
1 /*
2  * (C) Copyright 2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2002
6  * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
7  *
8  * (C) Copyright 2003
9  * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
10  *
11  * (C) Copyright 2005
12  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
13  *
14  *   Added support for reading flash partition table from environment.
15  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
16  *   kernel tree.
17  *
18  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
19  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
20  *
21  * See file CREDITS for list of people who contributed to this
22  * project.
23  *
24  * This program is free software; you can redistribute it and/or
25  * modify it under the terms of the GNU General Public License as
26  * published by the Free Software Foundation; either version 2 of
27  * the License, or (at your option) any later version.
28  *
29  * This program is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32  * GNU General Public License for more details.
33  *
34  * You should have received a copy of the GNU General Public License
35  * along with this program; if not, write to the Free Software
36  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
37  * MA 02111-1307 USA
38  */
39
40 /*
41  * Three environment variables are used by the parsing routines:
42  *
43  * 'partition' - keeps current partition identifier
44  *
45  * partition  := <part-id>
46  * <part-id>  := <dev-id>,part_num
47  *
48  *
49  * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
50  *
51  * mtdids=<idmap>[,<idmap>,...]
52  *
53  * <idmap>    := <dev-id>=<mtd-id>
54  * <dev-id>   := 'nand'|'nor'|'onenand'<dev-num>
55  * <dev-num>  := mtd device number, 0...
56  * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
57  *
58  *
59  * 'mtdparts' - partition list
60  *
61  * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
62  *
63  * <mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]
64  * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
65  * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
66  * <size>     := standard linux memsize OR '-' to denote all remaining space
67  * <offset>   := partition start offset within the device
68  * <name>     := '(' NAME ')'
69  * <ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)
70  *
71  * Notes:
72  * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
73  * - if the above variables are not set defaults for a given target are used
74  *
75  * Examples:
76  *
77  * 1 NOR Flash, with 1 single writable partition:
78  * mtdids=nor0=edb7312-nor
79  * mtdparts=mtdparts=edb7312-nor:-
80  *
81  * 1 NOR Flash with 2 partitions, 1 NAND with one
82  * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
83  * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
84  *
85  */
86
87 /*
88  * JFFS2/CRAMFS support
89  */
90 #include <common.h>
91 #include <command.h>
92 #include <malloc.h>
93 #include <jffs2/jffs2.h>
94 #include <linux/list.h>
95 #include <linux/ctype.h>
96 #include <cramfs/cramfs_fs.h>
97
98 #if defined(CONFIG_CMD_NAND)
99 #ifdef CONFIG_NAND_LEGACY
100 #include <linux/mtd/nand_legacy.h>
101 #else /* !CONFIG_NAND_LEGACY */
102 #include <linux/mtd/nand.h>
103 #include <nand.h>
104 #endif /* !CONFIG_NAND_LEGACY */
105 #endif
106
107 #if defined(CONFIG_CMD_ONENAND)
108 #include <linux/mtd/mtd.h>
109 #include <linux/mtd/onenand.h>
110 #include <onenand_uboot.h>
111 #endif
112
113 /* enable/disable debugging messages */
114 #define DEBUG_JFFS
115 #undef  DEBUG_JFFS
116
117 #ifdef  DEBUG_JFFS
118 # define DEBUGF(fmt, args...)   printf(fmt ,##args)
119 #else
120 # define DEBUGF(fmt, args...)
121 #endif
122
123 /* special size referring to all the remaining space in a partition */
124 #define SIZE_REMAINING          0xFFFFFFFF
125
126 /* special offset value, it is used when not provided by user
127  *
128  * this value is used temporarily during parsing, later such offests
129  * are recalculated */
130 #define OFFSET_NOT_SPECIFIED    0xFFFFFFFF
131
132 /* minimum partition size */
133 #define MIN_PART_SIZE           4096
134
135 /* this flag needs to be set in part_info struct mask_flags
136  * field for read-only partitions */
137 #define MTD_WRITEABLE_CMD               1
138
139 #ifdef CONFIG_JFFS2_CMDLINE
140 /* default values for mtdids and mtdparts variables */
141 #if defined(MTDIDS_DEFAULT)
142 static const char *const mtdids_default = MTDIDS_DEFAULT;
143 #else
144 #warning "MTDIDS_DEFAULT not defined!"
145 static const char *const mtdids_default = NULL;
146 #endif
147
148 #if defined(MTDPARTS_DEFAULT)
149 static const char *const mtdparts_default = MTDPARTS_DEFAULT;
150 #else
151 #warning "MTDPARTS_DEFAULT not defined!"
152 static const char *const mtdparts_default = NULL;
153 #endif
154
155 /* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */
156 #define MTDIDS_MAXLEN           128
157 #define MTDPARTS_MAXLEN         512
158 #define PARTITION_MAXLEN        16
159 static char last_ids[MTDIDS_MAXLEN];
160 static char last_parts[MTDPARTS_MAXLEN];
161 static char last_partition[PARTITION_MAXLEN];
162
163 /* low level jffs2 cache cleaning routine */
164 extern void jffs2_free_cache(struct part_info *part);
165
166 /* mtdids mapping list, filled by parse_ids() */
167 struct list_head mtdids;
168
169 /* device/partition list, parse_cmdline() parses into here */
170 struct list_head devices;
171 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
172
173 /* current active device and partition number */
174 static struct mtd_device *current_dev = NULL;
175 static u8 current_partnum = 0;
176
177 #if defined(CONFIG_CMD_CRAMFS)
178 extern int cramfs_check (struct part_info *info);
179 extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename);
180 extern int cramfs_ls (struct part_info *info, char *filename);
181 extern int cramfs_info (struct part_info *info);
182 #else
183 /* defining empty macros for function names is ugly but avoids ifdef clutter
184  * all over the code */
185 #define cramfs_check(x)         (0)
186 #define cramfs_load(x,y,z)      (-1)
187 #define cramfs_ls(x,y)          (0)
188 #define cramfs_info(x)          (0)
189 #endif
190
191 static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num);
192
193 /* command line only routines */
194 #ifdef CONFIG_JFFS2_CMDLINE
195
196 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);
197 static int device_del(struct mtd_device *dev);
198
199 /**
200  * Parses a string into a number.  The number stored at ptr is
201  * potentially suffixed with K (for kilobytes, or 1024 bytes),
202  * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
203  * 1073741824).  If the number is suffixed with K, M, or G, then
204  * the return value is the number multiplied by one kilobyte, one
205  * megabyte, or one gigabyte, respectively.
206  *
207  * @param ptr where parse begins
208  * @param retptr output pointer to next char after parse completes (output)
209  * @return resulting unsigned int
210  */
211 static unsigned long memsize_parse (const char *const ptr, const char **retptr)
212 {
213         unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
214
215         switch (**retptr) {
216                 case 'G':
217                 case 'g':
218                         ret <<= 10;
219                 case 'M':
220                 case 'm':
221                         ret <<= 10;
222                 case 'K':
223                 case 'k':
224                         ret <<= 10;
225                         (*retptr)++;
226                 default:
227                         break;
228         }
229
230         return ret;
231 }
232
233 /**
234  * Format string describing supplied size. This routine does the opposite job
235  * to memsize_parse(). Size in bytes is converted to string and if possible
236  * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix.
237  *
238  * Note, that this routine does not check for buffer overflow, it's the caller
239  * who must assure enough space.
240  *
241  * @param buf output buffer
242  * @param size size to be converted to string
243  */
244 static void memsize_format(char *buf, u32 size)
245 {
246 #define SIZE_GB ((u32)1024*1024*1024)
247 #define SIZE_MB ((u32)1024*1024)
248 #define SIZE_KB ((u32)1024)
249
250         if ((size % SIZE_GB) == 0)
251                 sprintf(buf, "%ug", size/SIZE_GB);
252         else if ((size % SIZE_MB) == 0)
253                 sprintf(buf, "%um", size/SIZE_MB);
254         else if (size % SIZE_KB == 0)
255                 sprintf(buf, "%uk", size/SIZE_KB);
256         else
257                 sprintf(buf, "%u", size);
258 }
259
260 /**
261  * This routine does global indexing of all partitions. Resulting index for
262  * current partition is saved in 'mtddevnum'. Current partition name in
263  * 'mtddevname'.
264  */
265 static void index_partitions(void)
266 {
267         char buf[16];
268         u16 mtddevnum;
269         struct part_info *part;
270         struct list_head *dentry;
271         struct mtd_device *dev;
272
273         DEBUGF("--- index partitions ---\n");
274
275         if (current_dev) {
276                 mtddevnum = 0;
277                 list_for_each(dentry, &devices) {
278                         dev = list_entry(dentry, struct mtd_device, link);
279                         if (dev == current_dev) {
280                                 mtddevnum += current_partnum;
281                                 sprintf(buf, "%d", mtddevnum);
282                                 setenv("mtddevnum", buf);
283                                 break;
284                         }
285                         mtddevnum += dev->num_parts;
286                 }
287
288                 part = jffs2_part_info(current_dev, current_partnum);
289                 setenv("mtddevname", part->name);
290
291                 DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name);
292         } else {
293                 setenv("mtddevnum", NULL);
294                 setenv("mtddevname", NULL);
295
296                 DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n");
297         }
298 }
299
300 /**
301  * Save current device and partition in environment variable 'partition'.
302  */
303 static void current_save(void)
304 {
305         char buf[16];
306
307         DEBUGF("--- current_save ---\n");
308
309         if (current_dev) {
310                 sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type),
311                                         current_dev->id->num, current_partnum);
312
313                 setenv("partition", buf);
314                 strncpy(last_partition, buf, 16);
315
316                 DEBUGF("=> partition %s\n", buf);
317         } else {
318                 setenv("partition", NULL);
319                 last_partition[0] = '\0';
320
321                 DEBUGF("=> partition NULL\n");
322         }
323         index_partitions();
324 }
325
326 /**
327  * Performs sanity check for supplied NOR flash partition. Table of existing
328  * NOR flash devices is searched and partition device is located. Alignment
329  * with the granularity of NOR flash sectors is verified.
330  *
331  * @param id of the parent device
332  * @param part partition to validate
333  * @return 0 if partition is valid, 1 otherwise
334  */
335 static int part_validate_nor(struct mtdids *id, struct part_info *part)
336 {
337 #if defined(CONFIG_CMD_FLASH)
338         /* info for FLASH chips */
339         extern flash_info_t flash_info[];
340         flash_info_t *flash;
341         int offset_aligned;
342         u32 end_offset, sector_size = 0;
343         int i;
344
345         flash = &flash_info[id->num];
346
347         /* size of last sector */
348         part->sector_size = flash->size -
349                 (flash->start[flash->sector_count-1] - flash->start[0]);
350
351         offset_aligned = 0;
352         for (i = 0; i < flash->sector_count; i++) {
353                 if ((flash->start[i] - flash->start[0]) == part->offset) {
354                         offset_aligned = 1;
355                         break;
356                 }
357         }
358         if (offset_aligned == 0) {
359                 printf("%s%d: partition (%s) start offset alignment incorrect\n",
360                                 MTD_DEV_TYPE(id->type), id->num, part->name);
361                 return 1;
362         }
363
364         end_offset = part->offset + part->size;
365         offset_aligned = 0;
366         for (i = 0; i < flash->sector_count; i++) {
367                 if (i) {
368                         sector_size = flash->start[i] - flash->start[i-1];
369                         if (part->sector_size < sector_size)
370                                 part->sector_size = sector_size;
371                 }
372                 if ((flash->start[i] - flash->start[0]) == end_offset)
373                         offset_aligned = 1;
374         }
375
376         if (offset_aligned || flash->size == end_offset)
377                 return 0;
378
379         printf("%s%d: partition (%s) size alignment incorrect\n",
380                         MTD_DEV_TYPE(id->type), id->num, part->name);
381 #endif
382         return 1;
383 }
384
385 /**
386  * Performs sanity check for supplied NAND flash partition. Table of existing
387  * NAND flash devices is searched and partition device is located. Alignment
388  * with the granularity of nand erasesize is verified.
389  *
390  * @param id of the parent device
391  * @param part partition to validate
392  * @return 0 if partition is valid, 1 otherwise
393  */
394 static int part_validate_nand(struct mtdids *id, struct part_info *part)
395 {
396 #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
397         /* info for NAND chips */
398         nand_info_t *nand;
399
400         nand = &nand_info[id->num];
401
402         part->sector_size = nand->erasesize;
403
404         if ((unsigned long)(part->offset) % nand->erasesize) {
405                 printf("%s%d: partition (%s) start offset alignment incorrect\n",
406                                 MTD_DEV_TYPE(id->type), id->num, part->name);
407                 return 1;
408         }
409
410         if (part->size % nand->erasesize) {
411                 printf("%s%d: partition (%s) size alignment incorrect\n",
412                                 MTD_DEV_TYPE(id->type), id->num, part->name);
413                 return 1;
414         }
415
416         return 0;
417 #else
418         return 1;
419 #endif
420 }
421
422 /**
423  * Performs sanity check for supplied OneNAND flash partition.
424  * Table of existing OneNAND flash devices is searched and partition device
425  * is located. Alignment with the granularity of nand erasesize is verified.
426  *
427  * @param id of the parent device
428  * @param part partition to validate
429  * @return 0 if partition is valid, 1 otherwise
430  */
431 static int part_validate_onenand(struct mtdids *id, struct part_info *part)
432 {
433 #if defined(CONFIG_CMD_ONENAND)
434         /* info for OneNAND chips */
435         struct mtd_info *mtd;
436
437         mtd = &onenand_mtd;
438
439         part->sector_size = mtd->erasesize;
440
441         if ((unsigned long)(part->offset) % mtd->erasesize) {
442                 printf("%s%d: partition (%s) start offset"
443                         "alignment incorrect\n",
444                                 MTD_DEV_TYPE(id->type), id->num, part->name);
445                 return 1;
446         }
447
448         if (part->size % mtd->erasesize) {
449                 printf("%s%d: partition (%s) size alignment incorrect\n",
450                                 MTD_DEV_TYPE(id->type), id->num, part->name);
451                 return 1;
452         }
453
454         return 0;
455 #else
456         return 1;
457 #endif
458 }
459
460
461 /**
462  * Performs sanity check for supplied partition. Offset and size are verified
463  * to be within valid range. Partition type is checked and either
464  * parts_validate_nor() or parts_validate_nand() is called with the argument
465  * of part.
466  *
467  * @param id of the parent device
468  * @param part partition to validate
469  * @return 0 if partition is valid, 1 otherwise
470  */
471 static int part_validate(struct mtdids *id, struct part_info *part)
472 {
473         if (part->size == SIZE_REMAINING)
474                 part->size = id->size - part->offset;
475
476         if (part->offset > id->size) {
477                 printf("%s: offset %08x beyond flash size %08x\n",
478                                 id->mtd_id, part->offset, id->size);
479                 return 1;
480         }
481
482         if ((part->offset + part->size) <= part->offset) {
483                 printf("%s%d: partition (%s) size too big\n",
484                                 MTD_DEV_TYPE(id->type), id->num, part->name);
485                 return 1;
486         }
487
488         if (part->offset + part->size > id->size) {
489                 printf("%s: partitioning exceeds flash size\n", id->mtd_id);
490                 return 1;
491         }
492
493         if (id->type == MTD_DEV_TYPE_NAND)
494                 return part_validate_nand(id, part);
495         else if (id->type == MTD_DEV_TYPE_NOR)
496                 return part_validate_nor(id, part);
497         else if (id->type == MTD_DEV_TYPE_ONENAND)
498                 return part_validate_onenand(id, part);
499         else
500                 DEBUGF("part_validate: invalid dev type\n");
501
502         return 1;
503 }
504
505 /**
506  * Delete selected partition from the partion list of the specified device.
507  *
508  * @param dev device to delete partition from
509  * @param part partition to delete
510  * @return 0 on success, 1 otherwise
511  */
512 static int part_del(struct mtd_device *dev, struct part_info *part)
513 {
514         u8 current_save_needed = 0;
515
516         /* if there is only one partition, remove whole device */
517         if (dev->num_parts == 1)
518                 return device_del(dev);
519
520         /* otherwise just delete this partition */
521
522         if (dev == current_dev) {
523                 /* we are modyfing partitions for the current device,
524                  * update current */
525                 struct part_info *curr_pi;
526                 curr_pi = jffs2_part_info(current_dev, current_partnum);
527
528                 if (curr_pi) {
529                         if (curr_pi == part) {
530                                 printf("current partition deleted, resetting current to 0\n");
531                                 current_partnum = 0;
532                         } else if (part->offset <= curr_pi->offset) {
533                                 current_partnum--;
534                         }
535                         current_save_needed = 1;
536                 }
537         }
538
539 #ifdef CONFIG_NAND_LEGACY
540         jffs2_free_cache(part);
541 #endif
542         list_del(&part->link);
543         free(part);
544         dev->num_parts--;
545
546         if (current_save_needed > 0)
547                 current_save();
548         else
549                 index_partitions();
550
551         return 0;
552 }
553
554 /**
555  * Delete all partitions from parts head list, free memory.
556  *
557  * @param head list of partitions to delete
558  */
559 static void part_delall(struct list_head *head)
560 {
561         struct list_head *entry, *n;
562         struct part_info *part_tmp;
563
564         /* clean tmp_list and free allocated memory */
565         list_for_each_safe(entry, n, head) {
566                 part_tmp = list_entry(entry, struct part_info, link);
567
568 #ifdef CONFIG_NAND_LEGACY
569                 jffs2_free_cache(part_tmp);
570 #endif
571                 list_del(entry);
572                 free(part_tmp);
573         }
574 }
575
576 /**
577  * Add new partition to the supplied partition list. Make sure partitions are
578  * sorted by offset in ascending order.
579  *
580  * @param head list this partition is to be added to
581  * @param new partition to be added
582  */
583 static int part_sort_add(struct mtd_device *dev, struct part_info *part)
584 {
585         struct list_head *entry;
586         struct part_info *new_pi, *curr_pi;
587
588         /* link partition to parrent dev */
589         part->dev = dev;
590
591         if (list_empty(&dev->parts)) {
592                 DEBUGF("part_sort_add: list empty\n");
593                 list_add(&part->link, &dev->parts);
594                 dev->num_parts++;
595                 index_partitions();
596                 return 0;
597         }
598
599         new_pi = list_entry(&part->link, struct part_info, link);
600
601         /* get current partition info if we are updating current device */
602         curr_pi = NULL;
603         if (dev == current_dev)
604                 curr_pi = jffs2_part_info(current_dev, current_partnum);
605
606         list_for_each(entry, &dev->parts) {
607                 struct part_info *pi;
608
609                 pi = list_entry(entry, struct part_info, link);
610
611                 /* be compliant with kernel cmdline, allow only one partition at offset zero */
612                 if ((new_pi->offset == pi->offset) && (pi->offset == 0)) {
613                         printf("cannot add second partition at offset 0\n");
614                         return 1;
615                 }
616
617                 if (new_pi->offset <= pi->offset) {
618                         list_add_tail(&part->link, entry);
619                         dev->num_parts++;
620
621                         if (curr_pi && (pi->offset <= curr_pi->offset)) {
622                                 /* we are modyfing partitions for the current
623                                  * device, update current */
624                                 current_partnum++;
625                                 current_save();
626                         } else {
627                                 index_partitions();
628                         }
629                         return 0;
630                 }
631         }
632
633         list_add_tail(&part->link, &dev->parts);
634         dev->num_parts++;
635         index_partitions();
636         return 0;
637 }
638
639 /**
640  * Add provided partition to the partition list of a given device.
641  *
642  * @param dev device to which partition is added
643  * @param part partition to be added
644  * @return 0 on success, 1 otherwise
645  */
646 static int part_add(struct mtd_device *dev, struct part_info *part)
647 {
648         /* verify alignment and size */
649         if (part_validate(dev->id, part) != 0)
650                 return 1;
651
652         /* partition is ok, add it to the list */
653         if (part_sort_add(dev, part) != 0)
654                 return 1;
655
656         return 0;
657 }
658
659 /**
660  * Parse one partition definition, allocate memory and return pointer to this
661  * location in retpart.
662  *
663  * @param partdef pointer to the partition definition string i.e. <part-def>
664  * @param ret output pointer to next char after parse completes (output)
665  * @param retpart pointer to the allocated partition (output)
666  * @return 0 on success, 1 otherwise
667  */
668 static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
669 {
670         struct part_info *part;
671         unsigned long size;
672         unsigned long offset;
673         const char *name;
674         int name_len;
675         unsigned int mask_flags;
676         const char *p;
677
678         p = partdef;
679         *retpart = NULL;
680         *ret = NULL;
681
682         /* fetch the partition size */
683         if (*p == '-') {
684                 /* assign all remaining space to this partition */
685                 DEBUGF("'-': remaining size assigned\n");
686                 size = SIZE_REMAINING;
687                 p++;
688         } else {
689                 size = memsize_parse(p, &p);
690                 if (size < MIN_PART_SIZE) {
691                         printf("partition size too small (%lx)\n", size);
692                         return 1;
693                 }
694         }
695
696         /* check for offset */
697         offset = OFFSET_NOT_SPECIFIED;
698         if (*p == '@') {
699                 p++;
700                 offset = memsize_parse(p, &p);
701         }
702
703         /* now look for the name */
704         if (*p == '(') {
705                 name = ++p;
706                 if ((p = strchr(name, ')')) == NULL) {
707                         printf("no closing ) found in partition name\n");
708                         return 1;
709                 }
710                 name_len = p - name + 1;
711                 if ((name_len - 1) == 0) {
712                         printf("empty partition name\n");
713                         return 1;
714                 }
715                 p++;
716         } else {
717                 /* 0x00000000@0x00000000 */
718                 name_len = 22;
719                 name = NULL;
720         }
721
722         /* test for options */
723         mask_flags = 0;
724         if (strncmp(p, "ro", 2) == 0) {
725                 mask_flags |= MTD_WRITEABLE_CMD;
726                 p += 2;
727         }
728
729         /* check for next partition definition */
730         if (*p == ',') {
731                 if (size == SIZE_REMAINING) {
732                         *ret = NULL;
733                         printf("no partitions allowed after a fill-up partition\n");
734                         return 1;
735                 }
736                 *ret = ++p;
737         } else if ((*p == ';') || (*p == '\0')) {
738                 *ret = p;
739         } else {
740                 printf("unexpected character '%c' at the end of partition\n", *p);
741                 *ret = NULL;
742                 return 1;
743         }
744
745         /*  allocate memory */
746         part = (struct part_info *)malloc(sizeof(struct part_info) + name_len);
747         if (!part) {
748                 printf("out of memory\n");
749                 return 1;
750         }
751         memset(part, 0, sizeof(struct part_info) + name_len);
752         part->size = size;
753         part->offset = offset;
754         part->mask_flags = mask_flags;
755         part->name = (char *)(part + 1);
756
757         if (name) {
758                 /* copy user provided name */
759                 strncpy(part->name, name, name_len - 1);
760                 part->auto_name = 0;
761         } else {
762                 /* auto generated name in form of size@offset */
763                 sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
764                 part->auto_name = 1;
765         }
766
767         part->name[name_len - 1] = '\0';
768         INIT_LIST_HEAD(&part->link);
769
770         DEBUGF("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
771                         part->name, part->size,
772                         part->offset, part->mask_flags);
773
774         *retpart = part;
775         return 0;
776 }
777 #endif/* #ifdef CONFIG_JFFS2_CMDLINE */
778
779 /**
780  * Check device number to be within valid range for given device type.
781  *
782  * @param dev device to validate
783  * @return 0 if device is valid, 1 otherwise
784  */
785 static int device_validate(u8 type, u8 num, u32 *size)
786 {
787         if (type == MTD_DEV_TYPE_NOR) {
788 #if defined(CONFIG_CMD_FLASH)
789                 if (num < CONFIG_SYS_MAX_FLASH_BANKS) {
790                         extern flash_info_t flash_info[];
791                         *size = flash_info[num].size;
792
793                         return 0;
794                 }
795
796                 printf("no such FLASH device: %s%d (valid range 0 ... %d\n",
797                                 MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_FLASH_BANKS - 1);
798 #else
799                 printf("support for FLASH devices not present\n");
800 #endif
801         } else if (type == MTD_DEV_TYPE_NAND) {
802 #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
803                 if (num < CONFIG_SYS_MAX_NAND_DEVICE) {
804 #ifndef CONFIG_NAND_LEGACY
805                         *size = nand_info[num].size;
806 #else
807                         extern struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE];
808                         *size = nand_dev_desc[num].totlen;
809 #endif
810                         return 0;
811                 }
812
813                 printf("no such NAND device: %s%d (valid range 0 ... %d)\n",
814                                 MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_NAND_DEVICE - 1);
815 #else
816                 printf("support for NAND devices not present\n");
817 #endif
818         } else if (type == MTD_DEV_TYPE_ONENAND) {
819 #if defined(CONFIG_CMD_ONENAND)
820                 *size = onenand_mtd.size;
821                 return 0;
822 #else
823                 printf("support for OneNAND devices not present\n");
824 #endif
825         } else
826                 printf("Unknown defice type %d\n", type);
827
828         return 1;
829 }
830
831 #ifdef CONFIG_JFFS2_CMDLINE
832 /**
833  * Delete all mtd devices from a supplied devices list, free memory allocated for
834  * each device and delete all device partitions.
835  *
836  * @return 0 on success, 1 otherwise
837  */
838 static int device_delall(struct list_head *head)
839 {
840         struct list_head *entry, *n;
841         struct mtd_device *dev_tmp;
842
843         /* clean devices list */
844         list_for_each_safe(entry, n, head) {
845                 dev_tmp = list_entry(entry, struct mtd_device, link);
846                 list_del(entry);
847                 part_delall(&dev_tmp->parts);
848                 free(dev_tmp);
849         }
850         INIT_LIST_HEAD(&devices);
851
852         return 0;
853 }
854
855 /**
856  * If provided device exists it's partitions are deleted, device is removed
857  * from device list and device memory is freed.
858  *
859  * @param dev device to be deleted
860  * @return 0 on success, 1 otherwise
861  */
862 static int device_del(struct mtd_device *dev)
863 {
864         part_delall(&dev->parts);
865         list_del(&dev->link);
866         free(dev);
867
868         if (dev == current_dev) {
869                 /* we just deleted current device */
870                 if (list_empty(&devices)) {
871                         current_dev = NULL;
872                 } else {
873                         /* reset first partition from first dev from the
874                          * devices list as current */
875                         current_dev = list_entry(devices.next, struct mtd_device, link);
876                         current_partnum = 0;
877                 }
878                 current_save();
879                 return 0;
880         }
881
882         index_partitions();
883         return 0;
884 }
885
886 /**
887  * Search global device list and return pointer to the device of type and num
888  * specified.
889  *
890  * @param type device type
891  * @param num device number
892  * @return NULL if requested device does not exist
893  */
894 static struct mtd_device* device_find(u8 type, u8 num)
895 {
896         struct list_head *entry;
897         struct mtd_device *dev_tmp;
898
899         list_for_each(entry, &devices) {
900                 dev_tmp = list_entry(entry, struct mtd_device, link);
901
902                 if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num))
903                         return dev_tmp;
904         }
905
906         return NULL;
907 }
908
909 /**
910  * Add specified device to the global device list.
911  *
912  * @param dev device to be added
913  */
914 static void device_add(struct mtd_device *dev)
915 {
916         u8 current_save_needed = 0;
917
918         if (list_empty(&devices)) {
919                 current_dev = dev;
920                 current_partnum = 0;
921                 current_save_needed = 1;
922         }
923
924         list_add_tail(&dev->link, &devices);
925
926         if (current_save_needed > 0)
927                 current_save();
928         else
929                 index_partitions();
930 }
931
932 /**
933  * Parse device type, name and mtd-id. If syntax is ok allocate memory and
934  * return pointer to the device structure.
935  *
936  * @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
937  * @param ret output pointer to next char after parse completes (output)
938  * @param retdev pointer to the allocated device (output)
939  * @return 0 on success, 1 otherwise
940  */
941 static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev)
942 {
943         struct mtd_device *dev;
944         struct part_info *part;
945         struct mtdids *id;
946         const char *mtd_id;
947         unsigned int mtd_id_len;
948         const char *p, *pend;
949         LIST_HEAD(tmp_list);
950         struct list_head *entry, *n;
951         u16 num_parts;
952         u32 offset;
953         int err = 1;
954
955         p = mtd_dev;
956         *retdev = NULL;
957         *ret = NULL;
958
959         DEBUGF("===device_parse===\n");
960
961         /* fetch <mtd-id> */
962         mtd_id = p;
963         if (!(p = strchr(mtd_id, ':'))) {
964                 printf("no <mtd-id> identifier\n");
965                 return 1;
966         }
967         mtd_id_len = p - mtd_id + 1;
968         p++;
969
970         /* verify if we have a valid device specified */
971         if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) {
972                 printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
973                 return 1;
974         }
975
976         DEBUGF("dev type = %d (%s), dev num = %d, mtd-id = %s\n",
977                         id->type, MTD_DEV_TYPE(id->type),
978                         id->num, id->mtd_id);
979         pend = strchr(p, ';');
980         DEBUGF("parsing partitions %.*s\n", (pend ? pend - p : strlen(p)), p);
981
982
983         /* parse partitions */
984         num_parts = 0;
985
986         offset = 0;
987         if ((dev = device_find(id->type, id->num)) != NULL) {
988                 /* if device already exists start at the end of the last partition */
989                 part = list_entry(dev->parts.prev, struct part_info, link);
990                 offset = part->offset + part->size;
991         }
992
993         while (p && (*p != '\0') && (*p != ';')) {
994                 err = 1;
995                 if ((part_parse(p, &p, &part) != 0) || (!part))
996                         break;
997
998                 /* calculate offset when not specified */
999                 if (part->offset == OFFSET_NOT_SPECIFIED)
1000                         part->offset = offset;
1001                 else
1002                         offset = part->offset;
1003
1004                 /* verify alignment and size */
1005                 if (part_validate(id, part) != 0)
1006                         break;
1007
1008                 offset += part->size;
1009
1010                 /* partition is ok, add it to the list */
1011                 list_add_tail(&part->link, &tmp_list);
1012                 num_parts++;
1013                 err = 0;
1014         }
1015         if (err == 1) {
1016                 part_delall(&tmp_list);
1017                 return 1;
1018         }
1019
1020         if (num_parts == 0) {
1021                 printf("no partitions for device %s%d (%s)\n",
1022                                 MTD_DEV_TYPE(id->type), id->num, id->mtd_id);
1023                 return 1;
1024         }
1025
1026         DEBUGF("\ntotal partitions: %d\n", num_parts);
1027
1028         /* check for next device presence */
1029         if (p) {
1030                 if (*p == ';') {
1031                         *ret = ++p;
1032                 } else if (*p == '\0') {
1033                         *ret = p;
1034                 } else {
1035                         printf("unexpected character '%c' at the end of device\n", *p);
1036                         *ret = NULL;
1037                         return 1;
1038                 }
1039         }
1040
1041         /* allocate memory for mtd_device structure */
1042         if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) {
1043                 printf("out of memory\n");
1044                 return 1;
1045         }
1046         memset(dev, 0, sizeof(struct mtd_device));
1047         dev->id = id;
1048         dev->num_parts = 0; /* part_sort_add increments num_parts */
1049         INIT_LIST_HEAD(&dev->parts);
1050         INIT_LIST_HEAD(&dev->link);
1051
1052         /* move partitions from tmp_list to dev->parts */
1053         list_for_each_safe(entry, n, &tmp_list) {
1054                 part = list_entry(entry, struct part_info, link);
1055                 list_del(entry);
1056                 if (part_sort_add(dev, part) != 0) {
1057                         device_del(dev);
1058                         return 1;
1059                 }
1060         }
1061
1062         *retdev = dev;
1063
1064         DEBUGF("===\n\n");
1065         return 0;
1066 }
1067
1068 /**
1069  * Initialize global device list.
1070  *
1071  * @return 0 on success, 1 otherwise
1072  */
1073 static int jffs2_devices_init(void)
1074 {
1075         last_parts[0] = '\0';
1076         current_dev = NULL;
1077         current_save();
1078
1079         return device_delall(&devices);
1080 }
1081
1082 /*
1083  * Search global mtdids list and find id of requested type and number.
1084  *
1085  * @return pointer to the id if it exists, NULL otherwise
1086  */
1087 static struct mtdids* id_find(u8 type, u8 num)
1088 {
1089         struct list_head *entry;
1090         struct mtdids *id;
1091
1092         list_for_each(entry, &mtdids) {
1093                 id = list_entry(entry, struct mtdids, link);
1094
1095                 if ((id->type == type) && (id->num == num))
1096                         return id;
1097         }
1098
1099         return NULL;
1100 }
1101
1102 /**
1103  * Search global mtdids list and find id of a requested mtd_id.
1104  *
1105  * Note: first argument is not null terminated.
1106  *
1107  * @param mtd_id string containing requested mtd_id
1108  * @param mtd_id_len length of supplied mtd_id
1109  * @return pointer to the id if it exists, NULL otherwise
1110  */
1111 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len)
1112 {
1113         struct list_head *entry;
1114         struct mtdids *id;
1115
1116         DEBUGF("--- id_find_by_mtd_id: '%.*s' (len = %d)\n",
1117                         mtd_id_len, mtd_id, mtd_id_len);
1118
1119         list_for_each(entry, &mtdids) {
1120                 id = list_entry(entry, struct mtdids, link);
1121
1122                 DEBUGF("entry: '%s' (len = %d)\n",
1123                                 id->mtd_id, strlen(id->mtd_id));
1124
1125                 if (mtd_id_len != strlen(id->mtd_id))
1126                         continue;
1127                 if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0)
1128                         return id;
1129         }
1130
1131         return NULL;
1132 }
1133 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
1134
1135 /**
1136  * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
1137  * return device type and number.
1138  *
1139  * @param id string describing device id
1140  * @param ret_id output pointer to next char after parse completes (output)
1141  * @param dev_type parsed device type (output)
1142  * @param dev_num parsed device number (output)
1143  * @return 0 on success, 1 otherwise
1144  */
1145 int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
1146 {
1147         const char *p = id;
1148
1149         *dev_type = 0;
1150         if (strncmp(p, "nand", 4) == 0) {
1151                 *dev_type = MTD_DEV_TYPE_NAND;
1152                 p += 4;
1153         } else if (strncmp(p, "nor", 3) == 0) {
1154                 *dev_type = MTD_DEV_TYPE_NOR;
1155                 p += 3;
1156         } else if (strncmp(p, "onenand", 7) == 0) {
1157                 *dev_type = MTD_DEV_TYPE_ONENAND;
1158                 p += 7;
1159         } else {
1160                 printf("incorrect device type in %s\n", id);
1161                 return 1;
1162         }
1163
1164         if (!isdigit(*p)) {
1165                 printf("incorrect device number in %s\n", id);
1166                 return 1;
1167         }
1168
1169         *dev_num = simple_strtoul(p, (char **)&p, 0);
1170         if (ret_id)
1171                 *ret_id = p;
1172         return 0;
1173 }
1174
1175 #ifdef CONFIG_JFFS2_CMDLINE
1176 /**
1177  * Process all devices and generate corresponding mtdparts string describing
1178  * all partitions on all devices.
1179  *
1180  * @param buf output buffer holding generated mtdparts string (output)
1181  * @param buflen buffer size
1182  * @return 0 on success, 1 otherwise
1183  */
1184 static int generate_mtdparts(char *buf, u32 buflen)
1185 {
1186         struct list_head *pentry, *dentry;
1187         struct mtd_device *dev;
1188         struct part_info *part, *prev_part;
1189         char *p = buf;
1190         char tmpbuf[32];
1191         u32 size, offset, len, part_cnt;
1192         u32 maxlen = buflen - 1;
1193
1194         DEBUGF("--- generate_mtdparts ---\n");
1195
1196         if (list_empty(&devices)) {
1197                 buf[0] = '\0';
1198                 return 0;
1199         }
1200
1201         sprintf(p, "mtdparts=");
1202         p += 9;
1203
1204         list_for_each(dentry, &devices) {
1205                 dev = list_entry(dentry, struct mtd_device, link);
1206
1207                 /* copy mtd_id */
1208                 len = strlen(dev->id->mtd_id) + 1;
1209                 if (len > maxlen)
1210                         goto cleanup;
1211                 memcpy(p, dev->id->mtd_id, len - 1);
1212                 p += len - 1;
1213                 *(p++) = ':';
1214                 maxlen -= len;
1215
1216                 /* format partitions */
1217                 prev_part = NULL;
1218                 part_cnt = 0;
1219                 list_for_each(pentry, &dev->parts) {
1220                         part = list_entry(pentry, struct part_info, link);
1221                         size = part->size;
1222                         offset = part->offset;
1223                         part_cnt++;
1224
1225                         /* partition size */
1226                         memsize_format(tmpbuf, size);
1227                         len = strlen(tmpbuf);
1228                         if (len > maxlen)
1229                                 goto cleanup;
1230                         memcpy(p, tmpbuf, len);
1231                         p += len;
1232                         maxlen -= len;
1233
1234
1235                         /* add offset only when there is a gap between
1236                          * partitions */
1237                         if ((!prev_part && (offset != 0)) ||
1238                                         (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) {
1239
1240                                 memsize_format(tmpbuf, offset);
1241                                 len = strlen(tmpbuf) + 1;
1242                                 if (len > maxlen)
1243                                         goto cleanup;
1244                                 *(p++) = '@';
1245                                 memcpy(p, tmpbuf, len - 1);
1246                                 p += len - 1;
1247                                 maxlen -= len;
1248                         }
1249
1250                         /* copy name only if user supplied */
1251                         if(!part->auto_name) {
1252                                 len = strlen(part->name) + 2;
1253                                 if (len > maxlen)
1254                                         goto cleanup;
1255
1256                                 *(p++) = '(';
1257                                 memcpy(p, part->name, len - 2);
1258                                 p += len - 2;
1259                                 *(p++) = ')';
1260                                 maxlen -= len;
1261                         }
1262
1263                         /* ro mask flag */
1264                         if (part->mask_flags && MTD_WRITEABLE_CMD) {
1265                                 len = 2;
1266                                 if (len > maxlen)
1267                                         goto cleanup;
1268                                 *(p++) = 'r';
1269                                 *(p++) = 'o';
1270                                 maxlen -= 2;
1271                         }
1272
1273                         /* print ',' separator if there are other partitions
1274                          * following */
1275                         if (dev->num_parts > part_cnt) {
1276                                 if (1 > maxlen)
1277                                         goto cleanup;
1278                                 *(p++) = ',';
1279                                 maxlen--;
1280                         }
1281                         prev_part = part;
1282                 }
1283                 /* print ';' separator if there are other devices following */
1284                 if (dentry->next != &devices) {
1285                         if (1 > maxlen)
1286                                 goto cleanup;
1287                         *(p++) = ';';
1288                         maxlen--;
1289                 }
1290         }
1291
1292         /* we still have at least one char left, as we decremented maxlen at
1293          * the begining */
1294         *p = '\0';
1295
1296         return 0;
1297
1298 cleanup:
1299         last_parts[0] = '\0';
1300         return 1;
1301 }
1302
1303 /**
1304  * Call generate_mtdparts to process all devices and generate corresponding
1305  * mtdparts string, save it in mtdparts environment variable.
1306  *
1307  * @param buf output buffer holding generated mtdparts string (output)
1308  * @param buflen buffer size
1309  * @return 0 on success, 1 otherwise
1310  */
1311 static int generate_mtdparts_save(char *buf, u32 buflen)
1312 {
1313         int ret;
1314
1315         ret = generate_mtdparts(buf, buflen);
1316
1317         if ((buf[0] != '\0') && (ret == 0))
1318                 setenv("mtdparts", buf);
1319         else
1320                 setenv("mtdparts", NULL);
1321
1322         return ret;
1323 }
1324
1325 /**
1326  * Format and print out a partition list for each device from global device
1327  * list.
1328  */
1329 static void list_partitions(void)
1330 {
1331         struct list_head *dentry, *pentry;
1332         struct part_info *part;
1333         struct mtd_device *dev;
1334         int part_num;
1335
1336         DEBUGF("\n---list_partitions---\n");
1337         list_for_each(dentry, &devices) {
1338                 dev = list_entry(dentry, struct mtd_device, link);
1339                 printf("\ndevice %s%d <%s>, # parts = %d\n",
1340                                 MTD_DEV_TYPE(dev->id->type), dev->id->num,
1341                                 dev->id->mtd_id, dev->num_parts);
1342                 printf(" #: name\t\t\tsize\t\toffset\t\tmask_flags\n");
1343
1344                 /* list partitions for given device */
1345                 part_num = 0;
1346                 list_for_each(pentry, &dev->parts) {
1347                         part = list_entry(pentry, struct part_info, link);
1348                         printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
1349                                         part_num, part->name, part->size,
1350                                         part->offset, part->mask_flags);
1351
1352                         part_num++;
1353                 }
1354         }
1355         if (list_empty(&devices))
1356                 printf("no partitions defined\n");
1357
1358         /* current_dev is not NULL only when we have non empty device list */
1359         if (current_dev) {
1360                 part = jffs2_part_info(current_dev, current_partnum);
1361                 if (part) {
1362                         printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n",
1363                                         MTD_DEV_TYPE(current_dev->id->type),
1364                                         current_dev->id->num, current_partnum,
1365                                         part->name, part->size, part->offset);
1366                 } else {
1367                         printf("could not get current partition info\n\n");
1368                 }
1369         }
1370
1371         printf("\ndefaults:\n");
1372         printf("mtdids  : %s\n", mtdids_default);
1373         printf("mtdparts: %s\n", mtdparts_default);
1374 }
1375
1376 /**
1377  * Given partition identifier in form of <dev_type><dev_num>,<part_num> find
1378  * corresponding device and verify partition number.
1379  *
1380  * @param id string describing device and partition or partition name
1381  * @param dev pointer to the requested device (output)
1382  * @param part_num verified partition number (output)
1383  * @param part pointer to requested partition (output)
1384  * @return 0 on success, 1 otherwise
1385  */
1386 int find_dev_and_part(const char *id, struct mtd_device **dev,
1387                 u8 *part_num, struct part_info **part)
1388 {
1389         struct list_head *dentry, *pentry;
1390         u8 type, dnum, pnum;
1391         const char *p;
1392
1393         DEBUGF("--- find_dev_and_part ---\nid = %s\n", id);
1394
1395         list_for_each(dentry, &devices) {
1396                 *part_num = 0;
1397                 *dev = list_entry(dentry, struct mtd_device, link);
1398                 list_for_each(pentry, &(*dev)->parts) {
1399                         *part = list_entry(pentry, struct part_info, link);
1400                         if (strcmp((*part)->name, id) == 0)
1401                                 return 0;
1402                         (*part_num)++;
1403                 }
1404         }
1405
1406         p = id;
1407         *dev = NULL;
1408         *part = NULL;
1409         *part_num = 0;
1410
1411         if (id_parse(p, &p, &type, &dnum) != 0)
1412                 return 1;
1413
1414         if ((*p++ != ',') || (*p == '\0')) {
1415                 printf("no partition number specified\n");
1416                 return 1;
1417         }
1418         pnum = simple_strtoul(p, (char **)&p, 0);
1419         if (*p != '\0') {
1420                 printf("unexpected trailing character '%c'\n", *p);
1421                 return 1;
1422         }
1423
1424         if ((*dev = device_find(type, dnum)) == NULL) {
1425                 printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
1426                 return 1;
1427         }
1428
1429         if ((*part = jffs2_part_info(*dev, pnum)) == NULL) {
1430                 printf("no such partition\n");
1431                 *dev = NULL;
1432                 return 1;
1433         }
1434
1435         *part_num = pnum;
1436
1437         return 0;
1438 }
1439
1440 /**
1441  * Find and delete partition. For partition id format see find_dev_and_part().
1442  *
1443  * @param id string describing device and partition
1444  * @return 0 on success, 1 otherwise
1445  */
1446 static int delete_partition(const char *id)
1447 {
1448         u8 pnum;
1449         struct mtd_device *dev;
1450         struct part_info *part;
1451
1452         if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
1453
1454                 DEBUGF("delete_partition: device = %s%d, partition %d = (%s) 0x%08lx@0x%08lx\n",
1455                                 MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
1456                                 part->name, part->size, part->offset);
1457
1458                 if (part_del(dev, part) != 0)
1459                         return 1;
1460
1461                 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
1462                         printf("generated mtdparts too long, reseting to null\n");
1463                         return 1;
1464                 }
1465                 return 0;
1466         }
1467
1468         printf("partition %s not found\n", id);
1469         return 1;
1470 }
1471
1472 /**
1473  * Accept character string describing mtd partitions and call device_parse()
1474  * for each entry. Add created devices to the global devices list.
1475  *
1476  * @param mtdparts string specifing mtd partitions
1477  * @return 0 on success, 1 otherwise
1478  */
1479 static int parse_mtdparts(const char *const mtdparts)
1480 {
1481         const char *p = mtdparts;
1482         struct mtd_device *dev;
1483         int err = 1;
1484
1485         DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p);
1486
1487         /* delete all devices and partitions */
1488         if (jffs2_devices_init() != 0) {
1489                 printf("could not initialise device list\n");
1490                 return err;
1491         }
1492
1493         /* re-read 'mtdparts' variable, jffs2_devices_init may be updating env */
1494         p = getenv("mtdparts");
1495
1496         if (strncmp(p, "mtdparts=", 9) != 0) {
1497                 printf("mtdparts variable doesn't start with 'mtdparts='\n");
1498                 return err;
1499         }
1500         p += 9;
1501
1502         while (p && (*p != '\0')) {
1503                 err = 1;
1504                 if ((device_parse(p, &p, &dev) != 0) || (!dev))
1505                         break;
1506
1507                 DEBUGF("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
1508                                 dev->id->num, dev->id->mtd_id);
1509
1510                 /* check if parsed device is already on the list */
1511                 if (device_find(dev->id->type, dev->id->num) != NULL) {
1512                         printf("device %s%d redefined, please correct mtdparts variable\n",
1513                                         MTD_DEV_TYPE(dev->id->type), dev->id->num);
1514                         break;
1515                 }
1516
1517                 list_add_tail(&dev->link, &devices);
1518                 err = 0;
1519         }
1520         if (err == 1) {
1521                 device_delall(&devices);
1522                 return 1;
1523         }
1524
1525         return 0;
1526 }
1527
1528 /**
1529  * Parse provided string describing mtdids mapping (see file header for mtdids
1530  * variable format). Allocate memory for each entry and add all found entries
1531  * to the global mtdids list.
1532  *
1533  * @param ids mapping string
1534  * @return 0 on success, 1 otherwise
1535  */
1536 static int parse_mtdids(const char *const ids)
1537 {
1538         const char *p = ids;
1539         const char *mtd_id;
1540         int mtd_id_len;
1541         struct mtdids *id;
1542         struct list_head *entry, *n;
1543         struct mtdids *id_tmp;
1544         u8 type, num;
1545         u32 size;
1546         int ret = 1;
1547
1548         DEBUGF("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
1549
1550         /* clean global mtdids list */
1551         list_for_each_safe(entry, n, &mtdids) {
1552                 id_tmp = list_entry(entry, struct mtdids, link);
1553                 DEBUGF("mtdids del: %d %d\n", id_tmp->type, id_tmp->num);
1554                 list_del(entry);
1555                 free(id_tmp);
1556         }
1557         last_ids[0] = '\0';
1558         INIT_LIST_HEAD(&mtdids);
1559
1560         while(p && (*p != '\0')) {
1561
1562                 ret = 1;
1563                 /* parse 'nor'|'nand'|'onenand'<dev-num> */
1564                 if (id_parse(p, &p, &type, &num) != 0)
1565                         break;
1566
1567                 if (*p != '=') {
1568                         printf("mtdids: incorrect <dev-num>\n");
1569                         break;
1570                 }
1571                 p++;
1572
1573                 /* check if requested device exists */
1574                 if (device_validate(type, num, &size) != 0)
1575                         return 1;
1576
1577                 /* locate <mtd-id> */
1578                 mtd_id = p;
1579                 if ((p = strchr(mtd_id, ',')) != NULL) {
1580                         mtd_id_len = p - mtd_id + 1;
1581                         p++;
1582                 } else {
1583                         mtd_id_len = strlen(mtd_id) + 1;
1584                 }
1585                 if (mtd_id_len == 0) {
1586                         printf("mtdids: no <mtd-id> identifier\n");
1587                         break;
1588                 }
1589
1590                 /* check if this id is already on the list */
1591                 int double_entry = 0;
1592                 list_for_each(entry, &mtdids) {
1593                         id_tmp = list_entry(entry, struct mtdids, link);
1594                         if ((id_tmp->type == type) && (id_tmp->num == num)) {
1595                                 double_entry = 1;
1596                                 break;
1597                         }
1598                 }
1599                 if (double_entry) {
1600                         printf("device id %s%d redefined, please correct mtdids variable\n",
1601                                         MTD_DEV_TYPE(type), num);
1602                         break;
1603                 }
1604
1605                 /* allocate mtdids structure */
1606                 if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) {
1607                         printf("out of memory\n");
1608                         break;
1609                 }
1610                 memset(id, 0, sizeof(struct mtdids) + mtd_id_len);
1611                 id->num = num;
1612                 id->type = type;
1613                 id->size = size;
1614                 id->mtd_id = (char *)(id + 1);
1615                 strncpy(id->mtd_id, mtd_id, mtd_id_len - 1);
1616                 id->mtd_id[mtd_id_len - 1] = '\0';
1617                 INIT_LIST_HEAD(&id->link);
1618
1619                 DEBUGF("+ id %s%d\t%16d bytes\t%s\n",
1620                                 MTD_DEV_TYPE(id->type), id->num,
1621                                 id->size, id->mtd_id);
1622
1623                 list_add_tail(&id->link, &mtdids);
1624                 ret = 0;
1625         }
1626         if (ret == 1) {
1627                 /* clean mtdids list and free allocated memory */
1628                 list_for_each_safe(entry, n, &mtdids) {
1629                         id_tmp = list_entry(entry, struct mtdids, link);
1630                         list_del(entry);
1631                         free(id_tmp);
1632                 }
1633                 return 1;
1634         }
1635
1636         return 0;
1637 }
1638
1639 /**
1640  * Parse and initialize global mtdids mapping and create global
1641  * device/partition list.
1642  *
1643  * @return 0 on success, 1 otherwise
1644  */
1645 int mtdparts_init(void)
1646 {
1647         static int initialized = 0;
1648         const char *ids, *parts;
1649         const char *current_partition;
1650         int ids_changed;
1651         char tmp_ep[PARTITION_MAXLEN];
1652
1653         DEBUGF("\n---mtdparts_init---\n");
1654         if (!initialized) {
1655                 INIT_LIST_HEAD(&mtdids);
1656                 INIT_LIST_HEAD(&devices);
1657                 memset(last_ids, 0, MTDIDS_MAXLEN);
1658                 memset(last_parts, 0, MTDPARTS_MAXLEN);
1659                 memset(last_partition, 0, PARTITION_MAXLEN);
1660                 initialized = 1;
1661         }
1662
1663         /* get variables */
1664         ids = getenv("mtdids");
1665         parts = getenv("mtdparts");
1666         current_partition = getenv("partition");
1667
1668         /* save it for later parsing, cannot rely on current partition pointer
1669          * as 'partition' variable may be updated during init */
1670         tmp_ep[0] = '\0';
1671         if (current_partition)
1672                 strncpy(tmp_ep, current_partition, PARTITION_MAXLEN);
1673
1674         DEBUGF("last_ids  : %s\n", last_ids);
1675         DEBUGF("env_ids   : %s\n", ids);
1676         DEBUGF("last_parts: %s\n", last_parts);
1677         DEBUGF("env_parts : %s\n\n", parts);
1678
1679         DEBUGF("last_partition : %s\n", last_partition);
1680         DEBUGF("env_partition  : %s\n", current_partition);
1681
1682         /* if mtdids varible is empty try to use defaults */
1683         if (!ids) {
1684                 if (mtdids_default) {
1685                         DEBUGF("mtdids variable not defined, using default\n");
1686                         ids = mtdids_default;
1687                         setenv("mtdids", (char *)ids);
1688                 } else {
1689                         printf("mtdids not defined, no default present\n");
1690                         return 1;
1691                 }
1692         }
1693         if (strlen(ids) > MTDIDS_MAXLEN - 1) {
1694                 printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
1695                 return 1;
1696         }
1697
1698         /* do no try to use defaults when mtdparts variable is not defined,
1699          * just check the length */
1700         if (!parts)
1701                 printf("mtdparts variable not set, see 'help mtdparts'\n");
1702
1703         if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) {
1704                 printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
1705                 return 1;
1706         }
1707
1708         /* check if we have already parsed those mtdids */
1709         if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) {
1710                 ids_changed = 0;
1711         } else {
1712                 ids_changed = 1;
1713
1714                 if (parse_mtdids(ids) != 0) {
1715                         jffs2_devices_init();
1716                         return 1;
1717                 }
1718
1719                 /* ok it's good, save new ids */
1720                 strncpy(last_ids, ids, MTDIDS_MAXLEN);
1721         }
1722
1723         /* parse partitions if either mtdparts or mtdids were updated */
1724         if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) {
1725                 if (parse_mtdparts(parts) != 0)
1726                         return 1;
1727
1728                 if (list_empty(&devices)) {
1729                         printf("mtdparts_init: no valid partitions\n");
1730                         return 1;
1731                 }
1732
1733                 /* ok it's good, save new parts */
1734                 strncpy(last_parts, parts, MTDPARTS_MAXLEN);
1735
1736                 /* reset first partition from first dev from the list as current */
1737                 current_dev = list_entry(devices.next, struct mtd_device, link);
1738                 current_partnum = 0;
1739                 current_save();
1740
1741                 DEBUGF("mtdparts_init: current_dev  = %s%d, current_partnum = %d\n",
1742                                 MTD_DEV_TYPE(current_dev->id->type),
1743                                 current_dev->id->num, current_partnum);
1744         }
1745
1746         /* mtdparts variable was reset to NULL, delete all devices/partitions */
1747         if (!parts && (last_parts[0] != '\0'))
1748                 return jffs2_devices_init();
1749
1750         /* do not process current partition if mtdparts variable is null */
1751         if (!parts)
1752                 return 0;
1753
1754         /* is current partition set in environment? if so, use it */
1755         if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) {
1756                 struct part_info *p;
1757                 struct mtd_device *cdev;
1758                 u8 pnum;
1759
1760                 DEBUGF("--- getting current partition: %s\n", tmp_ep);
1761
1762                 if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
1763                         current_dev = cdev;
1764                         current_partnum = pnum;
1765                         current_save();
1766                 }
1767         } else if (getenv("partition") == NULL) {
1768                 DEBUGF("no partition variable set, setting...\n");
1769                 current_save();
1770         }
1771
1772         return 0;
1773 }
1774 #else /* #ifdef CONFIG_JFFS2_CMDLINE */
1775 /*
1776  * 'Static' version of command line mtdparts_init() routine. Single partition on
1777  * a single device configuration.
1778  */
1779
1780 /**
1781  * Calculate sector size.
1782  *
1783  * @return sector size
1784  */
1785 static inline u32 get_part_sector_size_nand(struct mtdids *id)
1786 {
1787 #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
1788 #if defined(CONFIG_NAND_LEGACY)
1789         extern struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE];
1790
1791         return nand_dev_desc[id->num].erasesize;
1792 #else
1793         nand_info_t *nand;
1794
1795         nand = &nand_info[id->num];
1796
1797         return nand->erasesize;
1798 #endif
1799 #else
1800         BUG();
1801         return 0;
1802 #endif
1803 }
1804
1805 static inline u32 get_part_sector_size_nor(struct mtdids *id, struct part_info *part)
1806 {
1807 #if defined(CONFIG_CMD_FLASH)
1808         extern flash_info_t flash_info[];
1809
1810         u32 end_phys, start_phys, sector_size = 0, size = 0;
1811         int i;
1812         flash_info_t *flash;
1813
1814         flash = &flash_info[id->num];
1815
1816         start_phys = flash->start[0] + part->offset;
1817         end_phys = start_phys + part->size;
1818
1819         for (i = 0; i < flash->sector_count; i++) {
1820                 if (flash->start[i] >= end_phys)
1821                         break;
1822
1823                 if (flash->start[i] >= start_phys) {
1824                         if (i == flash->sector_count - 1) {
1825                                 size = flash->start[0] + flash->size - flash->start[i];
1826                         } else {
1827                                 size = flash->start[i+1] - flash->start[i];
1828                         }
1829
1830                         if (sector_size < size)
1831                                 sector_size = size;
1832                 }
1833         }
1834
1835         return sector_size;
1836 #else
1837         BUG();
1838         return 0;
1839 #endif
1840 }
1841
1842 static inline u32 get_part_sector_size_onenand(void)
1843 {
1844 #if defined(CONFIG_CMD_ONENAND)
1845         struct mtd_info *mtd;
1846
1847         mtd = &onenand_mtd;
1848
1849         return mtd->erasesize;
1850 #else
1851         BUG();
1852         return 0;
1853 #endif
1854 }
1855
1856 static inline u32 get_part_sector_size(struct mtdids *id, struct part_info *part)
1857 {
1858         if (id->type == MTD_DEV_TYPE_NAND)
1859                 return get_part_sector_size_nand(id);
1860         else if (id->type == MTD_DEV_TYPE_NOR)
1861                 return get_part_sector_size_nor(id, part);
1862         else if (id->type == MTD_DEV_TYPE_ONENAND)
1863                 return get_part_sector_size_onenand();
1864         else
1865                 DEBUGF("Error: Unknown device type.\n");
1866
1867         return 0;
1868 }
1869
1870 /**
1871  * Parse and initialize global mtdids mapping and create global
1872  * device/partition list.
1873  *
1874  * @return 0 on success, 1 otherwise
1875  */
1876 int mtdparts_init(void)
1877 {
1878         static int initialized = 0;
1879         u32 size;
1880         char *dev_name;
1881
1882         DEBUGF("\n---mtdparts_init---\n");
1883         if (!initialized) {
1884                 struct mtdids *id;
1885                 struct part_info *part;
1886
1887                 initialized = 1;
1888                 current_dev = (struct mtd_device *)
1889                         malloc(sizeof(struct mtd_device) +
1890                                         sizeof(struct part_info) +
1891                                         sizeof(struct mtdids));
1892                 if (!current_dev) {
1893                         printf("out of memory\n");
1894                         return 1;
1895                 }
1896                 memset(current_dev, 0, sizeof(struct mtd_device) +
1897                                         sizeof(struct part_info) + sizeof(struct mtdids));
1898
1899                 id = (struct mtdids *)(current_dev + 1);
1900                 part = (struct part_info *)(id + 1);
1901
1902                 /* id */
1903                 id->mtd_id = "single part";
1904
1905 #if defined(CONFIG_JFFS2_DEV)
1906                 dev_name = CONFIG_JFFS2_DEV;
1907 #else
1908                 dev_name = "nor0";
1909 #endif
1910
1911                 if ((id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
1912                                 (device_validate(id->type, id->num, &size) != 0)) {
1913                         printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num);
1914                         free(current_dev);
1915                         return 1;
1916                 }
1917                 id->size = size;
1918                 INIT_LIST_HEAD(&id->link);
1919
1920                 DEBUGF("dev id: type = %d, num = %d, size = 0x%08lx, mtd_id = %s\n",
1921                                 id->type, id->num, id->size, id->mtd_id);
1922
1923                 /* partition */
1924                 part->name = "static";
1925                 part->auto_name = 0;
1926
1927 #if defined(CONFIG_JFFS2_PART_SIZE)
1928                 part->size = CONFIG_JFFS2_PART_SIZE;
1929 #else
1930                 part->size = SIZE_REMAINING;
1931 #endif
1932
1933 #if defined(CONFIG_JFFS2_PART_OFFSET)
1934                 part->offset = CONFIG_JFFS2_PART_OFFSET;
1935 #else
1936                 part->offset = 0x00000000;
1937 #endif
1938
1939                 part->sector_size = get_part_sector_size(id, part);
1940
1941                 part->dev = current_dev;
1942                 INIT_LIST_HEAD(&part->link);
1943
1944                 /* recalculate size if needed */
1945                 if (part->size == SIZE_REMAINING)
1946                         part->size = id->size - part->offset;
1947
1948                 DEBUGF("part  : name = %s, size = 0x%08lx, offset = 0x%08lx\n",
1949                                 part->name, part->size, part->offset);
1950
1951                 /* device */
1952                 current_dev->id = id;
1953                 INIT_LIST_HEAD(&current_dev->link);
1954                 current_dev->num_parts = 1;
1955                 INIT_LIST_HEAD(&current_dev->parts);
1956                 list_add(&part->link, &current_dev->parts);
1957         }
1958
1959         return 0;
1960 }
1961 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
1962
1963 /**
1964  * Return pointer to the partition of a requested number from a requested
1965  * device.
1966  *
1967  * @param dev device that is to be searched for a partition
1968  * @param part_num requested partition number
1969  * @return pointer to the part_info, NULL otherwise
1970  */
1971 static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num)
1972 {
1973         struct list_head *entry;
1974         struct part_info *part;
1975         int num;
1976
1977         if (!dev)
1978                 return NULL;
1979
1980         DEBUGF("\n--- jffs2_part_info: partition number %d for device %s%d (%s)\n",
1981                         part_num, MTD_DEV_TYPE(dev->id->type),
1982                         dev->id->num, dev->id->mtd_id);
1983
1984         if (part_num >= dev->num_parts) {
1985                 printf("invalid partition number %d for device %s%d (%s)\n",
1986                                 part_num, MTD_DEV_TYPE(dev->id->type),
1987                                 dev->id->num, dev->id->mtd_id);
1988                 return NULL;
1989         }
1990
1991         /* locate partition number, return it */
1992         num = 0;
1993         list_for_each(entry, &dev->parts) {
1994                 part = list_entry(entry, struct part_info, link);
1995
1996                 if (part_num == num++) {
1997                         return part;
1998                 }
1999         }
2000
2001         return NULL;
2002 }
2003
2004 /***************************************************/
2005 /* U-boot commands                                 */
2006 /***************************************************/
2007
2008 /**
2009  * Routine implementing fsload u-boot command. This routine tries to load
2010  * a requested file from jffs2/cramfs filesystem on a current partition.
2011  *
2012  * @param cmdtp command internal data
2013  * @param flag command flag
2014  * @param argc number of arguments supplied to the command
2015  * @param argv arguments list
2016  * @return 0 on success, 1 otherwise
2017  */
2018 int do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
2019 {
2020         char *fsname;
2021         char *filename;
2022         int size;
2023         struct part_info *part;
2024         ulong offset = load_addr;
2025
2026         /* pre-set Boot file name */
2027         if ((filename = getenv("bootfile")) == NULL) {
2028                 filename = "uImage";
2029         }
2030
2031         if (argc == 2) {
2032                 filename = argv[1];
2033         }
2034         if (argc == 3) {
2035                 offset = simple_strtoul(argv[1], NULL, 16);
2036                 load_addr = offset;
2037                 filename = argv[2];
2038         }
2039
2040         /* make sure we are in sync with env variables */
2041         if (mtdparts_init() !=0)
2042                 return 1;
2043
2044         if ((part = jffs2_part_info(current_dev, current_partnum))){
2045
2046                 /* check partition type for cramfs */
2047                 fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
2048                 printf("### %s loading '%s' to 0x%lx\n", fsname, filename, offset);
2049
2050                 if (cramfs_check(part)) {
2051                         size = cramfs_load ((char *) offset, part, filename);
2052                 } else {
2053                         /* if this is not cramfs assume jffs2 */
2054                         size = jffs2_1pass_load((char *)offset, part, filename);
2055                 }
2056
2057                 if (size > 0) {
2058                         char buf[10];
2059                         printf("### %s load complete: %d bytes loaded to 0x%lx\n",
2060                                 fsname, size, offset);
2061                         sprintf(buf, "%x", size);
2062                         setenv("filesize", buf);
2063                 } else {
2064                         printf("### %s LOAD ERROR<%x> for %s!\n", fsname, size, filename);
2065                 }
2066
2067                 return !(size > 0);
2068         }
2069         return 1;
2070 }
2071
2072 /**
2073  * Routine implementing u-boot ls command which lists content of a given
2074  * directory on a current partition.
2075  *
2076  * @param cmdtp command internal data
2077  * @param flag command flag
2078  * @param argc number of arguments supplied to the command
2079  * @param argv arguments list
2080  * @return 0 on success, 1 otherwise
2081  */
2082 int do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
2083 {
2084         char *filename = "/";
2085         int ret;
2086         struct part_info *part;
2087
2088         if (argc == 2)
2089                 filename = argv[1];
2090
2091         /* make sure we are in sync with env variables */
2092         if (mtdparts_init() !=0)
2093                 return 1;
2094
2095         if ((part = jffs2_part_info(current_dev, current_partnum))){
2096
2097                 /* check partition type for cramfs */
2098                 if (cramfs_check(part)) {
2099                         ret = cramfs_ls (part, filename);
2100                 } else {
2101                         /* if this is not cramfs assume jffs2 */
2102                         ret = jffs2_1pass_ls(part, filename);
2103                 }
2104
2105                 return ret ? 0 : 1;
2106         }
2107         return 1;
2108 }
2109
2110 /**
2111  * Routine implementing u-boot fsinfo command. This routine prints out
2112  * miscellaneous filesystem informations/statistics.
2113  *
2114  * @param cmdtp command internal data
2115  * @param flag command flag
2116  * @param argc number of arguments supplied to the command
2117  * @param argv arguments list
2118  * @return 0 on success, 1 otherwise
2119  */
2120 int do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
2121 {
2122         struct part_info *part;
2123         char *fsname;
2124         int ret;
2125
2126         /* make sure we are in sync with env variables */
2127         if (mtdparts_init() !=0)
2128                 return 1;
2129
2130         if ((part = jffs2_part_info(current_dev, current_partnum))){
2131
2132                 /* check partition type for cramfs */
2133                 fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
2134                 printf("### filesystem type is %s\n", fsname);
2135
2136                 if (cramfs_check(part)) {
2137                         ret = cramfs_info (part);
2138                 } else {
2139                         /* if this is not cramfs assume jffs2 */
2140                         ret = jffs2_1pass_info(part);
2141                 }
2142
2143                 return ret ? 0 : 1;
2144         }
2145         return 1;
2146 }
2147
2148 /* command line only */
2149 #ifdef CONFIG_JFFS2_CMDLINE
2150 /**
2151  * Routine implementing u-boot chpart command. Sets new current partition based
2152  * on the user supplied partition id. For partition id format see find_dev_and_part().
2153  *
2154  * @param cmdtp command internal data
2155  * @param flag command flag
2156  * @param argc number of arguments supplied to the command
2157  * @param argv arguments list
2158  * @return 0 on success, 1 otherwise
2159  */
2160 int do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
2161 {
2162 /* command line only */
2163         struct mtd_device *dev;
2164         struct part_info *part;
2165         u8 pnum;
2166
2167         if (mtdparts_init() !=0)
2168                 return 1;
2169
2170         if (argc < 2) {
2171                 printf("no partition id specified\n");
2172                 return 1;
2173         }
2174
2175         if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
2176                 return 1;
2177
2178         current_dev = dev;
2179         current_partnum = pnum;
2180         current_save();
2181
2182         printf("partition changed to %s%d,%d\n",
2183                         MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum);
2184
2185         return 0;
2186 }
2187
2188 /**
2189  * Routine implementing u-boot mtdparts command. Initialize/update default global
2190  * partition list and process user partition request (list, add, del).
2191  *
2192  * @param cmdtp command internal data
2193  * @param flag command flag
2194  * @param argc number of arguments supplied to the command
2195  * @param argv arguments list
2196  * @return 0 on success, 1 otherwise
2197  */
2198 int do_jffs2_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
2199 {
2200         if (argc == 2) {
2201                 if (strcmp(argv[1], "default") == 0) {
2202                         setenv("mtdids", (char *)mtdids_default);
2203                         setenv("mtdparts", (char *)mtdparts_default);
2204                         setenv("partition", NULL);
2205
2206                         mtdparts_init();
2207                         return 0;
2208                 } else if (strcmp(argv[1], "delall") == 0) {
2209                         /* this may be the first run, initialize lists if needed */
2210                         mtdparts_init();
2211
2212                         setenv("mtdparts", NULL);
2213
2214                         /* jffs2_devices_init() calls current_save() */
2215                         return jffs2_devices_init();
2216                 }
2217         }
2218
2219         /* make sure we are in sync with env variables */
2220         if (mtdparts_init() != 0)
2221                 return 1;
2222
2223         if (argc == 1) {
2224                 list_partitions();
2225                 return 0;
2226         }
2227
2228         /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
2229         if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
2230 #define PART_ADD_DESC_MAXLEN 64
2231                 char tmpbuf[PART_ADD_DESC_MAXLEN];
2232                 u8 type, num, len;
2233                 struct mtd_device *dev;
2234                 struct mtd_device *dev_tmp;
2235                 struct mtdids *id;
2236                 struct part_info *p;
2237
2238                 if (id_parse(argv[2], NULL, &type, &num) != 0)
2239                         return 1;
2240
2241                 if ((id = id_find(type, num)) == NULL) {
2242                         printf("no such device %s defined in mtdids variable\n", argv[2]);
2243                         return 1;
2244                 }
2245
2246                 len = strlen(id->mtd_id) + 1;   /* 'mtd_id:' */
2247                 len += strlen(argv[3]);         /* size@offset */
2248                 len += strlen(argv[4]) + 2;     /* '(' name ')' */
2249                 if (argv[5] && (strlen(argv[5]) == 2))
2250                         len += 2;               /* 'ro' */
2251
2252                 if (len >= PART_ADD_DESC_MAXLEN) {
2253                         printf("too long partition description\n");
2254                         return 1;
2255                 }
2256                 sprintf(tmpbuf, "%s:%s(%s)%s",
2257                                 id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : "");
2258                 DEBUGF("add tmpbuf: %s\n", tmpbuf);
2259
2260                 if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
2261                         return 1;
2262
2263                 DEBUGF("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
2264                                 dev->id->num, dev->id->mtd_id);
2265
2266                 if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
2267                         device_add(dev);
2268                 } else {
2269                         /* merge new partition with existing ones*/
2270                         p = list_entry(dev->parts.next, struct part_info, link);
2271                         if (part_add(dev_tmp, p) != 0) {
2272                                 device_del(dev);
2273                                 return 1;
2274                         }
2275                 }
2276
2277                 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
2278                         printf("generated mtdparts too long, reseting to null\n");
2279                         return 1;
2280                 }
2281
2282                 return 0;
2283         }
2284
2285         /* mtdparts del part-id */
2286         if ((argc == 3) && (strcmp(argv[1], "del") == 0)) {
2287                 DEBUGF("del: part-id = %s\n", argv[2]);
2288
2289                 return delete_partition(argv[2]);
2290         }
2291
2292         cmd_usage(cmdtp);
2293         return 1;
2294 }
2295 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
2296
2297 /***************************************************/
2298 U_BOOT_CMD(
2299         fsload, 3,      0,      do_jffs2_fsload,
2300         "load binary file from a filesystem image",
2301         "[ off ] [ filename ]\n"
2302         "    - load binary file from flash bank\n"
2303         "      with offset 'off'\n"
2304 );
2305 U_BOOT_CMD(
2306         ls,     2,      1,      do_jffs2_ls,
2307         "list files in a directory (default /)",
2308         "[ directory ]\n"
2309         "    - list files in a directory.\n"
2310 );
2311
2312 U_BOOT_CMD(
2313         fsinfo, 1,      1,      do_jffs2_fsinfo,
2314         "print information about filesystems",
2315         "    - print information about filesystems\n"
2316 );
2317
2318 #ifdef CONFIG_JFFS2_CMDLINE
2319 U_BOOT_CMD(
2320         chpart, 2,      0,      do_jffs2_chpart,
2321         "change active partition",
2322         "part-id\n"
2323         "    - change active partition (e.g. part-id = nand0,1)\n"
2324 );
2325
2326 U_BOOT_CMD(
2327         mtdparts,       6,      0,      do_jffs2_mtdparts,
2328         "define flash/nand partitions",
2329         "\n"
2330         "    - list partition table\n"
2331         "mtdparts delall\n"
2332         "    - delete all partitions\n"
2333         "mtdparts del part-id\n"
2334         "    - delete partition (e.g. part-id = nand0,1)\n"
2335         "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
2336         "    - add partition\n"
2337         "mtdparts default\n"
2338         "    - reset partition table to defaults\n\n"
2339         "-----\n\n"
2340         "this command uses three environment variables:\n\n"
2341         "'partition' - keeps current partition identifier\n\n"
2342         "partition  := <part-id>\n"
2343         "<part-id>  := <dev-id>,part_num\n\n"
2344         "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
2345         "mtdids=<idmap>[,<idmap>,...]\n\n"
2346         "<idmap>    := <dev-id>=<mtd-id>\n"
2347         "<dev-id>   := 'nand'|'nor'|'onenand'<dev-num>\n"
2348         "<dev-num>  := mtd device number, 0...\n"
2349         "<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
2350         "'mtdparts' - partition list\n\n"
2351         "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n"
2352         "<mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]\n"
2353         "<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n"
2354         "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n"
2355         "<size>     := standard linux memsize OR '-' to denote all remaining space\n"
2356         "<offset>   := partition start offset within the device\n"
2357         "<name>     := '(' NAME ')'\n"
2358         "<ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)\n"
2359 );
2360 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
2361
2362 /***************************************************/